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