forked from Dynatrace/OneAgent-SDK-for-Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsetup.py
397 lines (324 loc) · 13.4 KB
/
setup.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
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
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
#! /usr/bin/env python3
#
# Copyright 2019 Dynatrace LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Beware when cross-building 64/32 bit:
# When using --plat-name to override this, make sure to `rm -r build` othewise
# files from the wrong platform might be reused.
# Also, on Linux because of https://bugs.python.org/issue18987, using a 32 bit
# Python on a 64 bit OS is not enough to change the platform tag.
from __future__ import print_function
import io
import os
from os import path
import re
# https://github.com/PyCQA/pylint/issues/73
#pylint:disable=no-name-in-module,import-error
from distutils.util import get_platform
from distutils.command.build import build
from distutils import log as distlog
#pylint:enable=no-name-in-module,import-error
from setuptools import setup, find_packages, Distribution
from setuptools.command.install import install
from setuptools.command.build_ext import build_ext
from pkg_resources import parse_version
try:
from wheel.bdist_wheel import bdist_wheel
except ImportError:
bdist_wheel = None
CSDK_ENV_NAME = 'DT_PYSDK_CSDK_PATH'
_THIS_DIR = path.dirname(path.abspath(__file__))
with io.open(path.join(_THIS_DIR, 'README.md'), encoding='utf-8') as readmefile:
long_description = readmefile.read()
del readmefile
def get_version_from_pkg_info():
pkg_info_path = path.join(_THIS_DIR, 'PKG-INFO')
if not path.isfile(pkg_info_path):
return None
ver_re = re.compile(r"^Version: (.+)$")
with io.open(pkg_info_path, encoding='utf-8') as pinfofile:
for line in pinfofile:
match = ver_re.match(line)
if match:
return match.group(1)
return None
def get_version_from_version_py():
ver_re = re.compile(r"^__version__ = '([^']+)'$")
verfilepath = path.join(_THIS_DIR, 'src/oneagent/version.py')
with io.open(verfilepath, encoding='utf-8') as verfile:
for line in verfile:
match = ver_re.match(line)
if match:
version = match.group(1)
break
else:
raise AssertionError('Version not found in src/oneagent/version.py')
build_timestamp = os.environ.get('BUILD_TIMESTAMP')
if build_timestamp:
version = '{}.{}'.format(version, re.sub(r'-0*', '.', build_timestamp))
return version
__version__ = get_version_from_pkg_info()
if not __version__:
__version__ = get_version_from_version_py()
if __version__ != str(parse_version(__version__)):
raise AssertionError(
'Version {} normalizes to {}'.format(
__version__, parse_version(__version__)))
# This function was adapted from https://www.python.org/dev/peps/pep-0513/
# (public domain)
def get_glibc_version_string():
import ctypes
try:
process_namespace = ctypes.CDLL(None)
gnu_get_libc_version = process_namespace.gnu_get_libc_version
# Call gnu_get_libc_version, which returns a string like "2.5".
gnu_get_libc_version.restype = ctypes.c_char_p
version_str = gnu_get_libc_version()
# py2 / py3 compatibility:
if not isinstance(version_str, str):
version_str = version_str.decode("ascii")
return version_str
except Exception: #pylint:disable=broad-except
# Symbol doesn't exist -> therefore, we are not linked to
# glibc.
return None
def unsupported_msg(plat_name):
try:
import pip
pipver = pip.__version__
except Exception: #pylint:disable=broad-except
pipver = 'Unknown or not using pip'
glibc_ver = get_glibc_version_string()
if glibc_ver:
glibc = '\nGNU libc version: ' + glibc_ver + '\n'
elif os.name != 'nt':
glibc = '\nNot using GNU libc. Note that musl libc is not supported.\n'
else:
glibc = ''
return '''
******************************************************************************
*** You are trying to build the Python SDK from source. ***
*** This could mean that you are using an outdated version of pip (older ***
*** than 8.1.0) or you are attempting to install the SDK on an ***
*** unsupported platform. Please check the requirements at ***
*** https://github.com/Dynatrace/OneAgent-SDK-for-Python#requirements ***
******************************************************************************
Your pip version: {pipver}
Your target platform: {plat}{glibc}
If you are intentionally building from source, download the OneAgent SDK for
C/C++ that corresponds to this Python SDK (v{v}; see table at
https://github.com/Dynatrace/OneAgent-SDK-for-Python#requirements) from
https://github.com/Dynatrace/OneAgent-SDK-for-C and set the environment variable
{env} to the path to the shared library/DLL correponding to the platform you are
building for.'''.format(
v=__version__, plat=plat_name, env=CSDK_ENV_NAME, pipver=pipver, glibc=glibc)
def compilefile(fname, mode='exec'):
with open(fname) as srcfile:
codestr = srcfile.read()
return compile(codestr, fname, mode)
def adjust_plat_name(self):
#pylint:disable=access-member-before-definition
if self.plat_name is not None:
return
baseplat = get_platform()
if baseplat.startswith('linux'):
platname = baseplat.split('-', 2)
platname[0] = 'manylinux1'
#pylint:disable=attribute-defined-outside-init
self.plat_name = '-'.join(platname)
else:
self.plat_name = baseplat
if bdist_wheel is not None:
class BdistWheel(bdist_wheel):
def finalize_options(self):
adjust_plat_name(self)
bdist_wheel.finalize_options(self)
def get_tag(self):
plat_name = self.plat_name or get_platform()
plat_name = plat_name.replace('-', '_').replace('.', '_')
return (
'py2.py3' if self.universal else self.python_tag, # impl-tag
'none', # abi-tag
plat_name)
def get_dll_info(plat_name):
dll_info = {}
infopath = path.join(_THIS_DIR, 'src/oneagent/_impl/native/sdkdllinfo.py')
exec(compilefile(infopath), dll_info) #pylint:disable=exec-used
if plat_name:
is_win32 = plat_name.startswith('win')
is_64bit = plat_name.endswith('64')
dll_info['IS64BIT'] = is_64bit
dll_info['WIN32'] = is_win32
return dll_info
def get_dll_input_path(plat_name):
dll_info = get_dll_info(plat_name) # Do this before defaulting plat_name
plat_name = plat_name or get_platform()
sdkpath = os.getenv(CSDK_ENV_NAME)
if not sdkpath:
warn_msg = unsupported_msg(plat_name)
distlog.error(warn_msg)
distlog.warn(
'Continuning installation, but resulting package will always be in'
' no-op mode (no connection to Dynatrace will be possible)')
return None
if path.isfile(sdkpath):
return sdkpath
if not path.exists(sdkpath):
raise ValueError(
'****** Path "{}" in ${} does not exist. ******'.format(
sdkpath, CSDK_ENV_NAME))
# A folder is specified in skdpath. We can try to find some well-known
# binaries in a folder with one of two well-known structures.
if not dll_info['WIN32'] and 'linux' not in plat_name:
raise ValueError(
'****** Your platform ({}) is not supported by the '
'native SDK (its OS is neither Linux nor Windows). ******'.format(
plat_name))
if '86' not in plat_name and 'amd64' not in plat_name.lower() \
and plat_name != 'win32':
raise ValueError(
'****** Your platform ({}) is not supported by the '
'native SDK (its CPU is not x86/AMD64-based). ******'.format(
plat_name))
# Try native SDK distribution package-like
nsdk_platname = '{}-x86_{}'.format(
'windows' if dll_info['WIN32'] else 'linux',
'64' if dll_info['IS64BIT'] else '32')
basename = dll_info['dll_name']()
fname = path.join(sdkpath, 'lib', nsdk_platname, basename)
if path.exists(fname):
return fname
fname = path.join(sdkpath, nsdk_platname, basename)
if path.exists(fname):
return fname
# Try DT_HOME-like path.
fname = dll_info['_dll_name_in_home'](sdkpath)
if path.exists(fname):
return fname
# Recommended, however, is setting the environment variable to the filename,
# which is the only way we recommend here.
raise ValueError(
'****** ${} is set to a directory with unknown content.'
' Please set it to the full path to {}'
' (including filename) instead. ******'.format(CSDK_ENV_NAME, basename))
class PostBuildCommand(build):
__base = build
def finalize_options(self):
#pylint:disable=access-member-before-definition
has_build_lib = self.build_lib is not None
self.__base.finalize_options(self)
if not has_build_lib:
#pylint:disable=attribute-defined-outside-init
self.build_lib = self.build_platlib
class PostBuildExtCommand(build_ext):
__base = build_ext
def finalize_options(self):
self.__base.finalize_options(self)
def get_dll_output_path(self):
targetdir = path.join(
self.build_lib,
'oneagent',
'_impl',
'native')
return path.join(targetdir, get_dll_info(self.plat_name)['dll_name']())
def get_outputs(self):
return self.__base.get_outputs(self) + [self.get_dll_output_path()]
def get_inputs(self):
extra_inputs = []
try:
dll_input = get_dll_input_path(self.plat_name)
except ValueError:
pass
else:
if dll_input:
extra_inputs.append(dll_input)
return self.__base.get_inputs(self) + extra_inputs
def run(self):
src = get_dll_input_path(self.plat_name)
dst = self.get_dll_output_path()
self.__base.run(self)
self.mkpath(path.dirname(dst))
if src:
self.copy_file(src, dst)
def copy_extensions_to_source(self):
self.__base.copy_extensions_to_source(self)
build_py = self.get_finalized_command('build_py')
src_filename = get_dll_input_path(self.plat_name)
package = 'oneagent._impl.native'
package_dir = build_py.get_package_dir(package)
if src_filename:
dest_filename = path.join(package_dir, path.basename(src_filename))
self.copy_file(src_filename, dest_filename)
class PostInstallCommand(install):
def finalize_options(self):
#pylint:disable=access-member-before-definition
if self.install_lib is None:
#pylint:disable=attribute-defined-outside-init
self.install_lib = self.install_platlib
return install.finalize_options(self)
class BinaryDistribution(Distribution):
def has_ext_modules(self): #pylint:disable=no-self-use
return True
cmdclss = {
'build': PostBuildCommand,
'build_ext': PostBuildExtCommand,
'install': PostInstallCommand,
}
if bdist_wheel is not None:
cmdclss['bdist_wheel'] = BdistWheel
def main():
setup(
packages=find_packages('src'),
package_dir={'': 'src'},
include_package_data=True,
zip_safe=True,
python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*',
cmdclass=cmdclss,
name='oneagent-sdk',
version=__version__,
distclass=BinaryDistribution,
description='Dynatrace OneAgent SDK for Python',
long_description=long_description,
long_description_content_type='text/markdown',
url='https://github.com/Dynatrace/OneAgent-SDK-for-Python',
download_url='https://pypi.org/project/oneagent-sdk/',
maintainer='Dynatrace LLC',
maintainer_email='dynatrace.oneagent.sdk@dynatrace.com',
license='Apache License 2.0',
classifiers=[
'Development Status :: 5 - Production/Stable',
'Intended Audience :: Developers',
'License :: OSI Approved',
'License :: OSI Approved :: Apache Software License', # 2.0
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.7',
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.4',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Programming Language :: Python :: Implementation :: CPython',
#'Programming Language :: Python :: Implementation :: PyPy',
'Operating System :: POSIX :: Linux',
'Operating System :: Microsoft :: Windows',
'Topic :: System :: Monitoring'
],
project_urls={
'Issue Tracker':
'https://github.com/Dynatrace/OneAgent-SDK-for-Python/issues',
'Documentation':
'https://dynatrace.github.io/OneAgent-SDK-for-Python/',
})
if __name__ == '__main__':
main()