home *** CD-ROM | disk | FTP | other *** search
/ Maximum CD 2011 June / maximum-cd-2011-06.iso / DiscContents / LibO_3.3.1_Win_x86_install_multi.exe / libreoffice1.cab / bdist_wininst.py < prev    next >
Encoding:
Python Source  |  2011-02-15  |  14.4 KB  |  354 lines

  1. """distutils.command.bdist_wininst
  2.  
  3. Implements the Distutils 'bdist_wininst' command: create a windows installer
  4. exe-program."""
  5.  
  6. # This module should be kept compatible with Python 2.1.
  7.  
  8. __revision__ = "$Id: bdist_wininst.py 63755 2008-05-28 01:54:55Z mark.hammond $"
  9.  
  10. import sys, os, string
  11. from distutils.core import Command
  12. from distutils.util import get_platform
  13. from distutils.dir_util import create_tree, remove_tree
  14. from distutils.errors import *
  15. from distutils.sysconfig import get_python_version
  16. from distutils import log
  17.  
  18. class bdist_wininst (Command):
  19.  
  20.     description = "create an executable installer for MS Windows"
  21.  
  22.     user_options = [('bdist-dir=', None,
  23.                      "temporary directory for creating the distribution"),
  24.                     ('plat-name=', 'p',
  25.                      "platform name to embed in generated filenames "
  26.                      "(default: %s)" % get_platform()),
  27.                     ('keep-temp', 'k',
  28.                      "keep the pseudo-installation tree around after " +
  29.                      "creating the distribution archive"),
  30.                     ('target-version=', None,
  31.                      "require a specific python version" +
  32.                      " on the target system"),
  33.                     ('no-target-compile', 'c',
  34.                      "do not compile .py to .pyc on the target system"),
  35.                     ('no-target-optimize', 'o',
  36.                      "do not compile .py to .pyo (optimized)"
  37.                      "on the target system"),
  38.                     ('dist-dir=', 'd',
  39.                      "directory to put final built distributions in"),
  40.                     ('bitmap=', 'b',
  41.                      "bitmap to use for the installer instead of python-powered logo"),
  42.                     ('title=', 't',
  43.                      "title to display on the installer background instead of default"),
  44.                     ('skip-build', None,
  45.                      "skip rebuilding everything (for testing/debugging)"),
  46.                     ('install-script=', None,
  47.                      "basename of installation script to be run after"
  48.                      "installation or before deinstallation"),
  49.                     ('pre-install-script=', None,
  50.                      "Fully qualified filename of a script to be run before "
  51.                      "any files are installed.  This script need not be in the "
  52.                      "distribution"),
  53.                     ('user-access-control=', None,
  54.                      "specify Vista's UAC handling - 'none'/default=no "
  55.                      "handling, 'auto'=use UAC if target Python installed for "
  56.                      "all users, 'force'=always use UAC"),
  57.                    ]
  58.  
  59.     boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize',
  60.                        'skip-build']
  61.  
  62.     def initialize_options (self):
  63.         self.bdist_dir = None
  64.         self.plat_name = None
  65.         self.keep_temp = 0
  66.         self.no_target_compile = 0
  67.         self.no_target_optimize = 0
  68.         self.target_version = None
  69.         self.dist_dir = None
  70.         self.bitmap = None
  71.         self.title = None
  72.         self.skip_build = 0
  73.         self.install_script = None
  74.         self.pre_install_script = None
  75.         self.user_access_control = None
  76.  
  77.     # initialize_options()
  78.  
  79.  
  80.     def finalize_options (self):
  81.         if self.bdist_dir is None:
  82.             if self.skip_build and self.plat_name:
  83.                 # If build is skipped and plat_name is overridden, bdist will
  84.                 # not see the correct 'plat_name' - so set that up manually.
  85.                 bdist = self.distribution.get_command_obj('bdist')
  86.                 bdist.plat_name = self.plat_name
  87.                 # next the command will be initialized using that name
  88.             bdist_base = self.get_finalized_command('bdist').bdist_base
  89.             self.bdist_dir = os.path.join(bdist_base, 'wininst')
  90.         if not self.target_version:
  91.             self.target_version = ""
  92.         if not self.skip_build and self.distribution.has_ext_modules():
  93.             short_version = get_python_version()
  94.             if self.target_version and self.target_version != short_version:
  95.                 raise DistutilsOptionError, \
  96.                       "target version can only be %s, or the '--skip_build'" \
  97.                       " option must be specified" % (short_version,)
  98.             self.target_version = short_version
  99.  
  100.         self.set_undefined_options('bdist',
  101.                                    ('dist_dir', 'dist_dir'),
  102.                                    ('plat_name', 'plat_name'),
  103.                                   )
  104.  
  105.         if self.install_script:
  106.             for script in self.distribution.scripts:
  107.                 if self.install_script == os.path.basename(script):
  108.                     break
  109.             else:
  110.                 raise DistutilsOptionError, \
  111.                       "install_script '%s' not found in scripts" % \
  112.                       self.install_script
  113.     # finalize_options()
  114.  
  115.  
  116.     def run (self):
  117.         if (sys.platform != "win32" and
  118.             (self.distribution.has_ext_modules() or
  119.              self.distribution.has_c_libraries())):
  120.             raise DistutilsPlatformError \
  121.                   ("distribution contains extensions and/or C libraries; "
  122.                    "must be compiled on a Windows 32 platform")
  123.  
  124.         if not self.skip_build:
  125.             self.run_command('build')
  126.  
  127.         install = self.reinitialize_command('install', reinit_subcommands=1)
  128.         install.root = self.bdist_dir
  129.         install.skip_build = self.skip_build
  130.         install.warn_dir = 0
  131.         install.plat_name = self.plat_name
  132.  
  133.         install_lib = self.reinitialize_command('install_lib')
  134.         # we do not want to include pyc or pyo files
  135.         install_lib.compile = 0
  136.         install_lib.optimize = 0
  137.  
  138.         if self.distribution.has_ext_modules():
  139.             # If we are building an installer for a Python version other
  140.             # than the one we are currently running, then we need to ensure
  141.             # our build_lib reflects the other Python version rather than ours.
  142.             # Note that for target_version!=sys.version, we must have skipped the
  143.             # build step, so there is no issue with enforcing the build of this
  144.             # version.
  145.             target_version = self.target_version
  146.             if not target_version:
  147.                 assert self.skip_build, "Should have already checked this"
  148.                 target_version = sys.version[0:3]
  149.             plat_specifier = ".%s-%s" % (self.plat_name, target_version)
  150.             build = self.get_finalized_command('build')
  151.             build.build_lib = os.path.join(build.build_base,
  152.                                            'lib' + plat_specifier)
  153.  
  154.         # Use a custom scheme for the zip-file, because we have to decide
  155.         # at installation time which scheme to use.
  156.         for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'):
  157.             value = string.upper(key)
  158.             if key == 'headers':
  159.                 value = value + '/Include/$dist_name'
  160.             setattr(install,
  161.                     'install_' + key,
  162.                     value)
  163.  
  164.         log.info("installing to %s", self.bdist_dir)
  165.         install.ensure_finalized()
  166.  
  167.         # avoid warning of 'install_lib' about installing
  168.         # into a directory not in sys.path
  169.         sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB'))
  170.  
  171.         install.run()
  172.  
  173.         del sys.path[0]
  174.  
  175.         # And make an archive relative to the root of the
  176.         # pseudo-installation tree.
  177.         from tempfile import mktemp
  178.         archive_basename = mktemp()
  179.         fullname = self.distribution.get_fullname()
  180.         arcname = self.make_archive(archive_basename, "zip",
  181.                                     root_dir=self.bdist_dir)
  182.         # create an exe containing the zip-file
  183.         self.create_exe(arcname, fullname, self.bitmap)
  184.         if self.distribution.has_ext_modules():
  185.             pyversion = get_python_version()
  186.         else:
  187.             pyversion = 'any'
  188.         self.distribution.dist_files.append(('bdist_wininst', pyversion,
  189.                                              self.get_installer_filename(fullname)))
  190.         # remove the zip-file again
  191.         log.debug("removing temporary file '%s'", arcname)
  192.         os.remove(arcname)
  193.  
  194.         if not self.keep_temp:
  195.             remove_tree(self.bdist_dir, dry_run=self.dry_run)
  196.  
  197.     # run()
  198.  
  199.     def get_inidata (self):
  200.         # Return data describing the installation.
  201.  
  202.         lines = []
  203.         metadata = self.distribution.metadata
  204.  
  205.         # Write the [metadata] section.
  206.         lines.append("[metadata]")
  207.  
  208.         # 'info' will be displayed in the installer's dialog box,
  209.         # describing the items to be installed.
  210.         info = (metadata.long_description or '') + '\n'
  211.  
  212.         # Escape newline characters
  213.         def escape(s):
  214.             return string.replace(s, "\n", "\\n")
  215.  
  216.         for name in ["author", "author_email", "description", "maintainer",
  217.                      "maintainer_email", "name", "url", "version"]:
  218.             data = getattr(metadata, name, "")
  219.             if data:
  220.                 info = info + ("\n    %s: %s" % \
  221.                                (string.capitalize(name), escape(data)))
  222.                 lines.append("%s=%s" % (name, escape(data)))
  223.  
  224.         # The [setup] section contains entries controlling
  225.         # the installer runtime.
  226.         lines.append("\n[Setup]")
  227.         if self.install_script:
  228.             lines.append("install_script=%s" % self.install_script)
  229.         lines.append("info=%s" % escape(info))
  230.         lines.append("target_compile=%d" % (not self.no_target_compile))
  231.         lines.append("target_optimize=%d" % (not self.no_target_optimize))
  232.         if self.target_version:
  233.             lines.append("target_version=%s" % self.target_version)
  234.         if self.user_access_control:
  235.             lines.append("user_access_control=%s" % self.user_access_control)
  236.  
  237.         title = self.title or self.distribution.get_fullname()
  238.         lines.append("title=%s" % escape(title))
  239.         import time
  240.         import distutils
  241.         build_info = "Built %s with distutils-%s" % \
  242.                      (time.ctime(time.time()), distutils.__version__)
  243.         lines.append("build_info=%s" % build_info)
  244.         return string.join(lines, "\n")
  245.  
  246.     # get_inidata()
  247.  
  248.     def create_exe (self, arcname, fullname, bitmap=None):
  249.         import struct
  250.  
  251.         self.mkpath(self.dist_dir)
  252.  
  253.         cfgdata = self.get_inidata()
  254.  
  255.         installer_name = self.get_installer_filename(fullname)
  256.         self.announce("creating %s" % installer_name)
  257.  
  258.         if bitmap:
  259.             bitmapdata = open(bitmap, "rb").read()
  260.             bitmaplen = len(bitmapdata)
  261.         else:
  262.             bitmaplen = 0
  263.  
  264.         file = open(installer_name, "wb")
  265.         file.write(self.get_exe_bytes())
  266.         if bitmap:
  267.             file.write(bitmapdata)
  268.  
  269.         # Convert cfgdata from unicode to ascii, mbcs encoded
  270.         try:
  271.             unicode
  272.         except NameError:
  273.             pass
  274.         else:
  275.             if isinstance(cfgdata, unicode):
  276.                 cfgdata = cfgdata.encode("mbcs")
  277.  
  278.         # Append the pre-install script
  279.         cfgdata = cfgdata + "\0"
  280.         if self.pre_install_script:
  281.             script_data = open(self.pre_install_script, "r").read()
  282.             cfgdata = cfgdata + script_data + "\n\0"
  283.         else:
  284.             # empty pre-install script
  285.             cfgdata = cfgdata + "\0"
  286.         file.write(cfgdata)
  287.  
  288.         # The 'magic number' 0x1234567B is used to make sure that the
  289.         # binary layout of 'cfgdata' is what the wininst.exe binary
  290.         # expects.  If the layout changes, increment that number, make
  291.         # the corresponding changes to the wininst.exe sources, and
  292.         # recompile them.
  293.         header = struct.pack("<iii",
  294.                              0x1234567B,       # tag
  295.                              len(cfgdata),     # length
  296.                              bitmaplen,        # number of bytes in bitmap
  297.                              )
  298.         file.write(header)
  299.         file.write(open(arcname, "rb").read())
  300.  
  301.     # create_exe()
  302.  
  303.     def get_installer_filename(self, fullname):
  304.         # Factored out to allow overriding in subclasses
  305.         if self.target_version:
  306.             # if we create an installer for a specific python version,
  307.             # it's better to include this in the name
  308.             installer_name = os.path.join(self.dist_dir,
  309.                                           "%s.%s-py%s.exe" %
  310.                                            (fullname, self.plat_name, self.target_version))
  311.         else:
  312.             installer_name = os.path.join(self.dist_dir,
  313.                                           "%s.%s.exe" % (fullname, self.plat_name))
  314.         return installer_name
  315.     # get_installer_filename()
  316.  
  317.     def get_exe_bytes (self):
  318.         from distutils.msvccompiler import get_build_version
  319.         # If a target-version other than the current version has been
  320.         # specified, then using the MSVC version from *this* build is no good.
  321.         # Without actually finding and executing the target version and parsing
  322.         # its sys.version, we just hard-code our knowledge of old versions.
  323.         # NOTE: Possible alternative is to allow "--target-version" to
  324.         # specify a Python executable rather than a simple version string.
  325.         # We can then execute this program to obtain any info we need, such
  326.         # as the real sys.version string for the build.
  327.         cur_version = get_python_version()
  328.         if self.target_version and self.target_version != cur_version:
  329.             # If the target version is *later* than us, then we assume they
  330.             # use what we use
  331.             # string compares seem wrong, but are what sysconfig.py itself uses
  332.             if self.target_version > cur_version:
  333.                 bv = get_build_version()
  334.             else:
  335.                 if self.target_version < "2.4":
  336.                     bv = 6.0
  337.                 else:
  338.                     bv = 7.1
  339.         else:
  340.             # for current version - use authoritative check.
  341.             bv = get_build_version()
  342.  
  343.         # wininst-x.y.exe is in the same directory as this file
  344.         directory = os.path.dirname(__file__)
  345.         # we must use a wininst-x.y.exe built with the same C compiler
  346.         # used for python.  XXX What about mingw, borland, and so on?
  347.         if self.plat_name == 'win32':
  348.             sfix = ''
  349.         else:
  350.             sfix = self.plat_name[3:] # strip 'win' - leaves eg '-amd64'
  351.         filename = os.path.join(directory, "wininst-%.1f%s.exe" % (bv, sfix))
  352.         return open(filename, "rb").read()
  353. # class bdist_wininst
  354.