Chromium Code Reviews| 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 |