Package: src:git-buildpackage
Version: 0.9.20
Severity: wishlist
Tags: patch

Feature request:

`gbp import-orig` should strip [~+](dfsg|ds).* or even [~+].* from the
upstream version (only) when calculating the upstream-vcs-tag.


Details:

I'm trying to get `gbp import-orig --uscan` working with a variant of
the repack-waf script from: https://wiki.debian.org/UnpackWaf

The example here is NTPsec 1.1.9.

The stock repack-waf script takes an input orig tarball of "1.1.9" and
outputs an orig tarball of "1.1.9+dfsg1".  Unfortunately, in this state,
uscan is not aware that the tarball was repacked, so neither is `gbp
import-orig`.  gbp gets the version from the tarball name, which it gets
from the <target> element in the `uscan --dehs` output.

If I add oversionmangle=s/$/+dfsg1/ to the opts in debian/watch, then
uscan is aware that the output will be 1.1.9+dfsg1.  This seems like the
correct thing to do from uscan's perspective, as its man page says
oversionmangle "should be used to add a suffix such as +dfsg1".
However, uscan will also symlink the upstream orig tarball with that
name, so the stock repack-waf script breaks. That can easily be
addressed by changing repack-waf to use the 1.1.9+dfsg1 name as both
input and output, which I have done.

In that configuration, gbp gets the upstream version of 1.1.9+dfsg1.
This leads to tag names like upstream/1.1.9+dfsg1, which is what I have
been using so far.  DEP-14 isn't clear whether it should be
upstream/1.1.9+dfsg1 or upstream/1.1.9.  However, DEP-14 does
contemplate that "The upstream/<version> tag would be created by the
package maintainer when needed: for example when
it does a release based on a Git snapshot".  So those tags are not
expected to correspond exactly with upstream's tags.  I think they
should be the "Debian upstream version", so 1.1.9+dfsg1 is correct.

Further, in bug #546598, Charles Plessy <ple...@debian.org> suggested
that `gbp import-orig --filter` should automatically add "~dfsg":
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=546598 That bug was
from 2009.  Today, plessy seems to use +dfsg.1, +ds-1, and +dfsg-1
suffixes.  More importantly than those minor differences in suffix
style, some of those packages currently have numbers greater than 1.
That to me shows that stripping the +dfsg1 to get just upstream/1.1.9
would be inappropriate, as that would not scale to +dfsg2 and beyond.
This is further evidence that upstream/1.1.9+dfsg1 is correct.

However, that still leaves one problem.  The --upstream-vcs-tag tag
format only allows for one substitution which has to be a single
character substitution.  There is no way to strip the +dfsg1.  In my
case, I want to get to the NTPsec_1_1_9 format that upstream uses by
using: upstream-vcs-tag = NTPsec_%(version%.%_)s

I ran some queries against UDD to find various patterns. Based on that,
the attached patch series implements this and a bunch more. With this
change, I was able to import version 1.1.9 of NTPsec using:

gbp import-orig --uscan --upstream-vcs-tag="NTPsec_%(version%.%_)s"


The first patch is just a typo fix to a comment nearby. It's unrelated
to this change.

The second two patches are refactoring changes. Those can be squashed
together or into the last change, if you prefer. I included them to show
the refactoring steps individually, in case that helps you review this.

The third change is the meat of this. I have doctests, but I'm not sure
if those are automatically run or how I integrate them into the
git-buildpackage tests. I'm also not sure about the function name for
_upstream_version_from_debian_upstream(). In a previous version, I
called it _mangle_upstream_version().

-- 
Richard
From 7cc1195bac48833fa551102a114d943be2cc006b Mon Sep 17 00:00:00 2001
From: Richard Laager <rlaa...@wiktel.com>
Date: Wed, 12 Aug 2020 21:54:06 -0500
Subject: [PATCH 1/4] import-orig: Fix a comment typo

---
 gbp/deb/git.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gbp/deb/git.py b/gbp/deb/git.py
index 596c9ff..4b52122 100644
--- a/gbp/deb/git.py
+++ b/gbp/deb/git.py
@@ -171,7 +171,7 @@ class DebianGitRepository(PkgGitRepository):
     @classmethod
     def _mangle_version(cls, format, version):
         """
-        Basic version mangling to replce single characters
+        Basic version mangling to replace single characters
 
         >>> DebianGitRepository._mangle_version(r'%(version%-%\\%)s', "0-1.2.3")
         ('%(version)s', '0%1.2.3')
-- 
2.28.0

From 37904cdda6d4b1de4602bbf3e98baa8bb5ace42d Mon Sep 17 00:00:00 2001
From: Richard Laager <rlaa...@wiktel.com>
Date: Wed, 12 Aug 2020 21:58:31 -0500
Subject: [PATCH 2/4] import-orig: Refactor vcs_tag_parent

This eliminates an indentation level.
---
 gbp/deb/git.py | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/gbp/deb/git.py b/gbp/deb/git.py
index 4b52122..a701589 100644
--- a/gbp/deb/git.py
+++ b/gbp/deb/git.py
@@ -375,14 +375,13 @@ class DebianGitRepository(PkgGitRepository):
 
     def vcs_tag_parent(self, vcs_tag_format, version):
         """If linking to the upstream VCS get the commit id"""
-        if vcs_tag_format:
-            try:
-                tag = "%s^{}" % self.version_to_tag(vcs_tag_format, version)
-                return [self.rev_parse(tag)]
-            except GitRepositoryError:
-                raise GitRepositoryError("Can't find upstream vcs tag at '%s'" % tag)
-        else:
+        if not vcs_tag_format:
             return None
+        try:
+            tag = "%s^{}" % self.version_to_tag(vcs_tag_format, version)
+            return [self.rev_parse(tag)]
+        except GitRepositoryError:
+            raise GitRepositoryError("Can't find upstream vcs tag at '%s'" % tag)
 
 
 # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
-- 
2.28.0

From 8e676bebed16c46639ce50adcf52646679746c54 Mon Sep 17 00:00:00 2001
From: Richard Laager <rlaa...@wiktel.com>
Date: Wed, 12 Aug 2020 21:59:23 -0500
Subject: [PATCH 3/4] import-orig: Refactor vcs_tag_parent

This makes the "tag" variable just the tag.  This improves the
human-readability of the error message if the tag cannot be found.
---
 gbp/deb/git.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/gbp/deb/git.py b/gbp/deb/git.py
index a701589..4a17c2d 100644
--- a/gbp/deb/git.py
+++ b/gbp/deb/git.py
@@ -378,8 +378,8 @@ class DebianGitRepository(PkgGitRepository):
         if not vcs_tag_format:
             return None
         try:
-            tag = "%s^{}" % self.version_to_tag(vcs_tag_format, version)
-            return [self.rev_parse(tag)]
+            tag = self.version_to_tag(vcs_tag_format, version)
+            return [self.rev_parse("%s^{}" % tag)]
         except GitRepositoryError:
             raise GitRepositoryError("Can't find upstream vcs tag at '%s'" % tag)
 
-- 
2.28.0

From 1c8f2acbcbd3ccf14dc4d7bd99b4d1e92e4c1574 Mon Sep 17 00:00:00 2001
From: Richard Laager <rlaa...@wiktel.com>
Date: Wed, 12 Aug 2020 22:03:18 -0500
Subject: [PATCH 4/4] import-orig: Parse various Debian version patterns

This parses common Debian version patterns into the upstream version.
For example, 1.1.8+dfsg1 becomes 1.1.8.  This strips epochs, handles the
+really convention, finds git revisions, and strips other + or ~
patterns.
---
 gbp/deb/git.py | 59 +++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 56 insertions(+), 3 deletions(-)

diff --git a/gbp/deb/git.py b/gbp/deb/git.py
index 4a17c2d..a5367f4 100644
--- a/gbp/deb/git.py
+++ b/gbp/deb/git.py
@@ -129,6 +129,57 @@ class DebianGitRepository(PkgGitRepository):
             version = "%s:%s" % (epoch, version)
         return version
 
+    @classmethod
+    def _upstream_version_from_debian_upstream(cls, version):
+        """
+        Convert a Debian upstream version to an upstream version.
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "1.1.8+dfsg1")
+        ('1.1.8', None)
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "1:5.5.0~dfsg")
+        ('5.5.0', None)
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "0.0~git20160722.0.0cdb66a")
+        (None, '0cdb66a')
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "3:6.04~git20190206.bf6db5b4+dfsg1")
+        (None, 'bf6db5b4')
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "2.3+really2.2")
+        ('2.2', None)
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "4.99.4+dfsg+really4.10.0+py3")
+        ('4.10.0', None)
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "5.4.1+really5.4.1~repack")
+        ('5.4.1', None)
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "0.0~git20190103.40eba7e+really0.0~git20181023.b4e2780")
+        (None, 'b4e2780')
+        >>> DebianGitRepository._upstream_version_from_debian_upstream(
+        ... "1.1.0+really1.0.0+git20181028.94f6ae3")
+        (None, '94f6ae3')
+        """
+
+        # If version starts with an epoch, remove it.
+        m = re.search(r'^[0-9]+:(.*)', version)
+        if m:
+            version = m.group(1)
+
+        # If version has "really", keep the version starting after "really".
+        m = re.search(r'really(.*)', version)
+        if m:
+            version = m.group(1)
+
+        # If version matches a git snapshot pattern, return the git revision.
+        m = re.search(r'[~+]git[0-9]{8}(\.[0-9]+)?\.([0-9a-f]+)', version)
+        if m:
+            return (None, m.group(2))
+
+        # Strip off anything starting with [+~] and return the rest.
+        return (re.split(r'[+~]', version)[0], None)
+
     @staticmethod
     def _build_legacy_tag(format, version):
         """
@@ -377,11 +428,13 @@ class DebianGitRepository(PkgGitRepository):
         """If linking to the upstream VCS get the commit id"""
         if not vcs_tag_format:
             return None
+        (version, revision) = self._upstream_version_from_debian_upstream(version)
         try:
-            tag = self.version_to_tag(vcs_tag_format, version)
-            return [self.rev_parse("%s^{}" % tag)]
+            if not revision:
+                revision = self.version_to_tag(vcs_tag_format, version)
+            return [self.rev_parse("%s^{}" % revision)]
         except GitRepositoryError:
-            raise GitRepositoryError("Can't find upstream vcs tag at '%s'" % tag)
+            raise GitRepositoryError("Can't find upstream vcs tag/revision at '%s'" % revision)
 
 
 # vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·:
-- 
2.28.0

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to