OLD | NEW |
---|---|
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Script to create Chrome Installer archive. | 6 """Script to create Chrome Installer archive. |
7 | 7 |
8 This script is used to create an archive of all the files required for a | 8 This script is used to create an archive of all the files required for a |
9 Chrome install in appropriate directory structure. It reads chrome.release | 9 Chrome install in appropriate directory structure. It reads chrome.release |
10 file as input, creates chrome.7z archive, compresses setup.exe and | 10 file as input, creates chrome.7z archive, compresses setup.exe and |
(...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
318 | 318 |
319 with open(resource_file_path, 'w') as f: | 319 with open(resource_file_path, 'w') as f: |
320 f.write(resource_file) | 320 f.write(resource_file) |
321 | 321 |
322 | 322 |
323 # Reads |manifest_name| from |build_dir| and writes |manifest_name| to | 323 # Reads |manifest_name| from |build_dir| and writes |manifest_name| to |
324 # |output_dir| with the same content plus |inserted_string| added just before | 324 # |output_dir| with the same content plus |inserted_string| added just before |
325 # |insert_before|. | 325 # |insert_before|. |
326 def CopyAndAugmentManifest(build_dir, output_dir, manifest_name, | 326 def CopyAndAugmentManifest(build_dir, output_dir, manifest_name, |
327 inserted_string, insert_before): | 327 inserted_string, insert_before): |
328 manifest_file = open(os.path.join(build_dir, manifest_name), 'r') | 328 with open(os.path.join(build_dir, manifest_name), 'r') as manifest_file: |
329 manifest_lines = manifest_file.readlines() | 329 manifest_lines = manifest_file.readlines() |
330 manifest_file.close() | |
331 | 330 |
332 insert_line = -1 | 331 insert_line = -1 |
333 insert_pos = -1 | 332 insert_pos = -1 |
334 for i in xrange(len(manifest_lines)): | 333 for i in xrange(len(manifest_lines)): |
335 insert_pos = manifest_lines[i].find(insert_before) | 334 insert_pos = manifest_lines[i].find(insert_before) |
336 if insert_pos != -1: | 335 if insert_pos != -1: |
337 insert_line = i | 336 insert_line = i |
338 break | 337 break |
339 if insert_line == -1: | 338 if insert_line == -1: |
340 raise ValueError('Could not find {0} in the manifest:\n{1}'.format( | 339 raise ValueError('Could not find {0} in the manifest:\n{1}'.format( |
341 insert_before, ''.join(manifest_lines))) | 340 insert_before, ''.join(manifest_lines))) |
342 old = manifest_lines[insert_line] | 341 old = manifest_lines[insert_line] |
343 manifest_lines[insert_line] = (old[:insert_pos] + inserted_string + | 342 manifest_lines[insert_line] = (old[:insert_pos] + '\n' + inserted_string + |
344 old[insert_pos:]) | 343 '\n' + old[insert_pos:]) |
345 | 344 |
346 modified_manifest_file = open( | 345 with open(os.path.join(output_dir, manifest_name), |
347 os.path.join(output_dir, manifest_name), 'w') | 346 'w') as modified_manifest_file : |
grt (UTC plus 2)
2013/11/15 17:26:24
minor nit: i think it's okay to use "f" or "file"
gab
2013/11/15 21:18:52
Done.
| |
348 modified_manifest_file.write(''.join(manifest_lines)) | 347 modified_manifest_file.write(''.join(manifest_lines)) |
349 modified_manifest_file.close() | |
350 | 348 |
351 | 349 |
352 def CopyIfChanged(src, target_dir): | 350 def CopyIfChanged(src, target_dir): |
353 """Copy specified |src| file to |target_dir|, but only write to target if | 351 """Copy specified |src| file to |target_dir|, but only write to target if |
354 the file has changed. This avoids a problem during packaging where parts of | 352 the file has changed. This avoids a problem during packaging where parts of |
355 the build have not completed and have the runtime DLL locked when we try to | 353 the build have not completed and have the runtime DLL locked when we try to |
356 copy over it. See http://crbug.com/305877 for details.""" | 354 copy over it. See http://crbug.com/305877 for details.""" |
357 assert os.path.isdir(target_dir) | 355 assert os.path.isdir(target_dir) |
358 dest = os.path.join(target_dir, os.path.basename(src)) | 356 dest = os.path.join(target_dir, os.path.basename(src)) |
359 if os.path.exists(dest): | 357 if os.path.exists(dest): |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
438 # |installer_dir| is technically only created post-install, but we need it | 436 # |installer_dir| is technically only created post-install, but we need it |
439 # now to add setup.exe's config and manifest to the archive. | 437 # now to add setup.exe's config and manifest to the archive. |
440 if not os.path.exists(installer_dir): | 438 if not os.path.exists(installer_dir): |
441 os.mkdir(installer_dir) | 439 os.mkdir(installer_dir) |
442 | 440 |
443 # Copy the VS CRT DLLs to |build_dir|. This must be done before the general | 441 # Copy the VS CRT DLLs to |build_dir|. This must be done before the general |
444 # copy step below to ensure the CRT DLLs are added to the archive and marked | 442 # copy step below to ensure the CRT DLLs are added to the archive and marked |
445 # as a dependency in the exe manifests generated below. | 443 # as a dependency in the exe manifests generated below. |
446 CopyVisualStudioRuntimeDLLs(build_dir, target_arch) | 444 CopyVisualStudioRuntimeDLLs(build_dir, target_arch) |
447 | 445 |
448 # Copy all the DLLs in |build_dir| to the version directory. Simultaneously | 446 # Stage all the component DLLs found in |build_dir|. These are all the DLLs |
449 # build a list of their names to mark them as dependencies of chrome.exe and | 447 # which have not already been added to the staged |version_dir| by virtue of |
450 # setup.exe later. | 448 # chrome.release. |
451 dlls = glob.glob(os.path.join(build_dir, '*.dll')) | 449 build_dlls = glob.glob(os.path.join(build_dir, '*.dll')) |
452 dll_names = [] | 450 staged_dll_basenames = [os.path.basename(staged_dll) for staged_dll in \ |
453 for dll in dlls: | 451 glob.glob(os.path.join(version_dir, '*.dll'))] |
Mathieu
2013/11/18 19:10:06
nit: you can de-indent by 4
gab
2013/11/18 20:37:16
Done.
| |
452 component_dll_filenames = [] | |
453 for component_dll in [dll for dll in build_dlls if \ | |
454 os.path.basename(dll) not in staged_dll_basenames]: | |
Mathieu
2013/11/18 19:10:06
nit: same here
gab
2013/11/18 20:37:16
Done.
| |
454 # remoting_*.dll's don't belong in the archive (it doesn't depend on them | 455 # remoting_*.dll's don't belong in the archive (it doesn't depend on them |
455 # in gyp). Trying to copy them causes a build race when creating the | 456 # in gyp). Trying to copy them causes a build race when creating the |
456 # installer archive in component mode. See: crbug.com/180996 | 457 # installer archive in component mode. See: crbug.com/180996 |
457 if os.path.basename(dll).startswith('remoting_'): | 458 if os.path.basename(component_dll).startswith('remoting_'): |
458 continue | 459 continue |
459 shutil.copy(dll, version_dir) | 460 # Copy them to the version_dir (for the version assembly to be able to refer |
460 dll_names.append(os.path.splitext(os.path.basename(dll))[0]) | 461 # to them below and thus for chrome.exe to be able to load them at runtime). |
462 shutil.copy(component_dll, version_dir) | |
463 # Also copy them directly to the Installer directory for the installed | |
464 # setup.exe to be able to run (as it doesn't statically link in component | |
465 # DLLs). | |
466 # TODO(gab): This makes the archive ~278MB instead of ~185MB; consider | |
467 # copying the DLLs over from the installer. | |
468 shutil.copy(component_dll, installer_dir) | |
469 component_dll_filenames.append(os.path.basename(component_dll)) | |
461 | 470 |
462 exe_config = ( | 471 # Copy chrome.exe.manifest as-is. It is required, among other things, to |
463 "<configuration>\n" | 472 # declare a dependency on the version dir assembly. |
464 " <windows>\n" | 473 shutil.copy(os.path.join(build_dir, 'chrome.exe.manifest'), chrome_dir) |
465 " <assemblyBinding xmlns='urn:schemas-microsoft-com:asm.v1'>\n" | |
466 " <probing privatePath='{rel_path}'/>\n" | |
467 " </assemblyBinding>\n" | |
468 " </windows>\n" | |
469 "</configuration>") | |
470 | 474 |
471 # Write chrome.exe.config to point to the version directory. | 475 # Also copy setup.exe.manifest as-is. It is required, among other things, to |
472 chrome_exe_config_file = open( | 476 # let setup.exe UAC when it wants to, by specifying that it handles elevation |
473 os.path.join(chrome_dir, 'chrome.exe.config'), 'w') | 477 # "asInvoker", rather than have Windows auto-elevate it when launched. |
474 chrome_exe_config_file.write(exe_config.format(rel_path=current_version)) | 478 shutil.copy(os.path.join(build_dir, 'setup.exe.manifest'), installer_dir) |
475 chrome_exe_config_file.close() | |
476 | 479 |
477 # Write setup.exe.config to point to the version directory (which is one | 480 # Augment {version}.manifest to include all component DLLs as part of the |
478 # level up from setup.exe post-install). | 481 # assembly it constitutes which will allow dependents of this assembly to |
Sigurður Ásgeirsson
2013/11/15 18:31:12
nit: constitutes, which
gab
2013/11/15 21:18:52
Done.
| |
479 setup_exe_config_file = open( | 482 # find these DLLs. |
480 os.path.join(installer_dir, 'setup.exe.config'), 'w') | 483 version_assembly_dll_additions = [] |
481 setup_exe_config_file.write(exe_config.format(rel_path='..')) | 484 for dll_filename in component_dll_filenames: |
482 setup_exe_config_file.close() | 485 version_assembly_dll_additions.append( |
483 | 486 " <file name='{dll_filename}'/>".format(dll_filename=dll_filename)) |
Sigurður Ásgeirsson
2013/11/15 18:31:12
nit: this is a fairly long-winded way to say
" <
gab
2013/11/15 21:18:52
Done.
| |
484 # Add a dependency for each DLL in |dlls| to the existing manifests for | 487 CopyAndAugmentManifest(build_dir, version_dir, |
485 # chrome.exe and setup.exe. Some of these DLLs are not actually used by | 488 '{version}.manifest'.format(version=current_version), |
486 # either process, but listing them all as dependencies doesn't hurt as it | 489 '\n'.join(version_assembly_dll_additions), |
487 # only makes them visible to the exes, just like they already are in the | 490 '</assembly>') |
488 # build output directory. | |
489 exe_manifest_dependencies_list = [] | |
490 for name in dll_names: | |
491 exe_manifest_dependencies_list.append( | |
492 "<dependency>" | |
493 "<dependentAssembly>" | |
494 "<assemblyIdentity type='win32' name='chrome.{dll_name}' " | |
495 "version='0.0.0.0' language='*'/>" | |
496 "</dependentAssembly>" | |
497 "</dependency>".format(dll_name=name)) | |
498 | |
499 exe_manifest_dependencies = ''.join(exe_manifest_dependencies_list) | |
500 | |
501 # Write a modified chrome.exe.manifest beside chrome.exe. | |
502 CopyAndAugmentManifest(build_dir, chrome_dir, 'chrome.exe.manifest', | |
503 exe_manifest_dependencies, '</assembly>') | |
504 | |
505 # Write a modified setup.exe.manifest beside setup.exe in | |
506 # |version_dir|/Installer. | |
507 CopyAndAugmentManifest(build_dir, installer_dir, 'setup.exe.manifest', | |
508 exe_manifest_dependencies, '</assembly>') | |
509 | |
510 # Generate assembly manifests for each DLL in |dlls|. These do not interfere | |
511 # with the private manifests potentially embedded in each DLL. They simply | |
512 # allow chrome.exe and setup.exe to see those DLLs although they are in a | |
513 # separate directory post-install. | |
514 for name in dll_names: | |
515 dll_manifest = ( | |
516 "<assembly\n" | |
517 " xmlns='urn:schemas-microsoft-com:asm.v1' manifestVersion='1.0'>\n" | |
518 " <assemblyIdentity name='chrome.{dll_name}' version='0.0.0.0'\n" | |
519 " type='win32'/>\n" | |
520 " <file name='{dll_name}.dll'/>\n" | |
521 "</assembly>".format(dll_name=name)) | |
522 | |
523 dll_manifest_file = open(os.path.join( | |
524 version_dir, "chrome.{dll_name}.manifest".format(dll_name=name)), 'w') | |
525 dll_manifest_file.write(dll_manifest) | |
526 dll_manifest_file.close() | |
527 | 491 |
528 | 492 |
529 def main(options): | 493 def main(options): |
530 """Main method that reads input file, creates archive file and write | 494 """Main method that reads input file, creates archive file and write |
531 resource input file. | 495 resource input file. |
532 """ | 496 """ |
533 current_version = BuildVersion(options.build_dir) | 497 current_version = BuildVersion(options.build_dir) |
534 | 498 |
535 config = Readconfig(options.input_file, current_version) | 499 config = Readconfig(options.input_file, current_version) |
536 | 500 |
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
639 if not options.resource_file_path: | 603 if not options.resource_file_path: |
640 options.resource_file_path = os.path.join(options.build_dir, | 604 options.resource_file_path = os.path.join(options.build_dir, |
641 MINI_INSTALLER_INPUT_FILE) | 605 MINI_INSTALLER_INPUT_FILE) |
642 | 606 |
643 return options | 607 return options |
644 | 608 |
645 | 609 |
646 if '__main__' == __name__: | 610 if '__main__' == __name__: |
647 print sys.argv | 611 print sys.argv |
648 sys.exit(main(_ParseOptions())) | 612 sys.exit(main(_ParseOptions())) |
OLD | NEW |