blob: 794dd3ca09ebb3c86926e59925694ad627a865df [file] [log] [blame]
#!/usr/bin/env python
# Copyright 2018 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# This script builds the credential provider installer that is used to install
# all required components of the Google Credential Provider for Windows. The
# installer is a 7-zip self extracting executable file that wraps three main
# parts:
#
# - the Credential Provider COM DLL
# - a DLL that contains Windows EventLog message formatting
# - a setup exe that performs action required during install and uninstall
#
# In this description "installer" refers to the self extracting executable that
# wraps all the parts, whereas "setup" refers to an exe inside the installer
# that runs specific actions at install and uninstall time.
#
# When run, the installer extracts the wrapped files into a new empty
# directory under %TEMP%. The setup exe is then run to register the COM
# objects, install the message format dll, and properly register the credential
# provider with Windows. Once installation completes, the new directory
# containing the extracted files is automatically deleted.
#
# The installer can be run multiple times on the same machine. On an already
# working computer this is essentially a noop. On a damaged computer the files
# will be overwritten and the parts registered, so can be used to correct
# problems.
#
# Running a new version of the installer will replace the existing install with
# a newer one. It is not required to first uninstall the old version.
# Installation of the newer version will attempt to delete older versions if
# possible.
#
# The installer is not needed for uninstall and may be removed after initial
# install. To uninstall the Google Credential Provider for Windows, run the
# setup exe with the command line argument: /uninstall
"""Creates the GCPW self extracting installer. This script is not run manually,
it is called when building the //credential_provider:gcp_installer GN target.
All paths can be absolute or relative to $root_build_dir.
"""
import argparse
import os
import shutil
import subprocess
import sys
def GetLZMAExec(src_path):
"""Gets the path to the 7zip compression command line tool.
Args:
src_path: Full path to the source root
Returns:
The executable command to run the 7zip compressor.
"""
return (os.path.join(src_path, r'third_party\lzma_sdk\7zr.exe')
if sys.platform == 'win32' else '7zr')
def main():
parser = argparse.ArgumentParser(
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('src_path', help='Path to the source root')
parser.add_argument('cp_path',
help='Path to the credential provider directory')
parser.add_argument('root_build_path', help='$root_build_dir GN variable')
parser.add_argument('target_gen_path', help='$target_gen_dir GN variable')
args = parser.parse_args()
# Make sure all arguments are converted to absolute paths for use below.
args.src_path = os.path.abspath(args.src_path)
args.cp_path = os.path.abspath(args.cp_path)
args.root_build_path = os.path.abspath(args.root_build_path)
args.target_gen_path = os.path.abspath(args.target_gen_path)
if not os.path.isdir(args.cp_path):
parser.error('Invalid cp_path: "%s"' % args.cp_path)
if not os.path.isdir(args.src_path):
parser.error('Invalid src_path: "%s"' % args.src_path)
# Absolute path to gcp installer.
gcp_installer_fn = os.path.join(args.root_build_path, 'gcp_installer.exe')
gcp_7z_fn = os.path.join(args.root_build_path, 'gcp.7z')
sz_fn = GetLZMAExec(args.src_path)
sfx_fn = os.path.join(args.root_build_path, 'gcp_sfx.exe')
# Build the command line for updating files in the GCP 7z archive.
cmd = [
sz_fn, # Path to 7z executable.
'u', # Update file in archive.
# The follow options are equivalent to -mx9 with bcj2 turned on.
# Because //third_party/lzma_sdk is only partial copy of the ful sdk
# it does not support all forms of compression. Make sure to use
# compression that is compatible. These same options are used when
# building the chrome install compressed files.
'-m0=BCJ2',
'-m1=LZMA:d27:fb128',
'-m2=LZMA:d22:fb128:mf=bt2',
'-m3=LZMA:d22:fb128:mf=bt2',
'-mb0:1',
'-mb0s1:2',
'-mb0s2:3',
# Full path to archive.
gcp_7z_fn,
]
# Because of the way that 7zS2.sfx determine what program to run after
# extraction, only gcp_setup.exe should be placed in the root of the archive.
# Other "executable" type files (bat, cmd, exe, inf, msi, html, htm) should
# be located only in subfolders.
# Add the credential provider dll and setup programs to the archive.
# If the files added to the archive are changed, make sure to update the
# kFilenames array in setup_lib.cc.
# 7zip and copy commands don't have a "silent" mode, so redirecting stdout
# and stderr to nul.
with open(os.devnull) as nul_file:
os.chdir(args.root_build_path)
subprocess.check_call(cmd + ['gaia1_0.dll'], stdout=nul_file)
subprocess.check_call(cmd + ['gcp_setup.exe'], stdout=nul_file)
subprocess.check_call(cmd + ['gcp_eventlog_provider.dll'], stdout=nul_file)
# Combine the SFX module with the archive to make a self extracting
# executable.
with open(gcp_installer_fn, 'wb') as output:
with open (sfx_fn, 'rb') as input:
shutil.copyfileobj(input, output)
with open (gcp_7z_fn, 'rb') as input:
shutil.copyfileobj(input, output)
return 0
if __name__ == '__main__':
sys.exit(main())