Index: standalone/standalone_installer.py |
diff --git a/standalone/standalone_installer.py b/standalone/standalone_installer.py |
deleted file mode 100644 |
index 2800ae68d6a96c3f87b290738e0395dd4cbf0f44..0000000000000000000000000000000000000000 |
--- a/standalone/standalone_installer.py |
+++ /dev/null |
@@ -1,442 +0,0 @@ |
-#!/usr/bin/python2.4 |
-# Copyright 2009 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. |
-# ======================================================================== |
- |
-"""Builds standalone installers and MSI wrappers around them. |
- |
-This is very close to the logic within installers\build.scons. The difference |
-is that we have an additional file standalone_installers.txt. This file |
-contains a list of standalone installers to create along with necessary values. |
-For each entry in standalone_installers.txt, we create a corresponding |
-standalone installer, which is the meta-installer, app installer binaries, and |
-update response tarred together. |
-MSI installers that wrap the standalone installer may also be created. |
-""" |
- |
-import array |
-import base64 |
-import codecs |
-import os |
-import sha |
- |
-from enterprise.installer import build_enterprise_installer |
-from installers import build_metainstaller |
-from installers import tag_meta_installers |
-from installers import tagged_installer |
- |
- |
-class OfflineInstaller(object): |
- """Represents the information for a bundle.""" |
- |
- def __init__(self, |
- friendly_product_name, |
- exe_base_name, |
- binaries, |
- msi_base_name, |
- custom_tag_params, |
- silent_uninstall_args, |
- should_build_enterprise_msi, |
- msi_installer_data, |
- installers_txt_filename): |
- self.friendly_product_name = friendly_product_name |
- self.exe_base_name = exe_base_name |
- self.binaries = binaries |
- self.msi_base_name = msi_base_name |
- self.custom_tag_params = custom_tag_params |
- self.silent_uninstall_args = silent_uninstall_args |
- self.should_build_enterprise_msi = should_build_enterprise_msi |
- self.msi_installer_data = msi_installer_data |
- self.installers_txt_filename = installers_txt_filename |
- |
- |
-def ReadOfflineInstallersFile(env, offline_installers_file_path): |
- """Enumerates the entries in the offline installers file. |
- |
- Args: |
- env: Environment. |
- offline_installers_file_path: Path to file specifying installers to build. |
- |
- Returns: |
- Returns a list of structures used for creating the prestamped binaries. |
- """ |
- |
- offline_installers = [] |
- offline_abs_path = env.File(offline_installers_file_path).abspath |
- installer_file = codecs.open(offline_abs_path, 'r') |
- for line in installer_file: |
- line = line.strip() |
- if len(line) and not line.startswith('#'): |
- (friendly_product_name, |
- exe_base_name, |
- binaries, |
- msi_base_name, |
- custom_tag_params, |
- silent_uninstall_args, |
- should_build_enterprise_msi, |
- msi_installer_data, |
- installers_txt_filename) = eval(line) |
- installer = OfflineInstaller(friendly_product_name, |
- exe_base_name, |
- binaries, |
- msi_base_name, |
- custom_tag_params, |
- silent_uninstall_args, |
- should_build_enterprise_msi, |
- msi_installer_data, |
- installers_txt_filename) |
- offline_installers.append(installer) |
- return offline_installers |
- |
- |
-def BuildOfflineInstallersVersion(env, |
- omaha_version_info, |
- omaha_files_path, |
- empty_metainstaller_path, |
- offline_installers_file_path, |
- manifest_files_path, |
- prefix='', |
- is_official=False): |
- """Builds all standalone installers specified in offline_installers_file_path. |
- |
- Args: |
- env: Environment. |
- omaha_version_info: info about the version of the Omaha files |
- omaha_files_path: Path to the directory containing the Omaha binaries. |
- empty_metainstaller_path: Path to empty (no tarball) metainstaller binary. |
- offline_installers_file_path: Path to file specifying installers to build. |
- manifest_files_path: Path to the directory containing the manifests for the |
- apps specified in offline_installers_file_path. |
- prefix: Optional prefix for the resulting installer. |
- is_official: Whether to build official (vs. test) standalone installers. |
- """ |
- |
- offline_installers = ReadOfflineInstallersFile(env, |
- offline_installers_file_path) |
- |
- for offline_installer in offline_installers: |
- BuildOfflineInstaller( |
- env, |
- offline_installer, |
- omaha_version_info, |
- omaha_files_path, |
- empty_metainstaller_path, |
- offline_installers_file_path, |
- manifest_files_path, |
- prefix, |
- is_official |
- ) |
- |
- |
-def _GenerateUpdateResponseFile(target, source, env): |
- """Generate GUP file based on a list of sources. |
- |
- Don't call function directly from this script. source may be |
- generated as part of build. Use function as action in env.Command. |
- |
- Args: |
- target: Target GUP file name. |
- source: A list of source files. Source files should be listed as manifest1, |
- binary1, manifest2, binary2 and so on. Order is important so that |
- manifests and installers can be differentiated and 'INSTALLER_VERSIONS' |
- can be applied properly. |
- env: Construct environment. This environment must contain environment |
- variable 'INSTALLER_VERSIONS', which contains a list of versions for |
- corresponding binaries in source and should be in same order. |
- |
- Raises: |
- Exception: When build encounters error. |
- """ |
- xml_header = '<?xml version="1.0" encoding="UTF-8"?>\n' |
- response_header = '<response protocol="3.0">' |
- response_footer = '</response>' |
- |
- local_env = env.Clone() |
- |
- version_list = local_env['INSTALLER_VERSIONS'] |
- if not version_list: |
- raise Exception('INSTALLER_VERSIONS is missing from environment.') |
- |
- manifest_content_list = [xml_header, response_header] |
- for file_index in xrange(0, len(source), 2): |
- source_manifest_path = source[file_index] |
- binary_path = source[file_index + 1] |
- size = os.stat(binary_path.abspath).st_size |
- installer_file = open(binary_path.abspath, mode='rb') |
- data = array.array('B') |
- data.fromfile(installer_file, size) |
- installer_file.close() |
- s = sha.new(data) |
- hash_value = base64.b64encode(s.digest()) |
- |
- manifest_file = open(source_manifest_path.abspath) |
- manifest_content = manifest_file.read() |
- response_body_start_index = manifest_content.find('<response') |
- if response_body_start_index < 0: |
- raise Exception('GUP file does not contain response element.') |
- # + 1 to include the closing > in header |
- response_body_start_index = manifest_content.find( |
- '>', response_body_start_index) |
- if response_body_start_index < 0: |
- raise Exception('GUP file does not contain response element.') |
- response_body_start_index += 1 |
- response_body_end_index = manifest_content.find( |
- '</response>', response_body_start_index) |
- if response_body_end_index < 0: |
- raise Exception('GUP file is not in valid response format.') |
- local_env['INSTALLER_SIZE'] = str(size) |
- local_env['INSTALLER_HASH'] = hash_value |
- local_env['INSTALLER_VERSION'] = version_list[file_index/2] |
- manifest_content_list.append(local_env.subst( |
- manifest_content[response_body_start_index:response_body_end_index], |
- raw=1)) |
- manifest_file.close() |
- manifest_content_list.append(response_footer) |
- |
- manifest_content_str = ''.join(manifest_content_list) |
- output_file = open(target[0].abspath, 'w') |
- output_file.write(manifest_content_str) |
- output_file.close() |
- |
- |
-def BuildOfflineInstaller( |
- env, |
- offline_installer, |
- omaha_version_info, |
- omaha_files_path, |
- empty_metainstaller_path, |
- offline_installers_file_path, |
- manifest_files_path, |
- prefix='', |
- is_official=False, |
- installers_sources_path='$MAIN_DIR/installers', |
- enterprise_installers_sources_path='$MAIN_DIR/enterprise/installer', |
- lzma_path='$MAIN_DIR/third_party/lzma/v4_65/files/lzma.exe', |
- resmerge_path='$MAIN_DIR/tools/resmerge'): |
- """Builds the standalone installers specified by offline_installer. |
- |
- Args: |
- env: Environment. |
- offline_installer: OfflineInstaller containing the information about the |
- standalone installer to build. |
- omaha_version_info: info about the version of the Omaha files |
- omaha_files_path: Path to the directory containing the Omaha binaries. |
- empty_metainstaller_path: Path to empty (no tarball) metainstaller binary. |
- offline_installers_file_path: Path to file specifying installers to build. |
- manifest_files_path: Path to the directory containing the manifests for the |
- apps specified in offline_installers_file_path. |
- prefix: Optional prefix for the resulting installer. |
- is_official: Whether to build official (vs. test) standalone installers. |
- installers_sources_path: path to the directory containing the source files |
- for building the metainstaller |
- enterprise_installers_sources_path: path to the directory containing the |
- source files for building enterprise installers |
- lzma_path: path to lzma.exe |
- resmerge_path: path to resmerge.exe |
- |
- Returns: |
- Target nodes. |
- |
- Raises: |
- Exception: Missing or invalid data specified in offline_installer. |
- """ |
- standalone_installer_base_name = offline_installer.exe_base_name |
- if not standalone_installer_base_name: |
- raise Exception('Product name not specified.') |
- |
- output_dir = '$STAGING_DIR' |
- if not is_official: |
- standalone_installer_base_name = ('UNOFFICIAL_' + |
- standalone_installer_base_name) |
- output_dir = '$TARGET_ROOT/Test_Installers' |
- |
- target_base = prefix + standalone_installer_base_name |
- target_name = target_base + '.exe' |
- log_name = target_base + '_Contents.txt' |
- |
- # Write Omaha's version. |
- log_text = '*** Omaha Version ***\n\n' |
- log_text += omaha_version_info.GetVersionString() + '\n' |
- |
- # Rename the checked in binaries by adding the application guid as the |
- # extension. This is needed as the meta-installer expects the |
- # extension. |
- # Also, log information about each app. |
- additional_payload_contents = [] |
- if not offline_installer.binaries: |
- raise Exception('No binaries specified.') |
- |
- manifest_target = '' |
- manifest_source = [] |
- version_list = [] |
- for binary in offline_installer.binaries: |
- (version, installer_path, guid) = binary |
- if not installer_path or not guid or not version: |
- raise Exception('Application specification is incomplete.') |
- |
- installer_path_modified = os.path.basename(installer_path) + '.' + guid |
- # Have to use Command('copy') here instead of replicate, as the |
- # file is being renamed in the process. |
- env.Command( |
- target=installer_path_modified, |
- source=installer_path, |
- action='@copy /y $SOURCES $TARGET' |
- ) |
- |
- manifest_source.extend([ |
- manifest_files_path + '/' + guid + '.gup', installer_path_modified]) |
- version_list.append(version) |
- additional_payload_contents.append(installer_path_modified) |
- |
- # TODO(omaha): Use full guid and version to generate unique string, use |
- # hash of the unique string as target directory name. |
- manifest_target += guid[0:4] + version |
- |
- # Log info about the app. |
- log_text += '\n\n*** App: ' + guid + ' ***\n' |
- log_text += '\nVersion:' + version + '\n' |
- log_text += '\nINSTALLER:\n' + installer_path + '\n' |
- |
- # Place the generated manifests in a subdirectory. This allows a single |
- # build to generate installers for multiple versions of the same app. |
- manifest_target += '/OfflineManifest.gup' |
- manifest_file_path = env.Command( |
- target=manifest_target, |
- source=manifest_source, |
- action=[_GenerateUpdateResponseFile], |
- INSTALLER_VERSIONS=version_list |
- ) |
- |
- # Use the BCJ2 tool from the official build we're using to generate this |
- # metainstaller, not the current build directory. |
- bcj2_path = omaha_files_path + '/bcj2.exe' |
- |
- additional_payload_contents.append(manifest_file_path) |
- |
- def WriteLog(target, source, env): |
- """Writes the log of what is being built.""" |
- dump_data = '' |
- for f in source: |
- file_to_dump = open(env.File(f).abspath, 'r', -1) |
- content = file_to_dump.read() |
- file_to_dump.close() |
- dump_data += '\nMANIFEST:\n' |
- dump_data += str(f) |
- dump_data += '\n' |
- dump_data += content |
- source = source # Avoid PyLint warning. |
- f = open(env.File(target[0]).abspath, 'w') |
- f.write(env['write_data']) |
- f.write(dump_data) |
- f.close() |
- return 0 |
- |
- env.Command( |
- target='%s/%s' % (output_dir, log_name), |
- source=manifest_file_path, |
- action=WriteLog, |
- write_data=log_text |
- ) |
- |
- results = [] |
- results += build_metainstaller.BuildMetaInstaller( |
- env=env, |
- target_name=target_name, |
- omaha_version_info=omaha_version_info, |
- empty_metainstaller_path=empty_metainstaller_path, |
- omaha_files_path=omaha_files_path, |
- prefix=prefix, |
- suffix='_' + standalone_installer_base_name, |
- additional_payload_contents=additional_payload_contents, |
- additional_payload_contents_dependencies=offline_installers_file_path, |
- output_dir=output_dir, |
- installers_sources_path=installers_sources_path, |
- lzma_path=lzma_path, |
- resmerge_path=resmerge_path, |
- bcj2_path=bcj2_path |
- ) |
- |
- standalone_installer_path = '%s/%s' % (output_dir, target_name) |
- |
- # Build an enterprise installer. |
- if offline_installer.should_build_enterprise_msi: |
- # TODO(omaha): Add support for bundles here and to |
- # BuildEnterpriseInstallerFromStandaloneInstaller(). |
- # TODO(omaha): Determine how product_version should be decided for MSI in |
- # bundle scenarios. |
- # TODO(omaha): custom tag, silent uninstall args, distribution data may need |
- # to be made per-app. |
- if 1 < len(offline_installer.binaries): |
- raise Exception('Enterprise installers do not currently support bundles.') |
- (product_version, installer_path, product_guid) = offline_installer.binaries[0] |
- |
- # Note: msi_base_name should not include version info and cannot change! |
- friendly_product_name = offline_installer.friendly_product_name |
- msi_base_name = offline_installer.msi_base_name |
- custom_tag_params = offline_installer.custom_tag_params |
- silent_uninstall_args = offline_installer.silent_uninstall_args |
- msi_installer_data = offline_installer.msi_installer_data |
- |
- # custom_tag_params and msi_installer_data are optional. |
- if (not product_version or not friendly_product_name or not msi_base_name or |
- not silent_uninstall_args): |
- raise Exception('Field required to build enterprise MSI is missing.') |
- |
- if not is_official: |
- msi_base_name = ('UNOFFICIAL_' + msi_base_name) |
- |
- results += (build_enterprise_installer. |
- BuildEnterpriseInstallerFromStandaloneInstaller( |
- env, |
- friendly_product_name, |
- product_version, |
- product_guid, |
- custom_tag_params, |
- silent_uninstall_args, |
- msi_installer_data, |
- standalone_installer_path, |
- omaha_files_path + '/show_error_action.dll', |
- prefix + msi_base_name, |
- enterprise_installers_sources_path, |
- output_dir=output_dir |
- )) |
- |
- # Tag the meta-installer if an installers.txt file was specified. |
- if offline_installer.installers_txt_filename: |
- installers_txt_path = env.File( |
- offline_installer.installers_txt_filename).abspath |
- app_bundles = tag_meta_installers.ReadBundleInstallerFile( |
- installers_txt_path) |
- |
- bundles = {} |
- for (key, bundle_list) in app_bundles.items(): |
- if not bundle_list or not key: |
- continue |
- if not key in bundles: |
- bundles[key] = bundle_list |
- else: |
- new_bundles_list = bundles[key] + bundle_list |
- bundles[key] = new_bundles_list |
- |
- tag_meta_installers.SetOutputFileNames(target_name, bundles, '') |
- for bundles_lang in bundles.itervalues(): |
- for bundle in bundles_lang: |
- results += tagged_installer.TagOneBundle( |
- env=env, |
- bundle=bundle, |
- untagged_binary_path=standalone_installer_path, |
- output_dir='$TARGET_ROOT/Tagged_Offline_Installers', |
- ) |
- |
- return results |