/[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 2590 - (show annotations)
Tue Apr 5 17:26:58 2005 UTC (19 years, 11 months ago) by bh
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 43314 byte(s)
Use wxPython.h by default but provide a workaround when it isn't
available.

* setup.py (wxproj_extension): New variable.  Assign the Extension
instance for Lib.wxproj to this variable instead of putting it
directly into the listso that it can be accessed by other code
later.
(thuban_build_ext.user_options): Added boolean option
--use-wx-python-swig-hack.
(thuban_build_ext.initialize_options): Initialize the new option
to False.
(thuban_build_ext.finalize_options): If the new option was given,
define the preprocesser macro USE_WX_PYTHON_SWIG_HACK.
(thuban_build_ext): Update the doc-string

* libraries/thuban/wxproj.cpp: Normally we use
wx/wxPython/wxPython.h now.  Only if USE_WX_PYTHON_SWIG_HACK is
defined, use swigPtrConvertHack.h instead.

* libraries/thuban/swigPtrConvertHack.h: Remove the code that was
copied over from wxPython.h.
(decode_pointer_new): New.  Equivalent of decode_pointer for
wxPython 2.5.
(wxPyConvertSwigPtr): Modified to cope with wxPython 2.5 as well.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26