/[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 1229 - (hide annotations)
Wed Jun 18 14:46:30 2003 UTC (21 years, 8 months ago) by jonathan
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 41334 byte(s)
Use a list instead of seperate variables for
        extension parameters so we can create a generic function
        that runs an appropriate *-config script.
(run_cs_script): Renamed from run_wx_script and modified
        to accept a second argument which is a list of lists to
        be filled in by the values returned from running the command.
(thuban_build_ext): New. Extends the build_ext command and
        provides the options --with-gdal/--without-gdal which then
        optionally includes the gdalwarp extension.

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