- Add complete CLI command implementations with Typer subcommands - Implement utils/time.py with duration formatting and datetime utilities - Implement utils/path.py with project path management utilities - Wire up all commands to main CLI entry point
88 lines
2.2 KiB
Python
88 lines
2.2 KiB
Python
"""Path utility functions."""
|
|
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
|
|
def ensure_dir(path: Path) -> Path:
|
|
"""Ensure a directory exists, creating it if necessary.
|
|
|
|
Args:
|
|
path: Path to the directory.
|
|
|
|
Returns:
|
|
The path to the directory.
|
|
"""
|
|
path.mkdir(parents=True, exist_ok=True)
|
|
return path
|
|
|
|
|
|
def project_root(slug: str, projects_root: Optional[Path] = None) -> Path:
|
|
"""Get the root path for a project.
|
|
|
|
Args:
|
|
slug: Project slug.
|
|
projects_root: Root directory for all projects. Defaults to ./projects.
|
|
|
|
Returns:
|
|
Path to the project root.
|
|
"""
|
|
if projects_root is None:
|
|
projects_root = Path("projects")
|
|
return projects_root / slug
|
|
|
|
|
|
def relative_to_project(slug: str, relative_path: str, projects_root: Optional[Path] = None) -> Path:
|
|
"""Get a path relative to a project.
|
|
|
|
Args:
|
|
slug: Project slug.
|
|
relative_path: Relative path within the project.
|
|
projects_root: Root directory for all projects.
|
|
|
|
Returns:
|
|
Absolute path to the file within the project.
|
|
"""
|
|
root = project_root(slug, projects_root)
|
|
return root / relative_path
|
|
|
|
|
|
def is_within_project(slug: str, file_path: Path, projects_root: Optional[Path] = None) -> bool:
|
|
"""Check if a file path is within a project.
|
|
|
|
Args:
|
|
slug: Project slug.
|
|
file_path: Path to check.
|
|
projects_root: Root directory for all projects.
|
|
|
|
Returns:
|
|
True if file_path is within the project directory.
|
|
"""
|
|
project_path = project_root(slug, projects_root)
|
|
try:
|
|
file_path.resolve().relative_to(project_path.resolve())
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
|
|
def sanitize_filename(filename: str) -> str:
|
|
"""Sanitize a filename by removing invalid characters.
|
|
|
|
Args:
|
|
filename: Original filename.
|
|
|
|
Returns:
|
|
Sanitized filename safe for file system use.
|
|
"""
|
|
# Remove or replace invalid characters
|
|
invalid_chars = '<>:"/\\|?*'
|
|
for char in invalid_chars:
|
|
filename = filename.replace(char, "_")
|
|
|
|
# Limit length
|
|
if len(filename) > 255:
|
|
filename = filename[:255]
|
|
|
|
return filename
|