/[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 2742 - (hide annotations)
Wed Mar 14 16:26:14 2007 UTC (17 years, 11 months ago) by bramz
File MIME type: text/x-python
File size: 44351 byte(s)
pyshapelib: rewritten dbflib to use hand-crafted Python bindings instead of SWIG generated ones.

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 dpinte 2737 extensions.append(Extension("Lib.shapelib",
273 bramz 2742 [ext_dir + "/pyshapelib/shapelibmodule.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 bramz 2742 extensions.append(Extension("Lib.dbflib",
281     [ext_dir + "/pyshapelib/dbflibmodule.c",
282 bh 6 shp_dir + "/dbfopen.c"],
283 bh 2212 include_dirs = [shp_dir],
284     define_macros = [("HAVE_UPDATE_HEADER", "1")]))
285 bh 6
286 bramz 2742
287 bh 6 #
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 jonathan 1296 # Resources
305 bh 2007 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 bh 1717 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 bh 6
322 dpinte 2711 #add the Lib content to the output
323     if os.path.isdir("Lib"):
324     for d in os.listdir("Lib"):
325     data_files.append(("Lib", ["Lib/"+d]))
326    
327    
328 bh 6 #
329     # Command definitions
330     #
331     # So far distutils are only meant to distribute python extensions, not
332     # complete applications, so we have to redefine a few commands
333 bh 67 #
334 bh 6
335    
336 bh 67 # Much of the data_dist command is directly copied from the distutils'
337     # sdist command
338     class data_dist(Command):
339 bh 6
340 bh 67 description = "create a data distribution (tarball, zip file, etc.)"
341    
342     user_options = [
343     ('formats=', None,
344     "formats for source distribution (comma-separated list)"),
345     ('keep-temp', 'k',
346     "keep the distribution tree around after creating " +
347     "archive file(s)"),
348     ('dist-dir=', 'd',
349     "directory to put the source distribution archive(s) in "
350     "[default: dist]"),
351     ]
352    
353     boolean_options = ['keep-temp']
354    
355     def initialize_options (self):
356     self.formats = None
357     self.keep_temp = 0
358     self.dist_dir = None
359    
360     def finalize_options (self):
361     self.ensure_string_list('formats')
362     if self.formats is None:
363     self.formats = ["zip"]
364     bad_format = archive_util.check_archive_formats(self.formats)
365     if bad_format:
366     raise DistutilsOptionError, \
367     "unknown archive format '%s'" % bad_format
368    
369     if self.dist_dir is None:
370     self.dist_dir = "dist"
371    
372    
373     def run(self):
374     # 'filelist' contains the list of files that will make up the
375     # manifest
376     self.filelist = FileList()
377    
378     # Do whatever it takes to get the list of files to process.
379     # File list is accumulated in 'self.filelist'.
380     self.get_file_list()
381    
382     # Otherwise, go ahead and create the source distribution tarball,
383     # or zipfile, or whatever.
384     self.make_distribution()
385    
386     def get_file_list(self):
387     """Figure out the list of files to include in the data
388     distribution, and put it in 'self.filelist'.
389     """
390     self.filelist.findall("Data")
391     self.filelist.include_pattern("*", anchor = 0)
392     self.filelist.exclude_pattern(r'/(RCS|CVS)/.*', is_regex=1)
393     self.filelist.sort()
394     self.filelist.remove_duplicates()
395    
396     def make_release_tree(self, base_dir, files):
397     """Create the directory tree that will become the source
398     distribution archive. All directories implied by the filenames in
399     'files' are created under 'base_dir', and then we hard link or copy
400     (if hard linking is unavailable) those files into place.
401     Essentially, this duplicates the developer's source tree, but in a
402     directory named after the distribution, containing only the files
403     to be distributed.
404     """
405     # Create all the directories under 'base_dir' necessary to
406     # put 'files' there; the 'mkpath()' is just so we don't die
407     # if the manifest happens to be empty.
408     self.mkpath(base_dir)
409     dir_util.create_tree(base_dir, files,
410     verbose=self.verbose, dry_run=self.dry_run)
411    
412     # And walk over the list of files, either making a hard link (if
413     # os.link exists) to each one that doesn't already exist in its
414     # corresponding location under 'base_dir', or copying each file
415     # that's out-of-date in 'base_dir'. (Usually, all files will be
416     # out-of-date, because by default we blow away 'base_dir' when
417     # we're done making the distribution archives.)
418    
419     if hasattr(os, 'link'): # can make hard links on this system
420     link = 'hard'
421     msg = "making hard links in %s..." % base_dir
422     else: # nope, have to copy
423     link = None
424     msg = "copying files to %s..." % base_dir
425    
426     if not files:
427     self.warn("no files to distribute -- empty manifest?")
428     else:
429     self.announce(msg)
430     for file in files:
431     if not os.path.isfile(file):
432     self.warn("'%s' not a regular file -- skipping" % file)
433     else:
434     dest = os.path.join(base_dir, file)
435     self.copy_file(file, dest, link=link)
436    
437    
438     def make_distribution (self):
439     """Create the source distribution(s). First, we create the release
440     tree with 'make_release_tree()'; then, we create all required
441     archive files (according to 'self.formats') from the release tree.
442     Finally, we clean up by blowing away the release tree (unless
443     'self.keep_temp' is true). The list of archive files created is
444     stored so it can be retrieved later by 'get_archive_files()'.
445     """
446     # Don't warn about missing meta-data here -- should be (and is!)
447     # done elsewhere.
448     base_dir = "Thuban-data-" + self.distribution.get_version()
449     base_name = os.path.join(self.dist_dir, base_dir)
450    
451     self.make_release_tree(base_dir, self.filelist.files)
452     archive_files = [] # remember names of files we create
453     for fmt in self.formats:
454     file = self.make_archive(base_name, fmt, base_dir=base_dir)
455     archive_files.append(file)
456    
457     self.archive_files = archive_files
458    
459     if not self.keep_temp:
460     dir_util.remove_tree(base_dir, self.verbose, self.dry_run)
461    
462    
463    
464 bh 6 class InstallLocal(Command):
465    
466     """
467     A new install command to just link (or copy, on non-POSIX systems)
468     the extension modules to the top directory so that Thuban can be run
469     directly from the source dir.
470     """
471    
472     description =\
473 bh 71 "Create some symlinks so you can run thuban from the source directory"
474 bh 6
475     user_options = [
476     ('skip-build', None, "skip the build steps"),
477 bh 253 ('create-init-module', None,
478     "Create the thubaninit.py module to ease use of Thuban as a library"),
479     ('dont-create-init-module', None,
480     "Do not create the thubaninit.py module"),
481 bh 6 ]
482    
483 bh 253 boolean_options = ["create-init-module"]
484     negative_opt = {'dont-create-init-module' : 'create-init-module'}
485    
486    
487 bh 6 def initialize_options (self):
488     self.extensions = None
489     self.build_dir = None
490     self.skip_build = None
491 bh 253 self.create_init_module = None
492 bh 6
493     def finalize_options (self):
494     self.set_undefined_options("install",
495     ("build_lib", "build_dir"),
496     ('skip_build', 'skip_build'))
497     self.extensions = self.distribution.ext_modules
498 bh 253 if self.create_init_module is None:
499     # by default we create the init module
500     self.create_init_module = 1
501 bh 6
502     def run(self):
503     # Make sure we have built everything we need first
504     self.build()
505    
506     # now do the work. Simply link or copy the Lib dir
507     libdir = os.path.join(self.build_dir, "Lib")
508     if os.name == "posix":
509 bh 71 # on posix, just link the Lib dir
510 bh 6 self.link_dir(libdir, "Lib")
511     else:
512     self.copy_tree(libdir, "Lib")
513    
514 bh 253 # create the init module if desired
515     if self.create_init_module:
516     # create the init module
517     initfilename = "thubaninit.py"
518     contents = thubaninit_contents("")
519     self.execute(write_file, (initfilename, contents),
520     "Create %s" % initfilename)
521    
522 bh 6 def link_dir(self, src, dest):
523     """Create a symbolic link dest pointing to src"""
524     if self.verbose:
525 bh 15 self.announce("symlinking %s -> %s" % (src, dest))
526 bh 6 if self.dry_run:
527     return
528    
529     if not (os.path.exists(dest) and os.path.samefile(src, dest)):
530     os.symlink(src, dest)
531    
532     def build (self):
533     if not self.skip_build:
534     if self.distribution.has_pure_modules():
535     self.run_command('build_py')
536     if self.distribution.has_ext_modules():
537     self.run_command('build_ext')
538    
539    
540    
541     class thuban_build_py(build_py):
542    
543     """
544 bh 8 A new build_py that can deal with both packages and modules in one
545     distribution.
546 bh 6 """
547    
548 bh 452 # FIXME: When Thuban can rely on Python 2.3 as the oldest supported
549     # Python release we don't need to override the run and
550     # find_all_modules methods anymore. distutils will allow both python
551     # modules and packages starting with 2.3.
552    
553 bh 6 def run(self):
554 bh 8 """The same the as the original in build_py revision 1.33 except
555 bh 6 that this allows both packages and modules to be in one
556     distribution
557     """
558     if not self.py_modules and not self.packages:
559     return
560    
561     # Now we're down to two cases: 'py_modules' only and 'packages' only.
562     if self.py_modules:
563     self.build_modules()
564     if self.packages:
565     self.build_packages()
566    
567     self.byte_compile(self.get_outputs(include_bytecode=0))
568    
569     def find_modules (self):
570     """Thuban specific version of build_py.find_modules. Unlike the
571     original version, we assume that the modules in self.py_modules
572     can contain directories and are all to be placed into the same
573     subdirectory, Lib, in the build directory. This is achieved by
574     returning the modules as a list (package, module, filename)
575     where package is 'Lib', module is the basename of the module name
576     and filename is the filename relative to the package root.
577     """
578     modules = []
579     for module in self.py_modules:
580     module_base = os.path.basename(module)
581     module_file = module + ".py"
582     if not self.check_module(module, module_file):
583     continue
584    
585     modules.append(("Lib", module_base, module_file))
586     return modules
587    
588 bh 15 def find_all_modules (self):
589     # same as find_all_modules of the original build_py command
590     # (rev. 1.33) but handle installations with both modules and
591     # packages. Needed here so tha the get_outputs works correctly
592     modules = []
593     if self.py_modules:
594     modules.extend(self.find_modules())
595     if self.packages:
596     for package in self.packages:
597     package_dir = self.get_package_dir(package)
598     m = self.find_package_modules(package, package_dir)
599     modules.extend(m)
600 bh 6
601 bh 15 return modules
602    
603    
604 bh 253 thubaninit_contents_start = """
605 bh 204 # This module was automatically generated by Thuban's install script
606     '''Import this module once per program (best place is probably the file
607     that ends up as your __main__ module) to be able to import Thuban
608     afterwards.
609 bh 15
610 bh 204 Usage:
611    
612     import thubaninit
613     import Thuban
614     '''
615     import sys, os
616 bh 253 """
617    
618     thubaninit_contents_thubaninitdir = """
619 bh 204 sys.path.insert(0, %(thubandir)s)
620 bh 253 """
621     thubaninit_contents_otherdirs = """
622 bh 204 # Put the Lib dir into the path. The Lib dir contains some extra Python
623     # modules
624     import Thuban
625     thubandir = os.path.join(Thuban.__path__[0], '..')
626     dir = os.path.join(thubandir, "Lib")
627     if os.path.isdir(dir):
628     sys.path.insert(0, dir)
629     """
630    
631 bh 253 def thubaninit_contents(thubandir):
632     """Return the contents of the the thubaninit file as a list of lines.
633 bh 204
634 bh 253 The parameter thubandir is the parent directory where the Thuban/
635     package or the empty string if the thubaninit file itself will be
636     located in that direcory as well.
637     """
638     contents = thubaninit_contents_start
639     if thubandir:
640     thubandir = repr(thubandir)
641     contents += thubaninit_contents_thubaninitdir % locals()
642     contents += thubaninit_contents_otherdirs
643     return contents.split("\n")
644    
645    
646 bh 6 class ThubanInstall(install):
647    
648 bh 8 """
649     Thuban specific install command.
650    
651     Extend the standard install command to symlink the installed script
652     to $prefix/bin/
653     """
654 bh 15
655     user_options = install.user_options[:]
656     user_options.extend([("do-symlink", None,
657     "Create a symlink to the script in <prefix>/bin."
658     "(default on posix systems and only relevant there)"),
659    
660     ("extra-files", None,
661 bh 204 "List of filenames or (src, dest) pairs describing"
662 bh 15 " extra files to install "
663 jonathan 1229 "(can only be set from within setup.py"),
664 bh 204
665 bh 212 ("create-init-module=", None,
666     "If true, create a module in the site-packages"
667     " directory that tweaks sys.path to let you easily"
668     " import thuban modules from outside of thuban."),
669     ("init-module-dir=", None,
670 bh 204 "Directory in which to create the init module."
671     " Defaults to Python's site-packages directory."),
672 bh 15 ])
673    
674     boolean_options = install.boolean_options[:]
675     boolean_options.append("do-symlink")
676 bh 204 boolean_options.append("create-init-module")
677 bh 15
678     def initialize_options(self):
679     self.do_symlink = None
680     self.extra_files = []
681 bh 212
682     # initialize the create_init_module flag from the global
683     # determined at runtime
684     self.create_init_module = create_init_module
685 bh 204 self.init_module_dir = None
686 bh 15 install.initialize_options(self)
687    
688     def finalize_options(self):
689     if self.do_symlink is None:
690     if os.name == "posix":
691     self.do_symlink = 1
692     else:
693     self.do_symlink = 0
694     install.finalize_options(self)
695 bh 204 self.expand_with_pure_python_dirs(["init_module_dir"])
696 bh 15
697 bh 204 def expand_with_pure_python_dirs(self, attrs):
698     """Expand the attributes with default values of base and platbase"""
699     # it seems that the values for "prefix" and "exec_prefix" in
700     # self.config_vars are the corresponding values used by the
701     # python interpreter, so we just assign these to "base" and
702     # "platbase".
703     config_vars = self.config_vars.copy()
704     config_vars["base"] = self.config_vars["prefix"]
705     config_vars["platbase"] = self.config_vars["exec_prefix"]
706     for attr in attrs:
707     val = getattr(self, attr)
708     if val is not None:
709     if os.name == 'posix':
710     val = os.path.expanduser(val)
711     val = subst_vars(val, config_vars)
712     setattr(self, attr, val)
713    
714     def select_scheme(self, scheme):
715     """Extend the inherited method to set init_module_dir"""
716     install.select_scheme(self, scheme)
717     # only set init_module_dir if it wasn't set by the user
718     if self.init_module_dir is None:
719     self.init_module_dir = INSTALL_SCHEMES[scheme]['purelib']
720    
721     def convert_paths(self, *args):
722     """Extend the inherited method so that we can remember some filename
723     """
724     # remember the installation directory before its root gets
725     # changed
726     self.install_lib_orig = self.install_lib
727     apply(install.convert_paths, (self,) + args)
728    
729 bh 6 def run(self):
730     install.run(self)
731 bh 15 for item in self.extra_files:
732     if type(item) == TupleType:
733     src, dest = item
734     else:
735     src = dest = item
736 bh 266 self.copy_file(convert_path(src),
737 bh 15 os.path.join(self.root, convert_path(dest)))
738    
739     if os.name == "posix" and self.do_symlink:
740 bh 19 install_scripts = self.install_scripts
741     if self.root:
742     install_scripts = install_scripts[len(self.root):]
743     scriptfile = os.path.join(install_scripts, "thuban.py")
744 bh 6 bindir = os.path.join(self.prefix, "bin")
745 bh 18 if self.root:
746     bindir = change_root(self.root, bindir)
747 bh 6 binfile = os.path.join(bindir, "thuban")
748     self.mkpath(bindir)
749 bh 19 self.link_file(scriptfile, binfile)
750 bh 6
751 bh 204 if self.create_init_module:
752     # create the init module
753     initfilename = self.thuban_init_filename()
754     if self.root:
755     initfilename = change_root(self.root, initfilename)
756 bh 266 contents = thubaninit_contents(self.install_lib_orig)
757 bh 204 self.mkpath(os.path.dirname(initfilename))
758 bh 253 self.execute(write_file, (initfilename, contents),
759 bh 204 "Create %s" % initfilename)
760    
761 bh 19 def link_file(self, src, dest):
762     """Create a symbolic link dest pointing to src.
763    
764     Unlike the symlink variant of the command object's copy_file
765     method, this method even performs the link if src doesn't exist.
766     This is useful when installing with an alternat root directory"""
767     if self.verbose:
768     self.announce("symlinking %s -> %s" % (src, dest))
769     if self.dry_run:
770     return
771    
772     if not os.path.exists(dest):
773     os.symlink(src, dest)
774    
775 bh 204 def thuban_init_filename(self):
776     """Return the filename for the init-module"""
777     # Since we override the normal install dirs to point to our own
778     # prefix we have to reach into installed
779     return self.init_module_dir + "/thubaninit.py"
780 bh 19
781 bh 15 def get_outputs (self):
782     outputs = install.get_outputs(self)
783     for item in self.extra_files:
784     if type(item) == TupleType:
785     src, dest = item
786     else:
787     src = dest = item
788     outputs.append(os.path.join(self.root, convert_path(dest)))
789 bh 19 if os.name == "posix" and self.do_symlink:
790     bindir = os.path.join(self.prefix, "bin")
791     if self.root:
792     bindir = change_root(self.root, bindir)
793     binfile = os.path.join(bindir, "thuban")
794     outputs.append(binfile)
795 bh 204 if self.create_init_module:
796     initfilename = self.thuban_init_filename()
797     if self.root:
798     initfilename = change_root(self.root, initfilename)
799     outputs.append(initfilename)
800 bh 15 return outputs
801 bh 6
802 bh 19
803 bh 203 # scripts to override some of the commands put into the spec-file by the
804     # bdist_rpm command.
805    
806 bh 19 bdist_rpm_prep_script = '''
807     %setup
808 jan 1614 cp libraries/pyshapelib/{README,README.pyshapelib}
809     cp libraries/pyshapelib/{COPYING,COPYING.pyshapelib}
810     cp libraries/pyprojection/{LICENSE,LICENSE.pyprojection}
811 bh 19 '''
812    
813 jonathan 555 bdist_rpm_build_script = '''
814     env PATH="$PATH:%(prefix)s/lib/wxPython/bin:/usr/lib/wxPython/bin" CFLAGS="$RPM_OPT_FLAGS" %(python)s setup.py build
815     '''
816    
817 bh 203 bdist_rpm_install_script = '''
818     %(python)s setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES \
819     --prefix=%(prefix)s
820     '''
821 bh 19
822 bh 266
823 bh 19 class thuban_bdist_rpm(bdist_rpm):
824    
825     """Thuban specific RPM distribution command"""
826    
827 bh 203 user_options = bdist_rpm.user_options[:]
828     user_options.extend([("prefix=", None, "Install prefix for the RPM"),
829     ])
830    
831 bh 90 def initialize_options(self):
832 bh 203 # per default, RPMs are installed in /usr
833     self.prefix = "/usr/"
834 bh 19
835 bh 203 # create the scripts we want to override. We actually fill them
836     # with contents later because some values we put into those
837     # scripts such as the python interpreter to use are only known
838     # then.
839     open("bdist_rpm_prep", "w").close()
840 jonathan 555 open("bdist_rpm_build", "w").close()
841 bh 203 open("bdist_rpm_install", "w").close()
842 bh 90 bdist_rpm.initialize_options(self)
843 bh 19
844 bh 203 def _make_spec_file(self):
845     # create the scripts for the spec-file. Now we know the python
846     # interpreter to use.
847     open("bdist_rpm_prep", "w").write(bdist_rpm_prep_script)
848 jonathan 555
849     build = bdist_rpm_build_script % {"python": self.python,
850     "prefix": self.prefix}
851     open("bdist_rpm_build", "w").write(build)
852    
853 bh 203 install = bdist_rpm_install_script % {"python": self.python,
854     "prefix": self.prefix}
855     open("bdist_rpm_install", "w").write(install)
856 bh 19
857 bh 203 #
858     return bdist_rpm._make_spec_file(self)
859    
860    
861 bh 15 class bdist_inno(Command):
862    
863     """Command to create a windows installer with Inno Setup"""
864    
865     description = "Create a windows installer with Inno Setup"
866    
867     user_options = [
868     ('skip-build', None, "skip the build steps"),
869     ('bdist-dir=', None,
870     "temporary directory for creating the distribution"),
871     ('run-inno', None,
872     "Run inno-setup to create the installer. On by default on nt"),
873     ('iss-name', None,
874     "The name of the iss file to generate. "
875     "Shouldn't contain directories"),
876    
877     # Parameters for the Inno Setup script
878     ('copyright', None, "Copyright notice for the Inno Setup file"),
879     ('default-dir-name', None,
880     "Default installation directory. Defaults to '{pf}\\<name>'"),
881     ('default-group-name', None,
882     "Default program group name. Defaults to <name>'"),
883     ("license-file", None, "File containing the license."),
884     ("output-basename", None,
885     "Base filename for the Inno Setup output "
886     "(defaults to <name>-<version>-<issrevision>)."),
887     ("iss-revision", None,
888     "revision of the generated installer of the package version"),
889    
890     ("icons-entries", None,
891     "List if InnoIconItems "
892     "(this can only be set from inside the setup.py script)"),
893     ]
894    
895     boolean_options = ["do-symlink"]
896    
897     def initialize_options(self):
898     self.skip_build = 0
899     self.bdist_dir = None
900     self.run_inno = None
901     self.iss_name = None
902     self.copyright = ""
903     self.default_dir_name = None
904     self.default_group_name = None
905     self.license_file = None
906     self.output_basename = None
907     self.iss_revision = None
908     self.icons_entries = []
909    
910     def finalize_options(self):
911     self.set_undefined_options("install",
912     ('skip_build', 'skip_build'))
913     if self.bdist_dir is None:
914     bdist_base = self.get_finalized_command('bdist').bdist_base
915     self.bdist_dir = os.path.join(bdist_base, 'inno')
916    
917     if self.run_inno is None:
918     self.run_inno = os.name == "nt"
919    
920     name = self.distribution.get_name()
921     if self.iss_name is None:
922     self.iss_name = name + '.iss'
923    
924     if self.default_dir_name is None:
925     self.default_dir_name = "{pf}\\" + name
926     if self.default_group_name is None:
927     self.default_group_name = name
928    
929     if self.iss_revision is None:
930     self.iss_revision = 0
931     if self.output_basename is None:
932     self.output_basename = "%s-%s-%d" \
933     % (name, self.distribution.get_version(),
934 dpinte 2711 int(self.iss_revision))
935 bh 15
936     def run(self, install_options = None):
937     """Execute the command. install_options if given, should be a
938     directory of additional options to set in the install step"""
939     # Obviously have to build before we can install
940 jonathan 533
941 dpinte 2711 # add gdal to the build
942     for (dirpath, dnames, fnames) in os.walk('gdal'):
943     files_in_dir = []
944     dp = '/'.join(dirpath.split('\\'))
945     for f in fnames:
946     if os.path.isfile(os.path.join(dirpath,f)):
947     files_in_dir.append( dp + '/' + f)
948     if len(files_in_dir) > 0:
949     data_files.append(( dp , files_in_dir))
950     # add thubaninit to the build
951    
952    
953 bh 15 if not self.skip_build:
954     self.run_command('build')
955    
956     # Install in a temporary directory
957     install = self.reinitialize_command('install')
958     install.root = self.bdist_dir
959     if install_options is not None:
960     for key, value in install_options.items():
961     setattr(install, key, value)
962     if os.name != 'nt':
963     # Must force install to use the 'nt' scheme;
964     install.select_scheme('nt')
965    
966     self.announce("installing to %s" % self.bdist_dir)
967     install.ensure_finalized()
968     install.run()
969    
970     # Create the iss file
971     iss_file = os.path.join(self.bdist_dir, self.iss_name)
972     self.execute(write_file, (iss_file, self.generate_iss()),
973     "Create Inno Setup script file %s" % iss_file)
974    
975 bh 266 # and invoke
976 bh 15 if self.run_inno:
977     self.spawn(["iscc", iss_file])
978    
979     def generate_iss(self):
980     """Return the contents of the iss file as list of strings, one
981     string per line"""
982    
983     # first, turn the icons entries into a more usable form
984     icons = {}
985     for item in self.icons_entries:
986     icons[item.filename] = item
987    
988     iss = []
989    
990     name = self.distribution.get_name()
991     iss.extend(["[Setup]",
992     "AppName=" + name,
993     "AppVerName=" + name + " "+self.distribution.get_version(),
994     "DefaultDirName=" + self.default_dir_name,
995     "DefaultGroupName=" + self.default_group_name,
996     ])
997     if self.copyright:
998     iss.append("AppCopyright=" + self.copyright)
999     if self.license_file:
1000     iss.append("LicenseFile=" + self.license_file)
1001    
1002     iss.append("OutputBasefilename=" + self.output_basename)
1003    
1004     iss.append("")
1005     iss.append("[Files]")
1006    
1007     install = self.get_finalized_command("install")
1008     install_scripts = self.get_finalized_command("install_scripts")
1009     script_files = install_scripts.get_outputs()
1010     prefixlen = len(self.bdist_dir) + len(os.sep)
1011     for filename in install.get_outputs():
1012     filename = filename[prefixlen:]
1013     icon = icons.get(filename)
1014     dirname = os.path.dirname(filename)
1015     if os.name != "nt":
1016     # change the separators to \ on non-windos systems
1017     filename = string.join(string.split(filename, os.sep), "\\")
1018     dirname = string.join(string.split(dirname, os.sep), "\\")
1019     line = 'Source: "%s"' % filename
1020     if icon is not None:
1021     # install it as defined in the icon object
1022     backslash = string.rfind(icon.install_name, "\\")
1023     if backslash >= 0:
1024     dirname = icon.install_name[:backslash]
1025     basename = icon.install_name[backslash + 1:]
1026     else:
1027     dirname = ""
1028     basename = icon.install_name
1029     line = '%s; DestDir: "%s"; DestName: "%s"' % (line, dirname,
1030     basename)
1031     else:
1032     line = line + '; DestDir: "{app}\\%s"' % (dirname)
1033     iss.append(line)
1034    
1035     iss.append("")
1036     iss.append("[Icons]")
1037     for icon in self.icons_entries:
1038     line = 'Name: "{group}\\%s"; Filename: "%s";' \
1039     % (icon.title, icon.install_name)
1040     iss.append(line)
1041 bh 266
1042 bh 15 return iss
1043    
1044    
1045     class InnoIconItem:
1046    
1047 bh 54 """Describe one item for the start menu for the Inno Setup installer"""
1048 bh 15
1049     def __init__(self, filename, title, install_name = None):
1050     self.filename = filename
1051     self.title = title
1052     if install_name is not None:
1053     self.install_name = install_name
1054     else:
1055     self.install_name = filename
1056    
1057 bh 266
1058 bh 15 class thuban_bdist_inno(bdist_inno):
1059    
1060     """Thuban specific Inno Setup stuff"""
1061    
1062     def run(self):
1063     install_options = {
1064     "prefix": ".",
1065 jonathan 533 "install_lib": "$base",
1066     "install_data": "$base",
1067 bh 15 "install_scripts": "$base",
1068     "warn_dir": 0,
1069     "extra_files": ["COPYING", "Lib/proj.dll"],
1070     }
1071 dpinte 2711 install_options["extra_files"].extend(self.get_gdal_content())
1072    
1073 bh 54 # don't make a symlink because we're simulating windows, so
1074     # that we can generate the iss-file even on Linux
1075     install_options["do_symlink"] = 0
1076 jonathan 533
1077 bh 15 bdist_inno.run(self, install_options)
1078 bh 266
1079 dpinte 2711 def get_gdal_content(self):
1080     '''
1081     Return the list of files in the gdal directory of the Thuban installation
1082     '''
1083     gdal_files = []
1084     for (dirpath, dnames, fnames) in os.walk('gdal'):
1085     if len(fnames) > 0:
1086     for file in fnames :
1087     gdal_files.append(dirpath + os.sep + file)
1088     return gdal_files
1089    
1090 jonathan 543 class thuban_build_docs(Command):
1091 bh 266
1092 jonathan 543 """Command to generate documentation from source code."""
1093    
1094     description = "Generate documentation."
1095    
1096     user_options = []
1097    
1098     def initialize_options(self): pass
1099    
1100     def finalize_options(self): pass
1101    
1102     def run(self, install_options = None):
1103     self.spawn(["happydoc", "-d./Doc", "./Thuban"])
1104    
1105 jonathan 1229 class thuban_build_ext(build_ext):
1106    
1107 bh 2590 """Extend the build_ext command with some Thuban specific options
1108    
1109     --with-gdal, --without-gdal
1110    
1111     Switch the optional GDAL support on/off. Default is On.
1112    
1113     --use-wx-python-swig-hack
1114    
1115     For performance reasons, Thuban access wxPython objects at the
1116     C++ level so that it can directly call wxWidgets code from C++.
1117     The normal and preferred way to do that is to use the API
1118     defined in wxPython.h. Unfortunately, this header file is not
1119     distributed with binary packages of wxPython on some platforms.
1120     By using the --use-wx-python-swig-hack option you can activate a
1121     way to access the C++ objects without wxPython.h. This relies
1122     on internals of SWIG, so it might change with future wxPython
1123     versions. Therefore, only use this option if the normal way
1124     doesn't work for you.
1125 jonathan 1229 """
1126    
1127     user_options = build_ext.user_options[:]
1128     user_options.extend([("with-gdal", None, "Include GDAL support."),
1129 bh 2590 ("without-gdal", None, "Don't include GDAL support."),
1130     ("use-wx-python-swig-hack", None,
1131     "Use a hack to access wxPython objects at the C++ level"
1132     "(use only when you absolutely can't use wxPython.h)")])
1133 jonathan 1229
1134 bh 2590 boolean_options = ["with-gdal", "use-wx-python-swig-hack"]
1135 jonathan 1229 negative_opt = {'without-gdal' : 'with-gdal'}
1136    
1137     def initialize_options(self):
1138     self.with_gdal = True
1139 bh 2590 self.use_wx_python_swig_hack = False
1140 jonathan 1229 build_ext.initialize_options(self)
1141    
1142 bh 2590 def finalize_options(self):
1143 jonathan 1229 build_ext.finalize_options(self)
1144     if self.with_gdal and include_gdal:
1145     self.extensions.append(Extension("Lib.gdalwarp",
1146 jonathan 2537 [ext_dir + "/thuban/gdalwarp.cpp"],
1147 jonathan 1238 include_dirs = gdal_cs_params[CS_INCDIRS] +
1148 jonathan 2572 [ext_dir + "/thuban/"],
1149     define_macros = gdal_cs_params[CS_DEFS],
1150 jonathan 1229 library_dirs = gdal_cs_params[CS_LIBDIRS],
1151 jonathan 1238 libraries = gdal_cs_params[CS_LIBS]))
1152 bh 2590 if self.use_wx_python_swig_hack:
1153     wxproj_extension.define_macros.append(("USE_WX_PYTHON_SWIG_HACK",
1154     None))
1155 jonathan 1229
1156     def run(self, install_options = None):
1157     build_ext.run(self)
1158    
1159 bh 15 #
1160     # Run the script
1161     #
1162    
1163 bh 6 long_description = """\
1164     Thuban is a viewer for geographic data written in Python
1165     """
1166    
1167 bh 15 setup(name = "Thuban",
1168 bernhard 2729 version = "1.2.0",
1169 bh 6 description = "Geographic data viewer",
1170     long_description = long_description,
1171 bh 2024 license = "GPL",
1172 bh 6 author = "Intevation GmbH",
1173 bh 1994 author_email = "[email protected]",
1174 bh 209 url = "http://thuban.intevation.de/",
1175 bh 6
1176     scripts = ["thuban.py"],
1177 bh 2007 packages = ["Thuban", "Thuban.Lib", "Thuban.Model", "Thuban.UI",
1178     "Extensions", "Extensions.gns2shp", "Extensions.wms",
1179 dpinte 2711 "Extensions.importAPR", "Extensions.profiling",
1180     "Extensions.svgexport", "Extensions.mouseposition",
1181     "Extensions.bboxdump", "Extensions.ogr",
1182     "Extensions.umn_mapserver"],
1183 bh 6 ext_modules = extensions,
1184     py_modules = py_modules,
1185     data_files = data_files,
1186    
1187     # defaults for the install command
1188     options = {"install":
1189     # prefix defaults to python's prefix normally
1190     {"prefix": prefix,
1191     # make sure both libs and scripts are installed in the
1192     # same directory.
1193 bh 200 "install_lib": "$base/lib/thuban",
1194     "install_scripts": "$base/lib/thuban",
1195     "install_data": "$base/lib/thuban",
1196 bh 6 # Don't print warning messages about the lib dir not
1197     # being on Python's path. The libraries are Thuban
1198     # specific and are installed just for Thuban. They'll
1199     # be automatically on Python's path when Thuban is run
1200     "warn_dir": 0,
1201 bh 15 },
1202     "bdist_inno":
1203     {"icons_entries": [InnoIconItem(".\\thuban.py",
1204     "Start Thuban",
1205     "{app}\\thuban.pyw")],
1206     "license_file": "COPYING",
1207     }
1208     },
1209 bh 6 cmdclass = {"build_py": thuban_build_py,
1210     "install_local": InstallLocal,
1211 bh 15 "install": ThubanInstall,
1212 bh 19 "bdist_rpm": thuban_bdist_rpm,
1213 bh 67 "bdist_inno": thuban_bdist_inno,
1214 jonathan 543 "data_dist": data_dist,
1215 jonathan 1229 "build_docs": thuban_build_docs,
1216     "build_ext": thuban_build_ext
1217 bh 15 })
1218 bh 6
1219 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