1 parent
278d3e937e
commit
7bf04ff064
2 files changed
+113
-2
No files matched your search
+77
-2
@@ -1,11 +1,14 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
|
from collections.abc import Callable
|
||||||
from omicron.ssg.output import OutputError
|
from omicron.ssg.output import OutputError
|
||||||
from omicron.ssg.site import Site
|
from omicron.ssg.site import Site
|
||||||
from omicron.ssg.config import ConfigError
|
from omicron.ssg.config import ConfigError, SiteConfig, DEFAULT_ITEMS_PER_PAGE
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class CliError(RuntimeError):
|
class CliError(RuntimeError):
|
||||||
pass
|
pass
|
||||||
@@ -46,8 +49,15 @@ def setup_argparse() -> argparse.ArgumentParser:
|
|||||||
default=False,
|
default=False,
|
||||||
help="include draft content",
|
help="include draft content",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# clean command
|
||||||
subparsers.add_parser("clean", help="remove the output directory")
|
subparsers.add_parser("clean", help="remove the output directory")
|
||||||
|
|
||||||
|
# init command
|
||||||
|
subparsers.add_parser(
|
||||||
|
"init", help="create a new site directory", formatter_class=help_formatter
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
|
|
||||||
@@ -84,15 +94,80 @@ def clean(args: argparse.Namespace) -> None:
|
|||||||
site.clean()
|
site.clean()
|
||||||
|
|
||||||
|
|
||||||
|
def prompt(
|
||||||
|
label: str,
|
||||||
|
explanation: str | None = None,
|
||||||
|
default: str | None = None,
|
||||||
|
required: bool = True,
|
||||||
|
validate: Callable[[str], bool] | None = None,
|
||||||
|
error: str = "Invalid value.",
|
||||||
|
) -> str:
|
||||||
|
if explanation:
|
||||||
|
print(explanation)
|
||||||
|
hint = f" [{default}]" if default is not None else ""
|
||||||
|
while True:
|
||||||
|
value = input(f"{label}{hint}: ").strip()
|
||||||
|
if not value and default is not None:
|
||||||
|
value = default
|
||||||
|
if not value and not required:
|
||||||
|
return ""
|
||||||
|
if not value:
|
||||||
|
print("This field is required.")
|
||||||
|
continue
|
||||||
|
if validate and not validate(value):
|
||||||
|
print(error)
|
||||||
|
continue
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def init(args: argparse.Namespace) -> None:
|
||||||
|
try:
|
||||||
|
args.site.mkdir(parents=True, exist_ok=True)
|
||||||
|
except (FileExistsError, NotADirectoryError) as e:
|
||||||
|
raise CliError(f"{args.site} is not a directory") from e
|
||||||
|
if any(args.site.iterdir()):
|
||||||
|
raise CliError(f"{args.site} is not empty")
|
||||||
|
config_path = args.site / "config.yml"
|
||||||
|
|
||||||
|
name = prompt("Site name")
|
||||||
|
base_url = prompt(
|
||||||
|
"Base URL", "Optional, e.g. https://example.com/blog", required=False
|
||||||
|
)
|
||||||
|
template = prompt("Template", default="plain")
|
||||||
|
items_per_page = prompt(
|
||||||
|
"Items per page",
|
||||||
|
default=str(DEFAULT_ITEMS_PER_PAGE),
|
||||||
|
validate=lambda v: v.isdigit() and int(v) > 0,
|
||||||
|
error="Items per page must be a positive integer.",
|
||||||
|
)
|
||||||
|
|
||||||
|
config = SiteConfig.from_dict(
|
||||||
|
{
|
||||||
|
"name": name,
|
||||||
|
"base_url": base_url,
|
||||||
|
"template": template,
|
||||||
|
"items_per_page": int(items_per_page),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Site.resolve_template_path(config.template)
|
||||||
|
|
||||||
|
config.to_file(config_path)
|
||||||
|
(args.site / "content").mkdir(exist_ok=True)
|
||||||
|
log.info("Created new site at %s", args.site)
|
||||||
|
|
||||||
|
|
||||||
def cli() -> None:
|
def cli() -> None:
|
||||||
parser = setup_argparse()
|
parser = setup_argparse()
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
log_file = getattr(args, "log_file", args.site / "build.log")
|
default_log_file = None if args.command == "init" else args.site / "build.log"
|
||||||
|
log_file = getattr(args, "log_file", default_log_file)
|
||||||
setup_logging(verbose=bool(args.verbose), log_file=log_file)
|
setup_logging(verbose=bool(args.verbose), log_file=log_file)
|
||||||
if args.command == "build":
|
if args.command == "build":
|
||||||
build(args)
|
build(args)
|
||||||
elif args.command == "clean":
|
elif args.command == "clean":
|
||||||
clean(args)
|
clean(args)
|
||||||
|
elif args.command == "init":
|
||||||
|
init(args)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(f"'{args.command}' command not implemented yet")
|
raise NotImplementedError(f"'{args.command}' command not implemented yet")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import subprocess
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_creates_site(tmp_path):
|
||||||
|
site_dir = tmp_path / "newsite"
|
||||||
|
result = subprocess.run(
|
||||||
|
["ossg", "--site", str(site_dir), "init"],
|
||||||
|
input="My Site\nhttps://example.com\n\n\n",
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
assert result.returncode == 0, result.stderr
|
||||||
|
|
||||||
|
config = yaml.safe_load((site_dir / "config.yml").read_text())
|
||||||
|
assert config == {
|
||||||
|
"name": "My Site",
|
||||||
|
"base_url": "https://example.com/",
|
||||||
|
"template": "plain",
|
||||||
|
"items_per_page": 20,
|
||||||
|
}
|
||||||
|
assert (site_dir / "content").is_dir()
|
||||||
|
|
||||||
|
|
||||||
|
def test_init_refuses_non_empty_dir(tmp_path):
|
||||||
|
(tmp_path / "some_file").touch()
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
["ossg", "--site", str(tmp_path), "init"],
|
||||||
|
input="My Site\n\n\n\n",
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
assert result.returncode == 1
|
||||||
|
assert "is not empty" in result.stdout
|
||||||
Reference in new issue
Block a user