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