@@ -204,12 +204,24 @@ python do_ar_original() {
fetch = bb.fetch.Fetch(urls, ld)
tarball_suffix = {}
for url in fetch.urls:
+ ud = fetch.ud[url]
local = fetch.localpath(url).rstrip("/");
+ # A shallow git fetch which used the shallow tarball has no up to date
+ # clone, which is what localpath() points to. unpack() then uses the
+ # shallow tarball, using the same check as here.
+ shallow = getattr(ud, 'shallow', False) and os.path.isfile(ud.fullshallow) \
+ and ud.method.clonedir_need_update(ud, ld)
if os.path.isfile(local):
shutil.copy(local, ar_outdir)
- elif os.path.isdir(local):
+ elif os.path.isdir(local) or shallow:
tmpdir = tempfile.mkdtemp(dir=d.getVar('ARCHIVER_WORKDIR'))
fetch.unpack(tmpdir, (url,))
+ if shallow:
+ # The unpacked shallow tarball has a .git with all the objects,
+ # which would ship the sources twice. Drop it: the .git of a
+ # clone has no objects either (clone -s), so neither archive
+ # contains a usable repository.
+ bb.utils.remove(os.path.join(ud.destdir, '.git'), recurse=True)
# To handle recipes with more than one source, we add the "name"
# URL parameter as suffix. We treat it as an error when
# there's more than one URL without a name, or a name gets reused.
@@ -7,6 +7,8 @@
import os
import glob
import re
+import shutil
+import tarfile
from oeqa.utils.commands import bitbake, get_bb_vars
from oeqa.selftest.case import OESelftestTestCase
@@ -176,6 +178,45 @@ class Archiver(OESelftestTestCase):
self._test_archiver_mode('original', 'ed-1.21.1.tar.lz')
+ def test_archiver_mode_original_git_shallow(self):
+ """
+ Test that the archiver archives a shallow git source with
+ `ARCHIVER_MODE[src] = "original"` when only the shallow tarball is
+ available, but not the clone. This is what happens with the fast
+ initial shallow fetch, or when the shallow tarball is fetched from a
+ mirror.
+ """
+ target = 'gitrepotest'
+
+ features = 'INHERIT += "archiver"\n'
+ features += 'ARCHIVER_MODE[src] = "original"\n'
+ features += 'BB_GIT_SHALLOW = "1"\n'
+ features += 'BB_GENERATE_SHALLOW_TARBALLS = "1"\n'
+ features += 'DL_DIR = "${TOPDIR}/downloads-shallow"\n'
+ self.write_config(features)
+
+ # Fetch to create the shallow tarball, then remove the clone if the
+ # fetcher fell back to a full clone, so that the second fetch has to
+ # use the shallow tarball. cleansstate makes sure that the archive is
+ # created again and not restored from sstate.
+ bitbake('-c cleansstate %s' % target)
+ bitbake('-c fetch %s' % target)
+ bb_vars = get_bb_vars(['DL_DIR', 'DEPLOY_DIR_SRC'])
+ self.track_for_cleanup(bb_vars['DL_DIR'])
+ self.assertTrue(glob.glob(os.path.join(bb_vars['DL_DIR'], 'gitshallow_*.tar.gz')),
+ 'Missing shallow tarball in DL_DIR')
+ shutil.rmtree(os.path.join(bb_vars['DL_DIR'], 'git2'))
+ bitbake('-c cleansstate %s' % target)
+
+ bitbake('-c deploy_archives %s' % target)
+
+ archives = glob.glob(os.path.join(bb_vars['DEPLOY_DIR_SRC'], '*', '%s-*' % target, '%s-*.tar.*' % target))
+ self.assertEqual(len(archives), 1, 'Expected one source archive for %s, found %s' % (target, archives))
+ with tarfile.open(archives[0]) as tar:
+ names = tar.getnames()
+ self.assertTrue([n for n in names if n.endswith('/COPYING')], 'Archive has no source files: %s' % names[:20])
+ self.assertFalse([n for n in names if '/.git/' in n], 'Archive contains git objects')
+
def test_archiver_mode_patched(self):
"""
Test that the archiver works with `ARCHIVER_MODE[src] = "patched"`.