buildpackage-rpm: patch-export from development branch
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Thu, 6 Feb 2014 13:24:54 +0000 (15:24 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Fri, 14 Nov 2014 12:47:20 +0000 (14:47 +0200)
Adds git-buildpackage-rpm --patch-export support for the 'orphan
packaging' development model (where packaging files and development sources are kept in separate
branches).

New functionality:
1. If patch-export is enabled and gbp detects that the current branch
   has a development/patch-queue branch it exports the patches from there,
   instead of the tip of the packaging branch.
2. If gbp detects that the current (or exported) branch is a
   development/patch-queue branch it automatically enables patch-export
   and exports packaging files from the base branch (instead of the
   development/patch-queue branch.

Also, add a new '--git-patch-export-rev' command line option with which
the user can explicitly set the treeish from which patches are generated
(i.e. HEAD..<patch-export-rev>)

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gbp/scripts/buildpackage_rpm.py

index b57c528..1ada638 100755 (executable)
@@ -43,7 +43,8 @@ from gbp.scripts.common.buildpackage import (index_name, wc_names,
                                              git_archive_single, dump_tree,
                                              write_wc, drop_index)
 from gbp.pkg import (compressor_opts, compressor_aliases)
-from gbp.scripts.pq_rpm import update_patch_series
+from gbp.scripts.pq_rpm import update_patch_series, parse_spec
+from gbp.scripts.common.pq import is_pq_branch, pq_branch_name, pq_branch_base
 
 
 class GbpAutoGenerateError(GbpError):
@@ -193,6 +194,53 @@ def get_tree(repo, tree_name):
     return tree
 
 
+def get_current_branch(repo):
+    """Get the currently checked-out branch"""
+    try:
+        branch = repo.get_branch()
+    except GitRepositoryError:
+        branch = None
+    return branch
+
+
+def guess_export_params(repo, options):
+    """Get commit and tree from where to export packaging and patches"""
+    tree = None
+    branch = None
+    if options.export in wc_names.keys() + [index_name, 'HEAD']:
+        branch = get_current_branch(repo)
+    elif options.export in repo.get_local_branches():
+        branch = options.export
+    if branch:
+        if is_pq_branch(branch, options):
+            packaging_branch = pq_branch_base(branch, options)
+            if repo.has_branch(packaging_branch):
+                gbp.log.info("It seems you're building a development/patch-"
+                             "queue branch. Export target changed to '%s' and "
+                             "patch-export enabled!" % packaging_branch)
+                options.patch_export = True
+                if not options.patch_export_rev:
+                    options.patch_export_rev = options.export
+                options.export = packaging_branch
+            else:
+                gbp.log.warn("It seems you're building a development/patch-"
+                             "queue branch. No corresponding packaging branch "
+                             "found. Build may fail!")
+        elif options.patch_export and not options.patch_export_rev:
+            tree = get_tree(repo, options.export)
+            spec = parse_spec(options, repo, treeish=tree)
+            pq_branch = pq_branch_name(branch, options, spec.version)
+            if repo.has_branch(pq_branch):
+                gbp.log.info("Exporting patches from development/patch-queue "
+                             "branch '%s'" % pq_branch)
+                options.patch_export_rev = pq_branch
+    if tree is None:
+        tree = get_tree(repo, options.export)
+        spec = parse_spec(options, repo, treeish=tree)
+
+    # Return tree-ish object and relative spec path for for exporting packaging
+    return tree, spec.specpath
+
 def git_archive_build_orig(repo, spec, output_dir, options):
     """
     Build orig tarball using git-archive
@@ -230,15 +278,6 @@ def export_patches(repo, spec, export_treeish, options):
     """
     Generate patches and update spec file
     """
-    # Fail if we have local patch files not marked for manual maintenance.
-    # Ignore patches listed in spec but not found in packaging dir
-    for patch in spec.patchseries():
-        if os.path.exists(patch.path):
-            raise GbpAutoGenerateError(
-                    'Patches not marked for manual maintenance found, '
-                    'refusing to overwrite! Fix by applying them to packaging '
-                    'branch and removing the files.')
-
     try:
         upstream_tree = get_upstream_tree(repo, spec, options)
         update_patch_series(repo, spec, upstream_tree, export_treeish, options)
@@ -389,6 +428,7 @@ def parse_args(argv, prefix, git_treeish=None):
     orig_group.add_config_file_option(option_name="orig-prefix", dest="orig_prefix")
     branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch")
     branch_group.add_config_file_option(option_name="packaging-branch", dest="packaging_branch")
+    branch_group.add_config_file_option(option_name="pq-branch", dest="pq_branch")
     branch_group.add_boolean_config_file_option(option_name = "ignore-branch", dest="ignore_branch")
     branch_group.add_boolean_config_file_option(option_name = "submodules", dest="with_submodules")
     cmd_group.add_config_file_option(option_name="builder", dest="builder",
@@ -426,6 +466,10 @@ def parse_args(argv, prefix, git_treeish=None):
     export_group.add_option("--git-export-only", action="store_true", dest="export_only", default=False,
                       help="only export packaging files, don't build")
     export_group.add_boolean_config_file_option("patch-export", dest="patch_export")
+    export_group.add_option("--git-patch-export-rev", dest="patch_export_rev",
+                      metavar="TREEISH",
+                      help="[experimental] Export patches from treeish object "
+                           "TREEISH")
     export_group.add_config_file_option("patch-export-ignore-path",
                                         dest="patch_export_ignore_path")
     export_group.add_config_file_option("patch-export-compress", dest="patch_export_compress")
@@ -482,12 +526,11 @@ def main(argv):
         gbp.log.err(err)
         return 1
 
-    try:
-        branch = repo.get_branch()
-    except GitRepositoryError:
-        branch = None
+    branch = get_current_branch(repo)
 
     try:
+        tree, relative_spec_path = guess_export_params(repo, options)
+
         if not options.export_only:
             Command(options.cleaner, shell=True)()
         if not options.ignore_new:
@@ -508,18 +551,8 @@ def main(argv):
         gbp.log.debug("Dumping tree '%s' to '%s'" % (options.export, dump_dir))
         if not dump_tree(repo, dump_dir, tree, options.with_submodules):
             raise GbpError
-        # Find and parse spec from dump dir to get version etc.
-        if options.spec_file != 'auto':
-            specfile = os.path.join(dump_dir, options.spec_file)
-            options.packaging_dir = os.path.dirname(specfile)
-            if not os.path.exists(specfile):
-                raise rpm.NoSpecError("Failed to export specfile: %s" % options.spec_file)
-            spec = rpm.SpecFile(specfile)
-        else:
-            spec = rpm.guess_spec(os.path.join(dump_dir, options.packaging_dir),
-                                  True,
-                                  os.path.basename(repo.path) + '.spec')
-        gbp.log.debug("Using spec file '%s'" % spec.specfile)
+        # Parse spec from dump dir to get version etc.
+        spec = rpm.SpecFile(os.path.join(dump_dir, relative_spec_path))
 
         if not options.tag_only:
             # Setup builder opts
@@ -527,7 +560,11 @@ def main(argv):
 
             # Generate patches, if requested
             if options.patch_export and not is_native(repo, options):
-                export_patches(repo, spec, tree, options)
+                if options.patch_export_rev:
+                    patch_tree = get_tree(repo, options.patch_export_rev)
+                else:
+                    patch_tree = tree
+                export_patches(repo, spec, patch_tree, options)
 
             # Prepare final export dirs
             export_dir = prepare_export_dir(options.export_dir)