diff options
author | Philip Lorenz <philip.lorenz@bmw.de> | 2025-04-29 10:11:19 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2025-05-08 11:37:32 +0100 |
commit | 7642477dc8550eeff75d34bd3bbdf574e2f5687c (patch) | |
tree | 9d2f00d69555411a96af5b4848e62a0741c5bfad /bitbake | |
parent | 6d0cb00c6895df6940d07dd1d5d48078e8f701f2 (diff) | |
download | poky-7642477dc8550eeff75d34bd3bbdf574e2f5687c.tar.gz |
bitbake: fetch2: Check for git-lfs existence before using it
So far, existence of `git-lfs` was only checked during unpacking. As the
binary is also used in earlier steps also check for its existence there.
Additionally, factor out the LFS existence check into a dedicated
function and call it wherever git-lfs is used for the first time.
(Bitbake rev: 5818367db9b261b7e07c347d38044e6cba8f9727)
Signed-off-by: Philip Lorenz <philip.lorenz@bmw.de>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r-- | bitbake/lib/bb/fetch2/git.py | 26 | ||||
-rw-r--r-- | bitbake/lib/bb/tests/fetch.py | 73 |
2 files changed, 68 insertions, 31 deletions
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py index 39c1839277..9e58337359 100644 --- a/bitbake/lib/bb/fetch2/git.py +++ b/bitbake/lib/bb/fetch2/git.py | |||
@@ -324,6 +324,9 @@ class Git(FetchMethod): | |||
324 | return False | 324 | return False |
325 | 325 | ||
326 | def lfs_need_update(self, ud, d): | 326 | def lfs_need_update(self, ud, d): |
327 | if not self._need_lfs(ud): | ||
328 | return False | ||
329 | |||
327 | if self.clonedir_need_update(ud, d): | 330 | if self.clonedir_need_update(ud, d): |
328 | return True | 331 | return True |
329 | 332 | ||
@@ -507,7 +510,9 @@ class Git(FetchMethod): | |||
507 | def lfs_fetch(self, ud, d, clonedir, revision, fetchall=False, progresshandler=None): | 510 | def lfs_fetch(self, ud, d, clonedir, revision, fetchall=False, progresshandler=None): |
508 | """Helper method for fetching Git LFS data""" | 511 | """Helper method for fetching Git LFS data""" |
509 | try: | 512 | try: |
510 | if self._need_lfs(ud) and self._contains_lfs(ud, d, clonedir) and self._find_git_lfs(d) and len(revision): | 513 | if self._need_lfs(ud) and self._contains_lfs(ud, d, clonedir) and len(revision): |
514 | self._ensure_git_lfs(d, ud) | ||
515 | |||
511 | # Using worktree with the revision because .lfsconfig may exists | 516 | # Using worktree with the revision because .lfsconfig may exists |
512 | worktree_add_cmd = "%s worktree add wt %s" % (ud.basecmd, revision) | 517 | worktree_add_cmd = "%s worktree add wt %s" % (ud.basecmd, revision) |
513 | runfetchcmd(worktree_add_cmd, d, log=progresshandler, workdir=clonedir) | 518 | runfetchcmd(worktree_add_cmd, d, log=progresshandler, workdir=clonedir) |
@@ -740,11 +745,11 @@ class Git(FetchMethod): | |||
740 | runfetchcmd("%s remote set-url origin %s" % (ud.basecmd, shlex.quote(repourl)), d, workdir=destdir) | 745 | runfetchcmd("%s remote set-url origin %s" % (ud.basecmd, shlex.quote(repourl)), d, workdir=destdir) |
741 | 746 | ||
742 | if self._contains_lfs(ud, d, destdir): | 747 | if self._contains_lfs(ud, d, destdir): |
743 | if need_lfs and not self._find_git_lfs(d): | 748 | if not need_lfs: |
744 | raise bb.fetch2.FetchError("Repository %s has LFS content, install git-lfs on host to download (or set lfs=0 to ignore it)" % (repourl)) | ||
745 | elif not need_lfs: | ||
746 | bb.note("Repository %s has LFS content but it is not being fetched" % (repourl)) | 749 | bb.note("Repository %s has LFS content but it is not being fetched" % (repourl)) |
747 | else: | 750 | else: |
751 | self._ensure_git_lfs(d, ud) | ||
752 | |||
748 | runfetchcmd("%s lfs install --local" % ud.basecmd, d, workdir=destdir) | 753 | runfetchcmd("%s lfs install --local" % ud.basecmd, d, workdir=destdir) |
749 | 754 | ||
750 | if not ud.nocheckout: | 755 | if not ud.nocheckout: |
@@ -807,9 +812,11 @@ class Git(FetchMethod): | |||
807 | Verifies whether the LFS objects for requested revisions have already been downloaded | 812 | Verifies whether the LFS objects for requested revisions have already been downloaded |
808 | """ | 813 | """ |
809 | # Bail out early if this repository doesn't use LFS | 814 | # Bail out early if this repository doesn't use LFS |
810 | if not self._need_lfs(ud) or not self._contains_lfs(ud, d, wd): | 815 | if not self._contains_lfs(ud, d, wd): |
811 | return True | 816 | return True |
812 | 817 | ||
818 | self._ensure_git_lfs(d, ud) | ||
819 | |||
813 | # The Git LFS specification specifies ([1]) the LFS folder layout so it should be safe to check for file | 820 | # The Git LFS specification specifies ([1]) the LFS folder layout so it should be safe to check for file |
814 | # existence. | 821 | # existence. |
815 | # [1] https://github.com/git-lfs/git-lfs/blob/main/docs/spec.md#intercepting-git | 822 | # [1] https://github.com/git-lfs/git-lfs/blob/main/docs/spec.md#intercepting-git |
@@ -859,11 +866,14 @@ class Git(FetchMethod): | |||
859 | pass | 866 | pass |
860 | return False | 867 | return False |
861 | 868 | ||
862 | def _find_git_lfs(self, d): | 869 | def _ensure_git_lfs(self, d, ud): |
863 | """ | 870 | """ |
864 | Return True if git-lfs can be found, False otherwise. | 871 | Ensures that git-lfs is available, raising a FetchError if it isn't. |
865 | """ | 872 | """ |
866 | return shutil.which("git-lfs", path=d.getVar('PATH')) is not None | 873 | if shutil.which("git-lfs", path=d.getVar('PATH')) is None: |
874 | raise bb.fetch2.FetchError( | ||
875 | "Repository %s has LFS content, install git-lfs on host to download (or set lfs=0 " | ||
876 | "to ignore it)" % self._get_repo_url(ud)) | ||
867 | 877 | ||
868 | def _get_repo_url(self, ud): | 878 | def _get_repo_url(self, ud): |
869 | """ | 879 | """ |
diff --git a/bitbake/lib/bb/tests/fetch.py b/bitbake/lib/bb/tests/fetch.py index f0c628524c..c77725190f 100644 --- a/bitbake/lib/bb/tests/fetch.py +++ b/bitbake/lib/bb/tests/fetch.py | |||
@@ -9,6 +9,7 @@ | |||
9 | import contextlib | 9 | import contextlib |
10 | import shutil | 10 | import shutil |
11 | import unittest | 11 | import unittest |
12 | import unittest.mock | ||
12 | import urllib.parse | 13 | import urllib.parse |
13 | import hashlib | 14 | import hashlib |
14 | import tempfile | 15 | import tempfile |
@@ -2292,12 +2293,18 @@ class GitLfsTest(FetcherTest): | |||
2292 | self.git_init(cwd=self.srcdir) | 2293 | self.git_init(cwd=self.srcdir) |
2293 | self.commit_file('.gitattributes', '*.mp3 filter=lfs -text') | 2294 | self.commit_file('.gitattributes', '*.mp3 filter=lfs -text') |
2294 | 2295 | ||
2295 | def commit_file(self, filename, content): | 2296 | def commit(self, *, cwd=None): |
2296 | with open(os.path.join(self.srcdir, filename), "w") as f: | 2297 | cwd = cwd or self.srcdir |
2298 | self.git(["commit", "-m", "Change"], cwd=cwd) | ||
2299 | return self.git(["rev-parse", "HEAD"], cwd=cwd).strip() | ||
2300 | |||
2301 | def commit_file(self, filename, content, *, cwd=None): | ||
2302 | cwd = cwd or self.srcdir | ||
2303 | |||
2304 | with open(os.path.join(cwd, filename), "w") as f: | ||
2297 | f.write(content) | 2305 | f.write(content) |
2298 | self.git(["add", filename], cwd=self.srcdir) | 2306 | self.git(["add", filename], cwd=cwd) |
2299 | self.git(["commit", "-m", "Change"], cwd=self.srcdir) | 2307 | return self.commit(cwd=cwd) |
2300 | return self.git(["rev-parse", "HEAD"], cwd=self.srcdir).strip() | ||
2301 | 2308 | ||
2302 | def fetch(self, uri=None, download=True): | 2309 | def fetch(self, uri=None, download=True): |
2303 | uris = self.d.getVar('SRC_URI').split() | 2310 | uris = self.d.getVar('SRC_URI').split() |
@@ -2406,6 +2413,21 @@ class GitLfsTest(FetcherTest): | |||
2406 | fetcher, ud = self.fetch() | 2413 | fetcher, ud = self.fetch() |
2407 | fetcher.unpack(self.d.getVar('WORKDIR')) | 2414 | fetcher.unpack(self.d.getVar('WORKDIR')) |
2408 | 2415 | ||
2416 | @skipIfNoGitLFS() | ||
2417 | def test_lfs_enabled_not_installed_during_unpack(self): | ||
2418 | uri = 'git://%s;protocol=file;lfs=1;branch=master' % self.srcdir | ||
2419 | self.d.setVar('SRC_URI', uri) | ||
2420 | |||
2421 | # Careful: suppress initial attempt at downloading | ||
2422 | fetcher, ud = self.fetch(uri=None, download=False) | ||
2423 | |||
2424 | fetcher.download() | ||
2425 | # If git-lfs cannot be found, the unpack should throw an error | ||
2426 | with self.assertRaises(bb.fetch2.FetchError): | ||
2427 | with unittest.mock.patch("shutil.which", return_value=None): | ||
2428 | shutil.rmtree(self.gitdir, ignore_errors=True) | ||
2429 | fetcher.unpack(self.d.getVar('WORKDIR')) | ||
2430 | |||
2409 | def test_lfs_enabled_not_installed(self): | 2431 | def test_lfs_enabled_not_installed(self): |
2410 | uri = 'git://%s;protocol=file;lfs=1;branch=master' % self.srcdir | 2432 | uri = 'git://%s;protocol=file;lfs=1;branch=master' % self.srcdir |
2411 | self.d.setVar('SRC_URI', uri) | 2433 | self.d.setVar('SRC_URI', uri) |
@@ -2413,18 +2435,10 @@ class GitLfsTest(FetcherTest): | |||
2413 | # Careful: suppress initial attempt at downloading | 2435 | # Careful: suppress initial attempt at downloading |
2414 | fetcher, ud = self.fetch(uri=None, download=False) | 2436 | fetcher, ud = self.fetch(uri=None, download=False) |
2415 | 2437 | ||
2416 | # Artificially assert that git-lfs is not installed, so | 2438 | # If git-lfs cannot be found, the download should throw an error |
2417 | # we can verify a failure to unpack in it's absence. | 2439 | with unittest.mock.patch("shutil.which", return_value=None): |
2418 | old_find_git_lfs = ud.method._find_git_lfs | ||
2419 | try: | ||
2420 | # If git-lfs cannot be found, the unpack should throw an error | ||
2421 | with self.assertRaises(bb.fetch2.FetchError): | 2440 | with self.assertRaises(bb.fetch2.FetchError): |
2422 | fetcher.download() | 2441 | fetcher.download() |
2423 | ud.method._find_git_lfs = lambda d: False | ||
2424 | shutil.rmtree(self.gitdir, ignore_errors=True) | ||
2425 | fetcher.unpack(self.d.getVar('WORKDIR')) | ||
2426 | finally: | ||
2427 | ud.method._find_git_lfs = old_find_git_lfs | ||
2428 | 2442 | ||
2429 | def test_lfs_disabled_not_installed(self): | 2443 | def test_lfs_disabled_not_installed(self): |
2430 | uri = 'git://%s;protocol=file;lfs=0;branch=master' % self.srcdir | 2444 | uri = 'git://%s;protocol=file;lfs=0;branch=master' % self.srcdir |
@@ -2433,17 +2447,30 @@ class GitLfsTest(FetcherTest): | |||
2433 | # Careful: suppress initial attempt at downloading | 2447 | # Careful: suppress initial attempt at downloading |
2434 | fetcher, ud = self.fetch(uri=None, download=False) | 2448 | fetcher, ud = self.fetch(uri=None, download=False) |
2435 | 2449 | ||
2436 | # Artificially assert that git-lfs is not installed, so | 2450 | # Even if git-lfs cannot be found, the download / unpack should be successful |
2437 | # we can verify a failure to unpack in it's absence. | 2451 | with unittest.mock.patch("shutil.which", return_value=None): |
2438 | old_find_git_lfs = ud.method._find_git_lfs | 2452 | fetcher.download() |
2439 | try: | 2453 | shutil.rmtree(self.gitdir, ignore_errors=True) |
2440 | # Even if git-lfs cannot be found, the unpack should be successful | 2454 | fetcher.unpack(self.d.getVar('WORKDIR')) |
2455 | |||
2456 | def test_lfs_enabled_not_installed_but_not_needed(self): | ||
2457 | srcdir = os.path.join(self.tempdir, "emptygit") | ||
2458 | bb.utils.mkdirhier(srcdir) | ||
2459 | self.git_init(srcdir) | ||
2460 | self.commit_file("test", "test content", cwd=srcdir) | ||
2461 | |||
2462 | uri = 'git://%s;protocol=file;lfs=1;branch=master' % srcdir | ||
2463 | self.d.setVar('SRC_URI', uri) | ||
2464 | |||
2465 | # Careful: suppress initial attempt at downloading | ||
2466 | fetcher, ud = self.fetch(uri=None, download=False) | ||
2467 | |||
2468 | # It shouldnt't matter that git-lfs cannot be found as the repository configuration does not | ||
2469 | # specify any LFS filters. | ||
2470 | with unittest.mock.patch("shutil.which", return_value=None): | ||
2441 | fetcher.download() | 2471 | fetcher.download() |
2442 | ud.method._find_git_lfs = lambda d: False | ||
2443 | shutil.rmtree(self.gitdir, ignore_errors=True) | 2472 | shutil.rmtree(self.gitdir, ignore_errors=True) |
2444 | fetcher.unpack(self.d.getVar('WORKDIR')) | 2473 | fetcher.unpack(self.d.getVar('WORKDIR')) |
2445 | finally: | ||
2446 | ud.method._find_git_lfs = old_find_git_lfs | ||
2447 | 2474 | ||
2448 | class GitURLWithSpacesTest(FetcherTest): | 2475 | class GitURLWithSpacesTest(FetcherTest): |
2449 | test_git_urls = { | 2476 | test_git_urls = { |