Index: enterprise/installer/build_enterprise_installer.py |
diff --git a/enterprise/installer/build_enterprise_installer.py b/enterprise/installer/build_enterprise_installer.py |
deleted file mode 100644 |
index d09d47d6a6fdb84a6802de58b55586a0182eb40d..0000000000000000000000000000000000000000 |
--- a/enterprise/installer/build_enterprise_installer.py |
+++ /dev/null |
@@ -1,530 +0,0 @@ |
-#!/usr/bin/python2.4 |
-# |
-# Copyright 2009-2010 Google Inc. |
-# |
-# Licensed under the Apache License, Version 2.0 (the "License"); |
-# you may not use this file except in compliance with the License. |
-# You may obtain a copy of the License at |
-# |
-# http://www.apache.org/licenses/LICENSE-2.0 |
-# |
-# Unless required by applicable law or agreed to in writing, software |
-# distributed under the License is distributed on an "AS IS" BASIS, |
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
-# See the License for the specific language governing permissions and |
-# limitations under the License. |
-# ======================================================================== |
- |
-"""Build an installer for use in enterprise situations. |
- |
- This module contains the functionality required to build enterprise |
- installers (MSIs) for Omaha's various customers. |
- |
- The supplied wxs templates need to have an XML extension because SCons |
- tries to apply WiX building rules to any input file with the .wxs suffix. |
- |
- BuildGoogleUpdateFragment(): Build an update fragment into a .wixobj. |
- GenerateNameBasedGUID(): Generate a GUID based on the names supplied. |
- BuildEnterpriseInstaller(): Build an MSI installer for use in enterprises. |
-""" |
- |
-import binascii |
-import md5 |
- |
-_GOOGLE_UPDATE_NAMESPACE_GUID = 'BE19B3E4502845af8B3E67A99FCDCFB1' |
- |
- |
-def BuildGoogleUpdateFragment(env, |
- metainstaller_path, |
- product_name, |
- product_version, |
- product_guid, |
- product_custom_params, |
- wixobj_base_name, |
- google_update_wxs_template_path): |
- """Build an update fragment into a WiX object. |
- |
- Takes a supplied wix fragment, and turns it into a .wixobj object for later |
- inclusion into an MSI. |
- |
- Args: |
- env: environment to build with |
- metainstaller_path: path to the Omaha metainstaller to include |
- product_name: name of the product the fragment is being built for |
- product_version: product version to be installed |
- product_guid: Omaha application ID of the product the fragment is being |
- built for |
- product_custom_params: custom values to be appended to the Omaha tag |
- wixobj_base_name: root of name for the wixobj |
- google_update_wxs_template_path: path to the fragment source |
- |
- Returns: |
- Output object for the built wixobj. |
- |
- Raises: |
- Nothing. |
- """ |
- |
- product_name_legal_identifier = product_name.replace(' ', '') |
- |
- intermediate_base_name = wixobj_base_name + '_google_update_fragment' |
- |
- copy_target = env.Command( |
- target=intermediate_base_name + '.wxs', |
- source=google_update_wxs_template_path, |
- action='@copy /y $SOURCE $TARGET', |
- ) |
- |
- wix_defines = [ |
- '-dProductName="%s"' % product_name, |
- '-dProductNameLegalIdentifier="%s"' % product_name_legal_identifier, |
- '-dProductVersion=' + product_version, |
- '-dProductGuid="%s"' % product_guid, |
- '-dProductCustomParams="%s"' % product_custom_params, |
- '-dGoogleUpdateMetainstallerPath="%s"' % ( |
- env.File(metainstaller_path).abspath), |
- ] |
- |
- wixobj_output = env.Command( |
- target=intermediate_base_name + '.wixobj', |
- source=copy_target, |
- action='@candle.exe -nologo -out $TARGET $SOURCE ' + ' '.join(wix_defines) |
- ) |
- |
- # Force a rebuild of the .wixobj file when the metainstaller changes. |
- # Does not necessarily force rebuild of the MSI because hash does not change. |
- env.Depends(wixobj_output, metainstaller_path) |
- |
- return wixobj_output |
- |
- |
-def _BuildMsiForExe(env, |
- product_name, |
- product_version, |
- product_guid, |
- product_installer_path, |
- product_installer_install_command, |
- product_installer_disable_update_registration_arg, |
- product_uninstaller_additional_args, |
- msi_base_name, |
- google_update_wixobj_output, |
- enterprise_installer_dir, |
- show_error_action_dll_path, |
- metainstaller_path, |
- output_dir): |
- """Build an MSI installer for use in enterprise situations. |
- |
- Builds an MSI for the executable installer at product_installer_path using |
- the supplied details. Requires an existing Google Update installer fragment |
- as well as a path to a custom action DLL containing the logic to launch the |
- product's uninstaller. |
- |
- This is intended to enable enterprise installation scenarios. |
- |
- Args: |
- env: environment to build with |
- product_name: name of the product being built |
- product_version: product version to be installed |
- product_guid: product's Omaha application ID |
- product_installer_path: path to specific product installer |
- product_installer_install_command: command line args used to run product |
- installer in 'install' mode |
- product_installer_disable_update_registration_arg: command line args used |
- to run product installer in 'do not register' mode |
- product_uninstaller_additional_args: extra command line parameters that the |
- custom action dll will pass on to the product uninstaller, typically |
- you'll want to pass any extra arguments that will force the uninstaller |
- to run silently here. |
- msi_base_name: root of name for the MSI |
- google_update_wixobj_output: the MSI fragment containing the Omaha |
- installer. |
- enterprise_installer_dir: path to dir which contains |
- enterprise_installer.wxs.xml |
- show_error_action_dll_path: path to the error display custom action dll that |
- exports a ShowInstallerResultUIString method. This CA method will read |
- the LastInstallerResultUIString from the product's ClientState key in |
- the registry and display the string via MsiProcessMessage. |
- metainstaller_path: path to the Omaha metainstaller. Should be same file |
- used for google_update_wixobj_output. Used only to force rebuilds. |
- output_dir: path to the directory that will contain the resulting MSI |
- |
- Returns: |
- Nothing. |
- |
- Raises: |
- Nothing. |
- """ |
- |
- product_name_legal_identifier = product_name.replace(' ', '') |
- msi_name = msi_base_name + '.msi' |
- |
- omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID) |
- |
- # Include the .msi filename in the Product Code generation because "the |
- # product code must be changed if... the name of the .msi file has been |
- # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx. |
- msi_product_id = GenerateNameBasedGUID( |
- omaha_installer_namespace, |
- 'Product %s %s' % (product_name, msi_base_name) |
- ) |
- msi_upgradecode_guid = GenerateNameBasedGUID( |
- omaha_installer_namespace, |
- 'Upgrade ' + product_name |
- ) |
- |
- copy_target = env.Command( |
- target=msi_base_name + '.wxs', |
- source=enterprise_installer_dir + '/enterprise_installer.wxs.xml', |
- action='@copy /y $SOURCE $TARGET', |
- ) |
- |
- # Disable warning LGHT1076 and internal check ICE61 on light.exe. Details: |
- # 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 |
- # http://windows-installer-xml-wix-toolset.687559.n2.nabble.com/ICE61-Upgrade-VersionMax-format-is-wrong-td4396813.html # pylint: disable-msg=C6310 |
- wix_env = env.Clone() |
- wix_env.Append( |
- WIXCANDLEFLAGS=[ |
- '-dProductName=' + product_name, |
- '-dProductNameLegalIdentifier=' + product_name_legal_identifier, |
- '-dProductVersion=' + product_version, |
- '-dProductGuid=' + product_guid, |
- '-dProductInstallerPath=' + env.File(product_installer_path).abspath, |
- '-dProductInstallerInstallCommand=' + ( |
- product_installer_install_command), |
- '-dProductInstallerDisableUpdateRegistrationArg=' + ( |
- product_installer_disable_update_registration_arg), |
- '-dShowErrorCADll=' + env.File(show_error_action_dll_path).abspath, |
- '-dProductUninstallerAdditionalArgs=' + ( |
- product_uninstaller_additional_args), |
- '-dMsiProductId=' + msi_product_id, |
- '-dMsiUpgradeCode=' + msi_upgradecode_guid, |
- ], |
- WIXLIGHTFLAGS=[ |
- '-sw1076', |
- '-sice:ICE61', |
- ], |
- ) |
- |
- wix_output = wix_env.WiX( |
- target='unsigned_' + msi_name, |
- source=[copy_target, google_update_wixobj_output], |
- ) |
- |
- # Force a rebuild when the installer or metainstaller changes. |
- # The metainstaller change does not get passed through even though the .wixobj |
- # file is rebuilt because the hash of the .wixobj does not change. |
- # Also force a dependency on the CA DLL. Otherwise, it might not be built |
- # before the MSI. |
- wix_env.Depends(wix_output, [product_installer_path, |
- metainstaller_path, |
- show_error_action_dll_path]) |
- |
- sign_output = wix_env.SignedBinary( |
- target=msi_name, |
- source=wix_output, |
- ) |
- |
- env.Replicate(output_dir, sign_output) |
- |
- |
-def GenerateNameBasedGUID(namespace, name): |
- """Generate a GUID based on the names supplied. |
- |
- Follows a methodology recommended in Section 4.3 of RFC 4122 to generate |
- a "name-based UUID," which basically means that you want to control the |
- inputs to the GUID so that you can generate the same valid GUID each time |
- given the same inputs. |
- |
- Args: |
- namespace: First part of identifier used to generate GUID |
- name: Second part of identifier used to generate GUID |
- |
- Returns: |
- String representation of the generated GUID. |
- |
- Raises: |
- Nothing. |
- """ |
- |
- # Generate 128 unique bits. |
- mymd5 = md5.new() |
- mymd5.update(namespace + name) |
- md5_hash = mymd5.digest() |
- |
- # Set various reserved bits to make this a valid GUID. |
- |
- # "Set the four most significant bits (bits 12 through 15) of the |
- # time_hi_and_version field to the appropriate 4-bit version number |
- # from Section 4.1.3." |
- version = ord(md5_hash[6]) |
- version = 0x30 | (version & 0x0f) |
- |
- # "Set the two most significant bits (bits 6 and 7) of the |
- # clock_seq_hi_and_reserved to zero and one, respectively." |
- clock_seq_hi_and_reserved = ord(md5_hash[8]) |
- clock_seq_hi_and_reserved = 0x80 | (clock_seq_hi_and_reserved & 0x3f) |
- |
- return ( |
- '%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x' % ( |
- ord(md5_hash[0]), ord(md5_hash[1]), ord(md5_hash[2]), |
- ord(md5_hash[3]), |
- ord(md5_hash[4]), ord(md5_hash[5]), |
- version, ord(md5_hash[7]), |
- clock_seq_hi_and_reserved, ord(md5_hash[9]), |
- ord(md5_hash[10]), ord(md5_hash[11]), ord(md5_hash[12]), |
- ord(md5_hash[13]), ord(md5_hash[14]), ord(md5_hash[15]))) |
- |
- |
-def ConvertToMSIVersionNumberIfNeeded(product_version): |
- """Change product_version to fit in an MSI version number if needed. |
- |
- Some products use a 4-field version numbering scheme whereas MSI looks only |
- at the first three fields when considering version numbers. Furthermore, MSI |
- version fields have documented width restrictions of 8bits.8bits.16bits as |
- per http://msdn.microsoft.com/en-us/library/aa370859(VS.85).aspx |
- |
- As such, the following scheme is used: |
- |
- Product a.b.c.d -> a.(c>>8).(((c & 0xFF) << 8) + d) |
- |
- So eg. 6.1.420.8 would become 6.1.41992. |
- |
- This assumes: |
- 1) we don't care about the product minor number, e.g. we will never reset |
- the 'c' number after an increase in 'b'. |
- 2) 'd' will always be <= 255 |
- 3) 'c' is <= 65535 |
- |
- As a final note, if product_version is not of the format a.b.c.d then |
- this function returns the original product_version value. |
- """ |
- |
- try: |
- version_field_strings = product_version.split('.') |
- (major, minor, build, patch) = [int(x) for x in version_field_strings] |
- except: |
- # Couldn't parse the version number as a 4-term period-separated number, |
- # just return the original string. |
- return product_version |
- |
- # Input version number was out of range. Return the original string. |
- if patch > 255 or build > 65535: |
- return product_string |
- |
- msi_major = major |
- msi_minor = build >> 8 |
- msi_build = ((build & 0xff) << 8) + patch |
- |
- return str(msi_major) + '.' + str(msi_minor) + '.' + str(msi_build) |
- |
- |
-def BuildEnterpriseInstaller(env, |
- product_name, |
- product_version, |
- product_guid, |
- product_custom_params, |
- product_installer_path, |
- product_installer_install_command, |
- product_installer_disable_update_registration_arg, |
- product_uninstaller_additional_args, |
- msi_base_name, |
- enterprise_installer_dir, |
- show_error_action_dll_path, |
- metainstaller_path, |
- output_dir='$STAGING_DIR'): |
- """Build an installer for use in enterprise situations. |
- |
- Builds an MSI using the supplied details and binaries. This MSI is |
- intended to enable enterprise installation scenarios. |
- |
- Args: |
- env: environment to build with |
- product_name: name of the product being built |
- product_version: product version to be installed |
- product_guid: product's Omaha application ID |
- product_custom_params: custom values to be appended to the Omaha tag |
- product_installer_path: path to specific product installer |
- product_installer_install_command: command line args used to run product |
- installer in 'install' mode |
- product_installer_disable_update_registration_arg: command line args used |
- to run product installer in 'do not register' mode |
- product_uninstaller_additional_args: extra command line parameters that the |
- custom action dll will pass on to the product uninstaller, typically |
- you'll want to pass any extra arguments that will force the uninstaller |
- to run silently here. |
- msi_base_name: root of name for the MSI |
- enterprise_installer_dir: path to dir which contains |
- enterprise_installer.wxs.xml |
- show_error_action_dll_path: path to the error display custom action dll that |
- exports a ShowInstallerResultUIString method. This CA method will read |
- the LastInstallerResultUIString from the product's ClientState key in |
- the registry and display the string via MsiProcessMessage. |
- metainstaller_path: path to the Omaha metainstaller to include |
- output_dir: path to the directory that will contain the resulting MSI |
- |
- Returns: |
- Nothing. |
- |
- Raises: |
- Nothing. |
- """ |
- product_version = ConvertToMSIVersionNumberIfNeeded(product_version) |
- |
- google_update_wixobj_output = BuildGoogleUpdateFragment( |
- env, |
- metainstaller_path, |
- product_name, |
- product_version, |
- product_guid, |
- product_custom_params, |
- msi_base_name, |
- enterprise_installer_dir + '/google_update_installer_fragment.wxs.xml') |
- |
- _BuildMsiForExe( |
- env, |
- product_name, |
- product_version, |
- product_guid, |
- product_installer_path, |
- product_installer_install_command, |
- product_installer_disable_update_registration_arg, |
- product_uninstaller_additional_args, |
- msi_base_name, |
- google_update_wixobj_output, |
- enterprise_installer_dir, |
- show_error_action_dll_path, |
- metainstaller_path, |
- output_dir) |
- |
- |
-def BuildEnterpriseInstallerFromStandaloneInstaller( |
- env, |
- product_name, |
- product_version, |
- product_guid, |
- product_custom_params, |
- product_uninstaller_additional_args, |
- product_installer_data, |
- standalone_installer_path, |
- show_error_action_dll_path, |
- msi_base_name, |
- enterprise_installer_dir, |
- output_dir='$STAGING_DIR'): |
- """Build an installer for use in enterprise situations. |
- |
- Builds an MSI around the supplied standalone installer. This MSI is |
- intended to enable enterprise installation scenarios while being as close |
- to a normal install as possible. It does not suffer from the separation of |
- Omaha and application install like the other methods do. |
- |
- This method only works for installers that do not use an MSI. |
- |
- Args: |
- env: environment to build with |
- product_name: name of the product being built |
- product_version: product version to be installed |
- product_guid: product's Omaha application ID |
- product_custom_params: custom values to be appended to the Omaha tag |
- product_uninstaller_additional_args: extra command line parameters that the |
- custom action dll will pass on to the product uninstaller, typically |
- you'll want to pass any extra arguments that will force the uninstaller |
- to run silently here. |
- product_installer_data: installer data to be passed to the |
- product installer at run time. This is useful as an alternative to |
- the product_installer_install_command parameter accepted by |
- BuildEnterpriseInstaller() since command line parameters can't be |
- passed to the product installer when it is wrapped in a standalone |
- installer. |
- standalone_installer_path: path to product's standalone installer |
- show_error_action_dll_path: path to the error display custom action dll that |
- exports a ShowInstallerResultUIString method. This CA method will read |
- the LastInstallerResultUIString from the product's ClientState key in |
- the registry and display the string via MsiProcessMessage. |
- msi_base_name: root of name for the MSI |
- enterprise_installer_dir: path to dir which contains |
- enterprise_standalone_installer.wxs.xml |
- output_dir: path to the directory that will contain the resulting MSI |
- |
- Returns: |
- Target nodes. |
- |
- Raises: |
- Nothing. |
- """ |
- product_name_legal_identifier = product_name.replace(' ', '') |
- msi_name = msi_base_name + '.msi' |
- product_version = ConvertToMSIVersionNumberIfNeeded(product_version) |
- |
- omaha_installer_namespace = binascii.a2b_hex(_GOOGLE_UPDATE_NAMESPACE_GUID) |
- |
- # Include the .msi filename in the Product Code generation because "the |
- # product code must be changed if... the name of the .msi file has been |
- # changed" according to http://msdn.microsoft.com/en-us/library/aa367850.aspx. |
- msi_product_id = GenerateNameBasedGUID( |
- omaha_installer_namespace, |
- 'Product %s %s' % (product_name, msi_base_name) |
- ) |
- msi_upgradecode_guid = GenerateNameBasedGUID( |
- omaha_installer_namespace, |
- 'Upgrade ' + product_name |
- ) |
- |
- # To allow for multiple versions of the same product to be generated, |
- # stick output in a subdirectory. |
- output_directory_name = product_guid + '.' + product_version |
- |
- copy_target = env.Command( |
- target=output_directory_name + msi_base_name + '.wxs', |
- source=(enterprise_installer_dir + |
- '/enterprise_standalone_installer.wxs.xml'), |
- action='@copy /y $SOURCE $TARGET', |
- ) |
- |
- wix_env = env.Clone() |
- wix_candle_flags = [ |
- '-dProductName=' + product_name, |
- '-dProductNameLegalIdentifier=' + product_name_legal_identifier, |
- '-dProductVersion=' + product_version, |
- '-dProductGuid="%s"' % product_guid, |
- '-dProductCustomParams="%s"' % product_custom_params, |
- '-dStandaloneInstallerPath=' + ( |
- env.File(standalone_installer_path).abspath), |
- '-dShowErrorCADll=' + env.File(show_error_action_dll_path).abspath, |
- '-dProductUninstallerAdditionalArgs=' + ( |
- product_uninstaller_additional_args), |
- '-dMsiProductId=' + msi_product_id, |
- '-dMsiUpgradeCode=' + msi_upgradecode_guid, |
- ] |
- |
- if product_installer_data: |
- wix_candle_flags.append('-dProductInstallerData=' + product_installer_data) |
- |
- wix_light_flags = [ |
- '-sw1076', |
- '-sice:ICE61', |
- ] |
- |
- wix_env.Append( |
- WIXCANDLEFLAGS=wix_candle_flags, |
- WIXLIGHTFLAGS=wix_light_flags |
- ) |
- |
- wix_output = wix_env.WiX( |
- target = output_directory_name + '/' + 'unsigned_' + msi_name, |
- source = [copy_target], |
- ) |
- |
- # Force a rebuild when the standalone installer changes. |
- # The metainstaller change does not get passed through even though the .wixobj |
- # file is rebuilt because the hash of the .wixobj does not change. |
- # Also force a dependency on the CA DLL. Otherwise, it might not be built |
- # before the MSI. |
- wix_env.Depends(wix_output, [standalone_installer_path, |
- show_error_action_dll_path]) |
- |
- sign_output = wix_env.SignedBinary( |
- target=output_directory_name + '/' + msi_name, |
- source=wix_output, |
- ) |
- |
- return env.Replicate(output_dir + '/' + output_directory_name, sign_output) |