-
Notifications
You must be signed in to change notification settings - Fork 481
/
setup.py
executable file
·345 lines (286 loc) · 12.1 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
#!/usr/bin/env python3
import sys
import traceback
# quick version check
if sys.version_info[0] == 2 or (sys.version_info[0] == 3 and sys.version_info[1] < 4):
print("Sorry, the Overviewer requires at least Python 3.4 to run.")
sys.exit(1)
from distutils.core import setup
from distutils.extension import Extension
from distutils.command.build import build
from distutils.command.clean import clean
from distutils.command.build_ext import build_ext
from distutils.command.sdist import sdist
from distutils.cmd import Command
from distutils.dir_util import remove_tree
from distutils.sysconfig import get_python_inc
from distutils import log
import os, os.path
import glob
import platform
import time
import overviewer_core.util as util
import numpy
try:
import py2exe
except ImportError:
py2exe = None
try:
import py2app
from setuptools.extension import Extension
except ImportError:
py2app = None
# make sure our current working directory is the same directory
# setup.py is in
curdir = os.path.split(sys.argv[0])[0]
if curdir:
os.chdir(curdir)
# now, setup the keyword arguments for setup
# (because we don't know until runtime if py2exe/py2app is available)
setup_kwargs = {}
setup_kwargs['ext_modules'] = []
setup_kwargs['cmdclass'] = {}
setup_kwargs['options'] = {}
#
# metadata
#
# Utility function to read the README file.
# Used for the long_description. It's nice, because now 1) we have a top level
# README file and 2) it's easier to type in the README file than to put a raw
# string in below ...
def read(fname):
return open(fname).read()
setup_kwargs['name'] = 'Minecraft-Overviewer'
setup_kwargs['version'] = util.findGitVersion()
setup_kwargs['description'] = 'Generates large resolution images of a Minecraft map.'
setup_kwargs['url'] = 'http://overviewer.org/'
setup_kwargs['author'] = 'Andrew Brown'
setup_kwargs['author_email'] = 'brownan@gmail.com'
setup_kwargs['license'] = 'GNU General Public License v3'
setup_kwargs['long_description'] = read('README.rst')
# top-level files that should be included as documentation
doc_files = ['COPYING.txt', 'README.rst', 'CONTRIBUTORS.rst', 'sample_config.py']
# helper to create a 'data_files'-type sequence recursively for a given dir
def recursive_data_files(src, dest=None):
if dest is None:
dest = src
ret = []
for dirpath, dirnames, filenames in os.walk(src):
current_dest = os.path.relpath(dirpath, src)
if current_dest == '.':
current_dest = dest
else:
current_dest = os.path.join(dest, current_dest)
current_sources = map(lambda p: os.path.join(dirpath, p), filenames)
ret.append((current_dest, current_sources))
return ret
# helper to create a 'package_data'-type sequence recursively for a given dir
def recursive_package_data(src, package_dir='overviewer_core'):
full_src = os.path.join(package_dir, src)
ret = []
for dirpath, dirnames, filenames in os.walk(full_src, topdown=False):
current_path = os.path.relpath(dirpath, package_dir)
for filename in filenames:
ret.append(os.path.join(current_path, filename))
return ret
# Finds the system-wide path from within a venv.
# Taken from https://github.com/pyinstaller/pyinstaller/blob/master/PyInstaller/hooks/pre_find_module_path/hook-distutils.py
def find_system_module_path():
# opcode is not a virtualenv module, so we can use it to find the stdlib. Technique taken from virtualenv's
# "distutils" package detection at
# https://github.com/pypa/virtualenv/blob/16.3.0/virtualenv_embedded/distutils-init.py#L5
import opcode
system_module_path = os.path.normpath(os.path.dirname(opcode.__file__))
return system_module_path
#
# py2exe options
#
if py2exe is not None:
setup_kwargs['comments'] = "http://overviewer.org"
# py2exe likes a very particular type of version number:
setup_kwargs['version'] = util.findGitVersion().replace("-",".")
setup_kwargs['console'] = ['overviewer.py', 'contribManager.py']
setup_kwargs['data_files'] = [('', doc_files)]
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/textures', 'textures')
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/web_assets', 'web_assets')
setup_kwargs['data_files'] += recursive_data_files('overviewer_core/data/js_src', 'js_src')
setup_kwargs['data_files'] += recursive_data_files('contrib', 'contrib')
setup_kwargs['zipfile'] = None
if platform.system() == 'Windows' and '64bit' in platform.architecture():
b = 3
else:
b = 1
setup_kwargs['options']['py2exe'] = {'bundle_files' : b, 'excludes': 'Tkinter', 'includes':
['fileinput', 'overviewer_core.items', 'overviewer_core.aux_files.genPOI']}
#
# py2app options
#
if py2app is not None:
setup_kwargs['app'] = ['overviewer.py']
setup_kwargs['options']['py2app'] = {'argv_emulation' : False}
setup_kwargs['setup_requires'] = ['py2app']
#
# script, package, and data
#
setup_kwargs['packages'] = ['overviewer_core', 'overviewer_core/aux_files']
setup_kwargs['scripts'] = ['overviewer.py']
setup_kwargs['package_data'] = {'overviewer_core': recursive_package_data('data/textures') + recursive_package_data('data/web_assets') + recursive_package_data('data/js_src')}
if py2exe is None:
setup_kwargs['data_files'] = [('share/doc/minecraft-overviewer', doc_files)]
#
# c_overviewer extension
#
# Third-party modules - we depend on numpy for everything
# Obtain the numpy include directory. This logic works across numpy versions.
try:
numpy_include = numpy.get_include()
except AttributeError:
numpy_include = numpy.get_numpy_include()
try:
pil_include = os.environ['PIL_INCLUDE_DIR'].split(os.pathsep)
except Exception:
pil_include = [ os.path.join(get_python_inc(plat_specific=1), 'Imaging') ]
if not os.path.exists(pil_include[0]):
pil_include = [ ]
# used to figure out what files to compile
# auto-created from files in primitives/, but we need the raw names so
# we can use them later.
primitives = []
for name in glob.glob("overviewer_core/src/primitives/*.c"):
name = os.path.split(name)[-1]
name = os.path.splitext(name)[0]
primitives.append(name)
c_overviewer_files = ['main.c', 'composite.c', 'iterate.c', 'endian.c', 'rendermodes.c', 'block_class.c']
c_overviewer_files += ['primitives/%s.c' % (mode) for mode in primitives]
c_overviewer_files += ['Draw.c']
c_overviewer_includes = ['overviewer.h', 'rendermodes.h']
c_overviewer_files = ['overviewer_core/src/' + s for s in c_overviewer_files]
c_overviewer_includes = ['overviewer_core/src/' + s for s in c_overviewer_includes]
# really ugly hack for our scuffed CI, remove this once we move
# to something else. The problem is that virtualenv somehow
# now overrides the base_prefix (which it shouldn't do) which
# makes distutils unable to find our Python library
python_lib_dirs = None
if platform.system() == 'Windows':
ci_python_dir = os.path.split(find_system_module_path())[0]
python_lib_dirs = [os.path.join(ci_python_dir, "Libs")]
setup_kwargs['ext_modules'].append(Extension(
'overviewer_core.c_overviewer',
c_overviewer_files,
include_dirs=['.', numpy_include] + pil_include,
library_dirs=python_lib_dirs,
depends=c_overviewer_includes,
extra_link_args=[]
))
# tell build_ext to build the extension in-place
# (NOT in build/)
setup_kwargs['options']['build_ext'] = {'inplace' : 1}
# custom clean command to remove in-place extension
# and the version file, primitives header
class CustomClean(clean):
def run(self):
# do the normal cleanup
clean.run(self)
# try to remove '_composite.{so,pyd,...}' extension,
# regardless of the current system's extension name convention
build_ext = self.get_finalized_command('build_ext')
ext_fname = build_ext.get_ext_filename('overviewer_core.c_overviewer')
versionpath = os.path.join("overviewer_core", "overviewer_version.py")
primspath = os.path.join("overviewer_core", "src", "primitives.h")
for fname in [ext_fname, primspath]:
if os.path.exists(fname):
try:
log.info("removing '%s'", fname)
if not self.dry_run:
os.remove(fname)
except OSError:
log.warning("'%s' could not be cleaned -- permission denied",
fname)
else:
log.debug("'%s' does not exist -- can't clean it",
fname)
# now try to purge all *.pyc files
for root, dirs, files in os.walk(os.path.join(os.path.dirname(__file__), ".")):
for f in files:
if f.endswith(".pyc"):
if self.dry_run:
log.warning("Would remove %s", os.path.join(root,f))
else:
os.remove(os.path.join(root, f))
def generate_version_py():
try:
outstr = ""
outstr += "VERSION=%r\n" % util.findGitVersion()
outstr += "HASH=%r\n" % util.findGitHash()
outstr += "BUILD_DATE=%r\n" % time.asctime()
outstr += "BUILD_PLATFORM=%r\n" % platform.processor()
outstr += "BUILD_OS=%r\n" % platform.platform()
f = open("overviewer_core/overviewer_version.py", "w")
f.write(outstr)
f.close()
except Exception:
print("WARNING: failed to build overviewer_version file")
def generate_primitives_h():
global primitives
prims = [p.lower().replace('-', '_') for p in primitives]
outstr = "/* this file is auto-generated by setup.py */\n"
for p in prims:
outstr += "extern RenderPrimitiveInterface primitive_{0};\n".format(p)
outstr += "static RenderPrimitiveInterface *render_primitives[] = {\n"
for p in prims:
outstr += " &primitive_{0},\n".format(p)
outstr += " NULL\n"
outstr += "};\n"
with open("overviewer_core/src/primitives.h", "w") as f:
f.write(outstr)
class CustomSDist(sdist):
def run(self):
# generate the version file
generate_version_py()
generate_primitives_h()
sdist.run(self)
class CustomBuild(build):
def run(self):
# generate the version file
try:
generate_version_py()
generate_primitives_h()
build.run(self)
print("\nBuild Complete")
except Exception:
traceback.print_exc(limit=1)
print("\nFailed to build Overviewer!")
print("Please review the errors printed above and the build instructions")
print("at <http://docs.overviewer.org/en/latest/building/>. If you are")
print("still having build problems, file an incident on the github tracker")
print("or find us in IRC.")
sys.exit(1)
class CustomBuildExt(build_ext):
def build_extensions(self):
c = self.compiler.compiler_type
if c == "msvc":
# customize the build options for this compilier
for e in self.extensions:
e.extra_link_args.append("/MANIFEST")
e.extra_link_args.append("/DWINVER=0x060")
e.extra_link_args.append("/D_WIN32_WINNT=0x060")
if c == "unix":
# customize the build options for this compilier
for e in self.extensions:
e.extra_compile_args.append("-Wno-unused-variable") # quell some annoying warnings
e.extra_compile_args.append("-Wno-unused-function") # quell some annoying warnings
e.extra_compile_args.append("-Wdeclaration-after-statement")
e.extra_compile_args.append("-Werror=declaration-after-statement")
e.extra_compile_args.append("-O3")
e.extra_compile_args.append("-std=gnu99")
# build in place, and in the build/ tree
self.inplace = False
build_ext.build_extensions(self)
self.inplace = True
build_ext.build_extensions(self)
setup_kwargs['cmdclass']['clean'] = CustomClean
setup_kwargs['cmdclass']['sdist'] = CustomSDist
setup_kwargs['cmdclass']['build'] = CustomBuild
setup_kwargs['cmdclass']['build_ext'] = CustomBuildExt
###
setup(**setup_kwargs)