xref: /rk3399_rockchip-uboot/tools/patman/settings.py (revision a1dcee84c993232a6c5a1f3b4e54952b587cf1d1)
10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
20d24de9dSSimon Glass#
30d24de9dSSimon Glass# See file CREDITS for list of people who contributed to this
40d24de9dSSimon Glass# project.
50d24de9dSSimon Glass#
60d24de9dSSimon Glass# This program is free software; you can redistribute it and/or
70d24de9dSSimon Glass# modify it under the terms of the GNU General Public License as
80d24de9dSSimon Glass# published by the Free Software Foundation; either version 2 of
90d24de9dSSimon Glass# the License, or (at your option) any later version.
100d24de9dSSimon Glass#
110d24de9dSSimon Glass# This program is distributed in the hope that it will be useful,
120d24de9dSSimon Glass# but WITHOUT ANY WARRANTY; without even the implied warranty of
130d24de9dSSimon Glass# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
140d24de9dSSimon Glass# GNU General Public License for more details.
150d24de9dSSimon Glass#
160d24de9dSSimon Glass# You should have received a copy of the GNU General Public License
170d24de9dSSimon Glass# along with this program; if not, write to the Free Software
180d24de9dSSimon Glass# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
190d24de9dSSimon Glass# MA 02111-1307 USA
200d24de9dSSimon Glass#
210d24de9dSSimon Glass
220d24de9dSSimon Glassimport ConfigParser
230d24de9dSSimon Glassimport os
240d24de9dSSimon Glassimport re
250d24de9dSSimon Glass
260d24de9dSSimon Glassimport command
2787d65558SVikram Narayananimport gitutil
280d24de9dSSimon Glass
29*a1dcee84SDoug Anderson"""Default settings per-project.
30*a1dcee84SDoug Anderson
31*a1dcee84SDoug AndersonThese are used by _ProjectConfigParser.  Settings names should match
32*a1dcee84SDoug Andersonthe "dest" of the option parser from patman.py.
33*a1dcee84SDoug Anderson"""
34*a1dcee84SDoug Anderson_default_settings = {
35*a1dcee84SDoug Anderson    "u-boot": {},
36*a1dcee84SDoug Anderson    "linux": {
37*a1dcee84SDoug Anderson        "process_tags": "False",
38*a1dcee84SDoug Anderson    }
39*a1dcee84SDoug Anderson}
40*a1dcee84SDoug Anderson
41*a1dcee84SDoug Andersonclass _ProjectConfigParser(ConfigParser.SafeConfigParser):
42*a1dcee84SDoug Anderson    """ConfigParser that handles projects.
43*a1dcee84SDoug Anderson
44*a1dcee84SDoug Anderson    There are two main goals of this class:
45*a1dcee84SDoug Anderson    - Load project-specific default settings.
46*a1dcee84SDoug Anderson    - Merge general default settings/aliases with project-specific ones.
47*a1dcee84SDoug Anderson
48*a1dcee84SDoug Anderson    # Sample config used for tests below...
49*a1dcee84SDoug Anderson    >>> import StringIO
50*a1dcee84SDoug Anderson    >>> sample_config = '''
51*a1dcee84SDoug Anderson    ... [alias]
52*a1dcee84SDoug Anderson    ... me: Peter P. <likesspiders@example.com>
53*a1dcee84SDoug Anderson    ... enemies: Evil <evil@example.com>
54*a1dcee84SDoug Anderson    ...
55*a1dcee84SDoug Anderson    ... [sm_alias]
56*a1dcee84SDoug Anderson    ... enemies: Green G. <ugly@example.com>
57*a1dcee84SDoug Anderson    ...
58*a1dcee84SDoug Anderson    ... [sm2_alias]
59*a1dcee84SDoug Anderson    ... enemies: Doc O. <pus@example.com>
60*a1dcee84SDoug Anderson    ...
61*a1dcee84SDoug Anderson    ... [settings]
62*a1dcee84SDoug Anderson    ... am_hero: True
63*a1dcee84SDoug Anderson    ... '''
64*a1dcee84SDoug Anderson
65*a1dcee84SDoug Anderson    # Check to make sure that bogus project gets general alias.
66*a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("zzz")
67*a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
68*a1dcee84SDoug Anderson    >>> config.get("alias", "enemies")
69*a1dcee84SDoug Anderson    'Evil <evil@example.com>'
70*a1dcee84SDoug Anderson
71*a1dcee84SDoug Anderson    # Check to make sure that alias gets overridden by project.
72*a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("sm")
73*a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
74*a1dcee84SDoug Anderson    >>> config.get("alias", "enemies")
75*a1dcee84SDoug Anderson    'Green G. <ugly@example.com>'
76*a1dcee84SDoug Anderson
77*a1dcee84SDoug Anderson    # Check to make sure that settings get merged with project.
78*a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("linux")
79*a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
80*a1dcee84SDoug Anderson    >>> sorted(config.items("settings"))
81*a1dcee84SDoug Anderson    [('am_hero', 'True'), ('process_tags', 'False')]
82*a1dcee84SDoug Anderson
83*a1dcee84SDoug Anderson    # Check to make sure that settings works with unknown project.
84*a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("unknown")
85*a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
86*a1dcee84SDoug Anderson    >>> sorted(config.items("settings"))
87*a1dcee84SDoug Anderson    [('am_hero', 'True')]
88*a1dcee84SDoug Anderson    """
89*a1dcee84SDoug Anderson    def __init__(self, project_name):
90*a1dcee84SDoug Anderson        """Construct _ProjectConfigParser.
91*a1dcee84SDoug Anderson
92*a1dcee84SDoug Anderson        In addition to standard SafeConfigParser initialization, this also loads
93*a1dcee84SDoug Anderson        project defaults.
94*a1dcee84SDoug Anderson
95*a1dcee84SDoug Anderson        Args:
96*a1dcee84SDoug Anderson            project_name: The name of the project.
97*a1dcee84SDoug Anderson        """
98*a1dcee84SDoug Anderson        self._project_name = project_name
99*a1dcee84SDoug Anderson        ConfigParser.SafeConfigParser.__init__(self)
100*a1dcee84SDoug Anderson
101*a1dcee84SDoug Anderson        # Update the project settings in the config based on
102*a1dcee84SDoug Anderson        # the _default_settings global.
103*a1dcee84SDoug Anderson        project_settings = "%s_settings" % project_name
104*a1dcee84SDoug Anderson        if not self.has_section(project_settings):
105*a1dcee84SDoug Anderson            self.add_section(project_settings)
106*a1dcee84SDoug Anderson        project_defaults = _default_settings.get(project_name, {})
107*a1dcee84SDoug Anderson        for setting_name, setting_value in project_defaults.iteritems():
108*a1dcee84SDoug Anderson            self.set(project_settings, setting_name, setting_value)
109*a1dcee84SDoug Anderson
110*a1dcee84SDoug Anderson    def get(self, section, option, *args, **kwargs):
111*a1dcee84SDoug Anderson        """Extend SafeConfigParser to try project_section before section.
112*a1dcee84SDoug Anderson
113*a1dcee84SDoug Anderson        Args:
114*a1dcee84SDoug Anderson            See SafeConfigParser.
115*a1dcee84SDoug Anderson        Returns:
116*a1dcee84SDoug Anderson            See SafeConfigParser.
117*a1dcee84SDoug Anderson        """
118*a1dcee84SDoug Anderson        try:
119*a1dcee84SDoug Anderson            return ConfigParser.SafeConfigParser.get(
120*a1dcee84SDoug Anderson                self, "%s_%s" % (self._project_name, section), option,
121*a1dcee84SDoug Anderson                *args, **kwargs
122*a1dcee84SDoug Anderson            )
123*a1dcee84SDoug Anderson        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
124*a1dcee84SDoug Anderson            return ConfigParser.SafeConfigParser.get(
125*a1dcee84SDoug Anderson                self, section, option, *args, **kwargs
126*a1dcee84SDoug Anderson            )
127*a1dcee84SDoug Anderson
128*a1dcee84SDoug Anderson    def items(self, section, *args, **kwargs):
129*a1dcee84SDoug Anderson        """Extend SafeConfigParser to add project_section to section.
130*a1dcee84SDoug Anderson
131*a1dcee84SDoug Anderson        Args:
132*a1dcee84SDoug Anderson            See SafeConfigParser.
133*a1dcee84SDoug Anderson        Returns:
134*a1dcee84SDoug Anderson            See SafeConfigParser.
135*a1dcee84SDoug Anderson        """
136*a1dcee84SDoug Anderson        project_items = []
137*a1dcee84SDoug Anderson        has_project_section = False
138*a1dcee84SDoug Anderson        top_items = []
139*a1dcee84SDoug Anderson
140*a1dcee84SDoug Anderson        # Get items from the project section
141*a1dcee84SDoug Anderson        try:
142*a1dcee84SDoug Anderson            project_items = ConfigParser.SafeConfigParser.items(
143*a1dcee84SDoug Anderson                self, "%s_%s" % (self._project_name, section), *args, **kwargs
144*a1dcee84SDoug Anderson            )
145*a1dcee84SDoug Anderson            has_project_section = True
146*a1dcee84SDoug Anderson        except ConfigParser.NoSectionError:
147*a1dcee84SDoug Anderson            pass
148*a1dcee84SDoug Anderson
149*a1dcee84SDoug Anderson        # Get top-level items
150*a1dcee84SDoug Anderson        try:
151*a1dcee84SDoug Anderson            top_items = ConfigParser.SafeConfigParser.items(
152*a1dcee84SDoug Anderson                self, section, *args, **kwargs
153*a1dcee84SDoug Anderson            )
154*a1dcee84SDoug Anderson        except ConfigParser.NoSectionError:
155*a1dcee84SDoug Anderson            # If neither section exists raise the error on...
156*a1dcee84SDoug Anderson            if not has_project_section:
157*a1dcee84SDoug Anderson                raise
158*a1dcee84SDoug Anderson
159*a1dcee84SDoug Anderson        item_dict = dict(top_items)
160*a1dcee84SDoug Anderson        item_dict.update(project_items)
161*a1dcee84SDoug Anderson        return item_dict.items()
162*a1dcee84SDoug Anderson
1630d24de9dSSimon Glassdef ReadGitAliases(fname):
1640d24de9dSSimon Glass    """Read a git alias file. This is in the form used by git:
1650d24de9dSSimon Glass
1660d24de9dSSimon Glass    alias uboot  u-boot@lists.denx.de
1670d24de9dSSimon Glass    alias wd     Wolfgang Denk <wd@denx.de>
1680d24de9dSSimon Glass
1690d24de9dSSimon Glass    Args:
1700d24de9dSSimon Glass        fname: Filename to read
1710d24de9dSSimon Glass    """
1720d24de9dSSimon Glass    try:
1730d24de9dSSimon Glass        fd = open(fname, 'r')
1740d24de9dSSimon Glass    except IOError:
1750d24de9dSSimon Glass        print "Warning: Cannot find alias file '%s'" % fname
1760d24de9dSSimon Glass        return
1770d24de9dSSimon Glass
1780d24de9dSSimon Glass    re_line = re.compile('alias\s+(\S+)\s+(.*)')
1790d24de9dSSimon Glass    for line in fd.readlines():
1800d24de9dSSimon Glass        line = line.strip()
1810d24de9dSSimon Glass        if not line or line[0] == '#':
1820d24de9dSSimon Glass            continue
1830d24de9dSSimon Glass
1840d24de9dSSimon Glass        m = re_line.match(line)
1850d24de9dSSimon Glass        if not m:
1860d24de9dSSimon Glass            print "Warning: Alias file line '%s' not understood" % line
1870d24de9dSSimon Glass            continue
1880d24de9dSSimon Glass
1890d24de9dSSimon Glass        list = alias.get(m.group(1), [])
1900d24de9dSSimon Glass        for item in m.group(2).split(','):
1910d24de9dSSimon Glass            item = item.strip()
1920d24de9dSSimon Glass            if item:
1930d24de9dSSimon Glass                list.append(item)
1940d24de9dSSimon Glass        alias[m.group(1)] = list
1950d24de9dSSimon Glass
1960d24de9dSSimon Glass    fd.close()
1970d24de9dSSimon Glass
19887d65558SVikram Narayanandef CreatePatmanConfigFile(config_fname):
19987d65558SVikram Narayanan    """Creates a config file under $(HOME)/.patman if it can't find one.
20087d65558SVikram Narayanan
20187d65558SVikram Narayanan    Args:
20287d65558SVikram Narayanan        config_fname: Default config filename i.e., $(HOME)/.patman
20387d65558SVikram Narayanan
20487d65558SVikram Narayanan    Returns:
20587d65558SVikram Narayanan        None
20687d65558SVikram Narayanan    """
20787d65558SVikram Narayanan    name = gitutil.GetDefaultUserName()
20887d65558SVikram Narayanan    if name == None:
20987d65558SVikram Narayanan        name = raw_input("Enter name: ")
21087d65558SVikram Narayanan
21187d65558SVikram Narayanan    email = gitutil.GetDefaultUserEmail()
21287d65558SVikram Narayanan
21387d65558SVikram Narayanan    if email == None:
21487d65558SVikram Narayanan        email = raw_input("Enter email: ")
21587d65558SVikram Narayanan
21687d65558SVikram Narayanan    try:
21787d65558SVikram Narayanan        f = open(config_fname, 'w')
21887d65558SVikram Narayanan    except IOError:
21987d65558SVikram Narayanan        print "Couldn't create patman config file\n"
22087d65558SVikram Narayanan        raise
22187d65558SVikram Narayanan
22287d65558SVikram Narayanan    print >>f, "[alias]\nme: %s <%s>" % (name, email)
22387d65558SVikram Narayanan    f.close();
22487d65558SVikram Narayanan
2258568baedSDoug Andersondef _UpdateDefaults(parser, config):
2268568baedSDoug Anderson    """Update the given OptionParser defaults based on config.
2278568baedSDoug Anderson
2288568baedSDoug Anderson    We'll walk through all of the settings from the parser
2298568baedSDoug Anderson    For each setting we'll look for a default in the option parser.
2308568baedSDoug Anderson    If it's found we'll update the option parser default.
2318568baedSDoug Anderson
2328568baedSDoug Anderson    The idea here is that the .patman file should be able to update
2338568baedSDoug Anderson    defaults but that command line flags should still have the final
2348568baedSDoug Anderson    say.
2358568baedSDoug Anderson
2368568baedSDoug Anderson    Args:
2378568baedSDoug Anderson        parser: An instance of an OptionParser whose defaults will be
2388568baedSDoug Anderson            updated.
239*a1dcee84SDoug Anderson        config: An instance of _ProjectConfigParser that we will query
2408568baedSDoug Anderson            for settings.
2418568baedSDoug Anderson    """
2428568baedSDoug Anderson    defaults = parser.get_default_values()
2438568baedSDoug Anderson    for name, val in config.items('settings'):
2448568baedSDoug Anderson        if hasattr(defaults, name):
2458568baedSDoug Anderson            default_val = getattr(defaults, name)
2468568baedSDoug Anderson            if isinstance(default_val, bool):
2478568baedSDoug Anderson                val = config.getboolean('settings', name)
2488568baedSDoug Anderson            elif isinstance(default_val, int):
2498568baedSDoug Anderson                val = config.getint('settings', name)
2508568baedSDoug Anderson            parser.set_default(name, val)
2518568baedSDoug Anderson        else:
2528568baedSDoug Anderson            print "WARNING: Unknown setting %s" % name
2538568baedSDoug Anderson
254*a1dcee84SDoug Andersondef Setup(parser, project_name, config_fname=''):
2550d24de9dSSimon Glass    """Set up the settings module by reading config files.
2560d24de9dSSimon Glass
2570d24de9dSSimon Glass    Args:
2588568baedSDoug Anderson        parser:         The parser to update
259*a1dcee84SDoug Anderson        project_name:   Name of project that we're working on; we'll look
260*a1dcee84SDoug Anderson            for sections named "project_section" as well.
2610d24de9dSSimon Glass        config_fname:   Config filename to read ('' for default)
2620d24de9dSSimon Glass    """
263*a1dcee84SDoug Anderson    config = _ProjectConfigParser(project_name)
2640d24de9dSSimon Glass    if config_fname == '':
2652b36c75dSVikram Narayanan        config_fname = '%s/.patman' % os.getenv('HOME')
26687d65558SVikram Narayanan
26787d65558SVikram Narayanan    if not os.path.exists(config_fname):
26887d65558SVikram Narayanan        print "No config file found ~/.patman\nCreating one...\n"
26987d65558SVikram Narayanan        CreatePatmanConfigFile(config_fname)
27087d65558SVikram Narayanan
2718568baedSDoug Anderson    config.read(config_fname)
2720d24de9dSSimon Glass
2738568baedSDoug Anderson    for name, value in config.items('alias'):
2740d24de9dSSimon Glass        alias[name] = value.split(',')
2750d24de9dSSimon Glass
2768568baedSDoug Anderson    _UpdateDefaults(parser, config)
2770d24de9dSSimon Glass
2780d24de9dSSimon Glass# These are the aliases we understand, indexed by alias. Each member is a list.
2790d24de9dSSimon Glassalias = {}
280*a1dcee84SDoug Anderson
281*a1dcee84SDoug Andersonif __name__ == "__main__":
282*a1dcee84SDoug Anderson    import doctest
283*a1dcee84SDoug Anderson
284*a1dcee84SDoug Anderson    doctest.testmod()
285