import-srpm: support for patch import
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Wed, 27 Jun 2012 15:12:01 +0000 (18:12 +0300)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Fri, 14 Nov 2014 12:46:24 +0000 (14:46 +0200)
Adds a new commandline option '--patch-import' for importing patches
into the source tree in packaging branch. When enabled, gbp applies and
commits all patches (not marked for manual maintenance) into the
packaging branch. If this succeeds, it also removes all imported patch
files from the packaging directory and the spec file.

Currently only supported for non-orphan-packaging.

This setting is true by default which should make more sense as the
developer wants to do code development in the packaging branch (if
he/she selects to use non-orphan packaging).

However, patch-import is force-disabled if in bare git repository. We
cannot support this, currently.

Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
gbp/config.py
gbp/scripts/import_srpm.py
tests/component/rpm/test_import_srpm.py

index fdfc66c7ad1e461c4562bd9788fcd782ff28c1df..2c4917a379394602906cda8525b66d3ba7da274a 100644 (file)
@@ -613,6 +613,7 @@ class GbpOptionParserRpm(GbpOptionParser):
             'patch-export-compress'     : '0',
             'patch-export-ignore-path'  : '',
             'patch-export-squash-until' : '',
+            'patch-import'              : 'True',
             'spec-vcs-tag'              : '',
             'merge'                     : 'False',
             'pristine-tarball-name'     : 'auto',
@@ -660,6 +661,9 @@ class GbpOptionParserRpm(GbpOptionParser):
                 "Squash commits (from upstream) until given tree-ish into one "
                 "big diff, format is '<commit_ish>[:<filename_base>]'. "
                 "Default is '%(patch-export-squash-until)s'",
+            'patch-import':
+                "Import patches to the packaging branch, default is "
+                "'%(patch-import)s'",
             'spec-vcs-tag':
                 "Set/update the 'VCS:' tag in the spec file, empty value "
                 "removes the tag entirely, default is '%(spec-vcs-tag)s'",
index a04e10756f51beaa9ae12c3c8550d2413ee44216..ff946194a7f563a86f67ff78da275dd1b7a49ac1 100755 (executable)
@@ -37,6 +37,8 @@ from gbp.config import (GbpOptionParserRpm, GbpOptionGroup,
                        no_upstream_branch_msg)
 from gbp.errors import GbpError
 import gbp.log
+from gbp.scripts.pq_rpm import safe_patches, rm_patch_files, get_packager
+from gbp.scripts.common.pq import apply_and_commit_patch
 from gbp.pkg import parse_archive_filename
 
 no_packaging_branch_msg = """
@@ -44,10 +46,21 @@ Repository does not have branch '%s' for packaging/distribution sources.
 You need to reate it or use --packaging-branch to specify it.
 """
 
+PATCH_AUTODELETE_COMMIT_MSG = """
+Autoremove imported patches from packaging
+
+Removed all imported patches from %s
+and patch files from the packaging dir.
+"""
+
 class SkipImport(Exception):
     """Nothing imported"""
     pass
 
+class PatchImportError(Exception):
+    """Patch import failed"""
+    pass
+
 
 def download_file(target_dir, url):
     """Download a remote file"""
@@ -104,6 +117,46 @@ def set_bare_repo_options(options):
     if options.pristine_tar:
         gbp.log.info("Bare repository: setting %s option '--no-pristine-tar'")
         options.pristine_tar = False
+    if options.patch_import:
+        gbp.log.info("Bare repository: setting %s option '--no-patch-import')")
+        options.patch_import = False
+
+
+def import_spec_patches(repo, spec, dirs):
+    """
+    Import patches from a spec file to the current branch
+    """
+    queue = spec.patchseries()
+    if len(queue) == 0:
+        return
+
+    gbp.log.info("Importing patches to '%s' branch" % repo.get_branch())
+    tmpdir = tempfile.mkdtemp(dir=dirs['tmp_base'], prefix='import_')
+    orig_head = repo.rev_parse("HEAD")
+    packager = get_packager(spec)
+
+    # Put patches in a safe place
+    queue = safe_patches(queue, tmpdir)
+    for patch in queue:
+        gbp.log.debug("Applying %s" % patch.path)
+        try:
+            apply_and_commit_patch(repo, patch, packager)
+        except (GbpError, GitRepositoryError):
+            repo.force_head(orig_head, hard=True)
+            raise PatchImportError("Patch(es) didn't apply, you need apply "
+                                   "and commit manually")
+
+    # Remove patches from spec and packaging directory
+    gbp.log.info("Removing imported patch files from spec and packaging dir")
+    rm_patch_files(spec)
+    try:
+        spec.update_patches([], {})
+        spec.write_spec_file()
+    except GbpError:
+        repo.force_head('HEAD', hard=True)
+        raise PatchImportError("Unable to update spec file, you need to edit"
+                               "and commit it  manually")
+    repo.commit_all(msg=PATCH_AUTODELETE_COMMIT_MSG % spec.specfile)
 
 
 def force_to_branch_head(repo, branch):
@@ -186,6 +239,8 @@ def parse_args(argv):
                       dest="author_is_committer")
     import_group.add_config_file_option(option_name="packaging-dir",
                       dest="packaging_dir")
+    import_group.add_boolean_config_file_option(option_name="patch-import",
+                                                dest="patch_import")
     (options, args) = parser.parse_args(argv[1:])
     gbp.log.setup(options.color, options.verbose, options.color_scheme)
     return options, args
@@ -429,6 +484,11 @@ def main(argv):
                 # Import patches on top of the source tree
                 # (only for non-native packages with non-orphan packaging)
                 force_to_branch_head(repo, options.packaging_branch)
+                if options.patch_import:
+                    spec = SpecFile(os.path.join(repo.path,
+                                        options.packaging_dir, spec.specfile))
+                    import_spec_patches(repo, spec, dirs)
+                    commit = options.packaging_branch
 
             # Create packaging tag
             repo.create_tag(name=tag,
@@ -454,6 +514,9 @@ def main(argv):
     except NoSpecError as err:
         gbp.log.err("Failed determine spec file: %s" % err)
         ret = 1
+    except PatchImportError as err:
+        gbp.log.err(err)
+        ret = 2
     except SkipImport:
         skipped = True
     finally:
index acd8443b1e94cb3336c62bda4cb141767169207d..6659d369b9476396def7c518e470ea4d04f0a0ff 100644 (file)
@@ -55,10 +55,11 @@ class TestImportPacked(ComponentTestBase):
         # Check repository state
         repo = GitRepository('gbp-test')
         files =  {'Makefile', 'README', 'bar.tar.gz', 'dummy.sh', 'foo.txt',
-                  'gbp-test.spec', 'my.patch', 'my2.patch', 'my3.patch'}
+                  'gbp-test.spec', 'my.patch', 'mydir/myfile.txt'}
         self._check_repo_state(repo, 'master', ['master', 'upstream'], files)
-        # Two commits: upstream and packaging files
-        eq_(len(repo.get_commits()), 2)
+        # Four commits: upstream, packaging files, one patch and the removal
+        # of imported patches
+        eq_(len(repo.get_commits()), 4)
 
     def test_basic_import2(self):
         """Import package with multiple spec files and full url patch"""
@@ -68,11 +69,12 @@ class TestImportPacked(ComponentTestBase):
         repo = GitRepository('gbp-test2')
         files = {'Makefile', 'README', 'bar.tar.gz', 'dummy.sh', 'foo.txt',
                  'gbp-test2.spec', 'gbp-test2-alt.spec', 'my.patch',
-                 'my2.patch', 'my3.patch'}
+                 'mydir/myfile.txt'}
         self._check_repo_state(repo, 'master', ['master', 'upstream'], files)
 
-        # Two commits: upstream and packaging files
-        eq_(len(repo.get_commits()), 2)
+        # Four commits: upstream, packaging files, one patch and the removal
+        # of imported patches
+        eq_(len(repo.get_commits()), 4)
 
     def test_basic_import_orphan(self):
         """
@@ -119,21 +121,22 @@ class TestImportPacked(ComponentTestBase):
         eq_(mock_import(['--no-pristine-tar', srpms[0]]), 0)
         repo = GitRepository('gbp-test')
         self._check_repo_state(repo, 'master', ['master', 'upstream'])
-        eq_(len(repo.get_commits()), 2)
+        eq_(len(repo.get_commits()), 4)
         # Try to import same version again
         eq_(mock_import([srpms[1]]), 0)
-        eq_(len(repo.get_commits()), 2)
+        eq_(len(repo.get_commits()), 4)
         eq_(len(repo.get_commits(until='upstream')), 1)
-        eq_(mock_import(['--no-pristine-tar', '--allow-same-version', srpms[1]]), 0)
-        # Added new version of packaging
-        eq_(len(repo.get_commits()), 3)
+        eq_(mock_import(['--no-pristine-tar', '--allow-same-version',
+                         srpms[1]]), 0)
+        # Added new versio packaging plus one patch
+        eq_(len(repo.get_commits()), 7)
         eq_(len(repo.get_commits(until='upstream')), 1)
         # Import new version
         eq_(mock_import(['--no-pristine-tar', srpms[2]]), 0)
         files = {'Makefile', 'README', 'bar.tar.gz', 'dummy.sh', 'foo.txt',
-                 'gbp-test.spec', 'my.patch', 'my2.patch', 'my3.patch'}
+                 'gbp-test.spec', 'my.patch', 'mydir/myfile.txt'}
         self._check_repo_state(repo, 'master', ['master', 'upstream'], files)
-        eq_(len(repo.get_commits()), 5)
+        eq_(len(repo.get_commits()), 11)
         eq_(len(repo.get_commits(until='upstream')), 2)
         # Check number of tags
         eq_(len(repo.get_tags('upstream/*')), 2)
@@ -162,8 +165,9 @@ class TestImportPacked(ComponentTestBase):
         self._check_log(-1, 'Also check the --create-missing-branches')
         eq_(mock_import(['--no-pristine-tar', '--create-missing', srpm]), 0)
         self._check_repo_state(repo, 'master', ['master', 'upstream'])
-        # Four commits: our initial, upstream and packaging files
-        eq_(len(repo.get_commits()), 3)
+        # Four commits: our initial, upstream, packaging files, one patch,
+        # and the removal of imported patches
+        eq_(len(repo.get_commits()), 5)
 
         # The import should fail because missing packaging-branch
         srpm = os.path.join(DATA_DIR, 'gbp-test-1.1-1.src.rpm')
@@ -178,7 +182,7 @@ class TestImportPacked(ComponentTestBase):
         # Check repository state
         repo = GitRepository('gbp-test')
         files = set(['Makefile', 'dummy.sh', 'bar.tar.gz', 'foo.txt',
-                 'gbp-test.spec', 'my.patch', 'my2.patch', 'my3.patch'])
+                 'gbp-test.spec', 'my.patch', 'mydir/myfile.txt'])
         self._check_repo_state(repo, 'master', ['master', 'upstream'], files)
 
     def test_misc_options(self):
@@ -186,6 +190,7 @@ class TestImportPacked(ComponentTestBase):
         srpm = os.path.join(DATA_DIR, 'gbp-test2-2.0-0.src.rpm')
 
         eq_(mock_import(['--no-pristine-tar',
+                    '--no-patch-import',
                     '--packaging-branch=pack',
                     '--upstream-branch=orig',
                     '--packaging-dir=packaging',
@@ -311,8 +316,9 @@ class TestPristineTar(ComponentTestBase):
         repo = GitRepository('gbp-test')
         self._check_repo_state(repo, 'master', ['master', 'upstream',
                                'pristine-tar'])
-        # Two commits: upstream and packaging files
-        eq_(len(repo.get_commits()), 2)
+        # Four commits: upstream, packaging files, one patch and the removal
+        # of imported patches
+        eq_(len(repo.get_commits()), 4)
 
     def test_unsupported_archive(self):
         """Test importing of src.rpm with a zip source archive"""