/[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 19 - (show annotations)
Tue Sep 4 15:11:27 2001 UTC (23 years, 6 months ago) by bh
Original Path: trunk/thuban/setup.py
File MIME type: text/x-python
File size: 24723 byte(s)
* MANIFEST.in: Add extensions/pyprojection/LICENSE

* setup.py (thuban_bdist_rpm): New class implementing a Thuban
specific bdist_rpm command.

* Thuban/UI/main.py: Catch ImportError exceptions when importing
the locale module because it may not be available on some
installations.

* extensions/pyprojection/LICENSE: Copy of the license text in
Projection.i. Having it in a separate file makes it easier to
refer to license text in e.g. RPMs

* setup.py: use wx-config instead of wxgtk-config because it's
more generic

* setup.py (ThubanInstall.get_outputs): Add the symlink in
<prefix>/bin to the outputs
(ThubanInstall.link_file): New method to link files. We need this
because the standard copy_files refuses to link non-existing
files.
(ThubanInstall.run): Remove the leading install root from the
script filename if an install root was specified and use the new
link_file method

1 # Copyright (c) 2001 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 from distutils.core import setup, Extension, Command
21 from distutils.command.install import install
22 from distutils.command.build_py import build_py
23 from distutils.command.bdist_rpm import bdist_rpm
24 from distutils.file_util import write_file
25 from distutils.util import convert_path, change_root
26
27 import distutils
28
29 from string import split
30 import string
31
32 if os.name == "posix":
33 ###################################################################
34 # Posix configuration. Adapt this if you're running some kind of
35 # Unix like system.
36
37 # Directories where Proj4 is installed
38 proj4_prefix = "/usr/local/"
39 proj4_incdir = os.path.join(proj4_prefix, "include")
40 proj4_libdir = os.path.join(proj4_prefix, "lib")
41 proj4_lib = "proj"
42
43
44 # You shpuldn't have to modify anything below here
45 ###################################################################
46
47 # The installation prefix (similar to autoconf's --prefix). This is
48 # only the default value, you can override it on the command line
49 # with the install command's --prefix option
50 prefix = "/usr/local/"
51
52 # On POSIX-systems we run wxgtk-config to determine the C++-compiler
53 # flags
54 wx_config_script = "wx-config"
55 # These lists will be filled automatically below
56 wx_defs = []
57 wx_incdirs = []
58 wx_libdirs = []
59 wx_libs = []
60
61 elif os.name == "nt":
62 #################################################################
63 # Windows configuration.
64 #
65
66 # Directories where Proj4 is installed
67 proj4_prefix = r"D:\cygwin\home\user\proj-4.4.3\src"
68 proj4_incdir = proj4_prefix
69 proj4_libdir = proj4_prefix
70 proj4_lib = "proj_i"
71
72 # Define include and lib directories for wxWindows and
73 wx_prefix = r"D:\wx230"
74 wx_inc = os.path.join(wx_prefix, "include")
75 wx_lib = os.path.join(wx_prefix, "lib")
76
77 #
78 # Unless you use a wxPython version other than 2.3.1, you probably
79 # shouldn't have to modify anything below here
80 ##################################################################
81
82 # Installation prefix. Just install relative to current directory by
83 # default. This is only the default value, you can override it on
84 # the command line with the install command's --prefix option
85 prefix = r"install"
86
87 # There doesn't seem to be an easy way to get at the wx compiler
88 # flags, so we define them here. These flags work for us with
89 # wxPython 2.3.1. They may have to be modified for other versions.
90
91 # there's no config script.
92 wx_config_script = ""
93
94 # the values of wx_defs and wx_libs. copied from the wxPython
95 # setup.py
96 wx_defs = [ ('WIN32', None), # Some of these are no longer
97 ('__WIN32__', None), # necessary. Anybody know which?
98 ('_WINDOWS', None),
99 ('__WINDOWS__', None),
100 ('WINVER', '0x0400'),
101 ('__WIN95__', None),
102 ('STRICT', None),
103
104 ('__WXMSW__', None),
105 ('WXUSINGDLL', '1'),
106
107 ('SWIG_GLOBAL', None),
108 ('HAVE_CONFIG_H', None),
109 ('WXP_USE_THREAD', '1'),
110 ]
111
112 wx_incdirs = [wx_inc]
113 wx_libdirs = [wx_lib]
114 wx_libs = ["wx23_1h"]
115 wx_libs = wx_libs + ['kernel32', 'user32', 'gdi32', 'comdlg32',
116 'winspool', 'winmm', 'shell32', 'oldnames',
117 'comctl32', 'ctl3d32', 'odbc32', 'ole32', 'oleaut32',
118 'uuid', 'rpcrt4', 'advapi32', 'wsock32']
119 else:
120 raise RuntimeError("Unsupported platform " + os.name)
121
122
123 ######################################################################
124 #
125 # There's nothing beyond this point that has to be modified for a
126 # normal installation
127 #
128 ######################################################################
129
130
131 #
132 # Functions to determine wxWindows config on POSIX systems
133 #
134
135 def run_script(cmdline):
136 """Run command and return its stdout or none in case of errors"""
137 pipe = os.popen(cmdline)
138 result = pipe.read()
139 if pipe.close() is not None:
140 print '"' + cmdline + '"', 'failed'
141 return None
142 return result
143
144
145 def run_wx_script(command):
146 # first, determine the C++ preprocessor flags Use --cflags here
147 # because it seems that older version don't have --cxxflags and
148 # newer ones return the same result for both
149 flags = run_script(command + ' --cflags ')
150 if flags is None:
151 return 0
152 for flag in split(flags):
153 start = flag[:2]
154 value = flag[2:]
155 if start == "-I":
156 wx_incdirs.append(value)
157 elif start == "-D":
158 wx_defs.append((value, None))
159
160 # determine the library flags
161 flags = run_script(command + ' --libs')
162 if flags is None:
163 return 0
164 for flag in split(flags):
165 start = flag[:2]
166 value = flag[2:]
167 if start == "-L":
168 wx_libdirs.append(value)
169 elif start == "-l":
170 wx_libs.append(value)
171
172 if wx_config_script:
173 # if there's a wx config script, run it to determine the configuration
174 run_wx_script(wx_config_script)
175
176
177
178 #
179 # Define some extension and python modules
180 #
181 # The C-extension names are prefixed woth "Lib." so they get put into
182 # the Lib/ subdirectory. Lib/ is not really a package but distutils
183 # doesn't care
184
185 # subdirectory containing the extensions
186 ext_dir = "extensions"
187
188 # subdirectory with some shapelib files
189 shp_dir = ext_dir + "/shapelib"
190
191 # lists to fill with the module descriptions
192 extensions = []
193 py_modules = []
194
195
196 #
197 # Thuban specific modules
198 #
199
200 extensions.append(Extension("Lib.wxproj",
201 [ext_dir + "/thuban/wxproj.cpp",
202 shp_dir + "/shpopen.c"],
203 include_dirs = [shp_dir, proj4_incdir] +wx_incdirs,
204 define_macros = wx_defs,
205 library_dirs = [proj4_libdir] + wx_libdirs,
206 libraries = [proj4_lib] + wx_libs))
207
208 #
209 # shapelib wrappers are also distributed with thuban
210 #
211
212 extensions.append(Extension("Lib.shapelibc",
213 [ext_dir + "/pyshapelib/shapelib_wrap.c",
214 shp_dir + "/shpopen.c"],
215 include_dirs = [shp_dir]))
216 extensions.append(Extension("Lib.dbflibc",
217 [ext_dir + "/pyshapelib/dbflib_wrap.c",
218 shp_dir + "/dbfopen.c"],
219 include_dirs = [shp_dir]))
220 for name in ("shapelib", "dbflib"):
221 py_modules.append(ext_dir + "/pyshapelib/" + name)
222
223 #
224 # PROJ4 bindings are also distributed with thuban
225 #
226 extensions.append(Extension("Lib.Projectionc",
227 [ext_dir + "/pyprojection/Projection_wrap.c"],
228 include_dirs = [proj4_incdir],
229 library_dirs = [proj4_libdir],
230 libraries = [proj4_lib]))
231 py_modules.append(ext_dir + "/pyprojection/Projection")
232
233
234 #
235 # Data files
236 #
237
238 data_files = []
239
240 # bitmaps
241 dir = "Resources/Bitmaps"
242 bitmaps = []
243 for file in os.listdir(os.path.join("Resources", "Bitmaps")):
244 if string.lower(file[-4:]) == ".xpm":
245 bitmaps.append(dir + '/' + file)
246 data_files.append((dir, bitmaps))
247
248 #
249 # Command definitions
250 #
251 # So far distutils are only meant to distribute python extensions, not
252 # complete applications, so we have to redefine a few commands
253
254
255
256 class InstallLocal(Command):
257
258 """
259 A new install command to just link (or copy, on non-POSIX systems)
260 the extension modules to the top directory so that Thuban can be run
261 directly from the source dir.
262 """
263
264 description =\
265 "Create some symlink so you can run thubanfrom the source directory"
266
267 user_options = [
268 ('skip-build', None, "skip the build steps"),
269 ]
270
271 def initialize_options (self):
272 self.extensions = None
273 self.build_dir = None
274 self.skip_build = None
275
276 def finalize_options (self):
277 self.set_undefined_options("install",
278 ("build_lib", "build_dir"),
279 ('skip_build', 'skip_build'))
280 self.extensions = self.distribution.ext_modules
281
282 def run(self):
283 # Make sure we have built everything we need first
284 self.build()
285
286 # now do the work. Simply link or copy the Lib dir
287 libdir = os.path.join(self.build_dir, "Lib")
288 if os.name == "posix":
289 # on posix, just lilnk the Lib dir
290 self.link_dir(libdir, "Lib")
291 else:
292 self.copy_tree(libdir, "Lib")
293
294 def link_dir(self, src, dest):
295 """Create a symbolic link dest pointing to src"""
296 if self.verbose:
297 self.announce("symlinking %s -> %s" % (src, dest))
298 if self.dry_run:
299 return
300
301 if not (os.path.exists(dest) and os.path.samefile(src, dest)):
302 os.symlink(src, dest)
303
304 def build (self):
305 if not self.skip_build:
306 if self.distribution.has_pure_modules():
307 self.run_command('build_py')
308 if self.distribution.has_ext_modules():
309 self.run_command('build_ext')
310
311
312
313 class thuban_build_py(build_py):
314
315 """
316 A new build_py that can deal with both packages and modules in one
317 distribution.
318 """
319
320 def run(self):
321 """The same the as the original in build_py revision 1.33 except
322 that this allows both packages and modules to be in one
323 distribution
324 """
325 if not self.py_modules and not self.packages:
326 return
327
328 # Now we're down to two cases: 'py_modules' only and 'packages' only.
329 if self.py_modules:
330 self.build_modules()
331 if self.packages:
332 self.build_packages()
333
334 self.byte_compile(self.get_outputs(include_bytecode=0))
335
336 def find_modules (self):
337 """Thuban specific version of build_py.find_modules. Unlike the
338 original version, we assume that the modules in self.py_modules
339 can contain directories and are all to be placed into the same
340 subdirectory, Lib, in the build directory. This is achieved by
341 returning the modules as a list (package, module, filename)
342 where package is 'Lib', module is the basename of the module name
343 and filename is the filename relative to the package root.
344 """
345 modules = []
346 for module in self.py_modules:
347 module_base = os.path.basename(module)
348 module_file = module + ".py"
349 if not self.check_module(module, module_file):
350 continue
351
352 modules.append(("Lib", module_base, module_file))
353 return modules
354
355 def find_all_modules (self):
356 # same as find_all_modules of the original build_py command
357 # (rev. 1.33) but handle installations with both modules and
358 # packages. Needed here so tha the get_outputs works correctly
359 modules = []
360 if self.py_modules:
361 modules.extend(self.find_modules())
362 if self.packages:
363 for package in self.packages:
364 package_dir = self.get_package_dir(package)
365 m = self.find_package_modules(package, package_dir)
366 modules.extend(m)
367
368 return modules
369
370
371
372 class ThubanInstall(install):
373
374 """
375 Thuban specific install command.
376
377 Extend the standard install command to symlink the installed script
378 to $prefix/bin/
379 """
380
381 user_options = install.user_options[:]
382 user_options.extend([("do-symlink", None,
383 "Create a symlink to the script in <prefix>/bin."
384 "(default on posix systems and only relevant there)"),
385
386 ("extra-files", None,
387 "List of filenames or (src, dest) pairs describing "
388 " extra files to install "
389 "(can only be set from witin setup.py"),
390 ])
391
392 boolean_options = install.boolean_options[:]
393 boolean_options.append("do-symlink")
394
395 def initialize_options(self):
396 self.do_symlink = None
397 self.extra_files = []
398 install.initialize_options(self)
399
400 def finalize_options(self):
401 if self.do_symlink is None:
402 if os.name == "posix":
403 self.do_symlink = 1
404 else:
405 self.do_symlink = 0
406 install.finalize_options(self)
407
408 def run(self):
409 install.run(self)
410 for item in self.extra_files:
411 if type(item) == TupleType:
412 src, dest = item
413 else:
414 src = dest = item
415 self.copy_file(convert_path(src),
416 os.path.join(self.root, convert_path(dest)))
417
418 if os.name == "posix" and self.do_symlink:
419 install_scripts = self.install_scripts
420 if self.root:
421 install_scripts = install_scripts[len(self.root):]
422 scriptfile = os.path.join(install_scripts, "thuban.py")
423 bindir = os.path.join(self.prefix, "bin")
424 if self.root:
425 bindir = change_root(self.root, bindir)
426 binfile = os.path.join(bindir, "thuban")
427 self.mkpath(bindir)
428 self.link_file(scriptfile, binfile)
429
430 def link_file(self, src, dest):
431 """Create a symbolic link dest pointing to src.
432
433 Unlike the symlink variant of the command object's copy_file
434 method, this method even performs the link if src doesn't exist.
435 This is useful when installing with an alternat root directory"""
436 if self.verbose:
437 self.announce("symlinking %s -> %s" % (src, dest))
438 if self.dry_run:
439 return
440
441 if not os.path.exists(dest):
442 os.symlink(src, dest)
443
444
445 def get_outputs (self):
446 outputs = install.get_outputs(self)
447 for item in self.extra_files:
448 if type(item) == TupleType:
449 src, dest = item
450 else:
451 src = dest = item
452 outputs.append(os.path.join(self.root, convert_path(dest)))
453 if os.name == "posix" and self.do_symlink:
454 bindir = os.path.join(self.prefix, "bin")
455 if self.root:
456 bindir = change_root(self.root, bindir)
457 binfile = os.path.join(bindir, "thuban")
458 outputs.append(binfile)
459 return outputs
460
461
462 bdist_rpm_prep_script = '''
463 %setup
464 cp extensions/pyshapelib/{README,README.pyshapelib}
465 cp extensions/pyshapelib/{COPYING,COPYING.pyshapelib}
466 cp extensions/pyprojection/{LICENSE,LICENSE.pyprojection}
467 '''
468
469
470
471 class thuban_bdist_rpm(bdist_rpm):
472
473 """Thuban specific RPM distribution command"""
474
475 def run(self):
476 # create the prep script for the spec-file
477 open("bdist_rpm_prep", "w").write(bdist_rpm_prep_script)
478
479 bdist_rpm.run(self)
480
481
482 class bdist_inno(Command):
483
484 """Command to create a windows installer with Inno Setup"""
485
486 description = "Create a windows installer with Inno Setup"
487
488 user_options = [
489 ('skip-build', None, "skip the build steps"),
490 ('bdist-dir=', None,
491 "temporary directory for creating the distribution"),
492 ('run-inno', None,
493 "Run inno-setup to create the installer. On by default on nt"),
494 ('iss-name', None,
495 "The name of the iss file to generate. "
496 "Shouldn't contain directories"),
497
498 # Parameters for the Inno Setup script
499 ('copyright', None, "Copyright notice for the Inno Setup file"),
500 ('default-dir-name', None,
501 "Default installation directory. Defaults to '{pf}\\<name>'"),
502 ('default-group-name', None,
503 "Default program group name. Defaults to <name>'"),
504 ("license-file", None, "File containing the license."),
505 ("output-basename", None,
506 "Base filename for the Inno Setup output "
507 "(defaults to <name>-<version>-<issrevision>)."),
508 ("iss-revision", None,
509 "revision of the generated installer of the package version"),
510
511 ("icons-entries", None,
512 "List if InnoIconItems "
513 "(this can only be set from inside the setup.py script)"),
514 ]
515
516 boolean_options = ["do-symlink"]
517
518 def initialize_options(self):
519 self.skip_build = 0
520 self.bdist_dir = None
521 self.run_inno = None
522 self.iss_name = None
523 self.copyright = ""
524 self.default_dir_name = None
525 self.default_group_name = None
526 self.license_file = None
527 self.output_basename = None
528 self.iss_revision = None
529 self.icons_entries = []
530
531 def finalize_options(self):
532 self.set_undefined_options("install",
533 ('skip_build', 'skip_build'))
534 if self.bdist_dir is None:
535 bdist_base = self.get_finalized_command('bdist').bdist_base
536 self.bdist_dir = os.path.join(bdist_base, 'inno')
537
538 if self.run_inno is None:
539 self.run_inno = os.name == "nt"
540
541 name = self.distribution.get_name()
542 if self.iss_name is None:
543 self.iss_name = name + '.iss'
544
545 if self.default_dir_name is None:
546 self.default_dir_name = "{pf}\\" + name
547 if self.default_group_name is None:
548 self.default_group_name = name
549
550 if self.iss_revision is None:
551 self.iss_revision = 0
552 if self.output_basename is None:
553 self.output_basename = "%s-%s-%d" \
554 % (name, self.distribution.get_version(),
555 self.iss_revision)
556
557 def run(self, install_options = None):
558 """Execute the command. install_options if given, should be a
559 directory of additional options to set in the install step"""
560 # Obviously have to build before we can install
561 if not self.skip_build:
562 self.run_command('build')
563
564 # Install in a temporary directory
565 install = self.reinitialize_command('install')
566 install.root = self.bdist_dir
567 if install_options is not None:
568 for key, value in install_options.items():
569 setattr(install, key, value)
570 if os.name != 'nt':
571 # Must force install to use the 'nt' scheme;
572 install.select_scheme('nt')
573 # don't make a symlink because we're simulating windows, so
574 # that we can generate the iss-file even on Linux
575 install.do_symlink = 0
576
577 self.announce("installing to %s" % self.bdist_dir)
578 install.ensure_finalized()
579 install.run()
580
581 # Create the iss file
582 iss_file = os.path.join(self.bdist_dir, self.iss_name)
583 self.execute(write_file, (iss_file, self.generate_iss()),
584 "Create Inno Setup script file %s" % iss_file)
585
586 # and invoke
587 if self.run_inno:
588 self.spawn(["iscc", iss_file])
589
590 def generate_iss(self):
591 """Return the contents of the iss file as list of strings, one
592 string per line"""
593
594 # first, turn the icons entries into a more usable form
595 icons = {}
596 for item in self.icons_entries:
597 icons[item.filename] = item
598
599 iss = []
600
601 name = self.distribution.get_name()
602 iss.extend(["[Setup]",
603 "AppName=" + name,
604 "AppVerName=" + name + " "+self.distribution.get_version(),
605 "DefaultDirName=" + self.default_dir_name,
606 "DefaultGroupName=" + self.default_group_name,
607 ])
608 if self.copyright:
609 iss.append("AppCopyright=" + self.copyright)
610 if self.license_file:
611 iss.append("LicenseFile=" + self.license_file)
612
613 iss.append("OutputBasefilename=" + self.output_basename)
614
615 iss.append("")
616 iss.append("[Files]")
617
618 install = self.get_finalized_command("install")
619 install_scripts = self.get_finalized_command("install_scripts")
620 script_files = install_scripts.get_outputs()
621 prefixlen = len(self.bdist_dir) + len(os.sep)
622 for filename in install.get_outputs():
623 filename = filename[prefixlen:]
624 icon = icons.get(filename)
625 dirname = os.path.dirname(filename)
626 if os.name != "nt":
627 # change the separators to \ on non-windos systems
628 filename = string.join(string.split(filename, os.sep), "\\")
629 dirname = string.join(string.split(dirname, os.sep), "\\")
630 line = 'Source: "%s"' % filename
631 if icon is not None:
632 # install it as defined in the icon object
633 backslash = string.rfind(icon.install_name, "\\")
634 if backslash >= 0:
635 dirname = icon.install_name[:backslash]
636 basename = icon.install_name[backslash + 1:]
637 else:
638 dirname = ""
639 basename = icon.install_name
640 line = '%s; DestDir: "%s"; DestName: "%s"' % (line, dirname,
641 basename)
642 else:
643 line = line + '; DestDir: "{app}\\%s"' % (dirname)
644 iss.append(line)
645
646 iss.append("")
647 iss.append("[Icons]")
648 for icon in self.icons_entries:
649 line = 'Name: "{group}\\%s"; Filename: "%s";' \
650 % (icon.title, icon.install_name)
651 iss.append(line)
652
653 return iss
654
655
656 class InnoIconItem:
657
658 """Describe one item for he start menu for the Inno Setup installer"""
659
660 def __init__(self, filename, title, install_name = None):
661 self.filename = filename
662 self.title = title
663 if install_name is not None:
664 self.install_name = install_name
665 else:
666 self.install_name = filename
667
668
669 class thuban_bdist_inno(bdist_inno):
670
671 """Thuban specific Inno Setup stuff"""
672
673 def run(self):
674 install_options = {
675 "prefix": ".",
676 "install_scripts": "$base",
677 "warn_dir": 0,
678 "extra_files": ["COPYING", "Lib/proj.dll"],
679 }
680 bdist_inno.run(self, install_options)
681
682
683 #
684 # Run the script
685 #
686
687
688 long_description = """\
689 Thuban is a viewer for geographic data written in Python
690 """
691
692 setup(name = "Thuban",
693 version = "0.0.3",
694 description = "Geographic data viewer",
695 long_description = long_description,
696 licence = "GPL",
697 author = "Intevation GmbH",
698 author_email = "[email protected]",
699 url = "ftp:intevation.de/",
700
701 scripts = ["thuban.py"],
702 packages = ["Thuban", "Thuban.Lib", "Thuban.Model", "Thuban.UI"],
703 ext_modules = extensions,
704 py_modules = py_modules,
705 data_files = data_files,
706
707 # defaults for the install command
708 options = {"install":
709 # prefix defaults to python's prefix normally
710 {"prefix": prefix,
711 # make sure both libs and scripts are installed in the
712 # same directory.
713 "install_lib": "$base/thuban",
714 "install_scripts": "$base/thuban",
715 "install_data": "$base/thuban",
716
717 # Don't print warning messages about the lib dir not
718 # being on Python's path. The libraries are Thuban
719 # specific and are installed just for Thuban. They'll
720 # be automatically on Python's path when Thuban is run
721 "warn_dir": 0,
722 },
723 "bdist_inno":
724 {"icons_entries": [InnoIconItem(".\\thuban.py",
725 "Start Thuban",
726 "{app}\\thuban.pyw")],
727 "license_file": "COPYING",
728 }
729 },
730 cmdclass = {"build_py": thuban_build_py,
731 "install_local": InstallLocal,
732 "install": ThubanInstall,
733 "bdist_rpm": thuban_bdist_rpm,
734 "bdist_inno": thuban_bdist_inno
735 })
736
737

Properties

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26