Example #1
0
 def process(self, index: int, count: int, repo: Repo) -> Outcome:
     # Note:
     #  When self.parallel is True, this task will be run in parallel with
     #  other tasks.
     #
     #  So we need to:
     #    * capture the output of the commands we are running
     #    * raise a DetailedCommandError instance if a command's return code
     #      is 0 (because otherwise the output of the command is lost)
     #
     # When self.parallel is False, we don't capture the output, which means we
     # can't raise a DetailedCommandError. Instead, we raise a plain CommandError
     # instance. This means the user has to go up in the output to see the output
     # of the command that failed, but also that the command output are printed
     # in real time.
     full_path = self.workspace_path / repo.dest
     if not full_path.exists():
         raise MissingRepo(repo.dest)
     # fmt: off
     self.info(ui.brown,
               self.workspace_path / repo.dest,
               " ",
               ui.lightgray,
               "$ ",
               ui.reset,
               self.description,
               sep="")
     # fmt: on
     full_path = self.workspace_path / repo.dest
     run_env = self.env_setter.get_env_for_repo(repo)
     run_env.update(os.environ)
     try:
         kwargs: Dict[str, Any] = {
             "cwd": full_path,
             "shell": self.shell,
             "env": run_env,
         }
         if self.parallel:
             kwargs["stdout"] = subprocess.PIPE
             kwargs["stderr"] = subprocess.STDOUT
         process = subprocess.run(self.command,
                                  **kwargs,
                                  universal_newlines=True)
     except OSError as e:
         raise CouldNotStartProcess("Error when starting process:", e)
     if process.returncode != 0:
         if self.parallel:
             raise DetailedCommandError(
                 working_path=full_path,
                 cmd=self.description,
                 rc=process.returncode,
                 output=process.stdout,
             )
         else:
             raise CommandError()
     return Outcome.empty()
Example #2
0
    def process(self, index: int, count: int, repo: Repo) -> Outcome:
        # We just need to compute a summary here with the log between
        # self.from_ref and self.to_ref
        #
        # Note: make sure that when there is no diff between
        # self.from_ref and self.to_ref, the summary is empty,
        # so that the repo is not shown by OutcomeCollection.print_summary()
        repo_path = self.workspace_path / repo.dest
        if not repo_path.exists():
            raise MissingRepo(repo.dest)

        # The main reason for the `git log` command to fail is if `self.from_ref` or
        # `self.to_ref` references are not found for the repo, so check for this case
        # explicitly
        rc, _ = run_git_captured(repo_path,
                                 "rev-parse",
                                 self.from_ref,
                                 check=False)
        if rc != 0:
            raise Error(f"{self.from_ref} not found")
        rc, _ = run_git_captured(repo_path,
                                 "rev-parse",
                                 self.to_ref,
                                 check=False)
        if rc != 0:
            raise Error(f"{self.to_ref} not found")

        colors = ["green", "reset", "yellow", "reset", "bold blue", "reset"]
        log_format = "%m {}%h{} - {}%d{} %s {}<%an>{}"
        log_format = log_format.format(*("%C({})".format(x) for x in colors))
        cmd = [
            "log",
            "--color=always",
            f"--pretty=format:{log_format}",
            f"{self.from_ref}...{self.to_ref}",
        ]
        rc, out = run_git_captured(repo_path, *cmd, check=True)
        if out:
            lines = [repo.dest, "-" * len(repo.dest), out]
            return Outcome.from_lines(lines)
        else:
            return Outcome.empty()
 def process(self, index: int, count: int, item: FileSystemOperation) -> Outcome:
     # Note: we don't want to run this Task in parallel, just in case
     # the order of filesystem operations matters, so we can always
     # return an empty Outcome
     description = item.describe(self.workspace_path)
     self.info_count(index, count, description)
     try:
         item.perform(self.workspace_path)
     except OSError as e:
         raise Error(str(e))
     return Outcome.empty()
Example #4
0
 def process(self, index: int, count: int, repo: Repo) -> Outcome:
     # Note:
     #
     # When self.parallel is True, the output of `git clone` and
     # `git reset` will be captured, so we need to compute a summary
     # string for the user.
     #
     # Otherwise, the output of `git clone` and
     # `git reset` will be shown directly to the user, so we can use
     # an empty summary
     self.info_count(index, count, "Cloning", repo.dest)
     self.check_shallow_with_sha1(repo)
     summary: str = ""
     summary += self.clone_repo(repo)
     summary += self.reset_repo(repo)
     return Outcome.from_summary(summary)
Example #5
0
 def process(self, index: int, count: int, repo: Repo) -> Outcome:
     # Note:
     #   When self.parallel is True we need to return a string describing
     #   all the changes, otherwise, we can just call cli_ui.info() directly
     summary_lines = []
     for remote in repo.remotes:
         existing_remote = self.get_remote(repo, remote.name)
         if existing_remote:
             if existing_remote.url != remote.url:
                 self.set_remote(repo, remote)
                 summary_lines.append(
                     f"{repo.dest}: remote '{remote.name}' set to '{remote.url}'"
                 )
         else:
             self.add_remote(repo, remote)
             summary_lines.append(
                 f"{repo.dest}: added remote '{remote.name}' with url: '{remote.url}'"
             )
     return Outcome.from_lines(summary_lines)
Example #6
0
 def process(self, index: int, count: int, repo: Repo) -> Outcome:
     # Note: Outcome is always empty here, because we
     # use self.statuses in the main `run()` function instead
     # of calling OutcomeCollection.print_summary()
     full_path = self.workspace.root_path / repo.dest
     self.info_count(index, count, repo.dest, end="\r")
     if not full_path.exists():
         self.statuses[repo.dest] = MissingRepo(repo.dest)
     try:
         git_status = get_git_status(full_path)
         manifest_status = ManifestStatus(repo, manifest=self.manifest)
         manifest_status.update(git_status)
         status = Status(git=git_status, manifest=manifest_status)
         self.statuses[repo.dest] = status
     except Exception as e:
         self.statuses[repo.dest] = e
     if not self.parallel:
         erase_last_line()
     return Outcome.empty()
Example #7
0
    def process(self, index: int, count: int, repo: Repo) -> Outcome:
        """Synchronize a repo given its configuration in the manifest.

        Always start by running `git fetch`, then either:

        * try resetting the repo to the given tag or sha1 (abort
          if the repo is dirty)

        * or try merging the local branch with its upstream (abort if not
          on on the correct branch, or if the merge is not fast-forward).
        """
        error = None
        self.info_count(index, count, "Synchronizing", repo.dest)
        self.fetch(repo)

        summary_lines = []
        ref = None
        if repo.tag:
            ref = repo.tag
        elif repo.sha1:
            ref = repo.sha1

        if ref:
            self.info_3("Resetting to", ref)
            self.sync_repo_to_ref(repo, ref)
            summary_lines += [repo.dest, "-" * len(repo.dest)]
            summary_lines += [f"Reset to {ref}"]
        else:
            error, current_branch = self.check_branch(repo)
            self.info_3("Updating branch:", current_branch)
            sync_summary = self.sync_repo_to_branch(repo, current_branch=current_branch)
            if sync_summary:
                title = f"{repo.dest} on {current_branch}"
                summary_lines += [title, "-" * len(title), sync_summary]

        if not repo.ignore_submodules:
            submodule_line = self.update_submodules(repo)
            if submodule_line:
                summary_lines.append(submodule_line)

        summary = "\n".join(summary_lines)
        return Outcome(error=error, summary=summary)
Example #8
0
 def process(self, index: int, count: int, item: str) -> Outcome:
     if item == "failing":
         raise Kaboom()
     return Outcome.empty()