]> git.saurik.com Git - wxWidgets.git/blob - wxPython/distutils/command/bdist_wininst.py
Tweaking names (Thanks Jeff!)
[wxWidgets.git] / wxPython / distutils / command / bdist_wininst.py
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 1.5.2.
7
8 __revision__ = "$Id$"
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 ('keep-temp', 'k',
25 "keep the pseudo-installation tree around after " +
26 "creating the distribution archive"),
27 ('target-version=', 'v',
28 "require a specific python version" +
29 " on the target system"),
30 ('no-target-compile', 'c',
31 "do not compile .py to .pyc on the target system"),
32 ('no-target-optimize', 'o',
33 "do not compile .py to .pyo (optimized)"
34 "on the target system"),
35 ('dist-dir=', 'd',
36 "directory to put final built distributions in"),
37 ('bitmap=', 'b',
38 "bitmap to use for the installer instead of python-powered logo"),
39 ('title=', 't',
40 "title to display on the installer background instead of default"),
41 ('skip-build', None,
42 "skip rebuilding everything (for testing/debugging)"),
43 ('install-script=', None,
44 "basename of installation script to be run after"
45 "installation or before deinstallation"),
46 ]
47
48 boolean_options = ['keep-temp', 'no-target-compile', 'no-target-optimize',
49 'skip-build']
50
51 def initialize_options (self):
52 self.bdist_dir = None
53 self.keep_temp = 0
54 self.no_target_compile = 0
55 self.no_target_optimize = 0
56 self.target_version = None
57 self.dist_dir = None
58 self.bitmap = None
59 self.title = None
60 self.skip_build = 0
61 self.install_script = None
62
63 # initialize_options()
64
65
66 def finalize_options (self):
67 if self.bdist_dir is None:
68 bdist_base = self.get_finalized_command('bdist').bdist_base
69 self.bdist_dir = os.path.join(bdist_base, 'wininst')
70 if not self.target_version:
71 self.target_version = ""
72 if self.distribution.has_ext_modules():
73 short_version = get_python_version()
74 if self.target_version and self.target_version != short_version:
75 raise DistutilsOptionError, \
76 "target version can only be" + short_version
77 self.target_version = short_version
78
79 self.set_undefined_options('bdist', ('dist_dir', 'dist_dir'))
80
81 if self.install_script:
82 for script in self.distribution.scripts:
83 if self.install_script == os.path.basename(script):
84 break
85 else:
86 raise DistutilsOptionError, \
87 "install_script '%s' not found in scripts" % \
88 self.install_script
89 # finalize_options()
90
91
92 def run (self):
93 if (sys.platform != "win32" and
94 (self.distribution.has_ext_modules() or
95 self.distribution.has_c_libraries())):
96 raise DistutilsPlatformError \
97 ("distribution contains extensions and/or C libraries; "
98 "must be compiled on a Windows 32 platform")
99
100 if not self.skip_build:
101 self.run_command('build')
102
103 install = self.reinitialize_command('install', reinit_subcommands=1)
104 install.root = self.bdist_dir
105 install.skip_build = self.skip_build
106 install.warn_dir = 0
107
108 install_lib = self.reinitialize_command('install_lib')
109 # we do not want to include pyc or pyo files
110 install_lib.compile = 0
111 install_lib.optimize = 0
112
113 # Use a custom scheme for the zip-file, because we have to decide
114 # at installation time which scheme to use.
115 for key in ('purelib', 'platlib', 'headers', 'scripts', 'data'):
116 value = string.upper(key)
117 if key == 'headers':
118 value = value + '/Include/$dist_name'
119 setattr(install,
120 'install_' + key,
121 value)
122
123 log.info("installing to %s", self.bdist_dir)
124 install.ensure_finalized()
125
126 # avoid warning of 'install_lib' about installing
127 # into a directory not in sys.path
128 sys.path.insert(0, os.path.join(self.bdist_dir, 'PURELIB'))
129
130 install.run()
131
132 del sys.path[0]
133
134 # And make an archive relative to the root of the
135 # pseudo-installation tree.
136 from tempfile import mktemp
137 archive_basename = mktemp()
138 fullname = self.distribution.get_fullname()
139 arcname = self.make_archive(archive_basename, "zip",
140 root_dir=self.bdist_dir)
141 # create an exe containing the zip-file
142 self.create_exe(arcname, fullname, self.bitmap)
143 # remove the zip-file again
144 log.debug("removing temporary file '%s'", arcname)
145 os.remove(arcname)
146
147 if not self.keep_temp:
148 remove_tree(self.bdist_dir, dry_run=self.dry_run)
149
150 # run()
151
152 def get_inidata (self):
153 # Return data describing the installation.
154
155 lines = []
156 metadata = self.distribution.metadata
157
158 # Write the [metadata] section. Values are written with
159 # repr()[1:-1], so they do not contain unprintable characters, and
160 # are not surrounded by quote chars.
161 lines.append("[metadata]")
162
163 # 'info' will be displayed in the installer's dialog box,
164 # describing the items to be installed.
165 info = (metadata.long_description or '') + '\n'
166
167 for name in ["author", "author_email", "description", "maintainer",
168 "maintainer_email", "name", "url", "version"]:
169 data = getattr(metadata, name, "")
170 if data:
171 info = info + ("\n %s: %s" % \
172 (string.capitalize(name), data))
173 lines.append("%s=%s" % (name, repr(data)[1:-1]))
174
175 # The [setup] section contains entries controlling
176 # the installer runtime.
177 lines.append("\n[Setup]")
178 if self.install_script:
179 lines.append("install_script=%s" % self.install_script)
180 lines.append("info=%s" % repr(info)[1:-1])
181 lines.append("target_compile=%d" % (not self.no_target_compile))
182 lines.append("target_optimize=%d" % (not self.no_target_optimize))
183 if self.target_version:
184 lines.append("target_version=%s" % self.target_version)
185
186 title = self.title or self.distribution.get_fullname()
187 lines.append("title=%s" % repr(title)[1:-1])
188 import time
189 import distutils
190 build_info = "Build %s with distutils-%s" % \
191 (time.ctime(time.time()), distutils.__version__)
192 lines.append("build_info=%s" % build_info)
193 return string.join(lines, "\n")
194
195 # get_inidata()
196
197 def create_exe (self, arcname, fullname, bitmap=None):
198 import struct
199
200 self.mkpath(self.dist_dir)
201
202 cfgdata = self.get_inidata()
203
204 if self.target_version:
205 # if we create an installer for a specific python version,
206 # it's better to include this in the name
207 installer_name = os.path.join(self.dist_dir,
208 "%s.win32-py%s.exe" %
209 (fullname, self.target_version))
210 else:
211 installer_name = os.path.join(self.dist_dir,
212 "%s.win32.exe" % fullname)
213 self.announce("creating %s" % installer_name)
214
215 if bitmap:
216 bitmapdata = open(bitmap, "rb").read()
217 bitmaplen = len(bitmapdata)
218 else:
219 bitmaplen = 0
220
221 file = open(installer_name, "wb")
222 file.write(self.get_exe_bytes())
223 if bitmap:
224 file.write(bitmapdata)
225
226 file.write(cfgdata)
227 header = struct.pack("<iii",
228 0x1234567A, # tag
229 len(cfgdata), # length
230 bitmaplen, # number of bytes in bitmap
231 )
232 file.write(header)
233 file.write(open(arcname, "rb").read())
234
235 # create_exe()
236
237 def get_exe_bytes (self):
238 # wininst.exe is in the same directory as this file
239 directory = os.path.dirname(__file__)
240 filename = os.path.join(directory, "wininst.exe")
241 return open(filename, "rb").read()
242 # class bdist_wininst