Skip to content

Commit

Permalink
fix: Add back corruption checker
Browse files Browse the repository at this point in the history
  • Loading branch information
FHeilmann committed Dec 10, 2023
1 parent fa6c09b commit 7464dbe
Show file tree
Hide file tree
Showing 2 changed files with 159 additions and 1 deletion.
159 changes: 159 additions & 0 deletions voron_ci/tools/stl_corruption_checker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import tempfile
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
from typing import Self

import configargparse
from admesh import Stl

from voron_ci.constants import ReturnStatus, SummaryStatus
from voron_ci.utils.action_summary import ActionSummaryTable
from voron_ci.utils.file_helper import FileHelper
from voron_ci.utils.github_action_helper import ActionResult, GithubActionHelper
from voron_ci.utils.logging import init_logging

logger = init_logging(__name__)


ENV_VAR_PREFIX = "CORRUPTION_CHECKER"


class STLCorruptionChecker:
def __init__(self: Self, args: configargparse.Namespace) -> None:
self.input_dir: Path = Path(Path.cwd(), args.input_dir)
self.return_status: ReturnStatus = ReturnStatus.SUCCESS
self.check_summary: list[list[str]] = []
self.gh_helper: GithubActionHelper = GithubActionHelper(
output_path=args.output_dir, do_gh_step_summary=args.github_step_summary, ignore_warnings=args.ignore_warnings
)

if args.verbose:
logger.setLevel("INFO")

def run(self: Self) -> None:
logger.info("Searching for STL files in '%s'", str(self.input_dir))

stl_paths: list[Path] = FileHelper.find_files(directory=self.input_dir, extension="stl", max_files=40)

with ThreadPoolExecutor() as pool:
return_statuses: list[ReturnStatus] = list(pool.map(self._check_stl, stl_paths))
if return_statuses:
self.return_status = max(*return_statuses, self.return_status)
else:
self.return_status = ReturnStatus.SUCCESS

self.gh_helper.postprocess_action(
action_result=ActionResult(
action_id="stl_corruption_checker",
action_name="STL Corruption Checker",
outcome=self.return_status,
summary=ActionSummaryTable(
title="STL Corruption Checker",
columns=["Filename", "Result", "Edges Fixed", "Backwards Edges", "Degenerate Facets", "Facets Removed", "Facets Added", "Facets Reversed"],
rows=self.check_summary,
),
)
)

def _write_fixed_stl_file(self: Self, stl: Stl, path: Path) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
logger.info("Saving fixed STL to '%s'", path)
temp_file = tempfile.NamedTemporaryFile(suffix=".stl")
stl.write_binary(temp_file.name)
self.gh_helper.set_artifact(file_name=path.as_posix(), file_contents=Path(temp_file.name).read_bytes())
temp_file.close()

def _check_stl(self: Self, stl_file_path: Path) -> ReturnStatus:
try:
logger.info("Checking '%s'", stl_file_path.relative_to(self.input_dir).as_posix())
stl: Stl = Stl(stl_file_path.as_posix())
stl.repair(verbose_flag=False)
if (
stl.stats["edges_fixed"] > 0
or stl.stats["backwards_edges"] > 0
or stl.stats["degenerate_facets"] > 0
or stl.stats["facets_removed"] > 0
or stl.stats["facets_added"] > 0
or stl.stats["facets_reversed"] > 0
):
logger.error("Corrupt STL detected '%s'!", stl_file_path.relative_to(self.input_dir).as_posix())
self.check_summary.append(
[
stl_file_path.name,
SummaryStatus.FAILURE,
str(stl.stats["edges_fixed"]),
str(stl.stats["backwards_edges"]),
str(stl.stats["degenerate_facets"]),
str(stl.stats["facets_removed"]),
str(stl.stats["facets_added"]),
str(stl.stats["facets_reversed"]),
]
)
self._write_fixed_stl_file(stl=stl, path=Path(stl_file_path.relative_to(self.input_dir)))
return ReturnStatus.FAILURE
return ReturnStatus.SUCCESS
except Exception as e:
logger.exception("A fatal error occurred during corruption checking", exc_info=e)
self.check_summary.append(
[stl_file_path.name, SummaryStatus.EXCEPTION, "0", "0", "0", "0", "0", "0"],
)
return ReturnStatus.EXCEPTION


def main() -> None:
parser: configargparse.ArgumentParser = configargparse.ArgumentParser(
prog="VoronDesign STL checker & fixer",
description="This tool can be used to check a provided folder of STLs and potentially fix them",
)
parser.add_argument(
"-i",
"--input_dir",
required=True,
action="store",
type=str,
env_var=f"{ENV_VAR_PREFIX}_INPUT_DIR",
help="Directory containing STL files to be checked",
)
parser.add_argument(
"-o",
"--output_dir",
required=False,
action="store",
type=str,
env_var=f"{ENV_VAR_PREFIX}_OUTPUT_DIR",
help="Directory to store the fixed STL files into",
default="",
)
parser.add_argument(
"-f",
"--ignore_warnings",
required=False,
action="store_true",
env_var=f"{ENV_VAR_PREFIX}_IGNORE_WARNINGS",
help="Whether to ignore warnings and return a success exit code",
default=False,
)
parser.add_argument(
"-v",
"--verbose",
required=False,
action="store_true",
env_var=f"{ENV_VAR_PREFIX}_VERBOSE",
help="Print debug output to stdout",
default=False,
)
parser.add_argument(
"-g",
"--github_step_summary",
required=False,
action="store_true",
env_var=f"{ENV_VAR_PREFIX}_GITHUB_STEP_SUMMARY",
help="Whether to output a step summary when running inside a github action",
default=False,
)
args: configargparse.Namespace = parser.parse_args()
STLCorruptionChecker(args=args).run()


if __name__ == "__main__":
main()
1 change: 0 additions & 1 deletion voron_ci/tools/stl_rotation_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,6 @@ def _write_fixed_stl_file(self: Self, stl: dict[int, Any], opts: Tweak, stl_file

def _check_stl(self: Self, stl_file_path: Path) -> ReturnStatus:
logger.info("Checking '%s'", stl_file_path.relative_to(self.input_dir).as_posix())
rotated_image_url: str = ""
try:
mesh_objects: dict[int, Any] = FileHandler().load_mesh(inputfile=stl_file_path.as_posix())
if len(mesh_objects.items()) > 1:
Expand Down

0 comments on commit 7464dbe

Please sign in to comment.