Exemplo n.º 1
0
def apply_stack(repo_dir, stack, branch, default_base):
    """Apply a stack of patches on a repository"""
    assert len(stack) > 0, "Empty stack"

    # Start by updating the repository
    clean(repo_dir)

    def has_revision(revision):
        try:
            hg.identify(revision)
            return True
        except hglib.error.CommandError:
            return False

    with hglib.open(repo_dir) as hg:

        # Find the base revision to apply all the patches onto
        # Use first parent from first patch if all its parents are available
        # Otherwise fallback on tip
        parents = stack[0]["parents"]
        assert len(parents) > 0, "No parents found for first patch"
        if all(map(has_revision, parents)):
            base = parents[0]
        else:
            # Some repositories need to have the exact parent to apply
            if default_base is None:
                raise Exception(
                    "Parents are not available, cannot apply this stack")

            base = default_base

        # Update to base revision
        logger.info(f"Will apply stack on {base}")
        hg.update(base, clean=True)

        # Apply all the patches in the stack
        for rev in stack:
            node = rev["node"]
            logger.info(f"Applying patch for {node}")
            patch = get_hgmo_patch(branch, node)
            hg.import_(patches=io.BytesIO(patch.encode("utf-8")),
                       user="******")
Exemplo n.º 2
0
def apply_stack(repo_dir, stack, branch):
    """Apply a stack of patches on a repository"""
    assert len(stack) > 0, "Empty stack"

    def has_revision(revision):
        try:
            hg.identify(revision)
            return True
        except hglib.error.CommandError:
            return False

    def apply_patches(base, patches):
        # Update to base revision
        logger.info(f"Updating {repo_dir} to {base}")
        hg.update(base, clean=True)

        # Then apply each patch in the stack
        logger.info(f"Applying {len(patches)}...")
        try:
            for node, patch in patches:
                hg.import_(patches=io.BytesIO(patch.encode("utf-8")),
                           user="******")
        except hglib.error.CommandError as e:
            logger.warning(f"Failed to apply patch {node}: {e.err}")
            return False
        return True

    # Find the base revision to apply all the patches onto
    # Use first parent from first patch if all its parents are available
    # Otherwise fallback on tip
    def get_base():
        parents = stack[0]["parents"]
        assert len(parents) > 0, "No parents found for first patch"
        if all(map(has_revision, parents)):
            return parents[0]

        return "tip"

    def stack_nodes():
        return get_revs(hg, f"-{len(stack)}")

    with hglib.open(repo_dir) as hg:
        if branch != "try":
            hg.pull(
                source=f"https://hg.mozilla.org/{branch}/".encode("ascii"),
                rev=stack[-1]["pushhead"].encode("ascii"),
            )
            return [rev["node"].encode("ascii") for rev in stack]
        else:
            # Start by cleaning the repo, without pulling
            clean(hg, repo_dir, pull=False)
            logger.info("Repository cleaned")

            # Get initial base revision
            base = get_base()

            # Load all the patches in the stack
            patches = [(rev["node"], get_hgmo_patch(branch, rev["node"]))
                       for rev in stack]
            logger.info(f"Loaded {len(patches)} patches for the stack")

            # Apply all the patches in the stack on current base
            if apply_patches(base, patches):
                logger.info(f"Stack applied successfully on {base}")
                return stack_nodes()

            # We tried to apply on the valid parent and failed: cannot try another revision
            if base != "tip":
                raise Exception(f"Failed to apply on valid parent {base}")

            # We tried to apply on tip, let's try to find the valid parent after pulling
            clean(hg, repo_dir, pull=True)

            # Check if the valid base is now available
            new_base = get_base()
            if base == new_base:
                raise Exception("No valid parent found for the stack")

            if not apply_patches(new_base, patches):
                raise Exception("Failed to apply stack on second try")

            logger.info(
                f"Stack applied successfully on second try on {new_base}")

            return stack_nodes()