25from os
import environ
as env
32TOP = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
36 """Runs a subprocess and waits for termination. Returns (stdout, returncode)
37 of the process. stderr is attached to the parent.
"""
38 proc = subprocess.Popen(args, stdout=subprocess.PIPE)
39 (stdout, stderr) = proc.communicate()
40 return (stdout, proc.returncode)
43def _GetOutputNoError(args):
44 """Similar to _GetOutput() but ignores stderr. If there's an error launching
45 the child (like file not found), the exception will be caught
and (
None, 1)
46 will be returned to mimic quiet failure.
"""
48 proc = subprocess.Popen(
49 args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
52 (stdout, stderr) = proc.communicate()
53 return (stdout, proc.returncode)
56def _RemoveKeys(plist, *keys):
57 """Removes a varargs of keys from the plist."""
65def _AddVersionKeys(plist, version=None):
66 """Adds the product version number into the plist. Returns True on success and
67 False on error. The error will be printed to stderr.
"""
69 match = re.match(
'\d+\.\d+\.(\d+\.\d+)$', version)
71 print(
'Invalid version string specified: "%s"' % version,
75 full_version = match.group(0)
76 bundle_version = match.group(1)
80 VERSION_TOOL = os.path.join(TOP,
'build/util/version.py')
81 VERSION_FILE = os.path.join(TOP,
'chrome/VERSION')
83 (stdout, retval1) = _GetOutput([
84 VERSION_TOOL,
'-f', VERSION_FILE,
'-t',
85 '@MAJOR@.@MINOR@.@BUILD@.@PATCH@'
87 full_version = stdout.rstrip()
89 (stdout, retval2) = _GetOutput(
90 [VERSION_TOOL,
'-f', VERSION_FILE,
'-t',
'@BUILD@.@PATCH@'])
91 bundle_version = stdout.rstrip()
95 if retval1
or retval2:
99 plist[
'CFBundleShortVersionString'] = full_version
108 plist[
'CFBundleVersion'] = bundle_version
114def _DoSCMKeys(plist, add_keys):
115 """Adds the SCM information, visible in about:version, to property list. If
116 |add_keys| is True, it will insert the keys, otherwise it will remove them.
"""
120 VERSION_TOOL = os.path.join(TOP,
'build/util/version.py')
121 LASTCHANGE_FILE = os.path.join(TOP,
'build/util/LASTCHANGE')
122 (stdout, retval) = _GetOutput(
123 [VERSION_TOOL,
'-f', LASTCHANGE_FILE,
'-t',
'@LASTCHANGE@'])
126 scm_revision = stdout.rstrip()
129 _RemoveKeys(plist,
'SCMRevision')
130 if scm_revision !=
None:
131 plist[
'SCMRevision'] = scm_revision
133 print(
'Could not determine SCM revision. This may be OK.',
139def _AddBreakpadKeys(plist, branding):
140 """Adds the Breakpad keys. This must be called AFTER _AddVersionKeys() and
141 also requires the |branding| argument."""
142 plist['BreakpadReportInterval'] =
'3600'
143 plist[
'BreakpadProduct'] =
'%s_Mac' % branding
144 plist[
'BreakpadProductDisplay'] = branding
145 plist[
'BreakpadVersion'] = plist[
'CFBundleShortVersionString']
147 plist[
'BreakpadSendAndExit'] =
'YES'
148 plist[
'BreakpadSkipConfirm'] =
'YES'
151def _RemoveBreakpadKeys(plist):
152 """Removes any set Breakpad keys."""
153 _RemoveKeys(plist,
'BreakpadURL',
'BreakpadReportInterval',
154 'BreakpadProduct',
'BreakpadProductDisplay',
'BreakpadVersion',
155 'BreakpadSendAndExit',
'BreakpadSkipConfirm')
161 components = (
'32bit',
'full')
162 assert tuple(sorted(components)) == components
164 components_len =
len(components)
165 combinations = 1 << components_len
167 for combination
in range(0, combinations):
169 for component_index
in range(0, components_len):
170 if combination & (1 << component_index):
171 tag_suffix +=
'-' + components[component_index]
172 tag_suffixes.append(tag_suffix)
176def _AddKeystoneKeys(plist, bundle_identifier):
177 """Adds the Keystone keys. This must be called AFTER _AddVersionKeys() and
178 also requires the |bundle_identifier| argument (com.example.product)."""
179 plist['KSVersion'] = plist[
'CFBundleShortVersionString']
180 plist[
'KSProductID'] = bundle_identifier
181 plist[
'KSUpdateURL'] =
'https://tools.google.com/service/update2'
183 _RemoveKeys(plist,
'KSChannelID')
184 for tag_suffix
in _TagSuffixes():
186 plist[
'KSChannelID' + tag_suffix] = tag_suffix
189def _RemoveKeystoneKeys(plist):
190 """Removes any set Keystone keys."""
191 _RemoveKeys(plist,
'KSVersion',
'KSProductID',
'KSUpdateURL')
194 for tag_suffix
in _TagSuffixes():
195 tag_keys.append(
'KSChannelID' + tag_suffix)
196 _RemoveKeys(plist, *tag_keys)
200 parser = optparse.OptionParser(
'%prog [options]')
207 help=
'Enable Breakpad [1 or 0]')
209 '--breakpad_uploads',
210 dest=
'breakpad_uploads',
214 help=
'Enable Breakpad\'s uploading of crash dumps [1 or 0]')
221 help=
'Enable Keystone [1 or 0]')
228 help=
'Add SCM metadata [1 or 0]')
235 help=
'The branding of the binary')
238 dest=
'bundle_identifier',
242 help=
'The bundle id of the binary')
249 help=
'The version string [major.minor.build.patch]')
250 (options, args) = parser.parse_args(argv)
253 print(parser.get_usage(), file=sys.stderr)
257 DEST_INFO_PLIST = os.path.join(env[
'TARGET_BUILD_DIR'],
258 env[
'INFOPLIST_PATH'])
259 plist = plistlib.readPlist(DEST_INFO_PLIST)
262 if not _AddVersionKeys(plist, version=options.version):
266 if options.use_breakpad:
267 if options.branding
is None:
268 print(
'Use of Breakpad requires branding.', file=sys.stderr)
270 _AddBreakpadKeys(plist, options.branding)
271 if options.breakpad_uploads:
272 plist[
'BreakpadURL'] =
'https://clients2.google.com/cr/report'
280 plist[
'BreakpadURL'] =
'none'
282 _RemoveBreakpadKeys(plist)
285 if options.use_keystone
and env[
'CONFIGURATION'] ==
'Release':
286 if options.bundle_identifier
is None:
287 print(
'Use of Keystone requires the bundle id.', file=sys.stderr)
289 _AddKeystoneKeys(plist, options.bundle_identifier)
291 _RemoveKeystoneKeys(plist)
294 if not _DoSCMKeys(plist, options.add_scm_info):
298 temp_info_plist = tempfile.NamedTemporaryFile()
299 plistlib.writePlist(plist, temp_info_plist.name)
303 proc = subprocess.Popen([
304 'plutil',
'-convert',
'xml1',
'-o', DEST_INFO_PLIST,
308 return proc.returncode
311if __name__ ==
'__main__':
312 sys.exit(
Main(sys.argv[1:]))
def print(*args, **kwargs)