Initial upload: Doc2Man CLI tool with parsers, generators, and tests
Some checks failed
CI / test (push) Has been cancelled
CI / build (push) Has been cancelled

This commit is contained in:
2026-01-31 00:54:21 +00:00
parent c2470c0705
commit 4af59b45ce

121
doc2man/config.py Normal file
View File

@@ -0,0 +1,121 @@
"""Configuration file handling for Doc2Man."""
from pathlib import Path
from typing import Any, Dict, List, Optional
import yaml
def find_config_file(start_path: Path = Path.cwd()) -> Optional[Path]:
"""Find configuration file starting from the given path."""
search_paths = [
".doc2man.yaml",
".doc2man.yml",
"doc2man.yaml",
"doc2man.yml",
"pyproject.toml",
]
current = start_path
while current != current.parent:
for config_name in search_paths:
config_path = current / config_name
if config_path.exists():
return config_path
current = current.parent
return None
def load_config(config_path: Optional[str] = None) -> Dict[str, Any]:
"""Load configuration from file."""
if config_path is None:
config_path = find_config_file()
if config_path is None:
return {}
else:
config_path = Path(config_path)
config_path = config_path.resolve()
if not config_path.exists():
return {}
if config_path.name == "pyproject.toml":
return load_pyproject_config(config_path)
else:
return load_yaml_config(config_path)
def load_yaml_config(config_path: Path) -> Dict[str, Any]:
"""Load configuration from YAML file."""
try:
with open(config_path, "r", encoding="utf-8") as f:
config = yaml.safe_load(f) or {}
return config.get("doc2man", config)
except yaml.YAMLError as e:
raise ValueError(f"Error parsing configuration file {config_path}: {e}")
except IOError as e:
raise ValueError(f"Error reading configuration file {config_path}: {e}")
def load_pyproject_config(config_path: Path) -> Dict[str, Any]:
"""Load configuration from pyproject.toml."""
try:
import tomli
with open(config_path, "rb") as f:
pyproject = tomli.load(f)
tool_section = pyproject.get("tool", {})
doc2man_section = tool_section.get("doc2man", {})
return doc2man_section
except ImportError:
import configparser
config = configparser.ConfigParser()
config.read(config_path)
if "doc2man" in config:
return dict(config["doc2man"])
return {}
def save_config(config: Dict[str, Any], config_path: Path) -> None:
"""Save configuration to file."""
with open(config_path, "w", encoding="utf-8") as f:
yaml.dump({"doc2man": config}, f, default_flow_style=False, indent=2)
def merge_configs(base_config: Dict[str, Any], override_config: Dict[str, Any]) -> Dict[str, Any]:
"""Merge two configurations, with override taking precedence."""
merged = base_config.copy()
for key, value in override_config.items():
if isinstance(value, dict) and key in merged and isinstance(merged[key], dict):
merged[key] = merge_configs(merged[key], value)
else:
merged[key] = value
return merged
def validate_config(config: Dict[str, Any]) -> List[str]:
"""Validate configuration and return list of warnings."""
warnings = []
valid_formats = ["man", "markdown", "html"]
if "format" in config and config["format"] not in valid_formats:
warnings.append(f"Invalid format '{config['format']}', must be one of {valid_formats}")
if "input" in config and not isinstance(config["input"], list):
warnings.append("'input' must be a list of paths")
if "output" in config and not isinstance(config["output"], str):
warnings.append("'output' must be a string path")
if "exclusions" in config and not isinstance(config["exclusions"], list):
warnings.append("'exclusions' must be a list of patterns")
return warnings