xref: /rk3399_rockchip-uboot/tools/patman/settings.py (revision 2ce7b21e6c98301f9b05daac076db33d498cfbe1)
10d24de9dSSimon Glass# Copyright (c) 2011 The Chromium OS Authors.
20d24de9dSSimon Glass#
31a459660SWolfgang Denk# SPDX-License-Identifier:	GPL-2.0+
40d24de9dSSimon Glass#
50d24de9dSSimon Glass
6a920a17bSPaul Burtonfrom __future__ import print_function
7a920a17bSPaul Burton
8*2ce7b21eSPaul Burtontry:
9*2ce7b21eSPaul Burton    import configparser as ConfigParser
10*2ce7b21eSPaul Burtonexcept:
110d24de9dSSimon Glass    import ConfigParser
12*2ce7b21eSPaul Burton
130d24de9dSSimon Glassimport os
140d24de9dSSimon Glassimport re
150d24de9dSSimon Glass
160d24de9dSSimon Glassimport command
1787d65558SVikram Narayananimport gitutil
180d24de9dSSimon Glass
19a1dcee84SDoug Anderson"""Default settings per-project.
20a1dcee84SDoug Anderson
21a1dcee84SDoug AndersonThese are used by _ProjectConfigParser.  Settings names should match
22a1dcee84SDoug Andersonthe "dest" of the option parser from patman.py.
23a1dcee84SDoug Anderson"""
24a1dcee84SDoug Anderson_default_settings = {
25a1dcee84SDoug Anderson    "u-boot": {},
26a1dcee84SDoug Anderson    "linux": {
27a1dcee84SDoug Anderson        "process_tags": "False",
28a1dcee84SDoug Anderson    }
29a1dcee84SDoug Anderson}
30a1dcee84SDoug Anderson
31a1dcee84SDoug Andersonclass _ProjectConfigParser(ConfigParser.SafeConfigParser):
32a1dcee84SDoug Anderson    """ConfigParser that handles projects.
33a1dcee84SDoug Anderson
34a1dcee84SDoug Anderson    There are two main goals of this class:
35a1dcee84SDoug Anderson    - Load project-specific default settings.
36a1dcee84SDoug Anderson    - Merge general default settings/aliases with project-specific ones.
37a1dcee84SDoug Anderson
38a1dcee84SDoug Anderson    # Sample config used for tests below...
39a1dcee84SDoug Anderson    >>> import StringIO
40a1dcee84SDoug Anderson    >>> sample_config = '''
41a1dcee84SDoug Anderson    ... [alias]
42a1dcee84SDoug Anderson    ... me: Peter P. <likesspiders@example.com>
43a1dcee84SDoug Anderson    ... enemies: Evil <evil@example.com>
44a1dcee84SDoug Anderson    ...
45a1dcee84SDoug Anderson    ... [sm_alias]
46a1dcee84SDoug Anderson    ... enemies: Green G. <ugly@example.com>
47a1dcee84SDoug Anderson    ...
48a1dcee84SDoug Anderson    ... [sm2_alias]
49a1dcee84SDoug Anderson    ... enemies: Doc O. <pus@example.com>
50a1dcee84SDoug Anderson    ...
51a1dcee84SDoug Anderson    ... [settings]
52a1dcee84SDoug Anderson    ... am_hero: True
53a1dcee84SDoug Anderson    ... '''
54a1dcee84SDoug Anderson
55a1dcee84SDoug Anderson    # Check to make sure that bogus project gets general alias.
56a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("zzz")
57a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
58a1dcee84SDoug Anderson    >>> config.get("alias", "enemies")
59a1dcee84SDoug Anderson    'Evil <evil@example.com>'
60a1dcee84SDoug Anderson
61a1dcee84SDoug Anderson    # Check to make sure that alias gets overridden by project.
62a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("sm")
63a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
64a1dcee84SDoug Anderson    >>> config.get("alias", "enemies")
65a1dcee84SDoug Anderson    'Green G. <ugly@example.com>'
66a1dcee84SDoug Anderson
67a1dcee84SDoug Anderson    # Check to make sure that settings get merged with project.
68a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("linux")
69a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
70a1dcee84SDoug Anderson    >>> sorted(config.items("settings"))
71a1dcee84SDoug Anderson    [('am_hero', 'True'), ('process_tags', 'False')]
72a1dcee84SDoug Anderson
73a1dcee84SDoug Anderson    # Check to make sure that settings works with unknown project.
74a1dcee84SDoug Anderson    >>> config = _ProjectConfigParser("unknown")
75a1dcee84SDoug Anderson    >>> config.readfp(StringIO.StringIO(sample_config))
76a1dcee84SDoug Anderson    >>> sorted(config.items("settings"))
77a1dcee84SDoug Anderson    [('am_hero', 'True')]
78a1dcee84SDoug Anderson    """
79a1dcee84SDoug Anderson    def __init__(self, project_name):
80a1dcee84SDoug Anderson        """Construct _ProjectConfigParser.
81a1dcee84SDoug Anderson
82a1dcee84SDoug Anderson        In addition to standard SafeConfigParser initialization, this also loads
83a1dcee84SDoug Anderson        project defaults.
84a1dcee84SDoug Anderson
85a1dcee84SDoug Anderson        Args:
86a1dcee84SDoug Anderson            project_name: The name of the project.
87a1dcee84SDoug Anderson        """
88a1dcee84SDoug Anderson        self._project_name = project_name
89a1dcee84SDoug Anderson        ConfigParser.SafeConfigParser.__init__(self)
90a1dcee84SDoug Anderson
91a1dcee84SDoug Anderson        # Update the project settings in the config based on
92a1dcee84SDoug Anderson        # the _default_settings global.
93a1dcee84SDoug Anderson        project_settings = "%s_settings" % project_name
94a1dcee84SDoug Anderson        if not self.has_section(project_settings):
95a1dcee84SDoug Anderson            self.add_section(project_settings)
96a1dcee84SDoug Anderson        project_defaults = _default_settings.get(project_name, {})
97a1dcee84SDoug Anderson        for setting_name, setting_value in project_defaults.iteritems():
98a1dcee84SDoug Anderson            self.set(project_settings, setting_name, setting_value)
99a1dcee84SDoug Anderson
100a1dcee84SDoug Anderson    def get(self, section, option, *args, **kwargs):
101a1dcee84SDoug Anderson        """Extend SafeConfigParser to try project_section before section.
102a1dcee84SDoug Anderson
103a1dcee84SDoug Anderson        Args:
104a1dcee84SDoug Anderson            See SafeConfigParser.
105a1dcee84SDoug Anderson        Returns:
106a1dcee84SDoug Anderson            See SafeConfigParser.
107a1dcee84SDoug Anderson        """
108a1dcee84SDoug Anderson        try:
109a1dcee84SDoug Anderson            return ConfigParser.SafeConfigParser.get(
110a1dcee84SDoug Anderson                self, "%s_%s" % (self._project_name, section), option,
111a1dcee84SDoug Anderson                *args, **kwargs
112a1dcee84SDoug Anderson            )
113a1dcee84SDoug Anderson        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
114a1dcee84SDoug Anderson            return ConfigParser.SafeConfigParser.get(
115a1dcee84SDoug Anderson                self, section, option, *args, **kwargs
116a1dcee84SDoug Anderson            )
117a1dcee84SDoug Anderson
118a1dcee84SDoug Anderson    def items(self, section, *args, **kwargs):
119a1dcee84SDoug Anderson        """Extend SafeConfigParser to add project_section to section.
120a1dcee84SDoug Anderson
121a1dcee84SDoug Anderson        Args:
122a1dcee84SDoug Anderson            See SafeConfigParser.
123a1dcee84SDoug Anderson        Returns:
124a1dcee84SDoug Anderson            See SafeConfigParser.
125a1dcee84SDoug Anderson        """
126a1dcee84SDoug Anderson        project_items = []
127a1dcee84SDoug Anderson        has_project_section = False
128a1dcee84SDoug Anderson        top_items = []
129a1dcee84SDoug Anderson
130a1dcee84SDoug Anderson        # Get items from the project section
131a1dcee84SDoug Anderson        try:
132a1dcee84SDoug Anderson            project_items = ConfigParser.SafeConfigParser.items(
133a1dcee84SDoug Anderson                self, "%s_%s" % (self._project_name, section), *args, **kwargs
134a1dcee84SDoug Anderson            )
135a1dcee84SDoug Anderson            has_project_section = True
136a1dcee84SDoug Anderson        except ConfigParser.NoSectionError:
137a1dcee84SDoug Anderson            pass
138a1dcee84SDoug Anderson
139a1dcee84SDoug Anderson        # Get top-level items
140a1dcee84SDoug Anderson        try:
141a1dcee84SDoug Anderson            top_items = ConfigParser.SafeConfigParser.items(
142a1dcee84SDoug Anderson                self, section, *args, **kwargs
143a1dcee84SDoug Anderson            )
144a1dcee84SDoug Anderson        except ConfigParser.NoSectionError:
145a1dcee84SDoug Anderson            # If neither section exists raise the error on...
146a1dcee84SDoug Anderson            if not has_project_section:
147a1dcee84SDoug Anderson                raise
148a1dcee84SDoug Anderson
149a1dcee84SDoug Anderson        item_dict = dict(top_items)
150a1dcee84SDoug Anderson        item_dict.update(project_items)
151a1dcee84SDoug Anderson        return item_dict.items()
152a1dcee84SDoug Anderson
1530d24de9dSSimon Glassdef ReadGitAliases(fname):
1540d24de9dSSimon Glass    """Read a git alias file. This is in the form used by git:
1550d24de9dSSimon Glass
1560d24de9dSSimon Glass    alias uboot  u-boot@lists.denx.de
1570d24de9dSSimon Glass    alias wd     Wolfgang Denk <wd@denx.de>
1580d24de9dSSimon Glass
1590d24de9dSSimon Glass    Args:
1600d24de9dSSimon Glass        fname: Filename to read
1610d24de9dSSimon Glass    """
1620d24de9dSSimon Glass    try:
1630d24de9dSSimon Glass        fd = open(fname, 'r')
1640d24de9dSSimon Glass    except IOError:
165a920a17bSPaul Burton        print("Warning: Cannot find alias file '%s'" % fname)
1660d24de9dSSimon Glass        return
1670d24de9dSSimon Glass
1680d24de9dSSimon Glass    re_line = re.compile('alias\s+(\S+)\s+(.*)')
1690d24de9dSSimon Glass    for line in fd.readlines():
1700d24de9dSSimon Glass        line = line.strip()
1710d24de9dSSimon Glass        if not line or line[0] == '#':
1720d24de9dSSimon Glass            continue
1730d24de9dSSimon Glass
1740d24de9dSSimon Glass        m = re_line.match(line)
1750d24de9dSSimon Glass        if not m:
176a920a17bSPaul Burton            print("Warning: Alias file line '%s' not understood" % line)
1770d24de9dSSimon Glass            continue
1780d24de9dSSimon Glass
1790d24de9dSSimon Glass        list = alias.get(m.group(1), [])
1800d24de9dSSimon Glass        for item in m.group(2).split(','):
1810d24de9dSSimon Glass            item = item.strip()
1820d24de9dSSimon Glass            if item:
1830d24de9dSSimon Glass                list.append(item)
1840d24de9dSSimon Glass        alias[m.group(1)] = list
1850d24de9dSSimon Glass
1860d24de9dSSimon Glass    fd.close()
1870d24de9dSSimon Glass
18887d65558SVikram Narayanandef CreatePatmanConfigFile(config_fname):
18987d65558SVikram Narayanan    """Creates a config file under $(HOME)/.patman if it can't find one.
19087d65558SVikram Narayanan
19187d65558SVikram Narayanan    Args:
19287d65558SVikram Narayanan        config_fname: Default config filename i.e., $(HOME)/.patman
19387d65558SVikram Narayanan
19487d65558SVikram Narayanan    Returns:
19587d65558SVikram Narayanan        None
19687d65558SVikram Narayanan    """
19787d65558SVikram Narayanan    name = gitutil.GetDefaultUserName()
19887d65558SVikram Narayanan    if name == None:
19987d65558SVikram Narayanan        name = raw_input("Enter name: ")
20087d65558SVikram Narayanan
20187d65558SVikram Narayanan    email = gitutil.GetDefaultUserEmail()
20287d65558SVikram Narayanan
20387d65558SVikram Narayanan    if email == None:
20487d65558SVikram Narayanan        email = raw_input("Enter email: ")
20587d65558SVikram Narayanan
20687d65558SVikram Narayanan    try:
20787d65558SVikram Narayanan        f = open(config_fname, 'w')
20887d65558SVikram Narayanan    except IOError:
209a920a17bSPaul Burton        print("Couldn't create patman config file\n")
21087d65558SVikram Narayanan        raise
21187d65558SVikram Narayanan
212a920a17bSPaul Burton    print("[alias]\nme: %s <%s>" % (name, email), file=f)
21387d65558SVikram Narayanan    f.close();
21487d65558SVikram Narayanan
2158568baedSDoug Andersondef _UpdateDefaults(parser, config):
2168568baedSDoug Anderson    """Update the given OptionParser defaults based on config.
2178568baedSDoug Anderson
2188568baedSDoug Anderson    We'll walk through all of the settings from the parser
2198568baedSDoug Anderson    For each setting we'll look for a default in the option parser.
2208568baedSDoug Anderson    If it's found we'll update the option parser default.
2218568baedSDoug Anderson
2228568baedSDoug Anderson    The idea here is that the .patman file should be able to update
2238568baedSDoug Anderson    defaults but that command line flags should still have the final
2248568baedSDoug Anderson    say.
2258568baedSDoug Anderson
2268568baedSDoug Anderson    Args:
2278568baedSDoug Anderson        parser: An instance of an OptionParser whose defaults will be
2288568baedSDoug Anderson            updated.
229a1dcee84SDoug Anderson        config: An instance of _ProjectConfigParser that we will query
2308568baedSDoug Anderson            for settings.
2318568baedSDoug Anderson    """
2328568baedSDoug Anderson    defaults = parser.get_default_values()
2338568baedSDoug Anderson    for name, val in config.items('settings'):
2348568baedSDoug Anderson        if hasattr(defaults, name):
2358568baedSDoug Anderson            default_val = getattr(defaults, name)
2368568baedSDoug Anderson            if isinstance(default_val, bool):
2378568baedSDoug Anderson                val = config.getboolean('settings', name)
2388568baedSDoug Anderson            elif isinstance(default_val, int):
2398568baedSDoug Anderson                val = config.getint('settings', name)
2408568baedSDoug Anderson            parser.set_default(name, val)
2418568baedSDoug Anderson        else:
242a920a17bSPaul Burton            print("WARNING: Unknown setting %s" % name)
2438568baedSDoug Anderson
2448895b3e1SSimon Glassdef _ReadAliasFile(fname):
2458895b3e1SSimon Glass    """Read in the U-Boot git alias file if it exists.
2468895b3e1SSimon Glass
2478895b3e1SSimon Glass    Args:
2488895b3e1SSimon Glass        fname: Filename to read.
2498895b3e1SSimon Glass    """
2508895b3e1SSimon Glass    if os.path.exists(fname):
2518895b3e1SSimon Glass        bad_line = None
2528895b3e1SSimon Glass        with open(fname) as fd:
2538895b3e1SSimon Glass            linenum = 0
2548895b3e1SSimon Glass            for line in fd:
2558895b3e1SSimon Glass                linenum += 1
2568895b3e1SSimon Glass                line = line.strip()
2578895b3e1SSimon Glass                if not line or line.startswith('#'):
2588895b3e1SSimon Glass                    continue
2598895b3e1SSimon Glass                words = line.split(' ', 2)
2608895b3e1SSimon Glass                if len(words) < 3 or words[0] != 'alias':
2618895b3e1SSimon Glass                    if not bad_line:
2628895b3e1SSimon Glass                        bad_line = "%s:%d:Invalid line '%s'" % (fname, linenum,
2638895b3e1SSimon Glass                                                                line)
2648895b3e1SSimon Glass                    continue
2658895b3e1SSimon Glass                alias[words[1]] = [s.strip() for s in words[2].split(',')]
2668895b3e1SSimon Glass        if bad_line:
267a920a17bSPaul Burton            print(bad_line)
2688895b3e1SSimon Glass
269a1dcee84SDoug Andersondef Setup(parser, project_name, config_fname=''):
2700d24de9dSSimon Glass    """Set up the settings module by reading config files.
2710d24de9dSSimon Glass
2720d24de9dSSimon Glass    Args:
2738568baedSDoug Anderson        parser:         The parser to update
274a1dcee84SDoug Anderson        project_name:   Name of project that we're working on; we'll look
275a1dcee84SDoug Anderson            for sections named "project_section" as well.
2760d24de9dSSimon Glass        config_fname:   Config filename to read ('' for default)
2770d24de9dSSimon Glass    """
2788895b3e1SSimon Glass    # First read the git alias file if available
2798895b3e1SSimon Glass    _ReadAliasFile('doc/git-mailrc')
280a1dcee84SDoug Anderson    config = _ProjectConfigParser(project_name)
2810d24de9dSSimon Glass    if config_fname == '':
2822b36c75dSVikram Narayanan        config_fname = '%s/.patman' % os.getenv('HOME')
28387d65558SVikram Narayanan
28487d65558SVikram Narayanan    if not os.path.exists(config_fname):
285a920a17bSPaul Burton        print("No config file found ~/.patman\nCreating one...\n")
28687d65558SVikram Narayanan        CreatePatmanConfigFile(config_fname)
28787d65558SVikram Narayanan
2888568baedSDoug Anderson    config.read(config_fname)
2890d24de9dSSimon Glass
2908568baedSDoug Anderson    for name, value in config.items('alias'):
2910d24de9dSSimon Glass        alias[name] = value.split(',')
2920d24de9dSSimon Glass
2938568baedSDoug Anderson    _UpdateDefaults(parser, config)
2940d24de9dSSimon Glass
2950d24de9dSSimon Glass# These are the aliases we understand, indexed by alias. Each member is a list.
2960d24de9dSSimon Glassalias = {}
297a1dcee84SDoug Anderson
298a1dcee84SDoug Andersonif __name__ == "__main__":
299a1dcee84SDoug Anderson    import doctest
300a1dcee84SDoug Anderson
301a1dcee84SDoug Anderson    doctest.testmod()
302