blob: 6762c75f3552459fb36c0074e0db493b8f4cbe67 [file] [log] [blame]
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +00001#!/usr/bin/env python
Mike Frysingerafe292c2019-08-05 19:15:18 +00002# -*- coding:utf-8 -*-
3
4"""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
11from __future__ import print_function
msb@chromium.org38b04f82010-07-13 23:03:34 +000012
vapierae39f562016-10-10 19:08:17 -070013# repo default configuration
14#
15import os
16REPO_URL = os.environ.get('REPO_URL', None)
17if not REPO_URL:
18 REPO_URL = 'https://chromium.googlesource.com/external/repo'
19REPO_REV = 'stable'
msb@chromium.org38b04f82010-07-13 23:03:34 +000020
21# Copyright (C) 2008 Google Inc.
22#
23# Licensed under the Apache License, Version 2.0 (the "License");
24# you may not use this file except in compliance with the License.
25# You may obtain a copy of the License at
26#
27# http://www.apache.org/licenses/LICENSE-2.0
28#
29# Unless required by applicable law or agreed to in writing, software
30# distributed under the License is distributed on an "AS IS" BASIS,
31# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
32# See the License for the specific language governing permissions and
33# limitations under the License.
34
msb@chromium.org38b04f82010-07-13 23:03:34 +000035# increment this whenever we make important changes to this script
Nico Weber64ae6992019-09-19 19:03:28 +000036VERSION = (1, 26)
msb@chromium.org38b04f82010-07-13 23:03:34 +000037
38# increment this if the MAINTAINER_KEYS block is modified
vapier74751962016-09-14 16:08:34 -070039KEYRING_VERSION = (1, 5)
Don Garrett24f2cc02018-12-18 18:07:17 +000040
41# Each individual key entry is created by using:
42# gpg --armor --export keyid
msb@chromium.org38b04f82010-07-13 23:03:34 +000043MAINTAINER_KEYS = """
44
45 Repo Maintainer <repo@android.kernel.org>
46-----BEGIN PGP PUBLIC KEY BLOCK-----
47Version: GnuPG v1.4.2.2 (GNU/Linux)
48
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
84=CMiZ
85-----END PGP PUBLIC KEY BLOCK-----
ferringb@google.com8db6c882012-12-25 17:02:37 +000086
87 Conley Owens <cco3@android.com>
88-----BEGIN PGP PUBLIC KEY BLOCK-----
89Version: GnuPG v1.4.11 (GNU/Linux)
90
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +000091mQENBFHRvc8BCADFg45Xx/y6QDC+T7Y/gGc7vx0ww7qfOwIKlAZ9xG3qKunMxo+S
92hPCnzEl3cq+6I1Ww/ndop/HB3N3toPXRCoN8Vs4/Hc7by+SnaLFnacrm+tV5/OgT
93V37Lzt8lhay1Kl+YfpFwHYYpIEBLFV9knyfRXS/428W2qhdzYfvB15/AasRmwmor
94py4NIzSs8UD/SPr1ihqNCdZM76+MQyN5HMYXW/ALZXUFG0pwluHFA7hrfPG74i8C
95zMiP7qvMWIl/r/jtzHioH1dRKgbod+LZsrDJ8mBaqsZaDmNJMhss9g76XvfMyLra
969DI9/iFuBpGzeqBv0hwOGQspLRrEoyTeR6n1ABEBAAG0H0NvbmxleSBPd2VucyA8
97Y2NvM0BhbmRyb2lkLmNvbT6JATgEEwECACIFAlHRvc8CGwMGCwkIBwMCBhUIAgkK
98CwQWAgMBAh4BAheAAAoJEGe35EhpKzgsP6AIAJKJmNtn4l7hkYHKHFSo3egb6RjQ
99zEIP3MFTcu8HFX1kF1ZFbrp7xqurLaE53kEkKuAAvjJDAgI8mcZHP1JyplubqjQA
100xvv84gK+OGP3Xk+QK1ZjUQSbjOpjEiSZpRhWcHci3dgOUH4blJfByHw25hlgHowd
101a/2PrNKZVcJ92YienaxxGjcXEUcd0uYEG2+rwllQigFcnMFDhr9B71MfalRHjFKE
102fmdoypqLrri61YBc59P88Rw2/WUpTQjgNubSqa3A2+CKdaRyaRw+2fdF4TdR0h8W
103zbg+lbaPtJHsV+3mJC7fq26MiJDRJa5ZztpMn8su20gbLgi2ShBOaHAYDDi5AQ0E
104UdG9zwEIAMoOBq+QLNozAhxOOl5GL3StTStGRgPRXINfmViTsihrqGCWBBUfXlUE
105OytC0mYcrDUQev/8ToVoyqw+iGSwDkcSXkrEUCKFtHV/GECWtk1keyHgR10YKI1R
106mquSXoubWGqPeG1PAI74XWaRx8UrL8uCXUtmD8Q5J7mDjKR5NpxaXrwlA0bKsf2E
107Gp9tu1kKauuToZhWHMRMqYSOGikQJwWSFYKT1KdNcOXLQF6+bfoJ6sjVYdwfmNQL
108Ixn8QVhoTDedcqClSWB17VDEFDFa7MmqXZz2qtM3X1R/MUMHqPtegQzBGNhRdnI2
109V45+1Nnx/uuCxDbeI4RbHzujnxDiq70AEQEAAYkBHwQYAQIACQUCUdG9zwIbDAAK
110CRBnt+RIaSs4LNVeB/0Y2pZ8I7gAAcEM0Xw8drr4omg2fUoK1J33ozlA/RxeA/lJ
111I3KnyCDTpXuIeBKPGkdL8uMATC9Z8DnBBajRlftNDVZS3Hz4G09G9QpMojvJkFJV
112By+01Flw/X+eeN8NpqSuLV4W+AjEO8at/VvgKr1AFvBRdZ7GkpI1o6DgPe7ZqX+1
113dzQZt3e13W0rVBb/bUgx9iSLoeWP3aq/k+/GRGOR+S6F6BBSl0SQ2EF2+dIywb1x
114JuinEP+AwLAUZ1Bsx9ISC0Agpk2VeHXPL3FGhroEmoMvBzO0kTFGyoeT7PR/BfKv
115+H/g3HsL2LOB9uoIm8/5p2TTU5ttYCXMHhQZ81AY
116=AUp4
ferringb@google.com8db6c882012-12-25 17:02:37 +0000117-----END PGP PUBLIC KEY BLOCK-----
szager@chromium.org538283f2013-08-13 21:37:50 +0000118
119 Stefan Zager <szager@chromium.org>
120-----BEGIN PGP PUBLIC KEY BLOCK-----
121Version: GnuPG v1.4.11 (GNU/Linux)
122
123mQINBFIJOcgBEADwZIq4GRGoO1RJFKlrtVK501cwT5H+Acbizc9N5RxTkFmqxDjb
1249ApUaPW6S1b8+nrzE9P1Ri5erfzipuStfaZ/Wl3mP1JjKulibddmgnPOEbAJ673k
125Vj85RUO4rt2oZAHnZN3D3gFJzVY8JVlZ47Enj9fTqzcW78FVsPCpIT9P2LpTLWeE
126jX9Cjxeimy6VvyJstIcDLYhlpUN5UWen79L4LFAkHf3luLuU4W3p9NriqUsy5UG2
1278vO6QdhKrCr5wsjDFFeVnpMtjlSeZJAWH+XhFFibMX1xP5R9BTuJfzw3kOVKvcE0
128e9ClxgoulepXPv2xnDkqO3pG2gQVzl8LA+Aol8/IXfa7KP5FBkxK/g1cDuDtXRk4
129YLpLaLYeeKEhhOHLpsKYkK2DXTIcN+56UnTLGolummpZnCM8UUSZxQgbkFgk4YJL
130Elip0hgLZzqEl5h9vjmnQp89AZIHKcgNmzn+szLTOR9x24joaLyQ534x8OSC8lmu
131tJv2tQjDOVGWVwvY4gOTpyxCWMwur6WOiMk/TPWdiVRFWAGrAHwf0/CTBEqNhosh
132sVXfPeMADBA0PorDbJ6kwcOkLUTGf8CT7OG1R9TuKPEmSjK7BYu/pT4DXitaRCiv
133uPVlwbVFpLFr0/jwaKJVMLUjL5MaYwzjJqI2c4RdROZhpMhkn4LvCMmFSQARAQAB
134tCJTdGVmYW4gWmFnZXIgPHN6YWdlckBjaHJvbWl1bS5vcmc+iQI4BBMBAgAiBQJS
135CTnIAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAAKCRDcuoHPGCdZNU0UD/9y
1360zwwOJH2UGPAzZ0YVzr7p0HtKedoxuFvPkdQxlBIaUOueMzFRmNQu3GI9irAu3MQ
137Jkip8/gi7dnLVmJyS/zWARBaRGwSVd1++87XDjw8n7l181p7394X0Agq/heri599
138YheHXkxXKVMPqByWNEPHu4eDbxeJTaDIjcKC2pzKQkm6HbWgW4wA9gCh1TRki8FP
139LMv1Fu/dr13STCR9P2evsTRZ+ZSJhTSboHNHeEAJGiGZQAsN94oht7647lYj+AyR
140ThzyHDMXXiDr8jPJIkyRilY+y82bCOatOfPoCkce3VI+LRUGJ19hJY01m4RRneIE
14155l7fXR3zggcsONjV5b+oLcGQPGgX9w64BJ7khT7Wb9+kuyrdJBIBzJsaACFEbri
142pPi02FS/HahYpLC3J66REAeNyofgVXau6WQsHrHMGsBTL9aAr0nrCrkF4Nyyc2Jd
143do6nYuljuUhORqbEECmmBM2eBtkL6Ac92D6WMBIwBOC5tCNHO2YFIvi8Y8EuE8sc
1441zB5U5Ai4SIu2icRAhzAhCRaUq02cMWuELKH6Vuh9nzgEefFWty6vPbKEyZLu19D
145B80aqP1cTN88FjtKQ/eTF29TUB6AefUeBS17e2e3WUMy4nc8tduuOFYfiHP40ScP
146wOoatwfzpiTIPGbocUEPL+pS0O/Xy8SINxFMCud3zA==
147=Vd2S
148-----END PGP PUBLIC KEY BLOCK-----
szager@chromium.org33c182b2014-09-08 17:50:45 +0000149
150 David James <davidjames@google.com>
151-----BEGIN PGP PUBLIC KEY BLOCK-----
152Version: GnuPG v1
153
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
200IM4=
201=6VNc
202-----END PGP PUBLIC KEY BLOCK-----
vapier74751962016-09-14 16:08:34 -0700203
204 Mike Frysinger <vapier@chromium.org>
205-----BEGIN PGP PUBLIC KEY BLOCK-----
206Version: GnuPG v1
207
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
243=i88c
244-----END PGP PUBLIC KEY BLOCK-----
msb@chromium.org38b04f82010-07-13 23:03:34 +0000245"""
246
vapierae39f562016-10-10 19:08:17 -0700247GIT = 'git' # our git command
248MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version
249repodir = '.repo' # name of repo's private directory
250S_repo = 'repo' # special repo repository
251S_manifests = 'manifests' # special manifest repository
252REPO_MAIN = S_repo + '/main.py' # main script
Mike Frysinger58649e32018-12-20 21:53:50 +0000253MIN_PYTHON_VERSION = (2, 7) # minimum supported python version
vapierae39f562016-10-10 19:08:17 -0700254GITC_CONFIG_FILE = '/gitc/.config'
255GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
msb@chromium.org38b04f82010-07-13 23:03:34 +0000256
257
Mike Frysingerafe292c2019-08-05 19:15:18 +0000258import collections
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000259import errno
msb@chromium.org38b04f82010-07-13 23:03:34 +0000260import optparse
Don Garrett24f2cc02018-12-18 18:07:17 +0000261import platform
msb@chromium.org38b04f82010-07-13 23:03:34 +0000262import re
vapier74751962016-09-14 16:08:34 -0700263import shutil
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000264import stat
msb@chromium.org38b04f82010-07-13 23:03:34 +0000265import subprocess
266import sys
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000267
268if sys.version_info[0] == 3:
269 import urllib.request
270 import urllib.error
271else:
272 import imp
273 import urllib2
274 urllib = imp.new_module('urllib')
275 urllib.request = urllib2
276 urllib.error = urllib2
277
278
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000279# Python version check
280ver = sys.version_info
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000281if (ver[0], ver[1]) < MIN_PYTHON_VERSION:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000282 print('error: Python version {} unsupported.\n'
283 'Please use Python {}.{} instead.'.format(
284 sys.version.split(' ')[0],
285 MIN_PYTHON_VERSION[0],
286 MIN_PYTHON_VERSION[1],
287 ), file=sys.stderr)
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000288 sys.exit(1)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000289
vapier74751962016-09-14 16:08:34 -0700290home_dot_repo = os.path.expanduser('~/.repoconfig')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000291gpg_dir = os.path.join(home_dot_repo, 'gnupg')
292
293extra_args = []
294init_optparse = optparse.OptionParser(usage="repo init -u url [options]")
295
296# Logging
297group = init_optparse.add_option_group('Logging options')
298group.add_option('-q', '--quiet',
299 dest="quiet", action="store_true", default=False,
300 help="be quiet")
301
302# Manifest
303group = init_optparse.add_option_group('Manifest options')
304group.add_option('-u', '--manifest-url',
305 dest='manifest_url',
306 help='manifest repository location', metavar='URL')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000307group.add_option('-b', '--manifest-branch',
308 dest='manifest_branch',
309 help='manifest branch or revision', metavar='REVISION')
310group.add_option('-m', '--manifest-name',
311 dest='manifest_name',
maruel@chromium.orgb25b69b2011-06-16 17:41:05 +0000312 help='initial manifest file', metavar='NAME.xml')
Mike Frysinger58649e32018-12-20 21:53:50 +0000313group.add_option('--current-branch',
Don Garrett24f2cc02018-12-18 18:07:17 +0000314 dest='current_branch_only', action='store_true',
315 help='fetch only current manifest branch from server')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000316group.add_option('--mirror',
317 dest='mirror', action='store_true',
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000318 help='create a replica of the remote repositories '
319 'rather than a client working directory')
msb@chromium.org2c64b712011-01-11 22:57:47 +0000320group.add_option('--reference',
321 dest='reference',
322 help='location of mirror directory', metavar='DIR')
Mike Frysingerafe292c2019-08-05 19:15:18 +0000323group.add_option('--dissociate',
324 dest='dissociate', action='store_true',
325 help='dissociate from reference mirrors after clone')
maruel@chromium.orgb25b69b2011-06-16 17:41:05 +0000326group.add_option('--depth', type='int', default=None,
327 dest='depth',
328 help='create a shallow clone with given depth; see git clone')
Mike Frysingerafe292c2019-08-05 19:15:18 +0000329group.add_option('--partial-clone', action='store_true',
330 dest='partial_clone',
331 help='perform partial clone (https://git-scm.com/'
332 'docs/gitrepository-layout#_code_partialclone_code)')
333group.add_option('--clone-filter', action='store', default='blob:none',
334 dest='clone_filter',
335 help='filter for use with --partial-clone [default: %default]')
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000336group.add_option('--archive',
337 dest='archive', action='store_true',
338 help='checkout an archive instead of a git repository for '
339 'each project. See git archive.')
Don Garrett24f2cc02018-12-18 18:07:17 +0000340group.add_option('--submodules',
341 dest='submodules', action='store_true',
342 help='sync any submodules associated with the manifest repo')
ferringb@google.com79245bf2012-06-14 21:22:01 +0000343group.add_option('-g', '--groups',
344 dest='groups', default='default',
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000345 help='restrict manifest projects to ones with specified '
346 'group(s) [default|all|G1,G2,G3|G4,-G5,-G6]',
ferringb@google.com79245bf2012-06-14 21:22:01 +0000347 metavar='GROUP')
348group.add_option('-p', '--platform',
349 dest='platform', default="auto",
ferringb@google.com8db6c882012-12-25 17:02:37 +0000350 help='restrict manifest projects to ones with a specified '
ferringb@google.com79245bf2012-06-14 21:22:01 +0000351 'platform group [auto|all|none|linux|darwin|...]',
352 metavar='PLATFORM')
vapierae39f562016-10-10 19:08:17 -0700353group.add_option('--no-clone-bundle',
354 dest='no_clone_bundle', action='store_true',
355 help='disable use of /clone.bundle on HTTP/HTTPS')
Don Garrett24f2cc02018-12-18 18:07:17 +0000356group.add_option('--no-tags',
357 dest='no_tags', action='store_true',
358 help="don't fetch tags in the manifest")
maruel@chromium.orgb25b69b2011-06-16 17:41:05 +0000359
msb@chromium.org38b04f82010-07-13 23:03:34 +0000360
361# Tool
362group = init_optparse.add_option_group('repo Version options')
363group.add_option('--repo-url',
364 dest='repo_url',
365 help='repo repository location', metavar='URL')
366group.add_option('--repo-branch',
367 dest='repo_branch',
368 help='repo branch or revision', metavar='REVISION')
369group.add_option('--no-repo-verify',
370 dest='no_repo_verify', action='store_true',
371 help='do not verify repo source code')
372
ferringb@google.com79245bf2012-06-14 21:22:01 +0000373# Other
374group = init_optparse.add_option_group('Other options')
375group.add_option('--config-name',
376 dest='config_name', action="store_true", default=False,
377 help='Always prompt for name/e-mail')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000378
vapierae39f562016-10-10 19:08:17 -0700379
380def _GitcInitOptions(init_optparse_arg):
381 init_optparse_arg.set_usage("repo gitc-init -u url -c client [options]")
382 g = init_optparse_arg.add_option_group('GITC options')
383 g.add_option('-f', '--manifest-file',
384 dest='manifest_file',
385 help='Optional manifest file to use for this GITC client.')
386 g.add_option('-c', '--gitc-client',
387 dest='gitc_client',
388 help='The name of the gitc_client instance to create or modify.')
389
390_gitc_manifest_dir = None
391
392
393def get_gitc_manifest_dir():
394 global _gitc_manifest_dir
395 if _gitc_manifest_dir is None:
396 _gitc_manifest_dir = ''
397 try:
398 with open(GITC_CONFIG_FILE, 'r') as gitc_config:
399 for line in gitc_config:
400 match = re.match('gitc_dir=(?P<gitc_manifest_dir>.*)', line)
401 if match:
402 _gitc_manifest_dir = match.group('gitc_manifest_dir')
403 except IOError:
404 pass
405 return _gitc_manifest_dir
406
407
408def gitc_parse_clientdir(gitc_fs_path):
409 """Parse a path in the GITC FS and return its client name.
410
411 @param gitc_fs_path: A subdirectory path within the GITC_FS_ROOT_DIR.
412
413 @returns: The GITC client name
414 """
415 if gitc_fs_path == GITC_FS_ROOT_DIR:
416 return None
417 if not gitc_fs_path.startswith(GITC_FS_ROOT_DIR):
418 manifest_dir = get_gitc_manifest_dir()
419 if manifest_dir == '':
420 return None
421 if manifest_dir[-1] != '/':
422 manifest_dir += '/'
423 if gitc_fs_path == manifest_dir:
424 return None
425 if not gitc_fs_path.startswith(manifest_dir):
426 return None
427 return gitc_fs_path.split(manifest_dir)[1].split('/')[0]
428 return gitc_fs_path.split(GITC_FS_ROOT_DIR)[1].split('/')[0]
429
430
msb@chromium.org38b04f82010-07-13 23:03:34 +0000431class CloneFailure(Exception):
vapierae39f562016-10-10 19:08:17 -0700432
msb@chromium.org38b04f82010-07-13 23:03:34 +0000433 """Indicate the remote clone of repo itself failed.
434 """
435
436
vapierae39f562016-10-10 19:08:17 -0700437def _Init(args, gitc_init=False):
msb@chromium.org38b04f82010-07-13 23:03:34 +0000438 """Installs repo by cloning it over the network.
439 """
vapierae39f562016-10-10 19:08:17 -0700440 if gitc_init:
441 _GitcInitOptions(init_optparse)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000442 opt, args = init_optparse.parse_args(args)
ferringb@google.com79245bf2012-06-14 21:22:01 +0000443 if args:
msb@chromium.org38b04f82010-07-13 23:03:34 +0000444 init_optparse.print_usage()
445 sys.exit(1)
446
447 url = opt.repo_url
448 if not url:
449 url = REPO_URL
450 extra_args.append('--repo-url=%s' % url)
451
452 branch = opt.repo_branch
453 if not branch:
454 branch = REPO_REV
455 extra_args.append('--repo-branch=%s' % branch)
456
457 if branch.startswith('refs/heads/'):
458 branch = branch[len('refs/heads/'):]
459 if branch.startswith('refs/'):
Mike Frysingerafe292c2019-08-05 19:15:18 +0000460 print("fatal: invalid branch name '%s'" % branch, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000461 raise CloneFailure()
462
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000463 try:
vapierae39f562016-10-10 19:08:17 -0700464 if gitc_init:
465 gitc_manifest_dir = get_gitc_manifest_dir()
466 if not gitc_manifest_dir:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000467 print('fatal: GITC filesystem is not available. Exiting...',
468 file=sys.stderr)
vapierae39f562016-10-10 19:08:17 -0700469 sys.exit(1)
470 gitc_client = opt.gitc_client
471 if not gitc_client:
472 gitc_client = gitc_parse_clientdir(os.getcwd())
473 if not gitc_client:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000474 print('fatal: GITC client (-c) is required.', file=sys.stderr)
vapierae39f562016-10-10 19:08:17 -0700475 sys.exit(1)
476 client_dir = os.path.join(gitc_manifest_dir, gitc_client)
477 if not os.path.exists(client_dir):
478 os.makedirs(client_dir)
479 os.chdir(client_dir)
480 if os.path.exists(repodir):
481 # This GITC Client has already initialized repo so continue.
482 return
483
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000484 os.mkdir(repodir)
485 except OSError as e:
486 if e.errno != errno.EEXIST:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000487 print('fatal: cannot make %s directory: %s'
488 % (repodir, e.strerror), file=sys.stderr)
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000489 # Don't raise CloneFailure; that would delete the
msb@chromium.org38b04f82010-07-13 23:03:34 +0000490 # name. Instead exit immediately.
491 #
492 sys.exit(1)
493
494 _CheckGitVersion()
495 try:
ferringb@google.com8db6c882012-12-25 17:02:37 +0000496 if NeedSetupGnuPG():
497 can_verify = SetupGnuPG(opt.quiet)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000498 else:
499 can_verify = True
500
msb@chromium.org38b04f82010-07-13 23:03:34 +0000501 dst = os.path.abspath(os.path.join(repodir, S_repo))
vapierae39f562016-10-10 19:08:17 -0700502 _Clone(url, dst, opt.quiet, not opt.no_clone_bundle)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000503
504 if can_verify and not opt.no_repo_verify:
505 rev = _Verify(dst, branch, opt.quiet)
506 else:
507 rev = 'refs/remotes/origin/%s^0' % branch
508
509 _Checkout(dst, branch, rev, opt.quiet)
Mike Frysingerafe292c2019-08-05 19:15:18 +0000510
511 if not os.path.isfile(os.path.join(dst, 'repo')):
512 print("warning: '%s' does not look like a git-repo repository, is "
513 "REPO_URL set correctly?" % url, file=sys.stderr)
514
msb@chromium.org38b04f82010-07-13 23:03:34 +0000515 except CloneFailure:
516 if opt.quiet:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000517 print('fatal: repo init failed; run without --quiet to see why',
518 file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000519 raise
520
521
Mike Frysingerafe292c2019-08-05 19:15:18 +0000522# The git version info broken down into components for easy analysis.
523# Similar to Python's sys.version_info.
524GitVersion = collections.namedtuple(
525 'GitVersion', ('major', 'minor', 'micro', 'full'))
526
527def ParseGitVersion(ver_str=None):
528 if ver_str is None:
529 # Load the version ourselves.
530 ver_str = _GetGitVersion()
531
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000532 if not ver_str.startswith('git version '):
533 return None
534
Mike Frysingerafe292c2019-08-05 19:15:18 +0000535 full_version = ver_str[len('git version '):].strip()
536 num_ver_str = full_version.split('-')[0]
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000537 to_tuple = []
538 for num_str in num_ver_str.split('.')[:3]:
539 if num_str.isdigit():
540 to_tuple.append(int(num_str))
541 else:
542 to_tuple.append(0)
Mike Frysingerafe292c2019-08-05 19:15:18 +0000543 to_tuple.append(full_version)
544 return GitVersion(*to_tuple)
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000545
546
Mike Frysingerafe292c2019-08-05 19:15:18 +0000547def _GetGitVersion():
msb@chromium.org38b04f82010-07-13 23:03:34 +0000548 cmd = [GIT, '--version']
ferringb@google.com79245bf2012-06-14 21:22:01 +0000549 try:
550 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
ferringb@google.com8db6c882012-12-25 17:02:37 +0000551 except OSError as e:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000552 print(file=sys.stderr)
553 print("fatal: '%s' is not available" % GIT, file=sys.stderr)
554 print('fatal: %s' % e, file=sys.stderr)
555 print(file=sys.stderr)
556 print('Please make sure %s is installed and in your path.' % GIT,
557 file=sys.stderr)
558 raise
ferringb@google.com79245bf2012-06-14 21:22:01 +0000559
msb@chromium.org38b04f82010-07-13 23:03:34 +0000560 ver_str = proc.stdout.read().strip()
561 proc.stdout.close()
562 proc.wait()
Mike Frysingerafe292c2019-08-05 19:15:18 +0000563 return ver_str.decode('utf-8')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000564
Mike Frysingerafe292c2019-08-05 19:15:18 +0000565
566def _CheckGitVersion():
567 try:
568 ver_act = ParseGitVersion()
569 except OSError:
570 raise CloneFailure()
571
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000572 if ver_act is None:
Nico Weber64ae6992019-09-19 19:03:28 +0000573 print('fatal: unable to detect git version', file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000574 raise CloneFailure()
575
msb@chromium.org38b04f82010-07-13 23:03:34 +0000576 if ver_act < MIN_GIT_VERSION:
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000577 need = '.'.join(map(str, MIN_GIT_VERSION))
Mike Frysingerafe292c2019-08-05 19:15:18 +0000578 print('fatal: git %s or later required' % need, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000579 raise CloneFailure()
580
581
ferringb@google.com8db6c882012-12-25 17:02:37 +0000582def NeedSetupGnuPG():
msb@chromium.org38b04f82010-07-13 23:03:34 +0000583 if not os.path.isdir(home_dot_repo):
584 return True
585
586 kv = os.path.join(home_dot_repo, 'keyring-version')
587 if not os.path.exists(kv):
588 return True
589
590 kv = open(kv).read()
591 if not kv:
592 return True
593
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000594 kv = tuple(map(int, kv.split('.')))
msb@chromium.org38b04f82010-07-13 23:03:34 +0000595 if kv < KEYRING_VERSION:
596 return True
597 return False
598
599
ferringb@google.com8db6c882012-12-25 17:02:37 +0000600def SetupGnuPG(quiet):
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000601 try:
602 os.mkdir(home_dot_repo)
603 except OSError as e:
604 if e.errno != errno.EEXIST:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000605 print('fatal: cannot make %s directory: %s'
606 % (home_dot_repo, e.strerror), file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000607 sys.exit(1)
608
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000609 try:
610 os.mkdir(gpg_dir, stat.S_IRWXU)
611 except OSError as e:
612 if e.errno != errno.EEXIST:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000613 print('fatal: cannot make %s directory: %s' % (gpg_dir, e.strerror),
614 file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000615 sys.exit(1)
616
msb@chromium.org2c64b712011-01-11 22:57:47 +0000617 env = os.environ.copy()
vapierae39f562016-10-10 19:08:17 -0700618 try:
619 env['GNUPGHOME'] = gpg_dir
620 except UnicodeEncodeError:
621 env['GNUPGHOME'] = gpg_dir.encode()
msb@chromium.org38b04f82010-07-13 23:03:34 +0000622
623 cmd = ['gpg', '--import']
624 try:
625 proc = subprocess.Popen(cmd,
vapierae39f562016-10-10 19:08:17 -0700626 env=env,
627 stdin=subprocess.PIPE)
ferringb@google.com8db6c882012-12-25 17:02:37 +0000628 except OSError as e:
msb@chromium.org38b04f82010-07-13 23:03:34 +0000629 if not quiet:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000630 print('warning: gpg (GnuPG) is not available.', file=sys.stderr)
631 print('warning: Installing it is strongly encouraged.', file=sys.stderr)
632 print(file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000633 return False
634
Nico Weber64ae6992019-09-19 19:03:28 +0000635 proc.stdin.write(MAINTAINER_KEYS.encode('utf-8'))
msb@chromium.org38b04f82010-07-13 23:03:34 +0000636 proc.stdin.close()
637
638 if proc.wait() != 0:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000639 print('fatal: registering repo maintainer keys failed', file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000640 sys.exit(1)
Mike Frysingerafe292c2019-08-05 19:15:18 +0000641 print()
msb@chromium.org38b04f82010-07-13 23:03:34 +0000642
643 fd = open(os.path.join(home_dot_repo, 'keyring-version'), 'w')
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000644 fd.write('.'.join(map(str, KEYRING_VERSION)) + '\n')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000645 fd.close()
646 return True
647
648
649def _SetConfig(local, name, value):
650 """Set a git configuration option to the specified value.
651 """
652 cmd = [GIT, 'config', name, value]
vapierae39f562016-10-10 19:08:17 -0700653 if subprocess.Popen(cmd, cwd=local).wait() != 0:
msb@chromium.org38b04f82010-07-13 23:03:34 +0000654 raise CloneFailure()
655
656
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000657def _InitHttp():
658 handlers = []
659
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000660 mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000661 try:
662 import netrc
663 n = netrc.netrc()
664 for host in n.hosts:
665 p = n.hosts[host]
vapierae39f562016-10-10 19:08:17 -0700666 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
ferringb@google.com79245bf2012-06-14 21:22:01 +0000667 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
Mike Frysingerafe292c2019-08-05 19:15:18 +0000668 except:
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000669 pass
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000670 handlers.append(urllib.request.HTTPBasicAuthHandler(mgr))
671 handlers.append(urllib.request.HTTPDigestAuthHandler(mgr))
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000672
673 if 'http_proxy' in os.environ:
674 url = os.environ['http_proxy']
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000675 handlers.append(urllib.request.ProxyHandler({'http': url, 'https': url}))
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000676 if 'REPO_CURL_VERBOSE' in os.environ:
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000677 handlers.append(urllib.request.HTTPHandler(debuglevel=1))
678 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
679 urllib.request.install_opener(urllib.request.build_opener(*handlers))
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000680
vapierae39f562016-10-10 19:08:17 -0700681
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000682def _Fetch(url, local, src, quiet):
683 if not quiet:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000684 print('Get %s' % url, file=sys.stderr)
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000685
msb@chromium.org38b04f82010-07-13 23:03:34 +0000686 cmd = [GIT, 'fetch']
687 if quiet:
688 cmd.append('--quiet')
689 err = subprocess.PIPE
690 else:
691 err = None
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000692 cmd.append(src)
693 cmd.append('+refs/heads/*:refs/remotes/origin/*')
Mike Frysingerafe292c2019-08-05 19:15:18 +0000694 cmd.append('+refs/tags/*:refs/tags/*')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000695
vapierae39f562016-10-10 19:08:17 -0700696 proc = subprocess.Popen(cmd, cwd=local, stderr=err)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000697 if err:
698 proc.stderr.read()
699 proc.stderr.close()
700 if proc.wait() != 0:
701 raise CloneFailure()
702
vapierae39f562016-10-10 19:08:17 -0700703
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000704def _DownloadBundle(url, local, quiet):
705 if not url.endswith('/'):
706 url += '/'
707 url += 'clone.bundle'
708
709 proc = subprocess.Popen(
vapierae39f562016-10-10 19:08:17 -0700710 [GIT, 'config', '--get-regexp', 'url.*.insteadof'],
711 cwd=local,
712 stdout=subprocess.PIPE)
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000713 for line in proc.stdout:
Nico Weber64ae6992019-09-19 19:03:28 +0000714 line = line.decode('utf-8')
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000715 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
716 if m:
717 new_url = m.group(1)
718 old_url = m.group(2)
719 if url.startswith(old_url):
720 url = new_url + url[len(old_url):]
721 break
722 proc.stdout.close()
723 proc.wait()
724
725 if not url.startswith('http:') and not url.startswith('https:'):
726 return False
727
728 dest = open(os.path.join(local, '.git', 'clone.bundle'), 'w+b')
729 try:
730 try:
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000731 r = urllib.request.urlopen(url)
732 except urllib.error.HTTPError as e:
vapierae39f562016-10-10 19:08:17 -0700733 if e.code in [401, 403, 404, 501]:
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000734 return False
Mike Frysingerafe292c2019-08-05 19:15:18 +0000735 print('fatal: Cannot get %s' % url, file=sys.stderr)
736 print('fatal: HTTP error %s' % e.code, file=sys.stderr)
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000737 raise CloneFailure()
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000738 except urllib.error.URLError as e:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000739 print('fatal: Cannot get %s' % url, file=sys.stderr)
740 print('fatal: error %s' % e.reason, file=sys.stderr)
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000741 raise CloneFailure()
742 try:
743 if not quiet:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000744 print('Get %s' % url, file=sys.stderr)
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000745 while True:
746 buf = r.read(8192)
Mike Frysingerafe292c2019-08-05 19:15:18 +0000747 if not buf:
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000748 return True
749 dest.write(buf)
750 finally:
751 r.close()
752 finally:
753 dest.close()
754
vapierae39f562016-10-10 19:08:17 -0700755
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000756def _ImportBundle(local):
757 path = os.path.join(local, '.git', 'clone.bundle')
758 try:
759 _Fetch(local, local, path, True)
760 finally:
761 os.remove(path)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000762
vapierae39f562016-10-10 19:08:17 -0700763
764def _Clone(url, local, quiet, clone_bundle):
msb@chromium.org38b04f82010-07-13 23:03:34 +0000765 """Clones a git repository to a new subdirectory of repodir
766 """
767 try:
768 os.mkdir(local)
ferringb@google.com8db6c882012-12-25 17:02:37 +0000769 except OSError as e:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000770 print('fatal: cannot make %s directory: %s' % (local, e.strerror),
771 file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000772 raise CloneFailure()
773
774 cmd = [GIT, 'init', '--quiet']
775 try:
vapierae39f562016-10-10 19:08:17 -0700776 proc = subprocess.Popen(cmd, cwd=local)
ferringb@google.com8db6c882012-12-25 17:02:37 +0000777 except OSError as e:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000778 print(file=sys.stderr)
779 print("fatal: '%s' is not available" % GIT, file=sys.stderr)
780 print('fatal: %s' % e, file=sys.stderr)
781 print(file=sys.stderr)
782 print('Please make sure %s is installed and in your path.' % GIT,
783 file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000784 raise CloneFailure()
785 if proc.wait() != 0:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000786 print('fatal: could not create %s' % local, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000787 raise CloneFailure()
788
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000789 _InitHttp()
msb@chromium.org38b04f82010-07-13 23:03:34 +0000790 _SetConfig(local, 'remote.origin.url', url)
vapierae39f562016-10-10 19:08:17 -0700791 _SetConfig(local,
792 'remote.origin.fetch',
793 '+refs/heads/*:refs/remotes/origin/*')
794 if clone_bundle and _DownloadBundle(url, local, quiet):
jeffbailey@chromium.orgad390562011-11-12 00:37:07 +0000795 _ImportBundle(local)
vapierae39f562016-10-10 19:08:17 -0700796 _Fetch(url, local, 'origin', quiet)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000797
798
799def _Verify(cwd, branch, quiet):
800 """Verify the branch has been signed by a tag.
801 """
802 cmd = [GIT, 'describe', 'origin/%s' % branch]
803 proc = subprocess.Popen(cmd,
804 stdout=subprocess.PIPE,
805 stderr=subprocess.PIPE,
vapierae39f562016-10-10 19:08:17 -0700806 cwd=cwd)
Nico Weber64ae6992019-09-19 19:03:28 +0000807 cur = proc.stdout.read().strip().decode('utf-8')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000808 proc.stdout.close()
809
810 proc.stderr.read()
811 proc.stderr.close()
812
813 if proc.wait() != 0 or not cur:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000814 print(file=sys.stderr)
815 print("fatal: branch '%s' has not been signed" % branch, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000816 raise CloneFailure()
817
818 m = re.compile(r'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur)
819 if m:
820 cur = m.group(1)
821 if not quiet:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000822 print(file=sys.stderr)
823 print("info: Ignoring branch '%s'; using tagged release '%s'"
824 % (branch, cur), file=sys.stderr)
825 print(file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000826
msb@chromium.org2c64b712011-01-11 22:57:47 +0000827 env = os.environ.copy()
vapierae39f562016-10-10 19:08:17 -0700828 try:
829 env['GNUPGHOME'] = gpg_dir
830 except UnicodeEncodeError:
831 env['GNUPGHOME'] = gpg_dir.encode()
msb@chromium.org38b04f82010-07-13 23:03:34 +0000832
833 cmd = [GIT, 'tag', '-v', cur]
834 proc = subprocess.Popen(cmd,
vapierae39f562016-10-10 19:08:17 -0700835 stdout=subprocess.PIPE,
836 stderr=subprocess.PIPE,
837 cwd=cwd,
838 env=env)
Nico Weber64ae6992019-09-19 19:03:28 +0000839 out = proc.stdout.read().decode('utf-8')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000840 proc.stdout.close()
841
Nico Weber64ae6992019-09-19 19:03:28 +0000842 err = proc.stderr.read().decode('utf-8')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000843 proc.stderr.close()
844
845 if proc.wait() != 0:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000846 print(file=sys.stderr)
847 print(out, file=sys.stderr)
848 print(err, file=sys.stderr)
849 print(file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000850 raise CloneFailure()
851 return '%s^0' % cur
852
853
854def _Checkout(cwd, branch, rev, quiet):
855 """Checkout an upstream branch into the repository and track it.
856 """
857 cmd = [GIT, 'update-ref', 'refs/heads/default', rev]
vapierae39f562016-10-10 19:08:17 -0700858 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
msb@chromium.org38b04f82010-07-13 23:03:34 +0000859 raise CloneFailure()
860
861 _SetConfig(cwd, 'branch.default.remote', 'origin')
862 _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch)
863
864 cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default']
vapierae39f562016-10-10 19:08:17 -0700865 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
msb@chromium.org38b04f82010-07-13 23:03:34 +0000866 raise CloneFailure()
867
868 cmd = [GIT, 'read-tree', '--reset', '-u']
869 if not quiet:
870 cmd.append('-v')
871 cmd.append('HEAD')
vapierae39f562016-10-10 19:08:17 -0700872 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
msb@chromium.org38b04f82010-07-13 23:03:34 +0000873 raise CloneFailure()
874
875
876def _FindRepo():
877 """Look for a repo installation, starting at the current directory.
878 """
ferringb@google.com8db6c882012-12-25 17:02:37 +0000879 curdir = os.getcwd()
msb@chromium.org38b04f82010-07-13 23:03:34 +0000880 repo = None
881
msb@chromium.org2c64b712011-01-11 22:57:47 +0000882 olddir = None
ferringb@google.com8db6c882012-12-25 17:02:37 +0000883 while curdir != '/' \
vapierae39f562016-10-10 19:08:17 -0700884 and curdir != olddir \
885 and not repo:
ferringb@google.com8db6c882012-12-25 17:02:37 +0000886 repo = os.path.join(curdir, repodir, REPO_MAIN)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000887 if not os.path.isfile(repo):
888 repo = None
ferringb@google.com8db6c882012-12-25 17:02:37 +0000889 olddir = curdir
890 curdir = os.path.dirname(curdir)
891 return (repo, os.path.join(curdir, repodir))
msb@chromium.org38b04f82010-07-13 23:03:34 +0000892
893
vapierae39f562016-10-10 19:08:17 -0700894class _Options(object):
msb@chromium.org38b04f82010-07-13 23:03:34 +0000895 help = False
896
897
898def _ParseArguments(args):
899 cmd = None
900 opt = _Options()
901 arg = []
902
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +0000903 for i in range(len(args)):
msb@chromium.org38b04f82010-07-13 23:03:34 +0000904 a = args[i]
905 if a == '-h' or a == '--help':
906 opt.help = True
907
908 elif not a.startswith('-'):
909 cmd = a
910 arg = args[i + 1:]
911 break
912 return cmd, opt, arg
913
914
915def _Usage():
vapierae39f562016-10-10 19:08:17 -0700916 gitc_usage = ""
917 if get_gitc_manifest_dir():
918 gitc_usage = " gitc-init Initialize a GITC Client.\n"
919
Mike Frysingerafe292c2019-08-05 19:15:18 +0000920 print(
vapierae39f562016-10-10 19:08:17 -0700921 """usage: repo COMMAND [ARGS]
msb@chromium.org38b04f82010-07-13 23:03:34 +0000922
923repo is not yet installed. Use "repo init" to install it here.
924
925The most commonly used repo commands are:
926
927 init Install repo in the current working directory
vapierae39f562016-10-10 19:08:17 -0700928""" + gitc_usage +
929 """ help Display detailed help on a command
msb@chromium.org38b04f82010-07-13 23:03:34 +0000930
931For access to the full online help, install repo ("repo init").
Mike Frysingerafe292c2019-08-05 19:15:18 +0000932""")
933 sys.exit(0)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000934
935
936def _Help(args):
937 if args:
938 if args[0] == 'init':
939 init_optparse.print_help()
msb@chromium.org2c64b712011-01-11 22:57:47 +0000940 sys.exit(0)
vapierae39f562016-10-10 19:08:17 -0700941 elif args[0] == 'gitc-init':
942 _GitcInitOptions(init_optparse)
943 init_optparse.print_help()
944 sys.exit(0)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000945 else:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000946 print("error: '%s' is not a bootstrap command.\n"
947 ' For access to online help, install repo ("repo init").'
948 % args[0], file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000949 else:
950 _Usage()
951 sys.exit(1)
952
953
954def _NotInstalled():
Mike Frysingerafe292c2019-08-05 19:15:18 +0000955 print('error: repo is not installed. Use "repo init" to install it here.',
956 file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000957 sys.exit(1)
958
959
960def _NoCommands(cmd):
Mike Frysingerafe292c2019-08-05 19:15:18 +0000961 print("""error: command '%s' requires repo to be installed first.
962 Use "repo init" to install it here.""" % cmd, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +0000963 sys.exit(1)
964
965
966def _RunSelf(wrapper_path):
967 my_dir = os.path.dirname(wrapper_path)
968 my_main = os.path.join(my_dir, 'main.py')
969 my_git = os.path.join(my_dir, '.git')
970
971 if os.path.isfile(my_main) and os.path.isdir(my_git):
972 for name in ['git_config.py',
973 'project.py',
974 'subcmds']:
975 if not os.path.exists(os.path.join(my_dir, name)):
976 return None, None
977 return my_main, my_git
978 return None, None
979
980
981def _SetDefaultsTo(gitdir):
982 global REPO_URL
983 global REPO_REV
984
985 REPO_URL = gitdir
986 proc = subprocess.Popen([GIT,
987 '--git-dir=%s' % gitdir,
988 'symbolic-ref',
989 'HEAD'],
vapierae39f562016-10-10 19:08:17 -0700990 stdout=subprocess.PIPE,
991 stderr=subprocess.PIPE)
Nico Weber64ae6992019-09-19 19:03:28 +0000992 REPO_REV = proc.stdout.read().strip().decode('utf-8')
msb@chromium.org38b04f82010-07-13 23:03:34 +0000993 proc.stdout.close()
994
995 proc.stderr.read()
996 proc.stderr.close()
997
998 if proc.wait() != 0:
Mike Frysingerafe292c2019-08-05 19:15:18 +0000999 print('fatal: %s has no current branch' % gitdir, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +00001000 sys.exit(1)
1001
1002
1003def main(orig_args):
msb@chromium.org38b04f82010-07-13 23:03:34 +00001004 cmd, opt, args = _ParseArguments(orig_args)
1005
vapierae39f562016-10-10 19:08:17 -07001006 repo_main, rel_repo_dir = None, None
1007 # Don't use the local repo copy, make sure to switch to the gitc client first.
1008 if cmd != 'gitc-init':
1009 repo_main, rel_repo_dir = _FindRepo()
1010
msb@chromium.org38b04f82010-07-13 23:03:34 +00001011 wrapper_path = os.path.abspath(__file__)
1012 my_main, my_git = _RunSelf(wrapper_path)
1013
vapierae39f562016-10-10 19:08:17 -07001014 cwd = os.getcwd()
1015 if get_gitc_manifest_dir() and cwd.startswith(get_gitc_manifest_dir()):
Mike Frysingerafe292c2019-08-05 19:15:18 +00001016 print('error: repo cannot be used in the GITC local manifest directory.'
1017 '\nIf you want to work on this GITC client please rerun this '
1018 'command from the corresponding client under /gitc/',
1019 file=sys.stderr)
vapierae39f562016-10-10 19:08:17 -07001020 sys.exit(1)
ferringb@google.com8db6c882012-12-25 17:02:37 +00001021 if not repo_main:
msb@chromium.org38b04f82010-07-13 23:03:34 +00001022 if opt.help:
1023 _Usage()
1024 if cmd == 'help':
1025 _Help(args)
1026 if not cmd:
1027 _NotInstalled()
vapierae39f562016-10-10 19:08:17 -07001028 if cmd == 'init' or cmd == 'gitc-init':
msb@chromium.org38b04f82010-07-13 23:03:34 +00001029 if my_git:
1030 _SetDefaultsTo(my_git)
1031 try:
vapierae39f562016-10-10 19:08:17 -07001032 _Init(args, gitc_init=(cmd == 'gitc-init'))
msb@chromium.org38b04f82010-07-13 23:03:34 +00001033 except CloneFailure:
Don Garrett24f2cc02018-12-18 18:07:17 +00001034 path = os.path.join(repodir, S_repo)
Mike Frysingerafe292c2019-08-05 19:15:18 +00001035 print("fatal: cloning the git-repo repository failed, will remove "
1036 "'%s' " % path, file=sys.stderr)
Don Garrett24f2cc02018-12-18 18:07:17 +00001037 shutil.rmtree(path, ignore_errors=True)
msb@chromium.org38b04f82010-07-13 23:03:34 +00001038 sys.exit(1)
ferringb@google.com8db6c882012-12-25 17:02:37 +00001039 repo_main, rel_repo_dir = _FindRepo()
msb@chromium.org38b04f82010-07-13 23:03:34 +00001040 else:
1041 _NoCommands(cmd)
1042
1043 if my_main:
ferringb@google.com8db6c882012-12-25 17:02:37 +00001044 repo_main = my_main
msb@chromium.org38b04f82010-07-13 23:03:34 +00001045
akeshet@google.com3bdfbeb2014-02-06 04:52:54 +00001046 ver_str = '.'.join(map(str, VERSION))
1047 me = [sys.executable, repo_main,
ferringb@google.com8db6c882012-12-25 17:02:37 +00001048 '--repo-dir=%s' % rel_repo_dir,
msb@chromium.org38b04f82010-07-13 23:03:34 +00001049 '--wrapper-version=%s' % ver_str,
1050 '--wrapper-path=%s' % wrapper_path,
1051 '--']
1052 me.extend(orig_args)
1053 me.extend(extra_args)
1054 try:
Don Garrett24f2cc02018-12-18 18:07:17 +00001055 if platform.system() == "Windows":
1056 sys.exit(subprocess.call(me))
1057 else:
1058 os.execv(sys.executable, me)
ferringb@google.com8db6c882012-12-25 17:02:37 +00001059 except OSError as e:
Mike Frysingerafe292c2019-08-05 19:15:18 +00001060 print("fatal: unable to start %s" % repo_main, file=sys.stderr)
1061 print("fatal: %s" % e, file=sys.stderr)
msb@chromium.org38b04f82010-07-13 23:03:34 +00001062 sys.exit(148)
1063
1064
1065if __name__ == '__main__':
1066 main(sys.argv[1:])