1
# This file is part of Buildbot.  Buildbot is free software: you can
2
# redistribute it and/or modify it under the terms of the GNU General Public
3
# License as published by the Free Software Foundation, version 2.
4
#
5
# This program is distributed in the hope that it will be useful, but WITHOUT
6
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
7
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
8
# details.
9
#
10
# You should have received a copy of the GNU General Public License along with
11
# this program; if not, write to the Free Software Foundation, Inc., 51
12
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
13
#
14
# Copyright Buildbot Team Members
15
#
16
# Keep in sync with master/buildbot/__init__.py
17
#
18
# We can't put this method in utility modules, because they import dependency packages
19
#
20

21 4
from __future__ import division
22 4
from __future__ import print_function
23

24 4
import datetime
25 4
import os
26 4
import re
27 4
from subprocess import PIPE
28 4
from subprocess import STDOUT
29 4
from subprocess import Popen
30

31

32 4
def gitDescribeToPep440(version):
33
    # git describe produce version in the form: v0.9.8-20-gf0f45ca
34
    # where 20 is the number of commit since last release, and gf0f45ca is the short commit id
35
    # preceded by 'g'
36
    # we parse this a transform into a pep440 release version 0.9.9.dev20 (increment last digit
37
    # band add dev before 20)
38

39 4
    VERSION_MATCH = re.compile(r'(?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)(\.post(?P<post>\d+))?(-(?P<dev>\d+))?(-g(?P<commit>.+))?') # noqa pylint: disable=line-too-long
40 4
    v = VERSION_MATCH.search(version)
41 4
    if v:
42 4
        major = int(v.group('major'))
43 4
        minor = int(v.group('minor'))
44 4
        patch = int(v.group('patch'))
45 4
        if v.group('dev'):
46 4
            patch += 1
47 4
            dev = int(v.group('dev'))
48 4
            return "{0}.{1}.{2}-dev{3}".format(major, minor, patch, dev)
49 4
        if v.group('post'):
50 4
            return "{0}.{1}.{2}.post{3}".format(major, minor, patch, v.group('post'))
51 4
        return "{0}.{1}.{2}".format(major, minor, patch)
52

53 0
    return v
54

55

56 4
def mTimeVersion(init_file):
57 0
    cwd = os.path.dirname(os.path.abspath(init_file))
58 0
    m = 0
59 0
    for root, dirs, files in os.walk(cwd):
60 0
        for f in files:
61 0
            m = max(os.path.getmtime(os.path.join(root, f)), m)
62 0
    d = datetime.datetime.utcfromtimestamp(m)
63 0
    return d.strftime("%Y.%m.%d")
64

65

66 4
def getVersionFromArchiveId(git_archive_id='$Format:%ct %d$'):
67
    """ Extract the tag if a source is from git archive.
68

69
        When source is exported via `git archive`, the git_archive_id init value is modified
70
        and placeholders are expanded to the "archived" revision:
71

72
            %ct: committer date, UNIX timestamp
73
            %d: ref names, like the --decorate option of git-log
74

75
        See man gitattributes(5) and git-log(1) (PRETTY FORMATS) for more details.
76
    """
77
    # mangle the magic string to make sure it is not replaced by git archive
78 4
    if not git_archive_id.startswith('$For''mat:'):
79
        # source was modified by git archive, try to parse the version from
80
        # the value of git_archive_id
81

82 4
        match = re.search(r'tag:\s*v([^,)]+)', git_archive_id)
83 4
        if match:
84
            # archived revision is tagged, use the tag
85 4
            return gitDescribeToPep440(match.group(1))
86

87
        # archived revision is not tagged, use the commit date
88 4
        tstamp = git_archive_id.strip().split()[0]
89 4
        d = datetime.datetime.utcfromtimestamp(int(tstamp))
90 4
        return d.strftime('%Y.%m.%d')
91 4
    return None
92

93

94 4
def getVersion(init_file):
95
    """
96
    Return BUILDBOT_VERSION environment variable, content of VERSION file, git
97
    tag or 'latest'
98
    """
99

100 4
    try:
101 4
        return os.environ['BUILDBOT_VERSION']
102 4
    except KeyError:
103
        pass
104

105 4
    try:
106 4
        cwd = os.path.dirname(os.path.abspath(init_file))
107 4
        fn = os.path.join(cwd, 'VERSION')
108 4
        with open(fn) as f:
109 0
            return f.read().strip()
110 4
    except IOError:
111
        pass
112

113 4
    version = getVersionFromArchiveId()
114 4
    if version is not None:
115 0
        return version
116

117 4
    try:
118 4
        p = Popen(['git', 'describe', '--tags', '--always'], stdout=PIPE, stderr=STDOUT, cwd=cwd)
119 4
        out = p.communicate()[0]
120

121 4
        if (not p.returncode) and out:
122 4
            v = gitDescribeToPep440(str(out))
123 4
            if v:
124 4
                return v
125 0
    except OSError:
126
        pass
127

128 0
    try:
129
        # if we really can't find the version, we use the date of modification of the most
130
        # recent file
131
        # docker hub builds cannot use git describe
132 0
        return mTimeVersion(init_file)
133 0
    except Exception:
134
        # bummer. lets report something
135 0
        return "latest"
136

137

138 4
version = getVersion(__file__)
139

140 4
__version__ = version

Read our documentation on viewing source code .

Loading