diff options
Diffstat (limited to 'bitbake/lib/bb/fetch2/git.py')
-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): |