add option to export tarballs with upstream signature
authorChristian Göttsche <cgzones@googlemail.com>
Mon, 16 Dec 2019 23:10:01 +0000 (00:10 +0100)
committerChristian Göttsche <cgzones@googlemail.com>
Tue, 21 Jan 2020 16:36:53 +0000 (17:36 +0100)
Add option `--upstream-signatures=[on|auto|off]` to export-orig.
Add option `--git-upstream-signatures=[on|auto|off]` to buildpackage.

Closes: 872864
docs/manpages/gbp-buildpackage.xml
docs/manpages/gbp-export-orig.xml
gbp/deb/git.py
gbp/pkg/pristinetar.py
gbp/scripts/buildpackage.py
gbp/scripts/export_orig.py
gbp/scripts/push.py
tests/component/deb/test_export_orig.py
tests/doctests/test_PristineTar.py

index f7e3f7f3166064c17355d7ff64c365ccb05e9e65..237632e8c25c83454dca9dd117ec9ba15a6d3a6b 100644 (file)
@@ -50,6 +50,7 @@
       <arg><option>--git-upstream-tag=</option><replaceable>tag-format</replaceable></arg>
       <arg><option>--git-force-create</option></arg>
       <arg><option>--git-no-create-orig</option></arg>
+      <arg><option>--git-upstream-signatures=</option>[auto|on|off]</arg>
       <arg><option>--git-upstream-tree=</option><replaceable>[BRANCH|SLOPPY|TAG|TREEISH]</replaceable></arg>
       <arg><option>--git-tarball-dir=</option><replaceable>DIRECTORY</replaceable></arg>
       <arg><option>--git-compression=</option><replaceable>TYPE</replaceable></arg>
             </para>
           </listitem>
        </varlistentry>
+       <varlistentry>
+          <term><option>--git-upstream-signatures=</option>[auto|on|off]
+          </term>
+          <listitem>
+            <para>
+              Whether to export the upstream tarball with signatures.
+            </para>
+          </listitem>
+       </varlistentry>
        <varlistentry>
           <term><option>--git-[no-]submodules</option>
           </term>
index 9711e0f0200c13f37507f35efcbedfc7aee69ff7..c3a1393c51f2fb200d568f213756b7d8b49f1bfa 100644 (file)
@@ -31,6 +31,7 @@
       <arg><option>--compression-level=</option><replaceable>LEVEL</replaceable></arg>
       <arg rep='repeat'><option>--component=</option><replaceable>component</replaceable></arg>
       <arg><option>--[no-]pristine-tar</option></arg>
+      <arg><option>--upstream-signatures=</option>[auto|on|off]</arg>
     </cmdsynopsis>
   </refsynopsisdiv>
   <refsect1>
         </listitem>
       </varlistentry>
     </variablelist>
+    <varlistentry>
+        <term><option>--upstream-signatures=</option>[auto|on|off]
+        </term>
+        <listitem>
+          <para>
+          Whether to export with upstream signatures.
+          </para>
+        </listitem>
+      </varlistentry>
   </refsect1>
   <refsect1>
     <title>EXAMPLES</title>
index 3584f6ff914634052fdc6cd8b0b7f9d5320cf5ec..ee939a85d4f2da8d0de0393cb8a10bac798fd2db 100644 (file)
@@ -316,13 +316,22 @@ class DebianGitRepository(PkgGitRepository):
                                                                     source.upstream_version,
                                                                     comp))
 
-    def create_upstream_tarball_via_pristine_tar(self, source, output_dir, comp, component=None):
+    def create_upstream_tarball_via_pristine_tar(self, source, output_dir, comp, upstream_signatures, component=None):
         output = source.upstream_tarball_name(comp.type, component=component)
+        gbp.log.debug("upstream signature state: %s" % upstream_signatures)
+        commit, found_signature = self.get_pristine_tar_commit(source, component)
+        if not commit and self.has_pristine_tar_branch():
+            raise GitRepositoryError("Can not find pristine tar commit for archive '%s'" % output)
+        if not found_signature and upstream_signatures.is_on():
+            raise GitRepositoryError("Can not find requested upstream signature for archive '%s' in pristine tar commit." % output)
         try:
+            signature = False if upstream_signatures.is_off() else found_signature
             self.pristine_tar.checkout(source.name, source.upstream_version, comp.type, output_dir,
-                                       component=component, quiet=True)
+                                       component=component, quiet=True, signature=signature)
         except Exception as e:
-            raise GitRepositoryError("Error creating %s: %s" % (output, e))
+            raise GitRepositoryError("Error creating %s%s: %s" % (output,
+                                                                  " with attached signature file" if signature else "",
+                                                                  e))
         return True
 
     def create_upstream_tarball_via_git_archive(self, source, output_dir, treeish,
index 5c0892b754e3f001dbcfc3e246165dce3d637e74..e853407616f66e9e579284e141aaf5a316e8c464 100644 (file)
@@ -63,25 +63,38 @@ class PristineTar(Command):
         @param archive_regexp: archive name to look for (regexp wildcards allowed)
         @type archive_regexp: C{str}
         """
-        return True if self.get_commit(archive_regexp) else False
+        return True if self.get_commit(archive_regexp)[0] else False
+
+    def _commit_contains_file(self, commit, regexp):
+        """Does the given commit contain a file with the given regex"""
+        files = self.repo.get_commit_info(commit)['files']
+        cregex = re.compile(regexp)
+        for _, v in files.items():
+            for f in v:
+                if cregex.match(f.decode()):
+                    return True
+        return False
 
     def get_commit(self, archive_regexp):
         """
         Get the pristine-tar commit of a package matching I{archive_regexp}.
+        Checks also whether the commit contains a signature file.
 
         @param archive_regexp: archive name to look for (regexp wildcards allowed)
         @type archive_regexp: C{str}
+        @return: Commit, True if commit contains a signature file
+        @rtype: C{tuple} of C{str} and C{bool}
         """
         if not self.repo.has_pristine_tar_branch():
-            return None
+            return None, False
 
         regex = ('pristine-tar .* %s' % archive_regexp)
         commits = self.repo.grep_log(regex, self.branch, merges=False)
         if commits:
             commit = commits[-1]
             gbp.log.debug("Found pristine-tar commit at '%s'" % commit)
-            return commit
-        return None
+            return commit, self._commit_contains_file(commit, '%s.asc' % archive_regexp)
+        return None, False
 
     def checkout(self, archive, quiet=False, signaturefile=None):
         """
index 2aca53df620ac1ab490f42e22dac645a922e7c61..9b3d67facaac17577a5de0c299f5bbd4704af15e 100755 (executable)
@@ -395,6 +395,8 @@ def build_parser(name, prefix=None):
                                       help="Compression type, default is '%(compression)s'")
     orig_group.add_config_file_option(option_name="compression-level", dest="comp_level",
                                       help="Compression level, default is '%(compression-level)s'")
+    orig_group.add_config_file_option(option_name="upstream-signatures", dest="upstream_signatures",
+                                      help="use upstream signatures, default is auto", type='tristate')
     orig_group.add_config_file_option("component", action="append", metavar='COMPONENT',
                                       dest="components")
     branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch")
index 13be4f912639d7e88454e94f4f549cb858f0c77d..cad8297badc4b735fbc5e80568f2961d57565b3d 100755 (executable)
@@ -113,7 +113,8 @@ def pristine_tar_build_origs(repo, source, output_dir, options):
                                                   source.upstream_tarball_name(comp.type))))
         repo.create_upstream_tarball_via_pristine_tar(source,
                                                       output_dir,
-                                                      comp)
+                                                      comp,
+                                                      options.upstream_signatures)
         for component in options.components:
             gbp.log.info("Creating %s" %
                          os.path.abspath(os.path.join(output_dir,
@@ -121,6 +122,7 @@ def pristine_tar_build_origs(repo, source, output_dir, options):
             repo.create_upstream_tarball_via_pristine_tar(source,
                                                           output_dir,
                                                           comp,
+                                                          options.upstream_signatures,
                                                           component=component)
         return True
     except GitRepositoryError:
@@ -303,6 +305,8 @@ def build_parser(name):
                                       help="Compression type, default is '%(compression)s'")
     orig_group.add_config_file_option(option_name="compression-level", dest="comp_level",
                                       help="Compression level, default is '%(compression-level)s'")
+    orig_group.add_config_file_option(option_name="upstream-signatures", dest="upstream_signatures",
+                                      help="use upstream signature, default is auto", type='tristate')
     orig_group.add_config_file_option("component", action="append", metavar='COMPONENT',
                                       dest="components")
     branch_group.add_config_file_option(option_name="upstream-branch", dest="upstream_branch")
index c897396ecfb5296f492335e80052c0b511b9e359..8233ace8973ae78aef8ab2a19f154eb6dc74cfae 100755 (executable)
@@ -164,7 +164,7 @@ def main(argv):
                 to_push['refs'].append((ref, get_push_src(repo, ref, utag)))
 
             if options.pristine_tar:
-                commit = repo.get_pristine_tar_commit(source)
+                commit, _ = repo.get_pristine_tar_commit(source)
                 if commit:
                     ref = 'refs/heads/pristine-tar'
                     to_push['refs'].append((ref, get_push_src(repo, ref, commit)))
index c01562def1c59652af822b9c50e08853b51436cf..8ff759829df412a186ed377be3cfc029fdf306b4 100644 (file)
@@ -112,7 +112,7 @@ class TestExportOrig(ComponentTestBase):
                            '--component=foo',
                            '--pristine-tar'])
         ok_(ret == 1, "Exporting tarballs must fail")
-        self._check_log(-1, ".*git show refs/heads/pristine-tar:.*failed")
+        self._check_log(-1, "gbp:error: Can not find pristine tar commit for archive 'hello-debhelper_2.8.orig.tar.gz'")
 
     def test_tarball_dir_version_replacement(self):
         """Test that generating tarball from directory version substitution works"""
@@ -139,6 +139,90 @@ class TestExportOrig(ComponentTestBase):
             self.assertFalse(os.path.exists(os.path.join('..', t)), "Tarball %s found" % t)
             self.assertTrue(os.path.exists(os.path.join(DEB_TEST_DATA_DIR, 'foo-2.8', t)), "Tarball %s not found" % t)
 
+    def test_pristine_tar_upstream_signatures_with(self):
+        """Test that exporting upstream signatures in pristine tar works with imported signature"""
+        pkg = 'hello-debhelper'
+        dsc = self._dsc_name(pkg, '2.8-1', 'dsc-3.0')
+        files = ["%s_2.8.orig.tar.gz" % pkg,
+                 "%s_2.8.orig.tar.gz.asc" % pkg]
+
+        assert import_dsc(['arg0', '--pristine-tar', dsc]) == 0
+        ComponentTestGitRepository(pkg)
+        os.chdir(pkg)
+        for f in files:
+            self.assertFalse(os.path.exists(os.path.join('..', f)), "File %s must not exist" % f)
+
+        ret = export_orig(['arg0',
+                           '--pristine-tar',
+                           '--upstream-signatures=no'])
+        ok_(ret == 0, "Exporting tarballs failed")
+        self.assertTrue(os.path.exists(os.path.join('..', files[0])), "Tarball %s not found" % files[0])
+        self.assertFalse(os.path.exists(os.path.join('..', files[1])), "Signature %s found" % files[1])
+
+        os.remove(os.path.join('..', files[0]))
+        for f in files:
+            self.assertFalse(os.path.exists(os.path.join('..', f)), "File %s must not exist" % f)
+
+        ret = export_orig(['arg0',
+                           '--pristine-tar',
+                           '--upstream-signatures=auto'])
+        ok_(ret == 0, "Exporting tarballs failed")
+        for f in files:
+            self.assertTrue(os.path.exists(os.path.join('..', f)), "File %s not found" % f)
+
+        for f in files:
+            os.remove(os.path.join('..', f))
+            self.assertFalse(os.path.exists(os.path.join('..', f)), "File %s must not exist" % f)
+
+        ret = export_orig(['arg0',
+                           '--pristine-tar',
+                           '--upstream-signatures=on'])
+        ok_(ret == 0, "Exporting tarballs failed")
+        for f in files:
+            self.assertTrue(os.path.exists(os.path.join('..', f)), "File %s not found" % f)
+
+    def test_pristine_tar_upstream_signatures_without(self):
+        """Test that exporting upstream signatures in pristine tar works without imported signature"""
+        pkg = 'hello-debhelper'
+        dsc = self._dsc_name(pkg, '2.6-1', 'dsc-3.0')
+        files = ["%s_2.6.orig.tar.gz" % pkg,
+                 "%s_2.6.orig.tar.gz.asc" % pkg]
+
+        assert import_dsc(['arg0', '--pristine-tar', dsc]) == 0
+        ComponentTestGitRepository(pkg)
+        os.chdir(pkg)
+        for f in files:
+            self.assertFalse(os.path.exists(os.path.join('..', f)), "File %s must not exist" % f)
+
+        ret = export_orig(['arg0',
+                           '--pristine-tar',
+                           '--upstream-signatures=no'])
+        ok_(ret == 0, "Exporting tarballs failed")
+        self.assertTrue(os.path.exists(os.path.join('..', files[0])), "Tarball %s not found" % files[0])
+        self.assertFalse(os.path.exists(os.path.join('..', files[1])), "Signature %s found" % files[1])
+
+        os.remove(os.path.join('..', files[0]))
+        for f in files:
+            self.assertFalse(os.path.exists(os.path.join('..', f)), "File %s must not exist" % f)
+
+        ret = export_orig(['arg0',
+                           '--pristine-tar',
+                           '--upstream-signatures=auto'])
+        ok_(ret == 0, "Exporting tarballs failed")
+        self.assertTrue(os.path.exists(os.path.join('..', files[0])), "Tarball %s not found" % files[0])
+        self.assertFalse(os.path.exists(os.path.join('..', files[1])), "Signature %s found" % files[1])
+
+        os.remove(os.path.join('..', files[0]))
+        for f in files:
+            self.assertFalse(os.path.exists(os.path.join('..', f)), "File %s must not exist" % f)
+
+        ret = export_orig(['arg0',
+                           '--pristine-tar',
+                           '--upstream-signatures=on'])
+        ok_(ret == 1, "Exporting tarballs must fail")
+        self._check_log(-1, "gbp:error: Can not find requested upstream signature for archive "
+                        "'hello-debhelper_2.6.orig.tar.gz' in pristine tar commit.")
+
     @RepoFixtures.quilt30(opts=['--pristine-tar'])
     def test_pristine_tar_commit_on_origin(self, repo):
         """Test that we can create tarball from 'origin/pristine-tar'"""
index 15c614cf42be8d946e04b1a29aa341592ae36a36..dfeb7193d53bd22bc17f03627afa8fd929af15f3 100644 (file)
@@ -134,9 +134,18 @@ def test_pristine_has_commit():
     >>> repo.pristine_tar.has_commit('upstream', '1.0')
     True
     >>> branch = repo.rev_parse('pristine-tar')
-    >>> commit = repo.pristine_tar.get_commit('upstream_1.0.orig.tar.gz')
+    >>> commit, sig = repo.pristine_tar.get_commit('upstream_1.0.orig.tar.gz')
     >>> branch == commit
     True
+    >>> sig
+    True
+    >>> repo.pristine_tar.commit('../upstream_1.0.orig.tar.gz', 'upstream')
+    >>> branch = repo.rev_parse('pristine-tar')
+    >>> commit, sig = repo.pristine_tar.get_commit('upstream_1.0.orig.tar.gz')
+    >>> branch == commit
+    True
+    >>> sig
+    False
     """