| 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 24 matching lines...) Expand all Loading... |
| 35 COMPRESSED_FILE_EXT = ".packed.7z" # extension of patch archive file | 35 COMPRESSED_FILE_EXT = ".packed.7z" # extension of patch archive file |
| 36 COURGETTE_EXEC = "courgette.exe" | 36 COURGETTE_EXEC = "courgette.exe" |
| 37 MINI_INSTALLER_INPUT_FILE = "packed_files.txt" | 37 MINI_INSTALLER_INPUT_FILE = "packed_files.txt" |
| 38 PATCH_FILE_EXT = '.diff' | 38 PATCH_FILE_EXT = '.diff' |
| 39 SETUP_EXEC = "setup.exe" | 39 SETUP_EXEC = "setup.exe" |
| 40 SETUP_PATCH_FILE_PREFIX = "setup_patch" | 40 SETUP_PATCH_FILE_PREFIX = "setup_patch" |
| 41 TEMP_ARCHIVE_DIR = "temp_installer_archive" | 41 TEMP_ARCHIVE_DIR = "temp_installer_archive" |
| 42 VERSION_FILE = "VERSION" | 42 VERSION_FILE = "VERSION" |
| 43 | 43 |
| 44 | 44 |
| 45 g_archive_inputs = [] |
| 46 |
| 47 |
| 45 def BuildVersion(build_dir): | 48 def BuildVersion(build_dir): |
| 46 """Returns the full build version string constructed from information in | 49 """Returns the full build version string constructed from information in |
| 47 VERSION_FILE. Any segment not found in that file will default to '0'. | 50 VERSION_FILE. Any segment not found in that file will default to '0'. |
| 48 """ | 51 """ |
| 49 major = 0 | 52 major = 0 |
| 50 minor = 0 | 53 minor = 0 |
| 51 build = 0 | 54 build = 0 |
| 52 patch = 0 | 55 patch = 0 |
| 53 for line in open(os.path.join(build_dir, '../../chrome', VERSION_FILE), 'r'): | 56 for line in open(os.path.join(build_dir, '../../chrome', VERSION_FILE), 'r'): |
| 54 line = line.rstrip() | 57 line = line.rstrip() |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 if option.endswith('dir'): | 117 if option.endswith('dir'): |
| 115 continue | 118 continue |
| 116 | 119 |
| 117 dst_dir = os.path.join(staging_dir, config.get(section, option)) | 120 dst_dir = os.path.join(staging_dir, config.get(section, option)) |
| 118 src_paths = glob.glob(os.path.join(src_dir, option)) | 121 src_paths = glob.glob(os.path.join(src_dir, option)) |
| 119 if src_paths and not os.path.exists(dst_dir): | 122 if src_paths and not os.path.exists(dst_dir): |
| 120 os.makedirs(dst_dir) | 123 os.makedirs(dst_dir) |
| 121 for src_path in src_paths: | 124 for src_path in src_paths: |
| 122 dst_path = os.path.join(dst_dir, os.path.basename(src_path)) | 125 dst_path = os.path.join(dst_dir, os.path.basename(src_path)) |
| 123 if not os.path.exists(dst_path): | 126 if not os.path.exists(dst_path): |
| 127 g_archive_inputs.append(src_path) |
| 124 shutil.copy(src_path, dst_dir) | 128 shutil.copy(src_path, dst_dir) |
| 125 | 129 |
| 126 def GenerateDiffPatch(options, orig_file, new_file, patch_file): | 130 def GenerateDiffPatch(options, orig_file, new_file, patch_file): |
| 127 if (options.diff_algorithm == "COURGETTE"): | 131 if (options.diff_algorithm == "COURGETTE"): |
| 128 exe_file = os.path.join(options.last_chrome_installer, COURGETTE_EXEC) | 132 exe_file = os.path.join(options.last_chrome_installer, COURGETTE_EXEC) |
| 129 cmd = '%s -gen "%s" "%s" "%s"' % (exe_file, orig_file, new_file, patch_file) | 133 cmd = '%s -gen "%s" "%s" "%s"' % (exe_file, orig_file, new_file, patch_file) |
| 130 else: | 134 else: |
| 131 exe_file = os.path.join(options.build_dir, BSDIFF_EXEC) | 135 exe_file = os.path.join(options.build_dir, BSDIFF_EXEC) |
| 132 cmd = [exe_file, orig_file, new_file, patch_file,] | 136 cmd = [exe_file, orig_file, new_file, patch_file,] |
| 133 RunSystemCommand(cmd) | 137 RunSystemCommand(cmd) |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 187 raise Exception("Error while running cmd: %s, exit_code: %s" % | 191 raise Exception("Error while running cmd: %s, exit_code: %s" % |
| 188 (cmd, exit_code)) | 192 (cmd, exit_code)) |
| 189 | 193 |
| 190 def CreateArchiveFile(options, staging_dir, current_version, prev_version): | 194 def CreateArchiveFile(options, staging_dir, current_version, prev_version): |
| 191 """Creates a new installer archive file after deleting any existing old file. | 195 """Creates a new installer archive file after deleting any existing old file. |
| 192 """ | 196 """ |
| 193 # First create an uncompressed archive file for the current build (chrome.7z) | 197 # First create an uncompressed archive file for the current build (chrome.7z) |
| 194 lzma_exec = GetLZMAExec(options.build_dir) | 198 lzma_exec = GetLZMAExec(options.build_dir) |
| 195 archive_file = os.path.join(options.output_dir, | 199 archive_file = os.path.join(options.output_dir, |
| 196 options.output_name + ARCHIVE_SUFFIX) | 200 options.output_name + ARCHIVE_SUFFIX) |
| 201 if options.depfile: |
| 202 # If a depfile was requested, do the glob of the staging dir and generate |
| 203 # a list of dependencies in .d format. We list the files that were copied |
| 204 # into the staging dir, not the files that are actually in the staging dir |
| 205 # because the ones in the staging dir will never be edited, and we want |
| 206 # to have the build be triggered when the thing-that-was-copied-there |
| 207 # changes. |
| 208 |
| 209 # Gather the list of files in the staging dir that will be zipped up. We |
| 210 # only gather this list to make sure that g_archive_inputs is complete (i.e. |
| 211 # that there's not file copies that got missed). |
| 212 staging_contents = [] |
| 213 for root, dirs, files in os.walk(os.path.join(staging_dir, CHROME_DIR)): |
| 214 for filename in files: |
| 215 staging_contents.append( |
| 216 os.path.relpath(os.path.join(root, filename), options.build_dir) |
| 217 .replace('\\', '/')) |
| 218 |
| 219 # Make sure there's an archive_input for each staging dir file. |
| 220 for staging_file in staging_contents: |
| 221 for archive_input in g_archive_inputs: |
| 222 archive_rel = (os.path.relpath(archive_input, options.build_dir) |
| 223 .replace('\\', '/')) |
| 224 if staging_file.lower().endswith('/' + archive_rel.lower()): |
| 225 break |
| 226 else: |
| 227 raise Exception('Did not find an archive input file for "%s"' % |
| 228 staging_file) |
| 229 |
| 230 # Finally, write the depfile referencing the inputs. |
| 231 with open(options.depfile, 'wb') as f: |
| 232 f.write(os.path.relpath(archive_file, options.build_dir) |
| 233 .replace('\\', '/') + ': \\\n') |
| 234 f.write(' ' + |
| 235 ' \\\n '.join(x.replace('\\', '/') for x in g_archive_inputs)) |
| 236 |
| 197 cmd = [lzma_exec, | 237 cmd = [lzma_exec, |
| 198 'a', | 238 'a', |
| 199 '-t7z', | 239 '-t7z', |
| 200 archive_file, | 240 archive_file, |
| 201 os.path.join(staging_dir, CHROME_DIR), | 241 os.path.join(staging_dir, CHROME_DIR), |
| 202 '-mx0',] | 242 '-mx0',] |
| 203 # There doesnt seem to be any way in 7za.exe to override existing file so | 243 # There doesnt seem to be any way in 7za.exe to override existing file so |
| 204 # we always delete before creating a new one. | 244 # we always delete before creating a new one. |
| 205 if not os.path.exists(archive_file): | 245 if not os.path.exists(archive_file): |
| 206 RunSystemCommand(cmd) | 246 RunSystemCommand(cmd) |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 343 f.write(''.join(manifest_lines)) | 383 f.write(''.join(manifest_lines)) |
| 344 | 384 |
| 345 | 385 |
| 346 def CopyIfChanged(src, target_dir): | 386 def CopyIfChanged(src, target_dir): |
| 347 """Copy specified |src| file to |target_dir|, but only write to target if | 387 """Copy specified |src| file to |target_dir|, but only write to target if |
| 348 the file has changed. This avoids a problem during packaging where parts of | 388 the file has changed. This avoids a problem during packaging where parts of |
| 349 the build have not completed and have the runtime DLL locked when we try to | 389 the build have not completed and have the runtime DLL locked when we try to |
| 350 copy over it. See http://crbug.com/305877 for details.""" | 390 copy over it. See http://crbug.com/305877 for details.""" |
| 351 assert os.path.isdir(target_dir) | 391 assert os.path.isdir(target_dir) |
| 352 dest = os.path.join(target_dir, os.path.basename(src)) | 392 dest = os.path.join(target_dir, os.path.basename(src)) |
| 393 g_archive_inputs.append(src) |
| 353 if os.path.exists(dest): | 394 if os.path.exists(dest): |
| 354 # We assume the files are OK to buffer fully into memory since we know | 395 # We assume the files are OK to buffer fully into memory since we know |
| 355 # they're only 1-2M. | 396 # they're only 1-2M. |
| 356 with open(src, 'rb') as fsrc: | 397 with open(src, 'rb') as fsrc: |
| 357 src_data = fsrc.read() | 398 src_data = fsrc.read() |
| 358 with open(dest, 'rb') as fdest: | 399 with open(dest, 'rb') as fdest: |
| 359 dest_data = fdest.read() | 400 dest_data = fdest.read() |
| 360 if src_data != dest_data: | 401 if src_data != dest_data: |
| 361 # This may still raise if we get here, but this really should almost | 402 # This may still raise if we get here, but this really should almost |
| 362 # never happen (it would mean that the contents of e.g. msvcr100d.dll | 403 # never happen (it would mean that the contents of e.g. msvcr100d.dll |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 setup_component_dll_globs = [ 'base.dll', | 485 setup_component_dll_globs = [ 'base.dll', |
| 445 'boringssl.dll', | 486 'boringssl.dll', |
| 446 'crcrypto.dll', | 487 'crcrypto.dll', |
| 447 'icui18n.dll', | 488 'icui18n.dll', |
| 448 'icuuc.dll', | 489 'icuuc.dll', |
| 449 'msvc*.dll' ] | 490 'msvc*.dll' ] |
| 450 for setup_component_dll_glob in setup_component_dll_globs: | 491 for setup_component_dll_glob in setup_component_dll_globs: |
| 451 setup_component_dlls = glob.glob(os.path.join(build_dir, | 492 setup_component_dlls = glob.glob(os.path.join(build_dir, |
| 452 setup_component_dll_glob)) | 493 setup_component_dll_glob)) |
| 453 for setup_component_dll in setup_component_dlls: | 494 for setup_component_dll in setup_component_dlls: |
| 495 g_archive_inputs.append(setup_component_dlls) |
| 454 shutil.copy(setup_component_dll, installer_dir) | 496 shutil.copy(setup_component_dll, installer_dir) |
| 455 | 497 |
| 456 # Stage all the component DLLs found in |build_dir| to the |version_dir| (for | 498 # Stage all the component DLLs found in |build_dir| to the |version_dir| (for |
| 457 # the version assembly to be able to refer to them below and make sure | 499 # the version assembly to be able to refer to them below and make sure |
| 458 # chrome.exe can find them at runtime). The component DLLs are considered to | 500 # chrome.exe can find them at runtime). The component DLLs are considered to |
| 459 # be all the DLLs which have not already been added to the |version_dir| by | 501 # be all the DLLs which have not already been added to the |version_dir| by |
| 460 # virtue of chrome.release. | 502 # virtue of chrome.release. |
| 461 build_dlls = glob.glob(os.path.join(build_dir, '*.dll')) | 503 build_dlls = glob.glob(os.path.join(build_dir, '*.dll')) |
| 462 staged_dll_basenames = [os.path.basename(staged_dll) for staged_dll in \ | 504 staged_dll_basenames = [os.path.basename(staged_dll) for staged_dll in \ |
| 463 glob.glob(os.path.join(version_dir, '*.dll'))] | 505 glob.glob(os.path.join(version_dir, '*.dll'))] |
| 464 component_dll_filenames = [] | 506 component_dll_filenames = [] |
| 465 for component_dll in [dll for dll in build_dlls if \ | 507 for component_dll in [dll for dll in build_dlls if \ |
| 466 os.path.basename(dll) not in staged_dll_basenames]: | 508 os.path.basename(dll) not in staged_dll_basenames]: |
| 467 component_dll_name = os.path.basename(component_dll) | 509 component_dll_name = os.path.basename(component_dll) |
| 468 # remoting_*.dll's don't belong in the archive (it doesn't depend on them | 510 # remoting_*.dll's don't belong in the archive (it doesn't depend on them |
| 469 # in gyp). Trying to copy them causes a build race when creating the | 511 # in gyp). Trying to copy them causes a build race when creating the |
| 470 # installer archive in component mode. See: crbug.com/180996 | 512 # installer archive in component mode. See: crbug.com/180996 |
| 471 if component_dll_name.startswith('remoting_'): | 513 if component_dll_name.startswith('remoting_'): |
| 472 continue | 514 continue |
| 473 component_dll_filenames.append(component_dll_name) | 515 component_dll_filenames.append(component_dll_name) |
| 516 g_archive_inputs.append(component_dll) |
| 474 shutil.copy(component_dll, version_dir) | 517 shutil.copy(component_dll, version_dir) |
| 475 | 518 |
| 476 # Augment {version}.manifest to include all component DLLs as part of the | 519 # Augment {version}.manifest to include all component DLLs as part of the |
| 477 # assembly it constitutes, which will allow dependents of this assembly to | 520 # assembly it constitutes, which will allow dependents of this assembly to |
| 478 # find these DLLs. | 521 # find these DLLs. |
| 479 version_assembly_dll_additions = [] | 522 version_assembly_dll_additions = [] |
| 480 for dll_filename in component_dll_filenames: | 523 for dll_filename in component_dll_filenames: |
| 481 version_assembly_dll_additions.append(" <file name='%s'/>" % dll_filename) | 524 version_assembly_dll_additions.append(" <file name='%s'/>" % dll_filename) |
| 482 CopyAndAugmentManifest(build_dir, version_dir, | 525 CopyAndAugmentManifest(build_dir, version_dir, |
| 483 '%s.manifest' % current_version, | 526 '%s.manifest' % current_version, |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 567 help='Diff algorithm to use when generating differential patches ' | 610 help='Diff algorithm to use when generating differential patches ' |
| 568 '{BSDIFF|COURGETTE}.') | 611 '{BSDIFF|COURGETTE}.') |
| 569 parser.add_option('-n', '--output_name', default='chrome', | 612 parser.add_option('-n', '--output_name', default='chrome', |
| 570 help='Name used to prefix names of generated archives.') | 613 help='Name used to prefix names of generated archives.') |
| 571 parser.add_option('--enable_hidpi', default='0', | 614 parser.add_option('--enable_hidpi', default='0', |
| 572 help='Whether to include HiDPI resource files.') | 615 help='Whether to include HiDPI resource files.') |
| 573 parser.add_option('--component_build', default='0', | 616 parser.add_option('--component_build', default='0', |
| 574 help='Whether this archive is packaging a component build. This will ' | 617 help='Whether this archive is packaging a component build. This will ' |
| 575 'also turn off compression of chrome.7z into chrome.packed.7z and ' | 618 'also turn off compression of chrome.7z into chrome.packed.7z and ' |
| 576 'helpfully delete any old chrome.packed.7z in |output_dir|.') | 619 'helpfully delete any old chrome.packed.7z in |output_dir|.') |
| 620 parser.add_option('--depfile', |
| 621 help='Generate a depfile with the given name listing the implicit inputs ' |
| 622 'to the archive process that can be used with a build system.') |
| 577 parser.add_option('--target_arch', default='x86', | 623 parser.add_option('--target_arch', default='x86', |
| 578 help='Specify the target architecture for installer - this is used ' | 624 help='Specify the target architecture for installer - this is used ' |
| 579 'to determine which CRT runtime files to pull and package ' | 625 'to determine which CRT runtime files to pull and package ' |
| 580 'with the installer archive {x86|x64}.') | 626 'with the installer archive {x86|x64}.') |
| 581 | 627 |
| 582 options, _ = parser.parse_args() | 628 options, _ = parser.parse_args() |
| 583 if not options.build_dir: | 629 if not options.build_dir: |
| 584 parser.error('You must provide a build dir.') | 630 parser.error('You must provide a build dir.') |
| 585 | 631 |
| 586 options.build_dir = os.path.normpath(options.build_dir) | 632 options.build_dir = os.path.normpath(options.build_dir) |
| (...skipping 10 matching lines...) Expand all Loading... |
| 597 if not options.resource_file_path: | 643 if not options.resource_file_path: |
| 598 options.resource_file_path = os.path.join(options.build_dir, | 644 options.resource_file_path = os.path.join(options.build_dir, |
| 599 MINI_INSTALLER_INPUT_FILE) | 645 MINI_INSTALLER_INPUT_FILE) |
| 600 | 646 |
| 601 return options | 647 return options |
| 602 | 648 |
| 603 | 649 |
| 604 if '__main__' == __name__: | 650 if '__main__' == __name__: |
| 605 print sys.argv | 651 print sys.argv |
| 606 sys.exit(main(_ParseOptions())) | 652 sys.exit(main(_ParseOptions())) |
| OLD | NEW |