##// END OF EJS Templates
packaging: always pass VERSION into Inno invocation...
Gregory Szorc -
r43824:cf5eaf24 default draft
parent child Browse files
Show More
@@ -1,158 +1,163 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 find_vc_runtime_files
21 from .util import (
22 find_vc_runtime_files,
23 read_version_py,
24 )
22
25
23 EXTRA_PACKAGES = {
26 EXTRA_PACKAGES = {
24 'dulwich',
27 'dulwich',
25 'keyring',
28 'keyring',
26 'pygments',
29 'pygments',
27 'win32ctypes',
30 'win32ctypes',
28 }
31 }
29
32
30 PACKAGE_FILES_METADATA = {
33 PACKAGE_FILES_METADATA = {
31 'ReadMe.html': 'Flags: isreadme',
34 'ReadMe.html': 'Flags: isreadme',
32 }
35 }
33
36
34
37
35 def build(
38 def build(
36 source_dir: pathlib.Path,
39 source_dir: pathlib.Path,
37 build_dir: pathlib.Path,
40 build_dir: pathlib.Path,
38 python_exe: pathlib.Path,
41 python_exe: pathlib.Path,
39 iscc_exe: pathlib.Path,
42 iscc_exe: pathlib.Path,
40 version=None,
43 version=None,
41 ):
44 ):
42 """Build the Inno installer.
45 """Build the Inno installer.
43
46
44 Build files will be placed in ``build_dir``.
47 Build files will be placed in ``build_dir``.
45
48
46 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
49 py2exe's setup.py doesn't use setuptools. It doesn't have modern logic
47 for finding the Python 2.7 toolchain. So, we require the environment
50 for finding the Python 2.7 toolchain. So, we require the environment
48 to already be configured with an active toolchain.
51 to already be configured with an active toolchain.
49 """
52 """
50 if not iscc_exe.exists():
53 if not iscc_exe.exists():
51 raise Exception('%s does not exist' % iscc_exe)
54 raise Exception('%s does not exist' % iscc_exe)
52
55
53 vc_x64 = r'\x64' in os.environ.get('LIB', '')
56 vc_x64 = r'\x64' in os.environ.get('LIB', '')
54 arch = 'x64' if vc_x64 else 'x86'
57 arch = 'x64' if vc_x64 else 'x86'
55 inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno'
58 inno_source_dir = source_dir / 'contrib' / 'packaging' / 'inno'
56 inno_build_dir = build_dir / ('inno-%s' % arch)
59 inno_build_dir = build_dir / ('inno-%s' % arch)
57 staging_dir = inno_build_dir / 'stage'
60 staging_dir = inno_build_dir / 'stage'
58
61
59 requirements_txt = (
62 requirements_txt = (
60 source_dir / 'contrib' / 'packaging' / 'inno' / 'requirements.txt'
63 source_dir / 'contrib' / 'packaging' / 'inno' / 'requirements.txt'
61 )
64 )
62
65
63 inno_build_dir.mkdir(parents=True, exist_ok=True)
66 inno_build_dir.mkdir(parents=True, exist_ok=True)
64
67
65 build_py2exe(
68 build_py2exe(
66 source_dir,
69 source_dir,
67 build_dir,
70 build_dir,
68 python_exe,
71 python_exe,
69 'inno',
72 'inno',
70 requirements_txt,
73 requirements_txt,
71 extra_packages=EXTRA_PACKAGES,
74 extra_packages=EXTRA_PACKAGES,
72 )
75 )
73
76
74 # Purge the staging directory for every build so packaging is
77 # Purge the staging directory for every build so packaging is
75 # pristine.
78 # pristine.
76 if staging_dir.exists():
79 if staging_dir.exists():
77 print('purging %s' % staging_dir)
80 print('purging %s' % staging_dir)
78 shutil.rmtree(staging_dir)
81 shutil.rmtree(staging_dir)
79
82
80 # Now assemble all the packaged files into the staging directory.
83 # Now assemble all the packaged files into the staging directory.
81 stage_install(source_dir, staging_dir)
84 stage_install(source_dir, staging_dir)
82
85
83 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
86 # hg.exe depends on VC9 runtime DLLs. Copy those into place.
84 for f in find_vc_runtime_files(vc_x64):
87 for f in find_vc_runtime_files(vc_x64):
85 if f.name.endswith('.manifest'):
88 if f.name.endswith('.manifest'):
86 basename = 'Microsoft.VC90.CRT.manifest'
89 basename = 'Microsoft.VC90.CRT.manifest'
87 else:
90 else:
88 basename = f.name
91 basename = f.name
89
92
90 dest_path = staging_dir / basename
93 dest_path = staging_dir / basename
91
94
92 print('copying %s to %s' % (f, dest_path))
95 print('copying %s to %s' % (f, dest_path))
93 shutil.copyfile(f, dest_path)
96 shutil.copyfile(f, dest_path)
94
97
95 # The final package layout is simply a mirror of the staging directory.
98 # The final package layout is simply a mirror of the staging directory.
96 package_files = []
99 package_files = []
97 for root, dirs, files in os.walk(staging_dir):
100 for root, dirs, files in os.walk(staging_dir):
98 dirs.sort()
101 dirs.sort()
99
102
100 root = pathlib.Path(root)
103 root = pathlib.Path(root)
101
104
102 for f in sorted(files):
105 for f in sorted(files):
103 full = root / f
106 full = root / f
104 rel = full.relative_to(staging_dir)
107 rel = full.relative_to(staging_dir)
105 if str(rel.parent) == '.':
108 if str(rel.parent) == '.':
106 dest_dir = '{app}'
109 dest_dir = '{app}'
107 else:
110 else:
108 dest_dir = '{app}\\%s' % rel.parent
111 dest_dir = '{app}\\%s' % rel.parent
109
112
110 package_files.append(
113 package_files.append(
111 {
114 {
112 'source': rel,
115 'source': rel,
113 'dest_dir': dest_dir,
116 'dest_dir': dest_dir,
114 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
117 'metadata': PACKAGE_FILES_METADATA.get(str(rel), None),
115 }
118 }
116 )
119 )
117
120
118 print('creating installer')
121 print('creating installer')
119
122
120 # Install Inno files by rendering a template.
123 # Install Inno files by rendering a template.
121 jinja_env = jinja2.Environment(
124 jinja_env = jinja2.Environment(
122 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
125 loader=jinja2.FileSystemLoader(str(inno_source_dir)),
123 # Need to change these to prevent conflict with Inno Setup.
126 # Need to change these to prevent conflict with Inno Setup.
124 comment_start_string='{##',
127 comment_start_string='{##',
125 comment_end_string='##}',
128 comment_end_string='##}',
126 )
129 )
127
130
128 try:
131 try:
129 template = jinja_env.get_template('mercurial.iss')
132 template = jinja_env.get_template('mercurial.iss')
130 except jinja2.TemplateSyntaxError as e:
133 except jinja2.TemplateSyntaxError as e:
131 raise Exception(
134 raise Exception(
132 'template syntax error at %s:%d: %s'
135 'template syntax error at %s:%d: %s'
133 % (e.name, e.lineno, e.message,)
136 % (e.name, e.lineno, e.message,)
134 )
137 )
135
138
136 content = template.render(package_files=package_files)
139 content = template.render(package_files=package_files)
137
140
138 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
141 with (inno_build_dir / 'mercurial.iss').open('w', encoding='utf-8') as fh:
139 fh.write(content)
142 fh.write(content)
140
143
141 # Copy additional files used by Inno.
144 # Copy additional files used by Inno.
142 for p in ('mercurial.ico', 'postinstall.txt'):
145 for p in ('mercurial.ico', 'postinstall.txt'):
143 shutil.copyfile(
146 shutil.copyfile(
144 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
147 source_dir / 'contrib' / 'win32' / p, inno_build_dir / p
145 )
148 )
146
149
147 args = [str(iscc_exe)]
150 args = [str(iscc_exe)]
148
151
149 if vc_x64:
152 if vc_x64:
150 args.append('/dARCH=x64')
153 args.append('/dARCH=x64')
151
154
152 if version:
155 if not version:
153 args.append('/dVERSION=%s' % version)
156 version = read_version_py(source_dir)
157
158 args.append('/dVERSION=%s' % version)
154
159
155 args.append('/Odist')
160 args.append('/Odist')
156 args.append(str(inno_build_dir / 'mercurial.iss'))
161 args.append(str(inno_build_dir / 'mercurial.iss'))
157
162
158 subprocess.run(args, cwd=str(source_dir), check=True)
163 subprocess.run(args, cwd=str(source_dir), check=True)
@@ -1,212 +1,226 b''
1 # util.py - Common packaging utility code.
1 # util.py - Common packaging utility code.
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 distutils.version
10 import distutils.version
11 import getpass
11 import getpass
12 import glob
12 import glob
13 import os
13 import os
14 import pathlib
14 import pathlib
15 import re
15 import shutil
16 import shutil
16 import subprocess
17 import subprocess
17 import tarfile
18 import tarfile
18 import zipfile
19 import zipfile
19
20
20
21
21 def extract_tar_to_directory(source: pathlib.Path, dest: pathlib.Path):
22 def extract_tar_to_directory(source: pathlib.Path, dest: pathlib.Path):
22 with tarfile.open(source, 'r') as tf:
23 with tarfile.open(source, 'r') as tf:
23 tf.extractall(dest)
24 tf.extractall(dest)
24
25
25
26
26 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path):
27 def extract_zip_to_directory(source: pathlib.Path, dest: pathlib.Path):
27 with zipfile.ZipFile(source, 'r') as zf:
28 with zipfile.ZipFile(source, 'r') as zf:
28 zf.extractall(dest)
29 zf.extractall(dest)
29
30
30
31
31 def find_vc_runtime_files(x64=False):
32 def find_vc_runtime_files(x64=False):
32 """Finds Visual C++ Runtime DLLs to include in distribution."""
33 """Finds Visual C++ Runtime DLLs to include in distribution."""
33 winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS'
34 winsxs = pathlib.Path(os.environ['SYSTEMROOT']) / 'WinSxS'
34
35
35 prefix = 'amd64' if x64 else 'x86'
36 prefix = 'amd64' if x64 else 'x86'
36
37
37 candidates = sorted(
38 candidates = sorted(
38 p
39 p
39 for p in os.listdir(winsxs)
40 for p in os.listdir(winsxs)
40 if p.lower().startswith('%s_microsoft.vc90.crt_' % prefix)
41 if p.lower().startswith('%s_microsoft.vc90.crt_' % prefix)
41 )
42 )
42
43
43 for p in candidates:
44 for p in candidates:
44 print('found candidate VC runtime: %s' % p)
45 print('found candidate VC runtime: %s' % p)
45
46
46 # Take the newest version.
47 # Take the newest version.
47 version = candidates[-1]
48 version = candidates[-1]
48
49
49 d = winsxs / version
50 d = winsxs / version
50
51
51 return [
52 return [
52 d / 'msvcm90.dll',
53 d / 'msvcm90.dll',
53 d / 'msvcp90.dll',
54 d / 'msvcp90.dll',
54 d / 'msvcr90.dll',
55 d / 'msvcr90.dll',
55 winsxs / 'Manifests' / ('%s.manifest' % version),
56 winsxs / 'Manifests' / ('%s.manifest' % version),
56 ]
57 ]
57
58
58
59
59 def windows_10_sdk_info():
60 def windows_10_sdk_info():
60 """Resolves information about the Windows 10 SDK."""
61 """Resolves information about the Windows 10 SDK."""
61
62
62 base = pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Windows Kits' / '10'
63 base = pathlib.Path(os.environ['ProgramFiles(x86)']) / 'Windows Kits' / '10'
63
64
64 if not base.is_dir():
65 if not base.is_dir():
65 raise Exception('unable to find Windows 10 SDK at %s' % base)
66 raise Exception('unable to find Windows 10 SDK at %s' % base)
66
67
67 # Find the latest version.
68 # Find the latest version.
68 bin_base = base / 'bin'
69 bin_base = base / 'bin'
69
70
70 versions = [v for v in os.listdir(bin_base) if v.startswith('10.')]
71 versions = [v for v in os.listdir(bin_base) if v.startswith('10.')]
71 version = sorted(versions, reverse=True)[0]
72 version = sorted(versions, reverse=True)[0]
72
73
73 bin_version = bin_base / version
74 bin_version = bin_base / version
74
75
75 return {
76 return {
76 'root': base,
77 'root': base,
77 'version': version,
78 'version': version,
78 'bin_root': bin_version,
79 'bin_root': bin_version,
79 'bin_x86': bin_version / 'x86',
80 'bin_x86': bin_version / 'x86',
80 'bin_x64': bin_version / 'x64',
81 'bin_x64': bin_version / 'x64',
81 }
82 }
82
83
83
84
84 def find_signtool():
85 def find_signtool():
85 """Find signtool.exe from the Windows SDK."""
86 """Find signtool.exe from the Windows SDK."""
86 sdk = windows_10_sdk_info()
87 sdk = windows_10_sdk_info()
87
88
88 for key in ('bin_x64', 'bin_x86'):
89 for key in ('bin_x64', 'bin_x86'):
89 p = sdk[key] / 'signtool.exe'
90 p = sdk[key] / 'signtool.exe'
90
91
91 if p.exists():
92 if p.exists():
92 return p
93 return p
93
94
94 raise Exception('could not find signtool.exe in Windows 10 SDK')
95 raise Exception('could not find signtool.exe in Windows 10 SDK')
95
96
96
97
97 def sign_with_signtool(
98 def sign_with_signtool(
98 file_path,
99 file_path,
99 description,
100 description,
100 subject_name=None,
101 subject_name=None,
101 cert_path=None,
102 cert_path=None,
102 cert_password=None,
103 cert_password=None,
103 timestamp_url=None,
104 timestamp_url=None,
104 ):
105 ):
105 """Digitally sign a file with signtool.exe.
106 """Digitally sign a file with signtool.exe.
106
107
107 ``file_path`` is file to sign.
108 ``file_path`` is file to sign.
108 ``description`` is text that goes in the signature.
109 ``description`` is text that goes in the signature.
109
110
110 The signing certificate can be specified by ``cert_path`` or
111 The signing certificate can be specified by ``cert_path`` or
111 ``subject_name``. These correspond to the ``/f`` and ``/n`` arguments
112 ``subject_name``. These correspond to the ``/f`` and ``/n`` arguments
112 to signtool.exe, respectively.
113 to signtool.exe, respectively.
113
114
114 The certificate password can be specified via ``cert_password``. If
115 The certificate password can be specified via ``cert_password``. If
115 not provided, you will be prompted for the password.
116 not provided, you will be prompted for the password.
116
117
117 ``timestamp_url`` is the URL of a RFC 3161 timestamp server (``/tr``
118 ``timestamp_url`` is the URL of a RFC 3161 timestamp server (``/tr``
118 argument to signtool.exe).
119 argument to signtool.exe).
119 """
120 """
120 if cert_path and subject_name:
121 if cert_path and subject_name:
121 raise ValueError('cannot specify both cert_path and subject_name')
122 raise ValueError('cannot specify both cert_path and subject_name')
122
123
123 while cert_path and not cert_password:
124 while cert_path and not cert_password:
124 cert_password = getpass.getpass('password for %s: ' % cert_path)
125 cert_password = getpass.getpass('password for %s: ' % cert_path)
125
126
126 args = [
127 args = [
127 str(find_signtool()),
128 str(find_signtool()),
128 'sign',
129 'sign',
129 '/v',
130 '/v',
130 '/fd',
131 '/fd',
131 'sha256',
132 'sha256',
132 '/d',
133 '/d',
133 description,
134 description,
134 ]
135 ]
135
136
136 if cert_path:
137 if cert_path:
137 args.extend(['/f', str(cert_path), '/p', cert_password])
138 args.extend(['/f', str(cert_path), '/p', cert_password])
138 elif subject_name:
139 elif subject_name:
139 args.extend(['/n', subject_name])
140 args.extend(['/n', subject_name])
140
141
141 if timestamp_url:
142 if timestamp_url:
142 args.extend(['/tr', timestamp_url, '/td', 'sha256'])
143 args.extend(['/tr', timestamp_url, '/td', 'sha256'])
143
144
144 args.append(str(file_path))
145 args.append(str(file_path))
145
146
146 print('signing %s' % file_path)
147 print('signing %s' % file_path)
147 subprocess.run(args, check=True)
148 subprocess.run(args, check=True)
148
149
149
150
150 PRINT_PYTHON_INFO = '''
151 PRINT_PYTHON_INFO = '''
151 import platform; print("%s:%s" % (platform.architecture()[0], platform.python_version()))
152 import platform; print("%s:%s" % (platform.architecture()[0], platform.python_version()))
152 '''.strip()
153 '''.strip()
153
154
154
155
155 def python_exe_info(python_exe: pathlib.Path):
156 def python_exe_info(python_exe: pathlib.Path):
156 """Obtain information about a Python executable."""
157 """Obtain information about a Python executable."""
157
158
158 res = subprocess.check_output([str(python_exe), '-c', PRINT_PYTHON_INFO])
159 res = subprocess.check_output([str(python_exe), '-c', PRINT_PYTHON_INFO])
159
160
160 arch, version = res.decode('utf-8').split(':')
161 arch, version = res.decode('utf-8').split(':')
161
162
162 version = distutils.version.LooseVersion(version)
163 version = distutils.version.LooseVersion(version)
163
164
164 return {
165 return {
165 'arch': arch,
166 'arch': arch,
166 'version': version,
167 'version': version,
167 'py3': version >= distutils.version.LooseVersion('3'),
168 'py3': version >= distutils.version.LooseVersion('3'),
168 }
169 }
169
170
170
171
171 def process_install_rules(
172 def process_install_rules(
172 rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path
173 rules: list, source_dir: pathlib.Path, dest_dir: pathlib.Path
173 ):
174 ):
174 for source, dest in rules:
175 for source, dest in rules:
175 if '*' in source:
176 if '*' in source:
176 if not dest.endswith('/'):
177 if not dest.endswith('/'):
177 raise ValueError('destination must end in / when globbing')
178 raise ValueError('destination must end in / when globbing')
178
179
179 # We strip off the source path component before the first glob
180 # We strip off the source path component before the first glob
180 # character to construct the relative install path.
181 # character to construct the relative install path.
181 prefix_end_index = source[: source.index('*')].rindex('/')
182 prefix_end_index = source[: source.index('*')].rindex('/')
182 relative_prefix = source_dir / source[0:prefix_end_index]
183 relative_prefix = source_dir / source[0:prefix_end_index]
183
184
184 for res in glob.glob(str(source_dir / source), recursive=True):
185 for res in glob.glob(str(source_dir / source), recursive=True):
185 source_path = pathlib.Path(res)
186 source_path = pathlib.Path(res)
186
187
187 if source_path.is_dir():
188 if source_path.is_dir():
188 continue
189 continue
189
190
190 rel_path = source_path.relative_to(relative_prefix)
191 rel_path = source_path.relative_to(relative_prefix)
191
192
192 dest_path = dest_dir / dest[:-1] / rel_path
193 dest_path = dest_dir / dest[:-1] / rel_path
193
194
194 dest_path.parent.mkdir(parents=True, exist_ok=True)
195 dest_path.parent.mkdir(parents=True, exist_ok=True)
195 print('copying %s to %s' % (source_path, dest_path))
196 print('copying %s to %s' % (source_path, dest_path))
196 shutil.copy(source_path, dest_path)
197 shutil.copy(source_path, dest_path)
197
198
198 # Simple file case.
199 # Simple file case.
199 else:
200 else:
200 source_path = pathlib.Path(source)
201 source_path = pathlib.Path(source)
201
202
202 if dest.endswith('/'):
203 if dest.endswith('/'):
203 dest_path = pathlib.Path(dest) / source_path.name
204 dest_path = pathlib.Path(dest) / source_path.name
204 else:
205 else:
205 dest_path = pathlib.Path(dest)
206 dest_path = pathlib.Path(dest)
206
207
207 full_source_path = source_dir / source_path
208 full_source_path = source_dir / source_path
208 full_dest_path = dest_dir / dest_path
209 full_dest_path = dest_dir / dest_path
209
210
210 full_dest_path.parent.mkdir(parents=True, exist_ok=True)
211 full_dest_path.parent.mkdir(parents=True, exist_ok=True)
211 shutil.copy(full_source_path, full_dest_path)
212 shutil.copy(full_source_path, full_dest_path)
212 print('copying %s to %s' % (full_source_path, full_dest_path))
213 print('copying %s to %s' % (full_source_path, full_dest_path))
214
215
216 def read_version_py(source_dir):
217 """Read the mercurial/__version__.py file to resolve the version string."""
218 p = source_dir / 'mercurial' / '__version__.py'
219
220 with p.open('r', encoding='utf-8') as fh:
221 m = re.search('version = b"([^"]+)"', fh.read(), re.MULTILINE)
222
223 if not m:
224 raise Exception('could not parse %s' % p)
225
226 return m.group(1)
@@ -1,98 +1,83 b''
1 ; Script generated by the Inno Setup Script Wizard.
1 ; Script generated by the Inno Setup Script Wizard.
2 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
2 ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
3
3
4 #ifndef VERSION
5 #define FileHandle
6 #define FileLine
7 #define VERSION = "unknown"
8 #if FileHandle = FileOpen(SourcePath + "\..\..\mercurial\__version__.py")
9 #expr FileLine = FileRead(FileHandle)
10 #expr FileLine = FileRead(FileHandle)
11 #define VERSION = Copy(FileLine, Pos('"', FileLine)+1, Len(FileLine)-Pos('"', FileLine)-1)
12 #endif
13 #if FileHandle
14 #expr FileClose(FileHandle)
15 #endif
16 #pragma message "Detected Version: " + VERSION
17 #endif
18
19 #ifndef ARCH
4 #ifndef ARCH
20 #define ARCH = "x86"
5 #define ARCH = "x86"
21 #endif
6 #endif
22
7
23 [Setup]
8 [Setup]
24 AppCopyright=Copyright 2005-2019 Matt Mackall and others
9 AppCopyright=Copyright 2005-2019 Matt Mackall and others
25 AppName=Mercurial
10 AppName=Mercurial
26 AppVersion={#VERSION}
11 AppVersion={#VERSION}
27 #if ARCH == "x64"
12 #if ARCH == "x64"
28 AppVerName=Mercurial {#VERSION} (64-bit)
13 AppVerName=Mercurial {#VERSION} (64-bit)
29 OutputBaseFilename=Mercurial-{#VERSION}-x64
14 OutputBaseFilename=Mercurial-{#VERSION}-x64
30 ArchitecturesAllowed=x64
15 ArchitecturesAllowed=x64
31 ArchitecturesInstallIn64BitMode=x64
16 ArchitecturesInstallIn64BitMode=x64
32 #else
17 #else
33 AppVerName=Mercurial {#VERSION}
18 AppVerName=Mercurial {#VERSION}
34 OutputBaseFilename=Mercurial-{#VERSION}
19 OutputBaseFilename=Mercurial-{#VERSION}
35 #endif
20 #endif
36 InfoAfterFile=../postinstall.txt
21 InfoAfterFile=../postinstall.txt
37 LicenseFile=Copying.txt
22 LicenseFile=Copying.txt
38 ShowLanguageDialog=yes
23 ShowLanguageDialog=yes
39 AppPublisher=Matt Mackall and others
24 AppPublisher=Matt Mackall and others
40 AppPublisherURL=https://mercurial-scm.org/
25 AppPublisherURL=https://mercurial-scm.org/
41 AppSupportURL=https://mercurial-scm.org/
26 AppSupportURL=https://mercurial-scm.org/
42 AppUpdatesURL=https://mercurial-scm.org/
27 AppUpdatesURL=https://mercurial-scm.org/
43 {{ 'AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}' }}
28 {{ 'AppID={{4B95A5F1-EF59-4B08-BED8-C891C46121B3}' }}
44 AppContact=mercurial@mercurial-scm.org
29 AppContact=mercurial@mercurial-scm.org
45 DefaultDirName={pf}\Mercurial
30 DefaultDirName={pf}\Mercurial
46 SourceDir=stage
31 SourceDir=stage
47 VersionInfoDescription=Mercurial distributed SCM (version {#VERSION})
32 VersionInfoDescription=Mercurial distributed SCM (version {#VERSION})
48 VersionInfoCopyright=Copyright 2005-2019 Matt Mackall and others
33 VersionInfoCopyright=Copyright 2005-2019 Matt Mackall and others
49 VersionInfoCompany=Matt Mackall and others
34 VersionInfoCompany=Matt Mackall and others
50 InternalCompressLevel=max
35 InternalCompressLevel=max
51 SolidCompression=true
36 SolidCompression=true
52 SetupIconFile=../mercurial.ico
37 SetupIconFile=../mercurial.ico
53 AllowNoIcons=true
38 AllowNoIcons=true
54 DefaultGroupName=Mercurial
39 DefaultGroupName=Mercurial
55 PrivilegesRequired=none
40 PrivilegesRequired=none
56 ChangesEnvironment=true
41 ChangesEnvironment=true
57
42
58 [Files]
43 [Files]
59 {% for entry in package_files -%}
44 {% for entry in package_files -%}
60 Source: {{ entry.source }}; DestDir: {{ entry.dest_dir }}
45 Source: {{ entry.source }}; DestDir: {{ entry.dest_dir }}
61 {%- if entry.metadata %}; {{ entry.metadata }}{% endif %}
46 {%- if entry.metadata %}; {{ entry.metadata }}{% endif %}
62 {% endfor %}
47 {% endfor %}
63
48
64 [INI]
49 [INI]
65 Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/
50 Filename: {app}\Mercurial.url; Section: InternetShortcut; Key: URL; String: https://mercurial-scm.org/
66 Filename: {app}\default.d\editor.rc; Section: ui; Key: editor; String: notepad
51 Filename: {app}\default.d\editor.rc; Section: ui; Key: editor; String: notepad
67
52
68 [UninstallDelete]
53 [UninstallDelete]
69 Type: files; Name: {app}\Mercurial.url
54 Type: files; Name: {app}\Mercurial.url
70 Type: filesandordirs; Name: {app}\default.d
55 Type: filesandordirs; Name: {app}\default.d
71
56
72 [Icons]
57 [Icons]
73 Name: {group}\Uninstall Mercurial; Filename: {uninstallexe}
58 Name: {group}\Uninstall Mercurial; Filename: {uninstallexe}
74 Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html
59 Name: {group}\Mercurial Command Reference; Filename: {app}\Docs\hg.1.html
75 Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html
60 Name: {group}\Mercurial Configuration Files; Filename: {app}\Docs\hgrc.5.html
76 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
61 Name: {group}\Mercurial Ignore Files; Filename: {app}\Docs\hgignore.5.html
77 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
62 Name: {group}\Mercurial Web Site; Filename: {app}\Mercurial.url
78
63
79 [Tasks]
64 [Tasks]
80 Name: modifypath; Description: Add the installation path to the search path; Flags: unchecked
65 Name: modifypath; Description: Add the installation path to the search path; Flags: unchecked
81
66
82 [Code]
67 [Code]
83 procedure Touch(fn: String);
68 procedure Touch(fn: String);
84 begin
69 begin
85 SaveStringToFile(ExpandConstant(fn), '', False);
70 SaveStringToFile(ExpandConstant(fn), '', False);
86 end;
71 end;
87
72
88 const
73 const
89 ModPathName = 'modifypath';
74 ModPathName = 'modifypath';
90 ModPathType = 'user';
75 ModPathType = 'user';
91
76
92 function ModPathDir(): TArrayOfString;
77 function ModPathDir(): TArrayOfString;
93 begin
78 begin
94 setArrayLength(Result, 1)
79 setArrayLength(Result, 1)
95 Result[0] := ExpandConstant('{app}');
80 Result[0] := ExpandConstant('{app}');
96 end;
81 end;
97
82
98 {% include 'modpath.iss' %}
83 {% include 'modpath.iss' %}
General Comments 0
You need to be logged in to leave comments. Login now