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
4 # found in the LICENSE file.
6 """Script to create Chrome Installer archive.
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
10 file as input, creates chrome.7z archive, compresses setup.exe and
11 generates packed_files.txt for mini_installer project.
24 ARCHIVE_DIR
= "installer_archive"
26 # suffix to uncompresed full archive file, appended to options.output_name
27 ARCHIVE_SUFFIX
= ".7z"
28 BSDIFF_EXEC
= "bsdiff.exe"
29 CHROME_DIR
= "Chrome-bin"
30 CHROME_PATCH_FILE_SUFFIX
= "_patch" # prefixed by options.output_name
32 # compressed full archive suffix, will be prefixed by options.output_name
33 COMPRESSED_ARCHIVE_SUFFIX
= ".packed.7z"
35 COMPRESSED_FILE_EXT
= ".packed.7z" # extension of patch archive file
36 COURGETTE_EXEC
= "courgette.exe"
37 MINI_INSTALLER_INPUT_FILE
= "packed_files.txt"
38 PATCH_FILE_EXT
= '.diff'
39 SETUP_EXEC
= "setup.exe"
40 SETUP_PATCH_FILE_PREFIX
= "setup_patch"
41 TEMP_ARCHIVE_DIR
= "temp_installer_archive"
42 VERSION_FILE
= "VERSION"
48 def BuildVersion(build_dir
):
49 """Returns the full build version string constructed from information in
50 VERSION_FILE. Any segment not found in that file will default to '0'.
56 for line
in open(os
.path
.join(build_dir
, '../../chrome', VERSION_FILE
), 'r'):
58 if line
.startswith('MAJOR='):
60 elif line
.startswith('MINOR='):
62 elif line
.startswith('BUILD='):
64 elif line
.startswith('PATCH='):
66 return '%s.%s.%s.%s' % (major
, minor
, build
, patch
)
69 def CompressUsingLZMA(build_dir
, compressed_file
, input_file
):
70 lzma_exec
= GetLZMAExec(build_dir
)
73 # Flags equivalent to -mx9 (ultra) but with the bcj2 turned on (exe
74 # pre-filter). This results in a ~2.3MB decrease in installer size on
76 # Additionally, these settings reflect a 7zip 4.42 and up change in
77 # the definition of -mx9, increasting the dicionary size moving to
78 # 26bit = 64MB. This results in an additional ~3.5MB decrease.
79 # Older 7zip versions can support these settings, as these changes
80 # rely on existing functionality in the lzma format.
83 '-m2=LZMA:d22:fb128:mf=bt2',
84 '-m3=LZMA:d22:fb128:mf=bt2',
90 if os
.path
.exists(compressed_file
):
91 os
.remove(compressed_file
)
95 def CopyAllFilesToStagingDir(config
, distribution
, staging_dir
, build_dir
,
97 """Copies the files required for installer archive.
98 Copies all common files required for various distributions of Chromium and
99 also files for the specific Chromium build specified by distribution.
101 CopySectionFilesToStagingDir(config
, 'GENERAL', staging_dir
, build_dir
)
103 if len(distribution
) > 1 and distribution
[0] == '_':
104 distribution
= distribution
[1:]
105 CopySectionFilesToStagingDir(config
, distribution
.upper(),
106 staging_dir
, build_dir
)
107 if enable_hidpi
== '1':
108 CopySectionFilesToStagingDir(config
, 'HIDPI', staging_dir
, build_dir
)
111 def CopySectionFilesToStagingDir(config
, section
, staging_dir
, src_dir
):
112 """Copies installer archive files specified in section from src_dir to
113 staging_dir. This method reads section from config and copies all the
114 files specified from src_dir to staging dir.
116 for option
in config
.options(section
):
117 if option
.endswith('dir'):
120 dst_dir
= os
.path
.join(staging_dir
, config
.get(section
, option
))
121 src_paths
= glob
.glob(os
.path
.join(src_dir
, option
))
122 if src_paths
and not os
.path
.exists(dst_dir
):
124 for src_path
in src_paths
:
125 dst_path
= os
.path
.join(dst_dir
, os
.path
.basename(src_path
))
126 if not os
.path
.exists(dst_path
):
127 g_archive_inputs
.append(src_path
)
128 shutil
.copy(src_path
, dst_dir
)
130 def GenerateDiffPatch(options
, orig_file
, new_file
, patch_file
):
131 if (options
.diff_algorithm
== "COURGETTE"):
132 exe_file
= os
.path
.join(options
.last_chrome_installer
, COURGETTE_EXEC
)
133 cmd
= '%s -gen "%s" "%s" "%s"' % (exe_file
, orig_file
, new_file
, patch_file
)
135 exe_file
= os
.path
.join(options
.build_dir
, BSDIFF_EXEC
)
136 cmd
= [exe_file
, orig_file
, new_file
, patch_file
,]
137 RunSystemCommand(cmd
)
139 def GetLZMAExec(build_dir
):
140 lzma_exec
= os
.path
.join(build_dir
, "..", "..", "third_party",
141 "lzma_sdk", "Executable", "7za.exe")
144 def GetPrevVersion(build_dir
, temp_dir
, last_chrome_installer
, output_name
):
145 if not last_chrome_installer
:
148 lzma_exec
= GetLZMAExec(build_dir
)
149 prev_archive_file
= os
.path
.join(last_chrome_installer
,
150 output_name
+ ARCHIVE_SUFFIX
)
155 'Chrome-bin/*/chrome.dll',]
156 RunSystemCommand(cmd
)
157 dll_path
= glob
.glob(os
.path
.join(temp_dir
, 'Chrome-bin', '*', 'chrome.dll'))
158 return os
.path
.split(os
.path
.split(dll_path
[0])[0])[1]
160 def MakeStagingDirectories(staging_dir
):
161 """Creates a staging path for installer archive. If directory exists already,
162 deletes the existing directory.
164 file_path
= os
.path
.join(staging_dir
, TEMP_ARCHIVE_DIR
)
165 if os
.path
.exists(file_path
):
166 shutil
.rmtree(file_path
)
167 os
.makedirs(file_path
)
169 temp_file_path
= os
.path
.join(staging_dir
, TEMP_ARCHIVE_DIR
)
170 if os
.path
.exists(temp_file_path
):
171 shutil
.rmtree(temp_file_path
)
172 os
.makedirs(temp_file_path
)
173 return (file_path
, temp_file_path
)
175 def Readconfig(input_file
, current_version
):
176 """Reads config information from input file after setting default value of
180 variables
['ChromeDir'] = CHROME_DIR
181 variables
['VersionDir'] = os
.path
.join(variables
['ChromeDir'],
183 config
= ConfigParser
.SafeConfigParser(variables
)
184 config
.read(input_file
)
187 def RunSystemCommand(cmd
, **kw
):
189 exit_code
= subprocess
.call(cmd
, **kw
)
191 raise Exception("Error while running cmd: %s, exit_code: %s" %
194 def CreateArchiveFile(options
, staging_dir
, current_version
, prev_version
):
195 """Creates a new installer archive file after deleting any existing old file.
197 # First create an uncompressed archive file for the current build (chrome.7z)
198 lzma_exec
= GetLZMAExec(options
.build_dir
)
199 archive_file
= os
.path
.join(options
.output_dir
,
200 options
.output_name
+ ARCHIVE_SUFFIX
)
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
209 def path_fixup(path
):
210 """Fixes path for depfile format: backslash to forward slash, and
211 backslash escaping for spaces."""
212 return path
.replace('\\', '/').replace(' ', '\\ ')
214 # Gather the list of files in the staging dir that will be zipped up. We
215 # only gather this list to make sure that g_archive_inputs is complete (i.e.
216 # that there's not file copies that got missed).
217 staging_contents
= []
218 for root
, dirs
, files
in os
.walk(os
.path
.join(staging_dir
, CHROME_DIR
)):
219 for filename
in files
:
220 staging_contents
.append(path_fixup(os
.path
.join(root
, filename
)))
222 # Make sure there's an archive_input for each staging dir file.
223 for staging_file
in staging_contents
:
224 for archive_input
in g_archive_inputs
:
225 archive_rel
= path_fixup(archive_input
)
226 if (os
.path
.basename(staging_file
).lower() ==
227 os
.path
.basename(archive_rel
).lower()):
230 raise Exception('Did not find an archive input file for "%s"' %
233 # Finally, write the depfile referencing the inputs.
234 with
open(options
.depfile
, 'wb') as f
:
235 f
.write(path_fixup(os
.path
.relpath(archive_file
, options
.build_dir
)) +
237 f
.write(' ' + ' \\\n '.join(path_fixup(x
) for x
in g_archive_inputs
))
243 os
.path
.join(staging_dir
, CHROME_DIR
),
245 # There doesnt seem to be any way in 7za.exe to override existing file so
246 # we always delete before creating a new one.
247 if not os
.path
.exists(archive_file
):
248 RunSystemCommand(cmd
)
249 elif options
.skip_rebuild_archive
!= "true":
250 os
.remove(archive_file
)
251 RunSystemCommand(cmd
)
253 # Do not compress the archive in developer (component) builds.
254 if options
.component_build
== '1':
255 compressed_file
= os
.path
.join(
256 options
.output_dir
, options
.output_name
+ COMPRESSED_ARCHIVE_SUFFIX
)
257 if os
.path
.exists(compressed_file
):
258 os
.remove(compressed_file
)
259 return os
.path
.basename(archive_file
)
261 # If we are generating a patch, run bsdiff against previous build and
262 # compress the resulting patch file. If this is not a patch just compress the
263 # uncompressed archive file.
264 patch_name_prefix
= options
.output_name
+ CHROME_PATCH_FILE_SUFFIX
265 if options
.last_chrome_installer
:
266 prev_archive_file
= os
.path
.join(options
.last_chrome_installer
,
267 options
.output_name
+ ARCHIVE_SUFFIX
)
268 patch_file
= os
.path
.join(options
.build_dir
, patch_name_prefix
+
270 GenerateDiffPatch(options
, prev_archive_file
, archive_file
, patch_file
)
271 compressed_archive_file
= patch_name_prefix
+ '_' + \
272 current_version
+ '_from_' + prev_version
+ \
274 orig_file
= patch_file
276 compressed_archive_file
= options
.output_name
+ COMPRESSED_ARCHIVE_SUFFIX
277 orig_file
= archive_file
279 compressed_archive_file_path
= os
.path
.join(options
.output_dir
,
280 compressed_archive_file
)
281 CompressUsingLZMA(options
.build_dir
, compressed_archive_file_path
, orig_file
)
283 return compressed_archive_file
286 def PrepareSetupExec(options
, current_version
, prev_version
):
287 """Prepares setup.exe for bundling in mini_installer based on options."""
288 if options
.setup_exe_format
== "FULL":
289 setup_file
= SETUP_EXEC
290 elif options
.setup_exe_format
== "DIFF":
291 if not options
.last_chrome_installer
:
293 "To use DIFF for setup.exe, --last_chrome_installer is needed.")
294 prev_setup_file
= os
.path
.join(options
.last_chrome_installer
, SETUP_EXEC
)
295 new_setup_file
= os
.path
.join(options
.build_dir
, SETUP_EXEC
)
296 patch_file
= os
.path
.join(options
.build_dir
, SETUP_PATCH_FILE_PREFIX
+
298 GenerateDiffPatch(options
, prev_setup_file
, new_setup_file
, patch_file
)
299 setup_file
= SETUP_PATCH_FILE_PREFIX
+ '_' + current_version
+ \
300 '_from_' + prev_version
+ COMPRESSED_FILE_EXT
301 setup_file_path
= os
.path
.join(options
.build_dir
, setup_file
)
302 CompressUsingLZMA(options
.build_dir
, setup_file_path
, patch_file
)
304 cmd
= ['makecab.exe',
305 '/D', 'CompressionType=LZX',
307 '/L', options
.output_dir
,
308 os
.path
.join(options
.build_dir
, SETUP_EXEC
),]
309 # Send useless makecab progress on stdout to the bitbucket.
310 RunSystemCommand(cmd
, stdout
=open(os
.devnull
, "w"))
311 setup_file
= SETUP_EXEC
[:-1] + "_"
315 _RESOURCE_FILE_HEADER
= """\
316 // This file is automatically generated by create_installer_archive.py.
317 // It contains the resource entries that are going to be linked inside
318 // mini_installer.exe. For each file to be linked there should be two
320 // - The first line contains the output filename (without path) and the
321 // type of the resource ('BN' - not compressed , 'BL' - LZ compressed,
322 // 'B7' - LZMA compressed)
323 // - The second line contains the path to the input file. Uses '/' to
324 // separate path components.
328 def CreateResourceInputFile(
329 output_dir
, setup_format
, archive_file
, setup_file
, resource_file_path
,
330 component_build
, staging_dir
, current_version
):
331 """Creates resource input file (packed_files.txt) for mini_installer project.
333 This method checks the format of setup.exe being used and according sets
336 setup_resource_type
= "BL"
337 if (setup_format
== "FULL"):
338 setup_resource_type
= "BN"
339 elif (setup_format
== "DIFF"):
340 setup_resource_type
= "B7"
342 # An array of (file, type, path) tuples of the files to be included.
344 resources
.append((setup_file
, setup_resource_type
,
345 os
.path
.join(output_dir
, setup_file
)))
346 resources
.append((archive_file
, 'B7',
347 os
.path
.join(output_dir
, archive_file
)))
348 # Include all files needed to run setup.exe (these are copied into the
349 # 'Installer' dir by DoComponentBuildTasks).
351 installer_dir
= os
.path
.join(staging_dir
, CHROME_DIR
, current_version
,
353 for file in os
.listdir(installer_dir
):
354 resources
.append((file, 'BN', os
.path
.join(installer_dir
, file)))
356 with
open(resource_file_path
, 'w') as f
:
357 f
.write(_RESOURCE_FILE_HEADER
)
358 for (file, type, path
) in resources
:
359 f
.write('\n%s %s\n "%s"\n' % (file, type, path
.replace("\\","/")))
362 # Reads |manifest_name| from |build_dir| and writes |manifest_name| to
363 # |output_dir| with the same content plus |inserted_string| added just before
365 def CopyAndAugmentManifest(build_dir
, output_dir
, manifest_name
,
366 inserted_string
, insert_before
):
367 with
open(os
.path
.join(build_dir
, manifest_name
), 'r') as f
:
368 manifest_lines
= f
.readlines()
372 for i
in xrange(len(manifest_lines
)):
373 insert_pos
= manifest_lines
[i
].find(insert_before
)
377 if insert_line
== -1:
378 raise ValueError('Could not find {0} in the manifest:\n{1}'.format(
379 insert_before
, ''.join(manifest_lines
)))
380 old
= manifest_lines
[insert_line
]
381 manifest_lines
[insert_line
] = (old
[:insert_pos
] + '\n' + inserted_string
+
382 '\n' + old
[insert_pos
:])
384 with
open(os
.path
.join(output_dir
, manifest_name
), 'w') as f
:
385 f
.write(''.join(manifest_lines
))
388 def CopyIfChanged(src
, target_dir
):
389 """Copy specified |src| file to |target_dir|, but only write to target if
390 the file has changed. This avoids a problem during packaging where parts of
391 the build have not completed and have the runtime DLL locked when we try to
392 copy over it. See http://crbug.com/305877 for details."""
393 assert os
.path
.isdir(target_dir
)
394 dest
= os
.path
.join(target_dir
, os
.path
.basename(src
))
395 g_archive_inputs
.append(src
)
396 if os
.path
.exists(dest
):
397 # We assume the files are OK to buffer fully into memory since we know
399 with
open(src
, 'rb') as fsrc
:
400 src_data
= fsrc
.read()
401 with
open(dest
, 'rb') as fdest
:
402 dest_data
= fdest
.read()
403 if src_data
!= dest_data
:
404 # This may still raise if we get here, but this really should almost
405 # never happen (it would mean that the contents of e.g. msvcr100d.dll
407 shutil
.copyfile(src
, dest
)
409 shutil
.copyfile(src
, dest
)
412 # Copy the relevant CRT DLLs to |build_dir|. We copy DLLs from all versions
413 # of VS installed to make sure we have the correct CRT version, unused DLLs
414 # should not conflict with the others anyways.
415 def CopyVisualStudioRuntimeDLLs(target_arch
, build_dir
):
416 is_debug
= os
.path
.basename(build_dir
).startswith('Debug')
417 if not is_debug
and not os
.path
.basename(build_dir
).startswith('Release'):
418 print ("Warning: could not determine build configuration from "
419 "output directory, assuming Release build.")
424 crt_dlls
= glob
.glob(
425 "C:/Program Files (x86)/Microsoft Visual Studio */VC/redist/"
426 "Debug_NonRedist/" + target_arch
+ "/Microsoft.*.DebugCRT/*.dll")
428 crt_dlls
= glob
.glob(
429 "C:/Program Files (x86)/Microsoft Visual Studio */VC/redist/" +
430 target_arch
+ "/Microsoft.*.CRT/*.dll")
432 # Also handle the case where someone is building using only winsdk and
433 # doesn't have Visual Studio installed.
435 if target_arch
== 'x64':
436 # check we are are on a 64bit system by existence of WOW64 dir
437 if os
.access("C:/Windows/SysWOW64", os
.F_OK
):
438 sys_dll_dir
= "C:/Windows/System32"
440 # only support packaging of 64bit installer on 64bit system
441 # but this just as bad as not finding DLLs at all so we
442 # don't abort here to mirror behavior below
443 print ("Warning: could not find x64 CRT DLLs on x86 system.")
445 # On a 64-bit system, 32-bit dlls are in SysWOW64 (don't ask).
446 if os
.access("C:/Windows/SysWOW64", os
.F_OK
):
447 sys_dll_dir
= "C:/Windows/SysWOW64"
449 sys_dll_dir
= "C:/Windows/System32"
451 if sys_dll_dir
is not None:
453 crt_dlls
= glob
.glob(os
.path
.join(sys_dll_dir
, "msvc*0d.dll"))
455 crt_dlls
= glob
.glob(os
.path
.join(sys_dll_dir
, "msvc*0.dll"))
458 print ("Warning: could not find CRT DLLs to copy to build dir - target "
459 "may not run on a system that doesn't have those DLLs.")
462 CopyIfChanged(dll
, build_dir
)
465 # Copies component build DLLs and generates required config files and manifests
466 # in order for chrome.exe and setup.exe to be able to find those DLLs at
468 # This is meant for developer builds only and should never be used to package
470 def DoComponentBuildTasks(staging_dir
, build_dir
, target_arch
, current_version
):
471 # Get the required directories for the upcoming operations.
472 chrome_dir
= os
.path
.join(staging_dir
, CHROME_DIR
)
473 version_dir
= os
.path
.join(chrome_dir
, current_version
)
474 installer_dir
= os
.path
.join(version_dir
, 'Installer')
475 # |installer_dir| is technically only created post-install, but we need it
476 # now to add setup.exe's config and manifest to the archive.
477 if not os
.path
.exists(installer_dir
):
478 os
.mkdir(installer_dir
)
480 # Copy the VS CRT DLLs to |build_dir|. This must be done before the general
481 # copy step below to ensure the CRT DLLs are added to the archive and marked
482 # as a dependency in the exe manifests generated below.
483 CopyVisualStudioRuntimeDLLs(target_arch
, build_dir
)
485 # Explicitly list the component DLLs setup.exe depends on (this list may
486 # contain wildcards). These will be copied to |installer_dir| in the archive.
487 setup_component_dll_globs
= [ 'base.dll',
493 for setup_component_dll_glob
in setup_component_dll_globs
:
494 setup_component_dlls
= glob
.glob(os
.path
.join(build_dir
,
495 setup_component_dll_glob
))
496 for setup_component_dll
in setup_component_dlls
:
497 g_archive_inputs
.append(setup_component_dll
)
498 shutil
.copy(setup_component_dll
, installer_dir
)
500 # Stage all the component DLLs found in |build_dir| to the |version_dir| (for
501 # the version assembly to be able to refer to them below and make sure
502 # chrome.exe can find them at runtime). The component DLLs are considered to
503 # be all the DLLs which have not already been added to the |version_dir| by
504 # virtue of chrome.release.
505 build_dlls
= glob
.glob(os
.path
.join(build_dir
, '*.dll'))
506 staged_dll_basenames
= [os
.path
.basename(staged_dll
) for staged_dll
in \
507 glob
.glob(os
.path
.join(version_dir
, '*.dll'))]
508 component_dll_filenames
= []
509 for component_dll
in [dll
for dll
in build_dlls
if \
510 os
.path
.basename(dll
) not in staged_dll_basenames
]:
511 component_dll_name
= os
.path
.basename(component_dll
)
512 # remoting_*.dll's don't belong in the archive (it doesn't depend on them
513 # in gyp). Trying to copy them causes a build race when creating the
514 # installer archive in component mode. See: crbug.com/180996
515 if component_dll_name
.startswith('remoting_'):
517 component_dll_filenames
.append(component_dll_name
)
518 g_archive_inputs
.append(component_dll
)
519 shutil
.copy(component_dll
, version_dir
)
521 # Augment {version}.manifest to include all component DLLs as part of the
522 # assembly it constitutes, which will allow dependents of this assembly to
524 version_assembly_dll_additions
= []
525 for dll_filename
in component_dll_filenames
:
526 version_assembly_dll_additions
.append(" <file name='%s'/>" % dll_filename
)
527 CopyAndAugmentManifest(build_dir
, version_dir
,
528 '%s.manifest' % current_version
,
529 '\n'.join(version_assembly_dll_additions
),
534 """Main method that reads input file, creates archive file and write
537 current_version
= BuildVersion(options
.build_dir
)
539 config
= Readconfig(options
.input_file
, current_version
)
541 (staging_dir
, temp_dir
) = MakeStagingDirectories(options
.staging_dir
)
543 prev_version
= GetPrevVersion(options
.build_dir
, temp_dir
,
544 options
.last_chrome_installer
,
547 # Preferentially copy the files we can find from the output_dir, as
548 # this is where we'll find the Syzygy-optimized executables when
549 # building the optimized mini_installer.
550 if options
.build_dir
!= options
.output_dir
:
551 CopyAllFilesToStagingDir(config
, options
.distribution
,
552 staging_dir
, options
.output_dir
,
553 options
.enable_hidpi
)
555 # Now copy the remainder of the files from the build dir.
556 CopyAllFilesToStagingDir(config
, options
.distribution
,
557 staging_dir
, options
.build_dir
,
558 options
.enable_hidpi
)
560 if options
.component_build
== '1':
561 DoComponentBuildTasks(staging_dir
, options
.build_dir
,
562 options
.target_arch
, current_version
)
564 version_numbers
= current_version
.split('.')
565 current_build_number
= version_numbers
[2] + '.' + version_numbers
[3]
566 prev_build_number
= ''
568 version_numbers
= prev_version
.split('.')
569 prev_build_number
= version_numbers
[2] + '.' + version_numbers
[3]
571 # Name of the archive file built (for example - chrome.7z or
572 # patch-<old_version>-<new_version>.7z or patch-<new_version>.7z
573 archive_file
= CreateArchiveFile(options
, staging_dir
,
574 current_build_number
, prev_build_number
)
576 setup_file
= PrepareSetupExec(options
,
577 current_build_number
, prev_build_number
)
579 CreateResourceInputFile(options
.output_dir
, options
.setup_exe_format
,
580 archive_file
, setup_file
, options
.resource_file_path
,
581 options
.component_build
== '1', staging_dir
,
585 parser
= optparse
.OptionParser()
586 parser
.add_option('-i', '--input_file',
587 help='Input file describing which files to archive.')
588 parser
.add_option('-b', '--build_dir',
589 help='Build directory. The paths in input_file are relative to this.')
590 parser
.add_option('--staging_dir',
591 help='Staging directory where intermediate files and directories '
593 parser
.add_option('-o', '--output_dir',
594 help='The output directory where the archives will be written. '
595 'Defaults to the build_dir.')
596 parser
.add_option('--resource_file_path',
597 help='The path where the resource file will be output. '
598 'Defaults to %s in the build directory.' %
599 MINI_INSTALLER_INPUT_FILE
)
600 parser
.add_option('-d', '--distribution',
601 help='Name of Chromium Distribution. Optional.')
602 parser
.add_option('-s', '--skip_rebuild_archive',
603 default
="False", help='Skip re-building Chrome.7z archive if it exists.')
604 parser
.add_option('-l', '--last_chrome_installer',
605 help='Generate differential installer. The value of this parameter '
606 'specifies the directory that contains base versions of '
607 'setup.exe, courgette.exe (if --diff_algorithm is COURGETTE) '
609 parser
.add_option('-f', '--setup_exe_format', default
='COMPRESSED',
610 help='How setup.exe should be included {COMPRESSED|DIFF|FULL}.')
611 parser
.add_option('-a', '--diff_algorithm', default
='BSDIFF',
612 help='Diff algorithm to use when generating differential patches '
613 '{BSDIFF|COURGETTE}.')
614 parser
.add_option('-n', '--output_name', default
='chrome',
615 help='Name used to prefix names of generated archives.')
616 parser
.add_option('--enable_hidpi', default
='0',
617 help='Whether to include HiDPI resource files.')
618 parser
.add_option('--component_build', default
='0',
619 help='Whether this archive is packaging a component build. This will '
620 'also turn off compression of chrome.7z into chrome.packed.7z and '
621 'helpfully delete any old chrome.packed.7z in |output_dir|.')
622 parser
.add_option('--depfile',
623 help='Generate a depfile with the given name listing the implicit inputs '
624 'to the archive process that can be used with a build system.')
625 parser
.add_option('--target_arch', default
='x86',
626 help='Specify the target architecture for installer - this is used '
627 'to determine which CRT runtime files to pull and package '
628 'with the installer archive {x86|x64}.')
630 options
, _
= parser
.parse_args()
631 if not options
.build_dir
:
632 parser
.error('You must provide a build dir.')
634 options
.build_dir
= os
.path
.normpath(options
.build_dir
)
636 if not options
.staging_dir
:
637 parser
.error('You must provide a staging dir.')
639 if not options
.input_file
:
640 parser
.error('You must provide an input file')
642 if not options
.output_dir
:
643 options
.output_dir
= options
.build_dir
645 if not options
.resource_file_path
:
646 options
.resource_file_path
= os
.path
.join(options
.build_dir
,
647 MINI_INSTALLER_INPUT_FILE
)
652 if '__main__' == __name__
:
654 sys
.exit(main(_ParseOptions()))