Improve cli, add subcommands and flags.

This commit is contained in:
2026-08-26 02:36:07 +02:00
parent 8c6c0d318e
commit 48af9665f0
2 changed files with 102 additions and 8 deletions
+89 -5
View File
@@ -1,10 +1,56 @@
import argparse
import logging
import sys
from omicron.ssg.site import Site
from omicron.ssg.output import OutputError
from omicron.ssg.site import ConfigError, Site
from pathlib import Path
def setup_logging(verbose: bool = False, log_file: str | None = None) -> None:
class CliError(RuntimeError):
pass
def setup_argparse() -> argparse.ArgumentParser:
# base options
help_formatter = argparse.ArgumentDefaultsHelpFormatter
parser = argparse.ArgumentParser(prog="ossg", formatter_class=help_formatter)
parser.add_argument(
"--site", type=Path, default=Path("."), help="path to site directory"
)
parser.add_argument(
"--verbose", "-v", action="count", default=0, help="increase log verbosity"
)
parser.add_argument(
"--log-file",
type=Path,
default=argparse.SUPPRESS,
help="write logs to this file (default: <site>/build.log)",
)
subparsers = parser.add_subparsers(dest="command", required=True)
# build command
build = subparsers.add_parser(
"build", help="build the site", formatter_class=help_formatter
)
build.add_argument(
"--clean",
action=argparse.BooleanOptionalAction,
default=True,
help="remove output directory before building",
)
build.add_argument(
"--drafts",
action=argparse.BooleanOptionalAction,
default=False,
help="include draft content",
)
subparsers.add_parser("clean", help="remove the output directory")
return parser
def setup_logging(verbose: bool = False, log_file: Path | None = None) -> None:
logger = logging.getLogger("omicron.ssg")
logger.setLevel(logging.DEBUG)
@@ -13,8 +59,46 @@ def setup_logging(verbose: bool = False, log_file: str | None = None) -> None:
console.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
logger.addHandler(console)
if log_file is not None:
try:
file_handler = logging.FileHandler(log_file)
except FileNotFoundError as e:
raise CliError("log file can't be written") from e
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(
logging.Formatter("%(asctime)s %(levelname)s: %(message)s")
)
logger.addHandler(file_handler)
def build(args: argparse.Namespace) -> None:
site = Site(args.site, args.drafts)
if args.clean:
site.clean()
site.build()
def clean(args: argparse.Namespace) -> None:
site = Site(args.site)
site.clean()
def cli() -> None:
parser = setup_argparse()
args = parser.parse_args()
log_file = getattr(args, "log_file", args.site / "build.log")
setup_logging(verbose=bool(args.verbose), log_file=log_file)
if args.command == "build":
build(args)
elif args.command == "clean":
clean(args)
else:
raise NotImplementedError(f"'{args.command}' command not implemented yet")
def main() -> None:
setup_logging(verbose=True)
site = Site(Path("."))
site.build()
try:
cli()
except (ConfigError, OutputError, CliError) as e:
print(e)
sys.exit(1)
+11 -1
View File
@@ -1,4 +1,5 @@
import logging
import shutil
from typing import Any, cast
from urllib.parse import urlparse
@@ -31,7 +32,7 @@ class ConfigError(RuntimeError):
class Site:
def __init__(self, site: Path):
def __init__(self, site: Path, drafts: bool = False):
self.site_path = site.resolve()
self.content: list[Content] = []
self.directories: list[Directory] = []
@@ -54,8 +55,11 @@ class Site:
def read_config(self) -> dict[str, Any]:
config_path = self.site_path / "config.yml"
log.debug("Reading config file %s", config_path)
try:
with open(config_path, "r") as f:
config = yaml.safe_load(f)
except FileNotFoundError:
raise ConfigError("config file missing, not a valid ossg directory")
if not isinstance(config, dict) or not all(isinstance(k, str) for k in config):
raise ConfigError("config file must be a YAML mapping with string keys")
if "name" not in config:
@@ -188,6 +192,12 @@ class Site:
self.other_outputs.append(tags_page)
log.info("Discovered %d content items", len(self.content))
def clean(self) -> None:
if not self.output_path.exists():
return
shutil.rmtree(self.output_path)
log.info("Removed %s", self.output_path)
def build(self) -> None:
if not self.origin:
log.warning(