Skip to content

Commit

Permalink
get stuff working better in windows
Browse files Browse the repository at this point in the history
  • Loading branch information
aappleby committed Mar 6, 2024
1 parent d79af01 commit f72aac3
Show file tree
Hide file tree
Showing 27 changed files with 163 additions and 109 deletions.
44 changes: 38 additions & 6 deletions hancho.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@

def color(red=None, green=None, blue=None):
"""Converts RGB color to ANSI format string"""
# FIXME: Color strings don't work in Windows console?
if os.name == 'nt': return ""
if red is None:
return "\x1B[0m"
return f"\x1B[38;2;{red};{green};{blue}m"
Expand Down Expand Up @@ -105,6 +107,28 @@ def maybe_as_number(text):
return text


def touch(name):
"""Convenience helper method"""
if isinstance(name, Rule):
for f in name.files_out:
touch(f)
if os.path.exists(name):
os.utime(name, None)
else:
with open(name, "w") as file:
file.write("")


async def async_touch(task):
"""Convenience helper method"""
for name in task.files_out:
if os.path.exists(name):
os.utime(name, None)
else:
with open(name, "w") as file:
file.write("")
return task.files_out

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

this.line_dirty = False
Expand Down Expand Up @@ -252,11 +276,11 @@ async def async_main():
log(f"mtime calls: {this.mtime_calls}")

if this.tasks_fail:
log("hancho: \x1B[31mBUILD FAILED\x1B[0m")
log(f"hancho: {color(255, 0, 0)}BUILD FAILED{color()}")
elif this.tasks_pass:
log("hancho: \x1B[32mBUILD PASSED\x1B[0m")
log(f"hancho: {color(0, 255, 0)}BUILD PASSED{color()}")
else:
log("hancho: \x1B[33mBUILD CLEAN\x1B[0m")
log(f"hancho: {color(255, 255, 0)}BUILD CLEAN{color()}")

if this.config.chdir:
os.chdir(this.hancho_root)
Expand Down Expand Up @@ -572,7 +596,9 @@ async def run_command(self, command):

# Custom commands just get await'ed and then early-out'ed.
if callable(command):
result = await command(self)
result = command(self)
if inspect.isawaitable(result):
result = await result
if result is None:
raise ValueError(f"Command {command} returned None")
return result
Expand Down Expand Up @@ -651,8 +677,14 @@ def needs_rerun(self):
if self.debug:
log(f"Found depfile {abs_depfile}")
with open(abs_depfile, encoding="utf-8") as depfile:
deplines = depfile.read().split()
deplines = [d for d in deplines[1:] if d != "\\"]
deplines = None
if os.name == 'nt':
# MSVC /sourceDependencies json depfile
deplines = json.load(depfile)['Data']['Includes']
elif os.name == 'posix':
# GCC .d depfile
deplines = depfile.read().split()
deplines = [d for d in deplines[1:] if d != "\\"]
if deplines and max(mtime(f) for f in deplines) >= min_out:
return (
f"Rebuilding {self.files_out} because a dependency in "
Expand Down
9 changes: 2 additions & 7 deletions tests/always_rebuild_if_no_inputs.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
# test/always_rebuild_if_no_inputs.hancho

always_rebuilt = Rule(
command = "touch {files_out}",
)

always_rebuilt([], "result.txt")
rules = load("rules.hancho")
rules.touch_outputs([], "result.txt")
10 changes: 2 additions & 8 deletions tests/build_dir_works.hancho
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
# tests/build_dir_works.hancho

rules = load("rules.hancho")
config.build_dir = "build/build_dir_works"

build_dir_works = Rule(
command = "touch {files_out}",
)

build_dir_works([], "result.txt")
rules.touch_outputs([], "result.txt")
4 changes: 1 addition & 3 deletions tests/check_output.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
# tests/check_output.hancho

check_output = Rule(
command = "touch {files_out[0]}",
)
check_output = Rule(command = "echo foo > {files_out[0]}")

check_output(__file__, ["result.txt", "not_modified.txt"])
6 changes: 1 addition & 5 deletions tests/command_missing.hancho
Original file line number Diff line number Diff line change
@@ -1,6 +1,2 @@
# tests/command_missing.hancho

command_missing = Rule(
)

command_missing = Rule()
command_missing(__file__)
8 changes: 2 additions & 6 deletions tests/dep_changed.hancho
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@

dep_changed = Rule(
command = "touch {files_out}",
)

dep_changed(
rules = load("rules.hancho")
rules.touch_outputs(
"src/test.cpp",
"result.txt",
deps = ["build/dummy.txt"]
Expand Down
9 changes: 2 additions & 7 deletions tests/does_create_output.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
# tests/does_create_output

does_create_output = Rule(
command = "touch {files_out}",
)

does_create_output([], files_out = "result.txt")
rules = load("rules.hancho")
rules.touch_outputs([], files_out = "result.txt")
7 changes: 1 addition & 6 deletions tests/doesnt_create_output.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
# tests/doesnt_create_output.hancho

doesnt_create_output = Rule(
command = ":",
)

doesnt_create_output = Rule(command = ":")
doesnt_create_output(__file__, "result.txt")
7 changes: 1 addition & 6 deletions tests/garbage_command.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
# tests/garbage_command.hancho

garbage_command = Rule(
command = "aklsjdflksjdlfkjldfk",
)

garbage_command = Rule(command = "aklsjdflksjdlfkjldfk")
garbage_command(__file__, "result.txt")
Empty file removed tests/hancho_dot_load.hancho
Empty file.
Empty file removed tests/hancho_in_src_dir.hancho
Empty file.
10 changes: 2 additions & 8 deletions tests/header_changed.hancho
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@

header_changed = Rule(
command = "gcc -MMD -c {files_in} -o {files_out}",
files_out = "{swap_ext(files_in, '.o')}",
depfile = "{swap_ext(files_out, '.d')}",
)

header_changed("src/test.cpp")
rules = load("rules.hancho")
rules.compile_cpp("src/test.cpp")
10 changes: 2 additions & 8 deletions tests/input_changed.hancho
Original file line number Diff line number Diff line change
@@ -1,8 +1,2 @@

input_changed = Rule(
command = "gcc -MMD -c {files_in} -o {files_out}",
files_out = "{swap_ext(files_in, '.o')}",
depfile = "{swap_ext(files_out, '.d')}",
)

input_changed("src/test.cpp")
rules = load("rules.hancho")
rules.compile_cpp("src/test.cpp")
Empty file removed tests/meta_deps_changed.hancho
Empty file.
9 changes: 2 additions & 7 deletions tests/missing_src.hancho
Original file line number Diff line number Diff line change
@@ -1,7 +1,2 @@
# tests/missing_src.hancho

missing_src = Rule(
command = "touch {files_out}",
)

missing_src("src/does_not_exist.txt", "build/missing_src.txt")
rules = load("rules.hancho")
rules.touch_outputs("src/does_not_exist.txt", "build/missing_src.txt")
8 changes: 5 additions & 3 deletions tests/multiple_commands.hancho
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import os

multiple_commands = Rule(
command = [
"touch {files_out[0]}",
"touch {files_out[1]}",
"touch {files_out[2]}"
"echo foo > {files_out[0]}",
"echo bar > {files_out[1]}",
"echo baz > {files_out[2]}"
]
)

Expand Down
18 changes: 18 additions & 0 deletions tests/rules.hancho
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import os

if os.name == 'nt':
compile_command = "cl.exe /c {files_in} /sourceDependencies {depfile} /Fo:{files_out}"
elif os.name == 'posix':
compile_command = "gcc -MMD -c {files_in} -o {files_out}"
else:
compile_command = "<unknown OS>"

compile_cpp = Rule(
command = compile_command,
files_out = "{swap_ext(files_in, '.o')}",
depfile = "{swap_ext(files_out, '.d')}",
)

touch_outputs = Rule(
command = async_touch
)
7 changes: 7 additions & 0 deletions tests/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <stdio.h>
#include "main.hpp"

int main(int argc, char** argv) {
printf(message());
return 0;
}
5 changes: 5 additions & 0 deletions tests/src/main.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

inline const char* message() {
return "Hello World!!!\n";
}
12 changes: 12 additions & 0 deletions tests/sync_command.hancho
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@


def sync_command(task):
print("hello world")
touch(task.files_out[0])
return task.files_out

rule = Rule(
command = sync_command
)

rule(__file__, "result.txt")
52 changes: 33 additions & 19 deletions tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,34 @@
from os import path
import subprocess
import unittest
import shutil
import sys

# min delta seems to be 4 msec
# os.system("touch blahblah.txt")
sys.path.append("..")
import hancho

# tests still needed -
# calling hancho in src dir
# meta deps changed
# transitive dependencies

# cl /c main.cpp
# link /out:"blah.exe" main.obj

# min delta seems to be 4 msec on linux, 1 msec on windows?
#os.system("touch blahblah.txt")
# old_mtime = path.getmtime("blahblah.txt")
# min_delta = 1000000
# for _ in range(1000):
# os.system("touch blahblah.txt")
# for _ in range(10000):
# #os.system("touch blahblah.txt")
# os.utime("blahblah.txt", None)
# new_mtime = path.getmtime("blahblah.txt")
# delta = new_mtime - old_mtime
# if delta and delta < min_delta:
# log(str(delta))
# print(delta)
# min_delta = delta
# old_mtime = new_mtime

# sys.exit(0)

def mtime(file):
"""Shorthand for path.getmtime()"""
Expand All @@ -32,12 +46,7 @@ def run(cmd):

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


def touch(name):
"""Convenience helper method"""
os.system(f"touch {name}")
return os.system(f"python3 ../hancho.py --quiet {name}.hancho")


################################################################################
Expand All @@ -48,7 +57,8 @@ class TestHancho(unittest.TestCase):

def setUp(self):
"""Always wipe the build dir before a test"""
os.system("rm -rf build")
if path.exists("build"):
shutil.rmtree("build")

def test_should_pass(self):
"""Sanity check"""
Expand Down Expand Up @@ -102,15 +112,15 @@ def test_build_dir_works(self):

def test_dep_changed(self):
"""Changing a file in deps[] should trigger a rebuild"""
os.system("mkdir build")
touch("build/dummy.txt")
os.makedirs("build", exist_ok = True)
hancho.touch("build/dummy.txt")
run_hancho("dep_changed")
mtime1 = mtime("build/result.txt")

run_hancho("dep_changed")
mtime2 = mtime("build/result.txt")

touch("build/dummy.txt")
hancho.touch("build/dummy.txt")
run_hancho("dep_changed")
mtime3 = mtime("build/result.txt")
self.assertEqual(mtime1, mtime2)
Expand All @@ -134,7 +144,7 @@ def test_header_changed(self):
run_hancho("header_changed")
mtime2 = mtime("build/src/test.o")

os.system("touch src/test.hpp")
hancho.touch("src/test.hpp")
run_hancho("header_changed")
mtime3 = mtime("build/src/test.o")
self.assertEqual(mtime1, mtime2)
Expand All @@ -148,7 +158,7 @@ def test_input_changed(self):
run_hancho("input_changed")
mtime2 = mtime("build/src/test.o")

os.system("touch src/test.cpp")
hancho.touch("src/test.cpp")
run_hancho("input_changed")
mtime3 = mtime("build/src/test.o")
self.assertEqual(mtime1, mtime2)
Expand All @@ -164,10 +174,14 @@ def test_multiple_commands(self):
def test_arbitrary_flags(self):
"""Passing arbitrary flags to Hancho should work"""
os.system(
"../hancho.py --build_dir=build/some/other/dir --quiet does_create_output.hancho"
"python3 ../hancho.py --build_dir=build/some/other/dir --quiet does_create_output.hancho"
)
self.assertTrue(path.exists("build/some/other/dir/result.txt"))

def test_sync_command(self):
run_hancho("sync_command")
self.assertTrue(path.exists("build/result.txt"))


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

Expand Down
Empty file removed tests/transitive_changed.hancho
Empty file.
2 changes: 1 addition & 1 deletion tutorial/build.hancho
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ config.jobs = 1

test_build = Rule(
desc = "{color(200, 200, 100)}Testing tutorial build '{files_in}'{color()}",
command = "../hancho.py --verbose {files_in} && touch {files_out} && echo",
command = "python3 ../hancho.py --verbose {files_in} && echo pass > {files_out} && echo",
files_out = "{files_in[0] + '.pass'}",
)

Expand Down
Loading

0 comments on commit f72aac3

Please sign in to comment.