|
1
|
|
|
#!/usr/bin/env python3 |
|
2
|
|
|
# encoding: utf-8 |
|
3
|
|
|
""" |
|
4
|
|
|
setup.py |
|
5
|
|
|
|
|
6
|
|
|
Created by Thomas Mangin on 2011-01-24. |
|
7
|
|
|
Copyright (c) 2009-2017 Exa Networks. All rights reserved. |
|
8
|
|
|
""" |
|
9
|
|
|
|
|
10
|
|
|
import os |
|
11
|
|
|
import sys |
|
12
|
|
|
|
|
13
|
|
|
class path: |
|
14
|
|
|
root = os.path.join(os.getcwd(), os.path.dirname(sys.argv[0])) |
|
15
|
|
|
changelog = os.path.join(root,'CHANGELOG') |
|
16
|
|
|
lib_exa = os.path.join(root, 'lib/exabgp') |
|
17
|
|
|
version = os.path.join(root, 'lib/exabgp/version.py') |
|
18
|
|
|
debian = os.path.join(root, 'debian/changelog') |
|
19
|
|
|
egg = os.path.join(root, 'lib/exabgp.egg-info') |
|
20
|
|
|
build_exabgp = os.path.join(root, 'build/lib/exabgp') |
|
21
|
|
|
build_root = os.path.join(root, 'build') |
|
22
|
|
|
|
|
23
|
|
|
@staticmethod |
|
24
|
|
|
def remove_egg(): |
|
25
|
|
|
from shutil import rmtree |
|
26
|
|
|
print('removing left-over egg') |
|
27
|
|
|
if os.path.exists(path.egg): |
|
28
|
|
|
rmtree(path.egg) |
|
29
|
|
|
if os.path.exists(path.build_exabgp): |
|
30
|
|
|
rmtree(path.build_root) |
|
31
|
|
|
return 0 |
|
32
|
|
|
|
|
33
|
|
|
|
|
34
|
|
|
class version: |
|
35
|
|
|
JSON = '4.0.1' |
|
36
|
|
|
TEXT = '4.0.1' |
|
37
|
|
|
|
|
38
|
|
|
template = """\ |
|
39
|
|
|
import os |
|
40
|
|
|
|
|
41
|
|
|
commit = "%s" |
|
42
|
|
|
release = "%s" |
|
43
|
|
|
json = "%s" |
|
44
|
|
|
text = "%s" |
|
45
|
|
|
version = os.environ.get('EXABGP_VERSION',release) |
|
46
|
|
|
|
|
47
|
|
|
# Do not change the first line as it is parsed by scripts |
|
48
|
|
|
|
|
49
|
|
|
if __name__ == '__main__': |
|
50
|
|
|
import sys |
|
51
|
|
|
sys.stdout.write(version) |
|
52
|
|
|
""" |
|
53
|
|
|
|
|
54
|
|
|
@staticmethod |
|
55
|
|
|
def get(): |
|
56
|
|
|
sys.path.append(path.lib_exa) |
|
57
|
|
|
from version import version as release |
|
58
|
|
|
|
|
59
|
|
|
# transitional fix |
|
60
|
|
|
if "-" in release: |
|
61
|
|
|
release = release.split("-")[0] |
|
62
|
|
|
|
|
63
|
|
|
if version.changelog() != release: |
|
64
|
|
|
release += ".post1" |
|
65
|
|
|
|
|
66
|
|
|
return release |
|
67
|
|
|
|
|
68
|
|
|
@staticmethod |
|
69
|
|
|
def changelog(): |
|
70
|
|
|
with open(path.changelog) as f: |
|
71
|
|
|
f.readline() |
|
72
|
|
|
for line in f: |
|
73
|
|
|
if line.lower().startswith('version '): |
|
74
|
|
|
return line.split()[1].rstrip().rstrip(':').strip() |
|
75
|
|
|
return '' |
|
76
|
|
|
|
|
77
|
|
|
@staticmethod |
|
78
|
|
|
def set(tag,commit): |
|
79
|
|
|
with open(path.version, 'w') as f: |
|
80
|
|
|
f.write(version.template % ( |
|
81
|
|
|
commit, tag, |
|
82
|
|
|
version.JSON, |
|
83
|
|
|
version.TEXT |
|
84
|
|
|
)) |
|
85
|
|
|
return version.get() == tag |
|
86
|
|
|
|
|
87
|
|
|
@staticmethod |
|
88
|
|
|
def latest (tags): |
|
89
|
|
|
valid = [ |
|
90
|
|
|
[int(_) for _ in tag.split('.')] for tag in tags |
|
91
|
|
|
if version.valid(tag) |
|
92
|
|
|
] |
|
93
|
|
|
return '.'.join(str(_) for _ in sorted(valid)[-1]) |
|
94
|
|
|
|
|
95
|
|
|
@staticmethod |
|
96
|
|
|
def valid (tag): |
|
97
|
|
|
parts = tag.split('.') |
|
98
|
|
|
return len(parts) == 3 \ |
|
99
|
|
|
and parts[0].isdigit() \ |
|
100
|
|
|
and parts[1].isdigit() \ |
|
101
|
|
|
and parts[2].isdigit() |
|
102
|
|
|
|
|
103
|
|
|
@staticmethod |
|
104
|
|
|
def candidates(tag): |
|
105
|
|
|
latest = [int(_) for _ in tag.split('.')] |
|
106
|
|
|
return [ |
|
107
|
|
|
'.'.join([str(_) for _ in (latest[0], latest[1], latest[2] + 1)]), |
|
108
|
|
|
'.'.join([str(_) for _ in (latest[0], latest[1] + 1, 0)]), |
|
109
|
|
|
'.'.join([str(_) for _ in (latest[0] + 1, 0, 0)]), |
|
110
|
|
|
] |
|
111
|
|
|
|
|
112
|
|
|
|
|
113
|
|
|
class debian: |
|
114
|
|
|
template = """\ |
|
115
|
|
|
exabgp (%s-0) unstable; urgency=low |
|
116
|
|
|
|
|
117
|
|
|
* Latest ExaBGP release. |
|
118
|
|
|
|
|
119
|
|
|
-- Vincent Bernat <[email protected]> %s |
|
120
|
|
|
|
|
121
|
|
|
""" |
|
122
|
|
|
@staticmethod |
|
123
|
|
|
def set(version): |
|
124
|
|
|
from email.utils import formatdate |
|
125
|
|
|
with open(path.debian, 'w') as w: |
|
126
|
|
|
w.write(debian.template % (version, formatdate())) |
|
127
|
|
|
print('updated debian/changelog') |
|
128
|
|
|
|
|
129
|
|
|
|
|
130
|
|
|
class command: |
|
131
|
|
|
dryrun = 'dry-run' if os.environ.get('DRY', os.environ.get('DRYRUN', os.environ.get('DRY_RUN', False))) else '' |
|
132
|
|
|
|
|
133
|
|
|
@staticmethod |
|
134
|
|
|
def run(cmd): |
|
135
|
|
|
print('>', cmd) |
|
136
|
|
|
return git.dryrun or os.system(cmd) |
|
137
|
|
|
|
|
138
|
|
|
|
|
139
|
|
|
class git (command): |
|
140
|
|
|
@staticmethod |
|
141
|
|
|
def commit (comment): |
|
142
|
|
|
return git.run('git commit -a -m "%s"' % comment) |
|
143
|
|
|
|
|
144
|
|
|
@staticmethod |
|
145
|
|
|
def push(tag=False,repo=''): |
|
146
|
|
|
command = 'git push' |
|
147
|
|
|
if tag: |
|
148
|
|
|
command += ' --tags' |
|
149
|
|
|
if repo: |
|
150
|
|
|
command += ' %s' % repo |
|
151
|
|
|
return git.run(command) |
|
152
|
|
|
|
|
153
|
|
|
@staticmethod |
|
154
|
|
|
def head_commit(): |
|
155
|
|
|
return os.popen('git rev-parse --short HEAD').read().strip() |
|
156
|
|
|
|
|
157
|
|
|
@staticmethod |
|
158
|
|
|
def tags(): |
|
159
|
|
|
return os.popen('git tag').read().split('-')[0].strip().split('\n') |
|
160
|
|
|
|
|
161
|
|
|
@staticmethod |
|
162
|
|
|
def tag(release): |
|
163
|
|
|
return git.run('git tag -a %s -m "release %s"' % (release, release)) |
|
164
|
|
|
|
|
165
|
|
|
@staticmethod |
|
166
|
|
|
def pending(): |
|
167
|
|
|
commit = None |
|
168
|
|
|
for line in os.popen('git status').read().split('\n'): |
|
169
|
|
|
if 'modified:' in line: |
|
170
|
|
|
if 'lib/exabgp/version.py' in line or 'debian/changelog' in line: |
|
171
|
|
|
if commit is not False: |
|
172
|
|
|
commit = True |
|
173
|
|
|
else: |
|
174
|
|
|
return False |
|
175
|
|
|
elif 'renamed:' in line: |
|
176
|
|
|
return False |
|
177
|
|
|
return commit |
|
178
|
|
|
|
|
179
|
|
|
class repo: |
|
180
|
|
|
def update_version(): |
|
181
|
|
|
if not version.set(version.changelog(), git.head_commit()): |
|
182
|
|
|
print('failed to set version in python code') |
|
183
|
|
|
return False |
|
184
|
|
|
|
|
185
|
|
|
if not git.commit('updating version to %s' % version.get()): |
|
186
|
|
|
print('failed to commit the change') |
|
187
|
|
|
return False |
|
188
|
|
|
|
|
189
|
|
|
if not git.push(): |
|
190
|
|
|
print('failed to push the change') |
|
191
|
|
|
return False |
|
192
|
|
|
return True |
|
193
|
|
|
|
|
194
|
|
|
|
|
195
|
|
|
# |
|
196
|
|
|
# Check that that there is no version inconsistancy before any pypi action |
|
197
|
|
|
# |
|
198
|
|
|
|
|
199
|
|
|
def release_github(): |
|
200
|
|
|
print() |
|
201
|
|
|
print('updating Github') |
|
202
|
|
|
release = version.changelog() |
|
203
|
|
|
tags = git.tags() |
|
204
|
|
|
|
|
205
|
|
|
if not version.valid(release): |
|
206
|
|
|
print('invalid new version in CHANGELOG (%s)' % release) |
|
207
|
|
|
return 1 |
|
208
|
|
|
|
|
209
|
|
|
candidates = version.candidates(version.latest(tags)) |
|
210
|
|
|
|
|
211
|
|
|
print('valid versions are:', ', '.join(candidates)) |
|
212
|
|
|
print('checking the CHANGELOG uses one of them') |
|
213
|
|
|
|
|
214
|
|
|
print('ok, next release is %s' % release) |
|
215
|
|
|
print('checking that this release is not already tagged') |
|
216
|
|
|
|
|
217
|
|
|
if release in tags: |
|
218
|
|
|
print('this tag was already released') |
|
219
|
|
|
return 1 |
|
220
|
|
|
|
|
221
|
|
|
print('ok, this is a new release') |
|
222
|
|
|
print('rewriting lib/exabgp/version.py') |
|
223
|
|
|
version.set(release, git.head_commit()) |
|
224
|
|
|
print('rewriting debian/changelog') |
|
225
|
|
|
debian.set(release) |
|
226
|
|
|
|
|
227
|
|
|
print('checking if we need to commit a version.py change') |
|
228
|
|
|
status = git.pending() |
|
229
|
|
|
if status is None: |
|
230
|
|
|
print('all is already set for release') |
|
231
|
|
|
elif status is False: |
|
232
|
|
|
print('more than one file is modified and need updating, aborting') |
|
233
|
|
|
return 1 |
|
234
|
|
|
else: |
|
235
|
|
|
if git.commit('updating version to %s' % release): |
|
236
|
|
|
print('could not commit version change (%s)' % release) |
|
237
|
|
|
return 1 |
|
238
|
|
|
print('version was updated') |
|
239
|
|
|
|
|
240
|
|
|
print('tagging the new version') |
|
241
|
|
|
if git.tag(release): |
|
242
|
|
|
print('could not tag version (%s)' % release) |
|
243
|
|
|
return 1 |
|
244
|
|
|
|
|
245
|
|
|
print('pushing the new tag to local repo') |
|
246
|
|
|
if git.push(tag=True, repo='upstream'): |
|
247
|
|
|
print('could not push release version') |
|
248
|
|
|
return 1 |
|
249
|
|
|
return 0 |
|
250
|
|
|
|
|
251
|
|
|
|
|
252
|
|
|
def release_pypi(): |
|
253
|
|
|
print() |
|
254
|
|
|
print('updating PyPI') |
|
255
|
|
|
|
|
256
|
|
|
path.remove_egg() |
|
257
|
|
|
|
|
258
|
|
|
if command.run('python setup.py sdist bdist_wheel'): |
|
259
|
|
|
print('could not generate egg') |
|
260
|
|
|
return 1 |
|
261
|
|
|
|
|
262
|
|
|
# keyring used to save credential |
|
263
|
|
|
# https://pypi.org/project/twine/ |
|
264
|
|
|
|
|
265
|
|
|
release = version.changelog() |
|
266
|
|
|
|
|
267
|
|
|
if command.run('twine upload dist/exabgp-%s.tar.gz' % release): |
|
268
|
|
|
print('could not upload with twine') |
|
269
|
|
|
return 1 |
|
270
|
|
|
|
|
271
|
|
|
print('all done.') |
|
272
|
|
|
return 0 |
|
273
|
|
|
|
|
274
|
|
|
|
|
275
|
|
|
def st(): |
|
276
|
|
|
import platform |
|
277
|
|
|
from distutils.util import get_platform |
|
278
|
|
|
from setuptools import setup |
|
279
|
|
|
|
|
280
|
|
|
def packages(lib): |
|
281
|
|
|
def dirs(*path): |
|
282
|
|
|
for location, _, _ in os.walk(os.path.join(*path)): |
|
283
|
|
|
yield location |
|
284
|
|
|
|
|
285
|
|
|
def modules(lib): |
|
286
|
|
|
return next(os.walk(lib))[1] |
|
287
|
|
|
|
|
288
|
|
|
r = [] |
|
289
|
|
|
for module in modules(lib): |
|
290
|
|
|
for d in dirs(lib, module): |
|
291
|
|
|
r.append(d.replace('/', '.').replace('\\', '.')[len(lib) + 1:]) |
|
292
|
|
|
return r |
|
293
|
|
|
|
|
294
|
|
|
|
|
295
|
|
|
def filesOf(directory): |
|
296
|
|
|
files = [] |
|
297
|
|
|
for l, d, fs in os.walk(directory): |
|
298
|
|
|
if not d: |
|
299
|
|
|
for f in fs: |
|
300
|
|
|
files.append(os.path.join(l, f)) |
|
301
|
|
|
return files |
|
302
|
|
|
|
|
303
|
|
|
|
|
304
|
|
|
def testFilesOf(directory): |
|
305
|
|
|
files = [] |
|
306
|
|
|
for l, d, fs in os.walk(directory): |
|
307
|
|
|
if not d: |
|
308
|
|
|
for f in fs: |
|
309
|
|
|
if f.endswith('.run') or f.endswith('.conf'): |
|
310
|
|
|
files.append(os.path.join(l, f)) |
|
311
|
|
|
return files |
|
312
|
|
|
|
|
313
|
|
|
|
|
314
|
|
|
files_definition = [ |
|
315
|
|
|
('share/exabgp/processes', filesOf('etc/exabgp')), |
|
316
|
|
|
('share/exabgp/etc', testFilesOf('qa/conf')), |
|
317
|
|
|
] |
|
318
|
|
|
|
|
319
|
|
|
if platform.system() != 'NetBSD': |
|
320
|
|
|
if sys.argv[-1] == 'systemd': |
|
321
|
|
|
files_definition.append(('/usr/lib/systemd/system', filesOf('etc/systemd'))) |
|
322
|
|
|
|
|
323
|
|
|
try: |
|
324
|
|
|
description_rst = open('PYPI.rst').read() % {'version': version.get()} |
|
325
|
|
|
except IOError: |
|
326
|
|
|
print('failed to open PYPI.rst') |
|
327
|
|
|
return 1 |
|
328
|
|
|
|
|
329
|
|
|
if command.dryrun: |
|
330
|
|
|
return 1 |
|
331
|
|
|
|
|
332
|
|
|
setup( |
|
333
|
|
|
name='exabgp', |
|
334
|
|
|
version=version.get(), |
|
335
|
|
|
description='BGP swiss army knife', |
|
336
|
|
|
long_description=description_rst, |
|
337
|
|
|
author='Thomas Mangin', |
|
338
|
|
|
author_email='[email protected]', |
|
339
|
|
|
url='https://github.com/Exa-Networks/exabgp', |
|
340
|
|
|
license='BSD', |
|
341
|
|
|
keywords='BGP routing SDN FlowSpec HA', |
|
342
|
|
|
platforms=[get_platform(), ], |
|
343
|
|
|
package_dir={'': 'lib'}, |
|
344
|
|
|
packages=packages('lib'), |
|
345
|
|
|
package_data={'': ['PYPI.rst']}, |
|
346
|
|
|
download_url='https://github.com/Exa-Networks/exabgp/archive/%s.tar.gz' % version.get(), |
|
347
|
|
|
data_files=files_definition, |
|
348
|
|
|
setup_requires=['setuptools'], |
|
349
|
|
|
classifiers=[ |
|
350
|
|
|
'Development Status :: 5 - Production/Stable', |
|
351
|
|
|
'Environment :: Console', |
|
352
|
|
|
'Intended Audience :: System Administrators', |
|
353
|
|
|
'Intended Audience :: Telecommunications Industry', |
|
354
|
|
|
'License :: OSI Approved :: BSD License', |
|
355
|
|
|
'Operating System :: POSIX', |
|
356
|
|
|
'Operating System :: MacOS :: MacOS X', |
|
357
|
|
|
'Programming Language :: Python', |
|
358
|
|
|
'Programming Language :: Python :: 3.7', |
|
359
|
|
|
'Topic :: Internet', |
|
360
|
|
|
], |
|
361
|
|
|
entry_points={ |
|
362
|
|
|
'console_scripts': [ |
|
363
|
|
|
'exabgp = exabgp.application:run_exabgp', |
|
364
|
|
|
'exabgpcli = exabgp.application:run_cli', |
|
365
|
|
|
], |
|
366
|
|
|
}, |
|
367
|
|
|
) |
|
368
|
|
|
return 0 |
|
369
|
|
|
|
|
370
|
|
|
|
|
371
|
|
|
def help(): |
|
372
|
|
|
print("""\ |
|
373
|
|
|
python3 setup.py help this help |
|
374
|
|
|
python3 setup.py cleanup delete left-over file from release |
|
375
|
|
|
python3 setup.py release tag a new version on github, and update pypi |
|
376
|
|
|
python3 setup.py pypi create egg/wheel |
|
377
|
|
|
python3 setup.py install local installation |
|
378
|
|
|
python3 setup.py build local build |
|
379
|
|
|
""") |
|
380
|
|
|
|
|
381
|
|
|
def main (): |
|
382
|
|
|
if os.environ.get("SCRUTINIZER", "") == "true": |
|
383
|
|
|
sys.exit(0) |
|
384
|
|
|
|
|
385
|
|
|
if sys.argv[-1] == 'cleanup': |
|
386
|
|
|
sys.exit(path.remove_egg()) |
|
387
|
|
|
|
|
388
|
|
|
if sys.argv[-1] == 'release': |
|
389
|
|
|
sys.exit(release_github()) |
|
390
|
|
|
|
|
391
|
|
|
if sys.argv[-1] == 'pypi': |
|
392
|
|
|
sys.exit(release_pypi()) |
|
393
|
|
|
|
|
394
|
|
|
# "internal" commands |
|
395
|
|
|
|
|
396
|
|
|
if sys.argv[-1] == 'version': |
|
397
|
|
|
sys.stdout.write("%s\n" % version.get()) |
|
398
|
|
|
sys.exit(0) |
|
399
|
|
|
|
|
400
|
|
|
if sys.argv[-1] == 'current': |
|
401
|
|
|
sys.stdout.write("%s\n" % version.changelog()) |
|
402
|
|
|
sys.exit(0) |
|
403
|
|
|
|
|
404
|
|
|
if '--help' in sys.argv or 'help' in sys.argv: |
|
405
|
|
|
help() |
|
406
|
|
|
sys.exit(1) |
|
407
|
|
|
|
|
408
|
|
|
if sys.argv[-1] == 'debian': |
|
409
|
|
|
release = version.changelog() |
|
410
|
|
|
debian.set(release) |
|
411
|
|
|
sys.exit(0) |
|
412
|
|
|
|
|
413
|
|
|
sys.exit(st()) |
|
414
|
|
|
|
|
415
|
|
|
|
|
416
|
|
|
if __name__ == '__main__': |
|
417
|
|
|
main() |
|
418
|
|
|
|