diff --git a/hancho.py b/hancho.py index b0cbcf7..61bb082 100755 --- a/hancho.py +++ b/hancho.py @@ -15,6 +15,7 @@ import traceback import types from pathlib import Path +from os.path import abspath, relpath # If we were launched directly, a reference to this module is already in # sys.modules[__name__]. Stash another reference in sys.modules["hancho"] so @@ -179,6 +180,8 @@ def main(): this.config.filename = Path(this.config.filename) + this.config.hancho_root = Path.cwd() + # Unrecognized flags become global config fields. for span in unrecognized: if match := re.match(r"-+([^=\s]+)(?:=(\S+))?", span): @@ -522,9 +525,11 @@ async def dispatch(self): # Check for duplicate task outputs for file in self.abs_files_out: - if file in this.hancho_outs: - raise NameError(f"Multiple rules build {file}!") - this.hancho_outs.add(file) + res_file = file.resolve() + if res_file in this.hancho_outs: + rel_file = relpath(res_file, this.config.hancho_root) + raise NameError(f"Multiple rules build {rel_file}!") + this.hancho_outs.add(res_file) # Check if we need a rebuild self.reason = await self.needs_rerun() @@ -578,6 +583,8 @@ async def dispatch(self): return result ######################################## + # Note - We should _not_ be expanding any templates in this step, that + # should've been done already. async def run_command(self, command): """Actually runs a command, either by calling it or running it in a subprocess""" @@ -600,11 +607,14 @@ async def run_command(self, command): raise ValueError(f"Don't know what to do with {command}") # Create the subprocess via asyncio and then await the result. + old_dir = os.getcwd() + if self.task_dir: os.chdir(self.task_dir) proc = await asyncio.create_subprocess_shell( command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, ) + os.chdir(old_dir) (stdout_data, stderr_data) = await proc.communicate() self.stdout = stdout_data.decode() diff --git a/tests/test.py b/tests/test.py index 4f785ff..4403e3d 100755 --- a/tests/test.py +++ b/tests/test.py @@ -90,6 +90,10 @@ def test_garbage_command(self): """Non-existent command line commands should cause Hancho to fail the build.""" self.assertNotEqual(0, run_hancho("garbage_command")) + def test_rule_collision(self): + """If multiple rules generate the same output file, that's an error.""" + self.assertNotEqual(0, run_hancho("rule_collision")) + def test_always_rebuild_if_no_inputs(self): """A rule with no inputs should always rebuild""" run_hancho("always_rebuild_if_no_inputs")