/[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 2742 - (show annotations)
Wed Mar 14 16:26:14 2007 UTC (17 years, 11 months ago) by bramz
File MIME type: text/x-python
File size: 44351 byte(s)
pyshapelib: rewritten dbflib to use hand-crafted Python bindings instead of SWIG generated ones.

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26