From 27199e80294defc30d0b2419c42ac957e892fe2d Mon Sep 17 00:00:00 2001 From: Greg Ward Date: Tue, 27 Jun 2000 01:24:38 +0000 Subject: Thomas Heller's "bdist_wininst" command (unreviewed, untested). --- Lib/distutils/command/bdist_wininst.py | 448 +++++++++++++++++++++++++++++++++ 1 file changed, 448 insertions(+) create mode 100644 Lib/distutils/command/bdist_wininst.py diff --git a/Lib/distutils/command/bdist_wininst.py b/Lib/distutils/command/bdist_wininst.py new file mode 100644 index 0000000..6a4b472 --- /dev/null +++ b/Lib/distutils/command/bdist_wininst.py @@ -0,0 +1,448 @@ +"""distutils.command.bdist_wininst + +Implements the Distutils 'bdist_wininst' command: create a windows installer +exe-program.""" + +# created 2000/06/02, Thomas Heller + +__revision__ = "$Id$" + +import os, sys +from distutils.core import Command +from distutils.util import get_platform, create_tree, remove_tree +from distutils.errors import * + +class bdist_wininst (Command): + + description = "create a \"wininst\" built distribution" + + user_options = [('bdist-dir=', 'd', + "temporary directory for creating the distribution"), + ('keep-tree', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('target-compile', 'c', + "compile to .pyc on the target system"), + ('target-optimize', 'o', + "compile to .pyo on the target system"), + ('target-version=', 'v', + "require a specific python version" + + " on the target system (1.5 or 1.6)"), + ] + + def initialize_options (self): + self.bdist_dir = None + self.keep_tree = 0 + self.target_compile = 0 + self.target_optimize = 0 + self.target_version = None + + # initialize_options() + + + def finalize_options (self): + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'wininst') + if not self.target_version: + self.target_version = "" + else: + if not self.target_version in ("1.5", "1.6"): + raise DistutilsOptionError ( + "target version must be 1.5 or 1.6") + if self.distribution.has_ext_modules(): + short_version = sys.version[:3] + if self.target_version and self.target_version != short_version: + raise DistutilsOptionError ("target version can only be" + + short_version) + self.target_version = short_version + + # finalize_options() + + + def run (self): + + self.run_command ('build') + + # XXX don't use 'self.get_finalized_command()', because it always + # runs 'ensure_finalized()' on the command object; we explictly + # want a command object that has *not* been finalized, so we can set + # options on it! (The option we set, 'root', is so that we can do + # a proper "fake install" using this install command object.) + install = self.distribution.get_command_obj('install') + install.root = self.bdist_dir + + install_lib = self.distribution.get_command_obj('install_lib') + + install_lib.compile = 0 + install_lib.optimize = 0 + + # The packager (correct term in distutils speak?) can choose + # if pyc and pyo files should be created on the TARGET system + # instead at the SOURCE system. + +## # The compilation can only be done on the SOURCE system +## # for one python version (assuming 1.6 and 1.5 have incompatible +## # byte-codes). +## short_version = sys.version[:3] +## if self.target_version == short_version: +## if not self.target_compile: +## install_lib.compile = 1 +## if not self.target_optimize: +## install_lib.optimize = 1 + + install_lib.ensure_finalized() + + self.announce ("installing to %s" % self.bdist_dir) + install.ensure_finalized() + + install.run() + + # And make an archive relative to the root of the + # pseudo-installation tree. + archive_basename = "%s.win32" % self.distribution.get_fullname() + # XXX hack! Our archive MUST be relative to sys.prefix + # XXX What about .install_data, .install_scripts, ...? + root_dir = install.install_lib + arcname = self.make_archive (archive_basename, "zip", + root_dir=root_dir) + + self.create_exe (arcname) + + if not self.keep_tree: + remove_tree (self.bdist_dir, self.verbose, self.dry_run) + + # run() + + def create_inifile (self): + # create an inifile containing data describing the installation. + # This could be done without creating a real file, but + # a file is (at least) usefull for debugging bdist_wininst. + import string + + metadata = self.distribution.metadata + + ini_name = "%s.ini" % self.distribution.get_fullname() + + self.announce ("creating %s" % ini_name) + + inifile = open (ini_name, "w") + + # write the [metadata] section. values are written with repr()[1:], + # so they do not contain unprintable characters, and are not + # surrounded by quote chars + inifile.write ("[metadata]\n") + + # 'info' will be displayed in the installers dialog box, + # describing the items to be installed + info = metadata.long_description + '\n' + + for name in dir (metadata): + if (name != 'long_description'): + data = getattr (metadata, name) + if data: + info = info + ("\n %s: %s" % \ + (string.capitalize (name), data)) + inifile.write ("%s=%s\n" % (name, repr (data)[1:-1])) + + # The [setup] section contains entries controlling + # the installer runtime. + inifile.write ("\n[Setup]\n") + inifile.write ("info=%s\n" % repr (info)[1:-1]) + inifile.write ("pthname=%s.%s\n" % (metadata.name, metadata.version)) + inifile.write ("pyc_compile=%d\n" % self.target_compile) + inifile.write ("pyo_compile=%d\n" % self.target_optimize) + if self.target_version: + vers_minor = string.split (self.target_version, '.')[1] + inifile.write ("vers_minor=%s\n" % vers_minor) + + title = self.distribution.get_fullname() + inifile.write ("title=%s\n" % repr (title)[1:-1]) + inifile.close() + return ini_name + + # create_inifile() + + def create_exe (self, arcname): + import struct, zlib + + cfgdata = open (self.create_inifile()).read() + + comp_method = zlib.DEFLATED + co = zlib.compressobj (zlib.Z_DEFAULT_COMPRESSION, comp_method, -15) + zcfgdata = co.compress (cfgdata) + co.flush() + + installer_name = "%s.win32.exe" % self.distribution.get_fullname() + + self.announce ("creating %s" % installer_name) + + file = open (installer_name, "wb") + file.write (self.get_exe_bytes ()) + file.write (zcfgdata) + crc32 = zlib.crc32 (cfgdata) + header = struct.pack ("