/[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 2737 - (show annotations)
Tue Mar 13 22:55:33 2007 UTC (17 years, 11 months ago) by dpinte
File MIME type: text/x-python
File size: 44435 byte(s)
2007-03-12 Didrik Pinte <dpinte@itae.be>

    * setup.py : updated in order to use the new pyshapelib C module in place
    of the old SWIG one


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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26