/[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 90 by bh, Thu Apr 4 14:55:02 2002 UTC
# Line 1  Line 1 
1  # Copyright (c) 2001 by Intevation GmbH  # Copyright (c) 2001, 2002 by Intevation GmbH
2  # Authors:  # Authors:
3  # Bernhard Herzog <[email protected]>  # Bernhard Herzog <[email protected]>
4  #  #
# Line 16  __version__ = "$Revision$" Line 16  __version__ = "$Revision$"
16  #  #
17    
18  import os  import os
19    from types import TupleType
20  from distutils.core import setup, Extension, Command  from distutils.core import setup, Extension, Command
21  from distutils.command.install import install  from distutils.command.install import install
22  from distutils.command.build_py import build_py  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.filelist import FileList
26    from distutils.util import convert_path, change_root
27    
28    from distutils import archive_util, dir_util
29  import distutils  import distutils
 print distutils.__file__  
30    
31  from string import split  from string import split
32  import string  import string
# Line 48  if os.name == "posix": Line 53  if os.name == "posix":
53    
54      # On POSIX-systems we run wxgtk-config to determine the C++-compiler      # On POSIX-systems we run wxgtk-config to determine the C++-compiler
55      # flags      # flags
56      wx_config_script = "wxgtk-config"      wx_config_script = "wx-config"
57      # These lists will be filled automatically below      # These lists will be filled automatically below
58      wx_defs = []      wx_defs = []
59      wx_incdirs = []      wx_incdirs = []
# Line 66  elif os.name == "nt": Line 71  elif os.name == "nt":
71      proj4_libdir =  proj4_prefix      proj4_libdir =  proj4_prefix
72      proj4_lib = "proj_i"      proj4_lib = "proj_i"
73    
74        # Define include and lib directories for wxWindows and
75        wx_prefix = r"D:\wx230"
76        wx_inc =  os.path.join(wx_prefix, "include")
77        wx_lib =  os.path.join(wx_prefix, "lib")
78    
79      #      #
80      # Unless you use a wxPython version other than 2.3.1, you probably      # Unless you use a wxPython version other than 2.3.1, you probably
81      # shouldn't have to modify anything below here      # shouldn't have to modify anything below here
# Line 83  elif os.name == "nt": Line 93  elif os.name == "nt":
93      # there's no config script.      # there's no config script.
94      wx_config_script = ""      wx_config_script = ""
95            
     # so we just define the flags manually  
     wx_prefix = r"D:\wx230"  
     wx_inc =  os.path.join(wx_prefix, "include")  
     wx_lib =  os.path.join(wx_prefix, "lib")  
96      # the values of wx_defs and wx_libs. copied from the wxPython      # the values of wx_defs and wx_libs. copied from the wxPython
97      # setup.py      # setup.py
98      wx_defs = [ ('WIN32', None),        # Some of these are no longer      wx_defs = [ ('WIN32', None),        # Some of these are no longer
# Line 139  def run_script(cmdline): Line 145  def run_script(cmdline):
145    
146    
147  def run_wx_script(command):  def run_wx_script(command):
148      # first, determine the C++ preprocessor flags      # first, determine the C++ preprocessor flags Use --cflags here
149      flags = run_script(command + ' --cxxflags ')      # because it seems that older version don't have --cxxflags and
150        # newer ones return the same result for both
151        flags = run_script(command + ' --cflags ')
152      if flags is None:      if flags is None:
153          return 0          return 0
154      for flag in split(flags):      for flag in split(flags):
# Line 232  py_modules.append(ext_dir + "/pyprojecti Line 240  py_modules.append(ext_dir + "/pyprojecti
240  data_files = []  data_files = []
241    
242  # bitmaps  # bitmaps
243  dir = "Resources/Bitmaps/"  dir = "Resources/Bitmaps"
244  bitmaps = []  bitmaps = []
245  for file in os.listdir(os.path.join("Resources", "Bitmaps")):  for file in os.listdir(os.path.join("Resources", "Bitmaps")):
246      if string.lower(file[-4:]) == ".xpm":      if string.lower(file[-4:]) == ".xpm":
247          bitmaps.append(dir + file)          bitmaps.append(dir + '/' +  file)
248  data_files.append((dir, bitmaps))  data_files.append((dir, bitmaps))
249    
250  #  #
# Line 244  data_files.append((dir, bitmaps)) Line 252  data_files.append((dir, bitmaps))
252  #  #
253  # So far distutils are only meant to distribute python extensions, not  # So far distutils are only meant to distribute python extensions, not
254  # complete applications, so we have to redefine a few commands  # complete applications, so we have to redefine a few commands
255    #
256    
257    
258    # Much of the data_dist command is directly copied from the distutils'
259    # sdist command
260    class data_dist(Command):
261    
262        description = "create a data distribution (tarball, zip file, etc.)"
263    
264        user_options = [
265            ('formats=', None,
266             "formats for source distribution (comma-separated list)"),
267            ('keep-temp', 'k',
268             "keep the distribution tree around after creating " +
269             "archive file(s)"),
270            ('dist-dir=', 'd',
271             "directory to put the source distribution archive(s) in "
272             "[default: dist]"),
273            ]
274    
275        boolean_options = ['keep-temp']
276    
277        def initialize_options (self):
278            self.formats = None
279            self.keep_temp = 0
280            self.dist_dir = None
281    
282        def finalize_options (self):
283            self.ensure_string_list('formats')
284            if self.formats is None:
285                self.formats = ["zip"]
286            bad_format = archive_util.check_archive_formats(self.formats)
287            if bad_format:
288                raise DistutilsOptionError, \
289                      "unknown archive format '%s'" % bad_format
290    
291            if self.dist_dir is None:
292                self.dist_dir = "dist"
293    
294    
295        def run(self):
296            # 'filelist' contains the list of files that will make up the
297            # manifest
298            self.filelist = FileList()
299            
300            # Do whatever it takes to get the list of files to process.
301            # File list is accumulated in 'self.filelist'.
302            self.get_file_list()
303    
304            # Otherwise, go ahead and create the source distribution tarball,
305            # or zipfile, or whatever.
306            self.make_distribution()
307    
308        def get_file_list(self):
309            """Figure out the list of files to include in the data
310            distribution, and put it in 'self.filelist'.
311            """
312            self.filelist.findall("Data")
313            self.filelist.include_pattern("*", anchor = 0)
314            self.filelist.exclude_pattern(r'/(RCS|CVS)/.*', is_regex=1)
315            self.filelist.sort()
316            self.filelist.remove_duplicates()
317    
318        def make_release_tree(self, base_dir, files):
319            """Create the directory tree that will become the source
320            distribution archive.  All directories implied by the filenames in
321            'files' are created under 'base_dir', and then we hard link or copy
322            (if hard linking is unavailable) those files into place.
323            Essentially, this duplicates the developer's source tree, but in a
324            directory named after the distribution, containing only the files
325            to be distributed.
326            """
327            # Create all the directories under 'base_dir' necessary to
328            # put 'files' there; the 'mkpath()' is just so we don't die
329            # if the manifest happens to be empty.
330            self.mkpath(base_dir)
331            dir_util.create_tree(base_dir, files,
332                                 verbose=self.verbose, dry_run=self.dry_run)
333    
334            # And walk over the list of files, either making a hard link (if
335            # os.link exists) to each one that doesn't already exist in its
336            # corresponding location under 'base_dir', or copying each file
337            # that's out-of-date in 'base_dir'.  (Usually, all files will be
338            # out-of-date, because by default we blow away 'base_dir' when
339            # we're done making the distribution archives.)
340        
341            if hasattr(os, 'link'):        # can make hard links on this system
342                link = 'hard'
343                msg = "making hard links in %s..." % base_dir
344            else:                           # nope, have to copy
345                link = None
346                msg = "copying files to %s..." % base_dir
347    
348            if not files:
349                self.warn("no files to distribute -- empty manifest?")
350            else:
351                self.announce(msg)
352            for file in files:
353                if not os.path.isfile(file):
354                    self.warn("'%s' not a regular file -- skipping" % file)
355                else:
356                    dest = os.path.join(base_dir, file)
357                    self.copy_file(file, dest, link=link)
358    
359    
360        def make_distribution (self):
361            """Create the source distribution(s).  First, we create the release
362            tree with 'make_release_tree()'; then, we create all required
363            archive files (according to 'self.formats') from the release tree.
364            Finally, we clean up by blowing away the release tree (unless
365            'self.keep_temp' is true).  The list of archive files created is
366            stored so it can be retrieved later by 'get_archive_files()'.
367            """
368            # Don't warn about missing meta-data here -- should be (and is!)
369            # done elsewhere.
370            base_dir = "Thuban-data-" + self.distribution.get_version()
371            base_name = os.path.join(self.dist_dir, base_dir)
372    
373            self.make_release_tree(base_dir, self.filelist.files)
374            archive_files = []              # remember names of files we create
375            for fmt in self.formats:
376                file = self.make_archive(base_name, fmt, base_dir=base_dir)
377                archive_files.append(file)
378    
379            self.archive_files = archive_files
380    
381            if not self.keep_temp:
382                dir_util.remove_tree(base_dir, self.verbose, self.dry_run)
383    
384    
385    
# Line 256  class InstallLocal(Command): Line 392  class InstallLocal(Command):
392      """      """
393    
394      description =\      description =\
395          "Create some symlink so you can run thubanfrom the source directory"          "Create some symlinks so you can run thuban from the source directory"
396    
397      user_options = [      user_options = [
         ('debug', 'g', "compile/link with debugging information"),  
398          ('skip-build', None, "skip the build steps"),          ('skip-build', None, "skip the build steps"),
399          ]          ]
400    
# Line 267  class InstallLocal(Command): Line 402  class InstallLocal(Command):
402          self.extensions = None          self.extensions = None
403          self.build_dir = None          self.build_dir = None
404          self.skip_build = None          self.skip_build = None
         self.debug = None  
405    
406      def finalize_options (self):      def finalize_options (self):
407          self.set_undefined_options("install",          self.set_undefined_options("install",
# Line 282  class InstallLocal(Command): Line 416  class InstallLocal(Command):
416          # now do the work. Simply link or copy the Lib dir          # now do the work. Simply link or copy the Lib dir
417          libdir = os.path.join(self.build_dir, "Lib")          libdir = os.path.join(self.build_dir, "Lib")
418          if os.name == "posix":          if os.name == "posix":
419              # on posix, just lilnk the Lib dir              # on posix, just link the Lib dir
420              self.link_dir(libdir, "Lib")              self.link_dir(libdir, "Lib")
421          else:          else:
422              self.copy_tree(libdir, "Lib")              self.copy_tree(libdir, "Lib")
# Line 290  class InstallLocal(Command): Line 424  class InstallLocal(Command):
424      def link_dir(self, src, dest):      def link_dir(self, src, dest):
425          """Create a symbolic link dest pointing to src"""          """Create a symbolic link dest pointing to src"""
426          if self.verbose:          if self.verbose:
427              print "symlinking %s -> %s" % (src, dest)              self.announce("symlinking %s -> %s" % (src, dest))
428          if self.dry_run:          if self.dry_run:
429              return              return
430    
# Line 348  class thuban_build_py(build_py): Line 482  class thuban_build_py(build_py):
482              modules.append(("Lib", module_base, module_file))              modules.append(("Lib", module_base, module_file))
483          return modules          return modules
484    
485        def find_all_modules (self):
486            # same as find_all_modules of the original build_py command
487            # (rev. 1.33) but handle installations with both modules and
488            # packages. Needed here so tha the get_outputs works correctly
489            modules = []
490            if self.py_modules:
491                modules.extend(self.find_modules())
492            if self.packages:
493                for package in self.packages:
494                    package_dir = self.get_package_dir(package)
495                    m = self.find_package_modules(package, package_dir)
496                    modules.extend(m)
497    
498            return modules
499    
500    
501    
502  class ThubanInstall(install):  class ThubanInstall(install):
503    
# Line 357  class ThubanInstall(install): Line 507  class ThubanInstall(install):
507      Extend the standard install command to symlink the installed script      Extend the standard install command to symlink the installed script
508      to $prefix/bin/      to $prefix/bin/
509      """      """
510    
511        user_options = install.user_options[:]
512        user_options.extend([("do-symlink", None,
513                              "Create a symlink to the script in <prefix>/bin."
514                            "(default on posix systems and only relevant there)"),
515    
516                             ("extra-files", None,
517                              "List of filenames or (src, dest) pairs describing "
518                              " extra files to install "
519                              "(can only be set from witin setup.py"),
520                             ])
521    
522        boolean_options = install.boolean_options[:]
523        boolean_options.append("do-symlink")
524    
525        def initialize_options(self):
526            self.do_symlink = None
527            self.extra_files = []
528            install.initialize_options(self)
529    
530        def finalize_options(self):
531            if self.do_symlink is None:
532                if os.name == "posix":
533                    self.do_symlink = 1
534                else:
535                    self.do_symlink = 0
536            install.finalize_options(self)
537    
538      def run(self):      def run(self):
539          install.run(self)          install.run(self)
540          if os.name == "posix":          for item in self.extra_files:
541              scriptfile = os.path.join(self.install_scripts, "thuban.py")              if type(item) == TupleType:
542                    src, dest = item
543                else:
544                    src = dest = item
545                self.copy_file(convert_path(src),
546                               os.path.join(self.root, convert_path(dest)))
547    
548            if os.name == "posix" and self.do_symlink:
549                install_scripts = self.install_scripts
550                if self.root:
551                    install_scripts = install_scripts[len(self.root):]
552                scriptfile = os.path.join(install_scripts, "thuban.py")
553              bindir = os.path.join(self.prefix, "bin")              bindir = os.path.join(self.prefix, "bin")
554                if self.root:
555                    bindir = change_root(self.root, bindir)
556              binfile = os.path.join(bindir, "thuban")              binfile = os.path.join(bindir, "thuban")
557              self.mkpath(bindir)              self.mkpath(bindir)
558              self.copy_file(scriptfile, binfile, link="sym")              self.link_file(scriptfile, binfile)
559    
560        def link_file(self, src, dest):
561            """Create a symbolic link dest pointing to src.
562    
563            Unlike the symlink variant of the command object's copy_file
564            method, this method even performs the link if src doesn't exist.
565            This is useful when installing with an alternat root directory"""
566            if self.verbose:
567                self.announce("symlinking %s -> %s" % (src, dest))
568            if self.dry_run:
569                return
570    
571            if not os.path.exists(dest):
572                os.symlink(src, dest)
573    
574    
575        def get_outputs (self):
576            outputs = install.get_outputs(self)
577            for item in self.extra_files:
578                if type(item) == TupleType:
579                    src, dest = item
580                else:
581                    src = dest = item
582                outputs.append(os.path.join(self.root, convert_path(dest)))
583            if os.name == "posix" and self.do_symlink:
584                bindir = os.path.join(self.prefix, "bin")
585                if self.root:
586                    bindir = change_root(self.root, bindir)
587                binfile = os.path.join(bindir, "thuban")
588                outputs.append(binfile)
589            return outputs
590    
591    
592    bdist_rpm_prep_script = '''
593    %setup
594    cp extensions/pyshapelib/{README,README.pyshapelib}
595    cp extensions/pyshapelib/{COPYING,COPYING.pyshapelib}
596    cp extensions/pyprojection/{LICENSE,LICENSE.pyprojection}
597    '''
598    
599    
600        
601    class thuban_bdist_rpm(bdist_rpm):
602    
603        """Thuban specific RPM distribution command"""
604    
605        def initialize_options(self):
606            # create the prep script for the spec-file
607            open("bdist_rpm_prep", "w").write(bdist_rpm_prep_script)
608    
609            bdist_rpm.initialize_options(self)
610    
611    
612    class bdist_inno(Command):
613    
614        """Command to create a windows installer with Inno Setup"""
615    
616        description = "Create a windows installer with Inno Setup"
617    
618        user_options = [
619            ('skip-build', None, "skip the build steps"),
620            ('bdist-dir=', None,
621             "temporary directory for creating the distribution"),
622            ('run-inno', None,
623             "Run inno-setup to create the installer. On by default on nt"),
624            ('iss-name', None,
625             "The name of the iss file to generate. "
626             "Shouldn't contain directories"),
627    
628            # Parameters for the Inno Setup script
629            ('copyright', None, "Copyright notice for the Inno Setup file"),
630            ('default-dir-name', None,
631             "Default installation directory. Defaults to '{pf}\\<name>'"),
632            ('default-group-name', None,
633             "Default program group name. Defaults to <name>'"),
634            ("license-file", None, "File containing the license."),
635            ("output-basename", None,
636             "Base filename for the Inno Setup output "
637             "(defaults to <name>-<version>-<issrevision>)."),
638            ("iss-revision", None,
639             "revision of the generated installer of the package version"),
640    
641            ("icons-entries", None,
642             "List if InnoIconItems "
643             "(this can only be set from inside the setup.py script)"),
644            ]
645    
646        boolean_options = ["do-symlink"]
647    
648        def initialize_options(self):
649            self.skip_build = 0
650            self.bdist_dir = None
651            self.run_inno = None
652            self.iss_name = None
653            self.copyright = ""
654            self.default_dir_name = None
655            self.default_group_name = None
656            self.license_file = None
657            self.output_basename = None
658            self.iss_revision = None
659            self.icons_entries = []
660    
661        def finalize_options(self):
662            self.set_undefined_options("install",
663                                       ('skip_build', 'skip_build'))
664            if self.bdist_dir is None:
665                bdist_base = self.get_finalized_command('bdist').bdist_base
666                self.bdist_dir = os.path.join(bdist_base, 'inno')
667    
668            if self.run_inno is None:
669                self.run_inno = os.name == "nt"
670    
671            name = self.distribution.get_name()
672            if self.iss_name is None:
673                self.iss_name = name + '.iss'
674    
675            if self.default_dir_name is None:
676                self.default_dir_name = "{pf}\\" + name
677            if self.default_group_name is None:
678                self.default_group_name = name
679    
680            if self.iss_revision is None:
681                self.iss_revision = 0
682            if self.output_basename is None:
683                self.output_basename = "%s-%s-%d" \
684                                       % (name, self.distribution.get_version(),
685                                          self.iss_revision)
686    
687        def run(self, install_options = None):
688            """Execute the command. install_options if given, should be a
689            directory of additional options to set in the install step"""
690            # Obviously have to build before we can install
691            if not self.skip_build:
692                self.run_command('build')
693    
694            # Install in a temporary directory
695            install = self.reinitialize_command('install')
696            install.root = self.bdist_dir
697            if install_options is not None:
698                for key, value in install_options.items():
699                    setattr(install, key, value)
700            if os.name != 'nt':
701                # Must force install to use the 'nt' scheme;
702                install.select_scheme('nt')
703    
704            self.announce("installing to %s" % self.bdist_dir)
705            install.ensure_finalized()
706            install.run()
707    
708            # Create the iss file
709            iss_file = os.path.join(self.bdist_dir, self.iss_name)
710            self.execute(write_file, (iss_file, self.generate_iss()),
711                         "Create Inno Setup script file %s" % iss_file)
712    
713            # and invoke
714            if self.run_inno:
715                self.spawn(["iscc", iss_file])
716    
717        def generate_iss(self):
718            """Return the contents of the iss file as list of strings, one
719            string per line"""
720    
721            # first, turn the icons entries into a more usable form
722            icons = {}
723            for item in self.icons_entries:
724                icons[item.filename] = item
725    
726            iss = []
727    
728            name = self.distribution.get_name()
729            iss.extend(["[Setup]",
730                        "AppName=" + name,
731                        "AppVerName=" + name + " "+self.distribution.get_version(),
732                        "DefaultDirName=" + self.default_dir_name,
733                        "DefaultGroupName=" + self.default_group_name,
734                        ])
735            if self.copyright:
736                iss.append("AppCopyright=" + self.copyright)
737            if self.license_file:
738                iss.append("LicenseFile=" + self.license_file)
739    
740            iss.append("OutputBasefilename=" + self.output_basename)
741    
742            iss.append("")
743            iss.append("[Files]")
744    
745            install = self.get_finalized_command("install")
746            install_scripts = self.get_finalized_command("install_scripts")
747            script_files = install_scripts.get_outputs()
748            prefixlen = len(self.bdist_dir) + len(os.sep)
749            for filename in install.get_outputs():
750                filename = filename[prefixlen:]
751                icon = icons.get(filename)
752                dirname = os.path.dirname(filename)
753                if os.name != "nt":
754                    # change the separators to \ on non-windos systems
755                    filename = string.join(string.split(filename, os.sep), "\\")
756                    dirname =  string.join(string.split(dirname, os.sep), "\\")
757                line = 'Source: "%s"' % filename
758                if icon is not None:
759                    # install it as defined in the icon object
760                    backslash = string.rfind(icon.install_name, "\\")
761                    if backslash >= 0:
762                        dirname = icon.install_name[:backslash]
763                        basename = icon.install_name[backslash + 1:]
764                    else:
765                        dirname = ""
766                        basename = icon.install_name
767                    line = '%s; DestDir: "%s"; DestName: "%s"' % (line, dirname,
768                                                                  basename)
769                else:
770                    line = line + '; DestDir: "{app}\\%s"' % (dirname)
771                iss.append(line)
772    
773            iss.append("")
774            iss.append("[Icons]")
775            for icon in self.icons_entries:
776                line = 'Name: "{group}\\%s"; Filename: "%s";' \
777                       % (icon.title, icon.install_name)
778                iss.append(line)
779                
780            return iss
781    
782    
783    class InnoIconItem:
784    
785        """Describe one item for the start menu for the Inno Setup installer"""
786    
787        def __init__(self, filename, title, install_name = None):
788            self.filename = filename
789            self.title = title
790            if install_name is not None:
791                self.install_name = install_name
792            else:
793                self.install_name = filename
794    
795                
796    class thuban_bdist_inno(bdist_inno):
797    
798        """Thuban specific Inno Setup stuff"""
799    
800        def run(self):
801            install_options = {
802                "prefix": ".",
803                "install_scripts": "$base",
804                "warn_dir": 0,
805                "extra_files": ["COPYING", "Lib/proj.dll"],
806                }
807            # don't make a symlink because we're simulating windows, so
808            # that we can generate the iss-file even on Linux
809            install_options["do_symlink"] = 0
810            bdist_inno.run(self, install_options)
811        
812                
813    #
814    #   Run the script
815    #
816    
817    
818  long_description = """\  long_description = """\
819  Thuban is a viewer for geographic data written in Python  Thuban is a viewer for geographic data written in Python
820  """  """
821    
822  setup(name = "thuban",  setup(name = "Thuban",
823        version = "0.0.3",        version = "0.1.1",
824        description = "Geographic data viewer",        description = "Geographic data viewer",
825        long_description = long_description,        long_description = long_description,
826        licence = "GPL",        licence = "GPL",
# Line 394  setup(name = "thuban", Line 842  setup(name = "thuban",
842                    # same directory.                    # same directory.
843                    "install_lib": "$base/thuban",                    "install_lib": "$base/thuban",
844                    "install_scripts": "$base/thuban",                    "install_scripts": "$base/thuban",
845                    "install_data": "$base/thuban/",                    "install_data": "$base/thuban",
846    
847                    # Don't print warning messages about the lib dir not                    # Don't print warning messages about the lib dir not
848                    # being on Python's path. The libraries are Thuban                    # being on Python's path. The libraries are Thuban
849                    # specific and are installed just for Thuban. They'll                    # specific and are installed just for Thuban. They'll
850                    # be automatically on Python's path when Thuban is run                    # be automatically on Python's path when Thuban is run
851                    "warn_dir": 0,                    "warn_dir": 0,
852                    }},                    },
853                     "bdist_inno":
854                     {"icons_entries": [InnoIconItem(".\\thuban.py",
855                                                     "Start Thuban",
856                                                     "{app}\\thuban.pyw")],
857                      "license_file": "COPYING",
858                      }
859                     },
860        cmdclass = {"build_py": thuban_build_py,        cmdclass = {"build_py": thuban_build_py,
861                    "install_local": InstallLocal,                    "install_local": InstallLocal,
862                    "install": ThubanInstall})                    "install": ThubanInstall,
863                      "bdist_rpm": thuban_bdist_rpm,
864                      "bdist_inno": thuban_bdist_inno,
865                      "data_dist": data_dist
866                      })
867    
868    

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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26