Ejemplo n.º 1
0
def main():
    from devflow.version import __version__  # pylint: disable=E0611,F0401
    parser = OptionParser(usage="usage: %prog [options] mode",
                          version="devflow %s" % __version__,
                          add_help_option=False)
    parser.add_option("-h", "--help",
                      action="store_true",
                      default=False,
                      help="show this help message")
    parser.add_option("-k", "--keep-repo",
                      action="store_true",
                      dest="keep_repo",
                      default=False,
                      help="Do not delete the cloned repository")
    parser.add_option("-b", "--build-dir",
                      dest="build_dir",
                      default=None,
                      help="Directory to store created pacakges")
    parser.add_option("-r", "--repo-dir",
                      dest="repo_dir",
                      default=None,
                      help="Directory to clone repository")
    parser.add_option("-d", "--dirty",
                      dest="force_dirty",
                      default=False,
                      action="store_true",
                      help="Do not check if working directory is dirty")
    parser.add_option("-c", "--config-file",
                      dest="config_file",
                      help="Override default configuration file")
    parser.add_option("--no-sign",
                      dest="sign",
                      action="store_false",
                      default=True,
                      help="Do not sign the packages")
    parser.add_option("--key-id",
                      dest="keyid",
                      help="Use this keyid for gpg signing")
    parser.add_option("--dist",
                      dest="dist",
                      default=None,
                      help="Force distribution in Debian changelog")
    parser.add_option("-S", "--source-only",
                      dest="source_only",
                      default=False,
                      action="store_true",
                      help="Specifies a source-only build, no binary packages"
                           " need to be made.")
    parser.add_option("--debian-branch",
                      dest="debian_branch",
                      default=None,
                      help="Use this debian branch, instead of"
                           "auto-discovering the debian branch to use")
    parser.add_option("--push-back",
                      dest="push_back",
                      default=False,
                      action="store_true",
                      help="Automatically push branches and tags to repo.")
    parser.add_option("--color",
                      dest="color_output",
                      default="auto",
                      help="Enable/disable colored output. Default mode is" +
                           " auto, available options are yes/no")

    (options, args) = parser.parse_args()

    if options.color_output == "yes":
        use_colors = True
    elif options.color_output == "no":
        use_colors = False
    else:
        if sys.stdout.isatty():
            use_colors = True
        else:
            use_colors = False

    red = lambda x: x
    green = lambda x: x

    if use_colors:
        try:
            import colors
            red = colors.red
            green = colors.green
        except AttributeError:
            pass

    print_red = lambda x: sys.stdout.write(red(x) + "\n")
    print_green = lambda x: sys.stdout.write(green(x) + "\n")

    if options.help:
        print_help(parser.get_prog_name())
        parser.print_help()
        return

    # Get build mode
    try:
        mode = args[0]
    except IndexError:
        mode = utils.get_build_mode()
    if mode not in AVAILABLE_MODES:
        raise ValueError(red("Invalid argument! Mode must be one: %s"
                         % ", ".join(AVAILABLE_MODES)))

    # Load the repository
    original_repo = utils.get_repository()

    # Check that repository is clean
    toplevel = original_repo.working_dir
    if original_repo.is_dirty() and not options.force_dirty:
        raise RuntimeError(red("Repository %s is dirty." % toplevel))

    # Get packages from configuration file
    config = utils.get_config(options.config_file)
    packages = config['packages'].keys()
    print_green("Will build the following packages:\n" + "\n".join(packages))

    # Get current branch name and type and check if it is a valid one
    branch = original_repo.head.reference.name
    branch = utils.undebianize(branch)
    branch_type_str = utils.get_branch_type(branch)

    if branch_type_str not in BRANCH_TYPES.keys():
        allowed_branches = ", ".join(BRANCH_TYPES.keys())
        raise ValueError("Malformed branch name '%s', cannot classify as"
                         " one of %s" % (branch, allowed_branches))

    # Fix needed environment variables
    v = utils.get_vcs_info()
    os.environ["DEVFLOW_BUILD_MODE"] = mode
    os.environ["DEBFULLNAME"] = v.name
    os.environ["DEBEMAIL"] = v.email

    # Check that base version file and branch are correct
    versioning.get_python_version()

    # Get the debian branch
    if options.debian_branch:
        debian_branch = options.debian_branch
    else:
        debian_branch = utils.get_debian_branch(branch)
    origin_debian = "origin/" + debian_branch

    # Clone the repo
    repo_dir = options.repo_dir or create_temp_directory("df-repo")
    repo_dir = os.path.abspath(repo_dir)
    repo = original_repo.clone(repo_dir, branch=branch)
    print_green("Cloned repository to '%s'." % repo_dir)

    build_dir = options.build_dir or create_temp_directory("df-build")
    build_dir = os.path.abspath(build_dir)
    print_green("Build directory: '%s'" % build_dir)

    # Create the debian branch
    repo.git.branch(debian_branch, origin_debian)
    print_green("Created branch '%s' to track '%s'" % (debian_branch,
                origin_debian))

    # Go to debian branch
    repo.git.checkout(debian_branch)
    print_green("Changed to branch '%s'" % debian_branch)

    # Merge with starting branch
    repo.git.merge(branch)
    print_green("Merged branch '%s' into '%s'" % (branch, debian_branch))

    # Compute python and debian version
    cd(repo_dir)
    python_version = versioning.get_python_version()
    debian_version = versioning.\
        debian_version_from_python_version(python_version)
    print_green("The new debian version will be: '%s'" % debian_version)

    # Update the version files
    versioning.update_version()

    if not options.sign:
        sign_tag_opt = None
    elif options.keyid:
        sign_tag_opt = "-u=%s" % options.keyid
    elif mode == "release":
        sign_tag_opt = "-s"
    else:
        sign_tag_opt = None

    # Tag branch with python version
    branch_tag = python_version
    tag_message = "%s version %s" % (mode.capitalize(), python_version)
    try:
        repo.git.tag(branch_tag, branch, sign_tag_opt, "-m %s" % tag_message)
    except GitCommandError:
        # Tag may already exist, if only the debian branch has changed
        pass
    upstream_tag = "upstream/" + branch_tag
    repo.git.tag(upstream_tag, branch)

    # Update changelog
    dch = git_dch("--debian-branch=%s" % debian_branch,
                  "--git-author",
                  "--ignore-regex=\".*\"",
                  "--multimaint-merge",
                  "--since=HEAD",
                  "--new-version=%s" % debian_version)
    print_green("Successfully ran '%s'" % " ".join(dch.cmd))

    if options.dist is not None:
        distribution = options.dist
    elif mode == "release":
        distribution = utils.get_distribution_codename()
    else:
        distribution = "unstable"

    f = open("debian/changelog", 'r+')
    lines = f.readlines()
    lines[0] = lines[0].replace("UNRELEASED", distribution)
    lines[2] = lines[2].replace("UNRELEASED", "%s build" % mode)
    f.seek(0)
    f.writelines(lines)
    f.close()

    if mode == "release":
        call("vim debian/changelog")

    # Add changelog to INDEX
    repo.git.add("debian/changelog")
    # Commit Changes
    repo.git.commit("-s", "debian/changelog",
                    m="Bump version to %s" % debian_version)
    # Tag debian branch
    debian_branch_tag = "debian/" + utils.version_to_tag(debian_version)
    tag_message = "%s version %s" % (mode.capitalize(), debian_version)
    if mode == "release":
        repo.git.tag(debian_branch_tag, sign_tag_opt, "-m %s" % tag_message)

    # Create debian packages
    cd(repo_dir)
    version_files = []
    for _, pkg_info in config['packages'].items():
        if pkg_info.get("version_file"):
            version_files.extend(pkg_info.as_list('version_file'))

    # Add version.py files to repo
    repo.git.add("-f", *version_files)

    # Export version info to debuilg environment
    os.environ["DEB_DEVFLOW_DEBIAN_VERSION"] = debian_version
    os.environ["DEB_DEVFLOW_VERSION"] = python_version
    build_cmd = "git-buildpackage --git-export-dir=%s"\
                " --git-upstream-branch=%s --git-debian-branch=%s"\
                " --git-export=INDEX --git-ignore-new -sa"\
                " --source-option=--auto-commit"\
                " --git-upstream-tag=%s"\
                % (build_dir, branch, debian_branch, upstream_tag)
    if options.source_only:
        build_cmd += " -S"
    if not options.sign:
        build_cmd += " -uc -us"
    elif options.keyid:
        build_cmd += " -k\"'%s'\"" % options.keyid
    call(build_cmd)

    # Remove cloned repo
    if mode != 'release' and not options.keep_repo:
        print_green("Removing cloned repo '%s'." % repo_dir)
        rm("-r", repo_dir)

    # Print final info
    info = (("Version", debian_version),
            ("Upstream branch", branch),
            ("Upstream tag", branch_tag),
            ("Debian branch", debian_branch),
            ("Debian tag", debian_branch_tag),
            ("Repository directory", repo_dir),
            ("Packages directory", build_dir))
    print_green("\n".join(["%s: %s" % (name, val) for name, val in info]))

    # Print help message
    if mode == "release":
        origin = original_repo.remote().url
        repo.create_remote("original_origin", origin)
        print_green("Created remote 'original_origin' for the repository '%s'"
                    % origin)

        print_green("To update repositories '%s' and '%s' go to '%s' and run:"
                    % (toplevel, origin, repo_dir))
        for remote in ['origin', 'original_origin']:
            objects = [debian_branch, branch_tag, debian_branch_tag]
            print_green("git push %s %s" % (remote, " ".join(objects)))
        if options.push_back:
            objects = [debian_branch, branch_tag, debian_branch_tag]
            repo.git.push("origin", *objects)
            print_green("Automatically updated origin repo.")
Ejemplo n.º 2
0
def debian_version_from_python_version(pyver):
    """Generate a debian package version from a Python version.

    This helper generates a Debian package version from a Python version,
    following devtools conventions.

    Debian sorts version strings differently compared to setuptools:
    http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version

    Initial tests:

    >>> debian_version("3") < debian_version("6")
    True
    >>> debian_version("3") < debian_version("2")
    False
    >>> debian_version("1") == debian_version("1")
    True
    >>> debian_version("1") != debian_version("1")
    False
    >>> debian_version("1") >= debian_version("1")
    True
    >>> debian_version("1") <= debian_version("1")
    True

    This helper defines a 1-1 mapping between Python and Debian versions,
    with the same ordering.

    Debian versions are ordered in the same way as Python versions:

    >>> D("0.14next") > D("0.14")
    True
    >>> D("0.14next") > D("0.14rc7")
    True
    >>> D("0.14next") > D("0.14.1")
    False
    >>> D("0.14rc6") > D("0.14")
    False
    >>> D("0.14.2rc6") > D("0.14.1")
    True

    and

    >>> D("0.14next_150") < D("0.14next")
    True
    >>> D("0.14.1next_150") < D("0.14.1next")
    True
    >>> D("0.14.1_149") < D("0.14.1")
    True
    >>> D("0.14.1_149") < D("0.14.1_150")
    True

    and

    >>> D("0.13next_102") < D("0.13next")
    True
    >>> D("0.13next") < D("0.14rc5_120")
    True
    >>> D("0.14rc3_120") < D("0.14rc3")
    True
    >>> D("0.14rc3") < D("0.14_1")
    True
    >>> D("0.14_120") < D("0.14")
    True
    >>> D("0.14") < D("0.14next_20")
    True
    >>> D("0.14next_20") < D("0.14next")
    True

    """

    if "_" in pyver:
        # This is the old format
        version = pyver.replace("_", "~").replace("rc", "~rc")
    else:
        # Create a random string that will help as during replacing
        rand = ''.join(
            random.choice(string.ascii_uppercase) for _ in range(16))
        # Replace '.dev' or 'dev' with ~dev. This is needed to make the Debian
        # develop version less than the non-develop one. Same thing for the rc
        # one.
        version = pyver.replace(
            ".dev", rand).replace("dev", "~dev").replace(rand, '~dev').replace(
            "rc", "~rc")
    codename = utils.get_distribution_codename()
    minor = str(get_revision(version, codename))
    return version + "-" + minor + "~" + codename
Ejemplo n.º 3
0
def debian_version_from_python_version(pyver):
    """Generate a debian package version from a Python version.

    This helper generates a Debian package version from a Python version,
    following devtools conventions.

    Debian sorts version strings differently compared to setuptools:
    http://www.debian.org/doc/debian-policy/ch-controlfields.html#s-f-Version

    Initial tests:

    >>> debian_version("3") < debian_version("6")
    True
    >>> debian_version("3") < debian_version("2")
    False
    >>> debian_version("1") == debian_version("1")
    True
    >>> debian_version("1") != debian_version("1")
    False
    >>> debian_version("1") >= debian_version("1")
    True
    >>> debian_version("1") <= debian_version("1")
    True

    This helper defines a 1-1 mapping between Python and Debian versions,
    with the same ordering.

    Debian versions are ordered in the same way as Python versions:

    >>> D("0.14next") > D("0.14")
    True
    >>> D("0.14next") > D("0.14rc7")
    True
    >>> D("0.14next") > D("0.14.1")
    False
    >>> D("0.14rc6") > D("0.14")
    False
    >>> D("0.14.2rc6") > D("0.14.1")
    True

    and

    >>> D("0.14next_150") < D("0.14next")
    True
    >>> D("0.14.1next_150") < D("0.14.1next")
    True
    >>> D("0.14.1_149") < D("0.14.1")
    True
    >>> D("0.14.1_149") < D("0.14.1_150")
    True

    and

    >>> D("0.13next_102") < D("0.13next")
    True
    >>> D("0.13next") < D("0.14rc5_120")
    True
    >>> D("0.14rc3_120") < D("0.14rc3")
    True
    >>> D("0.14rc3") < D("0.14_1")
    True
    >>> D("0.14_120") < D("0.14")
    True
    >>> D("0.14") < D("0.14next_20")
    True
    >>> D("0.14next_20") < D("0.14next")
    True

    """
    version = pyver.replace("_", "~").replace("rc", "~rc")
    codename = utils.get_distribution_codename()
    minor = str(get_revision(version, codename))
    return version + "-" + minor + "~" + codename