2008-10-21 14:00:00 +00:00
|
|
|
# Copyright (C) 2008 The Android Open Source Project
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import os
|
2012-04-16 18:02:21 +00:00
|
|
|
import platform
|
2012-04-16 17:36:08 +00:00
|
|
|
import re
|
2008-10-21 14:00:00 +00:00
|
|
|
import sys
|
2019-06-13 06:24:21 +00:00
|
|
|
import urllib.parse
|
2008-10-21 14:00:00 +00:00
|
|
|
|
|
|
|
from color import Coloring
|
2009-03-04 01:47:06 +00:00
|
|
|
from command import InteractiveCommand, MirrorSafeCommand
|
2008-10-21 14:00:00 +00:00
|
|
|
from error import ManifestParseError
|
2015-03-17 18:29:58 +00:00
|
|
|
from project import SyncBuffer
|
2011-09-19 21:50:58 +00:00
|
|
|
from git_config import GitConfig
|
2020-02-11 23:51:08 +00:00
|
|
|
from git_command import git_require, MIN_GIT_VERSION_SOFT, MIN_GIT_VERSION_HARD
|
2021-07-26 23:08:54 +00:00
|
|
|
import fetch
|
2016-11-03 17:37:53 +00:00
|
|
|
import platform_utils
|
2020-02-29 07:53:41 +00:00
|
|
|
from wrapper import Wrapper
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2009-03-04 01:47:06 +00:00
|
|
|
class Init(InteractiveCommand, MirrorSafeCommand):
|
2021-06-14 20:05:19 +00:00
|
|
|
COMMON = True
|
2022-04-05 21:21:56 +00:00
|
|
|
MULTI_MANIFEST_SUPPORT = True
|
2021-02-18 20:20:15 +00:00
|
|
|
helpSummary = "Initialize a repo client checkout in the current directory"
|
2008-10-21 14:00:00 +00:00
|
|
|
helpUsage = """
|
2021-02-18 20:20:15 +00:00
|
|
|
%prog [options] [manifest url]
|
2008-10-21 14:00:00 +00:00
|
|
|
"""
|
|
|
|
helpDescription = """
|
|
|
|
The '%prog' command is run once to install and initialize repo.
|
|
|
|
The latest repo source code and manifest collection is downloaded
|
|
|
|
from the server and is installed in the .repo/ directory in the
|
|
|
|
current working directory.
|
|
|
|
|
2021-02-18 20:20:15 +00:00
|
|
|
When creating a new checkout, the manifest URL is the only required setting.
|
|
|
|
It may be specified using the --manifest-url option, or as the first optional
|
|
|
|
argument.
|
|
|
|
|
2009-04-18 18:33:32 +00:00
|
|
|
The optional -b argument can be used to select the manifest branch
|
2020-09-06 19:51:21 +00:00
|
|
|
to checkout and use. If no branch is specified, the remote's default
|
2021-02-23 20:43:07 +00:00
|
|
|
branch is used. This is equivalent to using -b HEAD.
|
2009-04-18 18:33:32 +00:00
|
|
|
|
|
|
|
The optional -m argument can be used to specify an alternate manifest
|
|
|
|
to be used. If no manifest is specified, the manifest default.xml
|
|
|
|
will be used.
|
|
|
|
|
2021-07-26 23:08:54 +00:00
|
|
|
If the --standalone-manifest argument is set, the manifest will be downloaded
|
|
|
|
directly from the specified --manifest-url as a static file (rather than
|
|
|
|
setting up a manifest git checkout). With --standalone-manifest, the manifest
|
|
|
|
will be fully static and will not be re-downloaded during subsesquent
|
|
|
|
`repo init` and `repo sync` calls.
|
|
|
|
|
2010-10-08 08:02:09 +00:00
|
|
|
The --reference option can be used to point to a directory that
|
|
|
|
has the content of a --mirror sync. This will make the working
|
|
|
|
directory use as much data as possible from the local reference
|
|
|
|
directory when fetching from the server. This will make the sync
|
|
|
|
go a lot faster by reducing data traffic on the network.
|
|
|
|
|
2018-10-19 10:07:05 +00:00
|
|
|
The --dissociate option can be used to borrow the objects from
|
|
|
|
the directory specified with the --reference option only to reduce
|
|
|
|
network transfer, and stop borrowing from them after a first clone
|
|
|
|
is made by making necessary local copies of borrowed objects.
|
|
|
|
|
2015-12-11 03:16:41 +00:00
|
|
|
The --no-clone-bundle option disables any attempt to use
|
|
|
|
$URL/clone.bundle to bootstrap a new Git repository from a
|
|
|
|
resumeable bundle file on a content delivery network. This
|
|
|
|
may be necessary if there are problems with the local Python
|
|
|
|
HTTP client or proxy configuration, but the Git binary works.
|
2010-10-08 08:02:09 +00:00
|
|
|
|
2018-10-10 05:05:11 +00:00
|
|
|
# Switching Manifest Branches
|
2009-04-18 18:33:32 +00:00
|
|
|
|
|
|
|
To switch to another manifest branch, `repo init -b otherbranch`
|
|
|
|
may be used in an existing client. However, as this only updates the
|
|
|
|
manifest, a subsequent `repo sync` (or `repo sync -d`) is necessary
|
|
|
|
to update the working directory files.
|
2008-10-21 14:00:00 +00:00
|
|
|
"""
|
|
|
|
|
2021-04-13 18:57:40 +00:00
|
|
|
def _CommonOptions(self, p):
|
|
|
|
"""Disable due to re-use of Wrapper()."""
|
|
|
|
|
2020-02-05 05:01:59 +00:00
|
|
|
def _Options(self, p, gitc_init=False):
|
2021-04-08 23:14:15 +00:00
|
|
|
Wrapper().InitParser(p, gitc_init=gitc_init)
|
2021-11-18 22:40:18 +00:00
|
|
|
m = p.add_option_group('Multi-manifest')
|
|
|
|
m.add_option('--outer-manifest', action='store_true',
|
|
|
|
help='operate starting at the outermost manifest')
|
|
|
|
m.add_option('--no-outer-manifest', dest='outer_manifest',
|
|
|
|
action='store_false', default=None,
|
|
|
|
help='do not operate on outer manifests')
|
|
|
|
m.add_option('--this-manifest-only', action='store_true', default=None,
|
|
|
|
help='only operate on this (sub)manifest')
|
|
|
|
m.add_option('--no-this-manifest-only', '--all-manifests',
|
|
|
|
dest='this_manifest_only', action='store_false',
|
|
|
|
help='operate on this manifest and its submanifests')
|
2011-04-05 09:31:10 +00:00
|
|
|
|
2012-11-16 18:13:09 +00:00
|
|
|
def _RegisteredEnvironmentOptions(self):
|
|
|
|
return {'REPO_MANIFEST_URL': 'manifest_url',
|
|
|
|
'REPO_MIRROR_LOCATION': 'reference'}
|
|
|
|
|
2008-10-21 14:00:00 +00:00
|
|
|
def _SyncManifest(self, opt):
|
2022-03-29 23:01:18 +00:00
|
|
|
"""Call manifestProject.Sync with arguments from opt.
|
2021-07-26 23:08:54 +00:00
|
|
|
|
2022-03-29 23:01:18 +00:00
|
|
|
Args:
|
|
|
|
opt: options from optparse.
|
|
|
|
"""
|
|
|
|
if not self.manifest.manifestProject.Sync(
|
|
|
|
manifest_url=opt.manifest_url,
|
|
|
|
manifest_branch=opt.manifest_branch,
|
|
|
|
standalone_manifest=opt.standalone_manifest,
|
|
|
|
groups=opt.groups,
|
|
|
|
platform=opt.platform,
|
|
|
|
mirror=opt.mirror,
|
|
|
|
dissociate=opt.dissociate,
|
|
|
|
reference=opt.reference,
|
|
|
|
worktree=opt.worktree,
|
|
|
|
submodules=opt.submodules,
|
|
|
|
archive=opt.archive,
|
|
|
|
partial_clone=opt.partial_clone,
|
|
|
|
clone_filter=opt.clone_filter,
|
|
|
|
partial_clone_exclude=opt.partial_clone_exclude,
|
|
|
|
clone_bundle=opt.clone_bundle,
|
|
|
|
git_lfs=opt.git_lfs,
|
|
|
|
use_superproject=opt.use_superproject,
|
|
|
|
verbose=opt.verbose,
|
|
|
|
current_branch_only=opt.current_branch_only,
|
|
|
|
tags=opt.tags,
|
2022-04-05 21:21:56 +00:00
|
|
|
depth=opt.depth,
|
2022-04-06 17:10:21 +00:00
|
|
|
git_event_log=self.git_event_log,
|
2022-04-05 21:21:56 +00:00
|
|
|
manifest_name=opt.manifest_name):
|
2008-10-21 14:00:00 +00:00
|
|
|
sys.exit(1)
|
|
|
|
|
2009-07-02 17:53:04 +00:00
|
|
|
def _Prompt(self, prompt, value):
|
2019-07-04 21:35:11 +00:00
|
|
|
print('%-10s [%s]: ' % (prompt, value), end='')
|
|
|
|
# TODO: When we require Python 3, use flush=True w/print above.
|
|
|
|
sys.stdout.flush()
|
2008-10-21 14:00:00 +00:00
|
|
|
a = sys.stdin.readline().strip()
|
2009-07-02 17:53:04 +00:00
|
|
|
if a == '':
|
|
|
|
return value
|
|
|
|
return a
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
def _ShouldConfigureUser(self, opt):
|
2020-09-06 18:53:18 +00:00
|
|
|
gc = self.client.globalConfig
|
2011-04-05 09:31:10 +00:00
|
|
|
mp = self.manifest.manifestProject
|
|
|
|
|
|
|
|
# If we don't have local settings, get from global.
|
|
|
|
if not mp.config.Has('user.name') or not mp.config.Has('user.email'):
|
|
|
|
if not gc.Has('user.name') or not gc.Has('user.email'):
|
|
|
|
return True
|
|
|
|
|
|
|
|
mp.config.SetString('user.name', gc.GetString('user.name'))
|
|
|
|
mp.config.SetString('user.email', gc.GetString('user.email'))
|
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
if not opt.quiet:
|
|
|
|
print()
|
|
|
|
print('Your identity is: %s <%s>' % (mp.config.GetString('user.name'),
|
|
|
|
mp.config.GetString('user.email')))
|
|
|
|
print("If you want to change this, please re-run 'repo init' with --config-name")
|
2011-04-05 09:31:10 +00:00
|
|
|
return False
|
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
def _ConfigureUser(self, opt):
|
2008-10-21 14:00:00 +00:00
|
|
|
mp = self.manifest.manifestProject
|
|
|
|
|
2009-07-02 17:53:04 +00:00
|
|
|
while True:
|
2020-02-22 03:48:40 +00:00
|
|
|
if not opt.quiet:
|
|
|
|
print()
|
2020-02-12 05:31:05 +00:00
|
|
|
name = self._Prompt('Your Name', mp.UserName)
|
2009-07-02 17:53:04 +00:00
|
|
|
email = self._Prompt('Your Email', mp.UserEmail)
|
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
if not opt.quiet:
|
|
|
|
print()
|
2012-11-02 05:59:27 +00:00
|
|
|
print('Your identity is: %s <%s>' % (name, email))
|
2019-07-04 21:35:11 +00:00
|
|
|
print('is this correct [y/N]? ', end='')
|
|
|
|
# TODO: When we require Python 3, use flush=True w/print above.
|
|
|
|
sys.stdout.flush()
|
2012-11-14 00:19:39 +00:00
|
|
|
a = sys.stdin.readline().strip().lower()
|
2010-04-01 18:03:53 +00:00
|
|
|
if a in ('yes', 'y', 't', 'true'):
|
2009-07-02 17:53:04 +00:00
|
|
|
break
|
|
|
|
|
|
|
|
if name != mp.UserName:
|
|
|
|
mp.config.SetString('user.name', name)
|
|
|
|
if email != mp.UserEmail:
|
|
|
|
mp.config.SetString('user.email', email)
|
2008-10-21 14:00:00 +00:00
|
|
|
|
|
|
|
def _HasColorSet(self, gc):
|
|
|
|
for n in ['ui', 'diff', 'status']:
|
|
|
|
if gc.Has('color.%s' % n):
|
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
|
|
def _ConfigureColor(self):
|
2020-09-06 18:53:18 +00:00
|
|
|
gc = self.client.globalConfig
|
2008-10-21 14:00:00 +00:00
|
|
|
if self._HasColorSet(gc):
|
|
|
|
return
|
|
|
|
|
|
|
|
class _Test(Coloring):
|
|
|
|
def __init__(self):
|
|
|
|
Coloring.__init__(self, gc, 'test color display')
|
|
|
|
self._on = True
|
|
|
|
out = _Test()
|
|
|
|
|
2012-11-02 05:59:27 +00:00
|
|
|
print()
|
|
|
|
print("Testing colorized output (for 'repo diff', 'repo status'):")
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2012-11-14 03:09:38 +00:00
|
|
|
for c in ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan']:
|
2008-10-21 14:00:00 +00:00
|
|
|
out.write(' ')
|
|
|
|
out.printer(fg=c)(' %-6s ', c)
|
|
|
|
out.write(' ')
|
|
|
|
out.printer(fg='white', bg='black')(' %s ' % 'white')
|
|
|
|
out.nl()
|
|
|
|
|
2012-11-14 03:09:38 +00:00
|
|
|
for c in ['bold', 'dim', 'ul', 'reverse']:
|
2008-10-21 14:00:00 +00:00
|
|
|
out.write(' ')
|
|
|
|
out.printer(fg='black', attr=c)(' %-6s ', c)
|
|
|
|
out.nl()
|
|
|
|
|
2019-07-04 21:35:11 +00:00
|
|
|
print('Enable color display in this user account (y/N)? ', end='')
|
|
|
|
# TODO: When we require Python 3, use flush=True w/print above.
|
|
|
|
sys.stdout.flush()
|
2008-10-21 14:00:00 +00:00
|
|
|
a = sys.stdin.readline().strip().lower()
|
|
|
|
if a in ('y', 'yes', 't', 'true', 'on'):
|
|
|
|
gc.SetString('color.ui', 'auto')
|
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
def _DisplayResult(self, opt):
|
2012-10-23 07:41:54 +00:00
|
|
|
if self.manifest.IsMirror:
|
|
|
|
init_type = 'mirror '
|
|
|
|
else:
|
|
|
|
init_type = ''
|
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
if not opt.quiet:
|
|
|
|
print()
|
|
|
|
print('repo %shas been initialized in %s' %
|
|
|
|
(init_type, self.manifest.topdir))
|
2012-10-23 07:41:54 +00:00
|
|
|
|
|
|
|
current_dir = os.getcwd()
|
|
|
|
if current_dir != self.manifest.topdir:
|
2013-01-29 00:49:48 +00:00
|
|
|
print('If this is not the directory in which you want to initialize '
|
2012-11-02 05:59:27 +00:00
|
|
|
'repo, please run:')
|
|
|
|
print(' rm -r %s/.repo' % self.manifest.topdir)
|
|
|
|
print('and try again.')
|
2012-10-23 07:41:54 +00:00
|
|
|
|
2019-08-27 05:10:59 +00:00
|
|
|
def ValidateOptions(self, opt, args):
|
2012-10-05 12:50:05 +00:00
|
|
|
if opt.reference:
|
2018-01-22 16:57:29 +00:00
|
|
|
opt.reference = os.path.expanduser(opt.reference)
|
2012-10-05 12:50:05 +00:00
|
|
|
|
2013-10-16 09:02:35 +00:00
|
|
|
# Check this here, else manifest will be tagged "not new" and init won't be
|
|
|
|
# possible anymore without removing the .repo/manifests directory.
|
2021-11-16 19:48:09 +00:00
|
|
|
if opt.mirror:
|
|
|
|
if opt.archive:
|
|
|
|
self.OptionParser.error('--mirror and --archive cannot be used '
|
|
|
|
'together.')
|
|
|
|
if opt.use_superproject is not None:
|
|
|
|
self.OptionParser.error('--mirror and --use-superproject cannot be '
|
|
|
|
'used together.')
|
2019-08-27 05:10:59 +00:00
|
|
|
|
2021-11-18 02:38:24 +00:00
|
|
|
if opt.standalone_manifest and (opt.manifest_branch or
|
|
|
|
opt.manifest_name != 'default.xml'):
|
2021-07-26 23:08:54 +00:00
|
|
|
self.OptionParser.error('--manifest-branch and --manifest-name cannot'
|
|
|
|
' be used with --standalone-manifest.')
|
|
|
|
|
2020-08-27 05:50:12 +00:00
|
|
|
if args:
|
2021-02-18 20:20:15 +00:00
|
|
|
if opt.manifest_url:
|
|
|
|
self.OptionParser.error(
|
|
|
|
'--manifest-url option and URL argument both specified: only use '
|
|
|
|
'one to select the manifest URL.')
|
|
|
|
|
|
|
|
opt.manifest_url = args.pop(0)
|
|
|
|
|
|
|
|
if args:
|
|
|
|
self.OptionParser.error('too many arguments to init')
|
2020-08-27 05:50:12 +00:00
|
|
|
|
2019-08-27 05:10:59 +00:00
|
|
|
def Execute(self, opt, args):
|
2020-02-11 23:51:08 +00:00
|
|
|
git_require(MIN_GIT_VERSION_HARD, fail=True)
|
|
|
|
if not git_require(MIN_GIT_VERSION_SOFT):
|
|
|
|
print('repo: warning: git-%s+ will soon be required; please upgrade your '
|
|
|
|
'version of git to maintain support.'
|
|
|
|
% ('.'.join(str(x) for x in MIN_GIT_VERSION_SOFT),),
|
|
|
|
file=sys.stderr)
|
2013-10-16 09:02:35 +00:00
|
|
|
|
2020-02-29 07:53:41 +00:00
|
|
|
rp = self.manifest.repoProject
|
|
|
|
|
|
|
|
# Handle new --repo-url requests.
|
|
|
|
if opt.repo_url:
|
|
|
|
remote = rp.GetRemote('origin')
|
|
|
|
remote.url = opt.repo_url
|
|
|
|
remote.Save()
|
|
|
|
|
2020-02-29 07:53:41 +00:00
|
|
|
# Handle new --repo-rev requests.
|
|
|
|
if opt.repo_rev:
|
|
|
|
wrapper = Wrapper()
|
2022-01-25 07:10:28 +00:00
|
|
|
try:
|
|
|
|
remote_ref, rev = wrapper.check_repo_rev(
|
|
|
|
rp.gitdir, opt.repo_rev, repo_verify=opt.repo_verify, quiet=opt.quiet)
|
|
|
|
except wrapper.CloneFailure:
|
|
|
|
print('fatal: double check your --repo-rev setting.', file=sys.stderr)
|
|
|
|
sys.exit(1)
|
2020-02-29 07:53:41 +00:00
|
|
|
branch = rp.GetBranch('default')
|
|
|
|
branch.merge = remote_ref
|
2020-12-06 03:57:19 +00:00
|
|
|
rp.work_git.reset('--hard', rev)
|
2020-02-29 07:53:41 +00:00
|
|
|
branch.Save()
|
|
|
|
|
2020-02-09 07:28:34 +00:00
|
|
|
if opt.worktree:
|
|
|
|
# Older versions of git supported worktree, but had dangerous gc bugs.
|
|
|
|
git_require((2, 15, 0), fail=True, msg='git gc worktree corruption')
|
|
|
|
|
2008-10-21 14:00:00 +00:00
|
|
|
self._SyncManifest(opt)
|
2021-02-09 08:26:31 +00:00
|
|
|
|
2009-03-19 17:17:12 +00:00
|
|
|
if os.isatty(0) and os.isatty(1) and not self.manifest.IsMirror:
|
2020-02-22 03:48:40 +00:00
|
|
|
if opt.config_name or self._ShouldConfigureUser(opt):
|
|
|
|
self._ConfigureUser(opt)
|
2008-10-21 14:00:00 +00:00
|
|
|
self._ConfigureColor()
|
|
|
|
|
2020-02-22 03:48:40 +00:00
|
|
|
self._DisplayResult(opt)
|