/[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 2562 - (show annotations)
Wed Feb 16 21:14:47 2005 UTC (20 years ago) by jonathan
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 42187 byte(s)
Further wxPython 2.5 changes using patches from Daniel Calvelo Aros
so that that wxproj doesn't crash. Added GUI support for selecting
alpha channel (opacity can't be selected yet).

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

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26