PyXR

c:\python24\lib \ distutils \ command \ bdist_wininst.py



0001 """distutils.command.bdist_wininst
0002 
0003 Implements the Distutils 'bdist_wininst' command: create a windows installer
0004 exe-program."""
0005 
0006 # This module should be kept compatible with Python 1.5.2.
0007 
0008 __revision__ = "$Id: bdist_wininst.py,v 1.55 2004/10/27 21:54:33 mhammond Exp $"
0009 
0010 import sys, os, string
0011 from distutils.core import Command
0012 from distutils.util import get_platform
0013 from distutils.dir_util import create_tree, remove_tree
0014 from distutils.errors import *
0015 from distutils.sysconfig import get_python_version
0016 from distutils import log
0017 
0018 class bdist_wininst (Command):
0019 
0020     description = "create an executable installer for MS Windows"
0021 
0022     user_options = [('bdist-dir=', None,
0023                      "temporary directory for creating the distribution"),
0024                     ('keep-temp', 'k',
0025                      "keep the pseudo-installation tree around after " +
0026                      "creating the distribution archive"),
0027                     ('target-version=', None,
0028                      "require a specific python version" +
0029                      " on the target system"),
0030                     ('no-target-compile', 'c',
0031                      "do not compile .py to .pyc on the target system"),
0032                     ('no-target-optimize', 'o',
0033                      "do not compile .py to .pyo (optimized)"
0034                      "on the target system"),
0035                     ('dist-dir=', 'd',
0036                      "directory to put final built distributions in"),
0037                     ('bitmap=', 'b',
0038                      "bitmap to use for the installer instead of python-powered logo"),
0039                     ('title=', 't',
0040                      "title to display on the installer background instead of default"),
0041                     ('skip-build', None,
0042                      "skip rebuilding everything (for testing/debugging)"),
0043                     ('install-script=', None,
0044                      "basename of installation script to be run after"
0045                      "installation or before deinstallation"),
0046                     ('pre-install-script=', None,
0047                      "Fully qualified filename of a script to be run before "
0048                      "any files are installed.  This script need not be in the "
0049                      "distribution"),
0050                    ]
0051 
0052     boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize',
0053                        'skip-build']
0054 
0055     def initialize_options (self):
0056         self.bdist_dir = None
0057         self.keep_temp = 0
0058         self.no_target_compile = 0
0059         self.no_target_optimize = 0
0060         self.target_version = None
0061         self.dist_dir = None
0062         self.bitmap = None
0063         self.title = None
0064         self.skip_build = 0
0065         self.install_script = None
0066         self.pre_install_script = None
0067 
0068     # initialize_options()
0069 
0070 
0071     def finalize_options (self):
0072         if self.bdist_dir is None:
0073             bdist_base = self.get_finalized_command('bdist').bdist_base
0074             self.bdist_dir = os.path.join(bdist_base, 'wininst')
0075         if not self.target_version:
0076             self.target_version = ""
0077         if not self.skip_build and self.distribution.has_ext_modules():
0078             short_version = get_python_version()
0079             if self.target_version and self.target_version != short_version:
0080                 raise DistutilsOptionError, \
0081                       "target version can only be %s, or the '--skip_build'" \
0082                       " option must be specified" % (short_version,)
0083             self.target_version = short_version
0084 
0085         self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
0086 
0087         if self.install_script:
0088             for script in self.distribution.scripts:
0089                 if self.install_script == os.path.basename(script):
0090                     break
0091             else:
0092                 raise DistutilsOptionError, \
0093                       "install_script '%s' not found in scripts" % \
0094                       self.install_script
0095     # finalize_options()
0096 
0097 
0098     def run (self):
0099         if (sys.platform != "win32" and
0100             (self.distribution.has_ext_modules() or
0101              self.distribution.has_c_libraries())):
0102             raise DistutilsPlatformError \
0103                   ("distribution contains extensions and/or C libraries; "
0104                    "must be compiled on a Windows 32 platform")
0105 
0106         if not self.skip_build:
0107             self.run_command('build')
0108 
0109         install = self.reinitialize_command('install', reinit_subcommands=1)
0110         install.root = self.bdist_dir
0111         install.skip_build = self.skip_build
0112         install.warn_dir = 0
0113 
0114         install_lib = self.reinitialize_command('install_lib')
0115         # we do not want to include pyc or pyo files
0116         install_lib.compile = 0
0117         install_lib.optimize = 0
0118 
0119         if self.distribution.has_ext_modules():
0120             # If we are building an installer for a Python version other
0121             # than the one we are currently running, then we need to ensure
0122             # our build_lib reflects the other Python version rather than ours.
0123             # Note that for target_version!=sys.version, we must have skipped the
0124             # build step, so there is no issue with enforcing the build of this
0125             # version.
0126             target_version = self.target_version
0127             if not target_version:
0128                 assert self.skip_build, "Should have already checked this"
0129                 target_version = sys.version[0:3]
0130             plat_specifier = ".%s-%s" % (get_platform(), target_version)
0131             build = self.get_finalized_command('build')
0132             build.build_lib = os.path.join(build.build_base,
0133                                            'lib' + plat_specifier)
0134 
0135         # Use a custom scheme for the zip-file, because we have to decide
0136         # at installation time which scheme to use.
0137         for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'):
0138             value = string.upper(key)
0139             if key == 'headers':
0140                 value = value + '/Include/$dist_name'
0141             setattr(install,
0142                     'install_' + key,
0143                     value)
0144 
0145         log.info("installing to %s", self.bdist_dir)
0146         install.ensure_finalized()
0147 
0148         # avoid warning of 'install_lib' about installing
0149         # into a directory not in sys.path
0150         sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB'))
0151 
0152         install.run()
0153 
0154         del sys.path[0]
0155 
0156         # And make an archive relative to the root of the
0157         # pseudo-installation tree.
0158         from tempfile import mktemp
0159         archive_basename = mktemp()
0160         fullname = self.distribution.get_fullname()
0161         arcname = self.make_archive(archive_basename, "zip",
0162                                     root_dir=self.bdist_dir)
0163         # create an exe containing the zip-file
0164         self.create_exe(arcname, fullname, self.bitmap)
0165         # remove the zip-file again
0166         log.debug("removing temporary file '%s'", arcname)
0167         os.remove(arcname)
0168 
0169         if not self.keep_temp:
0170             remove_tree(self.bdist_dir, dry_run=self.dry_run)
0171 
0172     # run()
0173 
0174     def get_inidata (self):
0175         # Return data describing the installation.
0176 
0177         lines = []
0178         metadata = self.distribution.metadata
0179 
0180         # Write the [metadata] section.
0181         lines.append("[metadata]")
0182 
0183         # 'info' will be displayed in the installer's dialog box,
0184         # describing the items to be installed.
0185         info = (metadata.long_description or '') + '\n'
0186 
0187         # Escape newline characters
0188         def escape(s):
0189             return string.replace(s, "\n", "\\n")
0190 
0191         for name in ["author", "author_email", "description", "maintainer",
0192                      "maintainer_email", "name", "url", "version"]:
0193             data = getattr(metadata, name, "")
0194             if data:
0195                 info = info + ("\n    %s: %s" % \
0196                                (string.capitalize(name), escape(data)))
0197                 lines.append("%s=%s" % (name, escape(data)))
0198 
0199         # The [setup] section contains entries controlling
0200         # the installer runtime.
0201         lines.append("\n[Setup]")
0202         if self.install_script:
0203             lines.append("install_script=%s" % self.install_script)
0204         lines.append("info=%s" % escape(info))
0205         lines.append("target_compile=%d" % (not self.no_target_compile))
0206         lines.append("target_optimize=%d" % (not self.no_target_optimize))
0207         if self.target_version:
0208             lines.append("target_version=%s" % self.target_version)
0209 
0210         title = self.title or self.distribution.get_fullname()
0211         lines.append("title=%s" % escape(title))
0212         import time
0213         import distutils
0214         build_info = "Built %s with distutils-%s" % \
0215                      (time.ctime(time.time()), distutils.__version__)
0216         lines.append("build_info=%s" % build_info)
0217         return string.join(lines, "\n")
0218 
0219     # get_inidata()
0220 
0221     def create_exe (self, arcname, fullname, bitmap=None):
0222         import struct
0223 
0224         self.mkpath(self.dist_dir)
0225 
0226         cfgdata = self.get_inidata()
0227 
0228         installer_name = self.get_installer_filename(fullname)
0229         self.announce("creating %s" % installer_name)
0230 
0231         if bitmap:
0232             bitmapdata = open(bitmap, "rb").read()
0233             bitmaplen = len(bitmapdata)
0234         else:
0235             bitmaplen = 0
0236 
0237         file = open(installer_name, "wb")
0238         file.write(self.get_exe_bytes())
0239         if bitmap:
0240             file.write(bitmapdata)
0241 
0242         # Convert cfgdata from unicode to ascii, mbcs encoded
0243         try:
0244             unicode
0245         except NameError:
0246             pass
0247         else:
0248             if isinstance(cfgdata, unicode):
0249                 cfgdata = cfgdata.encode("mbcs")
0250 
0251         # Append the pre-install script
0252         cfgdata = cfgdata + "\0"
0253         if self.pre_install_script:
0254             script_data = open(self.pre_install_script, "r").read()
0255             cfgdata = cfgdata + script_data + "\n\0"
0256         else:
0257             # empty pre-install script
0258             cfgdata = cfgdata + "\0"
0259         file.write(cfgdata)
0260 
0261         # The 'magic number' 0x1234567B is used to make sure that the
0262         # binary layout of 'cfgdata' is what the wininst.exe binary
0263         # expects.  If the layout changes, increment that number, make
0264         # the corresponding changes to the wininst.exe sources, and
0265         # recompile them.
0266         header = struct.pack("<iii",
0267                              0x1234567B,       # tag
0268                              len(cfgdata),     # length
0269                              bitmaplen,        # number of bytes in bitmap
0270                              )
0271         file.write(header)
0272         file.write(open(arcname, "rb").read())
0273 
0274     # create_exe()
0275 
0276     def get_installer_filename(self, fullname):
0277         # Factored out to allow overriding in subclasses
0278         if self.target_version:
0279             # if we create an installer for a specific python version,
0280             # it's better to include this in the name
0281             installer_name = os.path.join(self.dist_dir,
0282                                           "%s.win32-py%s.exe" %
0283                                            (fullname, self.target_version))
0284         else:
0285             installer_name = os.path.join(self.dist_dir,
0286                                           "%s.win32.exe" % fullname)
0287         return installer_name
0288     # get_installer_filename()
0289 
0290     def get_exe_bytes (self):
0291         from distutils.msvccompiler import get_build_version
0292         # If a target-version other than the current version has been
0293         # specified, then using the MSVC version from *this* build is no good.
0294         # Without actually finding and executing the target version and parsing
0295         # its sys.version, we just hard-code our knowledge of old versions.
0296         # NOTE: Possible alternative is to allow "--target-version" to
0297         # specify a Python executable rather than a simple version string.
0298         # We can then execute this program to obtain any info we need, such
0299         # as the real sys.version string for the build.
0300         cur_version = get_python_version()
0301         if self.target_version and self.target_version != cur_version:
0302             # If the target version is *later* than us, then we assume they
0303             # use what we use
0304             # string compares seem wrong, but are what sysconfig.py itself uses
0305             if self.target_version > cur_version:
0306                 bv = get_build_version()
0307             else:
0308                 if self.target_version < "2.4":
0309                     bv = "6"
0310                 else:
0311                     bv = "7.1"
0312         else:
0313             # for current version - use authoritative check.
0314             bv = get_build_version()
0315 
0316         # wininst-x.y.exe is in the same directory as this file
0317         directory = os.path.dirname(__file__)
0318         # we must use a wininst-x.y.exe built with the same C compiler
0319         # used for python.  XXX What about mingw, borland, and so on?
0320         filename = os.path.join(directory, "wininst-%s.exe" % bv)
0321         return open(filename, "rb").read()
0322 # class bdist_wininst
0323 

Generated by PyXR 0.9.4
SourceForge.net Logo