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