from __future__ import annotations import json from pathlib import Path from typing import Any, Dict, List, Optional from .errors import MaterializeError def create_config(path: Path) -> None: _ensure_parent_exists(path) if path.exists(): raise MaterializeError(f"Config already exists: {path}") payload = { "wordpress_root": "/path/to/wordpress", "repo_storage_dir": "/path/to/repo-storage", "renderer": "default", "hard_line_breaks": False, "block_html": False, "git_repositories": [ { "name": "example-repo", "url": "https://example.com/repo.git", "branch": "main", "root_subdir": None, } ], "directories": [ { "name": "example-dir", "path": "/path/to/content", "root_subdir": None, } ], } path.write_text(json.dumps(payload, indent=2), encoding="utf-8") def create_manifest(directory: Path) -> Path: if not directory.exists(): raise MaterializeError(f"Directory does not exist: {directory}") if not directory.is_dir(): raise MaterializeError(f"Not a directory: {directory}") manifest_path = directory / ".wp-materialize.json" if manifest_path.exists(): raise MaterializeError(f"Manifest already exists: {manifest_path}") payload = { "categories": {"content": [], "inherit": True}, "tags": {"content": [], "inherit": True}, "author": {"content": [], "inherit": True}, "renderer": "default", "hard_line_breaks": False, "block_html": False, "subdirectories": {"content": [], "inherit": True}, "files": {}, } manifest_path.write_text(json.dumps(payload, indent=2), encoding="utf-8") return manifest_path def add_file_to_manifest(file_path: Path, manifest_dir: Path) -> None: if not file_path.exists(): raise MaterializeError(f"File does not exist: {file_path}") if not file_path.is_file(): raise MaterializeError(f"Not a file: {file_path}") manifest_path = _manifest_path(manifest_dir) data = _load_manifest_json(manifest_path) relative = _relative_to(file_path, manifest_dir) files = data.setdefault("files", {}) if not isinstance(files, dict): raise MaterializeError("Manifest files must be an object") if relative in files: raise MaterializeError(f"File already exists in manifest: {relative}") files[relative] = {"title": "TODO: Title"} _write_manifest_json(manifest_path, data) def add_dir_to_manifest(dir_path: Path, manifest_dir: Path) -> None: if not dir_path.exists(): raise MaterializeError(f"Directory does not exist: {dir_path}") if not dir_path.is_dir(): raise MaterializeError(f"Not a directory: {dir_path}") manifest_path = _manifest_path(manifest_dir) data = _load_manifest_json(manifest_path) relative = _relative_to(dir_path, manifest_dir) subdirs = data.setdefault("subdirectories", {"content": [], "inherit": True}) if not isinstance(subdirs, dict): raise MaterializeError("Manifest subdirectories must be an object") content = subdirs.setdefault("content", []) if not isinstance(content, list) or any(not isinstance(item, str) for item in content): raise MaterializeError("Manifest subdirectories.content must be a list of strings") if relative in content: raise MaterializeError(f"Subdirectory already exists in manifest: {relative}") content.append(relative) _write_manifest_json(manifest_path, data) def resolve_manifest_dir(target_path: Path, manifest_dir: Optional[Path], use_current: bool) -> Path: if manifest_dir and use_current: raise MaterializeError("--current cannot be used with an explicit manifest directory") if manifest_dir: return manifest_dir if use_current: return target_path.parent return Path.cwd() def _manifest_path(manifest_dir: Path) -> Path: if not manifest_dir.exists(): raise MaterializeError(f"Manifest directory does not exist: {manifest_dir}") if not manifest_dir.is_dir(): raise MaterializeError(f"Not a directory: {manifest_dir}") manifest_path = manifest_dir / ".wp-materialize.json" if not manifest_path.exists(): raise MaterializeError(f"Manifest not found: {manifest_path}") return manifest_path def _load_manifest_json(path: Path) -> Dict[str, Any]: try: data = json.loads(path.read_text(encoding="utf-8")) except json.JSONDecodeError as exc: raise MaterializeError(f"Invalid JSON in manifest: {exc}") from exc if not isinstance(data, dict): raise MaterializeError("Manifest must be a JSON object") return data def _write_manifest_json(path: Path, data: Dict[str, Any]) -> None: path.write_text(json.dumps(data, indent=2), encoding="utf-8") def _relative_to(path: Path, base: Path) -> str: try: relative = path.relative_to(base) except ValueError as exc: raise MaterializeError(f"Path is outside manifest directory: {path}") from exc relative_str = relative.as_posix() if relative_str in {".", ""}: raise MaterializeError(f"Path must be inside manifest directory: {path}") return relative_str def _ensure_parent_exists(path: Path) -> None: parent = path.parent if not parent.exists(): raise MaterializeError(f"Directory does not exist: {parent}") if not parent.is_dir(): raise MaterializeError(f"Not a directory: {parent}")