mirror of
https://github.com/python/cpython.git
synced 2025-07-24 19:54:21 +00:00

bdist_wininst.py we will see.) Removed the base64 encoded binary contents, wininst.exe must be in the same directory as this file now. wininst.exe must be recompiled and commited each time the sources in PC/bdist_wininst are changed.
242 lines
9 KiB
Python
242 lines
9 KiB
Python
"""distutils.command.bdist_wininst
|
|
|
|
Implements the Distutils 'bdist_wininst' command: create a windows installer
|
|
exe-program."""
|
|
|
|
# This module should be kept compatible with Python 1.5.2.
|
|
|
|
__revision__ = "$Id$"
|
|
|
|
import sys, os, string
|
|
from distutils.core import Command
|
|
from distutils.util import get_platform
|
|
from distutils.dir_util import create_tree, remove_tree
|
|
from distutils.errors import *
|
|
from distutils.sysconfig import get_python_version
|
|
from distutils import log
|
|
|
|
class bdist_wininst (Command):
|
|
|
|
description = "create an executable installer for MS Windows"
|
|
|
|
user_options = [('bdist-dir=', None,
|
|
"temporary directory for creating the distribution"),
|
|
('keep-temp', 'k',
|
|
"keep the pseudo-installation tree around after " +
|
|
"creating the distribution archive"),
|
|
('target-version=', 'v',
|
|
"require a specific python version" +
|
|
" on the target system"),
|
|
('no-target-compile', 'c',
|
|
"do not compile .py to .pyc on the target system"),
|
|
('no-target-optimize', 'o',
|
|
"do not compile .py to .pyo (optimized)"
|
|
"on the target system"),
|
|
('dist-dir=', 'd',
|
|
"directory to put final built distributions in"),
|
|
('bitmap=', 'b',
|
|
"bitmap to use for the installer instead of python-powered logo"),
|
|
('title=', 't',
|
|
"title to display on the installer background instead of default"),
|
|
('skip-build', None,
|
|
"skip rebuilding everything (for testing/debugging)"),
|
|
('install-script=', None,
|
|
"basename of installation script to be run after"
|
|
"installation or before deinstallation"),
|
|
]
|
|
|
|
boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize',
|
|
'skip-build']
|
|
|
|
def initialize_options (self):
|
|
self.bdist_dir = None
|
|
self.keep_temp = 0
|
|
self.no_target_compile = 0
|
|
self.no_target_optimize = 0
|
|
self.target_version = None
|
|
self.dist_dir = None
|
|
self.bitmap = None
|
|
self.title = None
|
|
self.skip_build = 0
|
|
self.install_script = 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 = ""
|
|
if self.distribution.has_ext_modules():
|
|
short_version = get_python_version()
|
|
if self.target_version and self.target_version != short_version:
|
|
raise DistutilsOptionError, \
|
|
"target version can only be" + short_version
|
|
self.target_version = short_version
|
|
|
|
self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
|
|
|
|
if self.install_script:
|
|
for script in self.distribution.scripts:
|
|
if self.install_script == os.path.basename(script):
|
|
break
|
|
else:
|
|
raise DistutilsOptionError, \
|
|
"install_script '%s' not found in scripts" % \
|
|
self.install_script
|
|
# finalize_options()
|
|
|
|
|
|
def run (self):
|
|
if (sys.platform != "win32" and
|
|
(self.distribution.has_ext_modules() or
|
|
self.distribution.has_c_libraries())):
|
|
raise DistutilsPlatformError \
|
|
("distribution contains extensions and/or C libraries; "
|
|
"must be compiled on a Windows 32 platform")
|
|
|
|
if not self.skip_build:
|
|
self.run_command('build')
|
|
|
|
install = self.reinitialize_command('install')
|
|
install.root = self.bdist_dir
|
|
install.skip_build = self.skip_build
|
|
install.warn_dir = 0
|
|
|
|
install_lib = self.reinitialize_command('install_lib')
|
|
# we do not want to include pyc or pyo files
|
|
install_lib.compile = 0
|
|
install_lib.optimize = 0
|
|
|
|
# Use a custom scheme for the zip-file, because we have to decide
|
|
# at installation time which scheme to use.
|
|
for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'):
|
|
value = string.upper(key)
|
|
if key == 'headers':
|
|
value = value + '/Include/$dist_name'
|
|
setattr(install,
|
|
'install_' + key,
|
|
value)
|
|
|
|
log.info("installing to %s", self.bdist_dir)
|
|
install.ensure_finalized()
|
|
|
|
# avoid warning of 'install_lib' about installing
|
|
# into a directory not in sys.path
|
|
sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB'))
|
|
|
|
install.run()
|
|
|
|
del sys.path[0]
|
|
|
|
# And make an archive relative to the root of the
|
|
# pseudo-installation tree.
|
|
from tempfile import mktemp
|
|
archive_basename = mktemp()
|
|
fullname = self.distribution.get_fullname()
|
|
arcname = self.make_archive(archive_basename, "zip",
|
|
root_dir=self.bdist_dir)
|
|
# create an exe containing the zip-file
|
|
self.create_exe(arcname, fullname, self.bitmap)
|
|
# remove the zip-file again
|
|
log.debug("removing temporary file '%s'", arcname)
|
|
os.remove(arcname)
|
|
|
|
if not self.keep_temp:
|
|
remove_tree(self.bdist_dir, dry_run=self.dry_run)
|
|
|
|
# run()
|
|
|
|
def get_inidata (self):
|
|
# Return data describing the installation.
|
|
|
|
lines = []
|
|
metadata = self.distribution.metadata
|
|
|
|
# Write the [metadata] section. Values are written with
|
|
# repr()[1:-1], so they do not contain unprintable characters, and
|
|
# are not surrounded by quote chars.
|
|
lines.append("[metadata]")
|
|
|
|
# 'info' will be displayed in the installer's dialog box,
|
|
# describing the items to be installed.
|
|
info = (metadata.long_description or '') + '\n'
|
|
|
|
for name in ["author", "author_email", "description", "maintainer",
|
|
"maintainer_email", "name", "url", "version"]:
|
|
data = getattr(metadata, name, "")
|
|
if data:
|
|
info = info + ("\n %s: %s" % \
|
|
(string.capitalize(name), data))
|
|
lines.append("%s=%s" % (name, repr(data)[1:-1]))
|
|
|
|
# The [setup] section contains entries controlling
|
|
# the installer runtime.
|
|
lines.append("\n[Setup]")
|
|
if self.install_script:
|
|
lines.append("install_script=%s" % self.install_script)
|
|
lines.append("info=%s" % repr(info)[1:-1])
|
|
lines.append("target_compile=%d" % (not self.no_target_compile))
|
|
lines.append("target_optimize=%d" % (not self.no_target_optimize))
|
|
if self.target_version:
|
|
lines.append("target_version=%s" % self.target_version)
|
|
|
|
title = self.title or self.distribution.get_fullname()
|
|
lines.append("title=%s" % repr(title)[1:-1])
|
|
import time
|
|
import distutils
|
|
build_info = "Build %s with distutils-%s" % \
|
|
(time.ctime(time.time()), distutils.__version__)
|
|
lines.append("build_info=%s" % build_info)
|
|
return string.join(lines, "\n")
|
|
|
|
# get_inidata()
|
|
|
|
def create_exe (self, arcname, fullname, bitmap=None):
|
|
import struct
|
|
|
|
self.mkpath(self.dist_dir)
|
|
|
|
cfgdata = self.get_inidata()
|
|
|
|
if self.target_version:
|
|
# if we create an installer for a specific python version,
|
|
# it's better to include this in the name
|
|
installer_name = os.path.join(self.dist_dir,
|
|
"%s.win32-py%s.exe" %
|
|
(fullname, self.target_version))
|
|
else:
|
|
installer_name = os.path.join(self.dist_dir,
|
|
"%s.win32.exe" % fullname)
|
|
self.announce("creating %s" % installer_name)
|
|
|
|
if bitmap:
|
|
bitmapdata = open(bitmap, "rb").read()
|
|
bitmaplen = len(bitmapdata)
|
|
else:
|
|
bitmaplen = 0
|
|
|
|
file = open(installer_name, "wb")
|
|
file.write(self.get_exe_bytes())
|
|
if bitmap:
|
|
file.write(bitmapdata)
|
|
|
|
file.write(cfgdata)
|
|
header = struct.pack("<iii",
|
|
0x1234567A, # tag
|
|
len(cfgdata), # length
|
|
bitmaplen, # number of bytes in bitmap
|
|
)
|
|
file.write(header)
|
|
file.write(open(arcname, "rb").read())
|
|
|
|
# create_exe()
|
|
|
|
def get_exe_bytes (self):
|
|
# wininst.exe is in the same directory as this file
|
|
directory = os.path.dirname(__file__)
|
|
filename = os.path.join(directory, "wininst.exe")
|
|
return open(filename, "rb").read()
|
|
# class bdist_wininst
|