blob: b13e34c6b289c94a693566ea17f76344c72e9ccd [file] [log] [blame]
David Pursehouse8898e2f2012-11-14 07:51:03 +09001#!/usr/bin/env python
Mike Frysingerf6013762019-06-13 02:30:51 -04002# -*- coding:utf-8 -*-
Mike Frysingerf241f8c2020-02-20 17:08:43 -05003#
4# Copyright (C) 2008 The Android Open Source Project
5#
6# Licensed under the Apache License, Version 2.0 (the "License");
7# you may not use this file except in compliance with the License.
8# You may obtain a copy of the License at
9#
10# http://www.apache.org/licenses/LICENSE-2.0
11#
12# Unless required by applicable law or agreed to in writing, software
13# distributed under the License is distributed on an "AS IS" BASIS,
14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15# See the License for the specific language governing permissions and
16# limitations under the License.
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070017
Mike Frysinger87fb5a12019-06-13 01:54:46 -040018"""Repo launcher.
19
20This is a standalone tool that people may copy to anywhere in their system.
21It is used to get an initial repo client checkout, and after that it runs the
22copy of repo in the checkout.
23"""
24
Mike Frysingerc92ce5c2019-06-13 01:14:23 -040025from __future__ import print_function
26
Mike Frysinger84094102020-02-11 02:10:28 -050027import datetime
Mike Frysinger3ba716f2019-06-13 01:48:12 -040028import os
29import platform
Mike Frysinger949bc342020-02-18 21:37:00 -050030import shlex
Mike Frysinger3ba716f2019-06-13 01:48:12 -040031import subprocess
32import sys
33
34
Mike Frysinger6fb0cb52020-02-12 09:39:23 -050035# Keep basic logic in sync with repo_trace.py.
36class Trace(object):
37 """Trace helper logic."""
38
39 REPO_TRACE = 'REPO_TRACE'
40
41 def __init__(self):
42 self.set(os.environ.get(self.REPO_TRACE) == '1')
43
44 def set(self, value):
45 self.enabled = bool(value)
46
47 def print(self, *args, **kwargs):
48 if self.enabled:
49 print(*args, **kwargs)
50
51
52trace = Trace()
53
54
Mike Frysinger3ba716f2019-06-13 01:48:12 -040055def exec_command(cmd):
56 """Execute |cmd| or return None on failure."""
Mike Frysinger6fb0cb52020-02-12 09:39:23 -050057 trace.print(':', ' '.join(cmd))
Mike Frysinger3ba716f2019-06-13 01:48:12 -040058 try:
59 if platform.system() == 'Windows':
60 ret = subprocess.call(cmd)
61 sys.exit(ret)
62 else:
63 os.execvp(cmd[0], cmd)
Mike Frysinger72b6dc82020-02-12 17:04:32 -050064 except Exception:
Mike Frysinger3ba716f2019-06-13 01:48:12 -040065 pass
66
67
68def check_python_version():
69 """Make sure the active Python version is recent enough."""
70 def reexec(prog):
71 exec_command([prog] + sys.argv)
72
73 MIN_PYTHON_VERSION = (3, 6)
74
75 ver = sys.version_info
76 major = ver.major
77 minor = ver.minor
78
79 # Abort on very old Python 2 versions.
80 if (major, minor) < (2, 7):
81 print('repo: error: Your Python version is too old. '
82 'Please use Python {}.{} or newer instead.'.format(
83 *MIN_PYTHON_VERSION), file=sys.stderr)
84 sys.exit(1)
85
86 # Try to re-exec the version specific Python 3 if needed.
87 if (major, minor) < MIN_PYTHON_VERSION:
88 # Python makes releases ~once a year, so try our min version +10 to help
89 # bridge the gap. This is the fallback anyways so perf isn't critical.
90 min_major, min_minor = MIN_PYTHON_VERSION
91 for inc in range(0, 10):
92 reexec('python{}.{}'.format(min_major, min_minor + inc))
93
94 # Try the generic Python 3 wrapper, but only if it's new enough. We don't
95 # want to go from (still supported) Python 2.7 to (unsupported) Python 3.5.
96 try:
97 proc = subprocess.Popen(
98 ['python3', '-c', 'import sys; '
99 'print(sys.version_info.major, sys.version_info.minor)'],
100 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
101 (output, _) = proc.communicate()
102 python3_ver = tuple(int(x) for x in output.decode('utf-8').split())
103 except (OSError, subprocess.CalledProcessError):
104 python3_ver = None
105
106 # The python3 version looks like it's new enough, so give it a try.
107 if python3_ver and python3_ver >= MIN_PYTHON_VERSION:
108 reexec('python3')
109
110 # We're still here, so diagnose things for the user.
111 if major < 3:
112 print('repo: warning: Python 2 is no longer supported; '
113 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION),
114 file=sys.stderr)
115 else:
116 print('repo: error: Python 3 version is too old; '
117 'Please use Python {}.{} or newer.'.format(*MIN_PYTHON_VERSION),
118 file=sys.stderr)
119 sys.exit(1)
120
121
122if __name__ == '__main__':
Mike Frysinger19ec7972020-02-16 12:02:01 -0500123 check_python_version()
Mike Frysinger3ba716f2019-06-13 01:48:12 -0400124
125
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700126# repo default configuration
127#
Mark E. Hamilton55536282016-02-03 15:49:43 -0700128REPO_URL = os.environ.get('REPO_URL', None)
129if not REPO_URL:
130 REPO_URL = 'https://gerrit.googlesource.com/git-repo'
Mike Frysinger563f1a62020-02-05 23:52:07 -0500131REPO_REV = os.environ.get('REPO_REV')
132if not REPO_REV:
133 REPO_REV = 'stable'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700134
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700135# increment this whenever we make important changes to this script
Mike Frysinger60fc51b2020-05-21 18:13:49 -0400136VERSION = (2, 8)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700137
138# increment this if the MAINTAINER_KEYS block is modified
Mike Frysinger9cc1d702020-02-13 18:28:03 -0500139KEYRING_VERSION = (2, 3)
Mike Frysingere4433652016-09-13 18:06:07 -0400140
141# Each individual key entry is created by using:
142# gpg --armor --export keyid
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700143MAINTAINER_KEYS = """
144
145 Repo Maintainer <repo@android.kernel.org>
146-----BEGIN PGP PUBLIC KEY BLOCK-----
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700147
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
Mike Frysinger9cc1d702020-02-13 18:28:03 -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
213cZ7aFsJF4PtcDrfdejyAxbtsSHI=
214=82Tj
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700215-----END PGP PUBLIC KEY BLOCK-----
216"""
217
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700218GIT = 'git' # our git command
Mike Frysinger82caef62020-02-11 18:51:08 -0500219# NB: The version of git that the repo launcher requires may be much older than
220# the version of git that the main repo source tree requires. Keeping this at
221# an older version also makes it easier for users to upgrade/rollback as needed.
222#
223# git-1.7 is in (EOL) Ubuntu Precise.
224MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700225repodir = '.repo' # name of repo's private directory
226S_repo = 'repo' # special repo repository
227S_manifests = 'manifests' # special manifest repository
228REPO_MAIN = S_repo + '/main.py' # main script
Simran Basi8ce50412015-08-28 14:25:44 -0700229GITC_CONFIG_FILE = '/gitc/.config'
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700230GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700231
232
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400233import collections
David Jamesbf79c662013-12-26 14:20:13 -0800234import errno
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700235import optparse
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700236import re
Mitchel Humpheryseb5acc92014-03-12 10:48:15 -0700237import shutil
Sarah Owens60798a32012-10-25 17:53:09 -0700238import stat
David Pursehouse59bbb582013-05-17 10:49:33 +0900239
240if sys.version_info[0] == 3:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700241 import urllib.request
242 import urllib.error
243else:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700244 import imp
David Pursehouse59bbb582013-05-17 10:49:33 +0900245 import urllib2
Sarah Owens1f7627f2012-10-31 09:21:55 -0700246 urllib = imp.new_module('urllib')
247 urllib.request = urllib2
248 urllib.error = urllib2
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700249
Conley Owens5e0ee142013-09-26 15:50:49 -0700250
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700251home_dot_repo = os.path.expanduser('~/.repoconfig')
252gpg_dir = os.path.join(home_dot_repo, 'gnupg')
253
David Pursehouse31b9b4b2020-02-13 08:20:14 +0900254
Mike Frysingerd8fda902020-02-14 00:24:38 -0500255def GetParser(gitc_init=False):
256 """Setup the CLI parser."""
257 if gitc_init:
258 usage = 'repo gitc-init -u url -c client [options]'
259 else:
260 usage = 'repo init -u url [options]'
261
262 parser = optparse.OptionParser(usage=usage)
263
Mike Frysingerf700ac72020-02-06 00:04:21 -0500264 # Logging.
Mike Frysingerd8fda902020-02-14 00:24:38 -0500265 group = parser.add_option_group('Logging options')
Mike Frysingeredd3d452020-02-21 23:55:07 -0500266 group.add_option('-v', '--verbose',
267 dest='output_mode', action='store_true',
268 help='show all output')
Mike Frysingerf700ac72020-02-06 00:04:21 -0500269 group.add_option('-q', '--quiet',
Mike Frysingeredd3d452020-02-21 23:55:07 -0500270 dest='output_mode', action='store_false',
271 help='only show errors')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700272
Mike Frysingerf700ac72020-02-06 00:04:21 -0500273 # Manifest.
Mike Frysingerd8fda902020-02-14 00:24:38 -0500274 group = parser.add_option_group('Manifest options')
Mike Frysingerf700ac72020-02-06 00:04:21 -0500275 group.add_option('-u', '--manifest-url',
276 help='manifest repository location', metavar='URL')
277 group.add_option('-b', '--manifest-branch',
278 help='manifest branch or revision', metavar='REVISION')
279 group.add_option('-m', '--manifest-name',
280 help='initial manifest file', metavar='NAME.xml')
Mike Frysingerd8fda902020-02-14 00:24:38 -0500281 cbr_opts = ['--current-branch']
282 # The gitc-init subcommand allocates -c itself, but a lot of init users
283 # want -c, so try to satisfy both as best we can.
284 if not gitc_init:
285 cbr_opts += ['-c']
286 group.add_option(*cbr_opts,
Mike Frysingerf700ac72020-02-06 00:04:21 -0500287 dest='current_branch_only', action='store_true',
288 help='fetch only current manifest branch from server')
289 group.add_option('--mirror', action='store_true',
290 help='create a replica of the remote repositories '
291 'rather than a client working directory')
292 group.add_option('--reference',
293 help='location of mirror directory', metavar='DIR')
294 group.add_option('--dissociate', action='store_true',
295 help='dissociate from reference mirrors after clone')
296 group.add_option('--depth', type='int', default=None,
297 help='create a shallow clone with given depth; '
298 'see git clone')
299 group.add_option('--partial-clone', action='store_true',
300 help='perform partial clone (https://git-scm.com/'
301 'docs/gitrepository-layout#_code_partialclone_code)')
302 group.add_option('--clone-filter', action='store', default='blob:none',
303 help='filter for use with --partial-clone '
304 '[default: %default]')
Mike Frysinger979d5bd2020-02-09 02:28:34 -0500305 group.add_option('--worktree', action='store_true',
306 help=optparse.SUPPRESS_HELP)
Mike Frysingerf700ac72020-02-06 00:04:21 -0500307 group.add_option('--archive', action='store_true',
308 help='checkout an archive instead of a git repository for '
309 'each project. See git archive.')
310 group.add_option('--submodules', action='store_true',
311 help='sync any submodules associated with the manifest repo')
312 group.add_option('-g', '--groups', default='default',
313 help='restrict manifest projects to ones with specified '
314 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
315 metavar='GROUP')
316 group.add_option('-p', '--platform', default='auto',
317 help='restrict manifest projects to ones with a specified '
318 'platform group [auto|all|none|linux|darwin|...]',
319 metavar='PLATFORM')
Xin Lid79a4bc2020-05-20 16:03:45 -0700320 group.add_option('--clone-bundle', action='store_true',
321 help='enable use of /clone.bundle on HTTP/HTTPS (default if not --partial-clone)')
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500322 group.add_option('--no-clone-bundle',
Xin Lid79a4bc2020-05-20 16:03:45 -0700323 dest='clone_bundle', action='store_false',
324 help='disable use of /clone.bundle on HTTP/HTTPS (default if --partial-clone)')
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500325 group.add_option('--no-tags',
326 dest='tags', default=True, action='store_false',
Mike Frysingerf700ac72020-02-06 00:04:21 -0500327 help="don't fetch tags in the manifest")
Doug Anderson49cd59b2011-06-13 21:42:06 -0700328
Mike Frysingerf700ac72020-02-06 00:04:21 -0500329 # Tool.
Mike Frysingerd8fda902020-02-14 00:24:38 -0500330 group = parser.add_option_group('repo Version options')
Mike Frysingerf700ac72020-02-06 00:04:21 -0500331 group.add_option('--repo-url', metavar='URL',
332 help='repo repository location ($REPO_URL)')
Mike Frysinger58ac1672020-03-14 14:35:26 -0400333 group.add_option('--repo-rev', metavar='REV',
Mike Frysingerf700ac72020-02-06 00:04:21 -0500334 help='repo branch or revision ($REPO_REV)')
Mike Frysinger58ac1672020-03-14 14:35:26 -0400335 group.add_option('--repo-branch', dest='repo_rev',
336 help=optparse.SUPPRESS_HELP)
Mike Frysingerc58ec4d2020-02-17 14:36:08 -0500337 group.add_option('--no-repo-verify',
338 dest='repo_verify', default=True, action='store_false',
Mike Frysingerf700ac72020-02-06 00:04:21 -0500339 help='do not verify repo source code')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700340
Mike Frysingerf700ac72020-02-06 00:04:21 -0500341 # Other.
Mike Frysingerd8fda902020-02-14 00:24:38 -0500342 group = parser.add_option_group('Other options')
Mike Frysingerf700ac72020-02-06 00:04:21 -0500343 group.add_option('--config-name',
344 action='store_true', default=False,
345 help='Always prompt for name/e-mail')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700346
Mike Frysingerd8fda902020-02-14 00:24:38 -0500347 # gitc-init specific settings.
348 if gitc_init:
349 group = parser.add_option_group('GITC options')
350 group.add_option('-f', '--manifest-file',
351 help='Optional manifest file to use for this GITC client.')
352 group.add_option('-c', '--gitc-client',
353 help='Name of the gitc_client instance to create or modify.')
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700354
Mike Frysingerd8fda902020-02-14 00:24:38 -0500355 return parser
Simran Basi1efc2b42015-08-05 15:04:22 -0700356
David Pursehouse31b9b4b2020-02-13 08:20:14 +0900357
Mike Frysinger62285d22020-02-12 08:01:38 -0500358# This is a poor replacement for subprocess.run until we require Python 3.6+.
359RunResult = collections.namedtuple(
360 'RunResult', ('returncode', 'stdout', 'stderr'))
361
362
363class RunError(Exception):
364 """Error when running a command failed."""
365
366
367def run_command(cmd, **kwargs):
368 """Run |cmd| and return its output."""
369 check = kwargs.pop('check', False)
370 if kwargs.pop('capture_output', False):
371 kwargs.setdefault('stdout', subprocess.PIPE)
372 kwargs.setdefault('stderr', subprocess.PIPE)
373 cmd_input = kwargs.pop('input', None)
374
Mike Frysinger6a784ff2020-02-14 23:38:28 -0500375 def decode(output):
376 """Decode |output| to text."""
377 if output is None:
378 return output
379 try:
380 return output.decode('utf-8')
381 except UnicodeError:
382 print('repo: warning: Invalid UTF-8 output:\ncmd: %r\n%r' % (cmd, output),
383 file=sys.stderr)
384 # TODO(vapier): Once we require Python 3, use 'backslashreplace'.
385 return output.decode('utf-8', 'replace')
386
Mike Frysinger62285d22020-02-12 08:01:38 -0500387 # Run & package the results.
388 proc = subprocess.Popen(cmd, **kwargs)
389 (stdout, stderr) = proc.communicate(input=cmd_input)
Mike Frysinger71928c12020-02-21 23:45:08 -0500390 dbg = ': ' + ' '.join(cmd)
391 if cmd_input is not None:
392 dbg += ' 0<|'
393 if stdout == subprocess.PIPE:
394 dbg += ' 1>|'
395 if stderr == subprocess.PIPE:
396 dbg += ' 2>|'
397 elif stderr == subprocess.STDOUT:
398 dbg += ' 2>&1'
399 trace.print(dbg)
Mike Frysinger6a784ff2020-02-14 23:38:28 -0500400 ret = RunResult(proc.returncode, decode(stdout), decode(stderr))
Mike Frysinger62285d22020-02-12 08:01:38 -0500401
402 # If things failed, print useful debugging output.
403 if check and ret.returncode:
404 print('repo: error: "%s" failed with exit status %s' %
405 (cmd[0], ret.returncode), file=sys.stderr)
406 print(' cwd: %s\n cmd: %r' %
407 (kwargs.get('cwd', os.getcwd()), cmd), file=sys.stderr)
David Pursehousec19cc5c2020-02-14 09:18:15 +0900408
Mike Frysinger62285d22020-02-12 08:01:38 -0500409 def _print_output(name, output):
410 if output:
411 print(' %s:\n >> %s' % (name, '\n >> '.join(output.splitlines())),
412 file=sys.stderr)
David Pursehousec19cc5c2020-02-14 09:18:15 +0900413
Mike Frysinger62285d22020-02-12 08:01:38 -0500414 _print_output('stdout', ret.stdout)
415 _print_output('stderr', ret.stderr)
416 raise RunError(ret)
417
418 return ret
419
420
Simran Basi8ce50412015-08-28 14:25:44 -0700421_gitc_manifest_dir = None
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700422
423
Simran Basi8ce50412015-08-28 14:25:44 -0700424def get_gitc_manifest_dir():
425 global _gitc_manifest_dir
426 if _gitc_manifest_dir is None:
Dan Willemsen2487cb72015-08-31 15:45:06 -0700427 _gitc_manifest_dir = ''
Simran Basi8ce50412015-08-28 14:25:44 -0700428 try:
429 with open(GITC_CONFIG_FILE, 'r') as gitc_config:
430 for line in gitc_config:
431 match = re.match('gitc_dir=(?P<gitc_manifest_dir>.*)', line)
432 if match:
433 _gitc_manifest_dir = match.group('gitc_manifest_dir')
434 except IOError:
Dan Willemsen2487cb72015-08-31 15:45:06 -0700435 pass
Simran Basi8ce50412015-08-28 14:25:44 -0700436 return _gitc_manifest_dir
437
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700438
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700439def gitc_parse_clientdir(gitc_fs_path):
440 """Parse a path in the GITC FS and return its client name.
441
442 @param gitc_fs_path: A subdirectory path within the GITC_FS_ROOT_DIR.
443
444 @returns: The GITC client name
445 """
446 if gitc_fs_path == GITC_FS_ROOT_DIR:
447 return None
448 if not gitc_fs_path.startswith(GITC_FS_ROOT_DIR):
449 manifest_dir = get_gitc_manifest_dir()
450 if manifest_dir == '':
451 return None
452 if manifest_dir[-1] != '/':
453 manifest_dir += '/'
454 if gitc_fs_path == manifest_dir:
455 return None
456 if not gitc_fs_path.startswith(manifest_dir):
457 return None
458 return gitc_fs_path.split(manifest_dir)[1].split('/')[0]
459 return gitc_fs_path.split(GITC_FS_ROOT_DIR)[1].split('/')[0]
460
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700461
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700462class CloneFailure(Exception):
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700463
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700464 """Indicate the remote clone of repo itself failed.
465 """
466
467
Mike Frysinger3599cc32020-02-29 02:53:41 -0500468def check_repo_verify(repo_verify, quiet=False):
469 """Check the --repo-verify state."""
470 if not repo_verify:
471 print('repo: warning: verification of repo code has been disabled;\n'
472 'repo will not be able to verify the integrity of itself.\n',
473 file=sys.stderr)
474 return False
475
476 if NeedSetupGnuPG():
477 return SetupGnuPG(quiet)
478
479 return True
480
481
482def check_repo_rev(dst, rev, repo_verify=True, quiet=False):
483 """Check that |rev| is valid."""
484 do_verify = check_repo_verify(repo_verify, quiet=quiet)
485 remote_ref, local_rev = resolve_repo_rev(dst, rev)
486 if not quiet and not remote_ref.startswith('refs/heads/'):
487 print('warning: repo is not tracking a remote branch, so it will not '
488 'receive updates', file=sys.stderr)
489 if do_verify:
490 rev = verify_rev(dst, remote_ref, local_rev, quiet)
491 else:
492 rev = local_rev
493 return (remote_ref, rev)
494
495
Simran Basi1efc2b42015-08-05 15:04:22 -0700496def _Init(args, gitc_init=False):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700497 """Installs repo by cloning it over the network.
498 """
Mike Frysingerd8fda902020-02-14 00:24:38 -0500499 parser = GetParser(gitc_init=gitc_init)
500 opt, args = parser.parse_args(args)
Xiaodong Xuae0a36c2012-01-31 11:10:09 +0800501 if args:
Mike Frysingerd8fda902020-02-14 00:24:38 -0500502 parser.print_usage()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700503 sys.exit(1)
Mike Frysingeredd3d452020-02-21 23:55:07 -0500504 opt.quiet = opt.output_mode is False
505 opt.verbose = opt.output_mode is True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700506
Xin Lid79a4bc2020-05-20 16:03:45 -0700507 if opt.clone_bundle is None:
508 opt.clone_bundle = False if opt.partial_clone else True
509
Mike Frysingere1111f52020-03-14 16:28:31 -0400510 url = opt.repo_url or REPO_URL
Mike Frysingercfc81112020-02-29 02:56:32 -0500511 rev = opt.repo_rev or REPO_REV
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700512
David Jamesbf79c662013-12-26 14:20:13 -0800513 try:
Simran Basi1efc2b42015-08-05 15:04:22 -0700514 if gitc_init:
Simran Basi8ce50412015-08-28 14:25:44 -0700515 gitc_manifest_dir = get_gitc_manifest_dir()
516 if not gitc_manifest_dir:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400517 print('fatal: GITC filesystem is not available. Exiting...',
518 file=sys.stderr)
Simran Basi8ce50412015-08-28 14:25:44 -0700519 sys.exit(1)
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700520 gitc_client = opt.gitc_client
521 if not gitc_client:
522 gitc_client = gitc_parse_clientdir(os.getcwd())
523 if not gitc_client:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400524 print('fatal: GITC client (-c) is required.', file=sys.stderr)
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700525 sys.exit(1)
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700526 client_dir = os.path.join(gitc_manifest_dir, gitc_client)
Simran Basi1efc2b42015-08-05 15:04:22 -0700527 if not os.path.exists(client_dir):
528 os.makedirs(client_dir)
529 os.chdir(client_dir)
530 if os.path.exists(repodir):
531 # This GITC Client has already initialized repo so continue.
532 return
533
David Jamesbf79c662013-12-26 14:20:13 -0800534 os.mkdir(repodir)
535 except OSError as e:
536 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400537 print('fatal: cannot make %s directory: %s'
538 % (repodir, e.strerror), file=sys.stderr)
David Pursehouse3794a782012-11-15 06:17:30 +0900539 # Don't raise CloneFailure; that would delete the
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700540 # name. Instead exit immediately.
541 #
542 sys.exit(1)
543
544 _CheckGitVersion()
545 try:
Mike Frysingerdcbfadf2020-02-22 00:04:39 -0500546 if not opt.quiet:
547 print('Downloading Repo source from', url)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700548 dst = os.path.abspath(os.path.join(repodir, S_repo))
Mike Frysingeredd3d452020-02-21 23:55:07 -0500549 _Clone(url, dst, opt.clone_bundle, opt.quiet, opt.verbose)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700550
Mike Frysinger3599cc32020-02-29 02:53:41 -0500551 remote_ref, rev = check_repo_rev(dst, rev, opt.repo_verify, quiet=opt.quiet)
Mike Frysingercfc81112020-02-29 02:56:32 -0500552 _Checkout(dst, remote_ref, rev, opt.quiet)
Sebastian Schuberth993dcac2018-07-13 10:25:52 +0200553
554 if not os.path.isfile(os.path.join(dst, 'repo')):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400555 print("warning: '%s' does not look like a git-repo repository, is "
556 "REPO_URL set correctly?" % url, file=sys.stderr)
Sebastian Schuberth993dcac2018-07-13 10:25:52 +0200557
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700558 except CloneFailure:
559 if opt.quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400560 print('fatal: repo init failed; run without --quiet to see why',
561 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700562 raise
563
564
Mike Frysinger62285d22020-02-12 08:01:38 -0500565def run_git(*args, **kwargs):
566 """Run git and return execution details."""
567 kwargs.setdefault('capture_output', True)
568 kwargs.setdefault('check', True)
569 try:
570 return run_command([GIT] + list(args), **kwargs)
571 except OSError as e:
572 print(file=sys.stderr)
573 print('repo: error: "%s" is not available' % GIT, file=sys.stderr)
574 print('repo: error: %s' % e, file=sys.stderr)
575 print(file=sys.stderr)
576 print('Please make sure %s is installed and in your path.' % GIT,
577 file=sys.stderr)
578 sys.exit(1)
579 except RunError:
580 raise CloneFailure()
581
582
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400583# The git version info broken down into components for easy analysis.
584# Similar to Python's sys.version_info.
585GitVersion = collections.namedtuple(
586 'GitVersion', ('major', 'minor', 'micro', 'full'))
587
David Pursehouse31b9b4b2020-02-13 08:20:14 +0900588
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400589def ParseGitVersion(ver_str=None):
590 if ver_str is None:
591 # Load the version ourselves.
Mike Frysinger62285d22020-02-12 08:01:38 -0500592 ver_str = run_git('--version').stdout
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400593
Conley Owensff0a3c82014-01-30 14:46:03 -0800594 if not ver_str.startswith('git version '):
595 return None
596
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400597 full_version = ver_str[len('git version '):].strip()
598 num_ver_str = full_version.split('-')[0]
Conley Owensff0a3c82014-01-30 14:46:03 -0800599 to_tuple = []
600 for num_str in num_ver_str.split('.')[:3]:
601 if num_str.isdigit():
602 to_tuple.append(int(num_str))
603 else:
604 to_tuple.append(0)
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400605 to_tuple.append(full_version)
606 return GitVersion(*to_tuple)
Conley Owensff0a3c82014-01-30 14:46:03 -0800607
608
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400609def _CheckGitVersion():
Mike Frysinger62285d22020-02-12 08:01:38 -0500610 ver_act = ParseGitVersion()
Conley Owensff0a3c82014-01-30 14:46:03 -0800611 if ver_act is None:
Mike Frysinger4c263b52019-09-11 04:04:16 -0400612 print('fatal: unable to detect git version', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700613 raise CloneFailure()
614
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700615 if ver_act < MIN_GIT_VERSION:
David Pursehouse685f0802012-11-14 08:34:39 +0900616 need = '.'.join(map(str, MIN_GIT_VERSION))
Mike Frysinger587f1622020-03-23 16:49:11 -0400617 print('fatal: git %s or later required; found %s' % (need, ver_act.full),
618 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700619 raise CloneFailure()
620
621
Mike Frysinger84094102020-02-11 02:10:28 -0500622def SetGitTrace2ParentSid(env=None):
623 """Set up GIT_TRACE2_PARENT_SID for git tracing."""
624 # We roughly follow the format git itself uses in trace2/tr2_sid.c.
625 # (1) Be unique (2) be valid filename (3) be fixed length.
626 #
627 # Since we always export this variable, we try to avoid more expensive calls.
628 # e.g. We don't attempt hostname lookups or hashing the results.
629 if env is None:
630 env = os.environ
631
632 KEY = 'GIT_TRACE2_PARENT_SID'
633
634 now = datetime.datetime.utcnow()
635 value = 'repo-%s-P%08x' % (now.strftime('%Y%m%dT%H%M%SZ'), os.getpid())
636
637 # If it's already set, then append ourselves.
638 if KEY in env:
639 value = env[KEY] + '/' + value
640
641 _setenv(KEY, value, env=env)
642
643
644def _setenv(key, value, env=None):
645 """Set |key| in the OS environment |env| to |value|."""
646 if env is None:
647 env = os.environ
648 # Environment handling across systems is messy.
649 try:
650 env[key] = value
651 except UnicodeEncodeError:
652 env[key] = value.encode()
653
654
Conley Owensc9129d92012-10-01 16:12:28 -0700655def NeedSetupGnuPG():
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700656 if not os.path.isdir(home_dot_repo):
657 return True
658
659 kv = os.path.join(home_dot_repo, 'keyring-version')
660 if not os.path.exists(kv):
661 return True
662
663 kv = open(kv).read()
664 if not kv:
665 return True
666
David Pursehouse685f0802012-11-14 08:34:39 +0900667 kv = tuple(map(int, kv.split('.')))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700668 if kv < KEYRING_VERSION:
669 return True
670 return False
671
672
Conley Owensc9129d92012-10-01 16:12:28 -0700673def SetupGnuPG(quiet):
David Jamesbf79c662013-12-26 14:20:13 -0800674 try:
675 os.mkdir(home_dot_repo)
676 except OSError as e:
677 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400678 print('fatal: cannot make %s directory: %s'
679 % (home_dot_repo, e.strerror), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700680 sys.exit(1)
681
David Jamesbf79c662013-12-26 14:20:13 -0800682 try:
683 os.mkdir(gpg_dir, stat.S_IRWXU)
684 except OSError as e:
685 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400686 print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror),
687 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700688 sys.exit(1)
689
Mike Frysinger19a1f222020-02-14 16:28:13 -0500690 if not quiet:
691 print('repo: Updating release signing keys to keyset ver %s' %
692 ('.'.join(str(x) for x in KEYRING_VERSION),))
693 # NB: We use --homedir (and cwd below) because some environments (Windows) do
694 # not correctly handle full native paths. We avoid the issue by changing to
695 # the right dir with cwd=gpg_dir before executing gpg, and then telling gpg to
696 # use the cwd (.) as its homedir which leaves the path resolution logic to it.
697 cmd = ['gpg', '--homedir', '.', '--import']
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700698 try:
Mike Frysinger19a1f222020-02-14 16:28:13 -0500699 # gpg can be pretty chatty. Always capture the output and if something goes
700 # wrong, the builtin check failure will dump stdout & stderr for debugging.
701 run_command(cmd, stdin=subprocess.PIPE, capture_output=True,
702 cwd=gpg_dir, check=True,
David Pursehousec19cc5c2020-02-14 09:18:15 +0900703 input=MAINTAINER_KEYS.encode('utf-8'))
David Pursehouse22dbfb92020-02-13 08:20:55 +0900704 except OSError:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700705 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400706 print('warning: gpg (GnuPG) is not available.', file=sys.stderr)
707 print('warning: Installing it is strongly encouraged.', file=sys.stderr)
708 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700709 return False
710
Mike Frysinger3164d402019-11-11 05:40:22 -0500711 with open(os.path.join(home_dot_repo, 'keyring-version'), 'w') as fd:
712 fd.write('.'.join(map(str, KEYRING_VERSION)) + '\n')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700713 return True
714
715
Mike Frysinger62285d22020-02-12 08:01:38 -0500716def _SetConfig(cwd, name, value):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700717 """Set a git configuration option to the specified value.
718 """
Mike Frysinger62285d22020-02-12 08:01:38 -0500719 run_git('config', name, value, cwd=cwd)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700720
721
Mike Frysinger949bc342020-02-18 21:37:00 -0500722def _GetRepoConfig(name):
723 """Read a repo configuration option."""
724 config = os.path.join(home_dot_repo, 'config')
725 if not os.path.exists(config):
726 return None
727
728 cmd = ['config', '--file', config, '--get', name]
729 ret = run_git(*cmd, check=False)
730 if ret.returncode == 0:
731 return ret.stdout
732 elif ret.returncode == 1:
733 return None
734 else:
735 print('repo: error: git %s failed:\n%s' % (' '.join(cmd), ret.stderr),
736 file=sys.stderr)
737 raise RunError()
738
739
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700740def _InitHttp():
741 handlers = []
742
Sarah Owens1f7627f2012-10-31 09:21:55 -0700743 mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700744 try:
745 import netrc
746 n = netrc.netrc()
747 for host in n.hosts:
748 p = n.hosts[host]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700749 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
Xiaodong Xuae0a36c2012-01-31 11:10:09 +0800750 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
David Pursehouse58a8b5c2020-02-13 08:21:28 +0900751 except Exception:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700752 pass
Sarah Owens1f7627f2012-10-31 09:21:55 -0700753 handlers.append(urllib.request.HTTPBasicAuthHandler(mgr))
754 handlers.append(urllib.request.HTTPDigestAuthHandler(mgr))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700755
756 if 'http_proxy' in os.environ:
757 url = os.environ['http_proxy']
Sarah Owens1f7627f2012-10-31 09:21:55 -0700758 handlers.append(urllib.request.ProxyHandler({'http': url, 'https': url}))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700759 if 'REPO_CURL_VERBOSE' in os.environ:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700760 handlers.append(urllib.request.HTTPHandler(debuglevel=1))
761 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
762 urllib.request.install_opener(urllib.request.build_opener(*handlers))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700763
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700764
Mike Frysingeredd3d452020-02-21 23:55:07 -0500765def _Fetch(url, cwd, src, quiet, verbose):
Mike Frysinger62285d22020-02-12 08:01:38 -0500766 cmd = ['fetch']
Mike Frysinger4847e052020-02-22 00:07:35 -0500767 if not verbose:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700768 cmd.append('--quiet')
Mike Frysinger4847e052020-02-22 00:07:35 -0500769 err = None
770 if not quiet and sys.stdout.isatty():
771 cmd.append('--progress')
772 elif not verbose:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700773 err = subprocess.PIPE
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700774 cmd.append(src)
775 cmd.append('+refs/heads/*:refs/remotes/origin/*')
Xin Li6e538442018-12-10 11:33:16 -0800776 cmd.append('+refs/tags/*:refs/tags/*')
Mike Frysinger4847e052020-02-22 00:07:35 -0500777 run_git(*cmd, stderr=err, capture_output=False, cwd=cwd)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700778
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700779
Mike Frysingeredd3d452020-02-21 23:55:07 -0500780def _DownloadBundle(url, cwd, quiet, verbose):
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700781 if not url.endswith('/'):
782 url += '/'
783 url += 'clone.bundle'
784
Mike Frysinger62285d22020-02-12 08:01:38 -0500785 ret = run_git('config', '--get-regexp', 'url.*.insteadof', cwd=cwd,
786 check=False)
787 for line in ret.stdout.splitlines():
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700788 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
789 if m:
790 new_url = m.group(1)
791 old_url = m.group(2)
792 if url.startswith(old_url):
793 url = new_url + url[len(old_url):]
794 break
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700795
796 if not url.startswith('http:') and not url.startswith('https:'):
797 return False
798
Mike Frysinger62285d22020-02-12 08:01:38 -0500799 dest = open(os.path.join(cwd, '.git', 'clone.bundle'), 'w+b')
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700800 try:
801 try:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700802 r = urllib.request.urlopen(url)
803 except urllib.error.HTTPError as e:
John Törnblomd3ddcdb2015-08-12 20:12:51 +0200804 if e.code in [401, 403, 404, 501]:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700805 return False
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400806 print('fatal: Cannot get %s' % url, file=sys.stderr)
807 print('fatal: HTTP error %s' % e.code, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700808 raise CloneFailure()
Sarah Owens1f7627f2012-10-31 09:21:55 -0700809 except urllib.error.URLError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400810 print('fatal: Cannot get %s' % url, file=sys.stderr)
811 print('fatal: error %s' % e.reason, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700812 raise CloneFailure()
813 try:
Mike Frysingerdcbfadf2020-02-22 00:04:39 -0500814 if verbose:
815 print('Downloading clone bundle %s' % url, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700816 while True:
817 buf = r.read(8192)
Mike Frysinger1b9adab2019-07-04 17:54:54 -0400818 if not buf:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700819 return True
820 dest.write(buf)
821 finally:
822 r.close()
823 finally:
824 dest.close()
825
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700826
Mike Frysinger62285d22020-02-12 08:01:38 -0500827def _ImportBundle(cwd):
828 path = os.path.join(cwd, '.git', 'clone.bundle')
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700829 try:
Mike Frysingeredd3d452020-02-21 23:55:07 -0500830 _Fetch(cwd, cwd, path, True, False)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700831 finally:
832 os.remove(path)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700833
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700834
Mike Frysingeredd3d452020-02-21 23:55:07 -0500835def _Clone(url, cwd, clone_bundle, quiet, verbose):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700836 """Clones a git repository to a new subdirectory of repodir
837 """
Mike Frysingerdcbfadf2020-02-22 00:04:39 -0500838 if verbose:
839 print('Cloning git repository', url)
840
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700841 try:
Mike Frysinger62285d22020-02-12 08:01:38 -0500842 os.mkdir(cwd)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700843 except OSError as e:
Mike Frysinger62285d22020-02-12 08:01:38 -0500844 print('fatal: cannot make %s directory: %s' % (cwd, e.strerror),
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400845 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700846 raise CloneFailure()
847
Mike Frysinger62285d22020-02-12 08:01:38 -0500848 run_git('init', '--quiet', cwd=cwd)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700849
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700850 _InitHttp()
Mike Frysinger62285d22020-02-12 08:01:38 -0500851 _SetConfig(cwd, 'remote.origin.url', url)
852 _SetConfig(cwd,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700853 'remote.origin.fetch',
854 '+refs/heads/*:refs/remotes/origin/*')
Mike Frysingeredd3d452020-02-21 23:55:07 -0500855 if clone_bundle and _DownloadBundle(url, cwd, quiet, verbose):
Mike Frysinger62285d22020-02-12 08:01:38 -0500856 _ImportBundle(cwd)
Mike Frysingeredd3d452020-02-21 23:55:07 -0500857 _Fetch(url, cwd, 'origin', quiet, verbose)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700858
859
Mike Frysingercfc81112020-02-29 02:56:32 -0500860def resolve_repo_rev(cwd, committish):
861 """Figure out what REPO_REV represents.
862
863 We support:
864 * refs/heads/xxx: Branch.
865 * refs/tags/xxx: Tag.
866 * xxx: Branch or tag or commit.
867
868 Args:
869 cwd: The git checkout to run in.
870 committish: The REPO_REV argument to resolve.
871
872 Returns:
873 A tuple of (remote ref, commit) as makes sense for the committish.
874 For branches, this will look like ('refs/heads/stable', <revision>).
875 For tags, this will look like ('refs/tags/v1.0', <revision>).
876 For commits, this will be (<revision>, <revision>).
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700877 """
Mike Frysingercfc81112020-02-29 02:56:32 -0500878 def resolve(committish):
879 ret = run_git('rev-parse', '--verify', '%s^{commit}' % (committish,),
880 cwd=cwd, check=False)
881 return None if ret.returncode else ret.stdout.strip()
882
883 # An explicit branch.
884 if committish.startswith('refs/heads/'):
885 remote_ref = committish
886 committish = committish[len('refs/heads/'):]
887 rev = resolve('refs/remotes/origin/%s' % committish)
888 if rev is None:
889 print('repo: error: unknown branch "%s"' % (committish,),
890 file=sys.stderr)
891 raise CloneFailure()
892 return (remote_ref, rev)
893
894 # An explicit tag.
895 if committish.startswith('refs/tags/'):
896 remote_ref = committish
897 committish = committish[len('refs/tags/'):]
898 rev = resolve(remote_ref)
899 if rev is None:
900 print('repo: error: unknown tag "%s"' % (committish,),
901 file=sys.stderr)
902 raise CloneFailure()
903 return (remote_ref, rev)
904
905 # See if it's a short branch name.
906 rev = resolve('refs/remotes/origin/%s' % committish)
907 if rev:
908 return ('refs/heads/%s' % (committish,), rev)
909
910 # See if it's a tag.
911 rev = resolve('refs/tags/%s' % committish)
912 if rev:
913 return ('refs/tags/%s' % (committish,), rev)
914
915 # See if it's a commit.
916 rev = resolve(committish)
917 if rev and rev.lower().startswith(committish.lower()):
918 return (rev, rev)
919
920 # Give up!
921 print('repo: error: unable to resolve "%s"' % (committish,), file=sys.stderr)
922 raise CloneFailure()
923
924
Mike Frysinger3599cc32020-02-29 02:53:41 -0500925def verify_rev(cwd, remote_ref, rev, quiet):
Mike Frysingercfc81112020-02-29 02:56:32 -0500926 """Verify the commit has been signed by a tag."""
927 ret = run_git('describe', rev, cwd=cwd)
928 cur = ret.stdout.strip()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700929
930 m = re.compile(r'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur)
931 if m:
932 cur = m.group(1)
933 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400934 print(file=sys.stderr)
Mike Frysingercfc81112020-02-29 02:56:32 -0500935 print("warning: '%s' is not signed; falling back to signed release '%s'"
936 % (remote_ref, cur), file=sys.stderr)
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400937 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700938
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800939 env = os.environ.copy()
Mike Frysinger84094102020-02-11 02:10:28 -0500940 _setenv('GNUPGHOME', gpg_dir, env)
Mike Frysinger62285d22020-02-12 08:01:38 -0500941 run_git('tag', '-v', cur, cwd=cwd, env=env)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700942 return '%s^0' % cur
943
944
Mike Frysingercfc81112020-02-29 02:56:32 -0500945def _Checkout(cwd, remote_ref, rev, quiet):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700946 """Checkout an upstream branch into the repository and track it.
947 """
Mike Frysinger62285d22020-02-12 08:01:38 -0500948 run_git('update-ref', 'refs/heads/default', rev, cwd=cwd)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700949
950 _SetConfig(cwd, 'branch.default.remote', 'origin')
Mike Frysingercfc81112020-02-29 02:56:32 -0500951 _SetConfig(cwd, 'branch.default.merge', remote_ref)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700952
Mike Frysinger62285d22020-02-12 08:01:38 -0500953 run_git('symbolic-ref', 'HEAD', 'refs/heads/default', cwd=cwd)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700954
Mike Frysinger62285d22020-02-12 08:01:38 -0500955 cmd = ['read-tree', '--reset', '-u']
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700956 if not quiet:
957 cmd.append('-v')
958 cmd.append('HEAD')
Mike Frysinger62285d22020-02-12 08:01:38 -0500959 run_git(*cmd, cwd=cwd)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700960
961
962def _FindRepo():
963 """Look for a repo installation, starting at the current directory.
964 """
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200965 curdir = os.getcwd()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700966 repo = None
967
Anthony Newnamdf14a702011-01-09 17:31:57 -0800968 olddir = None
Jonathan Nieder6248e0f2020-10-28 11:27:41 -0700969 while curdir != olddir and not repo:
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200970 repo = os.path.join(curdir, repodir, REPO_MAIN)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700971 if not os.path.isfile(repo):
972 repo = None
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200973 olddir = curdir
974 curdir = os.path.dirname(curdir)
975 return (repo, os.path.join(curdir, repodir))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700976
977
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700978class _Options(object):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700979 help = False
Mike Frysinger8ddff5c2020-02-09 15:00:25 -0500980 version = False
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700981
982
Mike Frysinger949bc342020-02-18 21:37:00 -0500983def _ExpandAlias(name):
984 """Look up user registered aliases."""
985 # We don't resolve aliases for existing subcommands. This matches git.
986 if name in {'gitc-init', 'help', 'init'}:
987 return name, []
988
989 alias = _GetRepoConfig('alias.%s' % (name,))
990 if alias is None:
991 return name, []
992
993 args = alias.strip().split(' ', 1)
994 name = args[0]
995 if len(args) == 2:
996 args = shlex.split(args[1])
997 else:
998 args = []
999 return name, args
1000
1001
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001002def _ParseArguments(args):
1003 cmd = None
1004 opt = _Options()
1005 arg = []
1006
Sarah Owensa6053d52012-11-01 13:36:50 -07001007 for i in range(len(args)):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001008 a = args[i]
1009 if a == '-h' or a == '--help':
1010 opt.help = True
Mike Frysinger8ddff5c2020-02-09 15:00:25 -05001011 elif a == '--version':
1012 opt.version = True
Mike Frysinger6fb0cb52020-02-12 09:39:23 -05001013 elif a == '--trace':
1014 trace.set(True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001015 elif not a.startswith('-'):
1016 cmd = a
1017 arg = args[i + 1:]
1018 break
1019 return cmd, opt, arg
1020
1021
1022def _Usage():
Dan Willemsen9ff2ece2015-08-31 15:45:06 -07001023 gitc_usage = ""
1024 if get_gitc_manifest_dir():
1025 gitc_usage = " gitc-init Initialize a GITC Client.\n"
1026
Mike Frysingerc92ce5c2019-06-13 01:14:23 -04001027 print(
Mark E. Hamilton4088eb42016-02-10 10:44:30 -07001028 """usage: repo COMMAND [ARGS]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001029
1030repo is not yet installed. Use "repo init" to install it here.
1031
1032The most commonly used repo commands are:
1033
1034 init Install repo in the current working directory
Dan Willemsen9ff2ece2015-08-31 15:45:06 -07001035""" + gitc_usage +
Mark E. Hamilton4088eb42016-02-10 10:44:30 -07001036 """ help Display detailed help on a command
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001037
1038For access to the full online help, install repo ("repo init").
Mike Frysinger35159ab2019-06-13 00:07:13 -04001039""")
1040 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001041
1042
1043def _Help(args):
1044 if args:
Mike Frysingerd8fda902020-02-14 00:24:38 -05001045 if args[0] in {'init', 'gitc-init'}:
1046 parser = GetParser(gitc_init=args[0] == 'gitc-init')
1047 parser.print_help()
Dan Willemsen9ff2ece2015-08-31 15:45:06 -07001048 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001049 else:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -04001050 print("error: '%s' is not a bootstrap command.\n"
1051 ' For access to online help, install repo ("repo init").'
1052 % args[0], file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001053 else:
1054 _Usage()
1055 sys.exit(1)
1056
1057
Mike Frysinger8ddff5c2020-02-09 15:00:25 -05001058def _Version():
1059 """Show version information."""
1060 print('<repo not installed>')
1061 print('repo launcher version %s' % ('.'.join(str(x) for x in VERSION),))
1062 print(' (from %s)' % (__file__,))
1063 print('git %s' % (ParseGitVersion().full,))
1064 print('Python %s' % sys.version)
Mike Frysinger5f11eac2020-02-25 15:09:01 -05001065 uname = platform.uname()
Mike Frysingere257d562020-03-23 16:55:02 -04001066 if sys.version_info.major < 3:
1067 # Python 3 returns a named tuple, but Python 2 is simpler.
1068 print(uname)
1069 else:
1070 print('OS %s %s (%s)' % (uname.system, uname.release, uname.version))
1071 print('CPU %s (%s)' %
1072 (uname.machine, uname.processor if uname.processor else 'unknown'))
Mike Frysinger8ddff5c2020-02-09 15:00:25 -05001073 sys.exit(0)
1074
1075
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001076def _NotInstalled():
Mike Frysingerc92ce5c2019-06-13 01:14:23 -04001077 print('error: repo is not installed. Use "repo init" to install it here.',
1078 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001079 sys.exit(1)
1080
1081
1082def _NoCommands(cmd):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -04001083 print("""error: command '%s' requires repo to be installed first.
1084 Use "repo init" to install it here.""" % cmd, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001085 sys.exit(1)
1086
1087
1088def _RunSelf(wrapper_path):
1089 my_dir = os.path.dirname(wrapper_path)
1090 my_main = os.path.join(my_dir, 'main.py')
1091 my_git = os.path.join(my_dir, '.git')
1092
1093 if os.path.isfile(my_main) and os.path.isdir(my_git):
Shawn O. Pearcec8a300f2009-05-18 13:19:57 -07001094 for name in ['git_config.py',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001095 'project.py',
1096 'subcmds']:
1097 if not os.path.exists(os.path.join(my_dir, name)):
1098 return None, None
1099 return my_main, my_git
1100 return None, None
1101
1102
1103def _SetDefaultsTo(gitdir):
1104 global REPO_URL
1105 global REPO_REV
1106
1107 REPO_URL = gitdir
Mike Frysingercdb344c2020-03-24 02:43:46 -04001108 ret = run_git('--git-dir=%s' % gitdir, 'symbolic-ref', 'HEAD', check=False)
1109 if ret.returncode:
1110 # If we're not tracking a branch (bisect/etc...), then fall back to commit.
1111 print('repo: warning: %s has no current branch; using HEAD' % gitdir,
1112 file=sys.stderr)
1113 try:
1114 ret = run_git('rev-parse', 'HEAD', cwd=gitdir)
1115 except CloneFailure:
1116 print('fatal: %s has invalid HEAD' % gitdir, file=sys.stderr)
1117 sys.exit(1)
1118
1119 REPO_REV = ret.stdout.strip()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001120
1121
1122def main(orig_args):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001123 cmd, opt, args = _ParseArguments(orig_args)
1124
Mike Frysinger84094102020-02-11 02:10:28 -05001125 # We run this early as we run some git commands ourselves.
1126 SetGitTrace2ParentSid()
1127
Dan Willemsen745b4ad2015-10-06 15:23:19 -07001128 repo_main, rel_repo_dir = None, None
1129 # Don't use the local repo copy, make sure to switch to the gitc client first.
1130 if cmd != 'gitc-init':
1131 repo_main, rel_repo_dir = _FindRepo()
1132
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001133 wrapper_path = os.path.abspath(__file__)
1134 my_main, my_git = _RunSelf(wrapper_path)
1135
Simran Basi8ce50412015-08-28 14:25:44 -07001136 cwd = os.getcwd()
Dan Willemsen2487cb72015-08-31 15:45:06 -07001137 if get_gitc_manifest_dir() and cwd.startswith(get_gitc_manifest_dir()):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -04001138 print('error: repo cannot be used in the GITC local manifest directory.'
1139 '\nIf you want to work on this GITC client please rerun this '
1140 'command from the corresponding client under /gitc/',
1141 file=sys.stderr)
Simran Basi8ce50412015-08-28 14:25:44 -07001142 sys.exit(1)
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +02001143 if not repo_main:
Mike Frysinger949bc342020-02-18 21:37:00 -05001144 # Only expand aliases here since we'll be parsing the CLI ourselves.
1145 # If we had repo_main, alias expansion would happen in main.py.
1146 cmd, alias_args = _ExpandAlias(cmd)
1147 args = alias_args + args
1148
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001149 if opt.help:
1150 _Usage()
1151 if cmd == 'help':
1152 _Help(args)
Mike Frysinger8ddff5c2020-02-09 15:00:25 -05001153 if opt.version or cmd == 'version':
1154 _Version()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001155 if not cmd:
1156 _NotInstalled()
Simran Basi1efc2b42015-08-05 15:04:22 -07001157 if cmd == 'init' or cmd == 'gitc-init':
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001158 if my_git:
1159 _SetDefaultsTo(my_git)
1160 try:
Simran Basi1efc2b42015-08-05 15:04:22 -07001161 _Init(args, gitc_init=(cmd == 'gitc-init'))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001162 except CloneFailure:
Sebastian Schuberth27226e72016-10-28 14:27:43 +02001163 path = os.path.join(repodir, S_repo)
Mike Frysingerc92ce5c2019-06-13 01:14:23 -04001164 print("fatal: cloning the git-repo repository failed, will remove "
1165 "'%s' " % path, file=sys.stderr)
Sebastian Schuberth27226e72016-10-28 14:27:43 +02001166 shutil.rmtree(path, ignore_errors=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001167 sys.exit(1)
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +02001168 repo_main, rel_repo_dir = _FindRepo()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001169 else:
1170 _NoCommands(cmd)
1171
1172 if my_main:
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +02001173 repo_main = my_main
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001174
Konrad Weihmann433977e2020-04-17 21:39:32 +02001175 if not repo_main:
1176 print("fatal: unable to find repo entry point", file=sys.stderr)
1177 sys.exit(1)
1178
David Pursehouse685f0802012-11-14 08:34:39 +09001179 ver_str = '.'.join(map(str, VERSION))
anatoly techtonik3a2a59e2013-09-21 19:29:10 +03001180 me = [sys.executable, repo_main,
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +02001181 '--repo-dir=%s' % rel_repo_dir,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001182 '--wrapper-version=%s' % ver_str,
1183 '--wrapper-path=%s' % wrapper_path,
1184 '--']
1185 me.extend(orig_args)
Mike Frysinger3ba716f2019-06-13 01:48:12 -04001186 exec_command(me)
1187 print("fatal: unable to start %s" % repo_main, file=sys.stderr)
1188 sys.exit(148)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001189
1190
1191if __name__ == '__main__':
1192 main(sys.argv[1:])