/[thuban]/branches/WIP-pyshapelib-bramz/setup.py
ViewVC logotype

Contents of /branches/WIP-pyshapelib-bramz/setup.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1614 - (show annotations)
Tue Aug 19 21:56:20 2003 UTC (21 years, 6 months ago) by jan
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 41410 byte(s)
renamed extensions to libraries.

1 # Copyright (c) 2001, 2002, 2003 by Intevation GmbH
2 # Authors:
3 # Bernhard Herzog <[email protected]>
4 #
5 # This program is free software under the GPL (>=v2)
6 # Read the file COPYING coming with Thuban for details.
7
8 """Distutils setup script for Thuban."""
9
10 __version__ = "$Revision$"
11
12 # Configuration:
13 #
14 # depending on your platform you may have to configure some variables by
15 # hand below.
16 #
17
18 import os
19 from types import TupleType
20 import glob
21 from distutils.core import setup, Extension, Command
22 from distutils.command.install import install, INSTALL_SCHEMES, subst_vars
23 from distutils.command.build_py import build_py
24 from distutils.command.bdist_rpm import bdist_rpm
25 from distutils.command.build_ext import build_ext
26 from distutils.file_util import write_file
27 from distutils.filelist import FileList
28 from distutils.util import convert_path, change_root
29
30 from distutils import archive_util, dir_util
31 import distutils
32
33 from string import split
34 import string
35
36 # config script parameter list indices
37 CS_DEFS, CS_INCDIRS, CS_LIBDIRS, CS_LIBS, CS_NUM_PARAMS = range(5)
38
39 # support for gdal is on by default, but under posix we try to
40 # detect it anyway. Set this to False to disable GDAL.
41 include_gdal = True
42
43 if os.name == "posix":
44 ###################################################################
45 # Posix configuration. Adapt this if you're running some kind of
46 # Unix like system.
47
48 # Directories where Proj4 is installed
49 proj4_prefix = "/usr/local/"
50 proj4_incdir = os.path.join(proj4_prefix, "include")
51 proj4_libdir = os.path.join(proj4_prefix, "lib")
52 proj4_lib = "proj"
53
54
55 # You shouldn't have to modify anything below here
56 ###################################################################
57
58 # The installation prefix (similar to autoconf's --prefix). This is
59 # only the default value, you can override it on the command line
60 # with the install command's --prefix option.
61 #
62 # Note that there's a separate prefix option for the bdist_rpm
63 # command completely independent of this one.
64 prefix = "/usr/local/"
65
66 # Whether to create the thubaninit module. You can override this
67 # value on the commandline with the --create-init-module to the
68 # install command.
69 create_init_module = 1
70
71 # On POSIX-systems we run wxgtk-config to determine the C++-compiler
72 # flags
73 wx_config_script = "wx-config"
74 # These lists will be filled automatically below
75 wx_cs_params = [[] for i in range(CS_NUM_PARAMS)]
76
77 gdal_config_script = "gdal-config"
78 gdal_cs_params = [[] for i in range(CS_NUM_PARAMS)]
79
80 elif os.name == "nt":
81 #################################################################
82 # Windows configuration.
83 #
84
85 # Directories where Proj4 is installed
86 proj4_prefix = r"D:\cygwin\home\user\proj-4.4.7\src"
87 proj4_incdir = proj4_prefix
88 proj4_libdir = proj4_prefix
89 proj4_lib = "proj_i"
90
91 # Define include and lib directories for wxWindows and
92 wx_prefix = r"C:\wx-versions\wxPython-2.4.0.6"
93 wx_inc = [os.path.join(wx_prefix, 'lib', 'mswdllh'),
94 os.path.join(wx_prefix, "include")]
95 wx_lib = [os.path.join(wx_prefix, "lib")]
96
97 # Define include and lib directories for GDAL
98 gdal_prefix = r"D:\cygwin\home\user\build\gdal-1.1.8"
99 gdal_inc = [os.path.join(gdal_prefix, 'alg'),
100 os.path.join(gdal_prefix, 'ogr'),
101 os.path.join(gdal_prefix, 'port'),
102 os.path.join(gdal_prefix, 'core')]
103 gdal_lib = [gdal_prefix]
104
105 #
106 # Unless you use a wxPython version other than 2.4.0, you probably
107 # shouldn't have to modify anything below here
108 ##################################################################
109
110 # Installation prefix. Just install relative to current directory by
111 # default. This is only the default value, you can override it on
112 # the command line with the install command's --prefix option
113 prefix = r"install"
114
115 # Whether to create the thubaninit module. You can override this
116 # value on the commandline with the --create-init-module to the
117 # install command. By default we don't create it under NT because we
118 # most often run install only as part of bdist_inno where we can't
119 # really create because it needs information only known at install
120 # time.
121 create_init_module = 0
122
123 # There doesn't seem to be an easy way to get at the wx compiler
124 # flags, so we define them here. These flags work for us with
125 # wxPython 2.3.1. They may have to be modified for other versions.
126
127 # there's no config script.
128 wx_config_script = ""
129
130 wx_cs_params = [[] for i in range(CS_NUM_PARAMS)]
131
132 # the values of wx_defs and wx_libs. copied from the wxPython
133 # setup.py
134 wx_cs_params[CS_DEFS] = \
135 [ ('WIN32', None), # Some of these are no longer
136 ('__WIN32__', None), # necessary. Anybody know which?
137 ('_WINDOWS', None),
138 ('__WINDOWS__', None),
139 ('WINVER', '0x0400'),
140 ('__WIN95__', None),
141 ('STRICT', None),
142
143 ('__WXMSW__', None),
144 ('WXUSINGDLL', '1'),
145
146 ('SWIG_GLOBAL', None),
147 ('HAVE_CONFIG_H', None),
148 ('WXP_USE_THREAD', '1'),
149 ]
150
151 wx_cs_params[CS_INCDIRS] = wx_inc
152 wx_cs_params[CS_LIBDIRS] = wx_lib
153 wx_cs_params[CS_LIBS] = ["wxmsw24h"] \
154 + ['kernel32', 'user32', 'gdi32', 'comdlg32',
155 'winspool', 'winmm', 'shell32', 'oldnames',
156 'comctl32', 'ctl3d32', 'odbc32', 'ole32', 'oleaut32',
157 'uuid', 'rpcrt4', 'advapi32', 'wsock32']
158
159 gdal_config_script = ""
160 gdal_cs_params = [[] for i in range(CS_NUM_PARAMS)]
161
162 gdal_cs_params[CS_INCDIRS] = gdal_inc
163 gdal_cs_params[CS_LIBDIRS] = gdal_lib
164 gdal_cs_params[CS_LIBS] = ["gdal_i"]
165
166 else:
167 raise RuntimeError("Unsupported platform " + os.name)
168
169
170 ######################################################################
171 #
172 # There's nothing beyond this point that has to be modified for a
173 # normal installation
174 #
175 ######################################################################
176
177
178 #
179 # Functions to determine wxWindows config on POSIX systems
180 #
181
182 def run_script(cmdline):
183 """Run command and return its stdout or none in case of errors"""
184 pipe = os.popen(cmdline)
185 result = pipe.read()
186 if pipe.close() is not None:
187 print '"' + cmdline + '"', 'failed'
188 return None
189 return result
190
191
192 def run_cs_script(command, store):
193 # first, determine the C++ preprocessor flags Use --cflags here
194 # because it seems that older version don't have --cxxflags and
195 # newer ones return the same result for both
196 flags = run_script(command + ' --cflags ')
197 if flags is None:
198 return False
199 for flag in split(flags):
200 start = flag[:2]
201 value = flag[2:]
202 if start == "-I":
203 store[CS_INCDIRS].append(value)
204 elif start == "-D":
205 store[CS_DEFS].append((value, None))
206
207 # determine the library flags
208 flags = run_script(command + ' --libs')
209 if flags is None:
210 return False
211 for flag in split(flags):
212 start = flag[:2]
213 value = flag[2:]
214 if start == "-L":
215 store[CS_LIBDIRS].append(value)
216 elif start == "-l":
217 store[CS_LIBS].append(value)
218
219 return True
220
221 if wx_config_script:
222 # if there's a wx config script, run it to determine the configuration
223 run_cs_script(wx_config_script, wx_cs_params)
224
225 if gdal_config_script:
226 # if there's a gdal config script, run it to determine the configuration
227 include_gdal = include_gdal \
228 and run_cs_script(gdal_config_script, gdal_cs_params)
229
230 #
231 # Define some extension and python modules
232 #
233 # The C-extension names are prefixed with "Lib." so they get put into
234 # the Lib/ subdirectory. Lib/ is not really a package but distutils
235 # doesn't care
236
237 # subdirectory containing the distutil extensions
238 ext_dir = "libraries"
239
240 # subdirectory with some shapelib files
241 shp_dir = ext_dir + "/shapelib"
242
243 # lists to fill with the module descriptions
244 extensions = []
245 py_modules = []
246
247
248 #
249 # Thuban specific modules
250 #
251
252 extensions.append(Extension("Lib.wxproj",
253 [ext_dir + "/thuban/wxproj.cpp"],
254 include_dirs = ([shp_dir, proj4_incdir,
255 ext_dir + "/pyshapelib/"]
256 + wx_cs_params[CS_INCDIRS]),
257 define_macros = wx_cs_params[CS_DEFS],
258 library_dirs = [proj4_libdir] +
259 wx_cs_params[CS_LIBDIRS],
260 libraries = [proj4_lib] + wx_cs_params[CS_LIBS]))
261
262
263 #
264 # shapelib wrappers are also distributed with thuban
265 #
266
267 extensions.append(Extension("Lib.shapelibc",
268 [ext_dir + "/pyshapelib/shapelib_wrap.c",
269 shp_dir + "/shpopen.c",
270 shp_dir + "/shptree.c"],
271 include_dirs = [shp_dir]))
272 extensions.append(Extension("Lib.shptree",
273 [ext_dir + "/pyshapelib/shptreemodule.c"],
274 include_dirs = [shp_dir]))
275 extensions.append(Extension("Lib.dbflibc",
276 [ext_dir + "/pyshapelib/dbflib_wrap.c",
277 shp_dir + "/dbfopen.c"],
278 include_dirs = [shp_dir]))
279 for name in ("shapelib", "dbflib"):
280 py_modules.append(ext_dir + "/pyshapelib/" + name)
281
282 #
283 # PROJ4 bindings are also distributed with thuban
284 #
285 extensions.append(Extension("Lib.Projectionc",
286 [ext_dir + "/pyprojection/Projection_wrap.c"],
287 include_dirs = [proj4_incdir],
288 library_dirs = [proj4_libdir],
289 libraries = [proj4_lib]))
290 py_modules.append(ext_dir + "/pyprojection/Projection")
291
292
293 #
294 # Data files
295 #
296
297 data_files = []
298
299 # Resources
300 # ("Resources/Locale", "Resources/Locale/*/LC_MESSAGES/*.mo")
301 for d, pattern in [("Resources/Bitmaps", "Resources/Bitmaps/*.xpm"),
302 ("Resources/Projections", "Resources/Projections/*.proj"),
303 ("Resources/XML", "Resources/XML/*.dtd")]:
304 data_files.append((d, glob.glob(pattern)))
305
306 #
307 # Command definitions
308 #
309 # So far distutils are only meant to distribute python extensions, not
310 # complete applications, so we have to redefine a few commands
311 #
312
313
314 # Much of the data_dist command is directly copied from the distutils'
315 # sdist command
316 class data_dist(Command):
317
318 description = "create a data distribution (tarball, zip file, etc.)"
319
320 user_options = [
321 ('formats=', None,
322 "formats for source distribution (comma-separated list)"),
323 ('keep-temp', 'k',
324 "keep the distribution tree around after creating " +
325 "archive file(s)"),
326 ('dist-dir=', 'd',
327 "directory to put the source distribution archive(s) in "
328 "[default: dist]"),
329 ]
330
331 boolean_options = ['keep-temp']
332
333 def initialize_options (self):
334 self.formats = None
335 self.keep_temp = 0
336 self.dist_dir = None
337
338 def finalize_options (self):
339 self.ensure_string_list('formats')
340 if self.formats is None:
341 self.formats = ["zip"]
342 bad_format = archive_util.check_archive_formats(self.formats)
343 if bad_format:
344 raise DistutilsOptionError, \
345 "unknown archive format '%s'" % bad_format
346
347 if self.dist_dir is None:
348 self.dist_dir = "dist"
349
350
351 def run(self):
352 # 'filelist' contains the list of files that will make up the
353 # manifest
354 self.filelist = FileList()
355
356 # Do whatever it takes to get the list of files to process.
357 # File list is accumulated in 'self.filelist'.
358 self.get_file_list()
359
360 # Otherwise, go ahead and create the source distribution tarball,
361 # or zipfile, or whatever.
362 self.make_distribution()
363
364 def get_file_list(self):
365 """Figure out the list of files to include in the data
366 distribution, and put it in 'self.filelist'.
367 """
368 self.filelist.findall("Data")
369 self.filelist.include_pattern("*", anchor = 0)
370 self.filelist.exclude_pattern(r'/(RCS|CVS)/.*', is_regex=1)
371 self.filelist.sort()
372 self.filelist.remove_duplicates()
373
374 def make_release_tree(self, base_dir, files):
375 """Create the directory tree that will become the source
376 distribution archive. All directories implied by the filenames in
377 'files' are created under 'base_dir', and then we hard link or copy
378 (if hard linking is unavailable) those files into place.
379 Essentially, this duplicates the developer's source tree, but in a
380 directory named after the distribution, containing only the files
381 to be distributed.
382 """
383 # Create all the directories under 'base_dir' necessary to
384 # put 'files' there; the 'mkpath()' is just so we don't die
385 # if the manifest happens to be empty.
386 self.mkpath(base_dir)
387 dir_util.create_tree(base_dir, files,
388 verbose=self.verbose, dry_run=self.dry_run)
389
390 # And walk over the list of files, either making a hard link (if
391 # os.link exists) to each one that doesn't already exist in its
392 # corresponding location under 'base_dir', or copying each file
393 # that's out-of-date in 'base_dir'. (Usually, all files will be
394 # out-of-date, because by default we blow away 'base_dir' when
395 # we're done making the distribution archives.)
396
397 if hasattr(os, 'link'): # can make hard links on this system
398 link = 'hard'
399 msg = "making hard links in %s..." % base_dir
400 else: # nope, have to copy
401 link = None
402 msg = "copying files to %s..." % base_dir
403
404 if not files:
405 self.warn("no files to distribute -- empty manifest?")
406 else:
407 self.announce(msg)
408 for file in files:
409 if not os.path.isfile(file):
410 self.warn("'%s' not a regular file -- skipping" % file)
411 else:
412 dest = os.path.join(base_dir, file)
413 self.copy_file(file, dest, link=link)
414
415
416 def make_distribution (self):
417 """Create the source distribution(s). First, we create the release
418 tree with 'make_release_tree()'; then, we create all required
419 archive files (according to 'self.formats') from the release tree.
420 Finally, we clean up by blowing away the release tree (unless
421 'self.keep_temp' is true). The list of archive files created is
422 stored so it can be retrieved later by 'get_archive_files()'.
423 """
424 # Don't warn about missing meta-data here -- should be (and is!)
425 # done elsewhere.
426 base_dir = "Thuban-data-" + self.distribution.get_version()
427 base_name = os.path.join(self.dist_dir, base_dir)
428
429 self.make_release_tree(base_dir, self.filelist.files)
430 archive_files = [] # remember names of files we create
431 for fmt in self.formats:
432 file = self.make_archive(base_name, fmt, base_dir=base_dir)
433 archive_files.append(file)
434
435 self.archive_files = archive_files
436
437 if not self.keep_temp:
438 dir_util.remove_tree(base_dir, self.verbose, self.dry_run)
439
440
441
442 class InstallLocal(Command):
443
444 """
445 A new install command to just link (or copy, on non-POSIX systems)
446 the extension modules to the top directory so that Thuban can be run
447 directly from the source dir.
448 """
449
450 description =\
451 "Create some symlinks so you can run thuban from the source directory"
452
453 user_options = [
454 ('skip-build', None, "skip the build steps"),
455 ('create-init-module', None,
456 "Create the thubaninit.py module to ease use of Thuban as a library"),
457 ('dont-create-init-module', None,
458 "Do not create the thubaninit.py module"),
459 ]
460
461 boolean_options = ["create-init-module"]
462 negative_opt = {'dont-create-init-module' : 'create-init-module'}
463
464
465 def initialize_options (self):
466 self.extensions = None
467 self.build_dir = None
468 self.skip_build = None
469 self.create_init_module = None
470
471 def finalize_options (self):
472 self.set_undefined_options("install",
473 ("build_lib", "build_dir"),
474 ('skip_build', 'skip_build'))
475 self.extensions = self.distribution.ext_modules
476 if self.create_init_module is None:
477 # by default we create the init module
478 self.create_init_module = 1
479
480 def run(self):
481 # Make sure we have built everything we need first
482 self.build()
483
484 # now do the work. Simply link or copy the Lib dir
485 libdir = os.path.join(self.build_dir, "Lib")
486 if os.name == "posix":
487 # on posix, just link the Lib dir
488 self.link_dir(libdir, "Lib")
489 else:
490 self.copy_tree(libdir, "Lib")
491
492 # create the init module if desired
493 if self.create_init_module:
494 # create the init module
495 initfilename = "thubaninit.py"
496 contents = thubaninit_contents("")
497 self.execute(write_file, (initfilename, contents),
498 "Create %s" % initfilename)
499
500 def link_dir(self, src, dest):
501 """Create a symbolic link dest pointing to src"""
502 if self.verbose:
503 self.announce("symlinking %s -> %s" % (src, dest))
504 if self.dry_run:
505 return
506
507 if not (os.path.exists(dest) and os.path.samefile(src, dest)):
508 os.symlink(src, dest)
509
510 def build (self):
511 if not self.skip_build:
512 if self.distribution.has_pure_modules():
513 self.run_command('build_py')
514 if self.distribution.has_ext_modules():
515 self.run_command('build_ext')
516
517
518
519 class thuban_build_py(build_py):
520
521 """
522 A new build_py that can deal with both packages and modules in one
523 distribution.
524 """
525
526 # FIXME: When Thuban can rely on Python 2.3 as the oldest supported
527 # Python release we don't need to override the run and
528 # find_all_modules methods anymore. distutils will allow both python
529 # modules and packages starting with 2.3.
530
531 def run(self):
532 """The same the as the original in build_py revision 1.33 except
533 that this allows both packages and modules to be in one
534 distribution
535 """
536 if not self.py_modules and not self.packages:
537 return
538
539 # Now we're down to two cases: 'py_modules' only and 'packages' only.
540 if self.py_modules:
541 self.build_modules()
542 if self.packages:
543 self.build_packages()
544
545 self.byte_compile(self.get_outputs(include_bytecode=0))
546
547 def find_modules (self):
548 """Thuban specific version of build_py.find_modules. Unlike the
549 original version, we assume that the modules in self.py_modules
550 can contain directories and are all to be placed into the same
551 subdirectory, Lib, in the build directory. This is achieved by
552 returning the modules as a list (package, module, filename)
553 where package is 'Lib', module is the basename of the module name
554 and filename is the filename relative to the package root.
555 """
556 modules = []
557 for module in self.py_modules:
558 module_base = os.path.basename(module)
559 module_file = module + ".py"
560 if not self.check_module(module, module_file):
561 continue
562
563 modules.append(("Lib", module_base, module_file))
564 return modules
565
566 def find_all_modules (self):
567 # same as find_all_modules of the original build_py command
568 # (rev. 1.33) but handle installations with both modules and
569 # packages. Needed here so tha the get_outputs works correctly
570 modules = []
571 if self.py_modules:
572 modules.extend(self.find_modules())
573 if self.packages:
574 for package in self.packages:
575 package_dir = self.get_package_dir(package)
576 m = self.find_package_modules(package, package_dir)
577 modules.extend(m)
578
579 return modules
580
581
582 thubaninit_contents_start = """
583 # This module was automatically generated by Thuban's install script
584 '''Import this module once per program (best place is probably the file
585 that ends up as your __main__ module) to be able to import Thuban
586 afterwards.
587
588 Usage:
589
590 import thubaninit
591 import Thuban
592 '''
593 import sys, os
594 """
595
596 thubaninit_contents_thubaninitdir = """
597 sys.path.insert(0, %(thubandir)s)
598 """
599 thubaninit_contents_otherdirs = """
600 # Put the Lib dir into the path. The Lib dir contains some extra Python
601 # modules
602 import Thuban
603 thubandir = os.path.join(Thuban.__path__[0], '..')
604 dir = os.path.join(thubandir, "Lib")
605 if os.path.isdir(dir):
606 sys.path.insert(0, dir)
607 """
608
609 def thubaninit_contents(thubandir):
610 """Return the contents of the the thubaninit file as a list of lines.
611
612 The parameter thubandir is the parent directory where the Thuban/
613 package or the empty string if the thubaninit file itself will be
614 located in that direcory as well.
615 """
616 contents = thubaninit_contents_start
617 if thubandir:
618 thubandir = repr(thubandir)
619 contents += thubaninit_contents_thubaninitdir % locals()
620 contents += thubaninit_contents_otherdirs
621 return contents.split("\n")
622
623
624 class ThubanInstall(install):
625
626 """
627 Thuban specific install command.
628
629 Extend the standard install command to symlink the installed script
630 to $prefix/bin/
631 """
632
633 user_options = install.user_options[:]
634 user_options.extend([("do-symlink", None,
635 "Create a symlink to the script in <prefix>/bin."
636 "(default on posix systems and only relevant there)"),
637
638 ("extra-files", None,
639 "List of filenames or (src, dest) pairs describing"
640 " extra files to install "
641 "(can only be set from within setup.py"),
642
643 ("create-init-module=", None,
644 "If true, create a module in the site-packages"
645 " directory that tweaks sys.path to let you easily"
646 " import thuban modules from outside of thuban."),
647 ("init-module-dir=", None,
648 "Directory in which to create the init module."
649 " Defaults to Python's site-packages directory."),
650 ])
651
652 boolean_options = install.boolean_options[:]
653 boolean_options.append("do-symlink")
654 boolean_options.append("create-init-module")
655
656 def initialize_options(self):
657 self.do_symlink = None
658 self.extra_files = []
659
660 # initialize the create_init_module flag from the global
661 # determined at runtime
662 self.create_init_module = create_init_module
663 self.init_module_dir = None
664 install.initialize_options(self)
665
666 def finalize_options(self):
667 if self.do_symlink is None:
668 if os.name == "posix":
669 self.do_symlink = 1
670 else:
671 self.do_symlink = 0
672 install.finalize_options(self)
673 self.expand_with_pure_python_dirs(["init_module_dir"])
674
675 def expand_with_pure_python_dirs(self, attrs):
676 """Expand the attributes with default values of base and platbase"""
677 # it seems that the values for "prefix" and "exec_prefix" in
678 # self.config_vars are the corresponding values used by the
679 # python interpreter, so we just assign these to "base" and
680 # "platbase".
681 config_vars = self.config_vars.copy()
682 config_vars["base"] = self.config_vars["prefix"]
683 config_vars["platbase"] = self.config_vars["exec_prefix"]
684 for attr in attrs:
685 val = getattr(self, attr)
686 if val is not None:
687 if os.name == 'posix':
688 val = os.path.expanduser(val)
689 val = subst_vars(val, config_vars)
690 setattr(self, attr, val)
691
692 def select_scheme(self, scheme):
693 """Extend the inherited method to set init_module_dir"""
694 install.select_scheme(self, scheme)
695 # only set init_module_dir if it wasn't set by the user
696 if self.init_module_dir is None:
697 self.init_module_dir = INSTALL_SCHEMES[scheme]['purelib']
698
699 def convert_paths(self, *args):
700 """Extend the inherited method so that we can remember some filename
701 """
702 # remember the installation directory before its root gets
703 # changed
704 self.install_lib_orig = self.install_lib
705 apply(install.convert_paths, (self,) + args)
706
707 def run(self):
708 install.run(self)
709 for item in self.extra_files:
710 if type(item) == TupleType:
711 src, dest = item
712 else:
713 src = dest = item
714 self.copy_file(convert_path(src),
715 os.path.join(self.root, convert_path(dest)))
716
717 if os.name == "posix" and self.do_symlink:
718 install_scripts = self.install_scripts
719 if self.root:
720 install_scripts = install_scripts[len(self.root):]
721 scriptfile = os.path.join(install_scripts, "thuban.py")
722 bindir = os.path.join(self.prefix, "bin")
723 if self.root:
724 bindir = change_root(self.root, bindir)
725 binfile = os.path.join(bindir, "thuban")
726 self.mkpath(bindir)
727 self.link_file(scriptfile, binfile)
728
729 if self.create_init_module:
730 # create the init module
731 initfilename = self.thuban_init_filename()
732 if self.root:
733 initfilename = change_root(self.root, initfilename)
734 contents = thubaninit_contents(self.install_lib_orig)
735 self.mkpath(os.path.dirname(initfilename))
736 self.execute(write_file, (initfilename, contents),
737 "Create %s" % initfilename)
738
739 def link_file(self, src, dest):
740 """Create a symbolic link dest pointing to src.
741
742 Unlike the symlink variant of the command object's copy_file
743 method, this method even performs the link if src doesn't exist.
744 This is useful when installing with an alternat root directory"""
745 if self.verbose:
746 self.announce("symlinking %s -> %s" % (src, dest))
747 if self.dry_run:
748 return
749
750 if not os.path.exists(dest):
751 os.symlink(src, dest)
752
753 def thuban_init_filename(self):
754 """Return the filename for the init-module"""
755 # Since we override the normal install dirs to point to our own
756 # prefix we have to reach into installed
757 return self.init_module_dir + "/thubaninit.py"
758
759 def get_outputs (self):
760 outputs = install.get_outputs(self)
761 for item in self.extra_files:
762 if type(item) == TupleType:
763 src, dest = item
764 else:
765 src = dest = item
766 outputs.append(os.path.join(self.root, convert_path(dest)))
767 if os.name == "posix" and self.do_symlink:
768 bindir = os.path.join(self.prefix, "bin")
769 if self.root:
770 bindir = change_root(self.root, bindir)
771 binfile = os.path.join(bindir, "thuban")
772 outputs.append(binfile)
773 if self.create_init_module:
774 initfilename = self.thuban_init_filename()
775 if self.root:
776 initfilename = change_root(self.root, initfilename)
777 outputs.append(initfilename)
778 return outputs
779
780
781 # scripts to override some of the commands put into the spec-file by the
782 # bdist_rpm command.
783
784 bdist_rpm_prep_script = '''
785 %setup
786 cp libraries/pyshapelib/{README,README.pyshapelib}
787 cp libraries/pyshapelib/{COPYING,COPYING.pyshapelib}
788 cp libraries/pyprojection/{LICENSE,LICENSE.pyprojection}
789 '''
790
791 bdist_rpm_build_script = '''
792 env PATH="$PATH:%(prefix)s/lib/wxPython/bin:/usr/lib/wxPython/bin" CFLAGS="$RPM_OPT_FLAGS" %(python)s setup.py build
793 '''
794
795 bdist_rpm_install_script = '''
796 %(python)s setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES \
797 --prefix=%(prefix)s
798 '''
799
800
801 class thuban_bdist_rpm(bdist_rpm):
802
803 """Thuban specific RPM distribution command"""
804
805 user_options = bdist_rpm.user_options[:]
806 user_options.extend([("prefix=", None, "Install prefix for the RPM"),
807 ])
808
809 def initialize_options(self):
810 # per default, RPMs are installed in /usr
811 self.prefix = "/usr/"
812
813 # create the scripts we want to override. We actually fill them
814 # with contents later because some values we put into those
815 # scripts such as the python interpreter to use are only known
816 # then.
817 open("bdist_rpm_prep", "w").close()
818 open("bdist_rpm_build", "w").close()
819 open("bdist_rpm_install", "w").close()
820 bdist_rpm.initialize_options(self)
821
822 def _make_spec_file(self):
823 # create the scripts for the spec-file. Now we know the python
824 # interpreter to use.
825 open("bdist_rpm_prep", "w").write(bdist_rpm_prep_script)
826
827 build = bdist_rpm_build_script % {"python": self.python,
828 "prefix": self.prefix}
829 open("bdist_rpm_build", "w").write(build)
830
831 install = bdist_rpm_install_script % {"python": self.python,
832 "prefix": self.prefix}
833 open("bdist_rpm_install", "w").write(install)
834
835 #
836 return bdist_rpm._make_spec_file(self)
837
838
839 class bdist_inno(Command):
840
841 """Command to create a windows installer with Inno Setup"""
842
843 description = "Create a windows installer with Inno Setup"
844
845 user_options = [
846 ('skip-build', None, "skip the build steps"),
847 ('bdist-dir=', None,
848 "temporary directory for creating the distribution"),
849 ('run-inno', None,
850 "Run inno-setup to create the installer. On by default on nt"),
851 ('iss-name', None,
852 "The name of the iss file to generate. "
853 "Shouldn't contain directories"),
854
855 # Parameters for the Inno Setup script
856 ('copyright', None, "Copyright notice for the Inno Setup file"),
857 ('default-dir-name', None,
858 "Default installation directory. Defaults to '{pf}\\<name>'"),
859 ('default-group-name', None,
860 "Default program group name. Defaults to <name>'"),
861 ("license-file", None, "File containing the license."),
862 ("output-basename", None,
863 "Base filename for the Inno Setup output "
864 "(defaults to <name>-<version>-<issrevision>)."),
865 ("iss-revision", None,
866 "revision of the generated installer of the package version"),
867
868 ("icons-entries", None,
869 "List if InnoIconItems "
870 "(this can only be set from inside the setup.py script)"),
871 ]
872
873 boolean_options = ["do-symlink"]
874
875 def initialize_options(self):
876 self.skip_build = 0
877 self.bdist_dir = None
878 self.run_inno = None
879 self.iss_name = None
880 self.copyright = ""
881 self.default_dir_name = None
882 self.default_group_name = None
883 self.license_file = None
884 self.output_basename = None
885 self.iss_revision = None
886 self.icons_entries = []
887
888 def finalize_options(self):
889 self.set_undefined_options("install",
890 ('skip_build', 'skip_build'))
891 if self.bdist_dir is None:
892 bdist_base = self.get_finalized_command('bdist').bdist_base
893 self.bdist_dir = os.path.join(bdist_base, 'inno')
894
895 if self.run_inno is None:
896 self.run_inno = os.name == "nt"
897
898 name = self.distribution.get_name()
899 if self.iss_name is None:
900 self.iss_name = name + '.iss'
901
902 if self.default_dir_name is None:
903 self.default_dir_name = "{pf}\\" + name
904 if self.default_group_name is None:
905 self.default_group_name = name
906
907 if self.iss_revision is None:
908 self.iss_revision = 0
909 if self.output_basename is None:
910 self.output_basename = "%s-%s-%d" \
911 % (name, self.distribution.get_version(),
912 self.iss_revision)
913
914 def run(self, install_options = None):
915 """Execute the command. install_options if given, should be a
916 directory of additional options to set in the install step"""
917 # Obviously have to build before we can install
918
919 if not self.skip_build:
920 self.run_command('build')
921
922 # Install in a temporary directory
923 install = self.reinitialize_command('install')
924 install.root = self.bdist_dir
925 if install_options is not None:
926 for key, value in install_options.items():
927 setattr(install, key, value)
928 if os.name != 'nt':
929 # Must force install to use the 'nt' scheme;
930 install.select_scheme('nt')
931
932 self.announce("installing to %s" % self.bdist_dir)
933 install.ensure_finalized()
934 install.run()
935
936 # Create the iss file
937 iss_file = os.path.join(self.bdist_dir, self.iss_name)
938 self.execute(write_file, (iss_file, self.generate_iss()),
939 "Create Inno Setup script file %s" % iss_file)
940
941 # and invoke
942 if self.run_inno:
943 self.spawn(["iscc", iss_file])
944
945 def generate_iss(self):
946 """Return the contents of the iss file as list of strings, one
947 string per line"""
948
949 # first, turn the icons entries into a more usable form
950 icons = {}
951 for item in self.icons_entries:
952 icons[item.filename] = item
953
954 iss = []
955
956 name = self.distribution.get_name()
957 iss.extend(["[Setup]",
958 "AppName=" + name,
959 "AppVerName=" + name + " "+self.distribution.get_version(),
960 "DefaultDirName=" + self.default_dir_name,
961 "DefaultGroupName=" + self.default_group_name,
962 ])
963 if self.copyright:
964 iss.append("AppCopyright=" + self.copyright)
965 if self.license_file:
966 iss.append("LicenseFile=" + self.license_file)
967
968 iss.append("OutputBasefilename=" + self.output_basename)
969
970 iss.append("")
971 iss.append("[Files]")
972
973 install = self.get_finalized_command("install")
974 install_scripts = self.get_finalized_command("install_scripts")
975 script_files = install_scripts.get_outputs()
976 prefixlen = len(self.bdist_dir) + len(os.sep)
977 for filename in install.get_outputs():
978 filename = filename[prefixlen:]
979 icon = icons.get(filename)
980 dirname = os.path.dirname(filename)
981 if os.name != "nt":
982 # change the separators to \ on non-windos systems
983 filename = string.join(string.split(filename, os.sep), "\\")
984 dirname = string.join(string.split(dirname, os.sep), "\\")
985 line = 'Source: "%s"' % filename
986 if icon is not None:
987 # install it as defined in the icon object
988 backslash = string.rfind(icon.install_name, "\\")
989 if backslash >= 0:
990 dirname = icon.install_name[:backslash]
991 basename = icon.install_name[backslash + 1:]
992 else:
993 dirname = ""
994 basename = icon.install_name
995 line = '%s; DestDir: "%s"; DestName: "%s"' % (line, dirname,
996 basename)
997 else:
998 line = line + '; DestDir: "{app}\\%s"' % (dirname)
999 iss.append(line)
1000
1001 iss.append("")
1002 iss.append("[Icons]")
1003 for icon in self.icons_entries:
1004 line = 'Name: "{group}\\%s"; Filename: "%s";' \
1005 % (icon.title, icon.install_name)
1006 iss.append(line)
1007
1008 return iss
1009
1010
1011 class InnoIconItem:
1012
1013 """Describe one item for the start menu for the Inno Setup installer"""
1014
1015 def __init__(self, filename, title, install_name = None):
1016 self.filename = filename
1017 self.title = title
1018 if install_name is not None:
1019 self.install_name = install_name
1020 else:
1021 self.install_name = filename
1022
1023
1024 class thuban_bdist_inno(bdist_inno):
1025
1026 """Thuban specific Inno Setup stuff"""
1027
1028 def run(self):
1029 install_options = {
1030 "prefix": ".",
1031 "install_lib": "$base",
1032 "install_data": "$base",
1033 "install_scripts": "$base",
1034 "warn_dir": 0,
1035 "extra_files": ["COPYING", "Lib/proj.dll"],
1036 }
1037 # don't make a symlink because we're simulating windows, so
1038 # that we can generate the iss-file even on Linux
1039 install_options["do_symlink"] = 0
1040
1041 bdist_inno.run(self, install_options)
1042
1043 class thuban_build_docs(Command):
1044
1045 """Command to generate documentation from source code."""
1046
1047 description = "Generate documentation."
1048
1049 user_options = []
1050
1051 def initialize_options(self): pass
1052
1053 def finalize_options(self): pass
1054
1055 def run(self, install_options = None):
1056 self.spawn(["happydoc", "-d./Doc", "./Thuban"])
1057
1058 class thuban_build_ext(build_ext):
1059
1060 """Extend the build_ext command to optionally include the
1061 GDAL extension.
1062 """
1063
1064 user_options = build_ext.user_options[:]
1065 user_options.extend([("with-gdal", None, "Include GDAL support."),
1066 ("without-gdal", None, "Don't include GDAL support.")])
1067
1068 boolean_options = ["with-gdal"]
1069 negative_opt = {'without-gdal' : 'with-gdal'}
1070
1071 def initialize_options(self):
1072 self.with_gdal = True
1073 build_ext.initialize_options(self)
1074
1075 def finalize_options(self):
1076 build_ext.finalize_options(self)
1077 if self.with_gdal and include_gdal:
1078 self.extensions.append(Extension("Lib.gdalwarp",
1079 [ext_dir + "/thuban/gdalwarp.cpp",
1080 ext_dir + "/thuban/cpl_mfile.cpp",
1081 ext_dir + "/thuban/bmpdataset.cpp"],
1082 include_dirs = gdal_cs_params[CS_INCDIRS] +
1083 [ext_dir + "/thuban/"],
1084 define_macros = gdal_cs_params[CS_DEFS],
1085 library_dirs = gdal_cs_params[CS_LIBDIRS],
1086 libraries = gdal_cs_params[CS_LIBS]))
1087
1088 def run(self, install_options = None):
1089 build_ext.run(self)
1090
1091 #
1092 # Run the script
1093 #
1094
1095 long_description = """\
1096 Thuban is a viewer for geographic data written in Python
1097 """
1098
1099 setup(name = "Thuban",
1100 version = "0.8.1",
1101 description = "Geographic data viewer",
1102 long_description = long_description,
1103 licence = "GPL",
1104 author = "Intevation GmbH",
1105 author_email = "[email protected]",
1106 url = "http://thuban.intevation.de/",
1107
1108 scripts = ["thuban.py"],
1109 packages = ["Thuban", "Thuban.Lib", "Thuban.Model", "Thuban.UI"],
1110 ext_modules = extensions,
1111 py_modules = py_modules,
1112 data_files = data_files,
1113
1114 # defaults for the install command
1115 options = {"install":
1116 # prefix defaults to python's prefix normally
1117 {"prefix": prefix,
1118 # make sure both libs and scripts are installed in the
1119 # same directory.
1120 "install_lib": "$base/lib/thuban",
1121 "install_scripts": "$base/lib/thuban",
1122 "install_data": "$base/lib/thuban",
1123
1124 # Don't print warning messages about the lib dir not
1125 # being on Python's path. The libraries are Thuban
1126 # specific and are installed just for Thuban. They'll
1127 # be automatically on Python's path when Thuban is run
1128 "warn_dir": 0,
1129 },
1130 "bdist_inno":
1131 {"icons_entries": [InnoIconItem(".\\thuban.py",
1132 "Start Thuban",
1133 "{app}\\thuban.pyw")],
1134 "license_file": "COPYING",
1135 }
1136 },
1137 cmdclass = {"build_py": thuban_build_py,
1138 "install_local": InstallLocal,
1139 "install": ThubanInstall,
1140 "bdist_rpm": thuban_bdist_rpm,
1141 "bdist_inno": thuban_bdist_inno,
1142 "data_dist": data_dist,
1143 "build_docs": thuban_build_docs,
1144 "build_ext": thuban_build_ext
1145 })
1146
1147

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26