#!/cygdrive/C/Python25/python
"""A script to help automate the build process."""

# When preparing a new release, make sure to set all of these to the latest
# values.
VERSIONS = {
    "brz": "1.17",
    "qbzr": "0.12",
    "bzrtools": "1.17.0",
    "bzr-svn": "0.6.3",
    "bzr-rewrite": "0.5.2",
    "subvertpy": "0.6.8",
}

# This will be passed to 'make' to ensure we build with the right python
PYTHON = "/cygdrive/c/Python25/python"

# Create the final build in this directory
TARGET_ROOT = "release"

DEBUG_SUBPROCESS = True


import os
import shutil
import subprocess
import sys

BRZ_EXE = None


def brz():
    global BRZ_EXE
    if BRZ_EXE is not None:
        return BRZ_EXE
    try:
        subprocess.call(
            ["brz", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
        )
        BRZ_EXE = "brz"
    except OSError:
        try:
            subprocess.call(
                ["brz.bat", "--version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE
            )
            BRZ_EXE = "brz.bat"
        except OSError:
            raise RuntimeError("Could not find brz or brz.bat on your path.")
    return BRZ_EXE


def call_or_fail(*args, **kwargs):
    """Call a subprocess, and fail if the return code is not 0."""
    if DEBUG_SUBPROCESS:
        print('  calling: "{}"'.format(" ".join(args[0])))
    p = subprocess.Popen(*args, **kwargs)
    (out, err) = p.communicate()
    if p.returncode != 0:
        raise RuntimeError("Failed to run: {}, {}".format(args, kwargs))
    return out


TARGET = None


def get_target():
    global TARGET
    if TARGET is not None:
        return TARGET
    out = call_or_fail(
        [get_brz_dir() + "/brz", "version", "--short"], stdout=subprocess.PIPE
    )
    version = out.strip()
    TARGET = os.path.abspath(TARGET_ROOT + "-" + version)
    return TARGET


def clean_target():
    """Nuke the target directory so we know we are starting from scratch."""
    target = get_target()
    if os.path.isdir(target):
        print("Deleting: {}".format(target))
        shutil.rmtree(target)


def get_brz_dir():
    return "brz." + VERSIONS["brz"]


def update_brz():
    """Make sure we have the latest brz in play."""
    brz_dir = get_brz_dir()
    if not os.path.isdir(brz_dir):
        brz_version = VERSIONS["brz"]
        brz_url = "lp:brz/" + brz_version
        print("Getting brz release {} from {}".format(brz_version, brz_url))
        call_or_fail([brz(), "co", brz_url, brz_dir])
    else:
        print("Ensuring {} is up-to-date".format(brz_dir))
        call_or_fail([brz(), "update", brz_dir])


def create_target():
    target = get_target()
    print("Creating target dir: {}".format(target))
    call_or_fail([brz(), "co", get_brz_dir(), target])


def get_plugin_trunk_dir(plugin_name):
    return "{}/trunk".format(plugin_name)


def get_plugin_release_dir(plugin_name):
    return "{}/{}".format(plugin_name, VERSIONS[plugin_name])


def get_plugin_trunk_branch(plugin_name):
    return "lp:{}".format(plugin_name)


def update_plugin_trunk(plugin_name):
    trunk_dir = get_plugin_trunk_dir(plugin_name)
    if not os.path.isdir(trunk_dir):
        plugin_trunk = get_plugin_trunk_branch(plugin_name)
        print("Getting latest {} trunk".format(plugin_name))
        call_or_fail([brz(), "co", plugin_trunk, trunk_dir])
    else:
        print("Ensuring {} is up-to-date".format(trunk_dir))
        call_or_fail([brz(), "update", trunk_dir])
    return trunk_dir


def _plugin_tag_name(plugin_name):
    if plugin_name in ("bzr-svn", "bzr-rewrite", "subvertpy"):
        return "{}-{}".format(plugin_name, VERSIONS[plugin_name])
    # bzrtools and qbzr use 'release-X.Y.Z'
    return "release-" + VERSIONS[plugin_name]


def update_plugin(plugin_name):
    release_dir = get_plugin_release_dir(plugin_name)
    if not os.path.isdir(plugin_name):
        if plugin_name in ("bzr-svn", "bzr-rewrite"):
            # bzr-svn uses a different repo format
            call_or_fail([brz(), "init-shared-repo", "--rich-root-pack", plugin_name])
        else:
            os.mkdir(plugin_name)
    if os.path.isdir(release_dir):
        print("Removing existing dir: {}".format(release_dir))
        shutil.rmtree(release_dir)
    # First update trunk
    trunk_dir = update_plugin_trunk(plugin_name)
    # Now create the tagged directory
    tag_name = _plugin_tag_name(plugin_name)
    print("Creating the branch {}".format(release_dir))
    call_or_fail([brz(), "co", "-rtag:{}".format(tag_name), trunk_dir, release_dir])
    return release_dir


def install_plugin(plugin_name):
    release_dir = update_plugin(plugin_name)
    # at least bzrtools doesn't like you to call 'setup.py' unless you are in
    # that directory specifically, so we cd, rather than calling it from
    # outside
    print("Installing {}".format(release_dir))
    call_or_fail(
        [
            sys.executable,
            "setup.py",
            "install",
            "-O1",
            "--install-lib={}".format(get_target()),
        ],
        cwd=release_dir,
    )


def update_tbzr():
    tbzr_loc = os.environ.get("TBZR", None)
    if tbzr_loc is None:
        raise ValueError("You must set TBZR to the location of tortoisebzr.")
    print("Updating {}".format(tbzr_loc))
    call_or_fail([brz(), "update", tbzr_loc])


def build_installer():
    target = get_target()
    print()
    print()
    print("*" * 60)
    print("Building standalone installer")
    call_or_fail(["make", "PYTHON={}".format(PYTHON), "installer"], cwd=target)


def main(args):
    import optparse

    p = optparse.OptionParser(usage="%prog [OPTIONS]")
    opts, args = p.parse_args(args)

    update_brz()
    update_tbzr()
    clean_target()
    create_target()
    install_plugin("subvertpy")
    install_plugin("bzrtools")
    install_plugin("qbzr")
    install_plugin("bzr-svn")
    install_plugin("bzr-rewrite")

    build_installer()


if __name__ == "__main__":
    main(sys.argv[1:])

# vim: ts=4 sw=4 sts=4 et ai
