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