-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathversioning.py
262 lines (187 loc) · 7.33 KB
/
versioning.py
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
import re
from waflib import ConfigSet, Configure, Context, Options, Task, TaskGen
CACHE_FILE = 'version.cache'
class ns3_version_info(Task.Task):
'''Base task which implements functionality common to all inherited tasks
This class handles parsing the ns-3 version tag into component parts
as well as saving the version fields to a cache file
All version fields should be stored in the fields property
Derived classes should override _find_closest_tag() and
_find_closest_ns3_tag()
'''
def __init__(self, *args, **kwargs):
self._fields = ConfigSet.ConfigSet()
super(ns3_version_info, self).__init__(*args, **kwargs)
@property
def fields(self):
return self._fields
def _find_closest_tag(self, ctx):
"""Override in derived classes"""
pass
def _find_closest_ns3_tag(self, ctx):
"""Override in derived classes"""
pass
def _parse_version_tag(self, ctx, tag):
safe_tag = tag.strip()
matches = re.match("ns-(\d+)\.(\d+)(?:.(\d+))?(?:-(RC.+))?.*", safe_tag)
if not matches:
return False
self.fields['VERSION_TAG'] = '"{}"'.format(safe_tag)
self.fields['VERSION_MAJOR'] = matches.group(1)
self.fields['VERSION_MINOR'] = matches.group(2)
patch = matches.group(3)
if not patch:
patch = '0'
self.fields['VERSION_PATCH'] = patch
release_candidate = matches.group(4)
if not release_candidate:
release_candidate = ''
self.fields['VERSION_RELEASE_CANDIDATE'] = '"{}"'.format(release_candidate)
return True
def run(self):
ctx = self.generator.bld
try:
self._find_closest_tag(ctx)
if 'VERSION_TAG' not in self.fields:
self._find_closest_ns3_tag(ctx)
#Generate the path where the cache file will be stored
base_path = self.generator.path.make_node('model')
cache_path = base_path.make_node(CACHE_FILE)
#Write the version information out to the cache file
#The cache file is used to populate the version fields when a git
#repository can not be found
self.fields.store(cache_path.abspath())
#merge version info into main configset
ctx.env.update(self.fields)
except Exception as e:
ctx.to_log("Extracting version information from tags failed: {}\n".format(e))
return 1
return 0
class git_ns3_version_info(ns3_version_info):
'''Task to generate version fields from an ns-3 git repository'''
always_run = True
def _find_closest_tag(self, ctx):
cmd = [
'git',
'describe',
'--tags',
'--dirty',
'--long'
]
try:
out = ctx.cmd_and_log(cmd,
output=Context.STDOUT,
quiet=Context.BOTH)
except Exception as e:
raise Exception(e.stderr.strip())
matches = re.match('(.+)-(\d+)-(g[a-fA-F0-9]+)(?:-(dirty))?', out)
if not matches:
raise ValueError("Closest tag found in git log"
"does not match the expected format (tag='{}')"
.format(out))
tag = matches.group(1)
self.fields['CLOSEST_TAG'] = '"{}"'.format(tag)
self.fields['VERSION_TAG_DISTANCE'] = matches.group(2)
self.fields['VERSION_COMMIT_HASH'] = '"{}"'.format(matches.group(3))
self.fields['VERSION_DIRTY_FLAG'] = '1' if matches.group(4) else '0'
self._parse_version_tag(ctx, tag)
def _find_closest_ns3_tag(self, ctx):
cmd = [
'git',
'describe',
'--tags',
'--abbrev=0',
'--match',
'ns-3*',
'HEAD'
]
try:
out = ctx.cmd_and_log(cmd,
output=Context.STDOUT,
quiet=Context.BOTH)
except Exception as e:
raise Exception(e.stderr.strip())
tag = out.strip()
result = self._parse_version_tag(ctx, tag)
if not result:
raise ValueError("Closest ns3 tag found in git log"
" does not match the expected format (tag='{}')"
.format(tag))
@TaskGen.feature('version-defines')
def generate_version_defines(self):
#Create a substitution task to generate version-defines.h
#from fields stored in env
subst_task = self.create_task('subst', self.source, self.target)
if self.env['HAVE_NS3_REPO']:
#if a git repo is present, run the version task first to
#populate the appropriate fields with data from the git repo
version_task = self.create_task('git_ns3_version_info')
subst_task.set_run_after(version_task)
@Configure.conf
def check_git_repo(self):
'''Determine if a git repository is present'''
root = False
cmd = [
'git',
'rev-parse',
'--show-toplevel'
]
try:
#determine if the current directory is part of a git repository
self.find_program('git')
out = self.cmd_and_log(cmd, output=Context.STDOUT, quiet=Context.BOTH)
root = out.strip()
except Exception:
root = False
self.msg('Checking for local git repository', root)
return bool(root)
@Configure.conf
def check_git_repo_has_ns3_tags(self):
'''Determine if the git repository is an ns-3 repository
A repository is considered an ns-3 repository if it has at least one
tag that matches the regex ns-3*
'''
tag = False
cmd = [
'git',
'describe',
'--tags',
'--abbrev=0',
'--match',
'ns-3.[0-9]*'
]
try:
out = self.cmd_and_log(cmd, output=Context.STDOUT, quiet=Context.BOTH)
tag = out.strip()
except Exception:
tag = False
self.msg('Checking local git repository for ns3 tags', tag)
return bool(tag)
def configure(ctx):
has_git_repo = False
has_ns3_tags = False
if not Options.options.enable_build_version:
return
if ctx.check_git_repo():
has_git_repo = True
has_ns3_tags = ctx.check_git_repo_has_ns3_tags()
ctx.env['HAVE_GIT_REPO'] = has_git_repo
ctx.env['HAVE_NS3_REPO'] = has_ns3_tags
if not has_ns3_tags:
version_cache = ConfigSet.ConfigSet ()
#no ns-3 repository, look for a cache file containing the version info
ctx.start_msg('Searching for file {}'.format(CACHE_FILE))
glob_pattern = '**/{}'.format(CACHE_FILE)
cache_path = ctx.path.ant_glob(glob_pattern)
if len(cache_path) > 0:
#Found cache file
#Load it and merge the information into the main context environment
src_path = cache_path[0].srcpath()
ctx.end_msg(src_path)
version_cache.load (src_path)
else:
ctx.end_msg(False)
ctx.fatal('Unable to find ns3 git repository or version.cache file '
'containing version information')
ctx.env.update(version_cache)