From 8909b8313171e37e42279e772ced657aed89ce66 Mon Sep 17 00:00:00 2001 From: BlackPhantomCoder Date: Sat, 26 Sep 2026 22:02:52 +0300 Subject: [PATCH] _yaml.pyx: Handle OSError when loading file When an error occurs while opening or reading a file in `load`, the exception type contract is violated, and various `bst` commands report an error with a stack trace. Several examples have been added to the tests. --- src/buildstream/_yaml.pyx | 3 +++ src/buildstream/exceptions.py | 3 +++ tests/internals/loader.py | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/src/buildstream/_yaml.pyx b/src/buildstream/_yaml.pyx index 0097e1e74..a2d29496a 100644 --- a/src/buildstream/_yaml.pyx +++ b/src/buildstream/_yaml.pyx @@ -284,6 +284,9 @@ cpdef MappingNode load(str filename, str shortname, bint copy_tree=False, object except IsADirectoryError as e: raise LoadError("{} is a directory".format(filename), LoadErrorReason.LOADING_DIRECTORY) from e + except OSError as e: + raise LoadError("Failed to load file at {}: {}".format(filename, e.strerror), + LoadErrorReason.LOAD_FAILED) from e except LoadError as e: raise LoadError("{}: {}".format(displayname, e), e.reason) from e diff --git a/src/buildstream/exceptions.py b/src/buildstream/exceptions.py index 418e51eda..238e477ad 100644 --- a/src/buildstream/exceptions.py +++ b/src/buildstream/exceptions.py @@ -160,3 +160,6 @@ class LoadErrorReason(Enum): """ Thee source provenance attribute specified was not defined in the project config """ + + LOAD_FAILED = 30 + """Failed to load a yaml file due to some error""" diff --git a/tests/internals/loader.py b/tests/internals/loader.py index 47c5bc691..d29896def 100644 --- a/tests/internals/loader.py +++ b/tests/internals/loader.py @@ -110,3 +110,25 @@ def test_invalid_directory_load(datafiles): loader.load(["element.bst"]) assert exc.value.reason == LoadErrorReason.LOADING_DIRECTORY + + +@pytest.mark.datafiles(os.path.join(DATA_DIR, "onefile")) +def test_invalid_nested_file_path(datafiles): + + basedir = str(datafiles) + with make_loader(basedir) as loader, pytest.raises(LoadError) as exc: + loader.load(["elements/onefile.bst/onefile.bst"]) + + assert exc.value.reason == LoadErrorReason.LOAD_FAILED + + +@pytest.mark.datafiles(os.path.join(DATA_DIR, "onefile")) +def test_fail_load_open_error(datafiles): + + basedir = str(datafiles) + # remove read prermission + os.chmod(f"{basedir}/elements/onefile.bst", 0o333) + with make_loader(basedir) as loader, pytest.raises(LoadError) as exc: + loader.load(["elements/onefile.bst"]) + + assert exc.value.reason == LoadErrorReason.LOAD_FAILED