blob: 01d5c46dda67f80b2e22e473be8113fe8c9ca61d [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 -*-
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07003
Mike Frysinger87fb5a12019-06-13 01:54:46 -04004"""Repo launcher.
5
6This is a standalone tool that people may copy to anywhere in their system.
7It is used to get an initial repo client checkout, and after that it runs the
8copy of repo in the checkout.
9"""
10
Mike Frysingerc92ce5c2019-06-13 01:14:23 -040011from __future__ import print_function
12
Mike Frysinger3ba716f2019-06-13 01:48:12 -040013import os
14import platform
15import subprocess
16import sys
17
18
19def exec_command(cmd):
20 """Execute |cmd| or return None on failure."""
21 try:
22 if platform.system() == 'Windows':
23 ret = subprocess.call(cmd)
24 sys.exit(ret)
25 else:
26 os.execvp(cmd[0], cmd)
27 except:
28 pass
29
30
31def check_python_version():
32 """Make sure the active Python version is recent enough."""
33 def reexec(prog):
34 exec_command([prog] + sys.argv)
35
36 MIN_PYTHON_VERSION = (3, 6)
37
38 ver = sys.version_info
39 major = ver.major
40 minor = ver.minor
41
42 # Abort on very old Python 2 versions.
43 if (major, minor) < (2, 7):
44 print('repo: error: Your Python version is too old. '
45 'Please use Python {}.{} or newer instead.'.format(
46 *MIN_PYTHON_VERSION), file=sys.stderr)
47 sys.exit(1)
48
49 # Try to re-exec the version specific Python 3 if needed.
50 if (major, minor) < MIN_PYTHON_VERSION:
51 # Python makes releases ~once a year, so try our min version +10 to help
52 # bridge the gap. This is the fallback anyways so perf isn't critical.
53 min_major, min_minor = MIN_PYTHON_VERSION
54 for inc in range(0, 10):
55 reexec('python{}.{}'.format(min_major, min_minor + inc))
56
57 # Try the generic Python 3 wrapper, but only if it's new enough. We don't
58 # want to go from (still supported) Python 2.7 to (unsupported) Python 3.5.
59 try:
60 proc = subprocess.Popen(
61 ['python3', '-c', 'import sys; '
62 'print(sys.version_info.major, sys.version_info.minor)'],
63 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
64 (output, _) = proc.communicate()
65 python3_ver = tuple(int(x) for x in output.decode('utf-8').split())
66 except (OSError, subprocess.CalledProcessError):
67 python3_ver = None
68
69 # The python3 version looks like it's new enough, so give it a try.
70 if python3_ver and python3_ver >= MIN_PYTHON_VERSION:
71 reexec('python3')
72
73 # We're still here, so diagnose things for the user.
74 if major < 3:
75 print('repo: warning: Python 2 is no longer supported; '
76 'Please upgrade to Python {}.{}+.'.format(*MIN_PYTHON_VERSION),
77 file=sys.stderr)
78 else:
79 print('repo: error: Python 3 version is too old; '
80 'Please use Python {}.{} or newer.'.format(*MIN_PYTHON_VERSION),
81 file=sys.stderr)
82 sys.exit(1)
83
84
85if __name__ == '__main__':
86 # TODO(vapier): Enable this on Windows once we have Python 3 issues fixed.
87 if platform.system() != 'Windows':
88 check_python_version()
89
90
Mark E. Hamilton4088eb42016-02-10 10:44:30 -070091# repo default configuration
92#
Mark E. Hamilton55536282016-02-03 15:49:43 -070093import os
94REPO_URL = os.environ.get('REPO_URL', None)
95if not REPO_URL:
96 REPO_URL = 'https://gerrit.googlesource.com/git-repo'
Mike Frysinger563f1a62020-02-05 23:52:07 -050097REPO_REV = os.environ.get('REPO_REV')
98if not REPO_REV:
99 REPO_REV = 'stable'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700100
101# Copyright (C) 2008 Google Inc.
102#
103# Licensed under the Apache License, Version 2.0 (the "License");
104# you may not use this file except in compliance with the License.
105# You may obtain a copy of the License at
106#
107# http://www.apache.org/licenses/LICENSE-2.0
108#
109# Unless required by applicable law or agreed to in writing, software
110# distributed under the License is distributed on an "AS IS" BASIS,
111# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
112# See the License for the specific language governing permissions and
113# limitations under the License.
114
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700115# increment this whenever we make important changes to this script
Mike Frysingeree451f02020-02-04 00:00:08 -0500116VERSION = (2, 0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700117
118# increment this if the MAINTAINER_KEYS block is modified
Mike Frysingerf5525fb2020-02-04 00:01:00 -0500119KEYRING_VERSION = (2, 0)
Mike Frysingere4433652016-09-13 18:06:07 -0400120
121# Each individual key entry is created by using:
122# gpg --armor --export keyid
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700123MAINTAINER_KEYS = """
124
125 Repo Maintainer <repo@android.kernel.org>
126-----BEGIN PGP PUBLIC KEY BLOCK-----
127Version: GnuPG v1.4.2.2 (GNU/Linux)
128
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
164=CMiZ
165-----END PGP PUBLIC KEY BLOCK-----
166"""
167
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700168GIT = 'git' # our git command
Mike Frysinger82caef62020-02-11 18:51:08 -0500169# NB: The version of git that the repo launcher requires may be much older than
170# the version of git that the main repo source tree requires. Keeping this at
171# an older version also makes it easier for users to upgrade/rollback as needed.
172#
173# git-1.7 is in (EOL) Ubuntu Precise.
174MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700175repodir = '.repo' # name of repo's private directory
176S_repo = 'repo' # special repo repository
177S_manifests = 'manifests' # special manifest repository
178REPO_MAIN = S_repo + '/main.py' # main script
Simran Basi8ce50412015-08-28 14:25:44 -0700179GITC_CONFIG_FILE = '/gitc/.config'
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700180GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700181
182
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400183import collections
David Jamesbf79c662013-12-26 14:20:13 -0800184import errno
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700185import optparse
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700186import re
Mitchel Humpheryseb5acc92014-03-12 10:48:15 -0700187import shutil
Sarah Owens60798a32012-10-25 17:53:09 -0700188import stat
David Pursehouse59bbb582013-05-17 10:49:33 +0900189
190if sys.version_info[0] == 3:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700191 import urllib.request
192 import urllib.error
193else:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700194 import imp
David Pursehouse59bbb582013-05-17 10:49:33 +0900195 import urllib2
Sarah Owens1f7627f2012-10-31 09:21:55 -0700196 urllib = imp.new_module('urllib')
197 urllib.request = urllib2
198 urllib.error = urllib2
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700199
Conley Owens5e0ee142013-09-26 15:50:49 -0700200
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700201home_dot_repo = os.path.expanduser('~/.repoconfig')
202gpg_dir = os.path.join(home_dot_repo, 'gnupg')
203
204extra_args = []
205init_optparse = optparse.OptionParser(usage="repo init -u url [options]")
206
207# Logging
208group = init_optparse.add_option_group('Logging options')
209group.add_option('-q', '--quiet',
210 dest="quiet", action="store_true", default=False,
211 help="be quiet")
212
213# Manifest
214group = init_optparse.add_option_group('Manifest options')
215group.add_option('-u', '--manifest-url',
216 dest='manifest_url',
217 help='manifest repository location', metavar='URL')
218group.add_option('-b', '--manifest-branch',
219 dest='manifest_branch',
220 help='manifest branch or revision', metavar='REVISION')
221group.add_option('-m', '--manifest-name',
222 dest='manifest_name',
223 help='initial manifest file', metavar='NAME.xml')
Ereth McKnight-MacNeil12ee5442018-12-19 21:28:35 -0800224group.add_option('--current-branch',
Naseer Ahmedf4dda9a2016-12-01 18:49:54 -0500225 dest='current_branch_only', action='store_true',
226 help='fetch only current manifest branch from server')
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800227group.add_option('--mirror',
228 dest='mirror', action='store_true',
David Pursehouse3794a782012-11-15 06:17:30 +0900229 help='create a replica of the remote repositories '
230 'rather than a client working directory')
Shawn O. Pearce88443382010-10-08 10:02:09 +0200231group.add_option('--reference',
232 dest='reference',
233 help='location of mirror directory', metavar='DIR')
Nikolai Merinov09f0abb2018-10-19 15:07:05 +0500234group.add_option('--dissociate',
235 dest='dissociate', action='store_true',
236 help='dissociate from reference mirrors after clone')
Doug Anderson49cd59b2011-06-13 21:42:06 -0700237group.add_option('--depth', type='int', default=None,
238 dest='depth',
239 help='create a shallow clone with given depth; see git clone')
Xin Li745be2e2019-06-03 11:24:30 -0700240group.add_option('--partial-clone', action='store_true',
241 dest='partial_clone',
242 help='perform partial clone (https://git-scm.com/'
243 'docs/gitrepository-layout#_code_partialclone_code)')
244group.add_option('--clone-filter', action='store', default='blob:none',
245 dest='clone_filter',
246 help='filter for use with --partial-clone [default: %default]')
Julien Campergue335f5ef2013-10-16 11:02:35 +0200247group.add_option('--archive',
248 dest='archive', action='store_true',
249 help='checkout an archive instead of a git repository for '
250 'each project. See git archive.')
Martin Kellye4e94d22017-03-21 16:05:12 -0700251group.add_option('--submodules',
252 dest='submodules', action='store_true',
253 help='sync any submodules associated with the manifest repo')
Colin Cross5acde752012-03-28 20:15:45 -0700254group.add_option('-g', '--groups',
Conley Owens971de8e2012-04-16 10:36:08 -0700255 dest='groups', default='default',
David Holmer0a1c6a12012-11-14 19:19:00 -0500256 help='restrict manifest projects to ones with specified '
257 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
Colin Cross5acde752012-03-28 20:15:45 -0700258 metavar='GROUP')
Conley Owensd21720d2012-04-16 11:02:21 -0700259group.add_option('-p', '--platform',
260 dest='platform', default="auto",
Conley Owensc9129d92012-10-01 16:12:28 -0700261 help='restrict manifest projects to ones with a specified '
Conley Owensd21720d2012-04-16 11:02:21 -0700262 'platform group [auto|all|none|linux|darwin|...]',
263 metavar='PLATFORM')
Hu xiuyun9711a982015-12-11 11:16:41 +0800264group.add_option('--no-clone-bundle',
265 dest='no_clone_bundle', action='store_true',
266 help='disable use of /clone.bundle on HTTP/HTTPS')
Naseer Ahmedf4dda9a2016-12-01 18:49:54 -0500267group.add_option('--no-tags',
268 dest='no_tags', action='store_true',
269 help="don't fetch tags in the manifest")
Doug Anderson49cd59b2011-06-13 21:42:06 -0700270
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700271
272# Tool
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700273group = init_optparse.add_option_group('repo Version options')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700274group.add_option('--repo-url',
275 dest='repo_url',
Mike Frysinger563f1a62020-02-05 23:52:07 -0500276 help='repo repository location ($REPO_URL)', metavar='URL')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700277group.add_option('--repo-branch',
278 dest='repo_branch',
Mike Frysinger563f1a62020-02-05 23:52:07 -0500279 help='repo branch or revision ($REPO_REV)', metavar='REVISION')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700280group.add_option('--no-repo-verify',
281 dest='no_repo_verify', action='store_true',
282 help='do not verify repo source code')
283
Victor Boivie841be342011-04-05 11:31:10 +0200284# Other
285group = init_optparse.add_option_group('Other options')
286group.add_option('--config-name',
287 dest='config_name', action="store_true", default=False,
288 help='Always prompt for name/e-mail')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700289
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700290
291def _GitcInitOptions(init_optparse_arg):
292 init_optparse_arg.set_usage("repo gitc-init -u url -c client [options]")
293 g = init_optparse_arg.add_option_group('GITC options')
Simran Basi1efc2b42015-08-05 15:04:22 -0700294 g.add_option('-f', '--manifest-file',
295 dest='manifest_file',
296 help='Optional manifest file to use for this GITC client.')
297 g.add_option('-c', '--gitc-client',
298 dest='gitc_client',
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700299 help='The name of the gitc_client instance to create or modify.')
Simran Basi1efc2b42015-08-05 15:04:22 -0700300
Simran Basi8ce50412015-08-28 14:25:44 -0700301_gitc_manifest_dir = None
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700302
303
Simran Basi8ce50412015-08-28 14:25:44 -0700304def get_gitc_manifest_dir():
305 global _gitc_manifest_dir
306 if _gitc_manifest_dir is None:
Dan Willemsen2487cb72015-08-31 15:45:06 -0700307 _gitc_manifest_dir = ''
Simran Basi8ce50412015-08-28 14:25:44 -0700308 try:
309 with open(GITC_CONFIG_FILE, 'r') as gitc_config:
310 for line in gitc_config:
311 match = re.match('gitc_dir=(?P<gitc_manifest_dir>.*)', line)
312 if match:
313 _gitc_manifest_dir = match.group('gitc_manifest_dir')
314 except IOError:
Dan Willemsen2487cb72015-08-31 15:45:06 -0700315 pass
Simran Basi8ce50412015-08-28 14:25:44 -0700316 return _gitc_manifest_dir
317
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700318
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700319def gitc_parse_clientdir(gitc_fs_path):
320 """Parse a path in the GITC FS and return its client name.
321
322 @param gitc_fs_path: A subdirectory path within the GITC_FS_ROOT_DIR.
323
324 @returns: The GITC client name
325 """
326 if gitc_fs_path == GITC_FS_ROOT_DIR:
327 return None
328 if not gitc_fs_path.startswith(GITC_FS_ROOT_DIR):
329 manifest_dir = get_gitc_manifest_dir()
330 if manifest_dir == '':
331 return None
332 if manifest_dir[-1] != '/':
333 manifest_dir += '/'
334 if gitc_fs_path == manifest_dir:
335 return None
336 if not gitc_fs_path.startswith(manifest_dir):
337 return None
338 return gitc_fs_path.split(manifest_dir)[1].split('/')[0]
339 return gitc_fs_path.split(GITC_FS_ROOT_DIR)[1].split('/')[0]
340
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700341
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700342class CloneFailure(Exception):
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700343
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700344 """Indicate the remote clone of repo itself failed.
345 """
346
347
Simran Basi1efc2b42015-08-05 15:04:22 -0700348def _Init(args, gitc_init=False):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700349 """Installs repo by cloning it over the network.
350 """
Simran Basi1efc2b42015-08-05 15:04:22 -0700351 if gitc_init:
352 _GitcInitOptions(init_optparse)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700353 opt, args = init_optparse.parse_args(args)
Xiaodong Xuae0a36c2012-01-31 11:10:09 +0800354 if args:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700355 init_optparse.print_usage()
356 sys.exit(1)
357
358 url = opt.repo_url
359 if not url:
360 url = REPO_URL
361 extra_args.append('--repo-url=%s' % url)
362
363 branch = opt.repo_branch
364 if not branch:
365 branch = REPO_REV
366 extra_args.append('--repo-branch=%s' % branch)
367
368 if branch.startswith('refs/heads/'):
369 branch = branch[len('refs/heads/'):]
370 if branch.startswith('refs/'):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400371 print("fatal: invalid branch name '%s'" % branch, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700372 raise CloneFailure()
373
David Jamesbf79c662013-12-26 14:20:13 -0800374 try:
Simran Basi1efc2b42015-08-05 15:04:22 -0700375 if gitc_init:
Simran Basi8ce50412015-08-28 14:25:44 -0700376 gitc_manifest_dir = get_gitc_manifest_dir()
377 if not gitc_manifest_dir:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400378 print('fatal: GITC filesystem is not available. Exiting...',
379 file=sys.stderr)
Simran Basi8ce50412015-08-28 14:25:44 -0700380 sys.exit(1)
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700381 gitc_client = opt.gitc_client
382 if not gitc_client:
383 gitc_client = gitc_parse_clientdir(os.getcwd())
384 if not gitc_client:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400385 print('fatal: GITC client (-c) is required.', file=sys.stderr)
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700386 sys.exit(1)
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700387 client_dir = os.path.join(gitc_manifest_dir, gitc_client)
Simran Basi1efc2b42015-08-05 15:04:22 -0700388 if not os.path.exists(client_dir):
389 os.makedirs(client_dir)
390 os.chdir(client_dir)
391 if os.path.exists(repodir):
392 # This GITC Client has already initialized repo so continue.
393 return
394
David Jamesbf79c662013-12-26 14:20:13 -0800395 os.mkdir(repodir)
396 except OSError as e:
397 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400398 print('fatal: cannot make %s directory: %s'
399 % (repodir, e.strerror), file=sys.stderr)
David Pursehouse3794a782012-11-15 06:17:30 +0900400 # Don't raise CloneFailure; that would delete the
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700401 # name. Instead exit immediately.
402 #
403 sys.exit(1)
404
405 _CheckGitVersion()
406 try:
Sebastian Schuberth8f997b32020-01-20 11:42:48 +0100407 if opt.no_repo_verify:
408 do_verify = False
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700409 else:
Sebastian Schuberth8f997b32020-01-20 11:42:48 +0100410 if NeedSetupGnuPG():
411 do_verify = SetupGnuPG(opt.quiet)
412 else:
413 do_verify = True
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700414
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700415 dst = os.path.abspath(os.path.join(repodir, S_repo))
Hu xiuyun9711a982015-12-11 11:16:41 +0800416 _Clone(url, dst, opt.quiet, not opt.no_clone_bundle)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700417
Sebastian Schuberth8f997b32020-01-20 11:42:48 +0100418 if do_verify:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700419 rev = _Verify(dst, branch, opt.quiet)
420 else:
421 rev = 'refs/remotes/origin/%s^0' % branch
422
423 _Checkout(dst, branch, rev, opt.quiet)
Sebastian Schuberth993dcac2018-07-13 10:25:52 +0200424
425 if not os.path.isfile(os.path.join(dst, 'repo')):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400426 print("warning: '%s' does not look like a git-repo repository, is "
427 "REPO_URL set correctly?" % url, file=sys.stderr)
Sebastian Schuberth993dcac2018-07-13 10:25:52 +0200428
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700429 except CloneFailure:
430 if opt.quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400431 print('fatal: repo init failed; run without --quiet to see why',
432 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700433 raise
434
435
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400436# The git version info broken down into components for easy analysis.
437# Similar to Python's sys.version_info.
438GitVersion = collections.namedtuple(
439 'GitVersion', ('major', 'minor', 'micro', 'full'))
440
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400441def ParseGitVersion(ver_str=None):
442 if ver_str is None:
443 # Load the version ourselves.
444 ver_str = _GetGitVersion()
445
Conley Owensff0a3c82014-01-30 14:46:03 -0800446 if not ver_str.startswith('git version '):
447 return None
448
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400449 full_version = ver_str[len('git version '):].strip()
450 num_ver_str = full_version.split('-')[0]
Conley Owensff0a3c82014-01-30 14:46:03 -0800451 to_tuple = []
452 for num_str in num_ver_str.split('.')[:3]:
453 if num_str.isdigit():
454 to_tuple.append(int(num_str))
455 else:
456 to_tuple.append(0)
Mike Frysinger6db1b9e2019-07-10 15:32:36 -0400457 to_tuple.append(full_version)
458 return GitVersion(*to_tuple)
Conley Owensff0a3c82014-01-30 14:46:03 -0800459
460
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400461def _GetGitVersion():
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700462 cmd = [GIT, '--version']
Shawn O. Pearce4fd38ec2012-06-05 07:55:07 -0700463 try:
464 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700465 except OSError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400466 print(file=sys.stderr)
467 print("fatal: '%s' is not available" % GIT, file=sys.stderr)
468 print('fatal: %s' % e, file=sys.stderr)
469 print(file=sys.stderr)
470 print('Please make sure %s is installed and in your path.' % GIT,
471 file=sys.stderr)
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400472 raise
Shawn O. Pearce4fd38ec2012-06-05 07:55:07 -0700473
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700474 ver_str = proc.stdout.read().strip()
475 proc.stdout.close()
Shawn O. Pearce16191342008-10-28 08:33:34 -0700476 proc.wait()
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400477 return ver_str.decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700478
Mike Frysingerf88b2fe2019-07-10 15:37:43 -0400479
480def _CheckGitVersion():
481 try:
482 ver_act = ParseGitVersion()
483 except OSError:
484 raise CloneFailure()
485
Conley Owensff0a3c82014-01-30 14:46:03 -0800486 if ver_act is None:
Mike Frysinger4c263b52019-09-11 04:04:16 -0400487 print('fatal: unable to detect git version', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700488 raise CloneFailure()
489
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700490 if ver_act < MIN_GIT_VERSION:
David Pursehouse685f0802012-11-14 08:34:39 +0900491 need = '.'.join(map(str, MIN_GIT_VERSION))
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400492 print('fatal: git %s or later required' % need, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700493 raise CloneFailure()
494
495
Conley Owensc9129d92012-10-01 16:12:28 -0700496def NeedSetupGnuPG():
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700497 if not os.path.isdir(home_dot_repo):
498 return True
499
500 kv = os.path.join(home_dot_repo, 'keyring-version')
501 if not os.path.exists(kv):
502 return True
503
504 kv = open(kv).read()
505 if not kv:
506 return True
507
David Pursehouse685f0802012-11-14 08:34:39 +0900508 kv = tuple(map(int, kv.split('.')))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700509 if kv < KEYRING_VERSION:
510 return True
511 return False
512
513
Conley Owensc9129d92012-10-01 16:12:28 -0700514def SetupGnuPG(quiet):
David Jamesbf79c662013-12-26 14:20:13 -0800515 try:
516 os.mkdir(home_dot_repo)
517 except OSError as e:
518 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400519 print('fatal: cannot make %s directory: %s'
520 % (home_dot_repo, e.strerror), file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700521 sys.exit(1)
522
David Jamesbf79c662013-12-26 14:20:13 -0800523 try:
524 os.mkdir(gpg_dir, stat.S_IRWXU)
525 except OSError as e:
526 if e.errno != errno.EEXIST:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400527 print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror),
528 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700529 sys.exit(1)
530
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800531 env = os.environ.copy()
Dāvis Mosāns631d0ec2016-07-16 21:11:11 +0300532 try:
533 env['GNUPGHOME'] = gpg_dir
534 except UnicodeEncodeError:
535 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700536
537 cmd = ['gpg', '--import']
538 try:
539 proc = subprocess.Popen(cmd,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700540 env=env,
541 stdin=subprocess.PIPE)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700542 except OSError as e:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700543 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400544 print('warning: gpg (GnuPG) is not available.', file=sys.stderr)
545 print('warning: Installing it is strongly encouraged.', file=sys.stderr)
546 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700547 return False
548
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400549 proc.stdin.write(MAINTAINER_KEYS.encode('utf-8'))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700550 proc.stdin.close()
551
552 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400553 print('fatal: registering repo maintainer keys failed', file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700554 sys.exit(1)
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400555 print()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700556
Mike Frysinger3164d402019-11-11 05:40:22 -0500557 with open(os.path.join(home_dot_repo, 'keyring-version'), 'w') as fd:
558 fd.write('.'.join(map(str, KEYRING_VERSION)) + '\n')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700559 return True
560
561
562def _SetConfig(local, name, value):
563 """Set a git configuration option to the specified value.
564 """
565 cmd = [GIT, 'config', name, value]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700566 if subprocess.Popen(cmd, cwd=local).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700567 raise CloneFailure()
568
569
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700570def _InitHttp():
571 handlers = []
572
Sarah Owens1f7627f2012-10-31 09:21:55 -0700573 mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700574 try:
575 import netrc
576 n = netrc.netrc()
577 for host in n.hosts:
578 p = n.hosts[host]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700579 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
Xiaodong Xuae0a36c2012-01-31 11:10:09 +0800580 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
David Pursehouse65b0ba52018-06-24 16:21:51 +0900581 except:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700582 pass
Sarah Owens1f7627f2012-10-31 09:21:55 -0700583 handlers.append(urllib.request.HTTPBasicAuthHandler(mgr))
584 handlers.append(urllib.request.HTTPDigestAuthHandler(mgr))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700585
586 if 'http_proxy' in os.environ:
587 url = os.environ['http_proxy']
Sarah Owens1f7627f2012-10-31 09:21:55 -0700588 handlers.append(urllib.request.ProxyHandler({'http': url, 'https': url}))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700589 if 'REPO_CURL_VERBOSE' in os.environ:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700590 handlers.append(urllib.request.HTTPHandler(debuglevel=1))
591 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
592 urllib.request.install_opener(urllib.request.build_opener(*handlers))
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700593
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700594
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700595def _Fetch(url, local, src, quiet):
596 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400597 print('Get %s' % url, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700598
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700599 cmd = [GIT, 'fetch']
600 if quiet:
601 cmd.append('--quiet')
602 err = subprocess.PIPE
603 else:
604 err = None
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700605 cmd.append(src)
606 cmd.append('+refs/heads/*:refs/remotes/origin/*')
Xin Li6e538442018-12-10 11:33:16 -0800607 cmd.append('+refs/tags/*:refs/tags/*')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700608
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700609 proc = subprocess.Popen(cmd, cwd=local, stderr=err)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700610 if err:
611 proc.stderr.read()
612 proc.stderr.close()
613 if proc.wait() != 0:
614 raise CloneFailure()
615
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700616
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700617def _DownloadBundle(url, local, quiet):
618 if not url.endswith('/'):
619 url += '/'
620 url += 'clone.bundle'
621
622 proc = subprocess.Popen(
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700623 [GIT, 'config', '--get-regexp', 'url.*.insteadof'],
624 cwd=local,
625 stdout=subprocess.PIPE)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700626 for line in proc.stdout:
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400627 line = line.decode('utf-8')
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700628 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
629 if m:
630 new_url = m.group(1)
631 old_url = m.group(2)
632 if url.startswith(old_url):
633 url = new_url + url[len(old_url):]
634 break
635 proc.stdout.close()
636 proc.wait()
637
638 if not url.startswith('http:') and not url.startswith('https:'):
639 return False
640
641 dest = open(os.path.join(local, '.git', 'clone.bundle'), 'w+b')
642 try:
643 try:
Sarah Owens1f7627f2012-10-31 09:21:55 -0700644 r = urllib.request.urlopen(url)
645 except urllib.error.HTTPError as e:
John Törnblomd3ddcdb2015-08-12 20:12:51 +0200646 if e.code in [401, 403, 404, 501]:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700647 return False
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400648 print('fatal: Cannot get %s' % url, file=sys.stderr)
649 print('fatal: HTTP error %s' % e.code, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700650 raise CloneFailure()
Sarah Owens1f7627f2012-10-31 09:21:55 -0700651 except urllib.error.URLError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400652 print('fatal: Cannot get %s' % url, file=sys.stderr)
653 print('fatal: error %s' % e.reason, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700654 raise CloneFailure()
655 try:
656 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400657 print('Get %s' % url, file=sys.stderr)
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700658 while True:
659 buf = r.read(8192)
Mike Frysinger1b9adab2019-07-04 17:54:54 -0400660 if not buf:
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700661 return True
662 dest.write(buf)
663 finally:
664 r.close()
665 finally:
666 dest.close()
667
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700668
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700669def _ImportBundle(local):
670 path = os.path.join(local, '.git', 'clone.bundle')
671 try:
672 _Fetch(local, local, path, True)
673 finally:
674 os.remove(path)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700675
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700676
Hu xiuyun9711a982015-12-11 11:16:41 +0800677def _Clone(url, local, quiet, clone_bundle):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700678 """Clones a git repository to a new subdirectory of repodir
679 """
680 try:
681 os.mkdir(local)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700682 except OSError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400683 print('fatal: cannot make %s directory: %s' % (local, e.strerror),
684 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700685 raise CloneFailure()
686
687 cmd = [GIT, 'init', '--quiet']
688 try:
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700689 proc = subprocess.Popen(cmd, cwd=local)
Sarah Owensa5be53f2012-09-09 15:37:57 -0700690 except OSError as e:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400691 print(file=sys.stderr)
692 print("fatal: '%s' is not available" % GIT, file=sys.stderr)
693 print('fatal: %s' % e, file=sys.stderr)
694 print(file=sys.stderr)
695 print('Please make sure %s is installed and in your path.' % GIT,
696 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700697 raise CloneFailure()
698 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400699 print('fatal: could not create %s' % local, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700700 raise CloneFailure()
701
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700702 _InitHttp()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700703 _SetConfig(local, 'remote.origin.url', url)
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700704 _SetConfig(local,
705 'remote.origin.fetch',
706 '+refs/heads/*:refs/remotes/origin/*')
Hu xiuyun9711a982015-12-11 11:16:41 +0800707 if clone_bundle and _DownloadBundle(url, local, quiet):
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700708 _ImportBundle(local)
Dan Willemsenfee390e2015-09-02 12:36:30 -0700709 _Fetch(url, local, 'origin', quiet)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700710
711
712def _Verify(cwd, branch, quiet):
713 """Verify the branch has been signed by a tag.
714 """
715 cmd = [GIT, 'describe', 'origin/%s' % branch]
716 proc = subprocess.Popen(cmd,
717 stdout=subprocess.PIPE,
718 stderr=subprocess.PIPE,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700719 cwd=cwd)
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400720 cur = proc.stdout.read().strip().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700721 proc.stdout.close()
722
723 proc.stderr.read()
724 proc.stderr.close()
725
726 if proc.wait() != 0 or not cur:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400727 print(file=sys.stderr)
728 print("fatal: branch '%s' has not been signed" % branch, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700729 raise CloneFailure()
730
731 m = re.compile(r'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur)
732 if m:
733 cur = m.group(1)
734 if not quiet:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400735 print(file=sys.stderr)
736 print("info: Ignoring branch '%s'; using tagged release '%s'"
737 % (branch, cur), file=sys.stderr)
738 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700739
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800740 env = os.environ.copy()
Dāvis Mosāns631d0ec2016-07-16 21:11:11 +0300741 try:
742 env['GNUPGHOME'] = gpg_dir
743 except UnicodeEncodeError:
744 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700745
746 cmd = [GIT, 'tag', '-v', cur]
747 proc = subprocess.Popen(cmd,
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700748 stdout=subprocess.PIPE,
749 stderr=subprocess.PIPE,
750 cwd=cwd,
751 env=env)
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400752 out = proc.stdout.read().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700753 proc.stdout.close()
754
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400755 err = proc.stderr.read().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700756 proc.stderr.close()
757
758 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400759 print(file=sys.stderr)
760 print(out, file=sys.stderr)
761 print(err, file=sys.stderr)
762 print(file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700763 raise CloneFailure()
764 return '%s^0' % cur
765
766
767def _Checkout(cwd, branch, rev, quiet):
768 """Checkout an upstream branch into the repository and track it.
769 """
770 cmd = [GIT, 'update-ref', 'refs/heads/default', rev]
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700771 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700772 raise CloneFailure()
773
774 _SetConfig(cwd, 'branch.default.remote', 'origin')
775 _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch)
776
777 cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default']
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700778 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700779 raise CloneFailure()
780
781 cmd = [GIT, 'read-tree', '--reset', '-u']
782 if not quiet:
783 cmd.append('-v')
784 cmd.append('HEAD')
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700785 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700786 raise CloneFailure()
787
788
789def _FindRepo():
790 """Look for a repo installation, starting at the current directory.
791 """
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200792 curdir = os.getcwd()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700793 repo = None
794
Anthony Newnamdf14a702011-01-09 17:31:57 -0800795 olddir = None
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200796 while curdir != '/' \
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700797 and curdir != olddir \
798 and not repo:
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200799 repo = os.path.join(curdir, repodir, REPO_MAIN)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700800 if not os.path.isfile(repo):
801 repo = None
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200802 olddir = curdir
803 curdir = os.path.dirname(curdir)
804 return (repo, os.path.join(curdir, repodir))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700805
806
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700807class _Options(object):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700808 help = False
809
810
811def _ParseArguments(args):
812 cmd = None
813 opt = _Options()
814 arg = []
815
Sarah Owensa6053d52012-11-01 13:36:50 -0700816 for i in range(len(args)):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700817 a = args[i]
818 if a == '-h' or a == '--help':
819 opt.help = True
820
821 elif not a.startswith('-'):
822 cmd = a
823 arg = args[i + 1:]
824 break
825 return cmd, opt, arg
826
827
828def _Usage():
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700829 gitc_usage = ""
830 if get_gitc_manifest_dir():
831 gitc_usage = " gitc-init Initialize a GITC Client.\n"
832
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400833 print(
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700834 """usage: repo COMMAND [ARGS]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700835
836repo is not yet installed. Use "repo init" to install it here.
837
838The most commonly used repo commands are:
839
840 init Install repo in the current working directory
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700841""" + gitc_usage +
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700842 """ help Display detailed help on a command
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700843
844For access to the full online help, install repo ("repo init").
Mike Frysinger35159ab2019-06-13 00:07:13 -0400845""")
846 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700847
848
849def _Help(args):
850 if args:
851 if args[0] == 'init':
852 init_optparse.print_help()
Trond Norbyed3fd5372011-01-03 11:35:15 +0100853 sys.exit(0)
Dan Willemsen9ff2ece2015-08-31 15:45:06 -0700854 elif args[0] == 'gitc-init':
855 _GitcInitOptions(init_optparse)
856 init_optparse.print_help()
857 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700858 else:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400859 print("error: '%s' is not a bootstrap command.\n"
860 ' For access to online help, install repo ("repo init").'
861 % args[0], file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700862 else:
863 _Usage()
864 sys.exit(1)
865
866
867def _NotInstalled():
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400868 print('error: repo is not installed. Use "repo init" to install it here.',
869 file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700870 sys.exit(1)
871
872
873def _NoCommands(cmd):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400874 print("""error: command '%s' requires repo to be installed first.
875 Use "repo init" to install it here.""" % cmd, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700876 sys.exit(1)
877
878
879def _RunSelf(wrapper_path):
880 my_dir = os.path.dirname(wrapper_path)
881 my_main = os.path.join(my_dir, 'main.py')
882 my_git = os.path.join(my_dir, '.git')
883
884 if os.path.isfile(my_main) and os.path.isdir(my_git):
Shawn O. Pearcec8a300f2009-05-18 13:19:57 -0700885 for name in ['git_config.py',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700886 'project.py',
887 'subcmds']:
888 if not os.path.exists(os.path.join(my_dir, name)):
889 return None, None
890 return my_main, my_git
891 return None, None
892
893
894def _SetDefaultsTo(gitdir):
895 global REPO_URL
896 global REPO_REV
897
898 REPO_URL = gitdir
899 proc = subprocess.Popen([GIT,
900 '--git-dir=%s' % gitdir,
901 'symbolic-ref',
902 'HEAD'],
Mark E. Hamilton4088eb42016-02-10 10:44:30 -0700903 stdout=subprocess.PIPE,
904 stderr=subprocess.PIPE)
Mike Frysinger9100f7f2019-09-11 03:58:36 -0400905 REPO_REV = proc.stdout.read().strip().decode('utf-8')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700906 proc.stdout.close()
907
908 proc.stderr.read()
909 proc.stderr.close()
910
911 if proc.wait() != 0:
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400912 print('fatal: %s has no current branch' % gitdir, file=sys.stderr)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700913 sys.exit(1)
914
915
916def main(orig_args):
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700917 cmd, opt, args = _ParseArguments(orig_args)
918
Dan Willemsen745b4ad2015-10-06 15:23:19 -0700919 repo_main, rel_repo_dir = None, None
920 # Don't use the local repo copy, make sure to switch to the gitc client first.
921 if cmd != 'gitc-init':
922 repo_main, rel_repo_dir = _FindRepo()
923
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700924 wrapper_path = os.path.abspath(__file__)
925 my_main, my_git = _RunSelf(wrapper_path)
926
Simran Basi8ce50412015-08-28 14:25:44 -0700927 cwd = os.getcwd()
Dan Willemsen2487cb72015-08-31 15:45:06 -0700928 if get_gitc_manifest_dir() and cwd.startswith(get_gitc_manifest_dir()):
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400929 print('error: repo cannot be used in the GITC local manifest directory.'
930 '\nIf you want to work on this GITC client please rerun this '
931 'command from the corresponding client under /gitc/',
932 file=sys.stderr)
Simran Basi8ce50412015-08-28 14:25:44 -0700933 sys.exit(1)
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200934 if not repo_main:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700935 if opt.help:
936 _Usage()
937 if cmd == 'help':
938 _Help(args)
939 if not cmd:
940 _NotInstalled()
Simran Basi1efc2b42015-08-05 15:04:22 -0700941 if cmd == 'init' or cmd == 'gitc-init':
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700942 if my_git:
943 _SetDefaultsTo(my_git)
944 try:
Simran Basi1efc2b42015-08-05 15:04:22 -0700945 _Init(args, gitc_init=(cmd == 'gitc-init'))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700946 except CloneFailure:
Sebastian Schuberth27226e72016-10-28 14:27:43 +0200947 path = os.path.join(repodir, S_repo)
Mike Frysingerc92ce5c2019-06-13 01:14:23 -0400948 print("fatal: cloning the git-repo repository failed, will remove "
949 "'%s' " % path, file=sys.stderr)
Sebastian Schuberth27226e72016-10-28 14:27:43 +0200950 shutil.rmtree(path, ignore_errors=True)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700951 sys.exit(1)
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200952 repo_main, rel_repo_dir = _FindRepo()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700953 else:
954 _NoCommands(cmd)
955
956 if my_main:
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200957 repo_main = my_main
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700958
David Pursehouse685f0802012-11-14 08:34:39 +0900959 ver_str = '.'.join(map(str, VERSION))
anatoly techtonik3a2a59e2013-09-21 19:29:10 +0300960 me = [sys.executable, repo_main,
Mickaël Salaün2f6ab7f2012-09-30 00:37:55 +0200961 '--repo-dir=%s' % rel_repo_dir,
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700962 '--wrapper-version=%s' % ver_str,
963 '--wrapper-path=%s' % wrapper_path,
964 '--']
965 me.extend(orig_args)
966 me.extend(extra_args)
Mike Frysinger3ba716f2019-06-13 01:48:12 -0400967 exec_command(me)
968 print("fatal: unable to start %s" % repo_main, file=sys.stderr)
969 sys.exit(148)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700970
971
972if __name__ == '__main__':
973 main(sys.argv[1:])