]> git.wh0rd.org - home.git/blame - .bin/cros-repo
cros-repo: run init with -c for speedup
[home.git] / .bin / cros-repo
CommitLineData
6c6826b7
MF
1#!/usr/bin/python3
2# -*- coding: utf-8 -*-
3
4"""Wrapper for syncing CrOS code.
5
6Actions:
7 depot_tools clone depot_tools tree
8 int switch to internal tree
9 ext switch to external tree
10
11Operates on the repo in the cwd.
12"""
13
14import argparse
15import fnmatch
16import os
17import subprocess
18import sys
19
20
21REPO_URL = 'https://chromium.googlesource.com/external/repo'
22INT_MANIFEST = 'https://chrome-internal.googlesource.com/chromeos/manifest-internal'
23EXT_MANIFEST = 'https://chromium.googlesource.com/chromiumos/manifest'
24
25
26def run(cmd, **kwargs):
27 """Run with command tracing."""
28 # Python 3.6 doesn't support capture_output.
29 if sys.version_info < (3, 7):
30 capture_output = kwargs.pop('capture_output', None)
31 if capture_output:
32 assert 'stdout' not in kwargs and 'stderr' not in kwargs
33 kwargs['stdout'] = subprocess.PIPE
34 kwargs['stderr'] = subprocess.PIPE
35
36 print(kwargs.get('cwd', os.getcwd()))
37 print(' '.join(cmd))
38 return subprocess.run(cmd, **kwargs)
39
40
41def expand_branch(opts):
42 """Support branch shortnames."""
43 url = INT_MANIFEST if opts.action == 'int' else EXT_MANIFEST
44 ret = run(['git', 'ls-remote', url, 'refs/heads/*'], capture_output=True, encoding='utf-8')
45 branches = [x.split()[-1].split('/')[-1] for x in ret.stdout.splitlines()]
46 ret = []
47 for branch in branches:
90340618
MF
48 if branch.lower() == opts.branch.lower():
49 ret = [branch]
50 break
51 elif fnmatch.fnmatch(branch.lower(), f'*{opts.branch.lower()}*'):
6c6826b7
MF
52 ret.append(branch)
53 if not ret:
54 print(f'error: could not match branch {opts.branch}', file=sys.stderr)
55 print(f'Available branches:\n{" ".join(sorted(branches))}', file=sys.stderr)
56 sys.exit(1)
57 if len(ret) > 1:
58 print(f'error: too many branches match {opts.branch}:\n{" ".join(sorted(ret))}',
59 file=sys.stderr)
60 sys.exit(1)
61 print(f'Expanded branch {opts.branch} into {ret[0]}')
62 return ret[0]
63
64
90340618
MF
65def get_repo_topdir(opts):
66 """Find the top dir of this repo client checkout."""
6c6826b7
MF
67 topdir = os.getcwd()
68 while True:
69 rdir = os.path.join(topdir, '.repo')
70 if os.path.exists(rdir):
71 break
72 topdir = os.path.dirname(topdir)
73 assert topdir != '/'
90340618
MF
74 return topdir
75
76
77def set_git_config(opts):
78 """Set .git/config settings in all the repos."""
79 topdir = get_repo_topdir(opts)
80 rdir = os.path.join(topdir, '.repo')
6c6826b7
MF
81
82 def gcfg(path, *args):
83 cmd = ['git', f'--git-dir={path}', 'config', 'user.email'] + list(args)
84 ret = run(cmd, capture_output=True, encoding='utf-8')
85 return ret.stdout.strip()
86
87 current_email = gcfg(os.path.join(rdir, 'manifests.git'))
88 if current_email == opts.email:
89 return
90
91 print(f'Setting e-mail to {opts.email}')
92 for root, dirs, files in os.walk(rdir):
93 if root.endswith('.git') and not os.path.islink(os.path.join(root, 'config')):
94 gcfg(root, opts.email)
95 del dirs[:]
96
97
98def init_repo(opts):
99 """Initialize CrOS checkout."""
4712112f 100 cmd = ['repo', 'init', '-c']
6c6826b7
MF
101
102 if opts.action == 'int':
103 cmd += ['-u', INT_MANIFEST]
104 cmd += ['--repo-url', REPO_URL]
105 elif opts.action == 'ext':
106 cmd += ['-u', EXT_MANIFEST]
107 cmd += ['--repo-url', REPO_URL]
108
90340618 109 if opts.ref and os.path.realpath(opts.ref) != os.path.realpath(get_repo_topdir(opts)):
6c6826b7
MF
110 cmd += ['--reference', opts.ref]
111
112 if opts.manifest:
113 cmd += ['-m', opts.manifest]
114
115 if opts.group:
116 cmd += ['-g', opts.group]
117
118 if opts.branch:
119 branch = expand_branch(opts)
120 cmd += ['-b', branch]
121
122 ret = run(cmd)
123 if ret.returncode:
124 return ret.returncode
125
126 set_git_config(opts)
127
128 print('\ncros-repo: all done')
129 return 0
130
131
132def clone_depot_tools():
133 """Clone depot_tools repo."""
134 ret = run(['git', 'clone', 'https://chromium.googlesource.com/chromium/tools/depot_tools'])
135 return ret.returncode
136
137
138def get_parser():
139 """Get command line parser."""
140 parser = argparse.ArgumentParser(
141 description=__doc__,
142 formatter_class=argparse.RawDescriptionHelpFormatter)
143 parser.add_argument('-b', '--branch',
be550c8e 144 help='Switch branches (use "main" to get to ToT)')
6c6826b7
MF
145 parser.add_argument('-r', '--ref', '--reference', default='~/chromiumos/',
146 help='Patch to reference repo (default: %(default)s)')
147 parser.add_argument('-g', '--group',
148 help='Manifest group to use (e.g. "minilayout")')
149 parser.add_argument('-m', '--manifest',
150 help='Manifest file name to use (e.g. "full.xml")')
151 parser.add_argument('-e', '--email', default='vapier@chromium.org',
152 help='E-mail address to force (default: %(default)s)')
153 parser.add_argument('action', nargs='?',
154 choices={'depot_tools', 'dt', 'int', 'ext'},
155 help='What to do!')
156 return parser
157
158
159def main(argv):
160 """The main func."""
161 parser = get_parser()
162 opts = parser.parse_args(argv)
163 if opts.manifest:
164 if '/' in opts.manifest:
165 parser.error('manifest should be basename like "full.xml"')
166 if opts.manifest.endswith('.xml'):
167 opts.manifest = opts.manifest[:-4]
168 opts.manifest += '.xml'
169 if opts.ref:
170 opts.ref = os.path.expanduser(opts.ref)
171
172 if opts.action in {'depot_tools', 'dt'}:
173 return clone_depot_tools()
174 else:
175 return init_repo(opts)
176
177
178if __name__ == '__main__':
179 sys.exit(main(sys.argv[1:]))