Show More
@@ -209,13 +209,26 b' def build_py2exe(' | |||||
209 | ) |
|
209 | ) | |
210 |
|
210 | |||
211 |
|
211 | |||
212 | def stage_install(source_dir: pathlib.Path, staging_dir: pathlib.Path): |
|
212 | def stage_install( | |
|
213 | source_dir: pathlib.Path, staging_dir: pathlib.Path, lower_case=False | |||
|
214 | ): | |||
213 | """Copy all files to be installed to a directory. |
|
215 | """Copy all files to be installed to a directory. | |
214 |
|
216 | |||
215 | This allows packaging to simply walk a directory tree to find source |
|
217 | This allows packaging to simply walk a directory tree to find source | |
216 | files. |
|
218 | files. | |
217 | """ |
|
219 | """ | |
218 | process_install_rules(STAGING_RULES, source_dir, staging_dir) |
|
220 | if lower_case: | |
|
221 | rules = [] | |||
|
222 | for source, dest in STAGING_RULES: | |||
|
223 | # Only lower directory names. | |||
|
224 | if '/' in dest: | |||
|
225 | parent, leaf = dest.rsplit('/', 1) | |||
|
226 | dest = '%s/%s' % (parent.lower(), leaf) | |||
|
227 | rules.append((source, dest)) | |||
|
228 | else: | |||
|
229 | rules = STAGING_RULES | |||
|
230 | ||||
|
231 | process_install_rules(rules, source_dir, staging_dir) | |||
219 |
|
232 | |||
220 | # Write out a default editor.rc file to configure notepad as the |
|
233 | # Write out a default editor.rc file to configure notepad as the | |
221 | # default editor. |
|
234 | # default editor. |
@@ -7,38 +7,60 b'' | |||||
7 |
|
7 | |||
8 | # no-check-code because Python 3 native. |
|
8 | # no-check-code because Python 3 native. | |
9 |
|
9 | |||
|
10 | import collections | |||
10 | import os |
|
11 | import os | |
11 | import pathlib |
|
12 | import pathlib | |
12 | import re |
|
13 | import re | |
|
14 | import shutil | |||
13 | import subprocess |
|
15 | import subprocess | |
14 | import tempfile |
|
|||
15 | import typing |
|
16 | import typing | |
|
17 | import uuid | |||
16 | import xml.dom.minidom |
|
18 | import xml.dom.minidom | |
17 |
|
19 | |||
18 | from .downloads import download_entry |
|
20 | from .downloads import download_entry | |
19 |
from .py2exe import |
|
21 | from .py2exe import ( | |
|
22 | build_py2exe, | |||
|
23 | stage_install, | |||
|
24 | ) | |||
20 | from .util import ( |
|
25 | from .util import ( | |
21 | extract_zip_to_directory, |
|
26 | extract_zip_to_directory, | |
|
27 | process_install_rules, | |||
22 | sign_with_signtool, |
|
28 | sign_with_signtool, | |
23 | ) |
|
29 | ) | |
24 |
|
30 | |||
25 |
|
31 | |||
26 | SUPPORT_WXS = [ |
|
|||
27 | ('contrib.wxs', r'contrib'), |
|
|||
28 | ('dist.wxs', r'dist'), |
|
|||
29 | ('doc.wxs', r'doc'), |
|
|||
30 | ('help.wxs', r'mercurial\help'), |
|
|||
31 | ('locale.wxs', r'mercurial\locale'), |
|
|||
32 | ('templates.wxs', r'mercurial\templates'), |
|
|||
33 | ] |
|
|||
34 |
|
||||
35 |
|
||||
36 | EXTRA_PACKAGES = { |
|
32 | EXTRA_PACKAGES = { | |
37 | 'distutils', |
|
33 | 'distutils', | |
38 | 'pygments', |
|
34 | 'pygments', | |
39 | } |
|
35 | } | |
40 |
|
36 | |||
41 |
|
37 | |||
|
38 | EXTRA_INSTALL_RULES = [ | |||
|
39 | ('contrib/packaging/wix/COPYING.rtf', 'COPYING.rtf'), | |||
|
40 | ('contrib/win32/mercurial.ini', 'hgrc.d/mercurial.rc'), | |||
|
41 | ] | |||
|
42 | ||||
|
43 | STAGING_REMOVE_FILES = [ | |||
|
44 | # We use the RTF variant. | |||
|
45 | 'copying.txt', | |||
|
46 | ] | |||
|
47 | ||||
|
48 | SHORTCUTS = { | |||
|
49 | # hg.1.html' | |||
|
50 | 'hg.file.5d3e441c_28d9_5542_afd0_cdd4234f12d5': { | |||
|
51 | 'Name': 'Mercurial Command Reference', | |||
|
52 | }, | |||
|
53 | # hgignore.5.html | |||
|
54 | 'hg.file.5757d8e0_f207_5e10_a2ec_3ba0a062f431': { | |||
|
55 | 'Name': 'Mercurial Ignore Files', | |||
|
56 | }, | |||
|
57 | # hgrc.5.html | |||
|
58 | 'hg.file.92e605fd_1d1a_5dc6_9fc0_5d2998eb8f5e': { | |||
|
59 | 'Name': 'Mercurial Configuration Files', | |||
|
60 | }, | |||
|
61 | } | |||
|
62 | ||||
|
63 | ||||
42 | def find_version(source_dir: pathlib.Path): |
|
64 | def find_version(source_dir: pathlib.Path): | |
43 | version_py = source_dir / 'mercurial' / '__version__.py' |
|
65 | version_py = source_dir / 'mercurial' / '__version__.py' | |
44 |
|
66 | |||
@@ -147,49 +169,165 b' def make_post_build_signing_fn(' | |||||
147 | return post_build_sign |
|
169 | return post_build_sign | |
148 |
|
170 | |||
149 |
|
171 | |||
150 | LIBRARIES_XML = ''' |
|
172 | def make_files_xml(staging_dir: pathlib.Path, is_x64) -> str: | |
151 | <?xml version="1.0" encoding="utf-8"?> |
|
173 | """Create XML string listing every file to be installed.""" | |
152 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> |
|
|||
153 |
|
||||
154 | <?include {wix_dir}/guids.wxi ?> |
|
|||
155 | <?include {wix_dir}/defines.wxi ?> |
|
|||
156 |
|
174 | |||
157 | <Fragment> |
|
175 | # We derive GUIDs from a deterministic file path identifier. | |
158 | <DirectoryRef Id="INSTALLDIR" FileSource="$(var.SourceDir)"> |
|
176 | # We shoehorn the name into something that looks like a URL because | |
159 | <Directory Id="libdir" Name="lib" FileSource="$(var.SourceDir)/lib"> |
|
177 | # the UUID namespaces are supposed to work that way (even though | |
160 | <Component Id="libOutput" Guid="$(var.lib.guid)" Win64='$(var.IsX64)'> |
|
178 | # the input data probably is never validated). | |
161 | </Component> |
|
|||
162 | </Directory> |
|
|||
163 | </DirectoryRef> |
|
|||
164 | </Fragment> |
|
|||
165 | </Wix> |
|
|||
166 | '''.lstrip() |
|
|||
167 |
|
179 | |||
168 |
|
||||
169 | def make_libraries_xml(wix_dir: pathlib.Path, dist_dir: pathlib.Path): |
|
|||
170 | """Make XML data for library components WXS.""" |
|
|||
171 | # We can't use ElementTree because it doesn't handle the |
|
|||
172 | # <?include ?> directives. |
|
|||
173 | doc = xml.dom.minidom.parseString( |
|
180 | doc = xml.dom.minidom.parseString( | |
174 | LIBRARIES_XML.format(wix_dir=str(wix_dir)) |
|
181 | '<?xml version="1.0" encoding="utf-8"?>' | |
|
182 | '<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">' | |||
|
183 | '</Wix>' | |||
175 | ) |
|
184 | ) | |
176 |
|
185 | |||
177 | component = doc.getElementsByTagName('Component')[0] |
|
186 | # Assemble the install layout by directory. This makes it easier to | |
|
187 | # emit XML, since each directory has separate entities. | |||
|
188 | manifest = collections.defaultdict(dict) | |||
|
189 | ||||
|
190 | for root, dirs, files in os.walk(staging_dir): | |||
|
191 | dirs.sort() | |||
|
192 | ||||
|
193 | root = pathlib.Path(root) | |||
|
194 | rel_dir = root.relative_to(staging_dir) | |||
|
195 | ||||
|
196 | for i in range(len(rel_dir.parts)): | |||
|
197 | parent = '/'.join(rel_dir.parts[0 : i + 1]) | |||
|
198 | manifest.setdefault(parent, {}) | |||
|
199 | ||||
|
200 | for f in sorted(files): | |||
|
201 | full = root / f | |||
|
202 | manifest[str(rel_dir).replace('\\', '/')][full.name] = full | |||
|
203 | ||||
|
204 | component_groups = collections.defaultdict(list) | |||
|
205 | ||||
|
206 | # Now emit a <Fragment> for each directory. | |||
|
207 | # Each directory is composed of a <DirectoryRef> pointing to its parent | |||
|
208 | # and defines child <Directory>'s and a <Component> with all the files. | |||
|
209 | for dir_name, entries in sorted(manifest.items()): | |||
|
210 | # The directory id is derived from the path. But the root directory | |||
|
211 | # is special. | |||
|
212 | if dir_name == '.': | |||
|
213 | parent_directory_id = 'INSTALLDIR' | |||
|
214 | else: | |||
|
215 | parent_directory_id = 'hg.dir.%s' % dir_name.replace('/', '.') | |||
178 |
|
216 | |||
179 |
f = doc.createElement('F |
|
217 | fragment = doc.createElement('Fragment') | |
180 | f.setAttribute('Name', 'library.zip') |
|
218 | directory_ref = doc.createElement('DirectoryRef') | |
181 | f.setAttribute('KeyPath', 'yes') |
|
219 | directory_ref.setAttribute('Id', parent_directory_id) | |
182 | component.appendChild(f) |
|
220 | ||
|
221 | # Add <Directory> entries for immediate children directories. | |||
|
222 | for possible_child in sorted(manifest.keys()): | |||
|
223 | if ( | |||
|
224 | dir_name == '.' | |||
|
225 | and '/' not in possible_child | |||
|
226 | and possible_child != '.' | |||
|
227 | ): | |||
|
228 | child_directory_id = 'hg.dir.%s' % possible_child | |||
|
229 | name = possible_child | |||
|
230 | else: | |||
|
231 | if not possible_child.startswith('%s/' % dir_name): | |||
|
232 | continue | |||
|
233 | name = possible_child[len(dir_name) + 1 :] | |||
|
234 | if '/' in name: | |||
|
235 | continue | |||
|
236 | ||||
|
237 | child_directory_id = 'hg.dir.%s' % possible_child.replace( | |||
|
238 | '/', '.' | |||
|
239 | ) | |||
|
240 | ||||
|
241 | directory = doc.createElement('Directory') | |||
|
242 | directory.setAttribute('Id', child_directory_id) | |||
|
243 | directory.setAttribute('Name', name) | |||
|
244 | directory_ref.appendChild(directory) | |||
|
245 | ||||
|
246 | # Add <Component>s for files in this directory. | |||
|
247 | for rel, source_path in sorted(entries.items()): | |||
|
248 | if dir_name == '.': | |||
|
249 | full_rel = rel | |||
|
250 | else: | |||
|
251 | full_rel = '%s/%s' % (dir_name, rel) | |||
183 |
|
252 | |||
184 | lib_dir = dist_dir / 'lib' |
|
253 | component_unique_id = ( | |
|
254 | 'https://www.mercurial-scm.org/wix-installer/0/component/%s' | |||
|
255 | % full_rel | |||
|
256 | ) | |||
|
257 | component_guid = uuid.uuid5(uuid.NAMESPACE_URL, component_unique_id) | |||
|
258 | component_id = 'hg.component.%s' % str(component_guid).replace( | |||
|
259 | '-', '_' | |||
|
260 | ) | |||
|
261 | ||||
|
262 | component = doc.createElement('Component') | |||
|
263 | ||||
|
264 | component.setAttribute('Id', component_id) | |||
|
265 | component.setAttribute('Guid', str(component_guid).upper()) | |||
|
266 | component.setAttribute('Win64', 'yes' if is_x64 else 'no') | |||
|
267 | ||||
|
268 | # Assign this component to a top-level group. | |||
|
269 | if dir_name == '.': | |||
|
270 | component_groups['ROOT'].append(component_id) | |||
|
271 | elif '/' in dir_name: | |||
|
272 | component_groups[dir_name[0 : dir_name.index('/')]].append( | |||
|
273 | component_id | |||
|
274 | ) | |||
|
275 | else: | |||
|
276 | component_groups[dir_name].append(component_id) | |||
|
277 | ||||
|
278 | unique_id = ( | |||
|
279 | 'https://www.mercurial-scm.org/wix-installer/0/%s' % full_rel | |||
|
280 | ) | |||
|
281 | file_guid = uuid.uuid5(uuid.NAMESPACE_URL, unique_id) | |||
|
282 | ||||
|
283 | # IDs have length limits. So use GUID to derive them. | |||
|
284 | file_guid_normalized = str(file_guid).replace('-', '_') | |||
|
285 | file_id = 'hg.file.%s' % file_guid_normalized | |||
185 |
|
286 | |||
186 | for p in sorted(lib_dir.iterdir()): |
|
287 | file_element = doc.createElement('File') | |
187 | if not p.name.endswith(('.dll', '.pyd')): |
|
288 | file_element.setAttribute('Id', file_id) | |
188 | continue |
|
289 | file_element.setAttribute('Source', str(source_path)) | |
|
290 | file_element.setAttribute('KeyPath', 'yes') | |||
|
291 | file_element.setAttribute('ReadOnly', 'yes') | |||
|
292 | ||||
|
293 | component.appendChild(file_element) | |||
|
294 | directory_ref.appendChild(component) | |||
|
295 | ||||
|
296 | fragment.appendChild(directory_ref) | |||
|
297 | doc.documentElement.appendChild(fragment) | |||
|
298 | ||||
|
299 | for group, component_ids in sorted(component_groups.items()): | |||
|
300 | fragment = doc.createElement('Fragment') | |||
|
301 | component_group = doc.createElement('ComponentGroup') | |||
|
302 | component_group.setAttribute('Id', 'hg.group.%s' % group) | |||
|
303 | ||||
|
304 | for component_id in component_ids: | |||
|
305 | component_ref = doc.createElement('ComponentRef') | |||
|
306 | component_ref.setAttribute('Id', component_id) | |||
|
307 | component_group.appendChild(component_ref) | |||
189 |
|
308 | |||
190 | f = doc.createElement('File') |
|
309 | fragment.appendChild(component_group) | |
191 | f.setAttribute('Name', p.name) |
|
310 | doc.documentElement.appendChild(fragment) | |
192 | component.appendChild(f) |
|
311 | ||
|
312 | # Add <Shortcut> to files that have it defined. | |||
|
313 | for file_id, metadata in sorted(SHORTCUTS.items()): | |||
|
314 | els = doc.getElementsByTagName('File') | |||
|
315 | els = [el for el in els if el.getAttribute('Id') == file_id] | |||
|
316 | ||||
|
317 | if not els: | |||
|
318 | raise Exception('could not find File[Id=%s]' % file_id) | |||
|
319 | ||||
|
320 | for el in els: | |||
|
321 | shortcut = doc.createElement('Shortcut') | |||
|
322 | shortcut.setAttribute('Id', 'hg.shortcut.%s' % file_id) | |||
|
323 | shortcut.setAttribute('Directory', 'ProgramMenuDir') | |||
|
324 | shortcut.setAttribute('Icon', 'hgIcon.ico') | |||
|
325 | shortcut.setAttribute('IconIndex', '0') | |||
|
326 | shortcut.setAttribute('Advertise', 'yes') | |||
|
327 | for k, v in sorted(metadata.items()): | |||
|
328 | shortcut.setAttribute(k, v) | |||
|
329 | ||||
|
330 | el.appendChild(shortcut) | |||
193 |
|
331 | |||
194 | return doc.toprettyxml() |
|
332 | return doc.toprettyxml() | |
195 |
|
333 | |||
@@ -248,9 +386,27 b' def build_installer(' | |||||
248 | post_build_fn(source_dir, hg_build_dir, dist_dir, version) |
|
386 | post_build_fn(source_dir, hg_build_dir, dist_dir, version) | |
249 |
|
387 | |||
250 | build_dir = hg_build_dir / ('wix-%s' % arch) |
|
388 | build_dir = hg_build_dir / ('wix-%s' % arch) | |
|
389 | staging_dir = build_dir / 'stage' | |||
251 |
|
390 | |||
252 | build_dir.mkdir(exist_ok=True) |
|
391 | build_dir.mkdir(exist_ok=True) | |
253 |
|
392 | |||
|
393 | # Purge the staging directory for every build so packaging is pristine. | |||
|
394 | if staging_dir.exists(): | |||
|
395 | print('purging %s' % staging_dir) | |||
|
396 | shutil.rmtree(staging_dir) | |||
|
397 | ||||
|
398 | stage_install(source_dir, staging_dir, lower_case=True) | |||
|
399 | ||||
|
400 | # We also install some extra files. | |||
|
401 | process_install_rules(EXTRA_INSTALL_RULES, source_dir, staging_dir) | |||
|
402 | ||||
|
403 | # And remove some files we don't want. | |||
|
404 | for f in STAGING_REMOVE_FILES: | |||
|
405 | p = staging_dir / f | |||
|
406 | if p.exists(): | |||
|
407 | print('removing %s' % p) | |||
|
408 | p.unlink() | |||
|
409 | ||||
254 | wix_pkg, wix_entry = download_entry('wix', hg_build_dir) |
|
410 | wix_pkg, wix_entry = download_entry('wix', hg_build_dir) | |
255 | wix_path = hg_build_dir / ('wix-%s' % wix_entry['version']) |
|
411 | wix_path = hg_build_dir / ('wix-%s' % wix_entry['version']) | |
256 |
|
412 | |||
@@ -263,25 +419,16 b' def build_installer(' | |||||
263 |
|
419 | |||
264 | defines = {'Platform': arch} |
|
420 | defines = {'Platform': arch} | |
265 |
|
421 | |||
266 | for wxs, rel_path in SUPPORT_WXS: |
|
422 | # Derive a .wxs file with the staged files. | |
267 |
|
|
423 | manifest_wxs = build_dir / 'stage.wxs' | |
268 | wxs_source_dir = source_dir / rel_path |
|
424 | with manifest_wxs.open('w', encoding='utf-8') as fh: | |
269 | run_candle(wix_path, build_dir, wxs, wxs_source_dir, defines=defines) |
|
425 | fh.write(make_files_xml(staging_dir, is_x64=arch == 'x64')) | |
|
426 | ||||
|
427 | run_candle(wix_path, build_dir, manifest_wxs, staging_dir, defines=defines) | |||
270 |
|
428 | |||
271 | for source, rel_path in sorted((extra_wxs or {}).items()): |
|
429 | for source, rel_path in sorted((extra_wxs or {}).items()): | |
272 | run_candle(wix_path, build_dir, source, rel_path, defines=defines) |
|
430 | run_candle(wix_path, build_dir, source, rel_path, defines=defines) | |
273 |
|
431 | |||
274 | # candle.exe doesn't like when we have an open handle on the file. |
|
|||
275 | # So use TemporaryDirectory() instead of NamedTemporaryFile(). |
|
|||
276 | with tempfile.TemporaryDirectory() as td: |
|
|||
277 | td = pathlib.Path(td) |
|
|||
278 |
|
||||
279 | tf = td / 'library.wxs' |
|
|||
280 | with tf.open('w') as fh: |
|
|||
281 | fh.write(make_libraries_xml(wix_dir, dist_dir)) |
|
|||
282 |
|
||||
283 | run_candle(wix_path, build_dir, tf, dist_dir, defines=defines) |
|
|||
284 |
|
||||
285 | source = wix_dir / 'mercurial.wxs' |
|
432 | source = wix_dir / 'mercurial.wxs' | |
286 | defines['Version'] = version |
|
433 | defines['Version'] = version | |
287 | defines['Comments'] = 'Installs Mercurial version %s' % version |
|
434 | defines['Comments'] = 'Installs Mercurial version %s' % version | |
@@ -307,20 +454,13 b' def build_installer(' | |||||
307 | str(msi_path), |
|
454 | str(msi_path), | |
308 | ] |
|
455 | ] | |
309 |
|
456 | |||
310 | for source, rel_path in SUPPORT_WXS: |
|
|||
311 | assert source.endswith('.wxs') |
|
|||
312 | args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) |
|
|||
313 |
|
||||
314 | for source, rel_path in sorted((extra_wxs or {}).items()): |
|
457 | for source, rel_path in sorted((extra_wxs or {}).items()): | |
315 | assert source.endswith('.wxs') |
|
458 | assert source.endswith('.wxs') | |
316 | source = os.path.basename(source) |
|
459 | source = os.path.basename(source) | |
317 | args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) |
|
460 | args.append(str(build_dir / ('%s.wixobj' % source[:-4]))) | |
318 |
|
461 | |||
319 | args.extend( |
|
462 | args.extend( | |
320 | [ |
|
463 | [str(build_dir / 'stage.wixobj'), str(build_dir / 'mercurial.wixobj'),] | |
321 | str(build_dir / 'library.wixobj'), |
|
|||
322 | str(build_dir / 'mercurial.wixobj'), |
|
|||
323 | ] |
|
|||
324 | ) |
|
464 | ) | |
325 |
|
465 | |||
326 | subprocess.run(args, cwd=str(source_dir), check=True) |
|
466 | subprocess.run(args, cwd=str(source_dir), check=True) |
@@ -4,46 +4,9 b'' | |||||
4 | and replace 'Mercurial' in this notice with the name of |
|
4 | and replace 'Mercurial' in this notice with the name of | |
5 | your project. Component GUIDs have global namespace! --> |
|
5 | your project. Component GUIDs have global namespace! --> | |
6 |
|
6 | |||
7 | <!-- contrib.wxs --> |
|
|||
8 | <?define contrib.guid = {4E11FFC2-E2F7-482A-8460-9394B5489F02} ?> |
|
|||
9 | <?define contrib.vim.guid = {BB04903A-652D-4C4F-9590-2BD07A2304F2} ?> |
|
|||
10 |
|
||||
11 | <!-- dist.wxs --> |
|
|||
12 | <?define dist.guid = {CE405FE6-CD1E-4873-9C9A-7683AE5A3D90} ?> |
|
|||
13 | <?define lib.guid = {877633b5-0b7e-4b46-8f1c-224a61733297} ?> |
|
|||
14 |
|
||||
15 | <!-- doc.wxs --> |
|
|||
16 | <?define doc.hg.1.html.guid = {AAAA3FDA-EDC5-4220-B59D-D342722358A2} ?> |
|
|||
17 | <?define doc.hgignore.5.html.guid = {AA9118C4-F3A0-4429-A5F4-5A1906B2D67F} ?> |
|
|||
18 | <?define doc.hgrc.5.html = {E0CEA1EB-FA01-408c-844B-EE5965165BAE} ?> |
|
|||
19 | <?define doc.style.css = {172F8262-98E0-4711-BD39-4DAE0D77EF05} ?> |
|
|||
20 |
|
||||
21 | <!-- help.wxs --> |
|
|||
22 | <?define help.root.guid = {9FA957DB-6DFE-44f2-AD03-293B2791CF17} ?> |
|
|||
23 | <?define help.internals.guid = {2DD7669D-0DB8-4C39-9806-78E6475E7ACC} ?> |
|
|||
24 |
|
||||
25 | <!-- templates.wxs --> |
|
|||
26 | <?define templates.root.guid = {437FD55C-7756-4EA0-87E5-FDBE75DC8595} ?> |
|
|||
27 | <?define templates.atom.guid = {D30E14A5-8AF0-4268-8B00-00BEE9E09E39} ?> |
|
|||
28 | <?define templates.coal.guid = {B63CCAAB-4EAF-43b4-901E-4BD13F5B78FC} ?> |
|
|||
29 | <?define templates.gitweb.guid = {827334AF-1EFD-421B-962C-5660A068F612} ?> |
|
|||
30 | <?define templates.json.guid = {F535BE7A-EC34-46E0-B9BE-013F3DBAFB19} ?> |
|
|||
31 | <?define templates.monoblue.guid = {8060A1E4-BD4C-453E-92CB-9536DC44A9E3} ?> |
|
|||
32 | <?define templates.paper.guid = {61AB1DE9-645F-46ED-8AF8-0CF02267FFBB} ?> |
|
|||
33 | <?define templates.raw.guid = {834DF8D7-9784-43A6-851D-A96CE1B3575B} ?> |
|
|||
34 | <?define templates.rss.guid = {9338FA09-E128-4B1C-B723-1142DBD09E14} ?> |
|
|||
35 | <?define templates.spartan.guid = {80222625-FA8F-44b1-86CE-1781EF375D09} ?> |
|
|||
36 | <?define templates.static.guid = {6B3D7C24-98DA-4B67-9F18-35F77357B0B4} ?> |
|
|||
37 |
|
||||
38 | <!-- mercurial.wxs --> |
|
7 | <!-- mercurial.wxs --> | |
39 | <?define ProductUpgradeCode = {A1CC6134-E945-4399-BE36-EB0017FDF7CF} ?> |
|
8 | <?define ProductUpgradeCode = {A1CC6134-E945-4399-BE36-EB0017FDF7CF} ?> | |
40 |
|
||||
41 | <?define ComponentMainExecutableGUID = {D102B8FA-059B-4ACC-9FA3-8C78C3B58EEF} ?> |
|
9 | <?define ComponentMainExecutableGUID = {D102B8FA-059B-4ACC-9FA3-8C78C3B58EEF} ?> | |
42 |
|
||||
43 | <?define ReadMe.guid = {56A8E372-991D-4DCA-B91D-93D775974CF5} ?> |
|
|||
44 | <?define COPYING.guid = {B7801DBA-1C49-4BF4-91AD-33C65F5C7895} ?> |
|
|||
45 | <?define mercurial.rc.guid = {52BBF223-58F6-47F5-9353-8FDEA88D9B8D} ?> |
|
|||
46 | <?define mergetools.rc.guid = {5AF0430B-2B76-4BC6-91EE-E771B74A0214} ?> |
|
|||
47 | <?define ProgramMenuDir.guid = {D5A63320-1238-489B-B68B-CF053E9577CA} ?> |
|
10 | <?define ProgramMenuDir.guid = {D5A63320-1238-489B-B68B-CF053E9577CA} ?> | |
48 |
|
11 | |||
49 | </Include> |
|
12 | </Include> |
@@ -60,30 +60,10 b'' | |||||
60 | <Directory Id='$(var.PFolder)' Name='PFiles'> |
|
60 | <Directory Id='$(var.PFolder)' Name='PFiles'> | |
61 | <Directory Id='INSTALLDIR' Name='Mercurial'> |
|
61 | <Directory Id='INSTALLDIR' Name='Mercurial'> | |
62 | <Component Id='MainExecutable' Guid='$(var.ComponentMainExecutableGUID)' Win64='$(var.IsX64)'> |
|
62 | <Component Id='MainExecutable' Guid='$(var.ComponentMainExecutableGUID)' Win64='$(var.IsX64)'> | |
63 | <File Id='hgEXE' Name='hg.exe' Source='dist\hg.exe' KeyPath='yes' /> |
|
63 | <CreateFolder /> | |
64 | <Environment Id="Environment" Name="PATH" Part="last" System="yes" |
|
64 | <Environment Id="Environment" Name="PATH" Part="last" System="yes" | |
65 | Permanent="no" Value="[INSTALLDIR]" Action="set" /> |
|
65 | Permanent="no" Value="[INSTALLDIR]" Action="set" /> | |
66 | </Component> |
|
66 | </Component> | |
67 | <Component Id='ReadMe' Guid='$(var.ReadMe.guid)' Win64='$(var.IsX64)'> |
|
|||
68 | <File Id='ReadMe' Name='ReadMe.html' Source='contrib\win32\ReadMe.html' |
|
|||
69 | KeyPath='yes'/> |
|
|||
70 | </Component> |
|
|||
71 | <Component Id='COPYING' Guid='$(var.COPYING.guid)' Win64='$(var.IsX64)'> |
|
|||
72 | <File Id='COPYING' Name='COPYING.rtf' Source='contrib\packaging\wix\COPYING.rtf' |
|
|||
73 | KeyPath='yes'/> |
|
|||
74 | </Component> |
|
|||
75 |
|
||||
76 | <Directory Id='HGRCD' Name='hgrc.d'> |
|
|||
77 | <Component Id='mercurial.rc' Guid='$(var.mercurial.rc.guid)' Win64='$(var.IsX64)'> |
|
|||
78 | <File Id='mercurial.rc' Name='mercurial.rc' Source='contrib\win32\mercurial.ini' |
|
|||
79 | ReadOnly='yes' KeyPath='yes'/> |
|
|||
80 | </Component> |
|
|||
81 | <Component Id='mergetools.rc' Guid='$(var.mergetools.rc.guid)' Win64='$(var.IsX64)'> |
|
|||
82 | <File Id='mergetools.rc' Name='mergetools.rc' Source='mercurial\default.d\mergetools.rc' |
|
|||
83 | ReadOnly='yes' KeyPath='yes'/> |
|
|||
84 | </Component> |
|
|||
85 | </Directory> |
|
|||
86 |
|
||||
87 | </Directory> |
|
67 | </Directory> | |
88 | </Directory> |
|
68 | </Directory> | |
89 |
|
69 | |||
@@ -117,15 +97,12 b'' | |||||
117 | <Feature Id='MainProgram' Title='Program' Description='Mercurial command line app' |
|
97 | <Feature Id='MainProgram' Title='Program' Description='Mercurial command line app' | |
118 | Level='1' Absent='disallow' > |
|
98 | Level='1' Absent='disallow' > | |
119 | <ComponentRef Id='MainExecutable' /> |
|
99 | <ComponentRef Id='MainExecutable' /> | |
120 | <ComponentRef Id='distOutput' /> |
|
|||
121 | <ComponentRef Id='libOutput' /> |
|
|||
122 | <ComponentRef Id='ProgramMenuDir' /> |
|
100 | <ComponentRef Id='ProgramMenuDir' /> | |
123 |
<ComponentRef Id= |
|
101 | <ComponentGroupRef Id="hg.group.ROOT" /> | |
124 |
<ComponentRef Id= |
|
102 | <ComponentGroupRef Id="hg.group.hgrc.d" /> | |
125 |
<ComponentRef Id= |
|
103 | <ComponentGroupRef Id="hg.group.help" /> | |
126 |
<ComponentRef Id= |
|
104 | <ComponentGroupRef Id="hg.group.lib" /> | |
127 |
<ComponentGroupRef Id= |
|
105 | <ComponentGroupRef Id="hg.group.templates" /> | |
128 | <ComponentGroupRef Id='templatesFolder' /> |
|
|||
129 | <MergeRef Id='VCRuntime' /> |
|
106 | <MergeRef Id='VCRuntime' /> | |
130 | <MergeRef Id='VCRuntimePolicy' /> |
|
107 | <MergeRef Id='VCRuntimePolicy' /> | |
131 | </Feature> |
|
108 | </Feature> | |
@@ -135,13 +112,13 b'' | |||||
135 | <?endforeach?> |
|
112 | <?endforeach?> | |
136 | <?endif?> |
|
113 | <?endif?> | |
137 | <Feature Id='Locales' Title='Translations' Description='Translations' Level='1'> |
|
114 | <Feature Id='Locales' Title='Translations' Description='Translations' Level='1'> | |
138 |
<ComponentGroupRef Id= |
|
115 | <ComponentGroupRef Id="hg.group.locale" /> | |
139 | </Feature> |
|
116 | </Feature> | |
140 | <Feature Id='Documentation' Title='Documentation' Description='HTML man pages' Level='1'> |
|
117 | <Feature Id='Documentation' Title='Documentation' Description='HTML man pages' Level='1'> | |
141 |
<ComponentGroupRef Id= |
|
118 | <ComponentGroupRef Id="hg.group.doc" /> | |
142 | </Feature> |
|
119 | </Feature> | |
143 | <Feature Id='Misc' Title='Miscellaneous' Description='Contributed scripts' Level='1'> |
|
120 | <Feature Id='Misc' Title='Miscellaneous' Description='Contributed scripts' Level='1'> | |
144 |
<ComponentGroupRef Id= |
|
121 | <ComponentGroupRef Id="hg.group.contrib" /> | |
145 | </Feature> |
|
122 | </Feature> | |
146 | </Feature> |
|
123 | </Feature> | |
147 |
|
124 |
@@ -16,7 +16,7 b'' | |||||
16 |
|
16 | |||
17 | [ui] |
|
17 | [ui] | |
18 | ; editor used to enter commit logs, etc. Most text editors will work. |
|
18 | ; editor used to enter commit logs, etc. Most text editors will work. | |
19 | editor = notepad |
|
19 | ; editor = notepad | |
20 | ; show changed files and be a bit more verbose if True |
|
20 | ; show changed files and be a bit more verbose if True | |
21 | ; verbose = True |
|
21 | ; verbose = True | |
22 | ; colorize commands output |
|
22 | ; colorize commands output |
@@ -162,75 +162,6 b' Verify the json works too:' | |||||
162 | "fsmonitor-watchman": "false", |
|
162 | "fsmonitor-watchman": "false", | |
163 | "fsmonitor-watchman-error": "warning: Watchman unavailable: watchman exited with code 1", |
|
163 | "fsmonitor-watchman-error": "warning: Watchman unavailable: watchman exited with code 1", | |
164 |
|
164 | |||
165 |
|
||||
166 | #if test-repo |
|
|||
167 | $ . "$TESTDIR/helpers-testrepo.sh" |
|
|||
168 |
|
||||
169 | $ cat >> wixxml.py << EOF |
|
|||
170 | > import os |
|
|||
171 | > import subprocess |
|
|||
172 | > import sys |
|
|||
173 | > import xml.etree.ElementTree as ET |
|
|||
174 | > from mercurial import pycompat |
|
|||
175 | > |
|
|||
176 | > # MSYS mangles the path if it expands $TESTDIR |
|
|||
177 | > testdir = os.environ['TESTDIR'] |
|
|||
178 | > ns = {'wix' : 'http://schemas.microsoft.com/wix/2006/wi'} |
|
|||
179 | > |
|
|||
180 | > def directory(node, relpath): |
|
|||
181 | > '''generator of files in the xml node, rooted at relpath''' |
|
|||
182 | > dirs = node.findall('./{%(wix)s}Directory' % ns) |
|
|||
183 | > |
|
|||
184 | > for d in dirs: |
|
|||
185 | > for subfile in directory(d, relpath + d.attrib['Name'] + '/'): |
|
|||
186 | > yield subfile |
|
|||
187 | > |
|
|||
188 | > files = node.findall('./{%(wix)s}Component/{%(wix)s}File' % ns) |
|
|||
189 | > |
|
|||
190 | > for f in files: |
|
|||
191 | > yield pycompat.sysbytes(relpath + f.attrib['Name']) |
|
|||
192 | > |
|
|||
193 | > def hgdirectory(relpath): |
|
|||
194 | > '''generator of tracked files, rooted at relpath''' |
|
|||
195 | > hgdir = "%s/../mercurial" % (testdir) |
|
|||
196 | > args = ['hg', '--cwd', hgdir, 'files', relpath] |
|
|||
197 | > proc = subprocess.Popen(args, stdout=subprocess.PIPE, |
|
|||
198 | > stderr=subprocess.PIPE) |
|
|||
199 | > output = proc.communicate()[0] |
|
|||
200 | > |
|
|||
201 | > for line in output.splitlines(): |
|
|||
202 | > if os.name == 'nt': |
|
|||
203 | > yield line.replace(pycompat.sysbytes(os.sep), b'/') |
|
|||
204 | > else: |
|
|||
205 | > yield line |
|
|||
206 | > |
|
|||
207 | > tracked = [f for f in hgdirectory(sys.argv[1])] |
|
|||
208 | > |
|
|||
209 | > xml = ET.parse("%s/../contrib/packaging/wix/%s.wxs" % (testdir, sys.argv[1])) |
|
|||
210 | > root = xml.getroot() |
|
|||
211 | > dir = root.find('.//{%(wix)s}DirectoryRef' % ns) |
|
|||
212 | > |
|
|||
213 | > installed = [f for f in directory(dir, '')] |
|
|||
214 | > |
|
|||
215 | > print('Not installed:') |
|
|||
216 | > for f in sorted(set(tracked) - set(installed)): |
|
|||
217 | > print(' %s' % pycompat.sysstr(f)) |
|
|||
218 | > |
|
|||
219 | > print('Not tracked:') |
|
|||
220 | > for f in sorted(set(installed) - set(tracked)): |
|
|||
221 | > print(' %s' % pycompat.sysstr(f)) |
|
|||
222 | > EOF |
|
|||
223 |
|
||||
224 | $ ( testrepohgenv; "$PYTHON" wixxml.py help ) |
|
|||
225 | Not installed: |
|
|||
226 | Not tracked: |
|
|||
227 |
|
||||
228 | $ ( testrepohgenv; "$PYTHON" wixxml.py templates ) |
|
|||
229 | Not installed: |
|
|||
230 | Not tracked: |
|
|||
231 |
|
||||
232 | #endif |
|
|||
233 |
|
||||
234 | Verify that Mercurial is installable with pip. Note that this MUST be |
|
165 | Verify that Mercurial is installable with pip. Note that this MUST be | |
235 | the last test in this file, because we do some nasty things to the |
|
166 | the last test in this file, because we do some nasty things to the | |
236 | shell environment in order to make the virtualenv work reliably. |
|
167 | shell environment in order to make the virtualenv work reliably. |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
1 | NO CONTENT: file was removed |
|
NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now