Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(549)

Side by Side Diff: enterprise/installer/build_enterprise_installer.py

Issue 624713003: Keep only base/extractor.[cc|h]. (Closed) Base URL: https://chromium.googlesource.com/external/omaha.git@master
Patch Set: Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « enterprise/installer/build.scons ('k') | enterprise/installer/custom_actions/build.scons » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python2.4
2 #
3 # Copyright 2009-2010 Google Inc.
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 # ========================================================================
17
18 """Build an installer for use in enterprise situations.
19
20 This module contains the functionality required to build enterprise
21 installers (MSIs) for Omaha's various customers.
22
23 The supplied wxs templates need to have an XML extension because SCons
24 tries to apply WiX building rules to any input file with the .wxs suffix.
25
26 BuildGoogleUpdateFragment(): Build an update fragment into a .wixobj.
27 GenerateNameBasedGUID(): Generate a GUID based on the names supplied.
28 BuildEnterpriseInstaller(): Build an MSI installer for use in enterprises.
29 """
30
31 import binascii
32 import md5
33
34 _GOOGLE_UPDATE_NAMESPACE_GUID = 'BE19B3E4502845af8B3E67A99FCDCFB1'
35
36
37 def BuildGoogleUpdateFragment(env,
38 metainstaller_path,
39 product_name,
40 product_version,
41 product_guid,
42 product_custom_params,
43 wixobj_base_name,
44 google_update_wxs_template_path):
45 """Build an update fragment into a WiX object.
46
47 Takes a supplied wix fragment, and turns it into a .wixobj object for later
48 inclusion into an MSI.
49
50 Args:
51 env: environment to build with
52 metainstaller_path: path to the Omaha metainstaller to include
53 product_name: name of the product the fragment is being built for
54 product_version: product version to be installed
55 product_guid: Omaha application ID of the product the fragment is being
56 built for
57 product_custom_params: custom values to be appended to the Omaha tag
58 wixobj_base_name: root of name for the wixobj
59 google_update_wxs_template_path: path to the fragment source
60
61 Returns:
62 Output object for the built wixobj.
63
64 Raises:
65 Nothing.
66 """
67
68 product_name_legal_identifier = product_name.replace(' ', '')
69
70 intermediate_base_name = wixobj_base_name + '_google_update_fragment'
71
72 copy_target = env.Command(
73 target=intermediate_base_name + '.wxs',
74 source=google_update_wxs_template_path,
75 action='@copy /y $SOURCE $TARGET',
76 )
77
78 wix_defines = [
79 '-dProductName="%s"' % product_name,
80 '-dProductNameLegalIdentifier="%s"' % product_name_legal_identifier,
81 '-dProductVersion=' + product_version,
82 '-dProductGuid="%s"' % product_guid,
83 '-dProductCustomParams="%s"' % product_custom_params,
84 '-dGoogleUpdateMetainstallerPath="%s"' % (
85 env.File(metainstaller_path).abspath),
86 ]
87
88 wixobj_output = env.Command(
89 target=intermediate_base_name + '.wixobj',
90 source=copy_target,
91 action='@candle.exe -nologo -out $TARGET $SOURCE ' + ' '.join(wix_defines)
92 )
93
94 # Force a rebuild of the .wixobj file when the metainstaller changes.
95 # Does not necessarily force rebuild of the MSI because hash does not change.
96 env.Depends(wixobj_output, metainstaller_path)
97
98 return wixobj_output
99
100
101 def _BuildMsiForExe(env,
102 product_name,
103 product_version,
104 product_guid,
105 product_installer_path,
106 product_installer_install_command,
107 product_installer_disable_update_registration_arg,
108 product_uninstaller_additional_args,
109 msi_base_name,
110 google_update_wixobj_output,
111 enterprise_installer_dir,
112 show_error_action_dll_path,
113 metainstaller_path,
114 output_dir):
115 """Build an MSI installer for use in enterprise situations.
116
117 Builds an MSI for the executable installer at product_installer_path using
118 the supplied details. Requires an existing Google Update installer fragment
119 as well as a path to a custom action DLL containing the logic to launch the
120 product's uninstaller.
121
122 This is intended to enable enterprise installation scenarios.
123
124 Args:
125 env: environment to build with
126 product_name: name of the product being built
127 product_version: product version to be installed
128 product_guid: product's Omaha application ID
129 product_installer_path: path to specific product installer
130 product_installer_install_command: command line args used to run product
131 installer in 'install' mode
132 product_installer_disable_update_registration_arg: command line args used
133 to run product installer in 'do not register' mode
134 product_uninstaller_additional_args: extra command line parameters that the
135 custom action dll will pass on to the product uninstaller, typically
136 you'll want to pass any extra arguments that will force the uninstaller
137 to run silently here.
138 msi_base_name: root of name for the MSI
139 google_update_wixobj_output: the MSI fragment containing the Omaha
140 installer.
141 enterprise_installer_dir: path to dir which contains
142 enterprise_installer.wxs.xml
143 show_error_action_dll_path: path to the error display custom action dll that
144 exports a ShowInstallerResultUIString method. This CA method will read
145 the LastInstallerResultUIString from the product's ClientState key in
146 the registry and display the string via MsiProcessMessage.
147 metainstaller_path: path to the Omaha metainstaller. Should be same file
148 used for google_update_wixobj_output. Used only to force rebuilds.
149 output_dir: path to the directory that will contain the resulting MSI
150
151 Returns:
152 Nothing.
153
154 Raises:
155 Nothing.
156 """
157
158 product_name_legal_identifier = product_name.replace(' ', '')
159 msi_name = msi_base_name + '.msi'
160
161 omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID)
162
163 # Include the .msi filename in the Product Code generation because "the
164 # product code must be changed if... the name of the .msi file has been
165 # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx.
166 msi_product_id = GenerateNameBasedGUID(
167 omaha_installer_namespace,
168 'Product %s %s' % (product_name, msi_base_name)
169 )
170 msi_upgradecode_guid = GenerateNameBasedGUID(
171 omaha_installer_namespace,
172 'Upgrade ' + product_name
173 )
174
175 copy_target = env.Command(
176 target=msi_base_name + '.wxs',
177 source=enterprise_installer_dir + '/enterprise_installer.wxs.xml',
178 action='@copy /y $SOURCE $TARGET',
179 )
180
181 # Disable warning LGHT1076 and internal check ICE61 on light.exe. Details:
182 # http://blogs.msdn.com/astebner/archive/2007/02/13/building-an-msi-using-wix- v3-0-that-includes-the-vc-8-0-runtime-merge-modules.aspx
183 # http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/ICE61-Upgrade- VersionMax-format-is-wrong-td4396813.html # pylint: disable-msg=C6310
184 wix_env = env.Clone()
185 wix_env.Append(
186 WIXCANDLEFLAGS=[
187 '-dProductName=' + product_name,
188 '-dProductNameLegalIdentifier=' + product_name_legal_identifier,
189 '-dProductVersion=' + product_version,
190 '-dProductGuid=' + product_guid,
191 '-dProductInstallerPath=' + env.File(product_installer_path).abspath,
192 '-dProductInstallerInstallCommand=' + (
193 product_installer_install_command),
194 '-dProductInstallerDisableUpdateRegistrationArg=' + (
195 product_installer_disable_update_registration_arg),
196 '-dShowErrorCADll=' + env.File(show_error_action_dll_path).abspath,
197 '-dProductUninstallerAdditionalArgs=' + (
198 product_uninstaller_additional_args),
199 '-dMsiProductId=' + msi_product_id,
200 '-dMsiUpgradeCode=' + msi_upgradecode_guid,
201 ],
202 WIXLIGHTFLAGS=[
203 '-sw1076',
204 '-sice:ICE61',
205 ],
206 )
207
208 wix_output = wix_env.WiX(
209 target='unsigned_' + msi_name,
210 source=[copy_target, google_update_wixobj_output],
211 )
212
213 # Force a rebuild when the installer or metainstaller changes.
214 # The metainstaller change does not get passed through even though the .wixobj
215 # file is rebuilt because the hash of the .wixobj does not change.
216 # Also force a dependency on the CA DLL. Otherwise, it might not be built
217 # before the MSI.
218 wix_env.Depends(wix_output, [product_installer_path,
219 metainstaller_path,
220 show_error_action_dll_path])
221
222 sign_output = wix_env.SignedBinary(
223 target=msi_name,
224 source=wix_output,
225 )
226
227 env.Replicate(output_dir, sign_output)
228
229
230 def GenerateNameBasedGUID(namespace, name):
231 """Generate a GUID based on the names supplied.
232
233 Follows a methodology recommended in Section 4.3 of RFC 4122 to generate
234 a "name-based UUID," which basically means that you want to control the
235 inputs to the GUID so that you can generate the same valid GUID each time
236 given the same inputs.
237
238 Args:
239 namespace: First part of identifier used to generate GUID
240 name: Second part of identifier used to generate GUID
241
242 Returns:
243 String representation of the generated GUID.
244
245 Raises:
246 Nothing.
247 """
248
249 # Generate 128 unique bits.
250 mymd5 = md5.new()
251 mymd5.update(namespace + name)
252 md5_hash = mymd5.digest()
253
254 # Set various reserved bits to make this a valid GUID.
255
256 # "Set the four most significant bits (bits 12 through 15) of the
257 # time_hi_and_version field to the appropriate 4-bit version number
258 # from Section 4.1.3."
259 version = ord(md5_hash[6])
260 version = 0x30 | (version & 0x0f)
261
262 # "Set the two most significant bits (bits 6 and 7) of the
263 # clock_seq_hi_and_reserved to zero and one, respectively."
264 clock_seq_hi_and_reserved = ord(md5_hash[8])
265 clock_seq_hi_and_reserved = 0x80 | (clock_seq_hi_and_reserved & 0x3f)
266
267 return (
268 '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % (
269 ord(md5_hash[0]), ord(md5_hash[1]), ord(md5_hash[2]),
270 ord(md5_hash[3]),
271 ord(md5_hash[4]), ord(md5_hash[5]),
272 version, ord(md5_hash[7]),
273 clock_seq_hi_and_reserved, ord(md5_hash[9]),
274 ord(md5_hash[10]), ord(md5_hash[11]), ord(md5_hash[12]),
275 ord(md5_hash[13]), ord(md5_hash[14]), ord(md5_hash[15])))
276
277
278 def ConvertToMSIVersionNumberIfNeeded(product_version):
279 """Change product_version to fit in an MSI version number if needed.
280
281 Some products use a 4-field version numbering scheme whereas MSI looks only
282 at the first three fields when considering version numbers. Furthermore, MSI
283 version fields have documented width restrictions of 8bits.8bits.16bits as
284 per http://msdn.microsoft.com/en-us/library/aa370859(VS.85).aspx
285
286 As such, the following scheme is used:
287
288 Product a.b.c.d -> a.(c>>8).(((c & 0xFF) << 8) + d)
289
290 So eg. 6.1.420.8 would become 6.1.41992.
291
292 This assumes:
293 1) we don't care about the product minor number, e.g. we will never reset
294 the 'c' number after an increase in 'b'.
295 2) 'd' will always be <= 255
296 3) 'c' is <= 65535
297
298 As a final note, if product_version is not of the format a.b.c.d then
299 this function returns the original product_version value.
300 """
301
302 try:
303 version_field_strings = product_version.split('.')
304 (major, minor, build, patch) = [int(x) for x in version_field_strings]
305 except:
306 # Couldn't parse the version number as a 4-term period-separated number,
307 # just return the original string.
308 return product_version
309
310 # Input version number was out of range. Return the original string.
311 if patch > 255 or build > 65535:
312 return product_string
313
314 msi_major = major
315 msi_minor = build >> 8
316 msi_build = ((build & 0xff) << 8) + patch
317
318 return str(msi_major) + '.' + str(msi_minor) + '.' + str(msi_build)
319
320
321 def BuildEnterpriseInstaller(env,
322 product_name,
323 product_version,
324 product_guid,
325 product_custom_params,
326 product_installer_path,
327 product_installer_install_command,
328 product_installer_disable_update_registration_arg,
329 product_uninstaller_additional_args,
330 msi_base_name,
331 enterprise_installer_dir,
332 show_error_action_dll_path,
333 metainstaller_path,
334 output_dir='$STAGING_DIR'):
335 """Build an installer for use in enterprise situations.
336
337 Builds an MSI using the supplied details and binaries. This MSI is
338 intended to enable enterprise installation scenarios.
339
340 Args:
341 env: environment to build with
342 product_name: name of the product being built
343 product_version: product version to be installed
344 product_guid: product's Omaha application ID
345 product_custom_params: custom values to be appended to the Omaha tag
346 product_installer_path: path to specific product installer
347 product_installer_install_command: command line args used to run product
348 installer in 'install' mode
349 product_installer_disable_update_registration_arg: command line args used
350 to run product installer in 'do not register' mode
351 product_uninstaller_additional_args: extra command line parameters that the
352 custom action dll will pass on to the product uninstaller, typically
353 you'll want to pass any extra arguments that will force the uninstaller
354 to run silently here.
355 msi_base_name: root of name for the MSI
356 enterprise_installer_dir: path to dir which contains
357 enterprise_installer.wxs.xml
358 show_error_action_dll_path: path to the error display custom action dll that
359 exports a ShowInstallerResultUIString method. This CA method will read
360 the LastInstallerResultUIString from the product's ClientState key in
361 the registry and display the string via MsiProcessMessage.
362 metainstaller_path: path to the Omaha metainstaller to include
363 output_dir: path to the directory that will contain the resulting MSI
364
365 Returns:
366 Nothing.
367
368 Raises:
369 Nothing.
370 """
371 product_version = ConvertToMSIVersionNumberIfNeeded(product_version)
372
373 google_update_wixobj_output = BuildGoogleUpdateFragment(
374 env,
375 metainstaller_path,
376 product_name,
377 product_version,
378 product_guid,
379 product_custom_params,
380 msi_base_name,
381 enterprise_installer_dir + '/google_update_installer_fragment.wxs.xml')
382
383 _BuildMsiForExe(
384 env,
385 product_name,
386 product_version,
387 product_guid,
388 product_installer_path,
389 product_installer_install_command,
390 product_installer_disable_update_registration_arg,
391 product_uninstaller_additional_args,
392 msi_base_name,
393 google_update_wixobj_output,
394 enterprise_installer_dir,
395 show_error_action_dll_path,
396 metainstaller_path,
397 output_dir)
398
399
400 def BuildEnterpriseInstallerFromStandaloneInstaller(
401 env,
402 product_name,
403 product_version,
404 product_guid,
405 product_custom_params,
406 product_uninstaller_additional_args,
407 product_installer_data,
408 standalone_installer_path,
409 show_error_action_dll_path,
410 msi_base_name,
411 enterprise_installer_dir,
412 output_dir='$STAGING_DIR'):
413 """Build an installer for use in enterprise situations.
414
415 Builds an MSI around the supplied standalone installer. This MSI is
416 intended to enable enterprise installation scenarios while being as close
417 to a normal install as possible. It does not suffer from the separation of
418 Omaha and application install like the other methods do.
419
420 This method only works for installers that do not use an MSI.
421
422 Args:
423 env: environment to build with
424 product_name: name of the product being built
425 product_version: product version to be installed
426 product_guid: product's Omaha application ID
427 product_custom_params: custom values to be appended to the Omaha tag
428 product_uninstaller_additional_args: extra command line parameters that the
429 custom action dll will pass on to the product uninstaller, typically
430 you'll want to pass any extra arguments that will force the uninstaller
431 to run silently here.
432 product_installer_data: installer data to be passed to the
433 product installer at run time. This is useful as an alternative to
434 the product_installer_install_command parameter accepted by
435 BuildEnterpriseInstaller() since command line parameters can't be
436 passed to the product installer when it is wrapped in a standalone
437 installer.
438 standalone_installer_path: path to product's standalone installer
439 show_error_action_dll_path: path to the error display custom action dll that
440 exports a ShowInstallerResultUIString method. This CA method will read
441 the LastInstallerResultUIString from the product's ClientState key in
442 the registry and display the string via MsiProcessMessage.
443 msi_base_name: root of name for the MSI
444 enterprise_installer_dir: path to dir which contains
445 enterprise_standalone_installer.wxs.xml
446 output_dir: path to the directory that will contain the resulting MSI
447
448 Returns:
449 Target nodes.
450
451 Raises:
452 Nothing.
453 """
454 product_name_legal_identifier = product_name.replace(' ', '')
455 msi_name = msi_base_name + '.msi'
456 product_version = ConvertToMSIVersionNumberIfNeeded(product_version)
457
458 omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID)
459
460 # Include the .msi filename in the Product Code generation because "the
461 # product code must be changed if... the name of the .msi file has been
462 # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx.
463 msi_product_id = GenerateNameBasedGUID(
464 omaha_installer_namespace,
465 'Product %s %s' % (product_name, msi_base_name)
466 )
467 msi_upgradecode_guid = GenerateNameBasedGUID(
468 omaha_installer_namespace,
469 'Upgrade ' + product_name
470 )
471
472 # To allow for multiple versions of the same product to be generated,
473 # stick output in a subdirectory.
474 output_directory_name = product_guid + '.' + product_version
475
476 copy_target = env.Command(
477 target=output_directory_name + msi_base_name + '.wxs',
478 source=(enterprise_installer_dir +
479 '/enterprise_standalone_installer.wxs.xml'),
480 action='@copy /y $SOURCE $TARGET',
481 )
482
483 wix_env = env.Clone()
484 wix_candle_flags = [
485 '-dProductName=' + product_name,
486 '-dProductNameLegalIdentifier=' + product_name_legal_identifier,
487 '-dProductVersion=' + product_version,
488 '-dProductGuid="%s"' % product_guid,
489 '-dProductCustomParams="%s"' % product_custom_params,
490 '-dStandaloneInstallerPath=' + (
491 env.File(standalone_installer_path).abspath),
492 '-dShowErrorCADll=' + env.File(show_error_action_dll_path).abspath,
493 '-dProductUninstallerAdditionalArgs=' + (
494 product_uninstaller_additional_args),
495 '-dMsiProductId=' + msi_product_id,
496 '-dMsiUpgradeCode=' + msi_upgradecode_guid,
497 ]
498
499 if product_installer_data:
500 wix_candle_flags.append('-dProductInstallerData=' + product_installer_data)
501
502 wix_light_flags = [
503 '-sw1076',
504 '-sice:ICE61',
505 ]
506
507 wix_env.Append(
508 WIXCANDLEFLAGS=wix_candle_flags,
509 WIXLIGHTFLAGS=wix_light_flags
510 )
511
512 wix_output = wix_env.WiX(
513 target = output_directory_name + '/' + 'unsigned_' + msi_name,
514 source = [copy_target],
515 )
516
517 # Force a rebuild when the standalone installer changes.
518 # The metainstaller change does not get passed through even though the .wixobj
519 # file is rebuilt because the hash of the .wixobj does not change.
520 # Also force a dependency on the CA DLL. Otherwise, it might not be built
521 # before the MSI.
522 wix_env.Depends(wix_output, [standalone_installer_path,
523 show_error_action_dll_path])
524
525 sign_output = wix_env.SignedBinary(
526 target=output_directory_name + '/' + msi_name,
527 source=wix_output,
528 )
529
530 return env.Replicate(output_dir + '/' + output_directory_name, sign_output)
OLDNEW
« no previous file with comments | « enterprise/installer/build.scons ('k') | enterprise/installer/custom_actions/build.scons » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698