111 lines
3.1 KiB
Python
111 lines
3.1 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import os
|
|
import shutil
|
|
from pathlib import Path
|
|
|
|
from imagepipeline.core.exceptions import StepError
|
|
from imagepipeline.core.step import StepDefinition
|
|
from imagepipeline.utils.files import is_image, list_images, stem_key
|
|
|
|
|
|
def expected_output_filenames(
|
|
step: StepDefinition,
|
|
*,
|
|
matched_groups: list[list[Path]],
|
|
input_paths: list[Path],
|
|
params: dict,
|
|
) -> list[str]:
|
|
if step.module_name == "composite":
|
|
output_ext = params.get("output_ext", ".png")
|
|
return [f"{group[-1].stem}{output_ext}" for group in matched_groups]
|
|
return [path.name for path in input_paths]
|
|
|
|
|
|
def expected_output_paths(
|
|
output_dir: Path,
|
|
step: StepDefinition,
|
|
*,
|
|
matched_groups: list[list[Path]],
|
|
input_paths: list[Path],
|
|
params: dict,
|
|
) -> list[Path]:
|
|
return [
|
|
output_dir / name
|
|
for name in expected_output_filenames(
|
|
step,
|
|
matched_groups=matched_groups,
|
|
input_paths=input_paths,
|
|
params=params,
|
|
)
|
|
]
|
|
|
|
|
|
def step_outputs_complete(expected_paths: list[Path]) -> bool:
|
|
return bool(expected_paths) and all(
|
|
path.is_file() and is_image(path) for path in expected_paths
|
|
)
|
|
|
|
|
|
def source_stems_for_step(
|
|
step: StepDefinition,
|
|
*,
|
|
matched_groups: list[list[Path]],
|
|
input_paths: list[Path],
|
|
) -> list[str]:
|
|
if step.module_name == "composite":
|
|
return [stem_key(group[-1]) for group in matched_groups]
|
|
return [stem_key(path) for path in input_paths]
|
|
|
|
|
|
def materialize_external_outputs(
|
|
external_dir: Path,
|
|
output_dir: Path,
|
|
step: StepDefinition,
|
|
*,
|
|
matched_groups: list[list[Path]],
|
|
input_paths: list[Path],
|
|
params: dict,
|
|
symlink: bool = True,
|
|
) -> list[Path]:
|
|
external_dir = external_dir.resolve()
|
|
if not external_dir.is_dir():
|
|
raise StepError(f"External output directory not found: {external_dir}")
|
|
|
|
external_by_stem = {stem_key(path): path for path in list_images(external_dir)}
|
|
output_names = expected_output_filenames(
|
|
step,
|
|
matched_groups=matched_groups,
|
|
input_paths=input_paths,
|
|
params=params,
|
|
)
|
|
stems = source_stems_for_step(
|
|
step,
|
|
matched_groups=matched_groups,
|
|
input_paths=input_paths,
|
|
)
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
output_paths: list[Path] = []
|
|
for output_name, stem in zip(output_names, stems, strict=True):
|
|
source = external_by_stem.get(stem)
|
|
if source is None:
|
|
raise StepError(
|
|
f"External output for step '{step.step_id}' is missing stem {stem!r} "
|
|
f"in {external_dir}"
|
|
)
|
|
destination = output_dir / output_name
|
|
if destination.exists() or destination.is_symlink():
|
|
destination.unlink()
|
|
if symlink:
|
|
os.symlink(source, destination)
|
|
else:
|
|
shutil.copy2(source, destination)
|
|
output_paths.append(destination)
|
|
return output_paths
|
|
|
|
|
|
def read_manifest(path: Path) -> dict:
|
|
return json.loads(path.read_text(encoding="utf-8"))
|