/[thuban]/branches/WIP-pyshapelib-bramz/setup.py
ViewVC logotype

Diff of /branches/WIP-pyshapelib-bramz/setup.py

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.8  
changed lines
  Added in v.2590

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26