/[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 1229 - (show 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 # Copyright (c) 2001, 2002, 2003 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\proj-4.4.3\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
92 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
97 # 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
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 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 [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 for name in ("shapelib", "dbflib"):
280 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 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
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 #
311
312
313 # Much of the data_dist command is directly copied from the distutils'
314 # sdist command
315 class data_dist(Command):
316
317 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 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 "Create some symlinks so you can run thuban from the source directory"
451
452 user_options = [
453 ('skip-build', None, "skip the build steps"),
454 ('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 ]
459
460 boolean_options = ["create-init-module"]
461 negative_opt = {'dont-create-init-module' : 'create-init-module'}
462
463
464 def initialize_options (self):
465 self.extensions = None
466 self.build_dir = None
467 self.skip_build = None
468 self.create_init_module = None
469
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 if self.create_init_module is None:
476 # by default we create the init module
477 self.create_init_module = 1
478
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 # on posix, just link the Lib dir
487 self.link_dir(libdir, "Lib")
488 else:
489 self.copy_tree(libdir, "Lib")
490
491 # 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 def link_dir(self, src, dest):
500 """Create a symbolic link dest pointing to src"""
501 if self.verbose:
502 self.announce("symlinking %s -> %s" % (src, dest))
503 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 A new build_py that can deal with both packages and modules in one
522 distribution.
523 """
524
525 # 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 def run(self):
531 """The same the as the original in build_py revision 1.33 except
532 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 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
578 return modules
579
580
581 thubaninit_contents_start = """
582 # 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
587 Usage:
588
589 import thubaninit
590 import Thuban
591 '''
592 import sys, os
593 """
594
595 thubaninit_contents_thubaninitdir = """
596 sys.path.insert(0, %(thubandir)s)
597 """
598 thubaninit_contents_otherdirs = """
599 # 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 def thubaninit_contents(thubandir):
609 """Return the contents of the the thubaninit file as a list of lines.
610
611 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 class ThubanInstall(install):
624
625 """
626 Thuban specific install command.
627
628 Extend the standard install command to symlink the installed script
629 to $prefix/bin/
630 """
631
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 "List of filenames or (src, dest) pairs describing"
639 " extra files to install "
640 "(can only be set from within setup.py"),
641
642 ("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 "Directory in which to create the init module."
648 " Defaults to Python's site-packages directory."),
649 ])
650
651 boolean_options = install.boolean_options[:]
652 boolean_options.append("do-symlink")
653 boolean_options.append("create-init-module")
654
655 def initialize_options(self):
656 self.do_symlink = None
657 self.extra_files = []
658
659 # initialize the create_init_module flag from the global
660 # determined at runtime
661 self.create_init_module = create_init_module
662 self.init_module_dir = None
663 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 self.expand_with_pure_python_dirs(["init_module_dir"])
673
674 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 def run(self):
707 install.run(self)
708 for item in self.extra_files:
709 if type(item) == TupleType:
710 src, dest = item
711 else:
712 src = dest = item
713 self.copy_file(convert_path(src),
714 os.path.join(self.root, convert_path(dest)))
715
716 if os.name == "posix" and self.do_symlink:
717 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 bindir = os.path.join(self.prefix, "bin")
722 if self.root:
723 bindir = change_root(self.root, bindir)
724 binfile = os.path.join(bindir, "thuban")
725 self.mkpath(bindir)
726 self.link_file(scriptfile, binfile)
727
728 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 contents = thubaninit_contents(self.install_lib_orig)
734 self.mkpath(os.path.dirname(initfilename))
735 self.execute(write_file, (initfilename, contents),
736 "Create %s" % initfilename)
737
738 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 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
758 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 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 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 return outputs
778
779
780 # scripts to override some of the commands put into the spec-file by the
781 # bdist_rpm command.
782
783 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 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 bdist_rpm_install_script = '''
795 %(python)s setup.py install --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES \
796 --prefix=%(prefix)s
797 '''
798
799
800 class thuban_bdist_rpm(bdist_rpm):
801
802 """Thuban specific RPM distribution command"""
803
804 user_options = bdist_rpm.user_options[:]
805 user_options.extend([("prefix=", None, "Install prefix for the RPM"),
806 ])
807
808 def initialize_options(self):
809 # per default, RPMs are installed in /usr
810 self.prefix = "/usr/"
811
812 # 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 open("bdist_rpm_build", "w").close()
818 open("bdist_rpm_install", "w").close()
819 bdist_rpm.initialize_options(self)
820
821 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
826 build = bdist_rpm_build_script % {"python": self.python,
827 "prefix": self.prefix}
828 open("bdist_rpm_build", "w").write(build)
829
830 install = bdist_rpm_install_script % {"python": self.python,
831 "prefix": self.prefix}
832 open("bdist_rpm_install", "w").write(install)
833
834 #
835 return bdist_rpm._make_spec_file(self)
836
837
838 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
918 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 # and invoke
941 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
1007 return iss
1008
1009
1010 class InnoIconItem:
1011
1012 """Describe one item for the start menu for the Inno Setup installer"""
1013
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
1023 class thuban_bdist_inno(bdist_inno):
1024
1025 """Thuban specific Inno Setup stuff"""
1026
1027 def run(self):
1028 install_options = {
1029 "prefix": ".",
1030 "install_lib": "$base",
1031 "install_data": "$base",
1032 "install_scripts": "$base",
1033 "warn_dir": 0,
1034 "extra_files": ["COPYING", "Lib/proj.dll"],
1035 }
1036 # 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
1040 bdist_inno.run(self, install_options)
1041
1042 class thuban_build_docs(Command):
1043
1044 """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 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 #
1092 # Run the script
1093 #
1094
1095 long_description = """\
1096 Thuban is a viewer for geographic data written in Python
1097 """
1098
1099 setup(name = "Thuban",
1100 version = "0.2.0",
1101 description = "Geographic data viewer",
1102 long_description = long_description,
1103 licence = "GPL",
1104 author = "Intevation GmbH",
1105 author_email = "[email protected]",
1106 url = "http://thuban.intevation.de/",
1107
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 "install_lib": "$base/lib/thuban",
1121 "install_scripts": "$base/lib/thuban",
1122 "install_data": "$base/lib/thuban",
1123
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 },
1130 "bdist_inno":
1131 {"icons_entries": [InnoIconItem(".\\thuban.py",
1132 "Start Thuban",
1133 "{app}\\thuban.pyw")],
1134 "license_file": "COPYING",
1135 }
1136 },
1137 cmdclass = {"build_py": thuban_build_py,
1138 "install_local": InstallLocal,
1139 "install": ThubanInstall,
1140 "bdist_rpm": thuban_bdist_rpm,
1141 "bdist_inno": thuban_bdist_inno,
1142 "data_dist": data_dist,
1143 "build_docs": thuban_build_docs,
1144 "build_ext": thuban_build_ext
1145 })
1146
1147

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26