blob: 2a13af5b689989a3775145d600b778d34c9c8aee [file] [log] [blame]
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07001#!/bin/sh
2
3## repo default configuration
4##
Shawn O. Pearce44da16e2011-09-05 14:02:38 -07005REPO_URL='https://code.google.com/p/git-repo/'
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -07006REPO_REV='stable'
7
8# Copyright (C) 2008 Google Inc.
9#
10# Licensed under the Apache License, Version 2.0 (the "License");
11# you may not use this file except in compliance with the License.
12# You may obtain a copy of the License at
13#
14# http://www.apache.org/licenses/LICENSE-2.0
15#
16# Unless required by applicable law or agreed to in writing, software
17# distributed under the License is distributed on an "AS IS" BASIS,
18# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19# See the License for the specific language governing permissions and
20# limitations under the License.
21
22magic='--calling-python-from-/bin/sh--'
Shawn O. Pearce7542d662008-10-21 07:11:36 -070023"""exec" python -E "$0" "$@" """#$magic"
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070024if __name__ == '__main__':
25 import sys
26 if sys.argv[-1] == '#%s' % magic:
27 del sys.argv[-1]
28del magic
29
30# increment this whenever we make important changes to this script
Shawn O. Pearce34fb20f2011-11-30 13:41:02 -080031VERSION = (1, 13)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070032
33# increment this if the MAINTAINER_KEYS block is modified
34KEYRING_VERSION = (1,0)
35MAINTAINER_KEYS = """
36
37 Repo Maintainer <repo@android.kernel.org>
38-----BEGIN PGP PUBLIC KEY BLOCK-----
39Version: GnuPG v1.4.2.2 (GNU/Linux)
40
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
76=CMiZ
77-----END PGP PUBLIC KEY BLOCK-----
78"""
79
80GIT = 'git' # our git command
81MIN_GIT_VERSION = (1, 5, 4) # minimum supported git version
82repodir = '.repo' # name of repo's private directory
83S_repo = 'repo' # special repo reposiory
84S_manifests = 'manifests' # special manifest repository
85REPO_MAIN = S_repo + '/main.py' # main script
86
87
88import optparse
89import os
90import re
91import readline
92import subprocess
93import sys
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -070094import urllib2
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -070095
96home_dot_repo = os.path.expanduser('~/.repoconfig')
97gpg_dir = os.path.join(home_dot_repo, 'gnupg')
98
99extra_args = []
100init_optparse = optparse.OptionParser(usage="repo init -u url [options]")
101
102# Logging
103group = init_optparse.add_option_group('Logging options')
104group.add_option('-q', '--quiet',
105 dest="quiet", action="store_true", default=False,
106 help="be quiet")
107
108# Manifest
109group = init_optparse.add_option_group('Manifest options')
110group.add_option('-u', '--manifest-url',
111 dest='manifest_url',
112 help='manifest repository location', metavar='URL')
113group.add_option('-b', '--manifest-branch',
114 dest='manifest_branch',
115 help='manifest branch or revision', metavar='REVISION')
116group.add_option('-m', '--manifest-name',
117 dest='manifest_name',
118 help='initial manifest file', metavar='NAME.xml')
Shawn O. Pearcee284ad12008-11-04 07:37:10 -0800119group.add_option('--mirror',
120 dest='mirror', action='store_true',
121 help='mirror the forrest')
Shawn O. Pearce88443382010-10-08 10:02:09 +0200122group.add_option('--reference',
123 dest='reference',
124 help='location of mirror directory', metavar='DIR')
Doug Anderson49cd59b2011-06-13 21:42:06 -0700125group.add_option('--depth', type='int', default=None,
126 dest='depth',
127 help='create a shallow clone with given depth; see git clone')
128
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700129
130# Tool
Shawn O. Pearcefd89b672009-04-18 11:28:57 -0700131group = init_optparse.add_option_group('repo Version options')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700132group.add_option('--repo-url',
133 dest='repo_url',
134 help='repo repository location', metavar='URL')
135group.add_option('--repo-branch',
136 dest='repo_branch',
137 help='repo branch or revision', metavar='REVISION')
138group.add_option('--no-repo-verify',
139 dest='no_repo_verify', action='store_true',
140 help='do not verify repo source code')
141
Victor Boivie841be342011-04-05 11:31:10 +0200142# Other
143group = init_optparse.add_option_group('Other options')
144group.add_option('--config-name',
145 dest='config_name', action="store_true", default=False,
146 help='Always prompt for name/e-mail')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700147
148class CloneFailure(Exception):
149 """Indicate the remote clone of repo itself failed.
150 """
151
152
153def _Init(args):
154 """Installs repo by cloning it over the network.
155 """
156 opt, args = init_optparse.parse_args(args)
Shawn O. Pearce34fb20f2011-11-30 13:41:02 -0800157 if args or not opt.manifest_url:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700158 init_optparse.print_usage()
159 sys.exit(1)
160
161 url = opt.repo_url
162 if not url:
163 url = REPO_URL
164 extra_args.append('--repo-url=%s' % url)
165
166 branch = opt.repo_branch
167 if not branch:
168 branch = REPO_REV
169 extra_args.append('--repo-branch=%s' % branch)
170
171 if branch.startswith('refs/heads/'):
172 branch = branch[len('refs/heads/'):]
173 if branch.startswith('refs/'):
174 print >>sys.stderr, "fatal: invalid branch name '%s'" % branch
175 raise CloneFailure()
176
177 if not os.path.isdir(repodir):
178 try:
179 os.mkdir(repodir)
180 except OSError, e:
181 print >>sys.stderr, \
182 'fatal: cannot make %s directory: %s' % (
183 repodir, e.strerror)
184 # Don't faise CloneFailure; that would delete the
185 # name. Instead exit immediately.
186 #
187 sys.exit(1)
188
189 _CheckGitVersion()
190 try:
191 if _NeedSetupGnuPG():
192 can_verify = _SetupGnuPG(opt.quiet)
193 else:
194 can_verify = True
195
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700196 dst = os.path.abspath(os.path.join(repodir, S_repo))
197 _Clone(url, dst, opt.quiet)
198
199 if can_verify and not opt.no_repo_verify:
200 rev = _Verify(dst, branch, opt.quiet)
201 else:
202 rev = 'refs/remotes/origin/%s^0' % branch
203
204 _Checkout(dst, branch, rev, opt.quiet)
205 except CloneFailure:
206 if opt.quiet:
207 print >>sys.stderr, \
208 'fatal: repo init failed; run without --quiet to see why'
209 raise
210
211
212def _CheckGitVersion():
213 cmd = [GIT, '--version']
214 proc = subprocess.Popen(cmd, stdout=subprocess.PIPE)
215 ver_str = proc.stdout.read().strip()
216 proc.stdout.close()
Shawn O. Pearce16191342008-10-28 08:33:34 -0700217 proc.wait()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700218
219 if not ver_str.startswith('git version '):
220 print >>sys.stderr, 'error: "%s" unsupported' % ver_str
221 raise CloneFailure()
222
223 ver_str = ver_str[len('git version '):].strip()
224 ver_act = tuple(map(lambda x: int(x), ver_str.split('.')[0:3]))
225 if ver_act < MIN_GIT_VERSION:
226 need = '.'.join(map(lambda x: str(x), MIN_GIT_VERSION))
227 print >>sys.stderr, 'fatal: git %s or later required' % need
228 raise CloneFailure()
229
230
231def _NeedSetupGnuPG():
232 if not os.path.isdir(home_dot_repo):
233 return True
234
235 kv = os.path.join(home_dot_repo, 'keyring-version')
236 if not os.path.exists(kv):
237 return True
238
239 kv = open(kv).read()
240 if not kv:
241 return True
242
243 kv = tuple(map(lambda x: int(x), kv.split('.')))
244 if kv < KEYRING_VERSION:
245 return True
246 return False
247
248
249def _SetupGnuPG(quiet):
250 if not os.path.isdir(home_dot_repo):
251 try:
252 os.mkdir(home_dot_repo)
253 except OSError, e:
254 print >>sys.stderr, \
255 'fatal: cannot make %s directory: %s' % (
256 home_dot_repo, e.strerror)
257 sys.exit(1)
258
259 if not os.path.isdir(gpg_dir):
260 try:
261 os.mkdir(gpg_dir, 0700)
262 except OSError, e:
263 print >>sys.stderr, \
264 'fatal: cannot make %s directory: %s' % (
265 gpg_dir, e.strerror)
266 sys.exit(1)
267
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800268 env = os.environ.copy()
269 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700270
271 cmd = ['gpg', '--import']
272 try:
273 proc = subprocess.Popen(cmd,
274 env = env,
275 stdin = subprocess.PIPE)
276 except OSError, e:
277 if not quiet:
278 print >>sys.stderr, 'warning: gpg (GnuPG) is not available.'
279 print >>sys.stderr, 'warning: Installing it is strongly encouraged.'
280 print >>sys.stderr
281 return False
282
283 proc.stdin.write(MAINTAINER_KEYS)
284 proc.stdin.close()
285
286 if proc.wait() != 0:
287 print >>sys.stderr, 'fatal: registering repo maintainer keys failed'
288 sys.exit(1)
289 print
290
291 fd = open(os.path.join(home_dot_repo, 'keyring-version'), 'w')
292 fd.write('.'.join(map(lambda x: str(x), KEYRING_VERSION)) + '\n')
293 fd.close()
294 return True
295
296
297def _SetConfig(local, name, value):
298 """Set a git configuration option to the specified value.
299 """
300 cmd = [GIT, 'config', name, value]
301 if subprocess.Popen(cmd, cwd = local).wait() != 0:
302 raise CloneFailure()
303
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700304
305def _InitHttp():
306 handlers = []
307
308 mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
309 try:
310 import netrc
311 n = netrc.netrc()
312 for host in n.hosts:
313 p = n.hosts[host]
314 mgr.add_password(None, 'http://%s/' % host, p[0], p[2])
315 mgr.add_password(None, 'https://%s/' % host, p[0], p[2])
316 except:
317 pass
318 handlers.append(urllib2.HTTPBasicAuthHandler(mgr))
319
320 if 'http_proxy' in os.environ:
321 url = os.environ['http_proxy']
322 handlers.append(urllib2.ProxyHandler({'http': url, 'https': url}))
323 if 'REPO_CURL_VERBOSE' in os.environ:
324 handlers.append(urllib2.HTTPHandler(debuglevel=1))
325 handlers.append(urllib2.HTTPSHandler(debuglevel=1))
326 urllib2.install_opener(urllib2.build_opener(*handlers))
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700327
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700328def _Fetch(url, local, src, quiet):
329 if not quiet:
330 print >>sys.stderr, 'Get %s' % url
331
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700332 cmd = [GIT, 'fetch']
333 if quiet:
334 cmd.append('--quiet')
335 err = subprocess.PIPE
336 else:
337 err = None
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700338 cmd.append(src)
339 cmd.append('+refs/heads/*:refs/remotes/origin/*')
340 cmd.append('refs/tags/*:refs/tags/*')
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700341
342 proc = subprocess.Popen(cmd, cwd = local, stderr = err)
343 if err:
344 proc.stderr.read()
345 proc.stderr.close()
346 if proc.wait() != 0:
347 raise CloneFailure()
348
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700349def _DownloadBundle(url, local, quiet):
350 if not url.endswith('/'):
351 url += '/'
352 url += 'clone.bundle'
353
354 proc = subprocess.Popen(
355 [GIT, 'config', '--get-regexp', 'url.*.insteadof'],
356 cwd = local,
357 stdout = subprocess.PIPE)
358 for line in proc.stdout:
359 m = re.compile(r'^url\.(.*)\.insteadof (.*)$').match(line)
360 if m:
361 new_url = m.group(1)
362 old_url = m.group(2)
363 if url.startswith(old_url):
364 url = new_url + url[len(old_url):]
365 break
366 proc.stdout.close()
367 proc.wait()
368
369 if not url.startswith('http:') and not url.startswith('https:'):
370 return False
371
372 dest = open(os.path.join(local, '.git', 'clone.bundle'), 'w+b')
373 try:
374 try:
375 r = urllib2.urlopen(url)
376 except urllib2.HTTPError, e:
377 if e.code == 404:
378 return False
379 print >>sys.stderr, 'fatal: Cannot get %s' % url
380 print >>sys.stderr, 'fatal: HTTP error %s' % e.code
381 raise CloneFailure()
382 except urllib2.URLError, e:
383 print >>sys.stderr, 'fatal: Cannot get %s' % url
384 print >>sys.stderr, 'fatal: error %s' % e.reason
385 raise CloneFailure()
386 try:
387 if not quiet:
388 print >>sys.stderr, 'Get %s' % url
389 while True:
390 buf = r.read(8192)
391 if buf == '':
392 return True
393 dest.write(buf)
394 finally:
395 r.close()
396 finally:
397 dest.close()
398
399def _ImportBundle(local):
400 path = os.path.join(local, '.git', 'clone.bundle')
401 try:
402 _Fetch(local, local, path, True)
403 finally:
404 os.remove(path)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700405
406def _Clone(url, local, quiet):
407 """Clones a git repository to a new subdirectory of repodir
408 """
409 try:
410 os.mkdir(local)
411 except OSError, e:
412 print >>sys.stderr, \
413 'fatal: cannot make %s directory: %s' \
414 % (local, e.strerror)
415 raise CloneFailure()
416
417 cmd = [GIT, 'init', '--quiet']
418 try:
419 proc = subprocess.Popen(cmd, cwd = local)
420 except OSError, e:
421 print >>sys.stderr
422 print >>sys.stderr, "fatal: '%s' is not available" % GIT
423 print >>sys.stderr, 'fatal: %s' % e
424 print >>sys.stderr
425 print >>sys.stderr, 'Please make sure %s is installed'\
426 ' and in your path.' % GIT
427 raise CloneFailure()
428 if proc.wait() != 0:
429 print >>sys.stderr, 'fatal: could not create %s' % local
430 raise CloneFailure()
431
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700432 _InitHttp()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700433 _SetConfig(local, 'remote.origin.url', url)
434 _SetConfig(local, 'remote.origin.fetch',
435 '+refs/heads/*:refs/remotes/origin/*')
Shawn O. Pearcef322b9a2011-09-19 14:50:58 -0700436 if _DownloadBundle(url, local, quiet):
437 _ImportBundle(local)
438 else:
439 _Fetch(url, local, 'origin', quiet)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700440
441
442def _Verify(cwd, branch, quiet):
443 """Verify the branch has been signed by a tag.
444 """
445 cmd = [GIT, 'describe', 'origin/%s' % branch]
446 proc = subprocess.Popen(cmd,
447 stdout=subprocess.PIPE,
448 stderr=subprocess.PIPE,
449 cwd = cwd)
450 cur = proc.stdout.read().strip()
451 proc.stdout.close()
452
453 proc.stderr.read()
454 proc.stderr.close()
455
456 if proc.wait() != 0 or not cur:
457 print >>sys.stderr
458 print >>sys.stderr,\
459 "fatal: branch '%s' has not been signed" \
460 % branch
461 raise CloneFailure()
462
463 m = re.compile(r'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match(cur)
464 if m:
465 cur = m.group(1)
466 if not quiet:
467 print >>sys.stderr
468 print >>sys.stderr, \
469 "info: Ignoring branch '%s'; using tagged release '%s'" \
470 % (branch, cur)
471 print >>sys.stderr
472
Shawn O. Pearcef18cb762010-12-07 11:41:05 -0800473 env = os.environ.copy()
474 env['GNUPGHOME'] = gpg_dir.encode()
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700475
476 cmd = [GIT, 'tag', '-v', cur]
477 proc = subprocess.Popen(cmd,
478 stdout = subprocess.PIPE,
479 stderr = subprocess.PIPE,
480 cwd = cwd,
481 env = env)
482 out = proc.stdout.read()
483 proc.stdout.close()
484
485 err = proc.stderr.read()
486 proc.stderr.close()
487
488 if proc.wait() != 0:
489 print >>sys.stderr
490 print >>sys.stderr, out
491 print >>sys.stderr, err
492 print >>sys.stderr
493 raise CloneFailure()
494 return '%s^0' % cur
495
496
497def _Checkout(cwd, branch, rev, quiet):
498 """Checkout an upstream branch into the repository and track it.
499 """
500 cmd = [GIT, 'update-ref', 'refs/heads/default', rev]
501 if subprocess.Popen(cmd, cwd = cwd).wait() != 0:
502 raise CloneFailure()
503
504 _SetConfig(cwd, 'branch.default.remote', 'origin')
505 _SetConfig(cwd, 'branch.default.merge', 'refs/heads/%s' % branch)
506
507 cmd = [GIT, 'symbolic-ref', 'HEAD', 'refs/heads/default']
508 if subprocess.Popen(cmd, cwd = cwd).wait() != 0:
509 raise CloneFailure()
510
511 cmd = [GIT, 'read-tree', '--reset', '-u']
512 if not quiet:
513 cmd.append('-v')
514 cmd.append('HEAD')
515 if subprocess.Popen(cmd, cwd = cwd).wait() != 0:
516 raise CloneFailure()
517
518
519def _FindRepo():
520 """Look for a repo installation, starting at the current directory.
521 """
522 dir = os.getcwd()
523 repo = None
524
Anthony Newnamdf14a702011-01-09 17:31:57 -0800525 olddir = None
526 while dir != '/' \
527 and dir != olddir \
528 and not repo:
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700529 repo = os.path.join(dir, repodir, REPO_MAIN)
530 if not os.path.isfile(repo):
531 repo = None
Anthony Newnamdf14a702011-01-09 17:31:57 -0800532 olddir = dir
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700533 dir = os.path.dirname(dir)
534 return (repo, os.path.join(dir, repodir))
535
536
537class _Options:
538 help = False
539
540
541def _ParseArguments(args):
542 cmd = None
543 opt = _Options()
544 arg = []
545
546 for i in xrange(0, len(args)):
547 a = args[i]
548 if a == '-h' or a == '--help':
549 opt.help = True
550
551 elif not a.startswith('-'):
552 cmd = a
553 arg = args[i + 1:]
554 break
555 return cmd, opt, arg
556
557
558def _Usage():
559 print >>sys.stderr,\
560"""usage: repo COMMAND [ARGS]
561
562repo is not yet installed. Use "repo init" to install it here.
563
564The most commonly used repo commands are:
565
566 init Install repo in the current working directory
567 help Display detailed help on a command
568
569For access to the full online help, install repo ("repo init").
570"""
571 sys.exit(1)
572
573
574def _Help(args):
575 if args:
576 if args[0] == 'init':
577 init_optparse.print_help()
Trond Norbyed3fd5372011-01-03 11:35:15 +0100578 sys.exit(0)
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700579 else:
580 print >>sys.stderr,\
581 "error: '%s' is not a bootstrap command.\n"\
582 ' For access to online help, install repo ("repo init").'\
583 % args[0]
584 else:
585 _Usage()
586 sys.exit(1)
587
588
589def _NotInstalled():
590 print >>sys.stderr,\
591'error: repo is not installed. Use "repo init" to install it here.'
592 sys.exit(1)
593
594
595def _NoCommands(cmd):
596 print >>sys.stderr,\
597"""error: command '%s' requires repo to be installed first.
598 Use "repo init" to install it here.""" % cmd
599 sys.exit(1)
600
601
602def _RunSelf(wrapper_path):
603 my_dir = os.path.dirname(wrapper_path)
604 my_main = os.path.join(my_dir, 'main.py')
605 my_git = os.path.join(my_dir, '.git')
606
607 if os.path.isfile(my_main) and os.path.isdir(my_git):
Shawn O. Pearcec8a300f2009-05-18 13:19:57 -0700608 for name in ['git_config.py',
The Android Open Source Projectcf31fe92008-10-21 07:00:00 -0700609 'project.py',
610 'subcmds']:
611 if not os.path.exists(os.path.join(my_dir, name)):
612 return None, None
613 return my_main, my_git
614 return None, None
615
616
617def _SetDefaultsTo(gitdir):
618 global REPO_URL
619 global REPO_REV
620
621 REPO_URL = gitdir
622 proc = subprocess.Popen([GIT,
623 '--git-dir=%s' % gitdir,
624 'symbolic-ref',
625 'HEAD'],
626 stdout = subprocess.PIPE,
627 stderr = subprocess.PIPE)
628 REPO_REV = proc.stdout.read().strip()
629 proc.stdout.close()
630
631 proc.stderr.read()
632 proc.stderr.close()
633
634 if proc.wait() != 0:
635 print >>sys.stderr, 'fatal: %s has no current branch' % gitdir
636 sys.exit(1)
637
638
639def main(orig_args):
640 main, dir = _FindRepo()
641 cmd, opt, args = _ParseArguments(orig_args)
642
643 wrapper_path = os.path.abspath(__file__)
644 my_main, my_git = _RunSelf(wrapper_path)
645
646 if not main:
647 if opt.help:
648 _Usage()
649 if cmd == 'help':
650 _Help(args)
651 if not cmd:
652 _NotInstalled()
653 if cmd == 'init':
654 if my_git:
655 _SetDefaultsTo(my_git)
656 try:
657 _Init(args)
658 except CloneFailure:
659 for root, dirs, files in os.walk(repodir, topdown=False):
660 for name in files:
661 os.remove(os.path.join(root, name))
662 for name in dirs:
663 os.rmdir(os.path.join(root, name))
664 os.rmdir(repodir)
665 sys.exit(1)
666 main, dir = _FindRepo()
667 else:
668 _NoCommands(cmd)
669
670 if my_main:
671 main = my_main
672
673 ver_str = '.'.join(map(lambda x: str(x), VERSION))
674 me = [main,
675 '--repo-dir=%s' % dir,
676 '--wrapper-version=%s' % ver_str,
677 '--wrapper-path=%s' % wrapper_path,
678 '--']
679 me.extend(orig_args)
680 me.extend(extra_args)
681 try:
682 os.execv(main, me)
683 except OSError, e:
684 print >>sys.stderr, "fatal: unable to start %s" % main
685 print >>sys.stderr, "fatal: %s" % e
686 sys.exit(148)
687
688
689if __name__ == '__main__':
690 main(sys.argv[1:])