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
|