summaryrefslogtreecommitdiffstats
path: root/bitbake
diff options
context:
space:
mode:
authorPhilip Lorenz <philip.lorenz@bmw.de>2025-04-29 10:11:19 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2025-05-08 11:37:32 +0100
commit7642477dc8550eeff75d34bd3bbdf574e2f5687c (patch)
tree9d2f00d69555411a96af5b4848e62a0741c5bfad /bitbake
parent6d0cb00c6895df6940d07dd1d5d48078e8f701f2 (diff)
downloadpoky-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.py26
-rw-r--r--bitbake/lib/bb/tests/fetch.py73
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 @@
9import contextlib 9import contextlib
10import shutil 10import shutil
11import unittest 11import unittest
12import unittest.mock
12import urllib.parse 13import urllib.parse
13import hashlib 14import hashlib
14import tempfile 15import 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
2448class GitURLWithSpacesTest(FetcherTest): 2475class GitURLWithSpacesTest(FetcherTest):
2449 test_git_urls = { 2476 test_git_urls = {