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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2711 - (hide annotations)
Tue Oct 10 10:30:54 2006 UTC (18 years, 4 months ago) by dpinte
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 44441 byte(s)
2006-10-10 Didrik Pinte <dpinte@itae.be>

    Win32 build updates 

        * setup.py : 
            - update to the latest libs for win32 setup tasks
            - added gdal and Lib content to the inno setup build task
            - added stable and experimental extensions to setup packages

        * thuban.py :
            - gdal support for win32 inno installation

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26