OLD | NEW |
(Empty) | |
| 1 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. |
| 4 |
| 5 import argparse |
| 6 import fnmatch |
| 7 import logging |
| 8 import os |
| 9 import shutil |
| 10 import subprocess |
| 11 import sys |
| 12 import tempfile |
| 13 |
| 14 |
| 15 THIS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| 16 ROOT_DIR = os.path.abspath(os.path.join(THIS_DIR, '..', '..')) |
| 17 |
| 18 DEVNULL = open(os.devnull, 'w') |
| 19 |
| 20 |
| 21 def _check_call(argv, **kwargs): |
| 22 """Wrapper for subprocess.check_call that adds logging.""" |
| 23 logging.info('running %r', argv) |
| 24 subprocess.check_call(argv, **kwargs) |
| 25 |
| 26 |
| 27 def get_target_git_version(): |
| 28 """Returns git version that should be installed.""" |
| 29 if os.path.exists(os.path.join(ROOT_DIR, '.git_bleeding_edge')): |
| 30 git_version_file = 'git_version_bleeding_edge.txt' |
| 31 else: |
| 32 git_version_file = 'git_version.txt' |
| 33 with open(os.path.join(THIS_DIR, git_version_file)) as f: |
| 34 return f.read().strip() |
| 35 |
| 36 |
| 37 def clean_up_old_git_installations(git_directory): |
| 38 """Removes git installations other than |git_directory|.""" |
| 39 for entry in fnmatch.filter(os.listdir(ROOT_DIR), 'git-*_bin'): |
| 40 full_entry = os.path.join(ROOT_DIR, entry) |
| 41 if full_entry != git_directory: |
| 42 logging.info('Cleaning up old git installation %r', entry) |
| 43 shutil.rmtree(full_entry, ignore_errors=True) |
| 44 |
| 45 |
| 46 def bootstrap_cipd(cipd_directory): |
| 47 """Bootstraps CIPD client into |cipd_directory|.""" |
| 48 _check_call([ |
| 49 sys.executable, |
| 50 os.path.join(ROOT_DIR, 'recipe_modules', 'cipd', 'resources', |
| 51 'bootstrap.py'), |
| 52 '--platform', 'windows-amd64', |
| 53 '--dest-directory', cipd_directory |
| 54 ]) |
| 55 |
| 56 |
| 57 def cipd_install(args, dest_directory, package, version): |
| 58 """Installs CIPD |package| at |version| into |dest_directory|.""" |
| 59 manifest_file = tempfile.mktemp() |
| 60 try: |
| 61 with open(manifest_file, 'w') as f: |
| 62 f.write('%s %s\n' % (package, version)) |
| 63 |
| 64 cipd_args = [ |
| 65 args.cipd_client, |
| 66 'ensure', |
| 67 '-list', manifest_file, |
| 68 '-root', dest_directory, |
| 69 ] |
| 70 if args.cipd_cache_directory: |
| 71 cipd_args.extend(['-cache-dir', args.cipd_cache_directory]) |
| 72 if args.verbose: |
| 73 cipd_args.append('-verbose') |
| 74 _check_call(cipd_args) |
| 75 finally: |
| 76 os.remove(manifest_file) |
| 77 |
| 78 |
| 79 def need_to_install_git(args, git_directory): |
| 80 """Returns True if git needs to be installed.""" |
| 81 if args.force: |
| 82 return True |
| 83 git_exe_path = os.path.join(git_directory, 'bin', 'git.exe') |
| 84 if not os.path.exists(git_exe_path): |
| 85 return True |
| 86 if subprocess.call( |
| 87 [git_exe_path, '--version'], |
| 88 stdout=DEVNULL, stderr=DEVNULL) != 0: |
| 89 return True |
| 90 for script in ('git.bat', 'gitk.bat', 'ssh.bat', 'ssh-keygen.bat', |
| 91 'git-bash'): |
| 92 full_path = os.path.join(ROOT_DIR, script) |
| 93 if not os.path.exists(full_path): |
| 94 return True |
| 95 with open(full_path) as f: |
| 96 if os.path.relpath(git_directory, ROOT_DIR) not in f.read(): |
| 97 return True |
| 98 if not os.path.exists(os.path.join( |
| 99 git_directory, 'etc', 'profile.d', 'python.sh')): |
| 100 return True |
| 101 return False |
| 102 |
| 103 |
| 104 def install_git(args, git_version, git_directory): |
| 105 """Installs |git_version| into |git_directory|.""" |
| 106 if not args.cipd_client: |
| 107 bootstrap_cipd(ROOT_DIR) |
| 108 args.cipd_client = os.path.join(ROOT_DIR, 'cipd') |
| 109 temp_dir = tempfile.mkdtemp() |
| 110 try: |
| 111 cipd_install(args, |
| 112 temp_dir, |
| 113 'infra/depot_tools/git_installer/windows-amd64', |
| 114 'v' + git_version.replace('.', '_')) |
| 115 |
| 116 if not os.path.exists(git_directory): |
| 117 os.makedirs(git_directory) |
| 118 |
| 119 # 7-zip has weird expectations for command-line syntax. Pass it as a string |
| 120 # to avoid subprocess module quoting breaking it. Also double-escape |
| 121 # backslashes in paths. |
| 122 _check_call(' '.join([ |
| 123 os.path.join(temp_dir, 'git-installer.exe'), |
| 124 '-y', |
| 125 '-InstallPath="%s"' % git_directory.replace('\\', '\\\\'), |
| 126 '-Directory="%s"' % git_directory.replace('\\', '\\\\'), |
| 127 ])) |
| 128 finally: |
| 129 shutil.rmtree(temp_dir, ignore_errors=True) |
| 130 |
| 131 with open(os.path.join(THIS_DIR, 'git.template.bat')) as f: |
| 132 git_template = f.read() |
| 133 git_template = git_template.replace( |
| 134 'GIT_BIN_DIR', os.path.relpath(git_directory, ROOT_DIR)) |
| 135 scripts = ( |
| 136 ('git.bat', 'cmd\\git.exe'), |
| 137 ('gitk.bat', 'cmd\\gitk.exe'), |
| 138 ('ssh.bat', 'usr\\bin\\ssh.exe'), |
| 139 ('ssh-keygen.bat', 'usr\\bin\\ssh-keygen.exe'), |
| 140 ) |
| 141 for script in scripts: |
| 142 with open(os.path.join(ROOT_DIR, script[0]), 'w') as f: |
| 143 f.write(git_template.replace('GIT_PROGRAM', script[1])) |
| 144 with open(os.path.join(THIS_DIR, 'git-bash.template.sh')) as f: |
| 145 git_bash_template = f.read() |
| 146 with open(os.path.join(ROOT_DIR, 'git-bash'), 'w') as f: |
| 147 f.write(git_bash_template.replace( |
| 148 'GIT_BIN_DIR', os.path.relpath(git_directory, ROOT_DIR))) |
| 149 shutil.copyfile( |
| 150 os.path.join(THIS_DIR, 'profile.d.python.sh'), |
| 151 os.path.join(git_directory, 'etc', 'profile.d', 'python.sh')) |
| 152 |
| 153 git_bat_path = os.path.join(ROOT_DIR, 'git.bat') |
| 154 _check_call([git_bat_path, 'config', '--system', 'core.autocrlf', 'false']) |
| 155 _check_call([git_bat_path, 'config', '--system', 'core.filemode', 'false']) |
| 156 _check_call([git_bat_path, 'config', '--system', 'core.preloadindex', 'true']) |
| 157 _check_call([git_bat_path, 'config', '--system', 'core.fscache', 'true']) |
| 158 |
| 159 |
| 160 def sync_git_help_files(git_directory): |
| 161 """Updates depot_tools help files inside |git_directory|.""" |
| 162 # TODO(phajdan.jr): consider replacing the call with python code. |
| 163 _check_call([ |
| 164 'xcopy', '/i', '/q', '/d', '/y', |
| 165 os.path.join(ROOT_DIR, 'man', 'html', '*'), |
| 166 os.path.join(git_directory, 'mingw64', 'share', 'doc', 'git-doc')], |
| 167 stdout=DEVNULL) |
| 168 |
| 169 |
| 170 def main(argv): |
| 171 parser = argparse.ArgumentParser() |
| 172 parser.add_argument('--cipd-client', help='Path to CIPD client binary.') |
| 173 parser.add_argument('--cipd-cache-directory', |
| 174 help='Path to CIPD cache directory.') |
| 175 parser.add_argument('--force', action='store_true', |
| 176 help='Always re-install git.') |
| 177 parser.add_argument('--verbose', action='store_true') |
| 178 args = parser.parse_args(argv) |
| 179 |
| 180 if os.environ.get('WIN_TOOLS_FORCE') == '1': |
| 181 args.force = True |
| 182 |
| 183 logging.basicConfig(level=logging.INFO if args.verbose else logging.WARN) |
| 184 |
| 185 git_version = get_target_git_version() |
| 186 git_directory = os.path.join(ROOT_DIR, 'git-%s-64_bin' % git_version) |
| 187 |
| 188 clean_up_old_git_installations(git_directory) |
| 189 |
| 190 if need_to_install_git(args, git_directory): |
| 191 install_git(args, git_version, git_directory) |
| 192 |
| 193 sync_git_help_files(git_directory) |
| 194 |
| 195 return 0 |
| 196 |
| 197 |
| 198 if __name__ == '__main__': |
| 199 sys.exit(main(sys.argv[1:])) |
OLD | NEW |