##// END OF EJS Templates
packaging: split Inno installer building from Mercurial building...
Gregory Szorc -
r45255:5760936e default draft
parent child Browse files
Show More
@@ -1,173 +1,197 b''
1 1 # inno.py - Inno Setup functionality.
2 2 #
3 3 # Copyright 2019 Gregory Szorc <gregory.szorc@gmail.com>
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 # no-check-code because Python 3 native.
9 9
10 10 import os
11 11 import pathlib
12 12 import shutil
13 13 import subprocess
14 14
15 15 import jinja2
16 16
17 17 from .py2exe import (
18 18 build_py2exe,
19 19 stage_install,
20 20 )
21 21 from .util import (
22 22 find_vc_runtime_files,
23 23 normalize_windows_version,
24 24 process_install_rules,
25 25 read_version_py,
26 26 )
27 27
28 28 EXTRA_PACKAGES = {
29 29 'dulwich',
30 30 'keyring',
31 31 'pygments',
32 32 'win32ctypes',
33 33 }
34 34
35 35 EXTRA_INSTALL_RULES = [
36 36 ('contrib/win32/mercurial.ini', 'defaultrc/mercurial.rc'),
37 37 ]
38 38
39 39 PACKAGE_FILES_METADATA = {
40 40 'ReadMe.html': 'Flags: isreadme',
41 41 }
42 42
43 43
44 44 def build(
45 45 source_dir: pathlib.Path,
46 46 build_dir: pathlib.Path,
47 47 python_exe: pathlib.Path,
48 48 iscc_exe: pathlib.Path,
49 49 version=None,
50 50 ):
51 51 """Build the Inno installer.
52 52
53 53 Build files will be placed in ``build_dir``.
54 54
55 55 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
56 56 for finding the Python 2.7 toolchain. So, we require the environment
57 57 to already be configured with an active toolchain.
58 58 """
59 59 if not iscc_exe.exists():
60 60 raise Exception('%s does not exist' % iscc_exe)
61 61
62 62 vc_x64 = r'\x64' in os.environ.get('LIB', '')
63 63 arch = 'x64' if vc_x64 else 'x86'
64 inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno'
65 inno_build_dir = build_dir / ('inno-%s' % arch)
64 inno_build_dir = build_dir / ('inno-py2exe-%s' % arch)
66 65 staging_dir = inno_build_dir / 'stage'
67 66
68 67 requirements_txt = (
69 68 source_dir / 'contrib' / 'packaging' / 'requirements_win32.txt'
70 69 )
71 70
72 71 inno_build_dir.mkdir(parents=True, exist_ok=True)
73 72
74 73 build_py2exe(
75 74 source_dir,
76 75 build_dir,
77 76 python_exe,
78 77 'inno',
79 78 requirements_txt,
80 79 extra_packages=EXTRA_PACKAGES,
81 80 )
82 81
83 82 # Purge the staging directory for every build so packaging is
84 83 # pristine.
85 84 if staging_dir.exists():
86 85 print('purging %s' % staging_dir)
87 86 shutil.rmtree(staging_dir)
88 87
89 88 # Now assemble all the packaged files into the staging directory.
90 89 stage_install(source_dir, staging_dir)
91 90
92 91 # We also install some extra files.
93 92 process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir)
94 93
95 94 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
96 95 for f in find_vc_runtime_files(vc_x64):
97 96 if f.name.endswith('.manifest'):
98 97 basename = 'Microsoft.VC90.CRT.manifest'
99 98 else:
100 99 basename = f.name
101 100
102 101 dest_path = staging_dir / basename
103 102
104 103 print('copying %s to %s' % (f, dest_path))
105 104 shutil.copyfile(f, dest_path)
106 105
106 build_installer(
107 source_dir,
108 inno_build_dir,
109 staging_dir,
110 iscc_exe,
111 version,
112 arch="x64" if vc_x64 else None,
113 )
114
115
116 def build_installer(
117 source_dir: pathlib.Path,
118 inno_build_dir: pathlib.Path,
119 staging_dir: pathlib.Path,
120 iscc_exe: pathlib.Path,
121 version,
122 arch=None,
123 ):
124 """Build an Inno installer from staged Mercurial files.
125
126 This function is agnostic about how to build Mercurial. It just
127 cares that Mercurial files are in ``staging_dir``.
128 """
129 inno_source_dir = source_dir / "contrib" / "packaging" / "inno"
130
107 131 # The final package layout is simply a mirror of the staging directory.
108 132 package_files = []
109 133 for root, dirs, files in os.walk(staging_dir):
110 134 dirs.sort()
111 135
112 136 root = pathlib.Path(root)
113 137
114 138 for f in sorted(files):
115 139 full = root / f
116 140 rel = full.relative_to(staging_dir)
117 141 if str(rel.parent) == '.':
118 142 dest_dir = '{app}'
119 143 else:
120 144 dest_dir = '{app}\\%s' % rel.parent
121 145
122 146 package_files.append(
123 147 {
124 148 'source': rel,
125 149 'dest_dir': dest_dir,
126 150 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
127 151 }
128 152 )
129 153
130 154 print('creating installer')
131 155
132 156 # Install Inno files by rendering a template.
133 157 jinja_env = jinja2.Environment(
134 158 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
135 159 # Need to change these to prevent conflict with Inno Setup.
136 160 comment_start_string='{##',
137 161 comment_end_string='##}',
138 162 )
139 163
140 164 try:
141 165 template = jinja_env.get_template('mercurial.iss')
142 166 except jinja2.TemplateSyntaxError as e:
143 167 raise Exception(
144 168 'template syntax error at %s:%d: %s'
145 169 % (e.name, e.lineno, e.message,)
146 170 )
147 171
148 172 content = template.render(package_files=package_files)
149 173
150 174 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
151 175 fh.write(content)
152 176
153 177 # Copy additional files used by Inno.
154 178 for p in ('mercurial.ico', 'postinstall.txt'):
155 179 shutil.copyfile(
156 180 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
157 181 )
158 182
159 183 args = [str(iscc_exe)]
160 184
161 if vc_x64:
162 args.append('/dARCH=x64')
185 if arch:
186 args.append('/dARCH=%s' % arch)
163 187
164 188 if not version:
165 189 version = read_version_py(source_dir)
166 190
167 191 args.append('/dVERSION=%s' % version)
168 192 args.append('/dQUAD_VERSION=%s' % normalize_windows_version(version))
169 193
170 194 args.append('/Odist')
171 195 args.append(str(inno_build_dir / 'mercurial.iss'))
172 196
173 197 subprocess.run(args, cwd=str(source_dir), check=True)
General Comments 0
You need to be logged in to leave comments. Login now