#! /usr/bin/env python

"""
Create _version.py, based upon the latest darcs release tag.

If your source tree is coming from darcs (i.e. it is in a darcs repository),
this tool will determine the most recent release tag, count the patches that
have been applied since then, and compute a version number to be written into
_version.py . This version number will be available by doing:

 from your_package_name import __version__

Source trees that do not come from darcs (e.g. release tarballs, nightly
tarballs) and are not within a darcs repository should instead, come with a
_version.py that was generated before the tarball was produced. In this case,
this script will quietly exit without modifying the existing _version.py .

'release tags' are tags in the source repository that match the following
regexp:

 ^your_package_name-\d+\.\d+(\.\d+)?((a|b|c)(\d+)?)?\w*$

"""

import os, sys, re
import xml.dom.minidom
from subprocess import Popen, PIPE

try:
    # If we can import allmydata.util.version_class then use its regex.
    from allmydata.util import version_class
    VERSION_BASE_RE_STR = version_class.VERSION_BASE_RE_STR
except ImportError:
    # Else (perhaps a bootstrapping problem),then we'll use this
    # regex, which was copied from the pyutil source code on
    # 2007-08-11.
    VERSION_BASE_RE_STR="(\d+)\.(\d+)(\.(\d+))?((a|b|c)(\d+))?"

def get_text(nodelist):
    rc = ""
    for node in nodelist:
        if node.nodeType == node.TEXT_NODE:
            rc = rc + node.data
    return rc

VERSION_BODY = '''
from allmydata.util.version_class import Version

# This is the version of this tree, as created by scripts/make-version.py from
# the Darcs patch information: the main version number is taken from the most
# recent release tag. If some patches have been added since the last release,
# this will have a -NN "build number" suffix. Please see
# allmydata.util.version_class for a description of what the different fields 
# mean.

verstr = "%s"
__version__ = Version(verstr)
'''

def write_version_py(verstr, outfname):
    f = open(outfname, "wt+")
    f.write(VERSION_BODY % (verstr,))
    f.close()

def update(pkgname, verfilename):
    rc = -1
    if not os.path.isdir("_darcs"):
        if os.path.exists(verfilename):
            print "No _darcs directory, and %s already exists, so leaving it alone." % (verfilename,)
            return 0
        print "No _darcs directory, no %s, so version is unknown." % (verfilename,)
        return 1
    cmd = ["darcs", "changes", "--from-tag=^%s" % (pkgname,), "--xml-output"]
    try:
        p = Popen(cmd, stdout=PIPE)
    except:
        pass
    else:
        output = p.communicate()[0]
        rc = p.returncode
    if rc != 0:
        cmd = ["realdarcs.exe", "changes", "--from-tag=^%s" % (pkgname,), "--xml-output"]
        p = Popen(cmd, stdout=PIPE)
        output = p.communicate()[0]
        rc = p.returncode
        if rc != 0:
            if os.path.exists(verfilename):
                print "Failure from attempt to find version tags with 'darcs changes', and %s already exists, so leaving it alone." % (verfilename,)
                return 0
            else:
                print "Failure from attempt to find version tags with 'darcs changes', and %s doesn't exist." % (verfilename,)
                return rc

    doc = xml.dom.minidom.parseString(output)
    changelog = doc.getElementsByTagName("changelog")[0]
    patches = changelog.getElementsByTagName("patch")
    count = 0
    regexstr = "^TAG %s-(%s)" % (pkgname, VERSION_BASE_RE_STR,)
    version_re = re.compile(regexstr)
    for patch in patches:
        name = get_text(patch.getElementsByTagName("name")[0].childNodes)
        m = version_re.match(name)
        if m:
            last_tag = m.group(1)
            last_tag = last_tag.encode("ascii")
            break
        count += 1
    else:
        print "I'm unable to find a tag in the darcs history matching \"%s\", so I'm leaving %s alone." % (regexstr, verfilename,)
        return 0

    if count:
        # this is an interim version
        verstr = "%s-%d" % (last_tag, count)
    else:
        # this is a release
        verstr = last_tag

    write_version_py(verstr, verfilename)
    print "wrote '%s' into %s" % (verstr, verfilename,)
    return 0

if __name__ == '__main__':
    if len(sys.argv) >= 2:
        pkgname = sys.argv[1]
    else:
        pkgname = os.path.basename(os.getcwd())
        print "You didn't pass a pkg-name on the command-line, so I'm going to take the name of the current working directory: \"%s\"" % (pkgname,)

    if len(sys.argv) >= 3:
        verfilename = sys.argv[2]
    else:
        verfilename = os.path.join(pkgname, "_version.py")
        print "You didn't pass a verfilename on the command-line, so I'm going to build one from the name of the package: \"%s\"" % (verfilename,)

    rc = update(pkgname=pkgname, verfilename=verfilename)
    sys.exit(rc)