diff options
| -rw-r--r-- | bitbake/lib/bb/fetch2/git.py | 114 |
1 files changed, 85 insertions, 29 deletions
diff --git a/bitbake/lib/bb/fetch2/git.py b/bitbake/lib/bb/fetch2/git.py index 168f14d0c8..9a15abaa79 100644 --- a/bitbake/lib/bb/fetch2/git.py +++ b/bitbake/lib/bb/fetch2/git.py | |||
| @@ -207,6 +207,7 @@ class Git(FetchMethod): | |||
| 207 | if ud.bareclone: | 207 | if ud.bareclone: |
| 208 | ud.cloneflags += " --mirror" | 208 | ud.cloneflags += " --mirror" |
| 209 | 209 | ||
| 210 | ud.shallow_skip_fast = False | ||
| 210 | ud.shallow = d.getVar("BB_GIT_SHALLOW") == "1" | 211 | ud.shallow = d.getVar("BB_GIT_SHALLOW") == "1" |
| 211 | ud.shallow_extra_refs = (d.getVar("BB_GIT_SHALLOW_EXTRA_REFS") or "").split() | 212 | ud.shallow_extra_refs = (d.getVar("BB_GIT_SHALLOW_EXTRA_REFS") or "").split() |
| 212 | 213 | ||
| @@ -446,6 +447,24 @@ class Git(FetchMethod): | |||
| 446 | if ud.proto.lower() != 'file': | 447 | if ud.proto.lower() != 'file': |
| 447 | bb.fetch2.check_network_access(d, clone_cmd, ud.url) | 448 | bb.fetch2.check_network_access(d, clone_cmd, ud.url) |
| 448 | progresshandler = GitProgressHandler(d) | 449 | progresshandler = GitProgressHandler(d) |
| 450 | |||
| 451 | # Try creating a fast initial shallow clone | ||
| 452 | # Enabling ud.shallow_skip_fast will skip this | ||
| 453 | # If the Git error "Server does not allow request for unadvertised object" | ||
| 454 | # occurs, shallow_skip_fast is enabled automatically. | ||
| 455 | # This may happen if the Git server does not allow the request | ||
| 456 | # or if the Git client has issues with this functionality. | ||
| 457 | if ud.shallow and not ud.shallow_skip_fast: | ||
| 458 | try: | ||
| 459 | self.clone_shallow_with_tarball(ud, d) | ||
| 460 | # When the shallow clone has succeeded, use the shallow tarball | ||
| 461 | ud.localpath = ud.fullshallow | ||
| 462 | return | ||
| 463 | except: | ||
| 464 | logger.warning("Creating fast initial shallow clone failed, try initial regular clone now.") | ||
| 465 | |||
| 466 | # When skipping fast initial shallow or the fast inital shallow clone failed: | ||
| 467 | # Try again with an initial regular clone | ||
| 449 | runfetchcmd(clone_cmd, d, log=progresshandler) | 468 | runfetchcmd(clone_cmd, d, log=progresshandler) |
| 450 | 469 | ||
| 451 | # Update the checkout if needed | 470 | # Update the checkout if needed |
| @@ -508,48 +527,74 @@ class Git(FetchMethod): | |||
| 508 | if os.path.exists(os.path.join(ud.destdir, ".git", "lfs")): | 527 | if os.path.exists(os.path.join(ud.destdir, ".git", "lfs")): |
| 509 | runfetchcmd("tar -cf - lfs | tar -xf - -C %s" % ud.clonedir, d, workdir="%s/.git" % ud.destdir) | 528 | runfetchcmd("tar -cf - lfs | tar -xf - -C %s" % ud.clonedir, d, workdir="%s/.git" % ud.destdir) |
| 510 | 529 | ||
| 511 | def build_mirror_data(self, ud, d): | 530 | def lfs_fetch(self, ud, d, clonedir, revision, fetchall=False, progresshandler=None): |
| 512 | 531 | """Helper method for fetching Git LFS data""" | |
| 513 | # Create as a temp file and move atomically into position to avoid races | 532 | try: |
| 514 | @contextmanager | 533 | if self._need_lfs(ud) and self._contains_lfs(ud, d, clonedir) and self._find_git_lfs(d) and len(revision): |
| 515 | def create_atomic(filename): | 534 | # Using worktree with the revision because .lfsconfig may exists |
| 516 | fd, tfile = tempfile.mkstemp(dir=os.path.dirname(filename)) | 535 | worktree_add_cmd = "%s worktree add wt %s" % (ud.basecmd, revision) |
| 517 | try: | 536 | runfetchcmd(worktree_add_cmd, d, log=progresshandler, workdir=clonedir) |
| 518 | yield tfile | 537 | lfs_fetch_cmd = "%s lfs fetch %s" % (ud.basecmd, "--all" if fetchall else "") |
| 519 | umask = os.umask(0o666) | 538 | runfetchcmd(lfs_fetch_cmd, d, log=progresshandler, workdir=(clonedir + "/wt")) |
| 520 | os.umask(umask) | 539 | worktree_rem_cmd = "%s worktree remove -f wt" % ud.basecmd |
| 521 | os.chmod(tfile, (0o666 & ~umask)) | 540 | runfetchcmd(worktree_rem_cmd, d, log=progresshandler, workdir=clonedir) |
| 522 | os.rename(tfile, filename) | 541 | except: |
| 523 | finally: | 542 | logger.warning("Fetching LFS did not succeed.") |
| 524 | os.close(fd) | 543 | |
| 544 | @contextmanager | ||
| 545 | def create_atomic(self, filename): | ||
| 546 | """Create as a temp file and move atomically into position to avoid races""" | ||
| 547 | fd, tfile = tempfile.mkstemp(dir=os.path.dirname(filename)) | ||
| 548 | try: | ||
| 549 | yield tfile | ||
| 550 | umask = os.umask(0o666) | ||
| 551 | os.umask(umask) | ||
| 552 | os.chmod(tfile, (0o666 & ~umask)) | ||
| 553 | os.rename(tfile, filename) | ||
| 554 | finally: | ||
| 555 | os.close(fd) | ||
| 525 | 556 | ||
| 557 | def build_mirror_data(self, ud, d): | ||
| 526 | if ud.shallow and ud.write_shallow_tarballs: | 558 | if ud.shallow and ud.write_shallow_tarballs: |
| 527 | if not os.path.exists(ud.fullshallow): | 559 | if not os.path.exists(ud.fullshallow): |
| 528 | if os.path.islink(ud.fullshallow): | 560 | if os.path.islink(ud.fullshallow): |
| 529 | os.unlink(ud.fullshallow) | 561 | os.unlink(ud.fullshallow) |
| 530 | tempdir = tempfile.mkdtemp(dir=d.getVar('DL_DIR')) | 562 | self.clone_shallow_with_tarball(ud, d) |
| 531 | shallowclone = os.path.join(tempdir, 'git') | ||
| 532 | try: | ||
| 533 | self.clone_shallow_local(ud, shallowclone, d) | ||
| 534 | |||
| 535 | logger.info("Creating tarball of git repository") | ||
| 536 | with create_atomic(ud.fullshallow) as tfile: | ||
| 537 | runfetchcmd("tar -czf %s ." % tfile, d, workdir=shallowclone) | ||
| 538 | runfetchcmd("touch %s.done" % ud.fullshallow, d) | ||
| 539 | finally: | ||
| 540 | bb.utils.remove(tempdir, recurse=True) | ||
| 541 | elif ud.write_tarballs and not os.path.exists(ud.fullmirror): | 563 | elif ud.write_tarballs and not os.path.exists(ud.fullmirror): |
| 542 | if os.path.islink(ud.fullmirror): | 564 | if os.path.islink(ud.fullmirror): |
| 543 | os.unlink(ud.fullmirror) | 565 | os.unlink(ud.fullmirror) |
| 544 | 566 | ||
| 545 | logger.info("Creating tarball of git repository") | 567 | logger.info("Creating tarball of git repository") |
| 546 | with create_atomic(ud.fullmirror) as tfile: | 568 | with self.create_atomic(ud.fullmirror) as tfile: |
| 547 | mtime = runfetchcmd("{} log --all -1 --format=%cD".format(ud.basecmd), d, | 569 | mtime = runfetchcmd("{} log --all -1 --format=%cD".format(ud.basecmd), d, |
| 548 | quiet=True, workdir=ud.clonedir) | 570 | quiet=True, workdir=ud.clonedir) |
| 549 | runfetchcmd("tar -czf %s --owner oe:0 --group oe:0 --mtime \"%s\" ." | 571 | runfetchcmd("tar -czf %s --owner oe:0 --group oe:0 --mtime \"%s\" ." |
| 550 | % (tfile, mtime), d, workdir=ud.clonedir) | 572 | % (tfile, mtime), d, workdir=ud.clonedir) |
| 551 | runfetchcmd("touch %s.done" % ud.fullmirror, d) | 573 | runfetchcmd("touch %s.done" % ud.fullmirror, d) |
| 552 | 574 | ||
| 575 | def clone_shallow_with_tarball(self, ud, d): | ||
| 576 | ret = False | ||
| 577 | tempdir = tempfile.mkdtemp(dir=d.getVar('DL_DIR')) | ||
| 578 | shallowclone = os.path.join(tempdir, 'git') | ||
| 579 | try: | ||
| 580 | try: | ||
| 581 | self.clone_shallow_local(ud, shallowclone, d) | ||
| 582 | except: | ||
| 583 | logger.warning("Fash shallow clone failed, try to skip fast mode now.") | ||
| 584 | bb.utils.remove(tempdir, recurse=True) | ||
| 585 | os.mkdir(tempdir) | ||
| 586 | ud.shallow_skip_fast = True | ||
| 587 | self.clone_shallow_local(ud, shallowclone, d) | ||
| 588 | logger.info("Creating tarball of git repository") | ||
| 589 | with self.create_atomic(ud.fullshallow) as tfile: | ||
| 590 | runfetchcmd("tar -czf %s ." % tfile, d, workdir=shallowclone) | ||
| 591 | runfetchcmd("touch %s.done" % ud.fullshallow, d) | ||
| 592 | ret = True | ||
| 593 | finally: | ||
| 594 | bb.utils.remove(tempdir, recurse=True) | ||
| 595 | |||
| 596 | return ret | ||
| 597 | |||
| 553 | def clone_shallow_local(self, ud, dest, d): | 598 | def clone_shallow_local(self, ud, dest, d): |
| 554 | """ | 599 | """ |
| 555 | Shallow fetch from ud.clonedir (${DL_DIR}/git2/<gitrepo> by default): | 600 | Shallow fetch from ud.clonedir (${DL_DIR}/git2/<gitrepo> by default): |
| @@ -557,12 +602,20 @@ class Git(FetchMethod): | |||
| 557 | - For BB_GIT_SHALLOW_REVS: git fetch --shallow-exclude=<revs> rev | 602 | - For BB_GIT_SHALLOW_REVS: git fetch --shallow-exclude=<revs> rev |
| 558 | """ | 603 | """ |
| 559 | 604 | ||
| 605 | progresshandler = GitProgressHandler(d) | ||
| 606 | repourl = self._get_repo_url(ud) | ||
| 560 | bb.utils.mkdirhier(dest) | 607 | bb.utils.mkdirhier(dest) |
| 561 | init_cmd = "%s init -q" % ud.basecmd | 608 | init_cmd = "%s init -q" % ud.basecmd |
| 562 | if ud.bareclone: | 609 | if ud.bareclone: |
| 563 | init_cmd += " --bare" | 610 | init_cmd += " --bare" |
| 564 | runfetchcmd(init_cmd, d, workdir=dest) | 611 | runfetchcmd(init_cmd, d, workdir=dest) |
| 565 | runfetchcmd("%s remote add origin %s" % (ud.basecmd, ud.clonedir), d, workdir=dest) | 612 | # Use repourl when creating a fast initial shallow clone |
| 613 | # Prefer already existing full bare clones if available | ||
| 614 | if not ud.shallow_skip_fast and not os.path.exists(ud.clonedir): | ||
| 615 | remote = shlex.quote(repourl) | ||
| 616 | else: | ||
| 617 | remote = ud.clonedir | ||
| 618 | runfetchcmd("%s remote add origin %s" % (ud.basecmd, remote), d, workdir=dest) | ||
| 566 | 619 | ||
| 567 | # Check the histories which should be excluded | 620 | # Check the histories which should be excluded |
| 568 | shallow_exclude = '' | 621 | shallow_exclude = '' |
| @@ -600,10 +653,14 @@ class Git(FetchMethod): | |||
| 600 | # The ud.clonedir is a local temporary dir, will be removed when | 653 | # The ud.clonedir is a local temporary dir, will be removed when |
| 601 | # fetch is done, so we can do anything on it. | 654 | # fetch is done, so we can do anything on it. |
| 602 | adv_cmd = 'git branch -f advertise-%s %s' % (revision, revision) | 655 | adv_cmd = 'git branch -f advertise-%s %s' % (revision, revision) |
| 603 | runfetchcmd(adv_cmd, d, workdir=ud.clonedir) | 656 | if ud.shallow_skip_fast: |
| 657 | runfetchcmd(adv_cmd, d, workdir=ud.clonedir) | ||
| 604 | 658 | ||
| 605 | runfetchcmd(fetch_cmd, d, workdir=dest) | 659 | runfetchcmd(fetch_cmd, d, workdir=dest) |
| 606 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) | 660 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) |
| 661 | # Fetch Git LFS data for fast shallow clones | ||
| 662 | if not ud.shallow_skip_fast: | ||
| 663 | self.lfs_fetch(ud, d, dest, ud.revisions[ud.names[0]]) | ||
| 607 | 664 | ||
| 608 | # Apply extra ref wildcards | 665 | # Apply extra ref wildcards |
| 609 | all_refs_remote = runfetchcmd("%s ls-remote origin 'refs/*'" % ud.basecmd, \ | 666 | all_refs_remote = runfetchcmd("%s ls-remote origin 'refs/*'" % ud.basecmd, \ |
| @@ -629,7 +686,6 @@ class Git(FetchMethod): | |||
| 629 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) | 686 | runfetchcmd("%s update-ref %s %s" % (ud.basecmd, ref, revision), d, workdir=dest) |
| 630 | 687 | ||
| 631 | # The url is local ud.clonedir, set it to upstream one | 688 | # 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) | 689 | runfetchcmd("%s remote set-url origin %s" % (ud.basecmd, shlex.quote(repourl)), d, workdir=dest) |
| 634 | 690 | ||
| 635 | def unpack(self, ud, destdir, d): | 691 | def unpack(self, ud, destdir, d): |
