gitc: drop support

Bug: b/282775958
Change-Id: Ib6383d6fd82a017d0a6670d6558a905d41be321f
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/375314
Reviewed-by: Mike Frysinger <vapier@google.com>
Tested-by: Jason Chang <jasonnc@google.com>
Commit-Queue: Jason Chang <jasonnc@google.com>
This commit is contained in:
Jason Chang 2023-05-26 12:44:50 -07:00 committed by LUCI
parent 082487dcd1
commit 8914b1f86d
13 changed files with 23 additions and 523 deletions

View File

@ -75,7 +75,6 @@ class Command(object):
repodir=None,
client=None,
manifest=None,
gitc_manifest=None,
git_event_log=None,
outer_client=None,
outer_manifest=None,
@ -84,7 +83,6 @@ class Command(object):
self.client = client
self.outer_client = outer_client or client
self.manifest = manifest
self.gitc_manifest = gitc_manifest
self.git_event_log = git_event_log
self.outer_manifest = outer_manifest
@ -506,11 +504,5 @@ class MirrorSafeCommand(object):
"""
class GitcAvailableCommand(object):
"""Command that requires GITC to be available, but does not require the
local client to be a GITC client.
"""
class GitcClientCommand(object):
"""Command that requires the local client to be a GITC client."""

View File

@ -107,6 +107,10 @@ class GitError(RepoError):
return self.message
class GitcUnsupportedError(RepoExitError):
"""Gitc no longer supported."""
class UploadError(RepoError):
"""A bundle upload to Gerrit did not succeed."""

View File

@ -1,166 +0,0 @@
# Copyright (C) 2015 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
import multiprocessing
import re
import sys
import time
import git_command
import git_config
import wrapper
from error import ManifestParseError
NUM_BATCH_RETRIEVE_REVISIONID = 32
def get_gitc_manifest_dir():
return wrapper.Wrapper().get_gitc_manifest_dir()
def parse_clientdir(gitc_fs_path):
return wrapper.Wrapper().gitc_parse_clientdir(gitc_fs_path)
def _get_project_revision(args):
"""Worker for _set_project_revisions to lookup one project remote."""
(i, url, expr) = args
gitcmd = git_command.GitCommand(
None, ["ls-remote", url, expr], capture_stdout=True, cwd="/tmp"
)
rc = gitcmd.Wait()
return (i, rc, gitcmd.stdout.split("\t", 1)[0])
def _set_project_revisions(projects):
"""Sets the revisionExpr for a list of projects.
Because of the limit of open file descriptors allowed, length of projects
should not be overly large. Recommend calling this function multiple times
with each call not exceeding NUM_BATCH_RETRIEVE_REVISIONID projects.
Args:
projects: List of project objects to set the revionExpr for.
"""
# Retrieve the commit id for each project based off of its current
# revisionExpr and it is not already a commit id.
with multiprocessing.Pool(NUM_BATCH_RETRIEVE_REVISIONID) as pool:
results_iter = pool.imap_unordered(
_get_project_revision,
(
(i, project.remote.url, project.revisionExpr)
for i, project in enumerate(projects)
if not git_config.IsId(project.revisionExpr)
),
chunksize=8,
)
for i, rc, revisionExpr in results_iter:
project = projects[i]
if rc:
print(
"FATAL: Failed to retrieve revisionExpr for %s"
% project.name
)
pool.terminate()
sys.exit(1)
if not revisionExpr:
pool.terminate()
raise ManifestParseError(
"Invalid SHA-1 revision project %s (%s)"
% (project.remote.url, project.revisionExpr)
)
project.revisionExpr = revisionExpr
def generate_gitc_manifest(gitc_manifest, manifest, paths=None):
"""Generate a manifest for shafsd to use for this GITC client.
Args:
gitc_manifest: Current gitc manifest, or None if there isn't one yet.
manifest: A GitcManifest object loaded with the current repo manifest.
paths: List of project paths we want to update.
"""
print(
"Generating GITC Manifest by fetching revision SHAs for each "
"project."
)
if paths is None:
paths = list(manifest.paths.keys())
groups = [x for x in re.split(r"[,\s]+", manifest.GetGroupsStr()) if x]
# Convert the paths to projects, and filter them to the matched groups.
projects = [manifest.paths[p] for p in paths]
projects = [p for p in projects if p.MatchesGroups(groups)]
if gitc_manifest is not None:
for path, proj in manifest.paths.items():
if not proj.MatchesGroups(groups):
continue
if not proj.upstream and not git_config.IsId(proj.revisionExpr):
proj.upstream = proj.revisionExpr
if path not in gitc_manifest.paths:
# Any new projects need their first revision, even if we weren't
# asked for them.
projects.append(proj)
elif path not in paths:
# And copy revisions from the previous manifest if we're not
# updating them now.
gitc_proj = gitc_manifest.paths[path]
if gitc_proj.old_revision:
proj.revisionExpr = None
proj.old_revision = gitc_proj.old_revision
else:
proj.revisionExpr = gitc_proj.revisionExpr
_set_project_revisions(projects)
if gitc_manifest is not None:
for path, proj in gitc_manifest.paths.items():
if proj.old_revision and path in paths:
# If we updated a project that has been started, keep the
# old-revision updated.
repo_proj = manifest.paths[path]
repo_proj.old_revision = repo_proj.revisionExpr
repo_proj.revisionExpr = None
# Convert URLs from relative to absolute.
for _name, remote in manifest.remotes.items():
remote.fetchUrl = remote.resolvedFetchUrl
# Save the manifest.
save_manifest(manifest)
def save_manifest(manifest, client_dir=None):
"""Save the manifest file in the client_dir.
Args:
manifest: Manifest object to save.
client_dir: Client directory to save the manifest in.
"""
if not client_dir:
manifest_file = manifest.manifestFile
else:
manifest_file = os.path.join(client_dir, ".manifest")
with open(manifest_file, "w") as f:
manifest.Save(f, groups=manifest.GetGroupsStr())
# TODO(sbasi/jorg): Come up with a solution to remove the sleep below.
# Give the GITC filesystem time to register the manifest changes.
time.sleep(3)

29
main.py
View File

@ -45,7 +45,6 @@ from git_config import RepoConfig
from git_trace2_event_log import EventLog
from command import InteractiveCommand
from command import MirrorSafeCommand
from command import GitcAvailableCommand, GitcClientCommand
from subcmds.version import Version
from editor import Editor
from error import DownloadError
@ -58,8 +57,8 @@ from error import RepoExitError
from error import RepoUnhandledExceptionError
from error import RepoError
from error import SilentRepoExitError
import gitc_utils
from manifest_xml import GitcClient, RepoClient
from error import GitcUnsupportedError
from manifest_xml import RepoClient
from pager import RunPager, TerminatePager
from wrapper import WrapperPath, Wrapper
@ -304,11 +303,10 @@ class _Repo(object):
submanifest_path=gopts.submanifest_path,
outer_client=outer_client,
)
gitc_manifest = None
gitc_client_name = gitc_utils.parse_clientdir(os.getcwd())
if gitc_client_name:
gitc_manifest = GitcClient(self.repodir, gitc_client_name)
repo_client.isGitcClient = True
if Wrapper().gitc_parse_clientdir(os.getcwd()):
print("GITC is not supported.", file=sys.stderr)
raise GitcUnsupportedError()
try:
cmd = self.commands[name](
@ -317,7 +315,6 @@ class _Repo(object):
manifest=repo_client.manifest,
outer_client=outer_client,
outer_manifest=outer_client.manifest,
gitc_manifest=gitc_manifest,
git_event_log=git_trace2_event_log,
)
except KeyError:
@ -336,20 +333,6 @@ class _Repo(object):
)
return 1
if (
isinstance(cmd, GitcAvailableCommand)
and not gitc_utils.get_gitc_manifest_dir()
):
print(
"fatal: '%s' requires GITC to be available" % name,
file=sys.stderr,
)
return 1
if isinstance(cmd, GitcClientCommand) and not gitc_client_name:
print("fatal: '%s' requires a GITC client" % name, file=sys.stderr)
return 1
try:
copts, cargs = cmd.OptionParser.parse_args(argv)
copts = cmd.ReadEnvironmentOptions(copts)

View File

@ -21,7 +21,6 @@ import sys
import xml.dom.minidom
import urllib.parse
import gitc_utils
from git_config import GitConfig
from git_refs import R_HEADS, HEAD
from git_superproject import Superproject
@ -2248,21 +2247,6 @@ https://gerrit.googlesource.com/git-repo/+/HEAD/docs/manifest-format.md
return diff
class GitcManifest(XmlManifest):
"""Parser for GitC (git-in-the-cloud) manifests."""
def _ParseProject(self, node, parent=None):
"""Override _ParseProject and add support for GITC specific attributes.""" # noqa: E501
return super()._ParseProject(
node, parent=parent, old_revision=node.getAttribute("old-revision")
)
def _output_manifest_project_extras(self, p, e):
"""Output GITC Specific Project attributes"""
if p.old_revision:
e.setAttribute("old-revision", str(p.old_revision))
class RepoClient(XmlManifest):
"""Manages a repo client checkout."""
@ -2315,19 +2299,3 @@ class RepoClient(XmlManifest):
# TODO: Completely separate manifest logic out of the client.
self.manifest = self
class GitcClient(RepoClient, GitcManifest):
"""Manages a GitC client checkout."""
def __init__(self, repodir, gitc_client_name):
"""Initialize the GitcManifest object."""
self.gitc_client_name = gitc_client_name
self.gitc_client_dir = os.path.join(
gitc_utils.get_gitc_manifest_dir(), gitc_client_name
)
super().__init__(
repodir, os.path.join(self.gitc_client_dir, ".manifest")
)
self.isGitcClient = True

44
repo
View File

@ -149,7 +149,7 @@ if not REPO_REV:
BUG_URL = 'https://issues.gerritcodereview.com/issues/new?component=1370071'
# increment this whenever we make important changes to this script
VERSION = (2, 35)
VERSION = (2, 36)
# increment this if the MAINTAINER_KEYS block is modified
KEYRING_VERSION = (2, 3)
@ -273,16 +273,16 @@ gpg_dir = os.path.join(home_dot_repo, 'gnupg')
def GetParser(gitc_init=False):
"""Setup the CLI parser."""
if gitc_init:
usage = 'repo gitc-init -c client [options] [-u] url'
sys.exit('repo: fatal: GITC not supported.')
else:
usage = 'repo init [options] [-u] url'
parser = optparse.OptionParser(usage=usage)
InitParser(parser, gitc_init=gitc_init)
InitParser(parser)
return parser
def InitParser(parser, gitc_init=False):
def InitParser(parser):
"""Setup the CLI parser."""
# NB: Keep in sync with command.py:_CommonOptions().
@ -325,12 +325,8 @@ def InitParser(parser, gitc_init=False):
# Options that only affect manifest project, and not any of the projects
# specified in the manifest itself.
group = parser.add_option_group('Manifest (only) checkout options')
cbr_opts = ['--current-branch']
# The gitc-init subcommand allocates -c itself, but a lot of init users
# want -c, so try to satisfy both as best we can.
if not gitc_init:
cbr_opts += ['-c']
group.add_option(*cbr_opts, default=True,
group.add_option('--current-branch', '-c', default=True,
dest='current_branch_only', action='store_true',
help='fetch only current manifest branch from server (default)')
group.add_option('--no-current-branch',
@ -411,14 +407,6 @@ def InitParser(parser, gitc_init=False):
action='store_true', default=False,
help='Always prompt for name/e-mail')
# gitc-init specific settings.
if gitc_init:
group = parser.add_option_group('GITC options')
group.add_option('-f', '--manifest-file',
help='Optional manifest file to use for this GITC client.')
group.add_option('-c', '--gitc-client',
help='Name of the gitc_client instance to create or modify.')
return parser
@ -582,26 +570,6 @@ def _Init(args, gitc_init=False):
rev = opt.repo_rev or REPO_REV
try:
if gitc_init:
gitc_manifest_dir = get_gitc_manifest_dir()
if not gitc_manifest_dir:
print('fatal: GITC filesystem is not available. Exiting...',
file=sys.stderr)
sys.exit(1)
gitc_client = opt.gitc_client
if not gitc_client:
gitc_client = gitc_parse_clientdir(os.getcwd())
if not gitc_client:
print('fatal: GITC client (-c) is required.', file=sys.stderr)
sys.exit(1)
client_dir = os.path.join(gitc_manifest_dir, gitc_client)
if not os.path.exists(client_dir):
os.makedirs(client_dir)
os.chdir(client_dir)
if os.path.exists(repodir):
# This GITC Client has already initialized repo so continue.
return
os.mkdir(repodir)
except OSError as e:
if e.errno != errno.EEXIST:

View File

@ -1,52 +0,0 @@
# Copyright (C) 2015 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 sys
from command import Command, GitcClientCommand
import platform_utils
class GitcDelete(Command, GitcClientCommand):
COMMON = True
visible_everywhere = False
helpSummary = "Delete a GITC Client."
helpUsage = """
%prog
"""
helpDescription = """
This subcommand deletes the current GITC client, deleting the GITC manifest
and all locally downloaded sources.
"""
def _Options(self, p):
p.add_option(
"-f",
"--force",
dest="force",
action="store_true",
help="force the deletion (no prompt)",
)
def Execute(self, opt, args):
if not opt.force:
prompt = (
"This will delete GITC client: %s\nAre you sure? (yes/no) "
% self.gitc_manifest.gitc_client_name
)
response = input(prompt).lower()
if not response == "yes":
print('Response was not "yes"\n Exiting...')
sys.exit(1)
platform_utils.rmtree(self.gitc_manifest.gitc_client_dir)

View File

@ -1,87 +0,0 @@
# Copyright (C) 2015 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
import sys
import gitc_utils
from command import GitcAvailableCommand
from manifest_xml import GitcManifest
from subcmds import init
import wrapper
class GitcInit(init.Init, GitcAvailableCommand):
COMMON = True
MULTI_MANIFEST_SUPPORT = False
helpSummary = "Initialize a GITC Client."
helpUsage = """
%prog [options] [client name]
"""
helpDescription = """
The '%prog' command is ran to initialize a new GITC client for use
with the GITC file system.
This command will setup the client directory, initialize repo, just
like repo init does, and then downloads the manifest collection
and installs it in the .repo/directory of the GITC client.
Once this is done, a GITC manifest is generated by pulling the HEAD
SHA for each project and generates the properly formatted XML file
and installs it as .manifest in the GITC client directory.
The -c argument is required to specify the GITC client name.
The optional -f argument can be used to specify the manifest file to
use for this GITC client.
"""
def _Options(self, p):
super()._Options(p, gitc_init=True)
def Execute(self, opt, args):
gitc_client = gitc_utils.parse_clientdir(os.getcwd())
if not gitc_client or (
opt.gitc_client and gitc_client != opt.gitc_client
):
print(
"fatal: Please update your repo command. See go/gitc for "
"instructions.",
file=sys.stderr,
)
sys.exit(1)
self.client_dir = os.path.join(
gitc_utils.get_gitc_manifest_dir(), gitc_client
)
super().Execute(opt, args)
manifest_file = self.manifest.manifestFile
if opt.manifest_file:
if not os.path.exists(opt.manifest_file):
print(
"fatal: Specified manifest file %s does not exist."
% opt.manifest_file
)
sys.exit(1)
manifest_file = opt.manifest_file
manifest = GitcManifest(
self.repodir, os.path.join(self.client_dir, ".manifest")
)
manifest.Override(manifest_file)
gitc_utils.generate_gitc_manifest(None, manifest)
print(
"Please run `cd %s` to view your GITC client."
% os.path.join(wrapper.Wrapper().GITC_FS_ROOT_DIR, gitc_client)
)

View File

@ -21,10 +21,7 @@ from color import Coloring
from command import (
PagedCommand,
MirrorSafeCommand,
GitcAvailableCommand,
GitcClientCommand,
)
import gitc_utils
from wrapper import Wrapper
from error import RepoExitError
@ -79,26 +76,9 @@ Displays detailed usage information about a command.
def PrintCommonCommandsBody(self):
print("The most commonly used repo commands are:")
def gitc_supported(cmd):
if not isinstance(cmd, GitcAvailableCommand) and not isinstance(
cmd, GitcClientCommand
):
return True
if self.client.isGitcClient:
return True
if isinstance(cmd, GitcClientCommand):
return False
if gitc_utils.get_gitc_manifest_dir():
return True
return False
commandNames = list(
sorted(
[
name
for name, command in all_commands.items()
if command.COMMON and gitc_supported(command)
]
name for name, command in all_commands.items() if command.COMMON
)
)
self._PrintCommands(commandNames)

View File

@ -84,8 +84,8 @@ to update the working directory files.
def _CommonOptions(self, p):
"""Disable due to re-use of Wrapper()."""
def _Options(self, p, gitc_init=False):
Wrapper().InitParser(p, gitc_init=gitc_init)
def _Options(self, p):
Wrapper().InitParser(p)
m = p.add_option_group("Multi-manifest")
m.add_option(
"--outer-manifest",

View File

@ -13,15 +13,13 @@
# limitations under the License.
import functools
import os
import sys
from command import Command, DEFAULT_LOCAL_JOBS
from git_config import IsImmutable
from git_command import git
import gitc_utils
from progress import Progress
from project import SyncBuffer, Project
from project import Project
from typing import NamedTuple
from error import RepoExitError
@ -115,49 +113,9 @@ revision specified in the manifest.
all_projects = self.GetProjects(
projects,
missing_ok=bool(self.gitc_manifest),
all_manifests=not opt.this_manifest_only,
)
# This must happen after we find all_projects, since GetProjects may
# need the local directory, which will disappear once we save the GITC
# manifest.
if self.gitc_manifest:
gitc_projects = self.GetProjects(
projects, manifest=self.gitc_manifest, missing_ok=True
)
for project in gitc_projects:
if project.old_revision:
project.already_synced = True
else:
project.already_synced = False
project.old_revision = project.revisionExpr
project.revisionExpr = None
# Save the GITC manifest.
gitc_utils.save_manifest(self.gitc_manifest)
# Make sure we have a valid CWD.
if not os.path.exists(os.getcwd()):
os.chdir(self.manifest.topdir)
pm = Progress("Syncing %s" % nb, len(all_projects), quiet=opt.quiet)
for project in all_projects:
gitc_project = self.gitc_manifest.paths[project.relpath]
# Sync projects that have not been opened.
if not gitc_project.already_synced:
proj_localdir = os.path.join(
self.gitc_manifest.gitc_client_dir, project.relpath
)
project.worktree = proj_localdir
if not os.path.exists(proj_localdir):
os.makedirs(proj_localdir)
project.Sync_NetworkHalf()
sync_buf = SyncBuffer(self.manifest.manifestProject.config)
project.Sync_LocalHalf(sync_buf)
project.revisionId = gitc_project.old_revision
pm.update(msg="")
pm.end()
def _ProcessResults(_pool, pm, results):
for result in results:
if result.error:

View File

@ -54,7 +54,6 @@ from git_command import git_require
from git_config import GetUrlCookieFile
from git_refs import R_HEADS, HEAD
import git_superproject
import gitc_utils
from project import Project
from project import RemoteSpec
from command import (
@ -77,7 +76,6 @@ from progress import Progress, elapsed_str, jobs_str
from repo_trace import Trace
import ssh
from wrapper import Wrapper
from manifest_xml import GitcManifest
_ONE_DAY_S = 24 * 60 * 60
@ -1678,50 +1676,6 @@ later is required to fix a server side protocol bug.
opt, args, superproject_logging_data, manifest
)
if self.gitc_manifest:
gitc_manifest_projects = self.GetProjects(args, missing_ok=True)
gitc_projects = []
opened_projects = []
for project in gitc_manifest_projects:
if (
project.relpath in self.gitc_manifest.paths
and self.gitc_manifest.paths[project.relpath].old_revision
):
opened_projects.append(project.relpath)
else:
gitc_projects.append(project.relpath)
if not args:
gitc_projects = None
if gitc_projects != [] and not opt.local_only:
print(
"Updating GITC client: %s"
% self.gitc_manifest.gitc_client_name
)
manifest = GitcManifest(
self.repodir, self.gitc_manifest.gitc_client_name
)
if manifest_name:
manifest.Override(manifest_name)
else:
manifest.Override(manifest.manifestFile)
gitc_utils.generate_gitc_manifest(
self.gitc_manifest, manifest, gitc_projects
)
print("GITC client successfully synced.")
# The opened projects need to be synced as normal, therefore we
# generate a new args list to represent the opened projects.
# TODO: make this more reliable -- if there's a project name/path
# overlap, this may choose the wrong project.
args = [
os.path.relpath(manifest.paths[path].worktree, os.getcwd())
for path in opened_projects
]
if not args:
return
all_projects = self.GetProjects(
args,
missing_ok=True,

View File

@ -76,11 +76,9 @@ class RepoWrapperUnitTest(RepoWrapperTestCase):
self.assertIsNone(opts.manifest_url)
def test_gitc_init_parser(self):
"""Make sure 'gitc-init' GetParser works."""
parser = self.wrapper.GetParser(gitc_init=True)
opts, args = parser.parse_args([])
self.assertEqual([], args)
self.assertIsNone(opts.manifest_file)
"""Make sure 'gitc-init' GetParser raises."""
with self.assertRaises(SystemExit):
self.wrapper.GetParser(gitc_init=True)
def test_get_gitc_manifest_dir_no_gitc(self):
"""