/[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 2024 - (show annotations)
Fri Dec 5 16:45:19 2003 UTC (21 years, 3 months ago) by bh
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 42066 byte(s)
* MANIFEST.in: Add the devtools directory

* setup.py (setup call): Use license instead of licence. This
silences a deprecation warning on Python 2.3

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26