xref: /rk3399_rockchip-uboot/tools/patman/settings.py (revision 8895b3e16c7a2aab4275d52be19e485605dc5c7b)
10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
20d24de9dSSimon Glass#
31a459660SWolfgang Denk# SPDX-License-Identifier:	GPL-2.0+
40d24de9dSSimon Glass#
50d24de9dSSimon Glass
60d24de9dSSimon Glassimport ConfigParser
70d24de9dSSimon Glassimport os
80d24de9dSSimon Glassimport re
90d24de9dSSimon Glass
100d24de9dSSimon Glassimport command
1187d65558SVikram Narayananimport gitutil
120d24de9dSSimon Glass
13a1dcee84SDoug Anderson"""Default settings per-project.
14a1dcee84SDoug Anderson
15a1dcee84SDoug AndersonThese are used by _ProjectConfigParser.  Settings names should match
16a1dcee84SDoug Andersonthe "dest" of the option parser from patman.py.
17a1dcee84SDoug Anderson"""
18a1dcee84SDoug Anderson_default_settings = {
19a1dcee84SDoug Anderson    "u-boot": {},
20a1dcee84SDoug Anderson    "linux": {
21a1dcee84SDoug Anderson        "process_tags": "False",
22a1dcee84SDoug Anderson    }
23a1dcee84SDoug Anderson}
24a1dcee84SDoug Anderson
25a1dcee84SDoug Andersonclass _ProjectConfigParser(ConfigParser.SafeConfigParser):
26a1dcee84SDoug Anderson    """ConfigParser that handles projects.
27a1dcee84SDoug Anderson
28a1dcee84SDoug Anderson    There are two main goals of this class:
29a1dcee84SDoug Anderson    - Load project-specific default settings.
30a1dcee84SDoug Anderson    - Merge general default settings/aliases with project-specific ones.
31a1dcee84SDoug Anderson
32a1dcee84SDoug Anderson    # Sample config used for tests below...
33a1dcee84SDoug Anderson    >>> import StringIO
34a1dcee84SDoug Anderson    >>> sample_config = '''
35a1dcee84SDoug Anderson    ... [alias]
36a1dcee84SDoug Anderson    ... me: Peter P. <likesspiders@example.com>
37a1dcee84SDoug Anderson    ... enemies: Evil <evil@example.com>
38a1dcee84SDoug Anderson    ...
39a1dcee84SDoug Anderson    ... [sm_alias]
40a1dcee84SDoug Anderson    ... enemies: Green G. <ugly@example.com>
41a1dcee84SDoug Anderson    ...
42a1dcee84SDoug Anderson    ... [sm2_alias]
43a1dcee84SDoug Anderson    ... enemies: Doc O. <pus@example.com>
44a1dcee84SDoug Anderson    ...
45a1dcee84SDoug Anderson    ... [settings]
46a1dcee84SDoug Anderson    ... am_hero: True
47a1dcee84SDoug Anderson    ... '''
48a1dcee84SDoug Anderson
49a1dcee84SDoug Anderson    # Check to make sure that bogus project gets general alias.
50a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("zzz")
51a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
52a1dcee84SDoug Anderson    >>> config.get("alias", "enemies")
53a1dcee84SDoug Anderson    'Evil <evil@example.com>'
54a1dcee84SDoug Anderson
55a1dcee84SDoug Anderson    # Check to make sure that alias gets overridden by project.
56a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("sm")
57a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
58a1dcee84SDoug Anderson    >>> config.get("alias", "enemies")
59a1dcee84SDoug Anderson    'Green G. <ugly@example.com>'
60a1dcee84SDoug Anderson
61a1dcee84SDoug Anderson    # Check to make sure that settings get merged with project.
62a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("linux")
63a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
64a1dcee84SDoug Anderson    >>> sorted(config.items("settings"))
65a1dcee84SDoug Anderson    [('am_hero', 'True'), ('process_tags', 'False')]
66a1dcee84SDoug Anderson
67a1dcee84SDoug Anderson    # Check to make sure that settings works with unknown project.
68a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("unknown")
69a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
70a1dcee84SDoug Anderson    >>> sorted(config.items("settings"))
71a1dcee84SDoug Anderson    [('am_hero', 'True')]
72a1dcee84SDoug Anderson    """
73a1dcee84SDoug Anderson    def __init__(self, project_name):
74a1dcee84SDoug Anderson        """Construct _ProjectConfigParser.
75a1dcee84SDoug Anderson
76a1dcee84SDoug Anderson        In addition to standard SafeConfigParser initialization, this also loads
77a1dcee84SDoug Anderson        project defaults.
78a1dcee84SDoug Anderson
79a1dcee84SDoug Anderson        Args:
80a1dcee84SDoug Anderson            project_name: The name of the project.
81a1dcee84SDoug Anderson        """
82a1dcee84SDoug Anderson        self._project_name = project_name
83a1dcee84SDoug Anderson        ConfigParser.SafeConfigParser.__init__(self)
84a1dcee84SDoug Anderson
85a1dcee84SDoug Anderson        # Update the project settings in the config based on
86a1dcee84SDoug Anderson        # the _default_settings global.
87a1dcee84SDoug Anderson        project_settings = "%s_settings" % project_name
88a1dcee84SDoug Anderson        if not self.has_section(project_settings):
89a1dcee84SDoug Anderson            self.add_section(project_settings)
90a1dcee84SDoug Anderson        project_defaults = _default_settings.get(project_name, {})
91a1dcee84SDoug Anderson        for setting_name, setting_value in project_defaults.iteritems():
92a1dcee84SDoug Anderson            self.set(project_settings, setting_name, setting_value)
93a1dcee84SDoug Anderson
94a1dcee84SDoug Anderson    def get(self, section, option, *args, **kwargs):
95a1dcee84SDoug Anderson        """Extend SafeConfigParser to try project_section before section.
96a1dcee84SDoug Anderson
97a1dcee84SDoug Anderson        Args:
98a1dcee84SDoug Anderson            See SafeConfigParser.
99a1dcee84SDoug Anderson        Returns:
100a1dcee84SDoug Anderson            See SafeConfigParser.
101a1dcee84SDoug Anderson        """
102a1dcee84SDoug Anderson        try:
103a1dcee84SDoug Anderson            return ConfigParser.SafeConfigParser.get(
104a1dcee84SDoug Anderson                self, "%s_%s" % (self._project_name, section), option,
105a1dcee84SDoug Anderson                *args, **kwargs
106a1dcee84SDoug Anderson            )
107a1dcee84SDoug Anderson        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
108a1dcee84SDoug Anderson            return ConfigParser.SafeConfigParser.get(
109a1dcee84SDoug Anderson                self, section, option, *args, **kwargs
110a1dcee84SDoug Anderson            )
111a1dcee84SDoug Anderson
112a1dcee84SDoug Anderson    def items(self, section, *args, **kwargs):
113a1dcee84SDoug Anderson        """Extend SafeConfigParser to add project_section to section.
114a1dcee84SDoug Anderson
115a1dcee84SDoug Anderson        Args:
116a1dcee84SDoug Anderson            See SafeConfigParser.
117a1dcee84SDoug Anderson        Returns:
118a1dcee84SDoug Anderson            See SafeConfigParser.
119a1dcee84SDoug Anderson        """
120a1dcee84SDoug Anderson        project_items = []
121a1dcee84SDoug Anderson        has_project_section = False
122a1dcee84SDoug Anderson        top_items = []
123a1dcee84SDoug Anderson
124a1dcee84SDoug Anderson        # Get items from the project section
125a1dcee84SDoug Anderson        try:
126a1dcee84SDoug Anderson            project_items = ConfigParser.SafeConfigParser.items(
127a1dcee84SDoug Anderson                self, "%s_%s" % (self._project_name, section), *args, **kwargs
128a1dcee84SDoug Anderson            )
129a1dcee84SDoug Anderson            has_project_section = True
130a1dcee84SDoug Anderson        except ConfigParser.NoSectionError:
131a1dcee84SDoug Anderson            pass
132a1dcee84SDoug Anderson
133a1dcee84SDoug Anderson        # Get top-level items
134a1dcee84SDoug Anderson        try:
135a1dcee84SDoug Anderson            top_items = ConfigParser.SafeConfigParser.items(
136a1dcee84SDoug Anderson                self, section, *args, **kwargs
137a1dcee84SDoug Anderson            )
138a1dcee84SDoug Anderson        except ConfigParser.NoSectionError:
139a1dcee84SDoug Anderson            # If neither section exists raise the error on...
140a1dcee84SDoug Anderson            if not has_project_section:
141a1dcee84SDoug Anderson                raise
142a1dcee84SDoug Anderson
143a1dcee84SDoug Anderson        item_dict = dict(top_items)
144a1dcee84SDoug Anderson        item_dict.update(project_items)
145a1dcee84SDoug Anderson        return item_dict.items()
146a1dcee84SDoug Anderson
1470d24de9dSSimon Glassdef ReadGitAliases(fname):
1480d24de9dSSimon Glass    """Read a git alias file. This is in the form used by git:
1490d24de9dSSimon Glass
1500d24de9dSSimon Glass    alias uboot  u-boot@lists.denx.de
1510d24de9dSSimon Glass    alias wd     Wolfgang Denk <wd@denx.de>
1520d24de9dSSimon Glass
1530d24de9dSSimon Glass    Args:
1540d24de9dSSimon Glass        fname: Filename to read
1550d24de9dSSimon Glass    """
1560d24de9dSSimon Glass    try:
1570d24de9dSSimon Glass        fd = open(fname, 'r')
1580d24de9dSSimon Glass    except IOError:
1590d24de9dSSimon Glass        print "Warning: Cannot find alias file '%s'" % fname
1600d24de9dSSimon Glass        return
1610d24de9dSSimon Glass
1620d24de9dSSimon Glass    re_line = re.compile('alias\s+(\S+)\s+(.*)')
1630d24de9dSSimon Glass    for line in fd.readlines():
1640d24de9dSSimon Glass        line = line.strip()
1650d24de9dSSimon Glass        if not line or line[0] == '#':
1660d24de9dSSimon Glass            continue
1670d24de9dSSimon Glass
1680d24de9dSSimon Glass        m = re_line.match(line)
1690d24de9dSSimon Glass        if not m:
1700d24de9dSSimon Glass            print "Warning: Alias file line '%s' not understood" % line
1710d24de9dSSimon Glass            continue
1720d24de9dSSimon Glass
1730d24de9dSSimon Glass        list = alias.get(m.group(1), [])
1740d24de9dSSimon Glass        for item in m.group(2).split(','):
1750d24de9dSSimon Glass            item = item.strip()
1760d24de9dSSimon Glass            if item:
1770d24de9dSSimon Glass                list.append(item)
1780d24de9dSSimon Glass        alias[m.group(1)] = list
1790d24de9dSSimon Glass
1800d24de9dSSimon Glass    fd.close()
1810d24de9dSSimon Glass
18287d65558SVikram Narayanandef CreatePatmanConfigFile(config_fname):
18387d65558SVikram Narayanan    """Creates a config file under $(HOME)/.patman if it can't find one.
18487d65558SVikram Narayanan
18587d65558SVikram Narayanan    Args:
18687d65558SVikram Narayanan        config_fname: Default config filename i.e., $(HOME)/.patman
18787d65558SVikram Narayanan
18887d65558SVikram Narayanan    Returns:
18987d65558SVikram Narayanan        None
19087d65558SVikram Narayanan    """
19187d65558SVikram Narayanan    name = gitutil.GetDefaultUserName()
19287d65558SVikram Narayanan    if name == None:
19387d65558SVikram Narayanan        name = raw_input("Enter name: ")
19487d65558SVikram Narayanan
19587d65558SVikram Narayanan    email = gitutil.GetDefaultUserEmail()
19687d65558SVikram Narayanan
19787d65558SVikram Narayanan    if email == None:
19887d65558SVikram Narayanan        email = raw_input("Enter email: ")
19987d65558SVikram Narayanan
20087d65558SVikram Narayanan    try:
20187d65558SVikram Narayanan        f = open(config_fname, 'w')
20287d65558SVikram Narayanan    except IOError:
20387d65558SVikram Narayanan        print "Couldn't create patman config file\n"
20487d65558SVikram Narayanan        raise
20587d65558SVikram Narayanan
20687d65558SVikram Narayanan    print >>f, "[alias]\nme: %s <%s>" % (name, email)
20787d65558SVikram Narayanan    f.close();
20887d65558SVikram Narayanan
2098568baedSDoug Andersondef _UpdateDefaults(parser, config):
2108568baedSDoug Anderson    """Update the given OptionParser defaults based on config.
2118568baedSDoug Anderson
2128568baedSDoug Anderson    We'll walk through all of the settings from the parser
2138568baedSDoug Anderson    For each setting we'll look for a default in the option parser.
2148568baedSDoug Anderson    If it's found we'll update the option parser default.
2158568baedSDoug Anderson
2168568baedSDoug Anderson    The idea here is that the .patman file should be able to update
2178568baedSDoug Anderson    defaults but that command line flags should still have the final
2188568baedSDoug Anderson    say.
2198568baedSDoug Anderson
2208568baedSDoug Anderson    Args:
2218568baedSDoug Anderson        parser: An instance of an OptionParser whose defaults will be
2228568baedSDoug Anderson            updated.
223a1dcee84SDoug Anderson        config: An instance of _ProjectConfigParser that we will query
2248568baedSDoug Anderson            for settings.
2258568baedSDoug Anderson    """
2268568baedSDoug Anderson    defaults = parser.get_default_values()
2278568baedSDoug Anderson    for name, val in config.items('settings'):
2288568baedSDoug Anderson        if hasattr(defaults, name):
2298568baedSDoug Anderson            default_val = getattr(defaults, name)
2308568baedSDoug Anderson            if isinstance(default_val, bool):
2318568baedSDoug Anderson                val = config.getboolean('settings', name)
2328568baedSDoug Anderson            elif isinstance(default_val, int):
2338568baedSDoug Anderson                val = config.getint('settings', name)
2348568baedSDoug Anderson            parser.set_default(name, val)
2358568baedSDoug Anderson        else:
2368568baedSDoug Anderson            print "WARNING: Unknown setting %s" % name
2378568baedSDoug Anderson
238*8895b3e1SSimon Glassdef _ReadAliasFile(fname):
239*8895b3e1SSimon Glass    """Read in the U-Boot git alias file if it exists.
240*8895b3e1SSimon Glass
241*8895b3e1SSimon Glass    Args:
242*8895b3e1SSimon Glass        fname: Filename to read.
243*8895b3e1SSimon Glass    """
244*8895b3e1SSimon Glass    if os.path.exists(fname):
245*8895b3e1SSimon Glass        bad_line = None
246*8895b3e1SSimon Glass        with open(fname) as fd:
247*8895b3e1SSimon Glass            linenum = 0
248*8895b3e1SSimon Glass            for line in fd:
249*8895b3e1SSimon Glass                linenum += 1
250*8895b3e1SSimon Glass                line = line.strip()
251*8895b3e1SSimon Glass                if not line or line.startswith('#'):
252*8895b3e1SSimon Glass                    continue
253*8895b3e1SSimon Glass                words = line.split(' ', 2)
254*8895b3e1SSimon Glass                if len(words) < 3 or words[0] != 'alias':
255*8895b3e1SSimon Glass                    if not bad_line:
256*8895b3e1SSimon Glass                        bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
257*8895b3e1SSimon Glass                                                                line)
258*8895b3e1SSimon Glass                    continue
259*8895b3e1SSimon Glass                alias[words[1]] = [s.strip() for s in words[2].split(',')]
260*8895b3e1SSimon Glass        if bad_line:
261*8895b3e1SSimon Glass            print bad_line
262*8895b3e1SSimon Glass
263a1dcee84SDoug Andersondef Setup(parser, project_name, config_fname=''):
2640d24de9dSSimon Glass    """Set up the settings module by reading config files.
2650d24de9dSSimon Glass
2660d24de9dSSimon Glass    Args:
2678568baedSDoug Anderson        parser:         The parser to update
268a1dcee84SDoug Anderson        project_name:   Name of project that we're working on; we'll look
269a1dcee84SDoug Anderson            for sections named "project_section" as well.
2700d24de9dSSimon Glass        config_fname:   Config filename to read ('' for default)
2710d24de9dSSimon Glass    """
272*8895b3e1SSimon Glass    # First read the git alias file if available
273*8895b3e1SSimon Glass    _ReadAliasFile('doc/git-mailrc')
274a1dcee84SDoug Anderson    config = _ProjectConfigParser(project_name)
2750d24de9dSSimon Glass    if config_fname == '':
2762b36c75dSVikram Narayanan        config_fname = '%s/.patman' % os.getenv('HOME')
27787d65558SVikram Narayanan
27887d65558SVikram Narayanan    if not os.path.exists(config_fname):
27987d65558SVikram Narayanan        print "No config file found ~/.patman\nCreating one...\n"
28087d65558SVikram Narayanan        CreatePatmanConfigFile(config_fname)
28187d65558SVikram Narayanan
2828568baedSDoug Anderson    config.read(config_fname)
2830d24de9dSSimon Glass
2848568baedSDoug Anderson    for name, value in config.items('alias'):
2850d24de9dSSimon Glass        alias[name] = value.split(',')
2860d24de9dSSimon Glass
2878568baedSDoug Anderson    _UpdateDefaults(parser, config)
2880d24de9dSSimon Glass
2890d24de9dSSimon Glass# These are the aliases we understand, indexed by alias. Each member is a list.
2900d24de9dSSimon Glassalias = {}
291a1dcee84SDoug Anderson
292a1dcee84SDoug Andersonif __name__ == "__main__":
293a1dcee84SDoug Anderson    import doctest
294a1dcee84SDoug Anderson
295a1dcee84SDoug Anderson    doctest.testmod()
296