Exemplo n.º 1
0
    def Midpoint(cls, change_a, change_b):
        """Returns a Change halfway between the two given Changes.

    This function does two passes over the Changes' Commits:
    * The first pass attempts to match the lengths of the Commit lists by
      expanding DEPS to fill in any repositories that are missing from one,
      but included in the other.
    * The second pass takes the midpoint of every matched pair of Commits,
      expanding DEPS rolls as it comes across them.

    A NonLinearError is raised if there is no valid midpoint. The Changes are
    not linear if any of the following is true:
      * They have different patches.
      * Their repositories don't match even after expanding DEPS rolls.
      * The left Change comes after the right Change.
      * They are the same or adjacent.
    See change_test.py for examples of linear and nonlinear Changes.

    Args:
      change_a: The first Change in the range.
      change_b: The last Change in the range.

    Returns:
      A new Change representing the midpoint.
      The Change before the midpoint if the range has an even number of commits.

    Raises:
      NonLinearError: The Changes are not linear.
    """
        if change_a.patch != change_b.patch:
            raise commit_module.NonLinearError(
                'Change A has patch "%s" and Change B has patch "%s".' %
                (change_a.patch, change_b.patch))

        commits_a = list(change_a.commits)
        commits_b = list(change_b.commits)

        _ExpandDepsToMatchRepositories(commits_a, commits_b)
        commits_midpoint = _FindMidpoints(commits_a, commits_b)

        if commits_a == commits_midpoint:
            raise commit_module.NonLinearError(
                'Changes are the same or adjacent.')

        return cls(commits_midpoint, change_a.patch)
Exemplo n.º 2
0
def _FindMidpoints(commits_a, commits_b):
    """Returns the midpoint of two Commit lists.

  Loops through each pair of Commits and takes the midpoint. If the repositories
  don't match, a NonLinearError is raised. If the Commits are adjacent and
  represent a DEPS roll, the differing DEPs are added to the end of the lists.

  Args:
    commits_a: A list of Commits.
    commits_b: A list of Commits.

  Returns:
    A list of Commits, each of which is the midpoint of the respective Commit in
    commits_a and commits_b.

  Raises:
    NonLinearError: The lists have a different number of commits even after
      expanding DEPS rolls, a Commit pair contains differing repositories, or a
      Commit pair is in the wrong order.
  """
    commits_midpoint = []

    for commit_a, commit_b in zip_longest(commits_a, commits_b):
        if not (commit_a and commit_b):
            # If the commit lists are not the same length, bail out. That could happen
            # if commits_b has a repository that was not found in the DEPS of
            # commits_a (or vice versa); or a DEPS roll added or removed a DEP.
            raise commit_module.NonLinearError(
                'Changes have a different number of commits.')

        commit_midpoint = commit_module.Commit.Midpoint(commit_a, commit_b)
        commits_midpoint.append(commit_midpoint)
        if commit_a == commit_midpoint and commit_midpoint != commit_b:
            # Commits are adjacent.
            # Add any DEPS changes to the commit lists.
            deps_a = commit_a.Deps()
            deps_b = commit_b.Deps()
            dep_commits_a = sorted(
                commit_module.Commit.FromDep(dep)
                for dep in deps_a.difference(deps_b) if
                not _FindRepositoryUrlInCommits(commits_a, dep.repository_url))
            dep_commits_b = sorted(
                commit_module.Commit.FromDep(dep)
                for dep in deps_b.difference(deps_a) if
                not _FindRepositoryUrlInCommits(commits_b, dep.repository_url))
            commits_a += [c for c in dep_commits_a if c is not None]
            commits_b += [c for c in dep_commits_b if c is not None]

    return commits_midpoint