Skip to content

Commit

Permalink
checkpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
aappleby committed Mar 26, 2024
1 parent 615143e commit b42e548
Show file tree
Hide file tree
Showing 12 changed files with 71 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"request": "launch",
"program": "${workspaceFolder}/hancho.py",
"cwd": "${workspaceFolder}/tutorial",
"args": ["-j1", "-v", "tut3.hancho"],
"args": ["-j1", "tut2.hancho"],
"console": "integratedTerminal",
"justMyCode": false,
},
Expand Down
43 changes: 21 additions & 22 deletions hancho.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ def log(message, *args, sameline=False, **kwargs):
if not sys.stdout.isatty():
sameline = False

if sameline:
kwargs.setdefault("end", "")

output = io.StringIO()
print(message, *args, file=output, **kwargs)
output = output.getvalue()
Expand Down Expand Up @@ -329,6 +332,8 @@ def flatten(self, variant):
return self.flatten(variant.promise)
case list():
return [x for element in variant for x in self.flatten(element)]
case str() if macro_regex.search(variant):
return self.flatten(self.expand(variant))
case _:
return [self.expand(variant)]

Expand Down Expand Up @@ -433,28 +438,18 @@ def task_init(self):
"""All the setup steps needed before we run a task."""

# Expand everything

# FIXME we don't need to expand source_files and prepend source_path, we can expand
# abs_source_files instead

expander = Expander(self.rule)
self.desc = expander.expand(self.rule.desc)
self.command = expander.flatten(self.rule.command)
self.command_files = expander.flatten(self.rule.get("command_files", []))
self.command_path = expander.expand(self.rule.command_path)
self.source_files = expander.flatten(self.rule.source_files)
self.source_path = expander.expand(self.rule.source_path)
self.build_files = expander.flatten(self.rule.build_files)
self.build_deps = expander.flatten(self.rule.get("build_deps", []))
self.build_path = expander.expand(self.rule.build_path)

# Sanity-check expanded paths. It's OK if 'build_path' doesn't exist yet.
check_path(self.source_path, exists=True)
check_path(self.command_path, exists=True)
check_path(self.build_path, exists=False)

# Prepend expanded absolute paths to expanded filenames. If the filenames are already
# absolute, this does nothing.
self.abs_command_files = [self.command_path / f for f in self.command_files]
self.abs_source_files = [self.source_path / f for f in self.source_files]
self.abs_build_files = [self.build_path / f for f in self.build_files]
self.abs_build_deps = [self.build_path / f for f in self.build_deps]
self.abs_command_files = expander.flatten(self.rule.abs_command_files)
self.abs_source_files = expander.flatten(self.rule.abs_source_files)
self.abs_build_files = expander.flatten(self.rule.abs_build_files)
self.abs_build_deps = expander.flatten(self.rule.abs_build_deps)

# Sanity-check file paths.
check_path(self.abs_command_files, exists=True)
Expand Down Expand Up @@ -583,8 +578,8 @@ async def run_commands(self):
# _Don't_ do this if this task represents a call to an external build system, as that
# system might not actually write to the output files.
if (
self.source_files
and self.build_files
self.abs_source_files
and self.abs_build_files
and not (self.rule.dry_run or self.rule.ext_build)
):
if second_reason := self.needs_rerun():
Expand Down Expand Up @@ -682,6 +677,8 @@ def __init__(self):
job_count=1,
depformat="gcc",
ext_build=False,
command_files=[],
build_deps=[],

# Helper functions
abspath=abspath,
Expand All @@ -695,12 +692,14 @@ def __init__(self):
swap_ext=swap_ext,

# Helper macros
abs_command_files = "{joinpath(command_path, command_files)}",
abs_source_files = "{joinpath(source_path, source_files)}",
abs_build_files = "{joinpath(build_path, build_files)}",
abs_command_files = "{joinpath(command_path, command_files)}",
abs_build_deps = "{joinpath(build_path, build_deps)}",
rel_command_files = "{relpath(abs_command_files, command_path)}",
rel_source_files = "{relpath(abs_source_files, command_path)}",
rel_build_files = "{relpath(abs_build_files, command_path)}",
rel_command_files = "{relpath(abs_command_files, command_path)}",
rel_build_deps = "{relpath(abs_build_deps, command_path)}",

# Global config has no base.
base=None,
Expand Down
4 changes: 2 additions & 2 deletions tests/check_output.hancho
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ from hancho import *
build_config.defaults(
command_path = Path.cwd(),
source_path = Path.cwd(),
build_path = Path.cwd()
build_path = Path.cwd() / "build"
)

check_output = Rule(command = "echo foo > {files_out[0]}")
check_output = build_config.rule(command = "echo foo > {rel_build_files[0]}")

check_output(__file__, ["result.txt", "not_modified.txt"])
9 changes: 8 additions & 1 deletion tests/command_missing.hancho
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# tests/command_missing.hancho
from hancho import *

build_config.defaults(
command_path = Path.cwd(),
source_path = Path.cwd(),
build_path = Path.cwd() / "build",
)

command_missing = Rule()
command_missing(__file__)
command_missing(__file__, "dummy.txt")
1 change: 1 addition & 0 deletions tests/config_child.hancho
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ from hancho import *
import sys

# We should inherit config.foobar from our parent module.

if build_config.get('foobar') is None:
sys.exit(-1)

Expand Down
11 changes: 9 additions & 2 deletions tests/missing_field.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
# tests/missing_field.hancho
from hancho import *

rule = Rule(
command = "touch {files_out} {this_field_does_not_exist}"
build_config.defaults(
command_path = Path.cwd(),
source_path = Path.cwd(),
build_path = Path.cwd() / "build",
)

rule = build_config.rule(
command = "touch {build_files} {this_field_does_not_exist}"
)

rule([], "result.txt")
9 changes: 8 additions & 1 deletion tests/missing_input.hancho
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
# tests/missing_input.hancho
from hancho import *

rules = load("rules.hancho")
build_config.defaults(
command_path = Path.cwd(),
source_path = Path.cwd(),
build_path = Path.cwd()
)

rules = load("rules.hancho", build_config)
rules.touch_outputs("src/does_not_exist.txt", "build/missing_src.txt")
17 changes: 0 additions & 17 deletions tests/recursive_base_is_bad.hancho

This file was deleted.

2 changes: 1 addition & 1 deletion tests/rules.hancho
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import os

if os.name == 'nt':
config.depformat = "msvc"
compile_command = "cl.exe /c {files_in} /sourceDependencies {depfile} /Fo:{files_out}"
compile_command = "cl.exe /c {rel_source_files} /sourceDependencies {rel_build_deps} /Fo:{files_out}"
elif os.name == 'posix':
config.depformat = "gcc"
compile_command = "gcc -MMD -c {files_in} -o {files_out}"
Expand Down
36 changes: 18 additions & 18 deletions tests/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@ def run(cmd):


def run_hancho(name):
"""Runs a Hancho build script, quietly."""
return os.system(f"python3 ../hancho.py --quiet {name}.hancho")

"""Runs a Hancho build script and returns a subprocess.CompletedProcess."""
return subprocess.run(f"python3 ../hancho.py {name}.hancho", shell=True, text=True, capture_output=True)

################################################################################

Expand All @@ -63,8 +62,7 @@ def setUp(self):
"""Always wipe the build dir before a test"""
print()
print(f"Running {self._testMethodName}..", end="")
if path.exists("build"):
shutil.rmtree("build")
shutil.rmtree("build", ignore_errors=True)
sys.stdout.flush()

def tearDown(self):
Expand All @@ -74,36 +72,38 @@ def tearDown(self):

def test_should_pass(self):
"""Sanity check"""
self.assertEqual(0, run_hancho("should_pass"))
self.assertEqual(0, run_hancho("should_pass").returncode)

def test_should_fail(self):
"""Sanity check"""
self.assertNotEqual(0, run_hancho("should_fail"))
result = run_hancho("should_fail")
self.assertTrue("ValueError: Command '(exit 255)' exited with return code 255" in result.stderr)

def test_check_output(self):
"""A build rule that doesn't update one of its outputs should fail"""
self.assertNotEqual(0, run_hancho("check_output"))
result = run_hancho("check_output")
self.assertTrue(Path("build/result.txt").exists())
self.assertFalse(Path("build/not_modified.txt").exists())
self.assertTrue("still needs rerun after running" in result.stderr)

def test_config_inheritance(self):
"""A module should inherit a config object extended from its parent, but should not be able
to modify its parent's config object."""
self.assertEqual(0, run_hancho("config_parent"))
self.assertEqual(0, run_hancho("config_parent").returncode)

# This should fail because it was expecting inheritance from its parent.
self.assertNotEqual(0, run_hancho("config_child"))

# def test_recursive_base_is_bad(self):
# """Referring to base.attrib in a template is a bad idea"""
# self.assertNotEqual(0, run_hancho("recursive_base_is_bad"))
self.assertNotEqual(0, run_hancho("config_child").returncode)
#
# def test_command_missing(self):
# """Rules with missing commands should fail"""
# self.assertNotEqual(0, run_hancho("command_missing"))
# result = run_hancho("command_missing")
# self.assertTrue("Config key 'command' was never defined" in result.stderr)
#
# def test_missing_field(self):
# """Missing fields should turn into empty strings when expanded"""
# self.assertEqual(0, run_hancho("missing_field"))
#
# """Missing fields should raise an error when expanded"""
# result = run_hancho("missing_field")
# self.assertTrue("NameError: name 'this_field_does_not_exist' is not defined" in result.stderr)

# def test_missing_input(self):
# """We should fail if an input is missing"""
# self.assertNotEqual(0, run_hancho("missing_input"))
Expand Down
2 changes: 1 addition & 1 deletion tests/should_fail.hancho
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from hancho import *
build_config.defaults(
command_path = Path.cwd(),
source_path = Path.cwd(),
build_path = Path.cwd()
build_path = Path.cwd() / "build",
)

should_pass = build_config.rule(
Expand Down
2 changes: 1 addition & 1 deletion tests/should_pass.hancho
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ from hancho import *
build_config.defaults(
command_path = Path.cwd(),
source_path = Path.cwd(),
build_path = Path.cwd()
build_path = Path.cwd() / "build",
)

should_pass = build_config.rule(
Expand Down

0 comments on commit b42e548

Please sign in to comment.