diff --git a/src/ape/managers/project/types.py b/src/ape/managers/project/types.py index 54c4e6bb69..8b73418ce1 100644 --- a/src/ape/managers/project/types.py +++ b/src/ape/managers/project/types.py @@ -86,7 +86,9 @@ def _check_needs_compiling(self, source_path: Path) -> bool: # ethpm_types strips trailing white space and ensures # a newline at the end so content so `splitlines()` works. # We need to do the same here for to prevent the endless recompiling bug. - content = f"{source_file.read_text('utf8').rstrip()}\n" + text = source_file.read_text("utf8").rstrip() + content = f"{text}\n" if text else "" + checksum = compute_checksum(content.encode("utf8"), algorithm=cached_checksum.algorithm) return checksum != cached_checksum.hash # Contents changed @@ -129,7 +131,7 @@ def source_paths(self) -> List[Path]: compilers = self.compiler_manager.registered_compilers for extension in compilers: ext = extension.replace(".", "\\.") - pattern = rf"[\w|-]+{ext}" + pattern = rf"[\w|-|/]+{ext}" ext_files = get_all_files_in_directory(self.contracts_folder, pattern=pattern) files.extend(ext_files) diff --git a/tests/functional/test_project.py b/tests/functional/test_project.py index cc5c4b0b6f..a4505067bc 100644 --- a/tests/functional/test_project.py +++ b/tests/functional/test_project.py @@ -1,5 +1,6 @@ import os import shutil +import tempfile from pathlib import Path import pytest @@ -172,6 +173,34 @@ def test_create_manifest_when_file_changed_with_cached_references_that_no_longer assert manifest +def test_create_manifest_empty_files(compilers, mock_compiler, config, caplog): + """ + Tests again a bug where empty contracts would infinitely compile. + """ + + with tempfile.TemporaryDirectory() as temp_dir: + base_dir = Path(temp_dir) + contracts = base_dir / "contracts" + contracts.mkdir() + file_1 = contracts / "foo.__mock__" + file_1.write_text("") + + with config.using_project(base_dir) as proj: + compilers.registered_compilers[".__mock__"] = mock_compiler + manifest = proj.local_project.create_manifest(use_cache=False) + assert "foo" in manifest.contract_types + assert "foo.__mock__" in manifest.sources + assert "Compiling 'foo.__mock__'." in caplog.records[-1].message + caplog.clear() + + # Ensure is not double compiled! + proj.local_project.create_manifest() + assert ( + len(caplog.records) < 1 + or "Compiling 'foo.__mock__'." not in caplog.records[-1].message + ) + + def test_meta(temp_config, project): meta_config = { "meta": {