#!/usr/bin/python


import os
import sys
import time

if not os.environ.get("PYXIE_DEV","dev")=="global": #"unless"
    sys.path[:0] = ["."]

import pyxie

verbose = False
dryrun = False
ver_updating = None


changelog_entry_tmpl = """\
## [%s] - UNRELEASED

### New

*

### Other

*
"""

def vPrint(*args):
    if verbose:
        print " ".join([str(x) for x in args])

def get_shortlog_version():
    global ver_updating
    
    f = open("site/src/panels/shortlog.md")
    shortlog = [x.strip() for x in f.readlines()]
    f.close()
    if shortlog[0] != "---":
        print "CANNOT GET VERSION"
        print "\n".join(shortlog)
        return "-1", "UNRELEASED"
    log = shortlog[1:]
    while log[0] != "---":
        log = log[1:]

    current_version_info = log[1].split()

    ver, release_date = current_version_info[1], current_version_info[3]

    if ver_updating is None:
        ver_updating = ver

    return ver, release_date

def unreleased(release):
    return release == "UNRELEASED"

def get_next_version(ver_type):
    vPrint("get_next_version", ver_type)
    ver, release = get_shortlog_version()
    if unreleased(release):
        vPrint("WARNING: Current version is not yet released")
        return ver, release

    major,minor,patch = [ int(x) for x in ver.split(".") ]
    if ver_type == "major":
        major = major + 1
    elif ver_type == "minor":
        minor = minor + 1
    else:
        patch = patch +1

    new_version = "%d.%d.%d" % (major, minor, patch)
    return new_version, release

help_text = """
pyxie-dev [toggles] [options]

toggles:
    -v        verbose mode
    -d        dryrun - don't change files

options:
    get       get current version, and if verbose other information
    propose   get proposed version
    released  get status of released, Returns 0 if released, 1 if not. If verbose outputs state as well
    bump      bump version

    rebase-release Rebase the current code, ready for release
    make-release   Make the release based on current code
    do-upload      upload to launchpad and pypi

pyxie-dev is intended to be run relative to a development checkout
If this is not what you want, set PYXIE_DEV=global prior to running pyxie-dev

eg:
    PYXIE_DEV=global pyxie-dev options"

Expected usage:

Before a release:

    - Create a branch containing the history. (eg git checkout -b pre_v0.0.19)
    - Checkout WIP again
    - Then: ./bin/pyxie-dev rebase-release
       - Clean up your history as you see fit
    - Then: ./bin/pyxie-dev make-release
    - Assuming that went fine, add/commit all the changes made for the release to git
    - Then: ./bin/pyxie-dev do-upload
    - Then double check everything related to that release is committed and push.

    - NOTE: When pushing, remember to push the tags - git push --follow-tags so that
      the release shows up on github.

You may need to do a stash/fetch/rebase/stash pop/build_site.py on the webserver

After a release:

    - Update latest release info in site/src/index.md (this will get rolled in make-release)
    - You may need to do a stash/fetch/rebase/stash pop/build_site.py on the webserver
    - Check the version you've just released has been released:
      - ./bin/pyxie-dev get
      - ./bin/pyxie-dev released
    - Check the next version looks sane:
      - ./bin/pyxie-dev propose
    - If it does, bump versions:
      - ./bin/pyxie-dev bump

"""

def do_usage():
    current_version = get_shortlog_version()

    print help_text
    print "CURRENT VERSION:", current_version



def do_get():
    ver, release = get_shortlog_version()
    if verbose:
        print "Dryrun: ", dryrun
        print "Release date:", release
        print "Version:",
    print ver
    return 0

def do_released():
    vPrint("do_released")
    ver, release = get_shortlog_version()
    if unreleased(release):
        vPrint("Unreleased")
        return 1
    vPrint("Released:", release)
    vPrint("Version:", ver)
    
    return 0

def do_propose(ver_type):
    vPrint("propose", ver_type)
    ver, release = get_next_version(ver_type)
    if unreleased(release):
        print "Releasing current version -", ver, "- before bumping to next release"
        return 1

    print "PROPOSED NEW VERSION:", ver
    return 0

def bump_shortlog(new_ver):
    f = open("site/src/panels/shortlog.md")
    shortlog =  f.readlines()
    f.close()
    if dryrun:
        vPrint("Writing to stdout")
        print "----SHORTLOG START"
        outfile = sys.stdout
    else:
	outfile = open("site/src/panels/shortlog.md","w")

    newline = "* %s - UNRELEASED - TBD\n" % (new_ver,)
    shortlog.insert(7, newline)
    
    for line in shortlog:
        outfile.write(line)
    
    outfile.flush()
    if not dryrun:
        outfile.close()
    else:
        print "------ END SHORTLOG"

def update_current_shortlog(shortlog_entry):

    ver, release = get_shortlog_version()
    if not unreleased(release):
        print "We appear to already have released this release."
        print "release date:", release

    release_date = time.strftime("%Y-%m-%d")
    new_log_line = "* %s - %s - %s\n" % (ver, release_date, shortlog_entry)

    f = open("site/src/panels/shortlog.md")
    shortlog =  f.readlines()
    f.close()
    if dryrun:
        vPrint("Writing to stdout")
        print "----SHORTLOG START"
        outfile = sys.stdout
    else:
	outfile = open("site/src/panels/shortlog.md","w")

    for line in shortlog:
        if (ver in line) and ("UNRELEASED") in line:
            outfile.write(new_log_line)
        else:
            outfile.write(line)

    outfile.flush()
    if not dryrun:
        outfile.close()
    else:
        print "------ END SHORTLOG"

def bump_CHANGELOG(new_ver):
    vPrint("TBD -- bump_CHANGELOG")
    f = open("CHANGELOG")
    lines = f.readlines()
    f.close()

    old_ver = ver_updating

    for line in range(len(lines)):
        if old_ver in lines[line]:
            # print "FOUND START OF LAST VERSION"
            break

    new_changelog = changelog_entry_tmpl % new_ver
    lines[line:line] = [x+"\n" for x in new_changelog.split("\n") ]

    if dryrun:
        vPrint("Writing to stdout")
        print "----CHANGELOG START"                 
        outfile = sys.stdout
    else:
	outfile = open("CHANGELOG","w")

    for line in lines:
        outfile.write(line)

    if not dryrun:
        outfile.close()
    else:
        print "------ END CHANGE"


def bump_Makefile(ver):
    vPrint("TBD -- bump_Makefile") 
    f = open("Makefile")
    lines = f.readlines()
    f.close()

    if dryrun:
        vPrint("Writing to stdout")
        print "----Makefile START"
        outfile = sys.stdout
    else:
	outfile = open("Makefile","w")


    for line in lines:
        if line.startswith("VERSION="):
            outfile.write("VERSION=%s\n" % (ver,)  )
        else:
            outfile.write(line)

    if not dryrun:
        outfile.close()
    else:
        print "------ END Makefile"

def bump_rebuildDocs():
    vPrint("TBD -- bump_rebuildDocs")
    if dryrun:
        print "Would rebuild docs now. (dryrun - means don't)"
	return

    here = os.getcwd()
    os.chdir("site")
    os.system("./build_site.py")
    os.chdir(here)


def do_bump(ver_type):
    global dryrun
    global verbose

    vPrint("bump", ver_type)
    ver, release = get_next_version(ver_type)
    if unreleased(release):
        print "Refusing to bump release version until this version is released"
        print "You can still do this manually, if you must"
        print
        print "So that you can see what would be updated though, switching dryrun to True, and verbose to True"
        dryrun = True
        verbose = True

    bump_shortlog(ver)
    bump_CHANGELOG(ver)
    bump_Makefile(ver)
    bump_rebuildDocs()

    if dryrun:
        vPrint("Dryrun")
        return 1


def update_changelog_release_date():

    release_date = time.strftime("%Y-%m-%d")

    f = open("CHANGELOG")
    lines = f.readlines()
    f.close()

    if dryrun:
        vPrint("Writing to stdout")
        print "----CHANGELOG START"
        outfile = sys.stdout
    else:
        outfile = open("CHANGELOG","w")

    found = False
    for line in lines:
        if ("UNRELEASED" in line) and not found:
            line = line.replace("UNRELEASED",release_date)
            found = True
        print "HERE"
        outfile.write(line)

    if not dryrun:
        outfile.close()
    else:
        print "------ END CHANGE"

def rebase_release(dryrun):
    release_branch = time.strftime("%Y%m%d")

    if dryrun:
        print "Do This"
        print "git checkout -b "+release_branch
        print "git checkout WIP"
        print "git rebase -i master"
    else:
        os.system("git checkout -b "+release_branch)
        os.system("git checkout WIP")
        os.system("git rebase -i master")
    return 0

def make_release():
    # Extract Shortlog
    x = os.popen("git log|head -20").read()
    lines = x.split("\n")
    shortlog = lines[4].strip()

    # Update shortlog
    update_current_shortlog(shortlog)

    # Update changelog date (assume rest is up to date)
    print "UPDATE CHANGELOG"
    update_changelog_release_date()

    print "update all docs"
    here = os.getcwd()
    os.chdir("site")
    os.system("./build_site.py")   
    os.chdir(here)

    os.system("rm -rf dist")
    os.system("rm MANIFEST")
    ver,release = get_shortlog_version()

    os.system('git tag -a v%s -m "Version %s"' % (ver, ver) )

    # Update python version of the clib.
    os.chdir("clib")
    os.system("./mk_py_clib.py")
    os.chdir(here)
    return 0

def do_upload():
    # Build debian package - for actual release change "make deb" to "make ppadeb"
    os.system("rm -rf dist")
    os.system("rm MANIFEST")
    os.system("make ppadeb")
    os.system("make distclean")

    # Build PyPI release
    os.system("rm -rf dist")
    os.system("rm MANIFEST")
    os.system("python setup.py sdist upload")
    os.system("make distclean")

    print ""


def main(argv):
    global verbose
    global dryrun
    if "-v" in argv:
        verbose = True
        argv = [x for x in argv if x != "-v" ]

    if "-d" in argv:
        dryrun = True
        argv = [x for x in argv if x != "-d" ]

    if len(argv) == 2:
        if argv[1] == "get":
            return do_get()

        if argv[1] == "released":
            return do_released()

    if len(argv) >= 2:
        if argv[1] == "bump":
            if len(argv) == 3:
                ver_type = argv[2]
            else:
                ver_type = "patch"
            return do_bump(ver_type)

        if argv[1] == "propose":
            if len(argv) == 3:
                ver_type = argv[2] 
            else:
                ver_type = "patch"
            return do_propose(ver_type)

        if argv[1] == "rebase-release":
            rebase_release(dryrun)
            return 0

        if argv[1] == "make-release":
            make_release()
            return 0

        if argv[1] == "do-upload":
            do_upload()
            return 0

    do_usage()
    return 1

if __name__ == "__main__":
    result = main(sys.argv[:])
    if result != None:
        sys.exit(result)
