diff options
author | Robert Yang <liezhi.yang@windriver.com> | 2024-07-07 00:20:37 -0700 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2024-07-13 23:30:07 +0100 |
commit | e2527cf58f4f390712641a99b276b9e0aeae01c6 (patch) | |
tree | 042f0172ed1f34b3800d479dce8cfa00c0426407 /bitbake | |
parent | ae4ec59b3eff85aaa1cfe914a134e56e1d125744 (diff) | |
download | poky-e2527cf58f4f390712641a99b276b9e0aeae01c6.tar.gz |
bitbake: fetch2/git: Use git shallow fetch to implement clone_shallow_local()
This patch can make the following settings much more faster:
BB_GIT_SHALLOW = "1"
BB_GENERATE_MIRROR_TARBALLS = "1"
* The previous implementation was:
- Make a full clone for the repo from local ud.clonedir
- Use git-make-shallow to remove unneeded revs
It was very slow for recipes which have a lot of SRC_URIs, for example
vulkan-samples and docker-compose, the docker-compose can't be done after 5
hours.
$ bitbake vulkan-samples -cfetch
Before: 12 minutes
Now: 2 minutes
$ bitbake docker-compose -cfetch
Before: More than 300 minutes
Now: 15 minutes
* The patch uses git shallow fetch to fetch the repo from local
ud.clonedir:
- For BB_GIT_SHALLOW_DEPTH: git fetch --depth <depth> rev
- For BB_GIT_SHALLOW_REVS: git fetch --shallow-exclude=<revs> rev
Then the git repo will be shallow, and git-make-shallow is not needed any
more.
And git shallow fetch will download less commits than before since it doesn't
need "rev^" to parse the dependencies, the previous code always need 'rev^'.
(Bitbake rev: a5a569c075224fe41707cfa9123c442d1fda2fbf)
Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'bitbake')
-rw-r--r-- | bitbake/lib/bb/fetch2/git.py | 78 |
1 files changed, 52 insertions, 26 deletions
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py index c7ff769fdf..16bc1f1cf8 100644 --- a/bitbake/lib/bb/fetch2/git.py +++ b/bitbake/lib/bb/fetch2/git.py | |||
@@ -551,18 +551,31 @@ class Git(FetchMethod): | |||
551 | runfetchcmd("touch %s.done" % ud.fullmirror, d) | 551 | runfetchcmd("touch %s.done" % ud.fullmirror, d) |
552 | 552 | ||
553 | def clone_shallow_local(self, ud, dest, d): | 553 | def clone_shallow_local(self, ud, dest, d): |
554 | """Clone the repo and make it shallow. | 554 | """ |
555 | Shallow fetch from ud.clonedir (${DL_DIR}/git2/<gitrepo> by default): | ||
556 | - For BB_GIT_SHALLOW_DEPTH: git fetch --depth <depth> rev | ||
557 | - For BB_GIT_SHALLOW_REVS: git fetch --shallow-exclude=<revs> rev | ||
558 | """ | ||
559 | |||
560 | bb.utils.mkdirhier(dest) | ||
561 | init_cmd = "%s init -q" % ud.basecmd | ||
562 | if ud.bareclone: | ||
563 | init_cmd += " --bare" | ||
564 | runfetchcmd(init_cmd, d, workdir=dest) | ||
565 | runfetchcmd("%s remote add origin %s" % (ud.basecmd, ud.clonedir), d, workdir=dest) | ||
555 | 566 | ||
556 | The upstream url of the new clone isn't set at this time, as it'll be | 567 | # Check the histories which should be excluded |
557 | set correctly when unpacked.""" | 568 | shallow_exclude = '' |
558 | runfetchcmd("%s clone %s %s %s" % (ud.basecmd, ud.cloneflags, ud.clonedir, dest), d) | 569 | for revision in ud.shallow_revs: |
570 | shallow_exclude += " --shallow-exclude=%s" % revision | ||
559 | 571 | ||
560 | to_parse, shallow_branches = [], [] | ||
561 | for name in ud.names: | 572 | for name in ud.names: |
562 | revision = ud.revisions[name] | 573 | revision = ud.revisions[name] |
563 | depth = ud.shallow_depths[name] | 574 | depth = ud.shallow_depths[name] |
564 | if depth: | 575 | |
565 | to_parse.append('%s~%d^{}' % (revision, depth - 1)) | 576 | # The --depth and --shallow-exclude can't be used together |
577 | if depth and shallow_exclude: | ||
578 | raise bb.fetch2.FetchError("BB_GIT_SHALLOW_REVS is set, but BB_GIT_SHALLOW_DEPTH is not 0.") | ||
566 | 579 | ||
567 | # For nobranch, we need a ref, otherwise the commits will be | 580 | # For nobranch, we need a ref, otherwise the commits will be |
568 | # removed, and for non-nobranch, we truncate the branch to our | 581 | # removed, and for non-nobranch, we truncate the branch to our |
@@ -575,36 +588,49 @@ class Git(FetchMethod): | |||
575 | else: | 588 | else: |
576 | ref = "refs/remotes/origin/%s" % branch | 589 | ref = "refs/remotes/origin/%s" % branch |
577 | 590 | ||
578 | shallow_branches.append(ref) | 591 | fetch_cmd = "%s fetch origin %s" % (ud.basecmd, revision) |
579 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) | 592 | if depth: |
593 | fetch_cmd += " --depth %s" % depth | ||
594 | |||
595 | if shallow_exclude: | ||
596 | fetch_cmd += shallow_exclude | ||
580 | 597 | ||
581 | # Map srcrev+depths to revisions | 598 | # Advertise the revision for lower version git such as 2.25.1: |
582 | parsed_depths = runfetchcmd("%s rev-parse %s" % (ud.basecmd, " ".join(to_parse)), d, workdir=dest) | 599 | # error: Server does not allow request for unadvertised object. |
600 | # The ud.clonedir is a local temporary dir, will be removed when | ||
601 | # fetch is done, so we can do anything on it. | ||
602 | adv_cmd = 'git branch -f advertise-%s %s' % (revision, revision) | ||
603 | runfetchcmd(adv_cmd, d, workdir=ud.clonedir) | ||
583 | 604 | ||
584 | # Resolve specified revisions | 605 | runfetchcmd(fetch_cmd, d, workdir=dest) |
585 | parsed_revs = runfetchcmd("%s rev-parse %s" % (ud.basecmd, " ".join('"%s^{}"' % r for r in ud.shallow_revs)), d, workdir=dest) | 606 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) |
586 | shallow_revisions = parsed_depths.splitlines() + parsed_revs.splitlines() | ||
587 | 607 | ||
588 | # Apply extra ref wildcards | 608 | # Apply extra ref wildcards |
589 | all_refs = runfetchcmd('%s for-each-ref "--format=%%(refname)"' % ud.basecmd, | 609 | all_refs_remote = runfetchcmd("%s ls-remote origin 'refs/*'" % ud.basecmd, \ |
590 | d, workdir=dest).splitlines() | 610 | d, workdir=dest).splitlines() |
611 | all_refs = [] | ||
612 | for line in all_refs_remote: | ||
613 | all_refs.append(line.split()[-1]) | ||
614 | extra_refs = [] | ||
591 | for r in ud.shallow_extra_refs: | 615 | for r in ud.shallow_extra_refs: |
592 | if not ud.bareclone: | 616 | if not ud.bareclone: |
593 | r = r.replace('refs/heads/', 'refs/remotes/origin/') | 617 | r = r.replace('refs/heads/', 'refs/remotes/origin/') |
594 | 618 | ||
595 | if '*' in r: | 619 | if '*' in r: |
596 | matches = filter(lambda a: fnmatch.fnmatchcase(a, r), all_refs) | 620 | matches = filter(lambda a: fnmatch.fnmatchcase(a, r), all_refs) |
597 | shallow_branches.extend(matches) | 621 | extra_refs.extend(matches) |
598 | else: | 622 | else: |
599 | shallow_branches.append(r) | 623 | extra_refs.append(r) |
600 | 624 | ||
601 | # Make the repository shallow | 625 | for ref in extra_refs: |
602 | shallow_cmd = [self.make_shallow_path, '-s'] | 626 | ref_fetch = os.path.basename(ref) |
603 | for b in shallow_branches: | 627 | runfetchcmd("%s fetch origin --depth 1 %s" % (ud.basecmd, ref_fetch), d, workdir=dest) |
604 | shallow_cmd.append('-r') | 628 | revision = runfetchcmd("%s rev-parse FETCH_HEAD" % ud.basecmd, d, workdir=dest) |
605 | shallow_cmd.append(b) | 629 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) |
606 | shallow_cmd.extend(shallow_revisions) | 630 | |
607 | runfetchcmd(subprocess.list2cmdline(shallow_cmd), d, workdir=dest) | 631 | # The url is local ud.clonedir, set it to upstream one |
632 | repourl = self._get_repo_url(ud) | ||
633 | runfetchcmd("%s remote set-url origin %s" % (ud.basecmd, shlex.quote(repourl)), d, workdir=dest) | ||
608 | 634 | ||
609 | def unpack(self, ud, destdir, d): | 635 | def unpack(self, ud, destdir, d): |
610 | """ unpack the downloaded src to destdir""" | 636 | """ unpack the downloaded src to destdir""" |