3 ## repo default configuration
5 REPO_URL
='https://android.googlesource.com/tools/repo'
8 # Copyright (C) 2008 Google Inc.
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
14 # http://www.apache.org/licenses/LICENSE-2.0
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.
22 magic
='--calling-python-from-/bin/sh--'
23 """exec" python
-E "$0" "$@" """#$magic"
24 if __name__
== '__main__':
26 if sys.argv
[-1] == '#%s' % magic
:
30 # increment this whenever we make important changes to this script
33 # increment this if the MAINTAINER_KEYS block is modified
34 KEYRING_VERSION
= (1,0)
37 Repo Maintainer <repo@android.kernel.org>
38 -----BEGIN PGP PUBLIC KEY BLOCK-----
39 Version: GnuPG v1.4.2.2 (GNU/Linux)
41 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
77 -----END PGP PUBLIC KEY BLOCK-----
80 GIT
= 'git' # our git command
81 MIN_GIT_VERSION
= (1, 5, 4) # minimum supported git version
82 repodir
= '.repo' # name of repo's private directory
83 S_repo
= 'repo' # special repo reposiory
84 S_manifests
= 'manifests' # special manifest repository
85 REPO_MAIN
= S_repo
+ '/main.py' # main script
96 home_dot_repo
= os.path.expanduser
('~/.repoconfig')
97 gpg_dir
= os.path.
join(home_dot_repo
, 'gnupg')
100 init_optparse
= optparse.OptionParser
(usage
="repo init -u url [options]")
103 group
= init_optparse.add_option_group
('Logging options')
104 group.add_option
('-q', '--quiet',
105 dest
="quiet", action
="store_true", default
=False
,
109 group
= init_optparse.add_option_group
('Manifest options')
110 group.add_option
('-u', '--manifest-url',
112 help='manifest repository location', metavar
='URL')
113 group.add_option
('-b', '--manifest-branch',
114 dest
='manifest_branch',
115 help='manifest branch or revision', metavar
='REVISION')
116 group.add_option
('-m', '--manifest-name',
117 dest
='manifest_name',
118 help='initial manifest file', metavar
='NAME.xml')
119 group.add_option
('--mirror',
120 dest
='mirror', action
='store_true',
121 help='mirror the forrest')
122 group.add_option
('--reference',
124 help='location of mirror directory', metavar
='DIR')
125 group.add_option
('--depth', type='int', default
=None
,
127 help='create a shallow clone with given depth; see git clone')
131 group
= init_optparse.add_option_group
('repo Version options')
132 group.add_option
('--repo-url',
134 help='repo repository location', metavar
='URL')
135 group.add_option
('--repo-branch',
137 help='repo branch or revision', metavar
='REVISION')
138 group.add_option
('--no-repo-verify',
139 dest
='no_repo_verify', action
='store_true',
140 help='do not verify repo source code')
143 group
= init_optparse.add_option_group
('Other options')
144 group.add_option
('--config-name',
145 dest
='config_name', action
="store_true", default
=False
,
146 help='Always prompt for name/e-mail')
148 class CloneFailure
(Exception
):
149 """Indicate the remote clone of repo itself failed.
154 """Installs repo by cloning it over the network.
156 opt
, args
= init_optparse.parse_args
(args
)
158 init_optparse.print_usage
()
164 extra_args.append
('--repo-url=%s' % url
)
166 branch
= opt.repo_branch
169 extra_args.append
('--repo-branch=%s' % branch
)
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
177 if not os.path.isdir
(repodir
):
181 print
>>sys.stderr
, \
182 'fatal: cannot make %s directory: %s' % (
184 # Don't faise CloneFailure; that would delete the
185 # name. Instead exit immediately.
191 if _NeedSetupGnuPG
():
192 can_verify
= _SetupGnuPG
(opt.quiet
)
196 dst
= os.path.abspath
(os.path.
join(repodir
, S_repo
))
197 _Clone
(url
, dst
, opt.quiet
)
199 if can_verify and not opt.no_repo_verify
:
200 rev = _Verify
(dst
, branch
, opt.quiet
)
202 rev = 'refs/remotes/origin/%s^0' % branch
204 _Checkout
(dst
, branch
, rev, opt.quiet
)
207 print
>>sys.stderr
, \
208 'fatal: repo init failed; run without --quiet to see why'
212 def _CheckGitVersion
():
213 cmd
= [GIT
, '--version']
214 proc
= subprocess.Popen
(cmd
, stdout
=subprocess.PIPE
)
215 ver_str
= proc.stdout.
read().strip
()
219 if not ver_str.startswith
('git version '):
220 print
>>sys.stderr
, 'error: "%s" unsupported' % ver_str
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
231 def _NeedSetupGnuPG
():
232 if not os.path.isdir
(home_dot_repo
):
235 kv
= os.path.
join(home_dot_repo
, 'keyring-version')
236 if not os.path.exists
(kv
):
243 kv
= tuple
(map
(lambda x
: int
(x
), kv.
split('.')))
244 if kv
< KEYRING_VERSION
:
249 def _SetupGnuPG
(quiet
):
250 if not os.path.isdir
(home_dot_repo
):
252 os.mkdir
(home_dot_repo
)
254 print
>>sys.stderr
, \
255 'fatal: cannot make %s directory: %s' % (
256 home_dot_repo
, e.strerror
)
259 if not os.path.isdir
(gpg_dir
):
261 os.mkdir
(gpg_dir
, 0700)
263 print
>>sys.stderr
, \
264 'fatal: cannot make %s directory: %s' % (
268 env
= os.environ.copy
()
269 env
['GNUPGHOME'] = gpg_dir.encode
()
271 cmd
= ['gpg', '--import']
273 proc
= subprocess.Popen
(cmd
,
275 stdin
= subprocess.PIPE
)
278 print
>>sys.stderr
, 'warning: gpg (GnuPG) is not available.'
279 print
>>sys.stderr
, 'warning: Installing it is strongly encouraged.'
283 proc.stdin.
write(MAINTAINER_KEYS
)
287 print
>>sys.stderr
, 'fatal: registering repo maintainer keys failed'
291 fd
= open
(os.path.
join(home_dot_repo
, 'keyring-version'), 'w')
292 fd.
write('.'.
join(map
(lambda x
: str
(x
), KEYRING_VERSION
)) + '\n')
297 def _SetConfig
(local, name
, value
):
298 """Set a git configuration option to the specified value.
300 cmd
= [GIT
, 'config', name
, value
]
301 if subprocess.Popen
(cmd
, cwd
= local).
wait() != 0:
308 mgr
= urllib2.HTTPPasswordMgrWithDefaultRealm
()
314 mgr.add_password
(None
, 'http://%s/' % host, p
[0], p
[2])
315 mgr.add_password
(None
, 'https://%s/' % host, p
[0], p
[2])
318 handlers.append
(urllib2.HTTPBasicAuthHandler
(mgr
))
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
))
328 def _Fetch
(url
, local, src
, quiet
):
330 print
>>sys.stderr
, 'Get %s' % url
334 cmd.append
('--quiet')
335 err
= subprocess.PIPE
339 cmd.append
('+refs/heads/*:refs/remotes/origin/*')
340 cmd.append
('refs/tags/*:refs/tags/*')
342 proc
= subprocess.Popen
(cmd
, cwd
= local, stderr
= err
)
349 def _DownloadBundle
(url
, local, quiet
):
350 if not url.endswith
('/'):
352 url
+= 'clone.bundle'
354 proc
= subprocess.Popen
(
355 [GIT
, 'config', '--get-regexp', 'url.*.insteadof'],
357 stdout
= subprocess.PIPE
)
358 for line
in proc.stdout
:
359 m
= re.compile
(r
'^url\.(.*)\.insteadof (.*)$').match
(line
)
363 if url.startswith
(old_url
):
364 url
= new_url
+ url
[len
(old_url
):]
369 if not url.startswith
('http:') and not url.startswith
('https:'):
372 dest
= open
(os.path.
join(local, '.git', 'clone.bundle'), 'w+b')
375 r
= urllib2.urlopen
(url
)
376 except urllib2.HTTPError
, e
:
379 print
>>sys.stderr
, 'fatal: Cannot get %s' % url
380 print
>>sys.stderr
, 'fatal: HTTP error %s' % e.code
382 except urllib2.URLError
, e
:
383 print
>>sys.stderr
, 'fatal: Cannot get %s' % url
384 print
>>sys.stderr
, 'fatal: error %s' % e.reason
388 print
>>sys.stderr
, 'Get %s' % url
399 def _ImportBundle
(local):
400 path
= os.path.
join(local, '.git', 'clone.bundle')
402 _Fetch
(local, local, path
, True
)
406 def _Clone
(url
, local, quiet
):
407 """Clones a git repository to a new subdirectory of repodir
412 print
>>sys.stderr
, \
413 'fatal: cannot make %s directory: %s' \
414 % (local, e.strerror
)
417 cmd
= [GIT
, 'init', '--quiet']
419 proc
= subprocess.Popen
(cmd
, cwd
= local)
422 print
>>sys.stderr
, "fatal: '%s' is not available" % GIT
423 print
>>sys.stderr
, 'fatal: %s' % e
425 print
>>sys.stderr
, 'Please make sure %s is installed'\
426 ' and in your path.' % GIT
429 print
>>sys.stderr
, 'fatal: could not create %s' % local
433 _SetConfig
(local, 'remote.origin.url', url
)
434 _SetConfig
(local, 'remote.origin.fetch',
435 '+refs/heads/*:refs/remotes/origin/*')
436 if _DownloadBundle
(url
, local, quiet
):
439 _Fetch
(url
, local, 'origin', quiet
)
442 def _Verify
(cwd
, branch
, quiet
):
443 """Verify the branch has been signed by a tag.
445 cmd
= [GIT
, 'describe', 'origin/%s' % branch
]
446 proc
= subprocess.Popen
(cmd
,
447 stdout
=subprocess.PIPE
,
448 stderr
=subprocess.PIPE
,
450 cur
= proc.stdout.
read().strip
()
456 if proc.
wait() != 0 or not cur
:
459 "fatal: branch '%s' has not been signed" \
463 m
= re.compile
(r
'^(.*)-[0-9]{1,}-g[0-9a-f]{1,}$').match
(cur
)
468 print
>>sys.stderr
, \
469 "info: Ignoring branch '%s'; using tagged release '%s'" \
473 env
= os.environ.copy
()
474 env
['GNUPGHOME'] = gpg_dir.encode
()
476 cmd
= [GIT
, 'tag', '-v', cur
]
477 proc
= subprocess.Popen
(cmd
,
478 stdout
= subprocess.PIPE
,
479 stderr
= subprocess.PIPE
,
482 out
= proc.stdout.
read()
485 err
= proc.stderr.
read()
490 print
>>sys.stderr
, out
491 print
>>sys.stderr
, err
497 def _Checkout
(cwd
, branch
, rev, quiet
):
498 """Checkout an upstream branch into the repository and track it.
500 cmd
= [GIT
, 'update-ref', 'refs/heads/default', rev]
501 if subprocess.Popen
(cmd
, cwd
= cwd
).
wait() != 0:
504 _SetConfig
(cwd
, 'branch.default.remote', 'origin')
505 _SetConfig
(cwd
, 'branch.default.merge', 'refs/heads/%s' % branch
)
507 cmd
= [GIT
, 'symbolic-ref', 'HEAD', 'refs/heads/default']
508 if subprocess.Popen
(cmd
, cwd
= cwd
).
wait() != 0:
511 cmd
= [GIT
, 'read-tree', '--reset', '-u']
515 if subprocess.Popen
(cmd
, cwd
= cwd
).
wait() != 0:
520 """Look for a repo installation, starting at the current directory.
529 repo
= os.path.
join(dir
, repodir
, REPO_MAIN
)
530 if not os.path.isfile
(repo
):
533 dir
= os.path.
dirname(dir
)
534 return (repo
, os.path.
join(dir
, repodir
))
541 def _ParseArguments
(args
):
546 for i
in xrange
(0, len
(args
)):
548 if a
== '-h' or a
== '--help':
551 elif not a.startswith
('-'):
560 """usage: repo COMMAND [ARGS]
562 repo is not yet installed. Use "repo init
" to install it here.
564 The most commonly used repo commands are:
566 init Install repo in the current working directory
567 help Display detailed help on a command
569 For access to the full online help, install repo ("repo init
").
576 if args
[0] == 'init':
577 init_optparse.print_help
()
581 "error: '%s' is not a bootstrap command.\n"\
582 ' For access to online help, install repo ("repo init").'\
591 'error: repo is not installed. Use "repo init" to install it here.'
595 def _NoCommands
(cmd
):
597 """error: command '%s' requires repo to be installed first.
598 Use "repo init
" to install it here.""" % cmd
602 def _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')
607 if os.path.isfile
(my_main
) and os.path.isdir
(my_git
):
608 for name
in ['git_config.py',
611 if not os.path.exists
(os.path.
join(my_dir
, name
)):
613 return my_main
, my_git
617 def _SetDefaultsTo
(gitdir
):
622 proc
= subprocess.Popen
([GIT
,
623 '--git-dir=%s' % gitdir
,
626 stdout
= subprocess.PIPE
,
627 stderr
= subprocess.PIPE
)
628 REPO_REV
= proc.stdout.
read().strip
()
635 print
>>sys.stderr
, 'fatal: %s has no current branch' % gitdir
640 main
, dir
= _FindRepo
()
641 cmd
, opt
, args
= _ParseArguments
(orig_args
)
643 wrapper_path
= os.path.abspath
(__file__
)
644 my_main
, my_git
= _RunSelf
(wrapper_path
)
655 _SetDefaultsTo
(my_git
)
659 for root
, dirs, files
in os.walk
(repodir
, topdown
=False
):
661 os.remove
(os.path.
join(root
, name
))
663 os.
rmdir(os.path.
join(root
, name
))
666 main
, dir
= _FindRepo
()
673 ver_str
= '.'.
join(map
(lambda x
: str
(x
), VERSION
))
675 '--repo-dir=%s' % dir
,
676 '--wrapper-version=%s' % ver_str
,
677 '--wrapper-path=%s' % wrapper_path
,
680 me.extend
(extra_args
)
684 print
>>sys.stderr
, "fatal: unable to start %s" % main
685 print
>>sys.stderr
, "fatal: %s" % e
689 if __name__
== '__main__':