| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -429,7 +429,7 @@ def add(cls, repo, name, path, url=None, branch=None, no_checkout=False): | |||
| 429 | 429 | return sm | |
| 430 | 430 | ||
| 431 | 431 | def update(self, recursive=False, init=True, to_latest_revision=False, progress=None, dry_run=False, | |
| 432 | - force=False): | ||
| 432 | + force=False, keep_going=False): | ||
| 433 | 433 | """Update the repository of this submodule to point to the checkout | |
| 434 | 434 | we point at with the binsha of this instance. | |
| 435 | 435 | ||
@@ -450,6 +450,10 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress= | |||
| 450 | 450 | remote branch. This will essentially 'forget' commits. | |
| 451 | 451 | If False, local tracking branches that are in the future of their respective remote branches will simply | |
| 452 | 452 | not be moved. | |
| 453 | + :param keep_going: if True, we will ignore but log all errors, and keep going recursively. | ||
| 454 | + Unless dry_run is set as well, keep_going could cause subsequent/inherited errors you wouldn't see | ||
| 455 | + otherwise. | ||
| 456 | + In conjunction with dry_run, it can be useful to anticipate all errors when updating submodules | ||
| 453 | 457 | :note: does nothing in bare repositories | |
| 454 | 458 | :note: method is definitely not atomic if recurisve is True | |
| 455 | 459 | :return: self""" | |
@@ -470,152 +474,158 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress= | |||
| 470 | 474 | mrepo = None | |
| 471 | 475 | # END init mrepo | |
| 472 | 476 | ||
| 473 | - # ASSURE REPO IS PRESENT AND UPTODATE | ||
| 474 | - ##################################### | ||
| 475 | 477 | try: | |
| 476 | - mrepo = self.module() | ||
| 477 | - rmts = mrepo.remotes | ||
| 478 | - len_rmts = len(rmts) | ||
| 479 | - for i, remote in enumerate(rmts): | ||
| 480 | - op = FETCH | ||
| 481 | - if i == 0: | ||
| 482 | - op |= BEGIN | ||
| 483 | - # END handle start | ||
| 484 | - | ||
| 485 | - progress.update(op, i, len_rmts, prefix + "Fetching remote %s of submodule %r" % (remote, self.name)) | ||
| 486 | - #=============================== | ||
| 478 | + # ASSURE REPO IS PRESENT AND UPTODATE | ||
| 479 | + ##################################### | ||
| 480 | + try: | ||
| 481 | + mrepo = self.module() | ||
| 482 | + rmts = mrepo.remotes | ||
| 483 | + len_rmts = len(rmts) | ||
| 484 | + for i, remote in enumerate(rmts): | ||
| 485 | + op = FETCH | ||
| 486 | + if i == 0: | ||
| 487 | + op |= BEGIN | ||
| 488 | + # END handle start | ||
| 489 | + | ||
| 490 | + progress.update(op, i, len_rmts, prefix + "Fetching remote %s of submodule %r" % (remote, self.name)) | ||
| 491 | + #=============================== | ||
| 492 | + if not dry_run: | ||
| 493 | + remote.fetch(progress=progress) | ||
| 494 | + # END handle dry-run | ||
| 495 | + #=============================== | ||
| 496 | + if i == len_rmts - 1: | ||
| 497 | + op |= END | ||
| 498 | + # END handle end | ||
| 499 | + progress.update(op, i, len_rmts, prefix + "Done fetching remote of submodule %r" % self.name) | ||
| 500 | + # END fetch new data | ||
| 501 | + except InvalidGitRepositoryError: | ||
| 502 | + if not init: | ||
| 503 | + return self | ||
| 504 | + # END early abort if init is not allowed | ||
| 505 | + | ||
| 506 | + # there is no git-repository yet - but delete empty paths | ||
| 507 | + checkout_module_abspath = self.abspath | ||
| 508 | + if not dry_run and os.path.isdir(checkout_module_abspath): | ||
| 509 | + try: | ||
| 510 | + os.rmdir(checkout_module_abspath) | ||
| 511 | + except OSError: | ||
| 512 | + raise OSError("Module directory at %r does already exist and is non-empty" | ||
| 513 | + % checkout_module_abspath) | ||
| 514 | + # END handle OSError | ||
| 515 | + # END handle directory removal | ||
| 516 | + | ||
| 517 | + # don't check it out at first - nonetheless it will create a local | ||
| 518 | + # branch according to the remote-HEAD if possible | ||
| 519 | + progress.update(BEGIN | CLONE, 0, 1, prefix + "Cloning url '%s' to '%s' in submodule %r" % | ||
| 520 | + (self.url, checkout_module_abspath, self.name)) | ||
| 487 | 521 | if not dry_run: | |
| 488 | - remote.fetch(progress=progress) | ||
| 522 | + mrepo = self._clone_repo(self.repo, self.url, self.path, self.name, n=True) | ||
| 489 | 523 | # END handle dry-run | |
| 490 | - #=============================== | ||
| 491 | - if i == len_rmts - 1: | ||
| 492 | - op |= END | ||
| 493 | - # END handle end | ||
| 494 | - progress.update(op, i, len_rmts, prefix + "Done fetching remote of submodule %r" % self.name) | ||
| 495 | - # END fetch new data | ||
| 496 | - except InvalidGitRepositoryError: | ||
| 497 | - if not init: | ||
| 498 | - return self | ||
| 499 | - # END early abort if init is not allowed | ||
| 524 | + progress.update(END | CLONE, 0, 1, prefix + "Done cloning to %s" % checkout_module_abspath) | ||
| 500 | 525 | ||
| 501 | - # there is no git-repository yet - but delete empty paths | ||
| 502 | - checkout_module_abspath = self.abspath | ||
| 503 | - if not dry_run and os.path.isdir(checkout_module_abspath): | ||
| 504 | - try: | ||
| 505 | - os.rmdir(checkout_module_abspath) | ||
| 506 | - except OSError: | ||
| 507 | - raise OSError("Module directory at %r does already exist and is non-empty" | ||
| 508 | - % checkout_module_abspath) | ||
| 509 | - # END handle OSError | ||
| 510 | - # END handle directory removal | ||
| 511 | - | ||
| 512 | - # don't check it out at first - nonetheless it will create a local | ||
| 513 | - # branch according to the remote-HEAD if possible | ||
| 514 | - progress.update(BEGIN | CLONE, 0, 1, prefix + "Cloning %s to %s in submodule %r" % | ||
| 515 | - (self.url, checkout_module_abspath, self.name)) | ||
| 516 | - if not dry_run: | ||
| 517 | - mrepo = self._clone_repo(self.repo, self.url, self.path, self.name, n=True) | ||
| 518 | - # END handle dry-run | ||
| 519 | - progress.update(END | CLONE, 0, 1, prefix + "Done cloning to %s" % checkout_module_abspath) | ||
| 520 | - | ||
| 521 | - if not dry_run: | ||
| 522 | - # see whether we have a valid branch to checkout | ||
| 523 | - try: | ||
| 524 | - # find a remote which has our branch - we try to be flexible | ||
| 525 | - remote_branch = find_first_remote_branch(mrepo.remotes, self.branch_name) | ||
| 526 | - local_branch = mkhead(mrepo, self.branch_path) | ||
| 527 | - | ||
| 528 | - # have a valid branch, but no checkout - make sure we can figure | ||
| 529 | - # that out by marking the commit with a null_sha | ||
| 530 | - local_branch.set_object(util.Object(mrepo, self.NULL_BIN_SHA)) | ||
| 531 | - # END initial checkout + branch creation | ||
| 532 | - | ||
| 533 | - # make sure HEAD is not detached | ||
| 534 | - mrepo.head.set_reference(local_branch, logmsg="submodule: attaching head to %s" % local_branch) | ||
| 535 | - mrepo.head.ref.set_tracking_branch(remote_branch) | ||
| 536 | - except IndexError: | ||
| 537 | - log.warn("Failed to checkout tracking branch %s", self.branch_path) | ||
| 538 | - # END handle tracking branch | ||
| 539 | - | ||
| 540 | - # NOTE: Have to write the repo config file as well, otherwise | ||
| 541 | - # the default implementation will be offended and not update the repository | ||
| 542 | - # Maybe this is a good way to assure it doesn't get into our way, but | ||
| 543 | - # we want to stay backwards compatible too ... . Its so redundant ! | ||
| 544 | - writer = self.repo.config_writer() | ||
| 545 | - writer.set_value(sm_section(self.name), 'url', self.url) | ||
| 546 | - writer.release() | ||
| 526 | + if not dry_run: | ||
| 527 | + # see whether we have a valid branch to checkout | ||
| 528 | + try: | ||
| 529 | + # find a remote which has our branch - we try to be flexible | ||
| 530 | + remote_branch = find_first_remote_branch(mrepo.remotes, self.branch_name) | ||
| 531 | + local_branch = mkhead(mrepo, self.branch_path) | ||
| 532 | + | ||
| 533 | + # have a valid branch, but no checkout - make sure we can figure | ||
| 534 | + # that out by marking the commit with a null_sha | ||
| 535 | + local_branch.set_object(util.Object(mrepo, self.NULL_BIN_SHA)) | ||
| 536 | + # END initial checkout + branch creation | ||
| 537 | + | ||
| 538 | + # make sure HEAD is not detached | ||
| 539 | + mrepo.head.set_reference(local_branch, logmsg="submodule: attaching head to %s" % local_branch) | ||
| 540 | + mrepo.head.ref.set_tracking_branch(remote_branch) | ||
| 541 | + except IndexError: | ||
| 542 | + log.warn("Failed to checkout tracking branch %s", self.branch_path) | ||
| 543 | + # END handle tracking branch | ||
| 544 | + | ||
| 545 | + # NOTE: Have to write the repo config file as well, otherwise | ||
| 546 | + # the default implementation will be offended and not update the repository | ||
| 547 | + # Maybe this is a good way to assure it doesn't get into our way, but | ||
| 548 | + # we want to stay backwards compatible too ... . Its so redundant ! | ||
| 549 | + writer = self.repo.config_writer() | ||
| 550 | + writer.set_value(sm_section(self.name), 'url', self.url) | ||
| 551 | + writer.release() | ||
| 552 | + # END handle dry_run | ||
| 553 | + # END handle initalization | ||
| 554 | + | ||
| 555 | + # DETERMINE SHAS TO CHECKOUT | ||
| 556 | + ############################ | ||
| 557 | + binsha = self.binsha | ||
| 558 | + hexsha = self.hexsha | ||
| 559 | + if mrepo is not None: | ||
| 560 | + # mrepo is only set if we are not in dry-run mode or if the module existed | ||
| 561 | + is_detached = mrepo.head.is_detached | ||
| 547 | 562 | # END handle dry_run | |
| 548 | - # END handle initalization | ||
| 549 | - | ||
| 550 | - # DETERMINE SHAS TO CHECKOUT | ||
| 551 | - ############################ | ||
| 552 | - binsha = self.binsha | ||
| 553 | - hexsha = self.hexsha | ||
| 554 | - if mrepo is not None: | ||
| 555 | - # mrepo is only set if we are not in dry-run mode or if the module existed | ||
| 556 | - is_detached = mrepo.head.is_detached | ||
| 557 | - # END handle dry_run | ||
| 558 | - | ||
| 559 | - if mrepo is not None and to_latest_revision: | ||
| 560 | - msg_base = "Cannot update to latest revision in repository at %r as " % mrepo.working_dir | ||
| 561 | - if not is_detached: | ||
| 562 | - rref = mrepo.head.ref.tracking_branch() | ||
| 563 | - if rref is not None: | ||
| 564 | - rcommit = rref.commit | ||
| 565 | - binsha = rcommit.binsha | ||
| 566 | - hexsha = rcommit.hexsha | ||
| 567 | - else: | ||
| 568 | - log.error("%s a tracking branch was not set for local branch '%s'", msg_base, mrepo.head.ref) | ||
| 569 | - # END handle remote ref | ||
| 570 | - else: | ||
| 571 | - log.error("%s there was no local tracking branch", msg_base) | ||
| 572 | - # END handle detached head | ||
| 573 | - # END handle to_latest_revision option | ||
| 574 | - | ||
| 575 | - # update the working tree | ||
| 576 | - # handles dry_run | ||
| 577 | - if mrepo is not None and mrepo.head.commit.binsha != binsha: | ||
| 578 | - # We must assure that our destination sha (the one to point to) is in the future of our current head. | ||
| 579 | - # Otherwise, we will reset changes that might have been done on the submodule, but were not yet pushed | ||
| 580 | - # We also handle the case that history has been rewritten, leaving no merge-base. In that case | ||
| 581 | - # we behave conservatively, protecting possible changes the user had done | ||
| 582 | - may_reset = True | ||
| 583 | - if mrepo.head.commit.binsha != self.NULL_BIN_SHA: | ||
| 584 | - base_commit = mrepo.merge_base(mrepo.head.commit, hexsha) | ||
| 585 | - if len(base_commit) == 0 or base_commit[0].hexsha == hexsha: | ||
| 586 | - if force: | ||
| 587 | - log.debug("Will force checkout or reset on local branch that is possibly in the future of" + | ||
| 588 | - "the commit it will be checked out to, effectively 'forgetting' new commits") | ||
| 563 | + | ||
| 564 | + if mrepo is not None and to_latest_revision: | ||
| 565 | + msg_base = "Cannot update to latest revision in repository at %r as " % mrepo.working_dir | ||
| 566 | + if not is_detached: | ||
| 567 | + rref = mrepo.head.ref.tracking_branch() | ||
| 568 | + if rref is not None: | ||
| 569 | + rcommit = rref.commit | ||
| 570 | + binsha = rcommit.binsha | ||
| 571 | + hexsha = rcommit.hexsha | ||
| 589 | 572 | else: | |
| 590 | - log.info("Skipping %s on branch '%s' of submodule repo '%s' as it contains un-pushed commits", | ||
| 591 | - is_detached and "checkout" or "reset", mrepo.head, mrepo) | ||
| 592 | - may_reset = False | ||
| 593 | - # end handle force | ||
| 594 | - # end handle if we are in the future | ||
| 595 | - | ||
| 596 | - if may_reset and not force and mrepo.is_dirty(index=True, working_tree=True, untracked_files=True): | ||
| 597 | - raise RepositoryDirtyError(mrepo, "Cannot reset a dirty repository") | ||
| 598 | - # end handle force and dirty state | ||
| 599 | - # end handle empty repo | ||
| 600 | - | ||
| 601 | - # end verify future/past | ||
| 602 | - progress.update(BEGIN | UPDWKTREE, 0, 1, prefix + | ||
| 603 | - "Updating working tree at %s for submodule %r to revision %s" | ||
| 604 | - % (self.path, self.name, hexsha)) | ||
| 605 | - | ||
| 606 | - if not dry_run and may_reset: | ||
| 607 | - if is_detached: | ||
| 608 | - # NOTE: for now we force, the user is no supposed to change detached | ||
| 609 | - # submodules anyway. Maybe at some point this becomes an option, to | ||
| 610 | - # properly handle user modifications - see below for future options | ||
| 611 | - # regarding rebase and merge. | ||
| 612 | - mrepo.git.checkout(hexsha, force=force) | ||
| 573 | + log.error("%s a tracking branch was not set for local branch '%s'", msg_base, mrepo.head.ref) | ||
| 574 | + # END handle remote ref | ||
| 613 | 575 | else: | |
| 614 | - mrepo.head.reset(hexsha, index=True, working_tree=True) | ||
| 615 | - # END handle checkout | ||
| 616 | - # if we may reset/checkout | ||
| 617 | - progress.update(END | UPDWKTREE, 0, 1, prefix + "Done updating working tree for submodule %r" % self.name) | ||
| 618 | - # END update to new commit only if needed | ||
| 576 | + log.error("%s there was no local tracking branch", msg_base) | ||
| 577 | + # END handle detached head | ||
| 578 | + # END handle to_latest_revision option | ||
| 579 | + | ||
| 580 | + # update the working tree | ||
| 581 | + # handles dry_run | ||
| 582 | + if mrepo is not None and mrepo.head.commit.binsha != binsha: | ||
| 583 | + # We must assure that our destination sha (the one to point to) is in the future of our current head. | ||
| 584 | + # Otherwise, we will reset changes that might have been done on the submodule, but were not yet pushed | ||
| 585 | + # We also handle the case that history has been rewritten, leaving no merge-base. In that case | ||
| 586 | + # we behave conservatively, protecting possible changes the user had done | ||
| 587 | + may_reset = True | ||
| 588 | + if mrepo.head.commit.binsha != self.NULL_BIN_SHA: | ||
| 589 | + base_commit = mrepo.merge_base(mrepo.head.commit, hexsha) | ||
| 590 | + if len(base_commit) == 0 or base_commit[0].hexsha == hexsha: | ||
| 591 | + if force: | ||
| 592 | + log.debug("Will force checkout or reset on local branch that is possibly in the future of" + | ||
| 593 | + "the commit it will be checked out to, effectively 'forgetting' new commits") | ||
| 594 | + else: | ||
| 595 | + log.info("Skipping %s on branch '%s' of submodule repo '%s' as it contains un-pushed commits", | ||
| 596 | + is_detached and "checkout" or "reset", mrepo.head, mrepo) | ||
| 597 | + may_reset = False | ||
| 598 | + # end handle force | ||
| 599 | + # end handle if we are in the future | ||
| 600 | + | ||
| 601 | + if may_reset and not force and mrepo.is_dirty(index=True, working_tree=True, untracked_files=True): | ||
| 602 | + raise RepositoryDirtyError(mrepo, "Cannot reset a dirty repository") | ||
| 603 | + # end handle force and dirty state | ||
| 604 | + # end handle empty repo | ||
| 605 | + | ||
| 606 | + # end verify future/past | ||
| 607 | + progress.update(BEGIN | UPDWKTREE, 0, 1, prefix + | ||
| 608 | + "Updating working tree at %s for submodule %r to revision %s" | ||
| 609 | + % (self.path, self.name, hexsha)) | ||
| 610 | + | ||
| 611 | + if not dry_run and may_reset: | ||
| 612 | + if is_detached: | ||
| 613 | + # NOTE: for now we force, the user is no supposed to change detached | ||
| 614 | + # submodules anyway. Maybe at some point this becomes an option, to | ||
| 615 | + # properly handle user modifications - see below for future options | ||
| 616 | + # regarding rebase and merge. | ||
| 617 | + mrepo.git.checkout(hexsha, force=force) | ||
| 618 | + else: | ||
| 619 | + mrepo.head.reset(hexsha, index=True, working_tree=True) | ||
| 620 | + # END handle checkout | ||
| 621 | + # if we may reset/checkout | ||
| 622 | + progress.update(END | UPDWKTREE, 0, 1, prefix + "Done updating working tree for submodule %r" % self.name) | ||
| 623 | + # END update to new commit only if needed | ||
| 624 | + except Exception as err: | ||
| 625 | + if not keep_going: | ||
| 626 | + raise | ||
| 627 | + log.error(str(err)) | ||
| 628 | + # end handle keep_going | ||
| 619 | 629 | ||
| 620 | 630 | # HANDLE RECURSION | |
| 621 | 631 | ################## | |
@@ -624,7 +634,7 @@ def update(self, recursive=False, init=True, to_latest_revision=False, progress= | |||
| 624 | 634 | if mrepo is not None: | |
| 625 | 635 | for submodule in self.iter_items(self.module()): | |
| 626 | 636 | submodule.update(recursive, init, to_latest_revision, progress=progress, dry_run=dry_run, | |
| 627 | - force=force) | ||
| 637 | + force=force, keep_going=keep_going) | ||
| 628 | 638 | # END handle recursive update | |
| 629 | 639 | # END handle dry run | |
| 630 | 640 | # END for each submodule | |
@@ -887,13 +897,16 @@ def remove(self, module=True, force=False, configuration=True, dry_run=False): | |||
| 887 | 897 | def set_parent_commit(self, commit, check=True): | |
| 888 | 898 | """Set this instance to use the given commit whose tree is supposed to | |
| 889 | 899 | contain the .gitmodules blob. | |
| 890 | - :param commit: Commit'ish reference pointing at the root_tree, or None to always point to the | ||
| 900 | + | ||
| 901 | + :param commit: | ||
| 902 | + Commit'ish reference pointing at the root_tree, or None to always point to the | ||
| 891 | 903 | most recent commit | |
| 892 | - :param check: if True, relatively expensive checks will be performed to verify | ||
| 904 | + :param check: | ||
| 905 | + if True, relatively expensive checks will be performed to verify | ||
| 893 | 906 | validity of the submodule. | |
| 894 | 907 | :raise ValueError: if the commit's tree didn't contain the .gitmodules blob. | |
| 895 | - :raise ValueError: if the parent commit didn't store this submodule under the | ||
| 896 | - current path | ||
| 908 | + :raise ValueError: | ||
| 909 | + if the parent commit didn't store this submodule under the current path | ||
| 897 | 910 | :return: self""" | |
| 898 | 911 | if commit is None: | |
| 899 | 912 | self._parent_commit = None | |
@@ -976,7 +989,7 @@ def rename(self, new_name): | |||
| 976 | 989 | pw.release() | |
| 977 | 990 | ||
| 978 | 991 | # .gitmodules | |
| 979 | - cw = self.config_writer(write=False).config | ||
| 992 | + cw = self.config_writer(write=True).config | ||
| 980 | 993 | cw.rename_section(sm_section(self.name), sm_section(new_name)) | |
| 981 | 994 | cw.release() | |
| 982 | 995 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments