diff --git a/specfile/spec_parser.py b/specfile/spec_parser.py index 196c875..9c8fe71 100644 --- a/specfile/spec_parser.py +++ b/specfile/spec_parser.py @@ -99,6 +99,20 @@ def _make_dummy_sources( Yields: List of paths to each created dummy source. """ + + def write_magic(path, magic): + # number of bytes that RPM reads to determine the file type + MAGIC_LENGTH = 13 + try: + if magic: + path.write_bytes(magic.ljust(MAGIC_LENGTH, b"\x00")) + else: + path.write_bytes(MAGIC_LENGTH * b"\x00") + except (FileNotFoundError, OSError, PermissionError): + logger.warning(f"Failed to create a dummy source: {path}") + return False + return True + # based on rpmFileIsCompressed() in rpmio/rpmfileutil.c in RPM source SIGNATURES = [ (".bz2", b"BZh"), @@ -110,32 +124,35 @@ def _make_dummy_sources( (".gz", b"\x1f\x8b"), (".7z", b"7z\xbc\xaf\x27\x1c"), ] - # number of bytes that RPM reads to determine the file type - MAGIC_LENGTH = 13 dummy_sources = [] for source in sources: filename = get_filename_from_location(source) if not filename: continue path = self.sourcedir / filename - if path.is_file(): + if path.exists(): continue - dummy_sources.append(path) for ext, magic in SIGNATURES: if filename.endswith(ext): - path.write_bytes(magic.ljust(MAGIC_LENGTH, b"\x00")) + if write_magic(path, magic): + dummy_sources.append(path) break else: - path.write_bytes(MAGIC_LENGTH * b"\x00") + if write_magic(path, None): + dummy_sources.append(path) for source in non_empty_sources: filename = get_filename_from_location(source) if not filename: continue path = self.sourcedir / filename - if path.is_file(): + if path.exists(): continue - dummy_sources.append(path) - path.write_text("DUMMY") + try: + path.write_text("DUMMY") + except (FileNotFoundError, OSError, PermissionError): + logger.warning(f"Failed to create a dummy source: {path}") + else: + dummy_sources.append(path) try: yield dummy_sources finally: diff --git a/tests/unit/test_spec_parser.py b/tests/unit/test_spec_parser.py index a1347c2..2d3faea 100644 --- a/tests/unit/test_spec_parser.py +++ b/tests/unit/test_spec_parser.py @@ -64,3 +64,32 @@ def test_spec_parser_macros(): "Test package\n" ), ) + + +def test_spec_parser_make_dummy_sources(tmp_path): + regular_source = "regular-source.zip" + non_empty_source = "non-empty-source.tar.xz" + existing_source = "existing-source.tar.gz" + sourcedir = tmp_path / "sources" + sourcedir.mkdir() + (sourcedir / existing_source).write_text("...") + parser = SpecParser(sourcedir) + with parser._make_dummy_sources( + {regular_source, existing_source}, {non_empty_source} + ) as dummy_sources: + assert all(s.exists() for s in dummy_sources) + assert sourcedir / regular_source in dummy_sources + assert sourcedir / non_empty_source in dummy_sources + assert sourcedir / existing_source not in dummy_sources + assert all(not s.exists() for s in dummy_sources) + assert (sourcedir / existing_source).exists() + read_only_sourcedir = tmp_path / "read-only-sources" + read_only_sourcedir.mkdir() + (read_only_sourcedir / existing_source).write_text("...") + read_only_sourcedir.chmod(0o555) + parser = SpecParser(read_only_sourcedir) + with parser._make_dummy_sources( + {regular_source, existing_source}, {non_empty_source} + ) as dummy_sources: + assert not dummy_sources + assert (read_only_sourcedir / existing_source).exists()