/[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 2651 - (hide annotations)
Tue Jul 5 20:24:50 2005 UTC (19 years, 8 months ago) by bh
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 43314 byte(s)
(setup call): Version 1.1.0

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