Compare commits

...

2 Commits

Author SHA1 Message Date
Kyler Olsen 018197e290 removed nessisary functions 2025-12-19 14:00:58 -07:00
Kyler Olsen 2efdd1d2e2 Created utils 2025-12-19 14:00:38 -07:00
1 changed files with 187 additions and 0 deletions

View File

@ -0,0 +1,187 @@
#!/usr/bin/env python3
"""
Utility functions for the build system.
Provides common operations like process execution,
file dependency checking, and tool detection.
"""
import subprocess
import shutil
from pathlib import Path
from typing import List, Union, Optional
# -----------------------------------------------------------------------------
# Process execution
# -----------------------------------------------------------------------------
def run(cmd: List[Union[str, Path]],
cwd: Optional[Path] = None,
check: bool = True,
capture_output: bool = False,
verbose: bool = True) -> subprocess.CompletedProcess:
"""
Execute a command and optionally capture its output.
Args:
cmd: Command and arguments to execute
cwd: Working directory for the command
check: If True, raise exception on non-zero exit code
capture_output: If True, capture stdout and stderr
verbose: If True, print the command before executing
Returns:
CompletedProcess instance with return code and output
Raises:
subprocess.CalledProcessError: If check=True and command fails
"""
# Convert all Path objects to strings
cmd_str = [str(c) for c in cmd]
if verbose:
print(">>", " ".join(cmd_str))
return subprocess.run(
cmd_str,
cwd=cwd,
check=check,
capture_output=capture_output,
text=True if capture_output else None
)
def run_quiet(cmd: List[Union[str, Path]],
cwd: Optional[Path] = None,
check: bool = False) -> subprocess.CompletedProcess:
"""
Execute a command silently (no output, no verbose).
Args:
cmd: Command and arguments to execute
cwd: Working directory for the command
check: If True, raise exception on non-zero exit code
Returns:
CompletedProcess instance
"""
cmd_str = [str(c) for c in cmd]
return subprocess.run(
cmd_str,
cwd=cwd,
check=check,
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
# -----------------------------------------------------------------------------
# File dependency checking
# -----------------------------------------------------------------------------
def is_up_to_date(source: Path, output: Path, dependency: Optional[Path] = None) -> bool:
"""
Check if an output file is up to date relative to its source and dependencies.
Args:
source: Source file path
output: Output file path
dependency: Optional dependency file (e.g., .d file)
Returns:
True if output is up to date, False if it needs rebuilding
"""
# Files with 'meta' in their name are never up to date (force rebuild)
if "meta" in source.stem or "meta" in output.stem:
return False
if dependency and "meta" in dependency.stem:
return False
# Output doesn't exist, needs building
if not output.exists():
return False
# Check dependency file if provided
if dependency:
if dependency.exists() and dependency.stat().st_mtime > output.stat().st_mtime:
return False
# Check source file modification time
return source.stat().st_mtime < output.stat().st_mtime
def needs_rebuild(sources: List[Path], output: Path) -> bool:
"""
Check if any source file is newer than the output file.
Args:
sources: List of source file paths
output: Output file path
Returns:
True if rebuild is needed, False otherwise
"""
if not output.exists():
return True
output_time = output.stat().st_mtime
return any(src.stat().st_mtime > output_time for src in sources if src.exists())
# -----------------------------------------------------------------------------
# Tool detection
# -----------------------------------------------------------------------------
def which(tool: str) -> Optional[Path]:
"""
Find a tool in the system PATH.
Args:
tool: Tool name to find
Returns:
Path to the tool if found, None otherwise
"""
result = shutil.which(tool)
return Path(result) if result else None
def check_tool(tool: str) -> bool:
"""
Check if a tool is available in the system PATH.
Args:
tool: Tool name to check
error_message: Optional custom error message to print if not found
Returns:
True if tool is found, False otherwise
"""
if which(tool):
return True
else:
print(f"ERROR: Required tool '{tool}' not found in PATH")
return False
def check_tools(tools: List[str]) -> bool:
"""
Check if multiple tools are available.
Args:
tools: List of tool names to check
error_messages: Optional list of custom error messages (same length as tools)
Returns:
True if all tools are found, False otherwise
"""
all_found = True
for tool in tools:
if not check_tool(tool):
all_found = False
return all_found