File: make_setup.py

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (198 lines) | stat: -rwxr-xr-x 7,766 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/env python
# Copyright 2018 The Chromium Authors
# 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.
  """
  executable = '7zr'
  if sys.platform == 'win32':
    executable += '.exe'

  return os.path.join(src_path, 'third_party', 'lzma_sdk', 'bin',
                      'host_platform', executable)

def GetCmdLine(command, sz_fn, gcp_7z_fn):
  """Builds the command line for the given archive.

  Args:
    command: 7Zip command such as 'u', 'rn'..
    sz_fn: The executable command to run 7zip.
    gcp_7z_fn: 7zip file for the archive.

  Returns:
    Returns the command line for the provided command and 7zip archive. Command
    needs to be one of the supported 7zip commands.
  """
  return [
      sz_fn,  # Path to 7z executable.
      command,

      # 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,
  ]

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.
  u_cmd = GetCmdLine('u', sz_fn, gcp_7z_fn)

  # 7Zip CLI doesn't provide a direct way of adding files into a custom
  # folder. As suggested by the developer of 7Zip the method is to rename
  # a file with a specific subfolder to achieve the same.
  # https://sourceforge.net/p/sevenzip/discussion/45798/thread/5856d980/
  # For instance, if there is a file called "a.txt" in the parent folder of
  # archive, when it is renamed with "f\a.txt", the "a.txt" file is actually
  # placed in a folder called "f".
  rn_cmd = GetCmdLine('rn', sz_fn, gcp_7z_fn)

  # Builds the command line for deleting files in the archive.
  d_cmd = GetCmdLine('d', sz_fn, 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. That's why all the files initially added in
  # the top folder. Then the ones need to move to subfolders are renamed. 7z
  # doesn't have a method to achieve the same directly.

  # Add the credential provider dll, credential provider extension 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.

  try:
    gcpw_log_file = 'gcpw_archive_log_file'
    if os.path.exists(gcpw_log_file):
      os.remove(gcpw_log_file)

    # Redirecting output of 7zip and copy commands to a file and only printing
    # if any of the subprocess commands fail.
    with open(gcpw_log_file, "w+") as output_file:
      os.chdir(args.root_build_path)
      subprocess.check_call(d_cmd + ['*'], stdout=output_file)
      subprocess.check_call(u_cmd + ['gaia1_0.dll'], stdout=output_file)
      subprocess.check_call(u_cmd + ['gcp_setup.exe'], stdout=output_file)
      subprocess.check_call(u_cmd + ['gcp_eventlog_provider.dll'],
          stdout=output_file)
      subprocess.check_call(u_cmd + ['gcpw_extension.exe'], stdout=output_file)
      # Move the executable into a subfolder as there needs to be only one
      # executable in the parent folder.
      subprocess.check_call(rn_cmd +
          [
            'gcpw_extension.exe',
            os.path.join('extension', 'gcpw_extension.exe')
          ],
          stdout=output_file)
  except subprocess.CalledProcessError as e:
    print(e.output)
    with open(gcpw_log_file, "r") as output_file:
      print(output_file.read())
    raise e

  # 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())