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