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>
Tue, 3 Mar 2015 08:07:46 +0000 (10:07 +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 ae022a3b11948e28f4cdaa63ad25e16e65141886..92147be1153e5e0d576b79e4655ddb310473ee68 100644 (file)
@@ -619,6 +619,7 @@ class GbpOptionParserRpm(GbpOptionParser):
             'export-specdir'            : 'SPECS',
             'export-sourcedir'          : 'SOURCES',
             'spec-vcs-tag'              : '',
+            'patch-import'              : 'True',
             'import-files'              : ['.gbp.conf',
                                            'debian/gbp.conf'],
                     })
@@ -658,6 +659,9 @@ class GbpOptionParserRpm(GbpOptionParser):
             'spec-vcs-tag':
                 "Set/update the 'VCS:' tag in the spec file, empty value "
                 "removes the tag entirely, default is '%(spec-vcs-tag)s'",
+            'patch-import':
+                "Import patches to the packaging branch, default is "
+                "'%(patch-import)s'",
             'import-files':
                 "Comma-separated list of additional file(s) to import from "
                 "packaging branch. These will appear as one monolithic patch "
index c7a866d20b253df78a8e614ffbfe229603edd501..d8ba5911d7ea129fdadc561eebefc518e0d45188 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,45 @@ 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):
+    """
+    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())
+    orig_head = repo.rev_parse("HEAD")
+    packager = get_packager(spec)
+
+    # Put patches in a safe place
+    queue = safe_patches(queue)
+    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):
@@ -189,6 +241,8 @@ def build_parser(name):
                       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")
     return parser
 
 def parse_args(argv):
@@ -448,6 +502,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)
+                    commit = options.packaging_branch
 
             # Create packaging tag
             if not options.skip_packaging_tag:
@@ -476,6 +535,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 1fa7aedf16d2482d8405d41b0825371e9335e86f..51b45e133adc65769f50dca87e7d198abdb3c281 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):
         """
@@ -111,6 +113,20 @@ class TestImportPacked(ComponentTestBase):
         # Only one commit: packaging files
         eq_(len(repo.get_commits()), 1)
 
+    def test_import_compressed_patches(self):
+        """Test importing of non-native src.rpm with compressed patches"""
+        srpm = os.path.join(DATA_DIR, 'gbp-test-1.1-2.src.rpm')
+        eq_(import_srpm(['arg0', srpm]), 0)
+        # Check repository state
+        repo = GitRepository('gbp-test')
+        files =  set(['Makefile', 'README', 'AUTHORS', 'NEWS', 'bar.tar.gz',
+                    'dummy.sh', 'foo.txt', 'gbp-test.spec', 'my.patch',
+                    'mydir/myfile.txt'])
+        self._check_repo_state(repo, 'master', ['master', 'upstream'], files)
+        # Four commits: upstream, packaging files, three patches and the removal
+        # of imported patches
+        eq_(len(repo.get_commits()), 6)
+
     def test_multiple_versions(self):
         """Test importing of multiple versions"""
         srpms = [ os.path.join(DATA_DIR, 'gbp-test-1.0-1.src.rpm'),
@@ -119,21 +135,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 +179,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 +196,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_tagging(self):
@@ -248,6 +266,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',
@@ -373,8 +392,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"""