Exemple #1
0
def rebase_patches(without_git_rebase=True, directory=None):
    ### Ensure a clean/valid working environment
    ensure_clean_working_env(git_status=True, directory=directory)
    ### Make sure we need to actually call this
    # Get the current branch
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    # Get the patches branch
    patches_branch = 'patches/' + current_branch
    # Get the current patches.conf
    config = get_patch_config(patches_branch, directory=directory)

    ### Execute the rebase
    if without_git_rebase:
        non_git_rebase(config['parent'], directory=directory)
    else:
        git_rebase(config['parent'], directory=directory)

    ### Update the patches information
    # Get the latest configs
    config = get_patch_config(patches_branch, directory)
    # Set the base to the current hash (before patches)
    current_branch_ = get_current_branch(directory)
    debug('Current branch: ' + current_branch_ or 'could not determine branch')
    config['base'] = get_commit_hash(current_branch_, directory)
    debug('New current commit hash after rebase: ' + config['base'])
    # Set the new upstream hash to the previous upstream hash
    config['previous'] = get_commit_hash(config['parent'], directory)
    debug('New parent commit hash after rebase: ' + config['previous'])
    # Clear the trimbase (it needs to be reapplied)
    config['trimbase'] = ''
    # Write the new configs
    set_patch_config(patches_branch, config, directory)
Exemple #2
0
def rebase_patches(without_git_rebase=True, directory=None):
    ### Ensure a clean/valid working environment
    ensure_clean_working_env(git_status=True, directory=directory)
    ### Make sure we need to actually call this
    # Get the current branch
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    # Get the patches branch
    patches_branch = 'patches/' + current_branch
    # Get the current patches.conf
    config = get_patch_config(patches_branch, directory=directory)

    ### Execute the rebase
    if without_git_rebase:
        non_git_rebase(config['parent'], directory=directory)
    else:
        git_rebase(config['parent'], directory=directory)

    ### Update the patches information
    # Get the latest configs
    config = get_patch_config(patches_branch, directory)
    # Set the base to the current hash (before patches)
    current_branch_ = get_current_branch(directory)
    debug('Current branch: ' + current_branch_ or 'could not determine branch')
    config['base'] = get_commit_hash(current_branch_, directory)
    debug('New current commit hash after rebase: ' + config['base'])
    # Set the new upstream hash to the previous upstream hash
    config['previous'] = get_commit_hash(config['parent'], directory)
    debug('New parent commit hash after rebase: ' + config['previous'])
    # Clear the trimbase (it needs to be reapplied)
    config['trimbase'] = ''
    # Write the new configs
    set_patch_config(patches_branch, config, directory)
Exemple #3
0
def rebase_patches(without_git_rebase=True, directory=None):
    ### Ensure a clean/valid working environment
    ret = ensure_clean_working_env(git_status=True, directory=directory)
    if ret != 0:
        return ret
    ### Make sure we need to actually call this
    # Get the current branch
    current_branch = get_current_branch(directory)
    # Get the patches branch
    patches_branch = "patches/" + current_branch
    # Get the current patches.conf
    config = get_patch_config(patches_branch, directory=directory)
    # Get the current upstream commit hash
    upstream_commit_hash = get_commit_hash(config["parent"], directory)
    # If the current upstream commit hash is the same as the stored one, noop
    if upstream_commit_hash == config["previous"]:
        debug(
            "Nothing to do: Current branch (" + current_branch + ")'s "
            "base commit hash is the same as the source branch (" + config["parent"] + ")'s commit hash."
        )
        debug("    Did you forget to update the parent branch first?")
        debug(
            "    Updating the parent branch can be done by calling "
            "'git-bloom-patch rebase' on it, or 'git-bloom-import-upsteam'"
            " if the parent branch is the upstream branch."
        )
        return 0
    else:
        debug(
            "rebase_patches: "
            + upstream_commit_hash
            + " == "
            + config["previous"]
            + ": "
            + str(upstream_commit_hash == config["previous"])
        )

    ### Execute the rebase
    if without_git_rebase:
        non_git_rebase(config["parent"], directory=directory)
    else:
        git_rebase(config["parent"], directory=directory)

    ### Update the patches information
    # Get the latest configs
    config = get_patch_config(patches_branch, directory)
    # Set the base to the current hash (before patches)
    config["base"] = get_commit_hash(current_branch, directory)
    # Set the new upstream hash to the previous upstream hash
    config["previous"] = get_commit_hash(config["parent"], directory)
    # Clear the trimbase (it needs to be reapplied)
    config["trimbase"] = ""
    # Write the new configs
    set_patch_config(patches_branch, config, directory)
    return 0
Exemple #4
0
 def post_rebase(self, destination):
     # Determine the current package being generated
     name = destination.split('/')[-1]
     distro = destination.split('/')[-2]
     # Retrieve the stackage
     stackage, kind = self.packages[name]
     # Ask to continue if interactive
     if self.interactive:
         if not maybe_continue('y'):
             error("Answered no to continue, aborting.")
             return code.ANSWERED_NO_TO_CONTINUE
     ### Start debian generation
     # Get time of day
     from dateutil import tz
     stamp = datetime.datetime.now(tz.tzlocal())
     # Convert stackage to debian data
     data = self.convert_stackage_to_debian_data(stackage, kind)
     # Get apt_installer from rosdep
     from rosdep2.catkin_support import get_installer
     self.apt_installer = get_installer(APT_INSTALLER)
     # Create debians for each distro
     with inbranch(destination):
         self.generate_debian(data, stamp, distro)
         # Create the tag name for later
         self.tag_names[destination] = self.generate_tag_name(data)
     # Update the patch configs
     patches_branch = 'patches/' + destination
     config = get_patch_config(patches_branch)
     # Store it
     self.store_original_config(config, patches_branch)
     # Modify the base so import/export patch works
     config['base'] = get_commit_hash(get_current_branch())
     # Set it
     set_patch_config(patches_branch, config)
Exemple #5
0
 def post_rebase(self, destination):
     name = destination.split('/')[-1]
     # Retrieve the package
     package = self.packages[name]
     # Handle differently if this is an rpm vs distro branch
     if destination in self.rpm_branches:
         info("Placing RPM template files into '{0}' branch."
              .format(destination))
         # Then this is an rpm branch
         # Place the raw template files
         self.place_template_files()
     else:
         # This is a distro specific rpm branch
         # Determine the current package being generated
         distro = destination.split('/')[-2]
         # Create RPMs for each distro
         with inbranch(destination):
             data = self.generate_rpm(package, distro)
             # Create the tag name for later
             self.tag_names[destination] = self.generate_tag_name(data)
     # Update the patch configs
     patches_branch = 'patches/' + destination
     config = get_patch_config(patches_branch)
     # Store it
     self.store_original_config(config, patches_branch)
     # Modify the base so import/export patch works
     current_branch = get_current_branch()
     if current_branch is None:
         error("Could not determine current branch.", exit=True)
     config['base'] = get_commit_hash(current_branch)
     # Set it
     set_patch_config(patches_branch, config)
Exemple #6
0
    def post_rebase(self, destination):
        name = destination.split('/')[-1]
        # Retrieve the package
        package = self.packages[name]
        # Handle differently if this is an arch vs distro branch
        if destination in self.arch_branches:
            info("Placing Arch template files into '{0}' branch."
                 .format(destination))
            # Then this is an arch branch
            # Place the raw template files
            self.place_template_files()
        else:
            # This is a distro specific arch branch
            # Determine the current package being generated
            distro = destination.split('/')[-2]

            # Create Arch packages for each distro
            with inbranch(destination):

                # To fit Arch Linux philosophy a bit better, we move all the source files into a subdirectory.
                # Arch Linux doesn't support source distribution through a subdirectory; therefore we should ideally compress the sources or provide a URL.
                # At this point in the generator, it is tricky to get the release URL. Furthermore it wouldn't fit bloom's patch mechanism very well.
                # To work around, we copy the sources to the $srcdir at the beginning inside the prepare() function.
                temp_dir = mkdtemp(dir='.')
                for item in os.listdir("."):
                    itemsrc = os.path.abspath(item)
                    if os.path.basename(itemsrc) in ['.', '..', '.git', '.svn', 'arch',os.path.basename(temp_dir)]:
                        continue
                    itemdst = os.path.abspath(os.path.join(temp_dir,item))
                    execute_command('git mv ' + itemsrc + ' ' + itemdst)
                execute_command('git mv ' + temp_dir + ' ' + name)
                execute_command('git commit --amend --no-edit')

                # Then generate the PKGBUILD
                data = self.generate_arch(package, distro)

                # And finally move the PKGBUILD to the root directory of the package.
                for item in os.listdir("arch"):
                    itemsrc = os.path.abspath(os.path.join("arch",item))
                    if os.path.basename(itemsrc) in ['.', '..', '.git', '.svn']:
                        continue
                    itemdst = os.path.abspath(item)
                    execute_command('git mv ' + itemsrc + ' ' + itemdst)
                execute_command('git commit --amend --no-edit')

                # Create the tag name for later
                self.tag_names[destination] = self.generate_tag_name(data)

        # Update the patch configs
        patches_branch = 'patches/' + destination
        config = get_patch_config(patches_branch)
        # Store it
        self.store_original_config(config, patches_branch)
        # Modify the base so import/export patch works
        current_branch = get_current_branch()
        if current_branch is None:
            error("Could not determine current branch.", exit=True)
        config['base'] = get_commit_hash(current_branch)
        # Set it
        set_patch_config(patches_branch, config)
Exemple #7
0
 def post_rebase(self, destination):
     name = destination.split('/')[-1]
     # Retrieve the package
     package = self.packages[name]
     # Handle differently if this is a debian vs distro branch
     if destination in self.debian_branches:
         info("Placing debian template files into '{0}' branch.".format(
             destination))
         # Then this is a debian branch
         # Place the raw template files
         self.place_template_files()
     else:
         # This is a distro specific debian branch
         # Determine the current package being generated
         distro = destination.split('/')[-2]
         # Create debians for each distro
         with inbranch(destination):
             data = self.generate_debian(package, distro)
             # Create the tag name for later
             self.tag_names[destination] = self.generate_tag_name(data)
     # Update the patch configs
     patches_branch = 'patches/' + destination
     config = get_patch_config(patches_branch)
     # Store it
     self.store_original_config(config, patches_branch)
     # Modify the base so import/export patch works
     current_branch = get_current_branch()
     if current_branch is None:
         error("Could not determine current branch.", exit=True)
     config['base'] = get_commit_hash(current_branch)
     # Set it
     set_patch_config(patches_branch, config)
Exemple #8
0
def _trim(config, force, directory):
    debug("_trim(" + str(config) + ", " + str(force) + ", " + \
          str(directory) + ")")
    if config['trimbase'] != '':
        warning("It looks like the trim operation has already been done, "
                "nested trimming is not supported.")
        if force:
            warning("Proceeding anyways because of '--force'")
        else:
            warning("If you would like to continue anyways use '--force'")
            return None
    config['trimbase'] = get_commit_hash(get_current_branch(directory))
    tmp_dir = tempfile.mkdtemp()
    try:
        # Buckup trim sub directory
        git_root = get_root()
        sub_dir = os.path.join(git_root, config['trim'])
        storage = os.path.join(tmp_dir, config['trim'])
        shutil.copytree(sub_dir, storage)
        # Clear out the git repo
        execute_command('git rm -rf ./*', cwd=directory)
        # Copy the sub directory back
        for item in os.listdir(storage):
            src = os.path.join(storage, item)
            dst = os.path.join(git_root, item)
            if os.path.isdir(src):
                shutil.copytree(src, dst)
            else:
                shutil.copy(src, dst)
        # Stage
        execute_command('git add ./*', cwd=directory)
        # Commit
        cmd = 'git commit -m "Trimmed the branch to only the ' + \
              config['trim'] + ' sub directory"'
        execute_command(cmd, cwd=directory)
        # Update the patch base to be this commit
        config['base'] = get_commit_hash(get_current_branch(directory))
    finally:
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)
    return config
Exemple #9
0
def remove_patches(directory=None):
    # Get the current branch
    current_branch = get_current_branch(directory)
    # Ensure the current branch is valid
    if current_branch is None:
        error("Could not determine current branch, are you in a git repo?")
        return 1
    # Construct the patches branch
    patches_branch = 'patches/' + current_branch
    try:
        # See if the patches branch exists
        if branch_exists(patches_branch, False, directory=directory):
            if not branch_exists(patches_branch, True, directory=directory):
                track_branches(patches_branch, directory)
        else:
            error("No patches branch (" + patches_branch + ") found, cannot "
                  "remove patches.")
            return 1
        # Get the parent branch from the patches branch
        config = get_patch_config(patches_branch, directory=directory)
        parent, spec = config['parent'], config['base']
        if None in [parent, spec]:
            error("Could not retrieve patches info.")
            return 1
        debug("Removing patches from " + current_branch + " back to base "
              "commit " + spec)
        # Reset this branch using git revert --no-edit spec
        current_commit = get_commit_hash(current_branch, directory)
        command_spec = spec + '..' + current_commit
        execute_command(
            'git revert --no-edit -Xtheirs ' + command_spec, cwd=directory
        )
        # Update the base
        config['base'] = get_commit_hash(current_branch, directory)
        set_patch_config(patches_branch, config, directory=directory)
    finally:
        if current_branch:
            checkout(current_branch, directory=directory)
    return 0
Exemple #10
0
def remove_patches(directory=None):
    # Get the current branch
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    # Ensure the current branch is valid
    if current_branch is None:
        error("Could not determine current branch, are you in a git repo?",
              exit=True)
    # Construct the patches branch
    patches_branch = 'patches/' + current_branch
    try:
        # See if the patches branch exists
        if branch_exists(patches_branch, False, directory=directory):
            if not branch_exists(patches_branch, True, directory=directory):
                track_branches(patches_branch, directory)
        else:
            error("No patches branch (" + patches_branch + ") found, cannot "
                  "remove patches.",
                  exit=True)
        # Get the parent branch from the patches branch
        config = get_patch_config(patches_branch, directory=directory)
        parent, spec = config['parent'], config['base']
        if None in [parent, spec]:
            error("Could not retrieve patches info.", exit=True)
        debug("Removing patches from " + current_branch + " back to base "
              "commit " + spec)
        # Reset this branch using git revert --no-edit spec
        current_commit = get_commit_hash(current_branch, directory)
        command_spec = spec + '..' + current_commit
        execute_command('git revert --no-edit -Xtheirs ' + command_spec,
                        cwd=directory)
        # Update the base
        config['base'] = get_commit_hash(current_branch, directory)
        set_patch_config(patches_branch, config, directory=directory)
    finally:
        if current_branch:
            checkout(current_branch, directory=directory)
Exemple #11
0
def _undo(config, directory):
    debug("_undo(" + str(config) + ", " + str(directory) + ")")
    # TODO: handle repo with changes
    # TODO: handle repo with patches applied
    if config['trimbase'] == '':
        debug("Branch has not been trimmed previously, undo not required.")
        return None
    # Reset with git-revert
    cmt = get_commit_hash(get_current_branch(directory), directory)
    cmd = 'git revert --no-edit -Xtheirs ' + config['trimbase'] + '..' + cmt
    execute_command(cmd, cwd=directory)
    # Unset the trimbase
    config['trimbase'] = ''
    return config
Exemple #12
0
def import_patches(directory=None):
    # Get current branch
    current_branch = get_current_branch(directory)
    # Construct the patches branch name
    patches_branch = 'patches/' + current_branch
    # Ensure the patches branch exists and is tracked
    if branch_exists(patches_branch, False, directory=directory):
        if not branch_exists(patches_branch, True, directory=directory):
            track_branches(patches_branch, directory)
    else:
        error("The patches branch ({0}) does not ".format(patches_branch) + \
              "exist, did you use git-bloom-branch?")
        return code.BRANCH_DOES_NOT_EXIST
    # Create a swap space
    tmp_dir = tempfile.mkdtemp()
    try:
        # Get parent branch and base commit from patches branch
        config = get_patch_config(patches_branch, directory)
        parent_branch, commit = config['parent'], config['base']
        if commit != get_commit_hash(current_branch, directory):
            warning("The current commit is not the same as the most recent "
                    "rebase commit. This might mean that you have committed "
                    "since the last time you did 'git-bloom-patch export'.")
            return code.PATCHES_NOT_EXPORTED
        # Checkout to the patches branch
        checkout(patches_branch, directory=directory)
        # Copy the patches to a temp location
        patches = list_patches(directory)
        if len(patches) == 0:
            debug("No patches in the patches branch, nothing to do")
            return code.NOTHING_TO_DO
        tmp_dir_patches = []
        for patch in patches:
            tmp_dir_patches.append(os.path.join(tmp_dir, patch))
            if directory is not None:
                patch = os.path.join(directory, patch)
            shutil.copy(patch, tmp_dir)
        # Now checkout back to the original branch and import them
        checkout(current_branch, directory=directory)
        cmd = 'git am {0}*.patch'.format(tmp_dir + os.sep)
        execute_command(cmd, cwd=directory)
        # Notify the user
        info("Applied {0} patches".format(len(patches)))
    finally:
        if current_branch:
            checkout(current_branch, directory=directory)
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)
    return 0
Exemple #13
0
 def post_rebase(self, destination):
     name = destination.split('/')[-1]
     # Retrieve the stackage
     stackage, kind = self.packages[name]
     # Handle differently if this is a debian vs distro branch
     if destination in self.debian_branches:
         info("Placing debian template files into '{0}' branch.".format(destination))
         # Check for valid CMakeLists.txt if a metapackage
         if kind == 'package' and is_metapackage(stackage):
             check_metapackage_for_valid_cmake(name)
         # Then this is a debian branch
         # Place the raw template files
         self.place_tempalte_files()
     else:
         # Check for valid CMakeLists.txt if a metapackage
         if kind == 'package' and is_metapackage(stackage):
             check_metapackage_for_valid_cmake(name)
         # This is a distro specific debian branch
         # Determine the current package being generated
         distro = destination.split('/')[-2]
         ### Start debian generation
         # Get time of day
         from dateutil import tz
         stamp = datetime.datetime.now(tz.tzlocal())
         # Convert stackage to debian data
         data = self.convert_stackage_to_debian_data(stackage, kind)
         # Get apt_installer from rosdep
         from rosdep2.catkin_support import get_installer
         self.apt_installer = get_installer(APT_INSTALLER)
         # Create debians for each distro
         with inbranch(destination):
             self.generate_debian(data, stamp, distro)
             # Create the tag name for later
             self.tag_names[destination] = self.generate_tag_name(data)
     # Update the patch configs
     patches_branch = 'patches/' + destination
     config = get_patch_config(patches_branch)
     # Store it
     self.store_original_config(config, patches_branch)
     # Modify the base so import/export patch works
     current_branch = get_current_branch()
     if current_branch is None:
         error("Could not determine current branch.", exit=True)
     config['base'] = get_commit_hash(current_branch)
     # Set it
     set_patch_config(patches_branch, config)
Exemple #14
0
def _undo(config, directory):
    debug("_undo(" + str(config) + ", " + str(directory) + ")")
    # TODO: handle repo with changes
    # TODO: handle repo with patches applied
    if config["trimbase"] == "":
        debug("Branch has not been trimmed previously, undo not required.")
        return None
    # Reset with git-revert
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    cmt = get_commit_hash(current_branch, directory)
    cmd = "git revert --no-edit -Xtheirs " + config["trimbase"] + ".." + cmt
    execute_command(cmd, cwd=directory)
    # Unset the trimbase
    config["trimbase"] = ""
    return config
Exemple #15
0
def _undo(config, directory):
    debug("_undo(" + str(config) + ", " + str(directory) + ")")
    # TODO: handle repo with changes
    # TODO: handle repo with patches applied
    if config['trimbase'] == '':
        debug("Branch has not been trimmed previously, undo not required.")
        return None
    # Reset with git-revert
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    cmt = get_commit_hash(current_branch, directory)
    cmd = 'git revert --no-edit -Xtheirs ' + config['trimbase'] + '..' + cmt
    execute_command(cmd, cwd=directory)
    # Unset the trimbase
    config['trimbase'] = ''
    return config
def main(sysargs=None):
    parser = get_argument_parser()
    parser = add_global_arguments(parser)
    args = parser.parse_args(sysargs)
    handle_global_arguments(args)

    # Check that the current directory is a serviceable git/bloom repo
    ret = ensure_clean_working_env()
    if ret != 0:
        parser.print_usage()
        return ret

    # Get the current git branch
    current_branch = get_current_branch()

    # Create a working temp directory
    tmp_dir = create_temporary_directory()

    cwd = os.getcwd()

    try:
        # Get off upstream branch
        if current_branch == 'upstream':
            checkout(get_commit_hash('upstream'), directory=cwd)

        retcode = import_upstream(cwd, tmp_dir, args)

        # Done!
        retcode = retcode if retcode is not None else 0
        if retcode == 0:
            info("I'm happy.  You should be too.")

        return retcode
    finally:
        # Change back to the original cwd
        os.chdir(cwd)
        # Clean up
        shutil.rmtree(tmp_dir)
        if current_branch and branch_exists(current_branch, True, cwd):
            checkout(current_branch, directory=cwd)
Exemple #17
0
def execute_branch(src, dst, interactive, directory=None):
    """
    Changes to the destination branch, creates branch and patches/branch
    if they do not exist.

    If the dst branch does not exist yet, then it is created by branching the
    current working branch or the specified SRC_BRANCH.

    If the patches/dst branch branch does not exist yet then it is created.

    If the branches are created successful, then the working branch will be
    set to the dst branch, otherwise the working branch will remain unchanged.

    :param src: source branch from which to copy
    :param dst: destination branch
    :param interactive: if True actions are summarized before committing
    :param directory: directory in which to preform this action

    :raises: subprocess.CalledProcessError if any git calls fail
    """
    # Determine if the srouce branch exists
    if src is None:
        error("No source specified and/or not a branch currently", exit=True)
    if branch_exists(src, local_only=False, directory=directory):
        if not branch_exists(src, local_only=True, directory=directory):
            debug("Tracking source branch: {0}".format(src))
            track_branches(src, directory)
    elif tag_exists(src):
        pass
    else:
        error("Specified source branch does not exist: {0}".format(src), exit=True)

    # Determine if the destination branch needs to be created
    create_dst_branch = False
    if branch_exists(dst, local_only=False, directory=directory):
        if not branch_exists(dst, local_only=True, directory=directory):
            debug("Tracking destination branch: {0}".format(dst))
            track_branches(dst, directory)
    else:
        create_dst_branch = True

    # Determine if the destination patches branch needs to be created
    create_dst_patches_branch = False
    dst_patches = "patches/" + dst
    if branch_exists(dst_patches, False, directory=directory):
        if not branch_exists(dst_patches, True, directory=directory):
            track_branches(dst_patches, directory)
    else:
        create_dst_patches_branch = True

    # Summarize
    if interactive:
        info("Summary of changes:")
        if create_dst_branch:
            info(
                " " * 22
                + "- The specified destination branch, "
                + ansi("boldon")
                + dst
                + ansi("reset")
                + ", does not exist; it will be created from the source "
                "branch " + ansi("boldon") + src + ansi("reset")
            )
        if create_dst_patches_branch:
            info(
                " " * 22
                + "- The destination patches branch, "
                + ansi("boldon")
                + dst_patches
                + ansi("reset")
                + ", does not exist; it will be created"
            )
        info(" " * 22 + "- The working branch will be set to " + ansi("boldon") + dst + ansi("reset"))
        if not maybe_continue():
            error("Answered no to continue, aborting.", exit=True)

    # Make changes to the layout
    current_branch = get_current_branch(directory)
    try:
        # Change to the src branch
        checkout(src, directory=directory)
        # Create the dst branch if needed
        if create_dst_branch:
            create_branch(dst, changeto=True, directory=directory)
        else:
            checkout(dst, directory=directory)
        # Create the dst patches branch if needed
        if create_dst_patches_branch:
            create_branch(dst_patches, orphaned=True, directory=directory)
        # Create the starting config data if it does not exist
        patches_ls = ls_tree(dst_patches, directory=directory)
        if "patches.conf" not in patches_ls:
            # Patches config not setup, set it up
            config = {
                "parent": src,
                "previous": "",
                "base": get_commit_hash(dst, directory=directory),
                "trim": "",
                "trimbase": "",
            }
            set_patch_config(dst_patches, config, directory=directory)
        else:
            config = get_patch_config(dst_patches, directory=directory)
            if config["parent"] != src:
                warning("Updated parent to '{0}' from '{1}'".format(src, config["parent"]))
                config["parent"] = src
                config["base"] = get_commit_hash(dst, directory=directory)
            set_patch_config(dst_patches, config, directory=directory)
        # Command successful, do not switch back to previous branch
        current_branch = None
    finally:
        if current_branch is not None:
            checkout(current_branch, directory=directory)
Exemple #18
0
def import_patches(directory=None):
    # Get current branch
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    # Construct the patches branch name
    patches_branch = 'patches/' + current_branch
    # Ensure the patches branch exists and is tracked
    if branch_exists(patches_branch, False, directory=directory):
        if not branch_exists(patches_branch, True, directory=directory):
            track_branches(patches_branch, directory)
    else:
        error("The patches branch ({0}) does not ".format(patches_branch) +
              "exist, did you use git-bloom-branch?", exit=True)
    # Create a swap space
    tmp_dir = tempfile.mkdtemp()
    try:
        # Get parent branch and base commit from patches branch
        config = get_patch_config(patches_branch, directory)
        parent_branch, commit = config['parent'], config['base']
        if commit != get_commit_hash(current_branch, directory):
            debug(
                "commit != get_commit_hash(current_branch, directory)"
            )
            debug(
                "{0} != get_commit_hash({1}, {2}) != {3}".format(
                    commit, current_branch, directory,
                    get_commit_hash(current_branch, directory)
                )
            )
            os.system('git log')
            warning(
                "The current commit is not the same as the most recent "
                "rebase commit."
            )
            warning(
                "This might mean that you have committed since the last "
                "time you did:"
            )
            warning(
                "    'git-bloom-patch rebase' or 'git-bloom-patch remove'"
            )
            warning(
                "Make sure you export any commits you want to save first:"
            )
            warning("    'git-bloom-patch export'")
            error("Patches not exported", exit=True)
        # Checkout to the patches branch
        checkout(patches_branch, directory=directory)
        # Copy the patches to a temp location
        patches = list_patches(directory)
        if len(patches) == 0:
            debug("No patches in the patches branch, nothing to do")
            return -1  # Indicates that nothing was done
        tmp_dir_patches = []
        for patch in patches:
            tmp_dir_patches.append(os.path.join(tmp_dir, patch))
            if directory is not None:
                patch = os.path.join(directory, patch)
            shutil.copy(patch, tmp_dir)
        # Now checkout back to the original branch and import them
        checkout(current_branch, directory=directory)
        try:
            cmd = 'git am {0}*.patch'.format(tmp_dir + os.sep)
            execute_command(cmd, cwd=directory)
        except subprocess.CalledProcessError as e:
            warning("Failed to apply one or more patches for the "
                    "'{0}' branch.".format(str(e)))
            info('', use_prefix=False)
            info('', use_prefix=False)
            info(">>> Resolve any conflicts and when you have resolved this "
                 "problem run 'git am --resolved' and then exit the "
                 "shell using 'exit 0'. <<<", use_prefix=False)
            info("    To abort use 'exit 1'", use_prefix=False)
            if 'bash' in os.environ['SHELL']:
                ret = subprocess.call([
                    "/bin/bash", "-l", "-c",
                    """\
/bin/bash --rcfile <(echo "if [ -f /etc/bashrc ]; then source /etc/bashrc; fi; \
if [ -f ~/.bashrc ]; then source ~/.bashrc; fi;PS1='(bloom)$PS1'") -i"""
                ])
            else:
                ret = subprocess.call("$SHELL", shell=True)
            if ret != 0:
                error("User failed to resolve patch conflicts, exiting.")
                sys.exit("'git-bloom-patch import' aborted.")
            info("User reports that conflicts have been resolved, continuing.")
        # Notify the user
        info("Applied {0} patches".format(len(patches)))
    finally:
        if current_branch:
            checkout(current_branch, directory=directory)
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)
Exemple #19
0
def _trim(config, force, directory):
    debug("_trim(" + str(config) + ", " + str(force) + ", " + \
          str(directory) + ")")
    if config['trimbase'] != '':
        warning("It looks like the trim operation has already been done, "
                "nested trimming is not supported.")
        if force:
            warning("Proceeding anyways because of '--force'")
        else:
            warning("If you would like to continue anyways use '--force'")
            return None
    config['trimbase'] = get_commit_hash(get_current_branch(directory))
    tmp_dir = tempfile.mkdtemp()
    try:
        # Buckup trim sub directory
        git_root = get_root()
        sub_dir = os.path.join(git_root, config['trim'])
        storage = os.path.join(tmp_dir, config['trim'])
        shutil.copytree(sub_dir, storage)
        # Clear out the git repo
        execute_command('git rm -rf ./*', cwd=directory)
        # Collect .* files (excluding .git)
        dot_items = []
        for item in os.listdir(git_root):
            if item in ['.git', '..', '.']:
                continue
            if item.startswith('.'):
                dot_items.append(item)
        # Remove and .* files missed by 'git rm -rf *'
        if len(dot_items) > 0:
            execute_command('git rm -rf ' + ' '.join(dot_items), cwd=directory)
        # Clear out any untracked files
        execute_command('git clean -fdx', cwd=directory)
        # Copy the sub directory back
        for item in os.listdir(storage):
            src = os.path.join(storage, item)
            dst = os.path.join(git_root, item)
            if os.path.isdir(src):
                shutil.copytree(src, dst)
            else:
                shutil.copy(src, dst)
        # Stage
        execute_command('git add ./*', cwd=directory)
        # Collect .* files
        dot_items = []
        for item in os.listdir(git_root):
            if item in ['.git', '..', '.']:
                continue
            if item.startswith('.'):
                dot_items.append(item)
        # Add any .* files missed by 'git add ./*'
        if len(dot_items) > 0:
            execute_command('git add ' + ' '.join(dot_items), cwd=directory)
        # Remove any straggling untracked files
        execute_command('git clean -dXf', cwd=directory)
        # Commit
        cmd = 'git commit -m "Trimmed the branch to only the ' + \
              config['trim'] + ' sub directory"'
        execute_command(cmd, cwd=directory)
        # Update the patch base to be this commit
        config['base'] = get_commit_hash(get_current_branch(directory))
    finally:
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)
    return config
Exemple #20
0
def _trim(config, force, directory):
    debug("_trim(" + str(config) + ", " + str(force) + ", " + str(directory) +
          ")")
    if config['trimbase'] != '':
        warning("It looks like the trim operation has already been done, "
                "nested trimming is not supported.")
        if force:
            warning("Proceeding anyways because of '--force'")
        else:
            warning("If you would like to continue anyways use '--force'")
            return None
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    config['trimbase'] = get_commit_hash(current_branch)
    tmp_dir = tempfile.mkdtemp()
    try:
        # Buckup trim sub directory
        git_root = get_root()
        sub_dir = os.path.join(git_root, config['trim'])
        storage = os.path.join(tmp_dir, config['trim'])
        shutil.copytree(sub_dir, storage)
        # Clear out any untracked files
        execute_command('git clean -fdx', cwd=directory)
        # Collect al files (excluding .git)
        items = []
        for item in os.listdir(git_root):
            if item in ['.git', '..', '.']:
                continue
            items.append(item)
        # Remove and .* files missed by 'git rm -rf *'
        if len(items) > 0:
            execute_command('git rm -rf ' + ' '.join(items), cwd=directory)
        # Copy the sub directory back
        for item in os.listdir(storage):
            src = os.path.join(storage, item)
            dst = os.path.join(git_root, item)
            if os.path.isdir(src):
                shutil.copytree(src, dst)
            else:
                shutil.copy(src, dst)
        # Stage
        execute_command('git add ./*', cwd=directory)
        # Collect .* files
        dot_items = []
        for item in os.listdir(git_root):
            if item in ['.git', '..', '.']:
                continue
            if item.startswith('.'):
                dot_items.append(item)
        # Add any .* files missed by 'git add ./*'
        if len(dot_items) > 0:
            execute_command('git add ' + ' '.join(dot_items), cwd=directory)
        # Remove any straggling untracked files
        execute_command('git clean -dXf', cwd=directory)
        # Commit
        cmd = 'git commit -m "Trimmed the branch to only the ' + \
              config['trim'] + ' sub directory"'
        execute_command(cmd, cwd=directory)
        # Update the patch base to be this commit
        current_branch = get_current_branch(directory)
        if current_branch is None:
            error("Could not determine current branch.", exit=True)
        config['base'] = get_commit_hash(current_branch)
    finally:
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)
    return config
Exemple #21
0
def _trim(config, force, directory):
    debug("_trim(" + str(config) + ", " + str(force) + ", " + str(directory) + ")")
    if config["trimbase"] != "":
        warning("It looks like the trim operation has already been done, " "nested trimming is not supported.")
        if force:
            warning("Proceeding anyways because of '--force'")
        else:
            warning("If you would like to continue anyways use '--force'")
            return None
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    config["trimbase"] = get_commit_hash(current_branch)
    tmp_dir = tempfile.mkdtemp()
    try:
        # Buckup trim sub directory
        git_root = get_root()
        sub_dir = os.path.join(git_root, config["trim"])
        storage = os.path.join(tmp_dir, config["trim"])
        shutil.copytree(sub_dir, storage)
        # Collect al files (excluding .git)
        items = []
        for item in os.listdir(git_root):
            if item in [".git", "..", "."]:
                continue
            items.append(item)
        # Remove and .* files missed by 'git rm -rf *'
        if len(items) > 0:
            execute_command("git rm -rf " + " ".join(items), cwd=directory)
        # Clear out any untracked files
        execute_command("git clean -fdx", cwd=directory)
        # Copy the sub directory back
        for item in os.listdir(storage):
            src = os.path.join(storage, item)
            dst = os.path.join(git_root, item)
            if os.path.isdir(src):
                shutil.copytree(src, dst)
            else:
                shutil.copy(src, dst)
        # Stage
        execute_command("git add ./*", cwd=directory)
        # Collect .* files
        dot_items = []
        for item in os.listdir(git_root):
            if item in [".git", "..", "."]:
                continue
            if item.startswith("."):
                dot_items.append(item)
        # Add any .* files missed by 'git add ./*'
        if len(dot_items) > 0:
            execute_command("git add " + " ".join(dot_items), cwd=directory)
        # Remove any straggling untracked files
        execute_command("git clean -dXf", cwd=directory)
        # Commit
        cmd = 'git commit -m "Trimmed the branch to only the ' + config["trim"] + ' sub directory"'
        execute_command(cmd, cwd=directory)
        # Update the patch base to be this commit
        current_branch = get_current_branch(directory)
        if current_branch is None:
            error("Could not determine current branch.", exit=True)
        config["base"] = get_commit_hash(current_branch)
    finally:
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)
    return config
Exemple #22
0
def import_upstream(cwd, tmp_dir, args):
    # Ensure the bloom and upstream branches are tracked locally
    track_branches(['bloom', 'upstream'])

    # Create a clone of the bloom_repo to help isolate the activity
    bloom_repo_clone_dir = os.path.join(tmp_dir, 'bloom_clone')
    os.makedirs(bloom_repo_clone_dir)
    os.chdir(bloom_repo_clone_dir)
    bloom_repo = VcsClient('git', bloom_repo_clone_dir)
    bloom_repo.checkout('file://{0}'.format(cwd))

    # Ensure the bloom and upstream branches are tracked from the original
    track_branches(['bloom', 'upstream'])

    ### Fetch the upstream tag
    upstream_repo = None
    upstream_repo_dir = os.path.join(tmp_dir, 'upstream_repo')
    # If explicit svn url just export and git-import-orig
    if args.explicit_svn_url is not None:
        if args.upstream_version is None:
            error("'--explicit-svn-version' must be specified with "
                  "'--explicit-svn-url'")
            return 1
        info("Checking out upstream at version " + ansi('boldon') + \
             str(args.upstream_version) + ansi('reset') + \
             " from repository at " + ansi('boldon') + \
             str(args.explicit_svn_url) + ansi('reset'))
        upstream_repo = VcsClient('svn', upstream_repo_dir)
        retcode = try_vcstools_checkout(upstream_repo, args.explicit_svn_url)
        if retcode != 0:
            return retcode
        meta = {
            'name': None,
            'version': args.upstream_version,
            'type': 'manual'
        }
    # Else fetching from bloom configs
    else:
        # Check for a bloom branch
        check_for_bloom()
        # Parse the bloom config file
        upstream_url, upstream_type, upstream_branch = parse_bloom_conf()
        # If the upstream_tag is specified, don't search just fetch
        upstream_repo = VcsClient(upstream_type, upstream_repo_dir)
        if args.upstream_tag is not None:
            warning("Using specified upstream tag '" + args.upstream_tag + "'")
            if upstream_type == 'svn':
                upstream_url += '/tags/' + args.upstream_tag
                upstream_tag = ''
            else:
                upstream_tag = args.upstream_tag
            retcode = try_vcstools_checkout(upstream_repo,
                                            upstream_url,
                                            upstream_tag)
            if retcode != 0:
                return retcode
            meta = {
                'name': None,
                'version': args.upstream_tag,
                'type': 'manual'
            }
        # We have to search for the upstream tag
        else:
            if args.upstream_devel is not None:
                warning("Overriding the bloom.conf upstream branch with " + \
                        args.upstream_devel)
                devel_branch = args.upstream_devel
            else:
                devel_branch = upstream_branch
            meta = auto_upstream_checkout(upstream_repo,
                                             upstream_url, devel_branch)
            if type(meta) not in [dict] and meta != 0:
                return meta

    ### Export the repository
    version = args.upstream_version if args.upstream_version is not None \
                                    else meta['version']

    # Export the repository to a tar ball
    tarball_prefix = 'upstream-' + str(version)
    info('Exporting version {0}'.format(version))
    tarball_path = os.path.join(tmp_dir, tarball_prefix)
    if upstream_repo.get_vcs_type_name() == 'svn':
        upstream_repo.export_repository('', tarball_path)
    else:
        if args.upstream_tag is not None:
            upstream_repo.export_repository(args.upstream_tag, tarball_path)
        else:
            upstream_repo.export_repository(version, tarball_path)

    # Get the gbp version elements from either the last tag or the default
    last_tag = get_last_tag_by_date()
    if last_tag == '':
        gbp_major, gbp_minor, gbp_patch = segment_version(version)
    else:
        gbp_major, gbp_minor, gbp_patch = \
            get_versions_from_upstream_tag(last_tag)
        info("The latest upstream tag in the release repository is "
              + ansi('boldon') + last_tag + ansi('reset'))
        # Ensure the new version is greater than the last tag
        last_tag_version = '.'.join([gbp_major, gbp_minor, gbp_patch])
        if parse_version(version) < parse_version(last_tag_version):
            warning("""\
Version discrepancy:
    The upstream version, {0}, is not newer than the previous \
release version, {1}.
""".format(version, last_tag_version))
        if parse_version(version) <= parse_version(last_tag_version):
            if args.replace:
                if not gbp.has_replace():
                    error("The '--replace' flag is not supported on this "
                          "version of git-buildpackage.")
                    return 1
                # Remove the conflicting tag first
                warning("""\
The upstream version, {0}, is equal to or less than a previous \
import version.
    Removing conflicting tag before continuing \
because the '--replace' options was specified.\
""".format(version))
                execute_command('git tag -d {0}'.format('upstream/' + version))
                execute_command('git push origin :refs/tags/'
                                '{0}'.format('upstream/' + version))
            else:
                warning("""\
The upstream version, {0}, is equal to a previous import version. \
git-buildpackage will fail, if you want to replace the existing \
upstream import use the '--replace' option.\
""".format(version))

    # Look for upstream branch
    if not branch_exists('upstream', local_only=True):
        create_branch('upstream', orphaned=True, changeto=True)

    # Go to the master branch
    bloom_repo.update(get_commit_hash('upstream'))

    # Detect if git-import-orig is installed
    tarball_path += '.tar.gz'
    if gbp.import_orig(tarball_path, args.interactive) != 0:
        return 1

    # Push changes back to the original bloom repo
    execute_command('git push --all -f')
    execute_command('git push --tags')
Exemple #23
0
def execute_branch(src, dst, interactive, directory=None):
    """
    Changes to the destination branch, creates branch and patches/branch
    if they do not exist.

    If the dst branch does not exist yet, then it is created by branching the
    current working branch or the specified SRC_BRANCH.

    If the patches/dst branch branch does not exist yet then it is created.

    If the branches are created successful, then the working branch will be
    set to the dst branch, otherwise the working branch will remain unchanged.

    :param src: source branch from which to copy
    :param dst: destination branch
    :param interactive: if True actions are summarized before committing
    :param directory: directory in which to preform this action

    :raises: subprocess.CalledProcessError if any git calls fail
    """
    # Determine if the srouce branch exists
    if src is None:
        error("No source specified and/or not a branch currently", exit=True)
    if branch_exists(src, local_only=False, directory=directory):
        if not branch_exists(src, local_only=True, directory=directory):
            debug("Tracking source branch: {0}".format(src))
            track_branches(src, directory)
    elif tag_exists(src):
        pass
    else:
        error("Specified source branch does not exist: {0}".format(src),
              exit=True)

    # Determine if the destination branch needs to be created
    create_dst_branch = False
    if branch_exists(dst, local_only=False, directory=directory):
        if not branch_exists(dst, local_only=True, directory=directory):
            debug("Tracking destination branch: {0}".format(dst))
            track_branches(dst, directory)
    else:
        create_dst_branch = True

    # Determine if the destination patches branch needs to be created
    create_dst_patches_branch = False
    dst_patches = 'patches/' + dst
    if branch_exists(dst_patches, False, directory=directory):
        if not branch_exists(dst_patches, True, directory=directory):
            track_branches(dst_patches, directory)
    else:
        create_dst_patches_branch = True

    # Summarize
    if interactive:
        info("Summary of changes:")
        if create_dst_branch:
            info(" " * 22 + "- The specified destination branch, " +
                 ansi('boldon') + dst + ansi('reset') +
                 ", does not exist; it will be created from the source "
                 "branch " + ansi('boldon') + src + ansi('reset'))
        if create_dst_patches_branch:
            info(" " * 22 + "- The destination patches branch, " +
                 ansi('boldon') + dst_patches + ansi('reset') +
                 ", does not exist; it will be created")
        info(" " * 22 + "- The working branch will be set to " +
             ansi('boldon') + dst + ansi('reset'))
        if not maybe_continue():
            error("Answered no to continue, aborting.", exit=True)

    # Make changes to the layout
    current_branch = get_current_branch(directory)
    try:
        # Change to the src branch
        checkout(src, directory=directory)
        # Create the dst branch if needed
        if create_dst_branch:
            create_branch(dst, changeto=True, directory=directory)
        else:
            checkout(dst, directory=directory)
        # Create the dst patches branch if needed
        if create_dst_patches_branch:
            create_branch(dst_patches, orphaned=True, directory=directory)
        # Create the starting config data if it does not exist
        patches_ls = ls_tree(dst_patches, directory=directory)
        if 'patches.conf' not in patches_ls:
            # Patches config not setup, set it up
            config = {
                'parent': src,
                'previous': '',
                'base': get_commit_hash(dst, directory=directory),
                'trim': '',
                'trimbase': ''
            }
            set_patch_config(dst_patches, config, directory=directory)
        else:
            config = get_patch_config(dst_patches, directory=directory)
            if config['parent'] != src:
                warning("Updated parent to '{0}' from '{1}'".format(
                    src, config['parent']))
                config['parent'] = src
                config['base'] = get_commit_hash(dst, directory=directory)
            set_patch_config(dst_patches, config, directory=directory)
        # Command successful, do not switch back to previous branch
        current_branch = None
    finally:
        if current_branch is not None:
            checkout(current_branch, directory=directory)
Exemple #24
0
def import_patches(directory=None):
    # Get current branch
    current_branch = get_current_branch(directory)
    if current_branch is None:
        error("Could not determine current branch.", exit=True)
    # Construct the patches branch name
    patches_branch = 'patches/' + current_branch
    # Ensure the patches branch exists and is tracked
    if branch_exists(patches_branch, False, directory=directory):
        if not branch_exists(patches_branch, True, directory=directory):
            track_branches(patches_branch, directory)
    else:
        error("The patches branch ({0}) does not ".format(patches_branch) +
              "exist, did you use git-bloom-branch?", exit=True)
    # Create a swap space
    tmp_dir = tempfile.mkdtemp()
    try:
        # Get parent branch and base commit from patches branch
        config = get_patch_config(patches_branch, directory)
        parent_branch, commit = config['parent'], config['base']
        if commit != get_commit_hash(current_branch, directory):
            debug(
                "commit != get_commit_hash(current_branch, directory)"
            )
            debug(
                "{0} != get_commit_hash({1}, {2}) != {3}".format(
                    commit, current_branch, directory,
                    get_commit_hash(current_branch, directory)
                )
            )
            os.system('git log')
            warning(
                "The current commit is not the same as the most recent "
                "rebase commit."
            )
            warning(
                "This might mean that you have committed since the last "
                "time you did:"
            )
            warning(
                "    'git-bloom-patch rebase' or 'git-bloom-patch remove'"
            )
            warning(
                "Make sure you export any commits you want to save first:"
            )
            warning("    'git-bloom-patch export'")
            error("Patches not exported", exit=True)
        # Checkout to the patches branch
        checkout(patches_branch, directory=directory)
        # Copy the patches to a temp location
        patches = list_patches(directory)
        if len(patches) == 0:
            debug("No patches in the patches branch, nothing to do")
            return -1  # Indicates that nothing was done
        tmp_dir_patches = []
        for patch in patches:
            tmp_dir_patches.append(os.path.join(tmp_dir, patch))
            if directory is not None:
                patch = os.path.join(directory, patch)
            shutil.copy(patch, tmp_dir)
        # Now checkout back to the original branch and import them
        checkout(current_branch, directory=directory)
        try:
            cmd = 'git am {0}*.patch'.format(tmp_dir + os.sep)
            execute_command(cmd, cwd=directory)
        except subprocess.CalledProcessError as e:
            warning("Failed to apply one or more patches for the "
                    "'{0}' branch.".format(str(e)))
            print()
            print()
            print(">>> Resolve any conflicts and when you have resolved this "
                  "problem run 'git am --resolved' and then exit the "
                  "shell using 'exit 0'. <<<")
            print("    To abort use 'exit 1'")
            if 'bash' in os.environ['SHELL']:
                ret = subprocess.call([
                    "/bin/bash", "-l", "-c",
                    """\
/bin/bash --rcfile <(echo "if [ -f /etc/bashrc ]; then source /etc/bashrc; fi; \
if [ -f ~/.bashrc ]; then source ~/.bashrc; fi;PS1='(bloom)$PS1'") -i"""
                ])
            else:
                ret = subprocess.call("$SHELL", shell=True)
            if ret != 0:
                error("User failed to resolve patch conflicts, exiting.")
                sys.exit("'git-bloom-patch import' aborted.")
            info("User reports that conflicts have been resolved, continuing.")
        # Notify the user
        info("Applied {0} patches".format(len(patches)))
    finally:
        if current_branch:
            checkout(current_branch, directory=directory)
        if os.path.exists(tmp_dir):
            shutil.rmtree(tmp_dir)