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.
|
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
from typing import List
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
|
|
|
|
class BaseRepoError(Exception):
|
|
|
|
"""All repo specific exceptions derive from BaseRepoError."""
|
|
|
|
|
|
|
|
|
|
|
|
class RepoError(BaseRepoError):
|
|
|
|
"""Exceptions thrown inside repo that can be handled."""
|
|
|
|
|
|
|
|
def __init__(self, *args, project: str = None) -> None:
|
|
|
|
super().__init__(*args)
|
|
|
|
self.project = project
|
|
|
|
|
|
|
|
|
|
|
|
class RepoExitError(BaseRepoError):
|
|
|
|
"""Exception thrown that result in termination of repo program.
|
|
|
|
- Should only be handled in main.py
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
*args,
|
|
|
|
exit_code: int = 1,
|
|
|
|
aggregate_errors: List[Exception] = None,
|
|
|
|
**kwargs,
|
|
|
|
) -> None:
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.exit_code = exit_code
|
|
|
|
self.aggregate_errors = aggregate_errors
|
|
|
|
|
|
|
|
|
|
|
|
class RepoUnhandledExceptionError(RepoExitError):
|
|
|
|
"""Exception that maintains error as reason for program exit."""
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
self,
|
|
|
|
error: BaseException,
|
|
|
|
**kwargs,
|
|
|
|
) -> None:
|
|
|
|
super().__init__(error, **kwargs)
|
|
|
|
self.error = error
|
|
|
|
|
|
|
|
|
|
|
|
class ManifestParseError(RepoExitError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""Failed to parse the manifest file."""
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2021-03-02 02:38:08 +00:00
|
|
|
class ManifestInvalidRevisionError(ManifestParseError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""The revision value in a project is incorrect."""
|
2009-03-02 20:56:08 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2021-03-02 02:38:08 +00:00
|
|
|
class ManifestInvalidPathError(ManifestParseError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""A path used in <copyfile> or <linkfile> is incorrect."""
|
2019-08-01 03:32:58 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class NoManifestException(RepoExitError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""The required manifest does not exist."""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, path, reason, **kwargs):
|
|
|
|
super().__init__(path, reason, **kwargs)
|
2023-03-11 06:46:20 +00:00
|
|
|
self.path = path
|
|
|
|
self.reason = reason
|
2014-03-09 17:20:02 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.reason
|
2012-11-16 01:33:11 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class EditorError(RepoError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""Unspecified error from the user's text editor."""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, reason, **kwargs):
|
|
|
|
super().__init__(reason, **kwargs)
|
2023-03-11 06:46:20 +00:00
|
|
|
self.reason = reason
|
2009-06-24 14:09:51 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.reason
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class GitError(RepoError):
|
|
|
|
"""Unspecified git related error."""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, message, command_args=None, **kwargs):
|
|
|
|
super().__init__(message, **kwargs)
|
|
|
|
self.message = message
|
|
|
|
self.command_args = command_args
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
2023-07-26 20:23:40 +00:00
|
|
|
return self.message
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class UploadError(RepoError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""A bundle upload to Gerrit did not succeed."""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, reason, **kwargs):
|
|
|
|
super().__init__(reason, **kwargs)
|
2023-03-11 06:46:20 +00:00
|
|
|
self.reason = reason
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.reason
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class DownloadError(RepoExitError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""Cannot download a repository."""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, reason, **kwargs):
|
|
|
|
super().__init__(reason, **kwargs)
|
2023-03-11 06:46:20 +00:00
|
|
|
self.reason = reason
|
2011-09-19 21:50:58 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
|
|
|
return self.reason
|
2011-09-19 21:50:58 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class SyncError(RepoExitError):
|
|
|
|
"""Cannot sync repo."""
|
|
|
|
|
|
|
|
|
|
|
|
class UpdateManifestError(RepoExitError):
|
|
|
|
"""Cannot update manifest."""
|
|
|
|
|
|
|
|
|
|
|
|
class NoSuchProjectError(RepoExitError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""A specified project does not exist in the work tree."""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, name=None, **kwargs):
|
|
|
|
super().__init__(**kwargs)
|
2023-03-11 06:46:20 +00:00
|
|
|
self.name = name
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
|
|
|
if self.name is None:
|
|
|
|
return "in current directory"
|
|
|
|
return self.name
|
2008-10-21 14:00:00 +00:00
|
|
|
|
2012-03-29 03:15:45 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class InvalidProjectGroupsError(RepoExitError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""A specified project is not suitable for the specified groups"""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
def __init__(self, name=None, **kwargs):
|
|
|
|
super().__init__(**kwargs)
|
2023-03-11 06:46:20 +00:00
|
|
|
self.name = name
|
2012-03-29 03:15:45 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __str__(self):
|
|
|
|
if self.name is None:
|
|
|
|
return "in current directory"
|
|
|
|
return self.name
|
2012-03-29 03:15:45 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class RepoChangedException(BaseRepoError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""Thrown if 'repo sync' results in repo updating its internal
|
|
|
|
repo or manifest repositories. In this special case we must
|
|
|
|
use exec to re-execute repo with the new code and manifest.
|
|
|
|
"""
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
def __init__(self, extra_args=None):
|
|
|
|
super().__init__(extra_args)
|
|
|
|
self.extra_args = extra_args or []
|
Support repo-level pre-upload hook and prep for future hooks.
All repo-level hooks are expected to live in a single project at the
top level of that project. The name of the hooks project is provided
in the manifest.xml. The manifest also lists which hooks are enabled
to make it obvious if a file somehow failed to sync down (or got
deleted).
Before running any hook, we will prompt the user to make sure that it
is OK. A user can deny running the hook, allow once, or allow
"forever" (until hooks change). This tries to keep with the git
spirit of not automatically running anything on the user's computer
that got synced down. Note that individual repo commands can add
always options to avoid these prompts as they see fit (see below for
the 'upload' options).
When hooks are run, they are loaded into the current interpreter (the
one running repo) and their main() function is run. This mechanism is
used (instead of using subprocess) to make it easier to expand to a
richer hook interface in the future. During loading, the
interpreter's sys.path is updated to contain the directory containing
the hooks so that hooks can be split into multiple files.
The upload command has two options that control hook behavior:
- no-verify=False, verify=False (DEFAULT):
If stdout is a tty, can prompt about running upload hooks if needed.
If user denies running hooks, the upload is cancelled. If stdout is
not a tty and we would need to prompt about upload hooks, upload is
cancelled.
- no-verify=False, verify=True:
Always run upload hooks with no prompt.
- no-verify=True, verify=False:
Never run upload hooks, but upload anyway (AKA bypass hooks).
- no-verify=True, verify=True:
Invalid
Sample bit of manifest.xml code for enabling hooks (assumes you have a
project named 'hooks' where hooks are stored):
<repo-hooks in-project="hooks" enabled-list="pre-upload" />
Sample main() function in pre-upload.py in hooks directory:
def main(project_list, **kwargs):
print ('These projects will be uploaded: %s' %
', '.join(project_list))
print ('I am being a good boy and ignoring anything in kwargs\n'
'that I don\'t understand.')
print 'I fail 50% of the time. How flaky.'
if random.random() <= .5:
raise Exception('Pre-upload hook failed. Have a nice day.')
Change-Id: I5cefa2cd5865c72589263cf8e2f152a43c122f70
2011-03-04 19:54:18 +00:00
|
|
|
|
2020-02-12 06:20:19 +00:00
|
|
|
|
2023-07-26 20:23:40 +00:00
|
|
|
class HookError(RepoError):
|
2023-03-11 06:46:20 +00:00
|
|
|
"""Thrown if a 'repo-hook' could not be run.
|
Support repo-level pre-upload hook and prep for future hooks.
All repo-level hooks are expected to live in a single project at the
top level of that project. The name of the hooks project is provided
in the manifest.xml. The manifest also lists which hooks are enabled
to make it obvious if a file somehow failed to sync down (or got
deleted).
Before running any hook, we will prompt the user to make sure that it
is OK. A user can deny running the hook, allow once, or allow
"forever" (until hooks change). This tries to keep with the git
spirit of not automatically running anything on the user's computer
that got synced down. Note that individual repo commands can add
always options to avoid these prompts as they see fit (see below for
the 'upload' options).
When hooks are run, they are loaded into the current interpreter (the
one running repo) and their main() function is run. This mechanism is
used (instead of using subprocess) to make it easier to expand to a
richer hook interface in the future. During loading, the
interpreter's sys.path is updated to contain the directory containing
the hooks so that hooks can be split into multiple files.
The upload command has two options that control hook behavior:
- no-verify=False, verify=False (DEFAULT):
If stdout is a tty, can prompt about running upload hooks if needed.
If user denies running hooks, the upload is cancelled. If stdout is
not a tty and we would need to prompt about upload hooks, upload is
cancelled.
- no-verify=False, verify=True:
Always run upload hooks with no prompt.
- no-verify=True, verify=False:
Never run upload hooks, but upload anyway (AKA bypass hooks).
- no-verify=True, verify=True:
Invalid
Sample bit of manifest.xml code for enabling hooks (assumes you have a
project named 'hooks' where hooks are stored):
<repo-hooks in-project="hooks" enabled-list="pre-upload" />
Sample main() function in pre-upload.py in hooks directory:
def main(project_list, **kwargs):
print ('These projects will be uploaded: %s' %
', '.join(project_list))
print ('I am being a good boy and ignoring anything in kwargs\n'
'that I don\'t understand.')
print 'I fail 50% of the time. How flaky.'
if random.random() <= .5:
raise Exception('Pre-upload hook failed. Have a nice day.')
Change-Id: I5cefa2cd5865c72589263cf8e2f152a43c122f70
2011-03-04 19:54:18 +00:00
|
|
|
|
2023-03-11 06:46:20 +00:00
|
|
|
The common case is that the file wasn't present when we tried to run it.
|
|
|
|
"""
|