| #!/usr/bin/env python |
| # Copyright (c) 2015 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. |
| |
| |
| """Wrapper for updating and calling infra.git tools. |
| |
| This tool does a two things: |
| * Maintains a infra.git checkout pinned at "deployed" in the home dir |
| * Acts as an alias to infra.tools.* |
| * Acts as an alias to infra.git/cipd/<executable> |
| """ |
| |
| # TODO(hinoka,iannucci): Pre-pack infra tools in cipd package with vpython spec. |
| |
| from __future__ import print_function |
| |
| import argparse |
| import sys |
| import os |
| import re |
| |
| import subprocess2 as subprocess |
| |
| |
| SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
| GCLIENT = os.path.join(SCRIPT_DIR, 'gclient.py') |
| TARGET_DIR = os.path.expanduser(os.path.join('~', '.chrome-infra')) |
| INFRA_DIR = os.path.join(TARGET_DIR, 'infra') |
| |
| |
| def get_git_rev(target, branch): |
| return subprocess.check_output( |
| ['git', 'log', '--format=%B', '-n1', branch], cwd=target) |
| |
| |
| def need_to_update(branch): |
| """Checks to see if we need to update the ~/.chrome-infra/infra checkout.""" |
| try: |
| cmd = [sys.executable, GCLIENT, 'revinfo'] |
| subprocess.check_call( |
| cmd, cwd=os.path.join(TARGET_DIR), stdout=subprocess.VOID) |
| except subprocess.CalledProcessError: |
| return True # Gclient failed, definitely need to update. |
| except OSError: |
| return True # Gclient failed, definitely need to update. |
| |
| if not os.path.isdir(INFRA_DIR): |
| return True |
| |
| local_rev = get_git_rev(INFRA_DIR, 'HEAD') |
| |
| subprocess.check_call( |
| ['git', 'fetch', 'origin'], cwd=INFRA_DIR, |
| stdout=subprocess.VOID, stderr=subprocess.STDOUT) |
| origin_rev = get_git_rev(INFRA_DIR, 'origin/%s' % (branch,)) |
| return origin_rev != local_rev |
| |
| |
| def ensure_infra(branch): |
| """Ensures that infra.git is present in ~/.chrome-infra.""" |
| sys.stderr.write( |
| 'Fetching infra@%s into %s, may take a couple of minutes...' % ( |
| branch, TARGET_DIR)) |
| sys.stderr.flush() |
| if not os.path.isdir(TARGET_DIR): |
| os.mkdir(TARGET_DIR) |
| if not os.path.exists(os.path.join(TARGET_DIR, '.gclient')): |
| subprocess.check_call( |
| [sys.executable, os.path.join(SCRIPT_DIR, 'fetch.py'), 'infra'], |
| cwd=TARGET_DIR, |
| stdout=subprocess.VOID) |
| subprocess.check_call( |
| [sys.executable, GCLIENT, 'sync', '--revision', 'origin/%s' % (branch,)], |
| cwd=TARGET_DIR, |
| stdout=subprocess.VOID) |
| sys.stderr.write(' done.\n') |
| sys.stderr.flush() |
| |
| |
| def is_exe(filename): |
| """Given a full filepath, return true if the file is an executable.""" |
| if sys.platform.startswith('win'): |
| return filename.endswith('.exe') |
| else: |
| return os.path.isfile(filename) and os.access(filename, os.X_OK) |
| |
| |
| def get_available_tools(): |
| """Returns a tuple of (list of infra tools, list of cipd tools)""" |
| infra_tools = [] |
| cipd_tools = [] |
| starting = os.path.join(TARGET_DIR, 'infra', 'infra', 'tools') |
| for root, _, files in os.walk(starting): |
| if '__main__.py' in files: |
| infra_tools.append(root[len(starting)+1:].replace(os.path.sep, '.')) |
| cipd = os.path.join(TARGET_DIR, 'infra', 'cipd') |
| for fn in os.listdir(cipd): |
| if is_exe(os.path.join(cipd, fn)): |
| cipd_tools.append(fn) |
| return (sorted(infra_tools), sorted(cipd_tools)) |
| |
| |
| def usage(): |
| infra_tools, cipd_tools = get_available_tools() |
| print("""usage: cit.py <name of tool> [args for tool] |
| |
| Wrapper for maintaining and calling tools in: |
| "infra.git/run.py infra.tools.*" |
| "infra.git/cipd/*" |
| |
| Available infra tools are:""") |
| for tool in infra_tools: |
| print(' * %s' % tool) |
| |
| print(""" |
| Available cipd tools are:""") |
| for tool in cipd_tools: |
| print(' * %s' % tool) |
| |
| |
| def run(args): |
| if not args: |
| return usage() |
| |
| tool_name = args[0] |
| # Check to see if it is a infra tool first. |
| infra_dir = os.path.join( |
| TARGET_DIR, 'infra', 'infra', 'tools', *tool_name.split('.')) |
| cipd_file = os.path.join(TARGET_DIR, 'infra', 'cipd', tool_name) |
| if sys.platform.startswith('win'): |
| cipd_file += '.exe' |
| if (os.path.isdir(infra_dir) |
| and os.path.isfile(os.path.join(infra_dir, '__main__.py'))): |
| cmd = [ |
| sys.executable, os.path.join(TARGET_DIR, 'infra', 'run.py'), |
| 'infra.tools.%s' % tool_name] |
| elif os.path.isfile(cipd_file) and is_exe(cipd_file): |
| cmd = [cipd_file] |
| else: |
| print('Unknown tool "%s"' % tool_name, file=sys.stderr) |
| return usage() |
| |
| # Add the remaining arguments. |
| cmd.extend(args[1:]) |
| return subprocess.call(cmd) |
| |
| |
| def main(): |
| parser = argparse.ArgumentParser("Chrome Infrastructure CLI.") |
| parser.add_argument('-b', '--infra-branch', default='cit', |
| help="The name of the 'infra' branch to use (default is %(default)s).") |
| parser.add_argument('args', nargs=argparse.REMAINDER) |
| |
| args, extras = parser.parse_known_args() |
| if args.args and args.args[0] == '--': |
| args.args.pop(0) |
| if extras: |
| args.args = extras + args.args |
| |
| if need_to_update(args.infra_branch): |
| ensure_infra(args.infra_branch) |
| return run(args.args) |
| |
| if __name__ == '__main__': |
| sys.exit(main()) |