From patchwork Tue Dec 4 00:43:18 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Doug Anderson X-Patchwork-Id: 203517 X-Patchwork-Delegate: sjg@chromium.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from theia.denx.de (theia.denx.de [85.214.87.163]) by ozlabs.org (Postfix) with ESMTP id A37BE2C008F for ; Tue, 4 Dec 2012 11:43:35 +1100 (EST) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 28DAB4A170; Tue, 4 Dec 2012 01:43:34 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id EObkAcZq4SxP; Tue, 4 Dec 2012 01:43:33 +0100 (CET) Received: from theia.denx.de (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id C43344A152; Tue, 4 Dec 2012 01:43:30 +0100 (CET) Received: from localhost (localhost [127.0.0.1]) by theia.denx.de (Postfix) with ESMTP id 3DC834A152 for ; Tue, 4 Dec 2012 01:43:28 +0100 (CET) X-Virus-Scanned: Debian amavisd-new at theia.denx.de Received: from theia.denx.de ([127.0.0.1]) by localhost (theia.denx.de [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id sLPWSE9Lo63a for ; Tue, 4 Dec 2012 01:43:27 +0100 (CET) X-policyd-weight: NOT_IN_SBL_XBL_SPAMHAUS=-1.5 NOT_IN_SPAMCOP=-1.5 NOT_IN_BL_NJABL=-1.5 (only DNSBL check requested) Received: from mail-wg0-f74.google.com (mail-wg0-f74.google.com [74.125.82.74]) by theia.denx.de (Postfix) with ESMTPS id 02B304A132 for ; Tue, 4 Dec 2012 01:43:25 +0100 (CET) Received: by mail-wg0-f74.google.com with SMTP id dt14so407281wgb.3 for ; Mon, 03 Dec 2012 16:43:25 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:in-reply-to:references :x-gm-message-state; bh=Jhge/7jnwZmPPv+MSEH0yAqfyM390LZMgF5WDqgLIRM=; b=EHmd7Jqw6yln05fLqgTqaVncmFVo0wNbkASVt75OeeEtGJx7jaHG10VQucEA4O3j1F R+xBUJwJK0oiLtBUT9VSWbiVkg1Ny2hVzIxX+DMWtbg/1SgEUIEzvciKrLGy+VpFpIL1 5S6+yyBFU1oXeow0N7EmNAfq9JgKNAj5coob+eZXyIr7qflRfTCq2e6iTYoMsAI4AP0x jfi6UGw7UnC10mRBMTWL2Y5ido74yFQJaQfUawJ+03k8utriqT9fDgllG6klBLOhui+/ stTTljOJW5shcZyvPn4fq1S7qDxirg9TGF0aGSRqwDSCA8ezk/Eu2nEwFrcqRzjcwHJK zv2Q== Received: by 10.14.216.197 with SMTP id g45mr12253000eep.3.1354581805274; Mon, 03 Dec 2012 16:43:25 -0800 (PST) Received: from hpza10.eem.corp.google.com ([74.125.121.33]) by gmr-mx.google.com with ESMTPS id u8si3560874een.1.2012.12.03.16.43.25 (version=TLSv1/SSLv3 cipher=AES128-SHA); Mon, 03 Dec 2012 16:43:25 -0800 (PST) Received: from tictac.mtv.corp.google.com (tictac.mtv.corp.google.com [172.22.73.80]) by hpza10.eem.corp.google.com (Postfix) with ESMTP id B049A20005C; Mon, 3 Dec 2012 16:43:24 -0800 (PST) Received: by tictac.mtv.corp.google.com (Postfix, from userid 121310) id 10E2C819C4; Mon, 3 Dec 2012 16:43:23 -0800 (PST) From: Doug Anderson To: Simon Glass Date: Mon, 3 Dec 2012 16:43:18 -0800 Message-Id: <1354581799-775-3-git-send-email-dianders@chromium.org> X-Mailer: git-send-email 1.7.7.3 In-Reply-To: <1354581799-775-1-git-send-email-dianders@chromium.org> References: <1354321745-1359-1-git-send-email-dianders@chromium.org> <1354581799-775-1-git-send-email-dianders@chromium.org> X-Gm-Message-State: ALoCoQkfqW5ZJz/2wjlDaM5B3kV0aVSUASHpjexvv8/qutAFvvNwebfILawJk8NcSD89+FuiKfhDdZyAXeMZgXg/PV3lOPa97G89rKu2ROIYJ7jOsXXAmRi0O8/GPXSFlHQPqeb9Uh/v67U2+E8ErstnYup8GSH+q7j3PTw3c2RljbYCPrmTDpt8CG0SZWQZJrXMcVGjPWMY Cc: u-boot@lists.denx.de Subject: [U-Boot] [PATCH v2 3/4] patman: Add the concept of multiple projects X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.11 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: u-boot-bounces@lists.denx.de Errors-To: u-boot-bounces@lists.denx.de There are cases that we want to support different settings (or maybe even different aliases) for different projects. Add support for this by: * Adding detection for two big projects: U-Boot and Linux. * Adding default settings for Linux (U-Boot is already good with the standard patman defaults). * Extend the new "settings" feature in .patman to specify per-project settings. Signed-off-by: Doug Anderson Acked-by: Simon Glass --- Changes in v2: - Added requested short option: '-p'. tools/patman/README | 13 ++++ tools/patman/patman.py | 9 +++- tools/patman/project.py | 43 +++++++++++++ tools/patman/settings.py | 147 +++++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 tools/patman/project.py diff --git a/tools/patman/README b/tools/patman/README index 2743da9..1832ebd 100644 --- a/tools/patman/README +++ b/tools/patman/README @@ -114,6 +114,19 @@ verbose: True <<< +If you want to adjust settings (or aliases) that affect just a single +project you can add a section that looks like [project_settings] or +[project_alias]. If you want to use tags for your linux work, you could +do: + +>>> + +[linux_settings] +process_tags: True + +<<< + + How to run it ============= diff --git a/tools/patman/patman.py b/tools/patman/patman.py index b327c67..2e9e5dc 100755 --- a/tools/patman/patman.py +++ b/tools/patman/patman.py @@ -34,6 +34,7 @@ import checkpatch import command import gitutil import patchstream +import project import settings import terminal import test @@ -59,6 +60,9 @@ parser.add_option('--cc-cmd', dest='cc_cmd', type='string', action='store', default=None, help='Output cc list for patch file (used by git)') parser.add_option('--no-tags', action='store_false', dest='process_tags', default=True, help="Don't process subject tags as aliaes") +parser.add_option('-p', '--project', default=project.DetectProject(), + help="Project name; affects default option values and " + "aliases [default: %default]") parser.usage = """patman [options] @@ -66,7 +70,10 @@ Create patches from commits in a branch, check them and email them as specified by tags you place in the commits. Use -n to """ -settings.Setup(parser, '') +# Parse options twice: first to get the project and second to handle +# defaults properly (which depends on project). +(options, args) = parser.parse_args() +settings.Setup(parser, options.project, '') (options, args) = parser.parse_args() # Run our meagre tests diff --git a/tools/patman/project.py b/tools/patman/project.py new file mode 100644 index 0000000..4f7b2b3 --- /dev/null +++ b/tools/patman/project.py @@ -0,0 +1,43 @@ +# Copyright (c) 2012 The Chromium OS Authors. +# +# See file CREDITS for list of people who contributed to this +# project. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2 of +# the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, +# MA 02111-1307 USA +# + +import os.path + +import gitutil + +def DetectProject(): + """Autodetect the name of the current project. + + This looks for signature files/directories that are unlikely to exist except + in the given project. + + Returns: + The name of the project, like "linux" or "u-boot". Returns "unknown" + if we can't detect the project. + """ + top_level = gitutil.GetTopLevel() + + if os.path.exists(os.path.join(top_level, "include", "u-boot")): + return "u-boot" + elif os.path.exists(os.path.join(top_level, "kernel")): + return "linux" + + return "unknown" diff --git a/tools/patman/settings.py b/tools/patman/settings.py index 5208f7d..084d1b8 100644 --- a/tools/patman/settings.py +++ b/tools/patman/settings.py @@ -26,6 +26,140 @@ import re import command import gitutil +"""Default settings per-project. + +These are used by _ProjectConfigParser. Settings names should match +the "dest" of the option parser from patman.py. +""" +_default_settings = { + "u-boot": {}, + "linux": { + "process_tags": "False", + } +} + +class _ProjectConfigParser(ConfigParser.SafeConfigParser): + """ConfigParser that handles projects. + + There are two main goals of this class: + - Load project-specific default settings. + - Merge general default settings/aliases with project-specific ones. + + # Sample config used for tests below... + >>> import StringIO + >>> sample_config = ''' + ... [alias] + ... me: Peter P. + ... enemies: Evil + ... + ... [sm_alias] + ... enemies: Green G. + ... + ... [sm2_alias] + ... enemies: Doc O. + ... + ... [settings] + ... am_hero: True + ... ''' + + # Check to make sure that bogus project gets general alias. + >>> config = _ProjectConfigParser("zzz") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> config.get("alias", "enemies") + 'Evil ' + + # Check to make sure that alias gets overridden by project. + >>> config = _ProjectConfigParser("sm") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> config.get("alias", "enemies") + 'Green G. ' + + # Check to make sure that settings get merged with project. + >>> config = _ProjectConfigParser("linux") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> sorted(config.items("settings")) + [('am_hero', 'True'), ('process_tags', 'False')] + + # Check to make sure that settings works with unknown project. + >>> config = _ProjectConfigParser("unknown") + >>> config.readfp(StringIO.StringIO(sample_config)) + >>> sorted(config.items("settings")) + [('am_hero', 'True')] + """ + def __init__(self, project_name): + """Construct _ProjectConfigParser. + + In addition to standard SafeConfigParser initialization, this also loads + project defaults. + + Args: + project_name: The name of the project. + """ + self._project_name = project_name + ConfigParser.SafeConfigParser.__init__(self) + + # Update the project settings in the config based on + # the _default_settings global. + project_settings = "%s_settings" % project_name + if not self.has_section(project_settings): + self.add_section(project_settings) + project_defaults = _default_settings.get(project_name, {}) + for setting_name, setting_value in project_defaults.iteritems(): + self.set(project_settings, setting_name, setting_value) + + def get(self, section, option, *args, **kwargs): + """Extend SafeConfigParser to try project_section before section. + + Args: + See SafeConfigParser. + Returns: + See SafeConfigParser. + """ + try: + return ConfigParser.SafeConfigParser.get( + self, "%s_%s" % (self._project_name, section), option, + *args, **kwargs + ) + except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): + return ConfigParser.SafeConfigParser.get( + self, section, option, *args, **kwargs + ) + + def items(self, section, *args, **kwargs): + """Extend SafeConfigParser to add project_section to section. + + Args: + See SafeConfigParser. + Returns: + See SafeConfigParser. + """ + project_items = [] + has_project_section = False + top_items = [] + + # Get items from the project section + try: + project_items = ConfigParser.SafeConfigParser.items( + self, "%s_%s" % (self._project_name, section), *args, **kwargs + ) + has_project_section = True + except ConfigParser.NoSectionError: + pass + + # Get top-level items + try: + top_items = ConfigParser.SafeConfigParser.items( + self, section, *args, **kwargs + ) + except ConfigParser.NoSectionError: + # If neither section exists raise the error on... + if not has_project_section: + raise + + item_dict = dict(top_items) + item_dict.update(project_items) + return item_dict.items() + def ReadGitAliases(fname): """Read a git alias file. This is in the form used by git: @@ -102,7 +236,7 @@ def _UpdateDefaults(parser, config): Args: parser: An instance of an OptionParser whose defaults will be updated. - config: An instance of SafeConfigParser that we will query + config: An instance of _ProjectConfigParser that we will query for settings. """ defaults = parser.get_default_values() @@ -117,14 +251,16 @@ def _UpdateDefaults(parser, config): else: print "WARNING: Unknown setting %s" % name -def Setup(parser, config_fname=''): +def Setup(parser, project_name, config_fname=''): """Set up the settings module by reading config files. Args: parser: The parser to update + project_name: Name of project that we're working on; we'll look + for sections named "project_section" as well. config_fname: Config filename to read ('' for default) """ - config = ConfigParser.SafeConfigParser() + config = _ProjectConfigParser(project_name) if config_fname == '': config_fname = '%s/.patman' % os.getenv('HOME') @@ -141,3 +277,8 @@ def Setup(parser, config_fname=''): # These are the aliases we understand, indexed by alias. Each member is a list. alias = {} + +if __name__ == "__main__": + import doctest + + doctest.testmod()