Skip to content

Commit

Permalink
Rewrite gen_matrix.py
Browse files Browse the repository at this point in the history
  • Loading branch information
yut23 committed Dec 14, 2023
1 parent 96dec3a commit ad588c2
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 58 deletions.
171 changes: 115 additions & 56 deletions .github/workflows/gen_matrix.py
Original file line number Diff line number Diff line change
@@ -1,74 +1,133 @@
from __future__ import annotations

import json
import re
import sys
from collections import deque
from dataclasses import asdict, dataclass
from collections import defaultdict
from dataclasses import dataclass
from pathlib import Path


@dataclass(order=True, frozen=True, kw_only=True)
class Config:
directory: str
target: str
compiler: str
class Target:
base_dir: Path
day: int
prefix: str

@property
def suffix(self) -> str:
return f"{self.day:02d}"

def __str__(self) -> str:
return f"{self.prefix}{self.day:02d}"

@classmethod
def from_file(cls, base_dir: Path, source_file: Path) -> Target:
m = re.match(r"(?P<prefix>day|test)(?P<day>\d+)$", source_file.stem)
assert m is not None, source_file
return cls(base_dir=base_dir, day=int(m["day"]), prefix=m["prefix"])

def get_deps(self) -> set[Path]:
deps = set()
src = self.base_dir / "src"
deps.add(src / f"{self}.cpp")
deps.add(src / f"day{self.suffix}.hpp")
deps.add(src / "lib.hpp")
deps.add(src / "lib.h")
if self.prefix == "test" and (src / "unit_test").exists():
for p in (src / "unit_test").iterdir():
deps.add(p)
deps.add(self.base_dir / "Makefile")
return deps


configs = set()

@dataclass(order=True, frozen=True, kw_only=True)
class Config:
target: Target
compiler: str

def add_config(directory: str, target: str) -> None:
configs.add(Config(directory=directory, target=target, compiler="clang++"))
configs.add(Config(directory=directory, target=target, compiler="g++"))
def to_dict(self) -> dict[str, str]:
return {
"directory": str(self.target.base_dir),
"target": str(self.target),
"compiler": self.compiler,
}


def enumerate_targets(base_dir: Path) -> list[Target]:
return sorted(
Target.from_file(base_dir, file)
for file in base_dir.glob("src/*.cpp")
if file.stem != "template"
)


def find_base_dirs() -> list[Path]:
return sorted(makefile.parent for makefile in Path().glob("*/Makefile"))


class Matrix:
def __init__(self, target_regex: str | None = None) -> None:
if target_regex is not None:
target_pat = re.compile(target_regex)
else:
target_pat = None
self.configs: set[Config] = set()

self.targets: list[Target] = []
for base_dir in find_base_dirs():
for target in enumerate_targets(base_dir):
if target_pat is None or target_pat.match(target.prefix):
self.targets.append(target)
self.targets.sort()

self.file_lookup: dict[Path, list[Target]] = defaultdict(list)
for target in self.targets:
for dep in target.get_deps():
self.file_lookup[dep].append(target)

self.file_lookup[Path(".github/workflows/gen_matrix.py")] = self.targets
for file in Path().glob(".github/workflows/*.yml"):
with open(file, "r") as f:
if "gen_matrix.py" in f.read():
self.file_lookup[file] = self.targets

def process_changed_file(self, file: Path) -> None:
for target in self.file_lookup.get(file, ()):
self.add_config(target)

def add_config(self, target: Target) -> None:
self.configs.add(Config(target=target, compiler="clang++"))
self.configs.add(Config(target=target, compiler="g++"))

def write_combinations(self, output_file: str) -> None:
matrix = {}
if self.configs:
config_list = sorted(self.configs)
includes = []
print("\nconfigurations:")
for config in config_list:
includes.append(config.to_dict())
print(f" {config}")
matrix["include"] = includes
with open(output_file, "a") as f:
f.write("matrix-combinations=")
json.dump(matrix, f, indent=None, separators=(",", ":"))
f.write("\n")


def main() -> None:
target_prefix = sys.argv[1]
assert target_prefix in {"day", "test"}
target_glob = target_prefix + "*.cpp"
changed_files_json = sys.argv[1]
output_file = sys.argv[2]
target_regex = sys.argv[3] if len(sys.argv) > 3 else None

changed_files: deque[Path] = deque()
print("got changed files:")
for f in json.loads(sys.argv[2]):
matrix = Matrix(target_regex)

for f in json.loads(changed_files_json):
print(f" {f}")
changed_files.append(Path(f))

while changed_files:
path = changed_files.popleft()

if path.parts[:2] == (".github", "workflows"):
# changed a workflow file, so include everything in all base
# directories
for makefile in Path().glob("*/Makefile"):
for path in (makefile.parent / "src").glob(target_glob):
changed_files.append(path)
continue

base_directory = path.parts[0]
if path.name in {"Makefile", "lib.h", "lib.hpp"} or "unit_test" in path.parts:
# changed a Makefile or some library code, so include everything in
# that base directory
for path in (Path(base_directory) / "src").glob(target_glob):
changed_files.append(path)
continue

m = re.search(r"(day|test)(\d+.*)", path.stem)
assert m is not None and path.suffix in {".cpp", ".hpp"}
if Path(f"{base_directory}/src/{target_prefix}{m[2]}.cpp").exists():
add_config(directory=base_directory, target=target_prefix + m[2])

matrix = {}
if configs:
config_list = sorted(configs)
includes = []
print("\nconfigurations:")
for config in config_list:
includes.append(asdict(config))
print(f" {config}")
matrix["include"] = includes
with open(sys.argv[3], "a") as f:
f.write("matrix-combinations=")
json.dump(matrix, f, indent=None, separators=(",", ":"))
f.write("\n")
matrix.process_changed_file(Path(f))

matrix.write_combinations(output_file)


if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/test-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
# reference: https://stackoverflow.com/a/65094398
- name: Setup matrix combinations
id: setup-matrix-combinations
run: python $GITHUB_WORKSPACE/.github/workflows/gen_matrix.py "day" "${{ steps.changed-files.outputs.all_changed_files }}" $GITHUB_OUTPUT
run: python $GITHUB_WORKSPACE/.github/workflows/gen_matrix.py "${{ steps.changed-files.outputs.all_changed_files }}" $GITHUB_OUTPUT "day|test"

outputs:
matrix-combinations: ${{ steps.setup-matrix-combinations.outputs.matrix-combinations }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
# reference: https://stackoverflow.com/a/65094398
- name: Setup matrix combinations
id: setup-matrix-combinations
run: python $GITHUB_WORKSPACE/.github/workflows/gen_matrix.py "test" "${{ steps.changed-files.outputs.all_changed_files }}" $GITHUB_OUTPUT
run: python $GITHUB_WORKSPACE/.github/workflows/gen_matrix.py "${{ steps.changed-files.outputs.all_changed_files }}" $GITHUB_OUTPUT "test"

outputs:
matrix-combinations: ${{ steps.setup-matrix-combinations.outputs.matrix-combinations }}
Expand Down

0 comments on commit ad588c2

Please sign in to comment.