Use pluggy for fetching mod version
This commit is contained in:
parent
6493f56b83
commit
1e64a589a9
10 changed files with 84 additions and 33 deletions
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
|
@ -16,7 +16,7 @@
|
||||||
"name": "Python: Generate Docs",
|
"name": "Python: Generate Docs",
|
||||||
"type": "python",
|
"type": "python",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"module": "hexdoc.hexdoc",
|
"module": "hexdoc.scripts.hexdoc",
|
||||||
"args": [
|
"args": [
|
||||||
"doc/properties.toml", "-o", "out", "--lang", "en_us",
|
"doc/properties.toml", "-o", "out", "--lang", "en_us",
|
||||||
],
|
],
|
||||||
|
|
7
doc/src/hexdoc/hexcasting/hooks.py
Normal file
7
doc/src/hexdoc/hexcasting/hooks.py
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
from hexdoc.__gradle_version__ import GRADLE_VERSION
|
||||||
|
from hexdoc.plugin import hookimpl
|
||||||
|
|
||||||
|
|
||||||
|
@hookimpl
|
||||||
|
def hexdoc_mod_version():
|
||||||
|
return GRADLE_VERSION
|
5
doc/src/hexdoc/plugin/__init__.py
Normal file
5
doc/src/hexdoc/plugin/__init__.py
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
__all__ = ["hookimpl"]
|
||||||
|
|
||||||
|
from pluggy import HookimplMarker
|
||||||
|
|
||||||
|
hookimpl = HookimplMarker("hexdoc")
|
10
doc/src/hexdoc/plugin/helpers.py
Normal file
10
doc/src/hexdoc/plugin/helpers.py
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
from pluggy import PluginManager
|
||||||
|
|
||||||
|
|
||||||
|
def name_hook_caller(pm: PluginManager, method_name: str, plugin_name: str):
|
||||||
|
return pm.subset_hook_caller(
|
||||||
|
name=method_name,
|
||||||
|
remove_plugins=(
|
||||||
|
plugin for name, plugin in pm.list_name_plugin() if name != plugin_name
|
||||||
|
),
|
||||||
|
)
|
8
doc/src/hexdoc/plugin/hookspecs.py
Normal file
8
doc/src/hexdoc/plugin/hookspecs.py
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
from pluggy import HookspecMarker
|
||||||
|
|
||||||
|
hookspec = HookspecMarker("hexdoc")
|
||||||
|
|
||||||
|
|
||||||
|
@hookspec(firstresult=True)
|
||||||
|
def hexdoc_mod_version():
|
||||||
|
"""Return the mod version (aka `GRADLE_VERSION`) from `__gradle_version__.py`."""
|
|
@ -6,6 +6,7 @@ import shutil
|
||||||
import sys
|
import sys
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from types import NoneType
|
||||||
from typing import Self, Sequence
|
from typing import Self, Sequence
|
||||||
|
|
||||||
from jinja2 import (
|
from jinja2 import (
|
||||||
|
@ -16,13 +17,16 @@ from jinja2 import (
|
||||||
Template,
|
Template,
|
||||||
)
|
)
|
||||||
from jinja2.sandbox import SandboxedEnvironment
|
from jinja2.sandbox import SandboxedEnvironment
|
||||||
|
from pluggy import PluginManager
|
||||||
from pydantic import model_validator
|
from pydantic import model_validator
|
||||||
|
|
||||||
from hexdoc.__gradle_version__ import GRADLE_VERSION
|
|
||||||
from hexdoc.hexcasting.hex_book import load_hex_book
|
from hexdoc.hexcasting.hex_book import load_hex_book
|
||||||
from hexdoc.minecraft import I18n
|
from hexdoc.minecraft import I18n
|
||||||
from hexdoc.patchouli import Book
|
from hexdoc.patchouli import Book
|
||||||
|
from hexdoc.plugin import hookspecs
|
||||||
|
from hexdoc.plugin.helpers import name_hook_caller
|
||||||
from hexdoc.utils import HexdocModel, ModResourceLoader, Properties
|
from hexdoc.utils import HexdocModel, ModResourceLoader, Properties
|
||||||
|
from hexdoc.utils.deserialize import cast_or_raise, isinstance_or_raise
|
||||||
from hexdoc.utils.jinja_extensions import IncludeRawExtension, hexdoc_block, hexdoc_wrap
|
from hexdoc.utils.jinja_extensions import IncludeRawExtension, hexdoc_block, hexdoc_wrap
|
||||||
from hexdoc.utils.path import write_to_path
|
from hexdoc.utils.path import write_to_path
|
||||||
|
|
||||||
|
@ -113,15 +117,15 @@ class SitemapMarker(HexdocModel):
|
||||||
|
|
||||||
|
|
||||||
def main(args: Args | None = None) -> None:
|
def main(args: Args | None = None) -> None:
|
||||||
|
# set stdout to utf-8 so printing to pipe or redirect doesn't break on Windows
|
||||||
|
# (common windows L)
|
||||||
|
cast_or_raise(sys.stdout, io.TextIOWrapper).reconfigure(encoding="utf-8")
|
||||||
|
cast_or_raise(sys.stderr, io.TextIOWrapper).reconfigure(encoding="utf-8")
|
||||||
|
|
||||||
# allow passing Args for test cases, but parse by default
|
# allow passing Args for test cases, but parse by default
|
||||||
if args is None:
|
if args is None:
|
||||||
args = Args.parse_args()
|
args = Args.parse_args()
|
||||||
|
|
||||||
# set stdout to utf-8 so printing to pipe or redirect doesn't break on Windows
|
|
||||||
# (common windows L)
|
|
||||||
assert isinstance(sys.stdout, io.TextIOWrapper)
|
|
||||||
sys.stdout.reconfigure(encoding="utf-8")
|
|
||||||
|
|
||||||
# set up logging
|
# set up logging
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
style="{",
|
style="{",
|
||||||
|
@ -130,18 +134,34 @@ def main(args: Args | None = None) -> None:
|
||||||
)
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Properties is the main config file for hexdoc
|
||||||
props = Properties.load(args.properties_file)
|
props = Properties.load(args.properties_file)
|
||||||
logger.debug(props)
|
logger.debug(props)
|
||||||
|
|
||||||
|
# load plugins
|
||||||
|
# load entry points for props.modid first to make sure its version is added last
|
||||||
|
pm = PluginManager("hexdoc")
|
||||||
|
pm.add_hookspecs(hookspecs)
|
||||||
|
pm.load_setuptools_entrypoints("hexdoc")
|
||||||
|
pm.check_pending()
|
||||||
|
|
||||||
|
# get the current mod version
|
||||||
|
version = name_hook_caller(pm, "hexdoc_mod_version", props.modid)()
|
||||||
|
assert isinstance_or_raise(version, (str, NoneType))
|
||||||
|
if version is None:
|
||||||
|
raise ValueError(f"Missing hexdoc_mod_version hookimpl for {props.modid}")
|
||||||
|
|
||||||
|
print(f"Building docs for {props.modid} {version}")
|
||||||
|
|
||||||
# just list the languages and exit
|
# just list the languages and exit
|
||||||
if args.list_langs:
|
if args.list_langs:
|
||||||
with ModResourceLoader.load_all(props, export=False) as loader:
|
with ModResourceLoader.load_all(props, version, export=False) as loader:
|
||||||
langs = sorted(I18n.list_all(loader))
|
langs = sorted(I18n.list_all(loader))
|
||||||
print(json.dumps(langs))
|
print(json.dumps(langs))
|
||||||
return
|
return
|
||||||
|
|
||||||
# load everything
|
# load everything
|
||||||
with ModResourceLoader.clean_and_load_all(props) as loader:
|
with ModResourceLoader.clean_and_load_all(props, version) as loader:
|
||||||
books = dict[str, Book]()
|
books = dict[str, Book]()
|
||||||
|
|
||||||
if args.lang:
|
if args.lang:
|
||||||
|
@ -181,7 +201,8 @@ def main(args: Args | None = None) -> None:
|
||||||
if args.export_only:
|
if args.export_only:
|
||||||
return
|
return
|
||||||
|
|
||||||
# set up Jinja environment
|
# set up Jinja
|
||||||
|
|
||||||
env = SandboxedEnvironment(
|
env = SandboxedEnvironment(
|
||||||
# search order: template_dirs, template_packages
|
# search order: template_dirs, template_packages
|
||||||
loader=ChoiceLoader(
|
loader=ChoiceLoader(
|
||||||
|
@ -204,6 +225,8 @@ def main(args: Args | None = None) -> None:
|
||||||
|
|
||||||
template = env.get_template(props.template.main)
|
template = env.get_template(props.template.main)
|
||||||
|
|
||||||
|
# render everything
|
||||||
|
|
||||||
assert (output_dir := args.output_dir)
|
assert (output_dir := args.output_dir)
|
||||||
if args.clean:
|
if args.clean:
|
||||||
shutil.rmtree(output_dir, ignore_errors=True)
|
shutil.rmtree(output_dir, ignore_errors=True)
|
||||||
|
@ -212,11 +235,11 @@ def main(args: Args | None = None) -> None:
|
||||||
render_books(props, books, template, output_dir, "latest")
|
render_books(props, books, template, output_dir, "latest")
|
||||||
|
|
||||||
if args.is_release:
|
if args.is_release:
|
||||||
render_books(props, books, template, output_dir, GRADLE_VERSION)
|
render_books(props, books, template, output_dir, version)
|
||||||
|
|
||||||
# the default book should be the latest released version
|
# the default book should be the latest released version
|
||||||
if args.update_latest and args.is_release:
|
if args.update_latest and args.is_release:
|
||||||
render_books(props, books, template, output_dir, GRADLE_VERSION, is_root=True)
|
render_books(props, books, template, output_dir, version, is_root=True)
|
||||||
|
|
||||||
|
|
||||||
def render_books(
|
def render_books(
|
||||||
|
|
|
@ -6,7 +6,6 @@ from typing import Self, Sequence
|
||||||
|
|
||||||
from pydantic import Field, TypeAdapter
|
from pydantic import Field, TypeAdapter
|
||||||
|
|
||||||
from hexdoc.__gradle_version__ import GRADLE_VERSION
|
|
||||||
from hexdoc.utils import DEFAULT_CONFIG, HexdocModel
|
from hexdoc.utils import DEFAULT_CONFIG, HexdocModel
|
||||||
from hexdoc.utils.path import write_to_path
|
from hexdoc.utils.path import write_to_path
|
||||||
|
|
||||||
|
@ -57,10 +56,11 @@ def main():
|
||||||
args = Args.parse_args()
|
args = Args.parse_args()
|
||||||
|
|
||||||
# ensure at least the default language was built successfully
|
# ensure at least the default language was built successfully
|
||||||
if args.is_release:
|
|
||||||
assert_version_exists(args.src, GRADLE_VERSION)
|
|
||||||
if args.update_latest:
|
if args.update_latest:
|
||||||
assert_version_exists(args.src, "latest")
|
assert_version_exists(args.src, "latest")
|
||||||
|
# TODO: figure out how to do this with pluggy
|
||||||
|
# if args.is_release:
|
||||||
|
# assert_version_exists(args.src, GRADLE_VERSION)
|
||||||
|
|
||||||
args.dst.mkdir(parents=True, exist_ok=True)
|
args.dst.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ from enum import Enum
|
||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
from typing import Any, Callable, Self
|
from typing import Any, Callable, Self
|
||||||
|
|
||||||
from hexdoc.__gradle_version__ import GRADLE_VERSION
|
from hexdoc.__gradle_version__ import GRADLE_VERSION as HEX_VERSION
|
||||||
|
|
||||||
|
|
||||||
@total_ordering
|
@total_ordering
|
||||||
|
@ -14,9 +14,9 @@ class HexVersion(Enum):
|
||||||
@classmethod
|
@classmethod
|
||||||
def get(cls):
|
def get(cls):
|
||||||
for version in cls:
|
for version in cls:
|
||||||
if GRADLE_VERSION.startswith(version.value):
|
if HEX_VERSION.startswith(version.value):
|
||||||
return version
|
return version
|
||||||
raise ValueError(f"Unknown mod version: {GRADLE_VERSION}")
|
raise ValueError(f"Unknown mod version: {HEX_VERSION}")
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def check(cls, version: Self | Callable[[Self], bool] | bool, typ: type[Any] | str):
|
def check(cls, version: Self | Callable[[Self], bool] | bool, typ: type[Any] | str):
|
||||||
|
@ -33,7 +33,7 @@ class HexVersion(Enum):
|
||||||
|
|
||||||
if not isinstance(typ, str):
|
if not isinstance(typ, str):
|
||||||
typ = typ.__name__
|
typ = typ.__name__
|
||||||
raise ValueError(f"{typ} is not supported in {GRADLE_VERSION}")
|
raise ValueError(f"{typ} is not supported in {HEX_VERSION}")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def _sort_by(self):
|
def _sort_by(self):
|
||||||
|
|
|
@ -9,7 +9,6 @@ from typing import Callable, Literal, Self, TypeVar, overload
|
||||||
|
|
||||||
from pydantic.dataclasses import dataclass
|
from pydantic.dataclasses import dataclass
|
||||||
|
|
||||||
from hexdoc.__gradle_version__ import GRADLE_VERSION
|
|
||||||
from hexdoc.utils.deserialize import JSONDict, decode_json_dict
|
from hexdoc.utils.deserialize import JSONDict, decode_json_dict
|
||||||
from hexdoc.utils.model import DEFAULT_CONFIG, HexdocModel, ValidationContext
|
from hexdoc.utils.model import DEFAULT_CONFIG, HexdocModel, ValidationContext
|
||||||
from hexdoc.utils.path import strip_suffixes, write_to_path
|
from hexdoc.utils.path import strip_suffixes, write_to_path
|
||||||
|
@ -45,19 +44,21 @@ class ModResourceLoader:
|
||||||
def clean_and_load_all(
|
def clean_and_load_all(
|
||||||
cls,
|
cls,
|
||||||
props: Properties,
|
props: Properties,
|
||||||
|
version: str,
|
||||||
*,
|
*,
|
||||||
export: bool = True,
|
export: bool = True,
|
||||||
):
|
):
|
||||||
# clear the export dir so we start with a clean slate
|
# clear the export dir so we start with a clean slate
|
||||||
if props.export_dir and export:
|
if props.export_dir and export:
|
||||||
subprocess.run(["git", "clean", "-fdX", props.export_dir])
|
subprocess.run(["git", "clean", "-fdX", props.export_dir])
|
||||||
return cls.load_all(props, export=export)
|
return cls.load_all(props, version, export=export)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def load_all(
|
def load_all(
|
||||||
cls,
|
cls,
|
||||||
props: Properties,
|
props: Properties,
|
||||||
|
version: str,
|
||||||
*,
|
*,
|
||||||
export: bool = True,
|
export: bool = True,
|
||||||
) -> Iterator[Self]:
|
) -> Iterator[Self]:
|
||||||
|
@ -78,7 +79,7 @@ class ModResourceLoader:
|
||||||
loader.export(
|
loader.export(
|
||||||
path=HexdocMetadata.path(props.modid),
|
path=HexdocMetadata.path(props.modid),
|
||||||
data=HexdocMetadata(
|
data=HexdocMetadata(
|
||||||
book_url=f"{props.url}/v/{GRADLE_VERSION}",
|
book_url=f"{props.url}/v/{version}",
|
||||||
).model_dump_json(),
|
).model_dump_json(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["hatchling"]
|
requires = ["hatchling", "hatch-gradle-version>=0.6.0"]
|
||||||
build-backend = "hatchling.build"
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
# project metadata
|
# project metadata
|
||||||
|
@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
||||||
name = "hexdoc"
|
name = "hexdoc"
|
||||||
dynamic = ["version"]
|
dynamic = ["version"]
|
||||||
authors = [
|
authors = [
|
||||||
{ name="object-Object", email="object@objectobject.ca" },
|
{ name="object-Object" },
|
||||||
{ name="Alwinfy" },
|
{ name="Alwinfy" },
|
||||||
]
|
]
|
||||||
readme = "doc/README.md"
|
readme = "doc/README.md"
|
||||||
|
@ -17,18 +17,15 @@ classifiers = [
|
||||||
]
|
]
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hexdoc[build]", # required optional dependency i guess
|
|
||||||
"typing_extensions>=4.6.1",
|
"typing_extensions>=4.6.1",
|
||||||
"importlib_resources>=6.0.1",
|
"importlib_resources>=6.0.1",
|
||||||
"pydantic>=2.3.0",
|
"pydantic>=2.3.0",
|
||||||
"Jinja2>=3.1.2",
|
"Jinja2>=3.1.2",
|
||||||
"pyjson5>=1.6.3",
|
"pyjson5>=1.6.3",
|
||||||
|
"pluggy>=1.3.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
build = [ # need these for build AND runtime
|
|
||||||
"hatch-gradle-version>=0.6.0",
|
|
||||||
]
|
|
||||||
dev = [
|
dev = [
|
||||||
"black==23.7.0",
|
"black==23.7.0",
|
||||||
"isort==5.12.0",
|
"isort==5.12.0",
|
||||||
|
@ -52,9 +49,6 @@ py-path = "doc/src/hexdoc/__version__.py"
|
||||||
# directory inclusion
|
# directory inclusion
|
||||||
|
|
||||||
[tool.hatch.build]
|
[tool.hatch.build]
|
||||||
require-runtime-features = [
|
|
||||||
"build",
|
|
||||||
]
|
|
||||||
artifacts = [
|
artifacts = [
|
||||||
"/doc/src/hexdoc/_export/generated",
|
"/doc/src/hexdoc/_export/generated",
|
||||||
"/doc/src/hexdoc/__gradle_version__.py",
|
"/doc/src/hexdoc/__gradle_version__.py",
|
||||||
|
@ -73,6 +67,9 @@ packages = [
|
||||||
|
|
||||||
# hexdoc entry points
|
# hexdoc entry points
|
||||||
|
|
||||||
|
[project.entry-points.hexdoc]
|
||||||
|
hexcasting = "hexdoc.hexcasting.hooks"
|
||||||
|
|
||||||
[project.entry-points."hexdoc.export"]
|
[project.entry-points."hexdoc.export"]
|
||||||
hexcasting = "hexdoc._export:__resources__"
|
hexcasting = "hexdoc._export:__resources__"
|
||||||
|
|
||||||
|
@ -110,8 +107,8 @@ known_first_party = ["hexdoc"]
|
||||||
pythonVersion = "3.11"
|
pythonVersion = "3.11"
|
||||||
pythonPlatform = "All"
|
pythonPlatform = "All"
|
||||||
|
|
||||||
include = [
|
extraPaths = [
|
||||||
"doc/src/hexdoc",
|
"doc/src",
|
||||||
]
|
]
|
||||||
|
|
||||||
# mostly we use strict mode
|
# mostly we use strict mode
|
||||||
|
|
Loading…
Reference in a new issue