use custom exceptions to improve error handling
This patch adds the KasUserError exception class to distinguish between internal kas exceptions and user or configuration errors. Exceptions previously raised on user errors are ported over by deriving KasUserError. In case of user errors, only the exception message is shown, but no stacktrace. This makes it easier for users to locate the issue as the reason is now stated in the last line of the output. Kas internal exceptions are not subject to this change to help the developers to find the root cause more easily. Signed-off-by: Felix Moessbauer <felix.moessbauer@siemens.com> Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
This commit is contained in:
parent
6fa40363aa
commit
a5750901c6
@ -101,6 +101,12 @@ Class reference documentation
|
||||
.. automodule:: kas.includehandler
|
||||
:members:
|
||||
|
||||
``kas.kasusererror`` Module
|
||||
.............................
|
||||
|
||||
.. automodule:: kas.kasusererror
|
||||
:members:
|
||||
|
||||
``kas.plugins`` Module
|
||||
......................
|
||||
|
||||
|
@ -34,6 +34,7 @@ import logging
|
||||
|
||||
from jsonschema.validators import Draft4Validator
|
||||
|
||||
from .kasusererror import KasUserError
|
||||
from . import __file_version__, __compatible_file_version__
|
||||
from . import CONFIGSCHEMA
|
||||
|
||||
@ -41,7 +42,7 @@ __license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) Siemens AG, 2017-2021'
|
||||
|
||||
|
||||
class LoadConfigException(Exception):
|
||||
class LoadConfigException(KasUserError):
|
||||
"""
|
||||
Class for exceptions that appear while loading a configuration file.
|
||||
"""
|
||||
@ -101,7 +102,7 @@ def load_config(filename):
|
||||
return config
|
||||
|
||||
|
||||
class IncludeException(Exception):
|
||||
class IncludeException(KasUserError):
|
||||
"""
|
||||
Class for exceptions that appear in the include mechanism.
|
||||
"""
|
||||
|
@ -21,7 +21,9 @@
|
||||
# SOFTWARE.
|
||||
"""
|
||||
This module is the main entry point for kas, setup tool for bitbake based
|
||||
projects
|
||||
projects. In case of user errors (e.g. invalid configuration, repo fetch
|
||||
failure) KAS exits with error code 2, while exiting with 1 for internal
|
||||
errors. For details on error handling, see :mod:`kas.kasusererror`.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
@ -32,6 +34,7 @@ import logging
|
||||
import signal
|
||||
import sys
|
||||
import os
|
||||
from .kasusererror import KasUserError
|
||||
|
||||
try:
|
||||
import colorlog
|
||||
@ -173,6 +176,9 @@ def main():
|
||||
|
||||
try:
|
||||
kas(sys.argv[1:])
|
||||
except KasUserError as err:
|
||||
logging.error('%s', err)
|
||||
sys.exit(2)
|
||||
except Exception as err:
|
||||
logging.error('%s', err)
|
||||
traceback.print_exc()
|
||||
|
45
kas/kasusererror.py
Normal file
45
kas/kasusererror.py
Normal file
@ -0,0 +1,45 @@
|
||||
# kas - setup tool for bitbake based projects
|
||||
#
|
||||
# Copyright (c) Siemens AG, 2017-2023
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
"""
|
||||
This module provides a common base class for all exceptions
|
||||
which are related to user or configuration errors. These exceptions
|
||||
should be caught and reported to the user using a meaningful message
|
||||
instead of a stacktrace.
|
||||
|
||||
When handling errors in KAS, never return directly using `sys.exit`,
|
||||
but instead throw an exception derived from :class:`KasUserError` (for user
|
||||
errors), or one derived from `Exception` for internal errors. These
|
||||
are then handled centrally, mapped to correct return codes and pretty
|
||||
printed.
|
||||
"""
|
||||
|
||||
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) Siemens AG, 2023'
|
||||
|
||||
|
||||
class KasUserError(Exception):
|
||||
"""
|
||||
User or input error. Derive all user error exceptions from this class.
|
||||
"""
|
||||
pass
|
19
kas/repos.py
19
kas/repos.py
@ -31,11 +31,26 @@ from urllib.parse import urlparse
|
||||
from tempfile import TemporaryDirectory
|
||||
from .context import get_context
|
||||
from .libkas import run_cmd_async, run_cmd
|
||||
from .kasusererror import KasUserError
|
||||
|
||||
__license__ = 'MIT'
|
||||
__copyright__ = 'Copyright (c) Siemens AG, 2017-2018'
|
||||
|
||||
|
||||
class UnsupportedRepoTypeError(KasUserError, NotImplementedError):
|
||||
"""
|
||||
Exception for unsupported / not implemented repository types
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class PatchFileNotFound(KasUserError, FileNotFoundError):
|
||||
"""
|
||||
The requested patch file was not found
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Repo:
|
||||
"""
|
||||
Represents a repository in the kas configuration.
|
||||
@ -151,7 +166,7 @@ class Repo:
|
||||
if typ == 'hg':
|
||||
return MercurialRepo(name, url, path, refspec, layers, patches,
|
||||
disable_operations)
|
||||
raise NotImplementedError('Repo type "%s" not supported.' % typ)
|
||||
raise UnsupportedRepoTypeError('Repo type "%s" not supported.' % typ)
|
||||
|
||||
@staticmethod
|
||||
def get_root_path(path, fallback=True):
|
||||
@ -324,7 +339,7 @@ class RepoImpl(Repo):
|
||||
if os.path.isfile(p):
|
||||
my_patches.append((p, patch['id']))
|
||||
else:
|
||||
raise FileNotFoundError(p)
|
||||
raise PatchFileNotFound(p)
|
||||
else:
|
||||
logging.error('Could not find patch. '
|
||||
'(patch path: %s, repo: %s, patch entry: %s)',
|
||||
|
Loading…
Reference in New Issue
Block a user