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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2212 - (show 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 # Copyright (c) 2001, 2002, 2003, 2004 by Intevation GmbH
2 # 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 from types import TupleType
20 import glob
21 from distutils.core import setup, Extension, Command
22 from distutils.command.install import install, INSTALL_SCHEMES, subst_vars
23 from distutils.command.build_py import build_py
24 from distutils.command.bdist_rpm import bdist_rpm
25 from distutils.command.build_ext import build_ext
26 from distutils.file_util import write_file
27 from distutils.filelist import FileList
28 from distutils.util import convert_path, change_root
29
30 from distutils import archive_util, dir_util
31 import distutils
32
33 from string import split
34 import string
35
36 # 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 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 # You shouldn't have to modify anything below here
56 ###################################################################
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 # with the install command's --prefix option.
61 #
62 # Note that there's a separate prefix option for the bdist_rpm
63 # command completely independent of this one.
64 prefix = "/usr/local/"
65
66 # 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 # On POSIX-systems we run wxgtk-config to determine the C++-compiler
72 # flags
73 wx_config_script = "wx-config"
74 # These lists will be filled automatically below
75 wx_cs_params = [[] for i in range(CS_NUM_PARAMS)]
76
77 gdal_config_script = "gdal-config"
78 gdal_cs_params = [[] for i in range(CS_NUM_PARAMS)]
79
80 elif os.name == "nt":
81 #################################################################
82 # Windows configuration.
83 #
84
85 # Directories where Proj4 is installed
86 proj4_prefix = r"D:\cygwin\home\user\projects\thuban\proj-4.4.7\src"
87 proj4_incdir = proj4_prefix
88 proj4_libdir = proj4_prefix
89 proj4_lib = "proj_i"
90
91 # Define include and lib directories for wxWindows and
92 wx_prefix = r"d:\cygwin\home\user\projects\thuban\wxPython-2.4.0.7"
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
97 # Define include and lib directories for GDAL
98 gdal_prefix = r"D:\cygwin\home\user\projects\thuban\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
105 #
106 # Unless you use a wxPython version other than 2.4.0, you probably
107 # 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 # 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 # 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 wx_cs_params = [[] for i in range(CS_NUM_PARAMS)]
131
132 # the values of wx_defs and wx_libs. copied from the wxPython
133 # setup.py
134 wx_cs_params[CS_DEFS] = \
135 [ ('WIN32', None), # Some of these are no longer
136 ('__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 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 'winspool', 'winmm', 'shell32', 'oldnames',
156 'comctl32', 'ctl3d32', 'odbc32', 'ole32', 'oleaut32',
157 'uuid', 'rpcrt4', 'advapi32', 'wsock32']
158
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 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 def run_cs_script(command, store):
193 # 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 if flags is None:
198 return False
199 for flag in split(flags):
200 start = flag[:2]
201 value = flag[2:]
202 if start == "-I":
203 store[CS_INCDIRS].append(value)
204 elif start == "-D":
205 store[CS_DEFS].append((value, None))
206
207 # determine the library flags
208 flags = run_script(command + ' --libs')
209 if flags is None:
210 return False
211 for flag in split(flags):
212 start = flag[:2]
213 value = flag[2:]
214 if start == "-L":
215 store[CS_LIBDIRS].append(value)
216 elif start == "-l":
217 store[CS_LIBS].append(value)
218
219 return True
220
221 if wx_config_script:
222 # if there's a wx config script, run it to determine the configuration
223 run_cs_script(wx_config_script, wx_cs_params)
224
225 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
230 #
231 # Define some extension and python modules
232 #
233 # The C-extension names are prefixed with "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 distutil extensions
238 ext_dir = "libraries"
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 [ext_dir + "/thuban/wxproj.cpp"],
254 include_dirs = ([shp_dir, proj4_incdir,
255 ext_dir + "/pyshapelib/"]
256 + 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
262
263 #
264 # shapelib wrappers are also distributed with thuban
265 #
266
267 extensions.append(Extension("Lib.shapelibc",
268 [ext_dir + "/pyshapelib/shapelib_wrap.c",
269 shp_dir + "/shpopen.c",
270 shp_dir + "/shptree.c"],
271 include_dirs = [shp_dir]))
272 extensions.append(Extension("Lib.shptree",
273 [ext_dir + "/pyshapelib/shptreemodule.c"],
274 include_dirs = [shp_dir]))
275 extensions.append(Extension("Lib.dbflibc",
276 [ext_dir + "/pyshapelib/dbflib_wrap.c",
277 shp_dir + "/dbfopen.c"],
278 include_dirs = [shp_dir],
279 define_macros = [("HAVE_UPDATE_HEADER", "1")]))
280 for name in ("shapelib", "dbflib"):
281 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 # Resources
301 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 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
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 #
324
325
326 # Much of the data_dist command is directly copied from the distutils'
327 # sdist command
328 class data_dist(Command):
329
330 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 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 "Create some symlinks so you can run thuban from the source directory"
464
465 user_options = [
466 ('skip-build', None, "skip the build steps"),
467 ('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 ]
472
473 boolean_options = ["create-init-module"]
474 negative_opt = {'dont-create-init-module' : 'create-init-module'}
475
476
477 def initialize_options (self):
478 self.extensions = None
479 self.build_dir = None
480 self.skip_build = None
481 self.create_init_module = None
482
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 if self.create_init_module is None:
489 # by default we create the init module
490 self.create_init_module = 1
491
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 # on posix, just link the Lib dir
500 self.link_dir(libdir, "Lib")
501 else:
502 self.copy_tree(libdir, "Lib")
503
504 # 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 def link_dir(self, src, dest):
513 """Create a symbolic link dest pointing to src"""
514 if self.verbose:
515 self.announce("symlinking %s -> %s" % (src, dest))
516 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 A new build_py that can deal with both packages and modules in one
535 distribution.
536 """
537
538 # 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 def run(self):
544 """The same the as the original in build_py revision 1.33 except
545 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 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
591 return modules
592
593
594 thubaninit_contents_start = """
595 # 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
600 Usage:
601
602 import thubaninit
603 import Thuban
604 '''
605 import sys, os
606 """
607
608 thubaninit_contents_thubaninitdir = """
609 sys.path.insert(0, %(thubandir)s)
610 """
611 thubaninit_contents_otherdirs = """
612 # 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 def thubaninit_contents(thubandir):
622 """Return the contents of the the thubaninit file as a list of lines.
623
624 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 class ThubanInstall(install):
637
638 """
639 Thuban specific install command.
640
641 Extend the standard install command to symlink the installed script
642 to $prefix/bin/
643 """
644
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 "List of filenames or (src, dest) pairs describing"
652 " extra files to install "
653 "(can only be set from within setup.py"),
654
655 ("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 "Directory in which to create the init module."
661 " Defaults to Python's site-packages directory."),
662 ])
663
664 boolean_options = install.boolean_options[:]
665 boolean_options.append("do-symlink")
666 boolean_options.append("create-init-module")
667
668 def initialize_options(self):
669 self.do_symlink = None
670 self.extra_files = []
671
672 # initialize the create_init_module flag from the global
673 # determined at runtime
674 self.create_init_module = create_init_module
675 self.init_module_dir = None
676 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 self.expand_with_pure_python_dirs(["init_module_dir"])
686
687 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 def run(self):
720 install.run(self)
721 for item in self.extra_files:
722 if type(item) == TupleType:
723 src, dest = item
724 else:
725 src = dest = item
726 self.copy_file(convert_path(src),
727 os.path.join(self.root, convert_path(dest)))
728
729 if os.name == "posix" and self.do_symlink:
730 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 bindir = os.path.join(self.prefix, "bin")
735 if self.root:
736 bindir = change_root(self.root, bindir)
737 binfile = os.path.join(bindir, "thuban")
738 self.mkpath(bindir)
739 self.link_file(scriptfile, binfile)
740
741 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 contents = thubaninit_contents(self.install_lib_orig)
747 self.mkpath(os.path.dirname(initfilename))
748 self.execute(write_file, (initfilename, contents),
749 "Create %s" % initfilename)
750
751 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 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
771 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 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 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 return outputs
791
792
793 # scripts to override some of the commands put into the spec-file by the
794 # bdist_rpm command.
795
796 bdist_rpm_prep_script = '''
797 %setup
798 cp libraries/pyshapelib/{README,README.pyshapelib}
799 cp libraries/pyshapelib/{COPYING,COPYING.pyshapelib}
800 cp libraries/pyprojection/{LICENSE,LICENSE.pyprojection}
801 '''
802
803 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 bdist_rpm_install_script = '''
808 %(python)s setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES \
809 --prefix=%(prefix)s
810 '''
811
812
813 class thuban_bdist_rpm(bdist_rpm):
814
815 """Thuban specific RPM distribution command"""
816
817 user_options = bdist_rpm.user_options[:]
818 user_options.extend([("prefix=", None, "Install prefix for the RPM"),
819 ])
820
821 def initialize_options(self):
822 # per default, RPMs are installed in /usr
823 self.prefix = "/usr/"
824
825 # 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 open("bdist_rpm_build", "w").close()
831 open("bdist_rpm_install", "w").close()
832 bdist_rpm.initialize_options(self)
833
834 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
839 build = bdist_rpm_build_script % {"python": self.python,
840 "prefix": self.prefix}
841 open("bdist_rpm_build", "w").write(build)
842
843 install = bdist_rpm_install_script % {"python": self.python,
844 "prefix": self.prefix}
845 open("bdist_rpm_install", "w").write(install)
846
847 #
848 return bdist_rpm._make_spec_file(self)
849
850
851 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
931 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 # and invoke
954 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
1020 return iss
1021
1022
1023 class InnoIconItem:
1024
1025 """Describe one item for the start menu for the Inno Setup installer"""
1026
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
1036 class thuban_bdist_inno(bdist_inno):
1037
1038 """Thuban specific Inno Setup stuff"""
1039
1040 def run(self):
1041 install_options = {
1042 "prefix": ".",
1043 "install_lib": "$base",
1044 "install_data": "$base",
1045 "install_scripts": "$base",
1046 "warn_dir": 0,
1047 "extra_files": ["COPYING", "Lib/proj.dll"],
1048 }
1049 # 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
1053 bdist_inno.run(self, install_options)
1054
1055 class thuban_build_docs(Command):
1056
1057 """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 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 include_dirs = gdal_cs_params[CS_INCDIRS] +
1095 [ext_dir + "/thuban/"],
1096 define_macros = gdal_cs_params[CS_DEFS],
1097 library_dirs = gdal_cs_params[CS_LIBDIRS],
1098 libraries = gdal_cs_params[CS_LIBS]))
1099
1100 def run(self, install_options = None):
1101 build_ext.run(self)
1102
1103 #
1104 # Run the script
1105 #
1106
1107 long_description = """\
1108 Thuban is a viewer for geographic data written in Python
1109 """
1110
1111 setup(name = "Thuban",
1112 version = "1.0.0",
1113 description = "Geographic data viewer",
1114 long_description = long_description,
1115 license = "GPL",
1116 author = "Intevation GmbH",
1117 author_email = "[email protected]",
1118 url = "http://thuban.intevation.de/",
1119
1120 scripts = ["thuban.py"],
1121 packages = ["Thuban", "Thuban.Lib", "Thuban.Model", "Thuban.UI",
1122 "Extensions", "Extensions.gns2shp", "Extensions.wms",
1123 "Extensions.importAPR", "Extensions.profiling"],
1124 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 "install_lib": "$base/lib/thuban",
1135 "install_scripts": "$base/lib/thuban",
1136 "install_data": "$base/lib/thuban",
1137
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 },
1144 "bdist_inno":
1145 {"icons_entries": [InnoIconItem(".\\thuban.py",
1146 "Start Thuban",
1147 "{app}\\thuban.pyw")],
1148 "license_file": "COPYING",
1149 }
1150 },
1151 cmdclass = {"build_py": thuban_build_py,
1152 "install_local": InstallLocal,
1153 "install": ThubanInstall,
1154 "bdist_rpm": thuban_bdist_rpm,
1155 "bdist_inno": thuban_bdist_inno,
1156 "data_dist": data_dist,
1157 "build_docs": thuban_build_docs,
1158 "build_ext": thuban_build_ext
1159 })
1160
1161

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26