@@ -1150,7 +1150,7 @@ def try_mirror_url(fetch, origud, ud, ld, check = False):
# This may also be a link to a shallow archive
# When using shallow mode, add a symlink to the original fullshallow
# path to ensure a valid symlink even in the `PREMIRRORS` case
- origud.method.update_mirror_links(ud, origud)
+ origud.method.update_mirror_links(ud, origud, ld)
update_stamp(origud, ld)
return ud.localpath
@@ -1692,7 +1692,7 @@ class FetchMethod(object):
except FileExistsError:
pass
- def update_mirror_links(self, ud, origud):
+ def update_mirror_links(self, ud, origud, d):
# For local file:// results, create a symlink to them
# This may also be a link to a shallow archive
self.ensure_symlink(ud.localpath, origud.localpath)
@@ -353,8 +353,12 @@ class Git(FetchMethod):
def tarball_need_update(self, ud):
return ud.write_tarballs and not os.path.exists(ud.fullmirror)
- def update_mirror_links(self, ud, origud):
- super().update_mirror_links(ud, origud)
+ def update_mirror_links(self, ud, origud, d):
+ # Replace a stale clone which would prevent linking the successful mirror.
+ if self.clonedir_need_update(origud, d) and os.path.exists(origud.localpath) \
+ and not os.path.samefile(ud.localpath, origud.localpath):
+ bb.utils.remove(origud.localpath, recurse=True)
+ super().update_mirror_links(ud, origud, d)
# When using shallow mode, add a symlink to the original fullshallow
# path to ensure a valid symlink even in the `PREMIRRORS` case
if origud.shallow and not os.path.exists(origud.fullshallow):
@@ -616,6 +616,48 @@ class GitDownloadDirectoryNamingTest(FetcherTest):
self.assertIn(self.recipe_dir, dir)
+class GitPremirrorStaleCloneTest(FetcherTest):
+
+ def test_premirror_replaces_stale_clone(self):
+ source = os.path.join(self.tempdir, "source")
+ os.mkdir(source)
+ self.git_init(cwd=source)
+
+ testfile = os.path.join(source, "testfile")
+ with open(testfile, "w") as f:
+ f.write("first\n")
+ self.git(["add", "testfile"], cwd=source)
+ self.git(["commit", "-m", "first commit"], cwd=source)
+
+ recipe_url = "git://upstream.invalid/project.git;branch=master;protocol=https"
+ self.d.setVar("SRCREV", self.git(["rev-parse", "HEAD"], cwd=source).strip())
+ fetcher = bb.fetch.Fetch([recipe_url], self.d)
+ ud = fetcher.ud[recipe_url]
+ ud.setup_localpath(self.d)
+ os.makedirs(os.path.dirname(ud.clonedir), exist_ok=True)
+ self.git(["clone", "--bare", "--mirror", source, ud.clonedir], cwd=self.tempdir)
+
+ with open(testfile, "a") as f:
+ f.write("second\n")
+ self.git(["commit", "-am", "second commit"], cwd=source)
+ revision = self.git(["rev-parse", "HEAD"], cwd=source).strip()
+
+ self.d.setVar("SRCREV", revision)
+ self.d.setVar("BB_FETCH_PREMIRRORONLY", "1")
+ self.d.setVar("BB_NO_NETWORK", "1")
+ self.d.setVar("PREMIRRORS", "%s git://%s;protocol=file" % (recipe_url, source))
+
+ fetcher = bb.fetch.Fetch([recipe_url], self.d)
+ ud = fetcher.ud[recipe_url]
+ fetcher.download()
+ fetcher.unpack(self.unpackdir)
+
+ self.assertTrue(os.path.islink(ud.clonedir))
+ unpack_revision = self.git(["rev-parse", "HEAD"],
+ cwd=os.path.join(self.unpackdir, "git")).strip()
+ self.assertEqual(revision, unpack_revision)
+
+
class TarballNamingTest(FetcherTest):
def setUp(self):
super(TarballNamingTest, self).setUp()
A successful premirror fetch can leave an existing clone at the original download path even when it lacks SRCREV. The fetch is then stamped complete before unpack rejects the stale clone. Pass the datastore to update_mirror_links() and remove the original clone only when the Git validity check says it needs updating, allowing the successful mirror to be linked. The new self-test creates a stale clone at the original download path and a local premirror containing a newer SRCREV. Without the fix it reproduces the UnpackError; with the fix it verifies that the mirror is linked and the requested revision is unpacked. Tested with bitbake-selftest on Python 3.11, 3.12, 3.13, and 3.14. AI-Generated: OpenAI Codex Signed-off-by: Fredrik Svensson <fredriks@meraki.com> --- lib/bb/fetch2/__init__.py | 4 ++-- lib/bb/fetch2/git.py | 8 ++++++-- lib/bb/tests/fetch.py | 42 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 4 deletions(-)