~nskaggs/juju-ci-tools/add-essential-operations

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python

from argparse import ArgumentParser
import json
import logging
import re
import subprocess
import sys
from textwrap import dedent
import urllib2


def parse_version(string):
    return re.search('^const version = "(.*)"', string, re.M).group(1)


def ls_remote(repo_url, ref, head=False, tag=False):
    """Return a tuple fo the matching commit hash and ref.

    None, None is returned when no matching commit was found.

    :raise: an exception when more than one commit matched
    :return: a tuple of commit, ref
    """
    command = ['git', 'ls-remote']
    if head:
        command.append('--heads')
    if tag:
        command.append('--tags')
    command.extend([repo_url, ref])
    found = subprocess.check_output(command)
    found = found.strip()
    if len(found) == 0:
        return None, None
    if len(found.split('\n')) > 1:
        raise Exception(
            "More than one commit matched the branch or tag:\n{}".format(
                found))
    commit, ref = found.split('\t')
    return commit, ref


def get_git_revision_info(branch, revision_spec):
    """Find the commit and juju-core version of a branch.

    Returns a tuple comparable to revno, revision-id, version.
    The revno is always None. The revision-id is the commit hash.

    :param branch: The location of the git branch.
    :param revision_spec: a human-readable revision spec like 'HEAD', '1.18.0',
        or '1dcf4e4fe1'
    :return: a tuple of None, revision-id, version
    """
    protocol, branch_name, repo_name = branch.split(':')
    repo_url = 'https://{}.git'.format(repo_name)
    if revision_spec in (None, '-1', 'HEAD'):
        commit, ref = ls_remote(repo_url, branch_name, head=True)
    else:
        commit, ref = ls_remote(repo_url, revision_spec, tag=True)
    if commit is None:
        commit = revision_spec
    return None, commit


def get_git_version(branch, commit):
    protocol, branch_name, repo_name = branch.split(':')
    domain, user, repo = repo_name.split('/')
    template = 'https://raw.githubusercontent.com/{}/{}/{}/version/version.go'
    file_url = template.format(user, repo, commit)
    response = urllib2.urlopen(file_url)
    return parse_version(response.read())


if __name__ == '__main__':
    parser = ArgumentParser()
    parser.add_argument('branch', help='The branch being built')
    parser.add_argument('revision', nargs='?', default=None,
                        help='The revision being built')
    parser.add_argument('--revision-build', default=None,
                        help='The build number.')
    args = parser.parse_args()
    branch = args.branch
    revision_spec = args.revision
    if branch.startswith('lp:'):
        logging.error('Launchpad branches are no longer supported.')
        sys.exit(1)
    revno, revision_id = get_git_revision_info(branch, revision_spec)
    version = None
    version_str = ''
    try:
        version = get_git_version(branch, revision_id)
        version_str = str(version)
    finally:
        with open('buildvars.bash', 'w') as f:
            f.write(dedent("""\
                export BRANCH=%s
                export REVISION_ID='%s'
                export VERSION=%s
            """ % (branch, revision_id, version_str)))
            if revno is not None:
                f.write('export REVNO=%s\n' % revno)
        with open('buildvars.json', 'w') as f:
            json.dump({
                'branch': branch,
                'revision_id': revision_id,
                'version': version,
                'revision_build': args.revision_build,
                }, f, indent=2)