#!/usr/bin/env python

"""This is a derivation of the Python distutils StrictVersion class. The parser
is mostly the same, and 'rc' replaces 'a' and 'b' as pre-release prefixes.
Methods are provided to generate new version numbers for testing and release,
'bump_for_testing' and 'bump_for_release' respectively.
"""

class DeployableVersion(object):
    """A version number consists of two or three dot-separated numeric
    components, with an optional "pre-release" tag on the end. The pre-release
    tag consists of 'rc' followed by a number. If the numeric components of two
    version numbers are equal, then one with a pre-release tag will always be
    deemed earlier (lesser) than one without.

    The following are valid version numbers (shown in the order that
    would be obtained by sorting according to the supplied cmp function):

        0.4       0.4.0  (these two are equivalent)
        0.4.1
        0.5rc1
        0.5rc3
        0.5
        0.9.6
        1.0
        1.0.4rc3
        1.0.4

    The following are examples of invalid version numbers:

        1
        2.7.2.2
        1.3.rc4
        1.3pl1
        1.3a4
    """

    import re
    version_re = re.compile(r'^v(\d+) \. (\d+) (\. (\d+))? (rc(\d+))?$',
                            re.VERBOSE) # should include re.ASCII if available


    def __init__ (self, vstring=None):
        if vstring:
            self.parse(vstring)

    def __repr__ (self):
        return "%s ('%s')" % (self.__class__.__name__, str(self))

    def parse(self, vstring):
        match = self.version_re.match(vstring)
        if not match:
            raise ValueError("invalid version number '%s'" % vstring)

        (major, minor, patch, prerelease, prerelease_num) = \
            match.group(1, 2, 4, 5, 6)

        if patch:
            self.version = tuple(map(int, [major, minor, patch]))
        else:
            self.version = tuple(map(int, [major, minor])) + (0,)

        if prerelease:
            self.prerelease = ('rc', int(prerelease_num))
        else:
            self.prerelease = None


    def __str__ (self):

        if self.version[2] == 0:
            vstring = 'v' + '.'.join(map(str, self.version[0:2]))
        else:
            vstring = 'v' + '.'.join(map(str, self.version))

        if self.prerelease:
            vstring = vstring + self.prerelease[0] + str(self.prerelease[1])

        return vstring


    def __cmp__ (self, other):
        if isinstance(other, str):
            other = DeployableVersion(other)

        if self.version != other.version:
            # numeric versions don't match
            # prerelease stuff doesn't matter
            if self.version < other.version:
                return -1
            else:
                return 1

        # have to compare prerelease
        # case 1: neither has prerelease; they're equal
        # case 2: self has prerelease, other doesn't; other is greater
        # case 3: self doesn't have prerelease, other does: self is greater
        # case 4: both have prerelease: must compare them!

        if (not self.prerelease and not other.prerelease):
            return 0
        elif (self.prerelease and not other.prerelease):
            return -1
        elif (not self.prerelease and other.prerelease):
            return 1
        elif (self.prerelease and other.prerelease):
            if self.prerelease == other.prerelease:
                return 0
            elif self.prerelease < other.prerelease:
                return -1
            else:
                return 1
        else:
            assert False, "never get here"

# end class DeployableVersion


def bump_rc(version):
    # Possibilities:
    # case 1: newest tag is an rc, bump the prerelease number
    # case 2: newest tag is a release, no prerelease

    current = DeployableVersion(version)
    command_template = "git tag {0}".format

    if current.prerelease:
        current.prerelease = current.prerelease[:1] + (current.prerelease[1]+1,)
    else:
        # 3-digit version number
        if current.version[2]:
            current.version = current.version[:2] + (current.version[2]+1,)
        # 2-digit version number
        else:
            current.version = current.version[:1] + (current.version[1]+1, 0)
        current.prerelease = ('rc',1)

    return command_template(str(current))


def bump_release(version):
    # Possibilities:
    # case 1: newest tag is an rc, leave the version and nuke the prerelease
    # case 2: newest tag is a release, bump the version

    current = DeployableVersion(version)
    updated = DeployableVersion(version)
    command_template = "git tag {0} {1}".format

    if updated.prerelease:
        updated.prerelease = None
    else:
        # 3-digit version number
        if updated.version[2]:
            updated.version = updated.version[:2] + (updated.version[2]+1,)
        # 2-digit version number
        else:
            updated.version = updated.version[:1] + (updated.version[1]+1, 0)

    return command_template(str(updated), str(current))



def plist(LIST):
    for x in LIST:
        print x

def main(argv=None):
    import sys
    import os
    import fileinput

    if argv is None:
        argv = sys.argv

    # Clean up $0 for parsing
    argv[0] = os.path.basename(argv[0])

    # What should we do?
    if argv[0].startswith('git-bump'):
        mode = 'bump'
    elif argv[0].startswith('git-deploy'):
        mode = 'deploy'
    else:
        print "Can't tell how I was called, not sure what mode you wanted. Exiting."
        print "Hint: $0 should begin with 'git-bump' or 'git-deploy'"
        print argv
        return 2


    # Read in all the version numbers from stdin
    VERSIONS = []
    for vstring in fileinput.input('-'):
        vstring = vstring.strip()
        try:
            VERSIONS.append( DeployableVersion(vstring) )
        except ValueError as e:
            pass


    if mode == 'bump':
        if argv[0].endswith('ANCHOR-STANDARD-STAGING'):
            versioning_style = 'ANCHOR-STANDARD-STAGING'
            gen_next = bump_rc
        elif argv[0].endswith('ANCHOR-STANDARD-PRODUCTION'):
            versioning_style = 'ANCHOR-STANDARD-PRODUCTION'
            gen_next = bump_release
        else:
            print "Can't tell how I was called, don't know how to bump your version. Exiting."
            print "Hint: $0 should end in ANCHOR-STANDARD-STAGING or ANCHOR-STANDARD-PRODUCTION"
            return 2

        if VERSIONS:
            newest = str(max(VERSIONS))
        else:
            print "Found no suitable version numbers"
            return 4

        #print "Current version is: {0}".format(newest)
        #print "Next version is:    {0}".format( gen_next(newest) )
        print str(gen_next(newest))


    elif mode == 'deploy':
        # Find the latest matching version number matching the spec
        if argv[0].endswith('ANCHOR-STANDARD-STAGING'):
            versioning_style = 'ANCHOR-STANDARD-STAGING'
            version_filter = lambda x: x.prerelease is not None
        elif argv[0].endswith('ANCHOR-STANDARD-PRODUCTION'):
            versioning_style = 'ANCHOR-STANDARD-PRODUCTION'
            version_filter = lambda x: x.prerelease is None
        else:
            print "Can't tell how I was called, don't know how to find suitable tags. Exiting."
            print "Hint: $0 should end in ANCHOR-STANDARD-STAGING or ANCHOR-STANDARD-PRODUCTION"
            return 2

        VERSIONS = filter(version_filter, VERSIONS)
        if not VERSIONS:
            print "Can't find any deployable tags"
            return 5

        tag_to_deploy = str(max(VERSIONS))
        #print "Will deploy version: {0}".format(tag_to_deploy)
	print tag_to_deploy


    return 0


if __name__ == '__main__':
    import sys
    sys.exit(main())
