1#!/usr/bin/env python
2#
3# Copyright 2016 Google Inc.
4#
5# Use of this source code is governed by a BSD-style license that can be
6# found in the LICENSE file.
7
8
9"""Download an updated VS toolchain"""
10
11
12import argparse
13import common
14import json
15import os
16import shlex
17import shutil
18import subprocess
19import sys
20import utils
21
22import win_toolchain_utils
23
24
25# By default the toolchain includes a bunch of unnecessary stuff with long path
26# names. Trim out directories with these names.
27IGNORE_LIST = [
28  'WindowsMobile',
29  'App Certification Kit',
30  'Debuggers',
31  'Extension SDKs',
32  'DesignTime',
33  'AccChecker',
34]
35
36REPO_CHROME = 'https://chromium.googlesource.com/chromium/src.git'
37
38
39def filter_toolchain_files(dirname, files):
40  """Callback for shutil.copytree. Return lists of files to skip."""
41  split = dirname.split(os.path.sep)
42  for ign in IGNORE_LIST:
43    if ign in split:
44       print 'Ignoring dir %s' % dirname
45       return files
46  return []
47
48
49def get_toolchain_dir(toolchain_dir_output):
50  """Find the toolchain directory."""
51  prefix = 'vs_path = '
52  for line in toolchain_dir_output.splitlines():
53    if line.startswith(prefix):
54      return line[len(prefix):].strip('"')
55  raise Exception('Unable to find toolchain dir in output:\n%s' % (
56                  toolchain_dir_output))
57
58
59def gen_toolchain(chrome_path, msvs_version, target_dir):
60  """Update the VS toolchain and copy it to the target_dir."""
61  with utils.chdir(os.path.join(chrome_path, 'src')):
62    subprocess.check_call([utils.GCLIENT, 'sync'])
63    depot_tools = subprocess.check_output([
64        'python', os.path.join('build', 'find_depot_tools.py')]).rstrip()
65    with utils.git_branch():
66      vs_toolchain_py = os.path.join('build', 'vs_toolchain.py')
67      env = os.environ.copy()
68      env['GYP_MSVS_VERSION'] = msvs_version
69      subprocess.check_call(['python', vs_toolchain_py, 'update'], env=env)
70      output = subprocess.check_output(['python', vs_toolchain_py,
71                                        'get_toolchain_dir'], env=env).rstrip()
72      src_dir = get_toolchain_dir(output)
73      # Mock out absolute paths in win_toolchain.json.
74      win_toolchain_utils.abstract(os.path.join('build', 'win_toolchain.json'),
75                                   os.path.dirname(depot_tools))
76
77      # Copy the toolchain files to the target_dir.
78      build = os.path.join(os.getcwd(), 'build')
79      dst_build = os.path.join(target_dir, 'src', 'build')
80      os.makedirs(dst_build)
81      for f in ('find_depot_tools.py', 'vs_toolchain.py', 'win_toolchain.json'):
82        shutil.copyfile(os.path.join(build, f), os.path.join(dst_build, f))
83
84      shutil.copytree(os.path.join(os.getcwd(), 'tools', 'gyp', 'pylib'),
85                      os.path.join(target_dir, 'src', 'tools', 'gyp', 'pylib'))
86
87      dst_depot_tools = os.path.join(target_dir, 'depot_tools')
88      os.makedirs(dst_depot_tools)
89      for f in ('gclient.py', 'breakpad.py'):
90        shutil.copyfile(os.path.join(depot_tools, f),
91                        os.path.join(dst_depot_tools, f))
92      toolchain_dst = os.path.join(
93          target_dir, 'depot_tools', os.path.relpath(src_dir, depot_tools))
94      shutil.copytree(src_dir, toolchain_dst, ignore=filter_toolchain_files)
95
96
97def create_asset(target_dir, msvs_version, chrome_path=None):
98  """Create the asset."""
99  if not os.path.isdir(target_dir):
100    os.makedirs(target_dir)
101  with utils.tmp_dir() as tmp_dir:
102    if not chrome_path:
103      print ('Syncing Chrome from scratch. If you already have a checkout, '
104             'specify --chrome_path to save time.')
105      chrome_path = os.path.join(tmp_dir.name, 'src')
106    if not os.path.isdir(chrome_path):
107      subprocess.check_call([utils.GCLIENT, 'config', REPO_CHROME, '--managed'])
108      subprocess.check_call([utils.GCLIENT, 'sync'])
109
110    gen_toolchain(chrome_path, msvs_version, target_dir)
111
112def main():
113  if sys.platform != 'win32':
114    print >> sys.stderr, 'This script only runs on Windows.'
115    sys.exit(1)
116
117  parser = argparse.ArgumentParser()
118  parser.add_argument('--msvs_version', required=True)
119  parser.add_argument('--chrome_path')
120  parser.add_argument('--target_dir', '-t', required=True)
121  args = parser.parse_args()
122  target_dir = os.path.abspath(args.target_dir)
123  create_asset(target_dir, args.msvs_version, args.chrome_path)
124
125
126if __name__ == '__main__':
127  main()
128