/[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 2212 - (hide annotations)
Mon May 17 15:47:57 2004 UTC (20 years, 9 months ago) by bh
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 42146 byte(s)
Update to newest shapelib and get rid of Thuban specific extensions,
i.e. use the new DBFUpdateHeader instead of our DBFCommit kludge

* libraries/shapelib/shpopen.c: Update to version from current
shapelib CVS.

* libraries/shapelib/shapefil.h: Update to version from current
shapelib CVS.

* libraries/shapelib/dbfopen.c: Update to version from current
shapelib CVS.
(DBFCommit): Effectively removed since shapelib itself has
DBFUpdateHeader now which is better for what DBFCommit wanted to
achieve.
We're now using an unmodified version of dbfopen.

* libraries/pyshapelib/dbflib_wrap.c, libraries/pyshapelib/dbflib.py:
Update from dbflib.i

* libraries/pyshapelib/dbflib.i (DBFInfo_commit): New. Implementation of
the commit method.  This new indirection is necessary because we use the
DBFUpdateHeader function now which is not available in shapelib <=
1.2.10
(DBFFile::commit): Use DBFInfo_commit as implementation
(pragma __class__): New. Kludge to remove the commit method when
the DBFUpdateHeader function isn't available
(_have_commit): New. Helper for the pragma kludge.

* libraries/pyshapelib/setup.py (dbf_macros): New. Return the
preprocessor macros needed to compile the dbflib wrapper.  Determine
whether DBFUpdateHeader is available and define the right value of
HAVE_UPDATE_HEADER
(extensions): Use dbf_macros for the dbflibc extension

* setup.py (extensions): Add the HAVE_UPDATE_HEADER macro with
value '1' to the Lib.dbflibc extension.  This simply reflects the
shapelib and pyshapelib updates

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