summaryrefslogtreecommitdiffstats
path: root/repo
diff options
context:
space:
mode:
Diffstat (limited to 'repo')
-rwxr-xr-xrepo197
1 files changed, 150 insertions, 47 deletions
diff --git a/repo b/repo
index 77695651..e5cb8904 100755
--- a/repo
+++ b/repo
@@ -1,8 +1,11 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2 2
3## repo default configuration 3# repo default configuration
4## 4#
5REPO_URL = 'https://gerrit.googlesource.com/git-repo' 5import os
6REPO_URL = os.environ.get('REPO_URL', None)
7if not REPO_URL:
8 REPO_URL = 'https://gerrit.googlesource.com/git-repo'
6REPO_REV = 'stable' 9REPO_REV = 'stable'
7 10
8# Copyright (C) 2008 Google Inc. 11# Copyright (C) 2008 Google Inc.
@@ -20,7 +23,7 @@ REPO_REV = 'stable'
20# limitations under the License. 23# limitations under the License.
21 24
22# increment this whenever we make important changes to this script 25# increment this whenever we make important changes to this script
23VERSION = (1, 21) 26VERSION = (1, 22)
24 27
25# increment this if the MAINTAINER_KEYS block is modified 28# increment this if the MAINTAINER_KEYS block is modified
26KEYRING_VERSION = (1, 2) 29KEYRING_VERSION = (1, 2)
@@ -101,18 +104,19 @@ JuinEP+AwLAUZ1Bsx9ISC0Agpk2VeHXPL3FGhroEmoMvBzO0kTFGyoeT7PR/BfKv
101-----END PGP PUBLIC KEY BLOCK----- 104-----END PGP PUBLIC KEY BLOCK-----
102""" 105"""
103 106
104GIT = 'git' # our git command 107GIT = 'git' # our git command
105MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version 108MIN_GIT_VERSION = (1, 7, 2) # minimum supported git version
106repodir = '.repo' # name of repo's private directory 109repodir = '.repo' # name of repo's private directory
107S_repo = 'repo' # special repo repository 110S_repo = 'repo' # special repo repository
108S_manifests = 'manifests' # special manifest repository 111S_manifests = 'manifests' # special manifest repository
109REPO_MAIN = S_repo + '/main.py' # main script 112REPO_MAIN = S_repo + '/main.py' # main script
110MIN_PYTHON_VERSION = (2, 6) # minimum supported python version 113MIN_PYTHON_VERSION = (2, 6) # minimum supported python version
114GITC_CONFIG_FILE = '/gitc/.config'
115GITC_FS_ROOT_DIR = '/gitc/manifest-rw/'
111 116
112 117
113import errno 118import errno
114import optparse 119import optparse
115import os
116import re 120import re
117import shutil 121import shutil
118import stat 122import stat
@@ -212,14 +216,69 @@ group.add_option('--config-name',
212 dest='config_name', action="store_true", default=False, 216 dest='config_name', action="store_true", default=False,
213 help='Always prompt for name/e-mail') 217 help='Always prompt for name/e-mail')
214 218
219
220def _GitcInitOptions(init_optparse_arg):
221 init_optparse_arg.set_usage("repo gitc-init -u url -c client [options]")
222 g = init_optparse_arg.add_option_group('GITC options')
223 g.add_option('-f', '--manifest-file',
224 dest='manifest_file',
225 help='Optional manifest file to use for this GITC client.')
226 g.add_option('-c', '--gitc-client',
227 dest='gitc_client',
228 help='The name of the gitc_client instance to create or modify.')
229
230_gitc_manifest_dir = None
231
232
233def get_gitc_manifest_dir():
234 global _gitc_manifest_dir
235 if _gitc_manifest_dir is None:
236 _gitc_manifest_dir = ''
237 try:
238 with open(GITC_CONFIG_FILE, 'r') as gitc_config:
239 for line in gitc_config:
240 match = re.match('gitc_dir=(?P<gitc_manifest_dir>.*)', line)
241 if match:
242 _gitc_manifest_dir = match.group('gitc_manifest_dir')
243 except IOError:
244 pass
245 return _gitc_manifest_dir
246
247
248def gitc_parse_clientdir(gitc_fs_path):
249 """Parse a path in the GITC FS and return its client name.
250
251 @param gitc_fs_path: A subdirectory path within the GITC_FS_ROOT_DIR.
252
253 @returns: The GITC client name
254 """
255 if gitc_fs_path == GITC_FS_ROOT_DIR:
256 return None
257 if not gitc_fs_path.startswith(GITC_FS_ROOT_DIR):
258 manifest_dir = get_gitc_manifest_dir()
259 if manifest_dir == '':
260 return None
261 if manifest_dir[-1] != '/':
262 manifest_dir += '/'
263 if gitc_fs_path == manifest_dir:
264 return None
265 if not gitc_fs_path.startswith(manifest_dir):
266 return None
267 return gitc_fs_path.split(manifest_dir)[1].split('/')[0]
268 return gitc_fs_path.split(GITC_FS_ROOT_DIR)[1].split('/')[0]
269
270
215class CloneFailure(Exception): 271class CloneFailure(Exception):
272
216 """Indicate the remote clone of repo itself failed. 273 """Indicate the remote clone of repo itself failed.
217 """ 274 """
218 275
219 276
220def _Init(args): 277def _Init(args, gitc_init=False):
221 """Installs repo by cloning it over the network. 278 """Installs repo by cloning it over the network.
222 """ 279 """
280 if gitc_init:
281 _GitcInitOptions(init_optparse)
223 opt, args = init_optparse.parse_args(args) 282 opt, args = init_optparse.parse_args(args)
224 if args: 283 if args:
225 init_optparse.print_usage() 284 init_optparse.print_usage()
@@ -242,6 +301,26 @@ def _Init(args):
242 raise CloneFailure() 301 raise CloneFailure()
243 302
244 try: 303 try:
304 if gitc_init:
305 gitc_manifest_dir = get_gitc_manifest_dir()
306 if not gitc_manifest_dir:
307 _print('fatal: GITC filesystem is not available. Exiting...',
308 file=sys.stderr)
309 sys.exit(1)
310 gitc_client = opt.gitc_client
311 if not gitc_client:
312 gitc_client = gitc_parse_clientdir(os.getcwd())
313 if not gitc_client:
314 _print('fatal: GITC client (-c) is required.', file=sys.stderr)
315 sys.exit(1)
316 client_dir = os.path.join(gitc_manifest_dir, gitc_client)
317 if not os.path.exists(client_dir):
318 os.makedirs(client_dir)
319 os.chdir(client_dir)
320 if os.path.exists(repodir):
321 # This GITC Client has already initialized repo so continue.
322 return
323
245 os.mkdir(repodir) 324 os.mkdir(repodir)
246 except OSError as e: 325 except OSError as e:
247 if e.errno != errno.EEXIST: 326 if e.errno != errno.EEXIST:
@@ -358,8 +437,8 @@ def SetupGnuPG(quiet):
358 cmd = ['gpg', '--import'] 437 cmd = ['gpg', '--import']
359 try: 438 try:
360 proc = subprocess.Popen(cmd, 439 proc = subprocess.Popen(cmd,
361 env = env, 440 env=env,
362 stdin = subprocess.PIPE) 441 stdin=subprocess.PIPE)
363 except OSError as e: 442 except OSError as e:
364 if not quiet: 443 if not quiet:
365 _print('warning: gpg (GnuPG) is not available.', file=sys.stderr) 444 _print('warning: gpg (GnuPG) is not available.', file=sys.stderr)
@@ -385,7 +464,7 @@ def _SetConfig(local, name, value):
385 """Set a git configuration option to the specified value. 464 """Set a git configuration option to the specified value.
386 """ 465 """
387 cmd = [GIT, 'config', name, value] 466 cmd = [GIT, 'config', name, value]
388 if subprocess.Popen(cmd, cwd = local).wait() != 0: 467 if subprocess.Popen(cmd, cwd=local).wait() != 0:
389 raise CloneFailure() 468 raise CloneFailure()
390 469
391 470
@@ -398,9 +477,9 @@ def _InitHttp():
398 n = netrc.netrc() 477 n = netrc.netrc()
399 for host in n.hosts: 478 for host in n.hosts:
400 p = n.hosts[host] 479 p = n.hosts[host]
401 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2]) 480 mgr.add_password(p[1], 'http://%s/' % host, p[0], p[2])
402 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2]) 481 mgr.add_password(p[1], 'https://%s/' % host, p[0], p[2])
403 except: 482 except: # pylint: disable=bare-except
404 pass 483 pass
405 handlers.append(urllib.request.HTTPBasicAuthHandler(mgr)) 484 handlers.append(urllib.request.HTTPBasicAuthHandler(mgr))
406 handlers.append(urllib.request.HTTPDigestAuthHandler(mgr)) 485 handlers.append(urllib.request.HTTPDigestAuthHandler(mgr))
@@ -413,6 +492,7 @@ def _InitHttp():
413 handlers.append(urllib.request.HTTPSHandler(debuglevel=1)) 492 handlers.append(urllib.request.HTTPSHandler(debuglevel=1))
414 urllib.request.install_opener(urllib.request.build_opener(*handlers)) 493 urllib.request.install_opener(urllib.request.build_opener(*handlers))
415 494
495
416def _Fetch(url, local, src, quiet): 496def _Fetch(url, local, src, quiet):
417 if not quiet: 497 if not quiet:
418 _print('Get %s' % url, file=sys.stderr) 498 _print('Get %s' % url, file=sys.stderr)
@@ -427,22 +507,23 @@ def _Fetch(url, local, src, quiet):
427 cmd.append('+refs/heads/*:refs/remotes/origin/*') 507 cmd.append('+refs/heads/*:refs/remotes/origin/*')
428 cmd.append('refs/tags/*:refs/tags/*') 508 cmd.append('refs/tags/*:refs/tags/*')
429 509
430 proc = subprocess.Popen(cmd, cwd = local, stderr = err) 510 proc = subprocess.Popen(cmd, cwd=local, stderr=err)
431 if err: 511 if err:
432 proc.stderr.read() 512 proc.stderr.read()
433 proc.stderr.close() 513 proc.stderr.close()
434 if proc.wait() != 0: 514 if proc.wait() != 0:
435 raise CloneFailure() 515 raise CloneFailure()
436 516
517
437def _DownloadBundle(url, local, quiet): 518def _DownloadBundle(url, local, quiet):
438 if not url.endswith('/'): 519 if not url.endswith('/'):
439 url += '/' 520 url += '/'
440 url += 'clone.bundle' 521 url += 'clone.bundle'
441 522
442 proc = subprocess.Popen( 523 proc = subprocess.Popen(
443 [GIT, 'config', '--get-regexp', 'url.*.insteadof'], 524 [GIT, 'config', '--get-regexp', 'url.*.insteadof'],
444 cwd = local, 525 cwd=local,
445 stdout = subprocess.PIPE) 526 stdout=subprocess.PIPE)
446 for line in proc.stdout: 527 for line in proc.stdout:
447 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line) 528 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
448 if m: 529 if m:
@@ -484,6 +565,7 @@ def _DownloadBundle(url, local, quiet):
484 finally: 565 finally:
485 dest.close() 566 dest.close()
486 567
568
487def _ImportBundle(local): 569def _ImportBundle(local):
488 path = os.path.join(local, '.git', 'clone.bundle') 570 path = os.path.join(local, '.git', 'clone.bundle')
489 try: 571 try:
@@ -491,6 +573,7 @@ def _ImportBundle(local):
491 finally: 573 finally:
492 os.remove(path) 574 os.remove(path)
493 575
576
494def _Clone(url, local, quiet): 577def _Clone(url, local, quiet):
495 """Clones a git repository to a new subdirectory of repodir 578 """Clones a git repository to a new subdirectory of repodir
496 """ 579 """
@@ -503,14 +586,14 @@ def _Clone(url, local, quiet):
503 586
504 cmd = [GIT, 'init', '--quiet'] 587 cmd = [GIT, 'init', '--quiet']
505 try: 588 try:
506 proc = subprocess.Popen(cmd, cwd = local) 589 proc = subprocess.Popen(cmd, cwd=local)
507 except OSError as e: 590 except OSError as e:
508 _print(file=sys.stderr) 591 _print(file=sys.stderr)
509 _print("fatal: '%s' is not available" % GIT, file=sys.stderr) 592 _print("fatal: '%s' is not available" % GIT, file=sys.stderr)
510 _print('fatal: %s' % e, file=sys.stderr) 593 _print('fatal: %s' % e, file=sys.stderr)
511 _print(file=sys.stderr) 594 _print(file=sys.stderr)
512 _print('Please make sure %s is installed and in your path.' % GIT, 595 _print('Please make sure %s is installed and in your path.' % GIT,
513 file=sys.stderr) 596 file=sys.stderr)
514 raise CloneFailure() 597 raise CloneFailure()
515 if proc.wait() != 0: 598 if proc.wait() != 0:
516 _print('fatal: could not create %s' % local, file=sys.stderr) 599 _print('fatal: could not create %s' % local, file=sys.stderr)
@@ -518,12 +601,12 @@ def _Clone(url, local, quiet):
518 601
519 _InitHttp() 602 _InitHttp()
520 _SetConfig(local, 'remote.origin.url', url) 603 _SetConfig(local, 'remote.origin.url', url)
521 _SetConfig(local, 'remote.origin.fetch', 604 _SetConfig(local,
522 '+refs/heads/*:refs/remotes/origin/*') 605 'remote.origin.fetch',
606 '+refs/heads/*:refs/remotes/origin/*')
523 if _DownloadBundle(url, local, quiet): 607 if _DownloadBundle(url, local, quiet):
524 _ImportBundle(local) 608 _ImportBundle(local)
525 else: 609 _Fetch(url, local, 'origin', quiet)
526 _Fetch(url, local, 'origin', quiet)
527 610
528 611
529def _Verify(cwd, branch, quiet): 612def _Verify(cwd, branch, quiet):
@@ -533,7 +616,7 @@ def _Verify(cwd, branch, quiet):
533 proc = subprocess.Popen(cmd, 616 proc = subprocess.Popen(cmd,
534 stdout=subprocess.PIPE, 617 stdout=subprocess.PIPE,
535 stderr=subprocess.PIPE, 618 stderr=subprocess.PIPE,
536 cwd = cwd) 619 cwd=cwd)
537 cur = proc.stdout.read().strip() 620 cur = proc.stdout.read().strip()
538 proc.stdout.close() 621 proc.stdout.close()
539 622
@@ -551,7 +634,7 @@ def _Verify(cwd, branch, quiet):
551 if not quiet: 634 if not quiet:
552 _print(file=sys.stderr) 635 _print(file=sys.stderr)
553 _print("info: Ignoring branch '%s'; using tagged release '%s'" 636 _print("info: Ignoring branch '%s'; using tagged release '%s'"
554 % (branch, cur), file=sys.stderr) 637 % (branch, cur), file=sys.stderr)
555 _print(file=sys.stderr) 638 _print(file=sys.stderr)
556 639
557 env = os.environ.copy() 640 env = os.environ.copy()
@@ -559,10 +642,10 @@ def _Verify(cwd, branch, quiet):
559 642
560 cmd = [GIT, 'tag', '-v', cur] 643 cmd = [GIT, 'tag', '-v', cur]
561 proc = subprocess.Popen(cmd, 644 proc = subprocess.Popen(cmd,
562 stdout = subprocess.PIPE, 645 stdout=subprocess.PIPE,
563 stderr = subprocess.PIPE, 646 stderr=subprocess.PIPE,
564 cwd = cwd, 647 cwd=cwd,
565 env = env) 648 env=env)
566 out = proc.stdout.read() 649 out = proc.stdout.read()
567 proc.stdout.close() 650 proc.stdout.close()
568 651
@@ -582,21 +665,21 @@ def _Checkout(cwd, branch, rev, quiet):
582 """Checkout an upstream branch into the repository and track it. 665 """Checkout an upstream branch into the repository and track it.
583 """ 666 """
584 cmd = [GIT, 'update-ref', 'refs/heads/default', rev] 667 cmd = [GIT, 'update-ref', 'refs/heads/default', rev]
585 if subprocess.Popen(cmd, cwd = cwd).wait() != 0: 668 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
586 raise CloneFailure() 669 raise CloneFailure()
587 670
588 _SetConfig(cwd, 'branch.default.remote', 'origin') 671 _SetConfig(cwd, 'branch.default.remote', 'origin')
589 _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch) 672 _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch)
590 673
591 cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default'] 674 cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default']
592 if subprocess.Popen(cmd, cwd = cwd).wait() != 0: 675 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
593 raise CloneFailure() 676 raise CloneFailure()
594 677
595 cmd = [GIT, 'read-tree', '--reset', '-u'] 678 cmd = [GIT, 'read-tree', '--reset', '-u']
596 if not quiet: 679 if not quiet:
597 cmd.append('-v') 680 cmd.append('-v')
598 cmd.append('HEAD') 681 cmd.append('HEAD')
599 if subprocess.Popen(cmd, cwd = cwd).wait() != 0: 682 if subprocess.Popen(cmd, cwd=cwd).wait() != 0:
600 raise CloneFailure() 683 raise CloneFailure()
601 684
602 685
@@ -608,8 +691,8 @@ def _FindRepo():
608 691
609 olddir = None 692 olddir = None
610 while curdir != '/' \ 693 while curdir != '/' \
611 and curdir != olddir \ 694 and curdir != olddir \
612 and not repo: 695 and not repo:
613 repo = os.path.join(curdir, repodir, REPO_MAIN) 696 repo = os.path.join(curdir, repodir, REPO_MAIN)
614 if not os.path.isfile(repo): 697 if not os.path.isfile(repo):
615 repo = None 698 repo = None
@@ -618,7 +701,7 @@ def _FindRepo():
618 return (repo, os.path.join(curdir, repodir)) 701 return (repo, os.path.join(curdir, repodir))
619 702
620 703
621class _Options: 704class _Options(object):
622 help = False 705 help = False
623 706
624 707
@@ -640,15 +723,20 @@ def _ParseArguments(args):
640 723
641 724
642def _Usage(): 725def _Usage():
726 gitc_usage = ""
727 if get_gitc_manifest_dir():
728 gitc_usage = " gitc-init Initialize a GITC Client.\n"
729
643 _print( 730 _print(
644"""usage: repo COMMAND [ARGS] 731 """usage: repo COMMAND [ARGS]
645 732
646repo is not yet installed. Use "repo init" to install it here. 733repo is not yet installed. Use "repo init" to install it here.
647 734
648The most commonly used repo commands are: 735The most commonly used repo commands are:
649 736
650 init Install repo in the current working directory 737 init Install repo in the current working directory
651 help Display detailed help on a command 738""" + gitc_usage +
739 """ help Display detailed help on a command
652 740
653For access to the full online help, install repo ("repo init"). 741For access to the full online help, install repo ("repo init").
654""", file=sys.stderr) 742""", file=sys.stderr)
@@ -660,6 +748,10 @@ def _Help(args):
660 if args[0] == 'init': 748 if args[0] == 'init':
661 init_optparse.print_help() 749 init_optparse.print_help()
662 sys.exit(0) 750 sys.exit(0)
751 elif args[0] == 'gitc-init':
752 _GitcInitOptions(init_optparse)
753 init_optparse.print_help()
754 sys.exit(0)
663 else: 755 else:
664 _print("error: '%s' is not a bootstrap command.\n" 756 _print("error: '%s' is not a bootstrap command.\n"
665 ' For access to online help, install repo ("repo init").' 757 ' For access to online help, install repo ("repo init").'
@@ -705,8 +797,8 @@ def _SetDefaultsTo(gitdir):
705 '--git-dir=%s' % gitdir, 797 '--git-dir=%s' % gitdir,
706 'symbolic-ref', 798 'symbolic-ref',
707 'HEAD'], 799 'HEAD'],
708 stdout = subprocess.PIPE, 800 stdout=subprocess.PIPE,
709 stderr = subprocess.PIPE) 801 stderr=subprocess.PIPE)
710 REPO_REV = proc.stdout.read().strip() 802 REPO_REV = proc.stdout.read().strip()
711 proc.stdout.close() 803 proc.stdout.close()
712 804
@@ -719,12 +811,23 @@ def _SetDefaultsTo(gitdir):
719 811
720 812
721def main(orig_args): 813def main(orig_args):
722 repo_main, rel_repo_dir = _FindRepo()
723 cmd, opt, args = _ParseArguments(orig_args) 814 cmd, opt, args = _ParseArguments(orig_args)
724 815
816 repo_main, rel_repo_dir = None, None
817 # Don't use the local repo copy, make sure to switch to the gitc client first.
818 if cmd != 'gitc-init':
819 repo_main, rel_repo_dir = _FindRepo()
820
725 wrapper_path = os.path.abspath(__file__) 821 wrapper_path = os.path.abspath(__file__)
726 my_main, my_git = _RunSelf(wrapper_path) 822 my_main, my_git = _RunSelf(wrapper_path)
727 823
824 cwd = os.getcwd()
825 if get_gitc_manifest_dir() and cwd.startswith(get_gitc_manifest_dir()):
826 _print('error: repo cannot be used in the GITC local manifest directory.'
827 '\nIf you want to work on this GITC client please rerun this '
828 'command from the corresponding client under /gitc/',
829 file=sys.stderr)
830 sys.exit(1)
728 if not repo_main: 831 if not repo_main:
729 if opt.help: 832 if opt.help:
730 _Usage() 833 _Usage()
@@ -732,11 +835,11 @@ def main(orig_args):
732 _Help(args) 835 _Help(args)
733 if not cmd: 836 if not cmd:
734 _NotInstalled() 837 _NotInstalled()
735 if cmd == 'init': 838 if cmd == 'init' or cmd == 'gitc-init':
736 if my_git: 839 if my_git:
737 _SetDefaultsTo(my_git) 840 _SetDefaultsTo(my_git)
738 try: 841 try:
739 _Init(args) 842 _Init(args, gitc_init=(cmd == 'gitc-init'))
740 except CloneFailure: 843 except CloneFailure:
741 shutil.rmtree(os.path.join(repodir, S_repo), ignore_errors=True) 844 shutil.rmtree(os.path.join(repodir, S_repo), ignore_errors=True)
742 sys.exit(1) 845 sys.exit(1)