Implement 'devel' subcommand
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Sat, 8 Feb 2014 08:58:49 +0000 (10:58 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 25 Mar 2014 11:26:38 +0000 (13:26 +0200)
This command is to support another development model where packaging
files are maintained in a separate branch and source code changes in
separate development branch(es). The devel command is designed for
managing these development branches.

The subcommand provides the following actions:
1. gbs devel start: initialize development branch
2. gbs devel export: export patches from development branch back onto
                     the packaging branch
3. gbs devel drop: delete the development branch
4. gbs devel switch: switch between packaging and development branches
5. gbs devel convert: convert a package from the "old single branch"
                      development model to the new model

Change-Id: I2eec2b2ed73f50e03a9f7a2e5f6d24fc765c3a5b
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gitbuildsys/cmd_devel.py [new file with mode: 0644]
gitbuildsys/conf.py
packaging/gbs.spec
tools/gbs

diff --git a/gitbuildsys/cmd_devel.py b/gitbuildsys/cmd_devel.py
new file mode 100644 (file)
index 0000000..09d1913
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2014 Intel, Inc.
+#
+# 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; version 2 of the License
+#
+# 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.
+
+"""Implementation of subcmd: devel
+"""
+
+import os
+import datetime
+import glob
+import re
+
+from gitbuildsys.cmd_export import get_packaging_dir
+from gitbuildsys.conf import configmgr, BrainConfigParser
+from gitbuildsys.errors import GbsError
+from gitbuildsys.log import LOGGER as log
+from gitbuildsys.utils import guess_spec, edit_file, Temp
+
+from gbp.scripts.pq_rpm import main as gbp_pq_rpm
+from gbp.rpm.git import GitRepositoryError, RpmGitRepository
+
+def compose_gbp_args(repo, tmp_dir, spec, args):
+    """Compose command line arguments for gbp-pq-rpm"""
+    upstream_tag = configmgr.get_arg_conf(args, 'upstream_tag')
+    # transform variables from shell to python convention ${xxx} -> %(xxx)s
+    upstream_tag = re.sub(r'\$\{([^}]+)\}', r'%(\1)s', upstream_tag)
+
+    packaging_dir = get_packaging_dir(args)
+
+    # Compose the list of command line arguments
+    argv = ["argv[0] placeholder",
+            "--color-scheme=magenta:green:yellow:red",
+            "--vendor=Tizen",
+            "--tmp-dir=%s" % tmp_dir,
+            "--packaging-dir=%s" % packaging_dir,
+            "--new-packaging-dir=%s" % packaging_dir,
+            "--spec-file=%s" % spec,
+            "--upstream-tag=%s" % upstream_tag,
+            "--pq-branch=development/%(branch)s/%(upstreamversion)s",
+            "--import-files=.gbs.conf",
+            "--patch-export-compress=100k",
+            "--patch-export-ignore-path=^(%s/.*|.gbs.conf)" % packaging_dir]
+    if args.debug:
+        argv.append("--verbose")
+
+    return argv
+
+def update_local_conf(repo, values):
+    """Create/update local gbs.conf"""
+    parser = BrainConfigParser()
+    conf_fn = os.path.join(repo.path, '.gbs.conf')
+    log.info('Updating local .gbs.conf')
+    with open(conf_fn, 'a+') as conf_fp:
+        parser.readfp(conf_fp)
+    for section, items in values.iteritems():
+        for key, value in items.iteritems():
+            parser.set_into_file(section, key, value)
+    parser.update()
+
+    log.info('Committing local .gbs.conf to git')
+    repo.add_files(['.gbs.conf'])
+    repo.commit_all(msg="Autoupdate local .gbs.conf\n\nGbp-Rpm: Ignore")
+
+
+def main(args):
+    """gbs devel entry point."""
+
+    try:
+        repo = RpmGitRepository(args.gitdir)
+    except GitRepositoryError, err:
+        raise GbsError(str(err))
+
+    tmp = Temp(prefix='gbp_', dirn=configmgr.get('tmpdir', 'general'),
+                     directory=True)
+    packaging_dir = get_packaging_dir(args)
+
+    # Guess spec from correct branch
+    packaging_branch = configmgr.get('packaging_branch', 'orphan-devel')
+    commit_id = packaging_branch if packaging_branch else 'WC.UNTRACKED'
+    specfile = guess_spec(repo.path, packaging_dir, args.spec, commit_id)[0]
+
+    # Get current branch
+    try:
+        current_branch = repo.get_branch()
+    except GitRepositoryError:
+        current_branch = None
+
+    gbp_args = compose_gbp_args(repo, tmp.path, specfile, args)
+
+    # Run gbp command
+    if args.action == 'start':
+        ret = gbp_pq_rpm(gbp_args + ['import'])
+        if not ret:
+            update_local_conf(repo, {'orphan-devel':
+                                     {'packaging_branch': current_branch}})
+    elif args.action == 'export':
+        log.info('Exporting patches to packaging branch')
+        ret = gbp_pq_rpm(gbp_args + ['export'])
+    elif args.action == 'switch':
+        ret = gbp_pq_rpm(gbp_args + ['switch'])
+    elif args.action == 'drop':
+        ret = gbp_pq_rpm(gbp_args + ['drop'])
+    elif args.action == 'convert':
+        log.info('Converting package to orphan-packaging git layout')
+        ret = gbp_pq_rpm(gbp_args + ['convert'])
+        if not ret:
+            log.info("You can now create the development branch with "
+                      "'gbs devel start'")
+    if ret:
+        raise GbsError('Action failed!')
+
index 5fbdcf4874cef4be4e9fd10bc13c369a1b85a862..f1ea4dfa37b0a57cf0c4903813b26c1fa3240aeb 100644 (file)
@@ -184,6 +184,9 @@ class ConfigMgr(object):
                 'packaging_dir': 'packaging',
                 'work_dir': '.',
             },
+            'orphan-devel': {
+                'packaging_branch': '',
+            },
     }
 
     DEFAULT_CONF_TEMPLATE = '''[general]
index f3d2db115605db080f5f3c05f5a2e264726b8040..9f7c32f16ec4b56287c96586402fff9aaf63eee8 100644 (file)
@@ -130,6 +130,7 @@ rm -rf %{buildroot}
 %{python_sitelib}/gitbuildsys/cmd_chroot.py*
 %{python_sitelib}/gitbuildsys/cmd_clone.py*
 %{python_sitelib}/gitbuildsys/cmd_createimage.py*
+%{python_sitelib}/gitbuildsys/cmd_devel.py*
 %{python_sitelib}/gitbuildsys/cmd_import.py*
 %{python_sitelib}/gitbuildsys/cmd_pull.py*
 %{python_sitelib}/gitbuildsys/cmd_submit.py*
index dbae6cc981348fe9754135b123ee0f82a6a54e21..5d69c382703e9c11ca2878532becef86b2a95ee9 100755 (executable)
--- a/tools/gbs
+++ b/tools/gbs
@@ -482,6 +482,32 @@ def pull_parser(parser):
                         help='update all branches')
     return parser
 
+@subparser
+def devel_parser(parser):
+    """Manage devel branches
+    Examples:
+      $ gbs devel start
+      $ gbs devel export
+    """
+
+    parser.add_argument('gitdir', nargs='?', type=os.path.abspath,
+                        default=os.getcwd(),
+                        action=SearchConfAction,
+                        help='path to git repository')
+    parser.add_argument('--packaging-dir',
+                        help='directory containing packaging files')
+    parser.add_argument('--spec', type=basename_type,
+                        help='specify a spec file to use. It should be a file '
+                        'name that GBS will find it in packaging dir')
+    parser.add_argument('--upstream-tag',
+                        help="upstream tag format, '${upstreamversion}' is "
+                        'expanded to the version in the spec file. '
+                        "E.g. 'v${upstreamversion}'")
+    parser.add_argument('action', choices=['start', 'export', 'drop', 'switch',
+                        'convert'],
+                        help='Action to take')
+    return parser
+
 def main(argv):
     """Script entry point."""