-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathsetup.py
More file actions
291 lines (236 loc) · 9.66 KB
/
setup.py
File metadata and controls
291 lines (236 loc) · 9.66 KB
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
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
# ============================================================
#
# Copyright (C) 2010-2018 by Johannes Wienke
#
# This file may be licensed under the terms of the
# GNU Lesser General Public License Version 3 (the ``LGPL''),
# or (at your option) any later version.
#
# Software distributed under the License is distributed
# on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
# express or implied. See the LGPL for the specific language
# governing rights and limitations.
#
# You should have received a copy of the LGPL along with this
# program. If not, go to http://www.gnu.org/licenses/lgpl.html
# or write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ============================================================
from distutils.command.build import build
from distutils.command.sdist import sdist
from distutils.spawn import find_executable
import os
import shutil
import subprocess
from setuptools import Command, find_packages, setup
from setuptools.command.bdist_egg import bdist_egg
def find_rsb_packages(ignore_protocol=False):
excludes = ['test', 'examples', 'build']
if ignore_protocol:
excludes.append('rsb/protocol')
packages = find_packages(exclude=excludes)
print('Relevant rsb packages: {}'.format(packages))
return packages
class FetchProtocol(Command):
"""
Fetches the protocol files into this project.
.. codeauthor:: jwienke
"""
user_options = [('protocolroot=', 'p',
'root path of the protocol')]
description = 'Fetches the protocol files into this project'
def initialize_options(self):
self.protocolroot = None
def finalize_options(self):
if self.protocolroot is None:
raise RuntimeError('No protocolroot specified. '
'Use the config file or command line option.')
def run(self):
# if it does not exist, create the target directory for the
# copied files
fetched_protocol_dir = 'rsb/protocol'
try:
# in cases of source distributions this would kill also the fetched
# proto files. However, for a source distribution we will never
# reach this method because the protocolroot option will not be set
shutil.rmtree(fetched_protocol_dir)
except os.error:
pass
proto_root = self.protocolroot
print('Using protocol folder: {}'.format(proto_root))
shutil.copytree(os.path.join(proto_root, 'rsb/protocol'),
fetched_protocol_dir)
class BuildProtocol(Command):
"""
Distutils command to build the protocol buffers.
.. codeauthor:: jwienke
"""
user_options = [('protocolroot=', 'p',
'root path of the protocol'),
('protoc=', 'c',
'the protoc compiler to use')]
description = 'Generates the protocol python files from the proto files'
def initialize_options(self):
self.protoc = None
def finalize_options(self):
if self.protoc is None:
self.protoc = find_executable('protoc')
if self.protoc is None:
raise RuntimeError('No protoc compiler specified or found. '
'Use the config file or command line option.')
def run(self):
try:
self.run_command('proto')
except RuntimeError as e:
# for sdist fetching the protocol may fail as long as we have
# the protocol available. Otherwise this is a real error
self.warn('Fetching the protocol failed, but this acceptable '
'in cases where the files have been cached: {}'.format(
e))
if not os.path.exists('rsb/protocol/Notification.proto'):
raise e
# create output directory
outdir = '.'
try:
os.makedirs(outdir)
except os.error:
pass
proto_files = []
for root, _, files in os.walk('rsb/protocol'):
# collect proto files to build
for proto_file in files:
if proto_file[-6:] == '.proto':
proto_files.append(os.path.join(root, proto_file))
# create __init__.py files for all resulting packages
with open(os.path.join(root, '__init__.py'), 'w'):
pass
print('Building protocol files: {}'.format(proto_files))
for proto in proto_files:
# TODO use project root for out path as defined in the test command
call = [self.protoc, '-I=.', '--python_out=' + outdir, proto]
ret = subprocess.call(call)
if ret != 0:
raise RuntimeError('Unable to build proto file: {}'.format(
proto))
# reinitialize the list of packages as we have added new python modules
self.distribution.packages = find_rsb_packages()
# also ensure that the build command for python module really gets
# informed about this
self.reinitialize_command('build_py')
class BDist_egg(bdist_egg): # noqa: N801
"""
Wrapper to require building protobuf before invoking the normal command.
.. codeauthor:: jwienke
"""
def run(self):
self.run_command('build_proto')
bdist_egg.run(self)
class Build(build):
"""
Wrapper to require building protobuf before invoking the normal command.
.. codeauthor:: jwienke
"""
def run(self):
self.run_command('build_proto')
build.run(self)
class Sdist(sdist):
"""
Wrapper to require building protobuf before invoking the normal command.
.. codeauthor:: jwienke
"""
def run(self):
# fetch the protocol before building the source distribution so that
# we have a cached version and each user can rebuild the protocol
# with his own protobuf version
self.run_command('proto')
# reinitialize the list of packages for the distribution to
# include the precompiled protocol results from protoc which
# might conflict with the user's version
self.distribution.packages = find_rsb_packages(ignore_protocol=True)
sdist.run(self)
def get_git_commit():
try:
return subprocess.check_output(
['git', 'log',
'-1', '--pretty=format:g%h']).decode('ascii').strip()
except subprocess.CalledProcessError:
return 'archive'
def determine_protoc_version():
"""
Detect the version of the available protoc compiler.
Determines the protoc version available to compile the protocol to python
files. This is required to define the protobuf library dependency version.
"""
protoc = find_executable('protoc')
print('Using protoc executable from {} '
'to determine the protobuf library version to use. '
'Adjust PATH if something different is desired.'.format(protoc))
version_output = subprocess.check_output(
[protoc, '--version']).decode('utf-8')
protoc_version_parts = version_output.split(' ')
if len(protoc_version_parts) != 2:
raise RuntimeError(
"Unexpected version out from protoc: '{}'".format(version_output))
# Only use the first two version components as the patch part seems to be
# unrelated to breaking changes.
# See: https://github.com/google/protobuf/issues/3602
return [int(x) for x in protoc_version_parts[1].split('.')[:2]]
def generate_version_file(version, commit):
"""
Generate a version file from available version information.
Writes version.py.
"""
with open(os.path.join('rsb', 'version.py.in'), 'r') as template:
with open(os.path.join('rsb', 'version.py'), 'w') as target:
target.write(
template.read().replace(
'@VERSION@', version).replace(
'@COMMIT@', commit))
version = '1.0.0-dev'
commit = get_git_commit()
print('This is version {version}-{commit}'.format(version=version,
commit=commit))
generate_version_file(version, commit)
protoc_version = determine_protoc_version()
print('Determined protobuf version to be {version}'.format(
version=protoc_version))
setup(name='rsb-python',
version=version,
description="Fully event-driven Robotics Service Bus",
author='Johannes Wienke',
author_email='jwienke@techfak.uni-bielefeld.de',
license='LGPLv3+',
url='https://github.com/open-rsx/rsb-python',
keywords=['middleware', 'bus', 'robotics'],
classifiers=[
'Programming Language :: Python',
'Development Status :: 5 - Production/Stable',
'Environment :: Other Environment',
'Intended Audience :: Developers',
'Intended Audience :: Science/Research',
'License :: OSI Approved :: '
'GNU Library or Lesser General Public License (LGPL)',
'Operating System :: OS Independent',
'Topic :: Communications',
'Topic :: Scientific/Engineering',
'Topic :: Software Development :: Libraries',
'Topic :: Software Development :: Libraries :: Python Modules',
],
install_requires=['protobuf>={}.{},<{}.{}'.format(
protoc_version[0],
protoc_version[1],
protoc_version[0],
protoc_version[1] + 1)],
extras_require={
'dev': ['pytest', 'pytest-timeout', 'pytest-cov',
'tox']
},
packages=find_rsb_packages(),
cmdclass={
'proto': FetchProtocol,
'build_proto': BuildProtocol,
'sdist': Sdist,
'build': Build,
'bdist_egg': BDist_egg,
})