Commit e5aedb16 authored by Luca Boccassi's avatar Luca Boccassi Committed by Guido Günther

buildpackage, export-orig: support version substitution for --git-tarball-dir

Add support for passing %(version), %(hversion) and %(version%A%B) in
buildpackage --git-tarball-dir and export-orig --tarball-dir.

Closes: #909266
Signed-off-by: Luca Boccassi's avatarLuca Boccassi <>
parent 44acc6d5
......@@ -222,6 +222,8 @@
Search for upstream tarballs in <replaceable>DIRECTORY</replaceable>
instead of generating them. If a tarball is not found here it
will be generated nevertheless.
<replaceable>DIRECTORY</replaceable> can contain a version format
substitution pattern, eg: <replaceable>foo-%(version)s</replaceable>.
......@@ -146,6 +146,8 @@
Search for original tarballs in <replaceable>DIRECTORY</replaceable>
instead of generating them.
<replaceable>DIRECTORY</replaceable> can contain a version format
substitution pattern, eg: <replaceable>foo-%(version)s</replaceable>.
......@@ -22,9 +22,9 @@ import re
from gbp.command_wrappers import CommandExecFailed
from gbp.git import GitRepositoryError
from gbp.deb.pristinetar import DebianPristineTar
from gbp.format import format_str
from gbp.paths import to_bin
from gbp.pkg.git import PkgGitRepository
from gbp.pkg.pkgpolicy import PkgPolicy
import gbp.log
......@@ -169,9 +169,7 @@ class DebianGitRepository(PkgGitRepository):
>>> DebianGitRepository.version_to_tag(r'%(version%-%\\%)s', "0-1.2.3")
f, v = cls._mangle_version(format, version)
return format_str(f, dict(version=cls._sanitize_version(v),
hversion=cls._sanitize_version(v).replace('.', '-')))
return PkgPolicy.version_subst(format, version, cls._sanitize_version)
def _mangle_version(cls, format, version):
......@@ -20,6 +20,7 @@ import os
import re
from gbp.pkg.archive import Archive
from gbp.format import format_str
class PkgPolicy(object):
......@@ -165,3 +166,40 @@ class PkgPolicy(object):
def symlink_orig(cls, orig_file, orig_dir, output_dir, force=False):
return cls.symlink_origs([orig_file], orig_dir, output_dir, force=force)
def version_subst(format, version, sanitizer=lambda arg: arg):
"""Generate a string from a given format and a version. The extracted
version can be passed through the sanitizer function argument before
being formatted into a string.
%(version)s provides a clean version.
%(hversion)s provides the same thing, but with '.' replaced with '-'.
hversion is useful for upstreams with tagging policies that prohibit .
%(version%A%B)s provides %(version)s with string 'A' replaced by 'B'.
This way, simple version mangling is possible via substitution.
Inside the substition string, '%' needs to be escaped. See the
examples below.
>>> PkgPolicy.version_subst("debian/%(version)s", "0:0~0")
>>> PkgPolicy.version_subst("libfoo-%(hversion)s", "1.8.1")
>>> PkgPolicy.version_subst("v%(version%.%_)s", "1.2.3")
>>> PkgPolicy.version_subst(r'%(version%-%\\%)s', "0-1.2.3")
version_mangle_re = (r'%\(version'
r =, format)
if r:
format = re.sub(version_mangle_re, "%(version)s", format)
version = version.replace('M'),'R').replace(r'\%', '%'))
return format_str(format, dict(version=sanitizer(version),
hversion=sanitizer(version).replace('.', '-')))
......@@ -45,6 +45,7 @@ from gbp.scripts.common.hook import Hook
from gbp.scripts.export_orig import prepare_upstream_tarballs, guess_comp_type
from gbp.scripts.tag import perform_tagging
from gbp.pkg.pkgpolicy import PkgPolicy
# Functions to handle export-dir
......@@ -499,7 +500,9 @@ def main(argv):
if not options.tag_only:
output_dir = prepare_output_dir(options.export_dir)
tarball_dir = options.tarball_dir or output_dir
tarball_dir = output_dir
if options.tarball_dir and source.upstream_version is not None:
tarball_dir = PkgPolicy.version_subst(options.tarball_dir, source.upstream_version)
tmp_dir = os.path.join(output_dir, "%s-tmp" % source.sourcepkg)
build_env, hook_env = setup_pbuilder(options, repo, source.is_native())
major = (source.debian_version if source.is_native()
......@@ -29,6 +29,7 @@ import gbp.log
import gbp.notifications
from gbp.scripts.common import ExitCodes
from gbp.pkg import Compressor, Archive
from gbp.pkg.pkgpolicy import PkgPolicy
def prepare_upstream_tarballs(repo, source, options, tarball_dir, output_dir):
......@@ -335,6 +336,10 @@ def main(argv):
except Exception as e:
raise GbpError("Can't determine package type: %s" % e)
if options.tarball_dir and source.upstream_version is not None:
options.tarball_dir = PkgPolicy.version_subst(options.tarball_dir,
output_dir = options.tarball_dir or os.path.join(repo.path, '..')
if source.is_native():
......@@ -312,3 +312,24 @@ class TestBuildpackage(ComponentTestBase):
'--git-preexport=printenv > %s' % preexport_out])
self.check_hook_vars('../preexport', ["GBP_BUILD_DIR", "GBP_GIT_DIR"])
def test_export_dir_version_replacement(self, repo):
"""Test that building in overlay mode with export dir with versioned name works"""
tarball_dir = os.path.join(DEB_TEST_DATA_DIR, 'foo-%(version)s')
self._test_buildpackage(repo, ['--git-overlay',
'--git-tarball-dir=%s' % tarball_dir,
# Check if main tarball got unpacked
# Check if debian dir is there
# Check if additional tarball got unpacked
# Check if upstream tarballs is in export_dir
eq_(sorted(glob.glob('../foo/*')), ['../foo/hello-debhelper-2.8',
......@@ -111,3 +111,28 @@ class TestExportOrig(ComponentTestBase):
ok_(ret == 1, "Exporting tarballs must fail")
self._check_log(-1, ".*git show refs/heads/pristine-tar:.*failed")
def test_tarball_dir_version_replacement(self):
"""Test that generating tarball from directory version substitution works"""
pkg = 'hello-debhelper'
dsc = self._dsc_name(pkg, '2.8-1', 'dsc-3.0-additional-tarballs')
tarballs = ["%s_2.8.orig-foo.tar.gz" % pkg,
"%s_2.8.orig.tar.gz" % pkg]
assert import_dsc(['arg0', '--no-pristine-tar', dsc]) == 0
for t in tarballs:
self.assertFalse(os.path.exists(os.path.join('..', t)), "Tarball %s must not exist" % t)
tarball_dir = os.path.join(DEB_TEST_DATA_DIR, 'foo-%(version)s')
ret = export_orig(['arg0',
'--tarball-dir=%s' % tarball_dir,
ok_(ret == 0, "Exporting tarballs failed")
# tarballs should be found in existing --tarball-dir directory and thus
# not get recreated by export-orig
for t in tarballs:
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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment