sure let's push a bunch of totally untested code
This commit is contained in:
parent
6f5a00d00e
commit
2838ce95b0
13 changed files with 345 additions and 213 deletions
32
.github/actions/install-artifact-wheel/action.yml
vendored
Normal file
32
.github/actions/install-artifact-wheel/action.yml
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
name: Install wheel from artifact
|
||||
description: Install wheel from artifact
|
||||
|
||||
inputs:
|
||||
name:
|
||||
description: Artifact name.
|
||||
required: true
|
||||
python-version:
|
||||
description: Version range or exact version of Python to use.
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ inputs.python-version }}
|
||||
cache: pip
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.name }}
|
||||
path: _dist
|
||||
|
||||
- name: Install wheel
|
||||
shell: bash
|
||||
run: |
|
||||
wheels=( _dist/*-py3-none-any.whl )
|
||||
pip install "${wheels[0]}"
|
||||
rm -r _dist
|
235
.github/workflows/build_docs.yml
vendored
235
.github/workflows/build_docs.yml
vendored
|
@ -17,13 +17,14 @@ on:
|
|||
required: false
|
||||
|
||||
env:
|
||||
PYPI_PACKAGE: hexdoc
|
||||
HEXDOC: hexdoc doc/properties.toml --ci
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: "hexdoc"
|
||||
group: "docgen"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
|
@ -37,28 +38,34 @@ jobs:
|
|||
|
||||
outputs:
|
||||
matrix: ${{ steps.list-langs.outputs.matrix }}
|
||||
release: ${{ steps.check-release.outputs.release }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
cache: pip
|
||||
|
||||
- name: Install docgen
|
||||
- name: Install docgen from source
|
||||
run: pip install . hatch
|
||||
|
||||
- name: List languages
|
||||
- name: List book languages
|
||||
id: list-langs
|
||||
run: echo "matrix=$($HEXDOC --list-langs)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check if this is a release
|
||||
id: check-release
|
||||
run: |
|
||||
release=${{ github.event_name == 'workflow_dispatch' && inputs.publish == 'PyPI' || startsWith(github.ref, 'refs/tags') || startsWith(github.event.head_commit.message, '[Release]') }}
|
||||
echo "release=$release" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Export web book
|
||||
run: $HEXDOC --export-only
|
||||
run: $HEXDOC --export-only --release $release
|
||||
|
||||
- name: Bump version
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.segment
|
||||
run: hatch version ${{ inputs.segment }}
|
||||
run: hatch version "${{ inputs.segment }}"
|
||||
|
||||
- name: Commit changes
|
||||
uses: stefanzweifel/git-auto-commit-action@v4
|
||||
|
@ -66,19 +73,13 @@ jobs:
|
|||
commit_message: Build web book from ${{ github.ref }}
|
||||
|
||||
- name: Build docgen
|
||||
run: hatch build
|
||||
run: hatch build _site/dist
|
||||
|
||||
- name: Upload hexdoc artifact
|
||||
- name: Upload docgen artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: hexdoc-build
|
||||
path: dist/
|
||||
|
||||
- name: Copy build to Pages
|
||||
run: |
|
||||
mkdir -p _site/dist
|
||||
cp dist/*.whl _site/dist/latest.whl
|
||||
cp dist/*.tar.gz _site/dist/latest.tar.gz
|
||||
name: docgen-build
|
||||
path: _site/dist/
|
||||
|
||||
- name: Upload temporary Pages artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
|
@ -86,118 +87,22 @@ jobs:
|
|||
name: github-pages-tmp
|
||||
path: _site/
|
||||
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
continue-on-error: true
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lang: ${{ fromJson(needs.build.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Download hexdoc artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: hexdoc-build
|
||||
|
||||
- name: Install docgen
|
||||
run: pip install *.whl
|
||||
|
||||
- name: Build web book
|
||||
run: $HEXDOC --lang ${{ matrix.lang }} -o _site
|
||||
|
||||
- name: Upload temporary Pages artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: github-pages-tmp
|
||||
path: _site/
|
||||
|
||||
bundle-pages:
|
||||
runs-on: ubuntu-latest
|
||||
needs: generate
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Download hexdoc artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: hexdoc-build
|
||||
|
||||
- name: Install docgen
|
||||
run: pip install *.whl
|
||||
|
||||
- name: Download temporary Pages artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: github-pages-tmp
|
||||
path: _site/
|
||||
|
||||
- name: Check default lang
|
||||
run: $HEXDOC --check-default-lang _site
|
||||
|
||||
- name: Fix permissions
|
||||
run: |
|
||||
chmod -c -R +rX "_site/" | while read line; do
|
||||
echo "::warning title=Invalid file permissions automatically fixed::$line"
|
||||
done
|
||||
|
||||
- name: Upload Pages artifact
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
|
||||
deploy-pages:
|
||||
runs-on: ubuntu-latest
|
||||
needs: bundle-pages
|
||||
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
permissions:
|
||||
id-token: write
|
||||
pages: write
|
||||
|
||||
steps:
|
||||
- name: Deploy to Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
with:
|
||||
timeout: 300000 # 5 minutes
|
||||
|
||||
publish-pypi:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: |-
|
||||
github.event_name == 'workflow_dispatch' && inputs.publish == 'PyPI' ||
|
||||
startsWith(github.ref, 'refs/tags') ||
|
||||
startsWith(github.event.head_commit.message, '[Release]')
|
||||
if: needs.build.outputs.release == true
|
||||
|
||||
environment:
|
||||
name: pypi
|
||||
url: https://pypi.org/p/hexdoc
|
||||
|
||||
url: https://pypi.org/p/${{ env.PYPI_PACKAGE }}
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Download hexdoc artifact
|
||||
- name: Download docgen artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: hexdoc-build
|
||||
name: docgen-build
|
||||
path: dist
|
||||
|
||||
- name: Publish to PyPI
|
||||
|
@ -210,19 +115,105 @@ jobs:
|
|||
|
||||
environment:
|
||||
name: testpypi
|
||||
url: https://test.pypi.org/p/hexdoc
|
||||
|
||||
url: https://test.pypi.org/p/${{ env.PYPI_PACKAGE }}
|
||||
permissions:
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Download hexdoc artifact
|
||||
- name: Download docgen artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: hexdoc-build
|
||||
name: docgen-build
|
||||
path: dist
|
||||
|
||||
- name: Publish to TestPyPI
|
||||
uses: pypa/gh-action-pypi-publish@release/v1
|
||||
with:
|
||||
repository-url: https://test.pypi.org/legacy/
|
||||
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
continue-on-error: true
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
lang: ${{ fromJson(needs.build.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/install-artifact-wheel
|
||||
with:
|
||||
name: docgen-build
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Build web book
|
||||
run: $HEXDOC --lang "${{ matrix.lang }}" -o _site --release "${{ needs.build.outputs.release }}"
|
||||
|
||||
- name: Upload temporary Pages artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: github-pages-tmp
|
||||
path: _site/
|
||||
|
||||
bundle-pages:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build, generate, publish-pypi]
|
||||
|
||||
# allow publish-pypi to be skipped, but run after it
|
||||
if: always() && !cancelled() && !failure() && needs.generate.result == 'success'
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: ./.github/actions/install-artifact-wheel
|
||||
with:
|
||||
name: docgen-build
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Checkout current Pages
|
||||
uses: actions/checkout@v3
|
||||
continue-on-error: true
|
||||
with:
|
||||
ref: gh-pages
|
||||
path: _site/
|
||||
|
||||
- name: Download temporary Pages artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: github-pages-tmp
|
||||
path: _new_site/
|
||||
|
||||
- name: Add new docs to site
|
||||
run: hexdoc_merge --source _new_site --dest _site --release "${{ needs.build.outputs.release == true }}"
|
||||
|
||||
- name: Fix permissions
|
||||
run: |
|
||||
chmod -c -R +rX "_site/" | while read line; do
|
||||
echo "::warning title=Invalid file permissions automatically fixed::$line"
|
||||
done
|
||||
|
||||
- name: Upload Pages artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: github-pages
|
||||
path: _site/
|
||||
|
||||
deploy-pages:
|
||||
runs-on: ubuntu-latest
|
||||
needs: bundle-pages
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Download Pages artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: github-pages
|
||||
path: _site/
|
||||
|
||||
- name: Deploy to Pages
|
||||
uses: JamesIves/github-pages-deploy-action@v4
|
||||
with:
|
||||
folder: _site
|
||||
|
|
|
@ -44,7 +44,6 @@ mod_name = "Hex Casting"
|
|||
author = "petrak@, Alwinfy"
|
||||
description = "The Hex Book, all in one place."
|
||||
icon_href = "logo.png"
|
||||
is_bleeding_edge = true
|
||||
show_landing_text = true
|
||||
|
||||
|
||||
|
|
|
@ -1 +1,10 @@
|
|||
__version__ = "1.0.dev1"
|
||||
# This file is auto-generated by hatch-gradle-version.
|
||||
# Only the value of PY_VERSION is editable.
|
||||
# All changes to other values will be ignored and overwritten.
|
||||
|
||||
PY_VERSION = "1.0.dev0"
|
||||
|
||||
# Everything below this line is completely auto-generated.
|
||||
|
||||
GRADLE_VERSION = "0.11.1-7"
|
||||
FULL_VERSION = "0.11.1.1.0rc7.dev0"
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<link rel="icon" href="{{ props.url }}/{{ icon_href }}">
|
||||
<link rel="icon" href="{{ icon_href }}">
|
||||
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
@ -11,8 +11,8 @@
|
|||
|
||||
<meta property="og:type" content="website" />
|
||||
<meta property="og:title" content="{{ title }}" />
|
||||
<meta property="og:image" content="{{ props.url }}/{{ icon_href }}" />
|
||||
<meta property="og:url" content="{{ props.url }}" />
|
||||
<meta property="og:image" content="{{ url }}/{{ icon_href }}" />
|
||||
<meta property="og:url" content="{{ url }}" />
|
||||
<meta property="og:description" content="{{ description }}" />
|
||||
<meta property="og:site_name" content="{{ mod_name }}" />
|
||||
|
||||
|
|
|
@ -14,15 +14,17 @@ from jinja2.sandbox import SandboxedEnvironment
|
|||
from pydantic import field_validator, model_validator
|
||||
|
||||
from hexdoc.hexcasting.hex_book import load_hex_book
|
||||
from hexdoc.minecraft.i18n import I18n
|
||||
from hexdoc.patchouli.book import Book
|
||||
from hexdoc.utils import Properties
|
||||
from hexdoc.minecraft import I18n
|
||||
from hexdoc.patchouli import Book
|
||||
from hexdoc.utils import HexdocModel, ModResourceLoader, Properties
|
||||
from hexdoc.utils.cd import cd
|
||||
from hexdoc.utils.model import HexdocModel
|
||||
from hexdoc.utils.resource_loader import ModResourceLoader
|
||||
from hexdoc.utils.path import write_to_path
|
||||
|
||||
from .__version__ import GRADLE_VERSION
|
||||
from .jinja_extensions import IncludeRawExtension, hexdoc_block, hexdoc_wrap
|
||||
|
||||
MARKER_NAME = ".hexdoc-meta-sitemap-marker.json"
|
||||
|
||||
|
||||
def strip_empty_lines(text: str) -> str:
|
||||
return "\n".join(s for s in text.splitlines() if s.strip())
|
||||
|
@ -38,11 +40,11 @@ class Args(HexdocModel):
|
|||
ci: bool
|
||||
allow_missing: bool
|
||||
lang: str | None
|
||||
release: bool
|
||||
|
||||
output_dir: Path | None
|
||||
export_only: bool
|
||||
list_langs: bool
|
||||
check_default_lang: Path | None
|
||||
|
||||
@classmethod
|
||||
def parse_args(cls, args: Sequence[str] | None = None) -> Self:
|
||||
|
@ -54,10 +56,10 @@ class Args(HexdocModel):
|
|||
parser.add_argument("--ci", action="store_true")
|
||||
parser.add_argument("--allow-missing", action="store_true")
|
||||
parser.add_argument("--lang", type=str, default=None)
|
||||
parser.add_argument("--release", default=False)
|
||||
|
||||
group = parser.add_mutually_exclusive_group(required=True)
|
||||
group.add_argument("--output_dir", "-o", type=Path)
|
||||
group.add_argument("--check-default-lang", type=Path)
|
||||
group.add_argument("--output-dir", "-o", type=Path)
|
||||
group.add_argument("--export-only", action="store_true")
|
||||
group.add_argument("--list-langs", action="store_true")
|
||||
|
||||
|
@ -66,7 +68,6 @@ class Args(HexdocModel):
|
|||
@field_validator(
|
||||
"properties_file",
|
||||
"output_dir",
|
||||
"check_default_lang",
|
||||
mode="after",
|
||||
)
|
||||
def _resolve_path(cls, value: Path | None):
|
||||
|
@ -83,13 +84,7 @@ class Args(HexdocModel):
|
|||
self.verbose = True
|
||||
|
||||
# exactly one of these must be truthy (should be enforced by group above)
|
||||
assert (
|
||||
bool(self.output_dir)
|
||||
+ self.export_only
|
||||
+ self.list_langs
|
||||
+ bool(self.check_default_lang)
|
||||
== 1
|
||||
)
|
||||
assert bool(self.output_dir) + self.export_only + self.list_langs == 1
|
||||
|
||||
return self
|
||||
|
||||
|
@ -104,6 +99,12 @@ class Args(HexdocModel):
|
|||
return logging.DEBUG
|
||||
|
||||
|
||||
class SitemapMarker(HexdocModel):
|
||||
version: str
|
||||
lang: str
|
||||
path: str
|
||||
|
||||
|
||||
def main(args: Args | None = None) -> None:
|
||||
# allow passing Args for test cases, but parse by default
|
||||
if args is None:
|
||||
|
@ -122,19 +123,10 @@ def main(args: Args | None = None) -> None:
|
|||
format="\033[1m[{relativeCreated:.02f} | {levelname} | {name}]\033[0m {message}",
|
||||
level=args.log_level,
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
props = Properties.load(args.properties_file)
|
||||
|
||||
if args.check_default_lang:
|
||||
dir_path = args.check_default_lang
|
||||
for path in [
|
||||
dir_path / "index.html",
|
||||
dir_path / props.default_lang / "index.html",
|
||||
]:
|
||||
if not path.is_file():
|
||||
raise FileNotFoundError(path)
|
||||
return
|
||||
|
||||
# just list the languages and exit
|
||||
if args.list_langs:
|
||||
with ModResourceLoader.load_all(props, export=False) as loader:
|
||||
|
@ -210,30 +202,54 @@ def main(args: Args | None = None) -> None:
|
|||
|
||||
template = env.get_template(props.template.main)
|
||||
|
||||
# set up the output directory
|
||||
subprocess.run(["git", "clean", "-fdX", args.output_dir])
|
||||
args.output_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
static_dir = props.template.static_dir
|
||||
if static_dir and static_dir.is_dir():
|
||||
shutil.copytree(static_dir, args.output_dir, dirs_exist_ok=True)
|
||||
subprocess.run(["git", "clean", "-fdX", args.output_dir])
|
||||
|
||||
# render each language separately
|
||||
for lang, book in books.items():
|
||||
docs = strip_empty_lines(
|
||||
template.render(
|
||||
**props.template.args,
|
||||
book=book,
|
||||
props=props,
|
||||
versions = ["latest"]
|
||||
if args.release:
|
||||
# root should be the latest released version
|
||||
versions += ["", GRADLE_VERSION]
|
||||
|
||||
# render each version and language separately
|
||||
for version in versions:
|
||||
for lang, book in books.items():
|
||||
# /index.html
|
||||
# /lang/index.html
|
||||
# /v/version/index.html
|
||||
# /v/version/lang/index.html
|
||||
parts = ["v", version] if version else []
|
||||
if lang != props.default_lang:
|
||||
parts.append(lang)
|
||||
|
||||
output_dir = args.output_dir / Path(*parts)
|
||||
url = "/".join([props.url] + parts)
|
||||
|
||||
logger.info(f"Rendering {output_dir}")
|
||||
docs = strip_empty_lines(
|
||||
template.render(
|
||||
**props.template.args,
|
||||
book=book,
|
||||
props=props,
|
||||
url=url,
|
||||
is_bleeding_edge=version != "latest",
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
lang_output_dir = args.output_dir / lang
|
||||
lang_output_dir.mkdir(parents=True, exist_ok=True)
|
||||
(lang_output_dir / "index.html").write_text(docs, "utf-8")
|
||||
write_to_path(output_dir / "index.html", docs)
|
||||
if static_dir:
|
||||
shutil.copytree(static_dir, output_dir, dirs_exist_ok=True)
|
||||
|
||||
if lang == props.default_lang:
|
||||
(args.output_dir / "index.html").write_text(docs, "utf-8")
|
||||
# marker file for updating the sitemap later
|
||||
# we use this because matrix doesn't have outputs
|
||||
# this feels scuffed but it does work
|
||||
if version:
|
||||
(output_dir / MARKER_NAME).write_text(
|
||||
SitemapMarker(
|
||||
version=version,
|
||||
lang=lang,
|
||||
path="/" + "/".join(parts),
|
||||
).model_dump_json()
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
71
doc/src/hexdoc/hexdoc_merge.py
Normal file
71
doc/src/hexdoc/hexdoc_merge.py
Normal file
|
@ -0,0 +1,71 @@
|
|||
import json
|
||||
import shutil
|
||||
from argparse import ArgumentParser
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
from typing import Self, Sequence
|
||||
|
||||
from hexdoc.hexdoc import MARKER_NAME, SitemapMarker
|
||||
from hexdoc.utils import HexdocModel
|
||||
from hexdoc.utils.path import write_to_path
|
||||
|
||||
|
||||
def strip_empty_lines(text: str) -> str:
|
||||
return "\n".join(s for s in text.splitlines() if s.strip())
|
||||
|
||||
|
||||
# CLI arguments
|
||||
class Args(HexdocModel):
|
||||
"""example: main.py properties.toml -o out.html"""
|
||||
|
||||
source: Path
|
||||
dest: Path
|
||||
release: bool
|
||||
|
||||
@classmethod
|
||||
def parse_args(cls, args: Sequence[str] | None = None) -> Self:
|
||||
parser = ArgumentParser(allow_abbrev=False)
|
||||
|
||||
parser.add_argument("--source", type=Path, required=True)
|
||||
parser.add_argument("--dest", type=Path, required=True)
|
||||
parser.add_argument("--release", default=False)
|
||||
|
||||
return cls.model_validate(vars(parser.parse_args(args)))
|
||||
|
||||
|
||||
def main():
|
||||
args = Args.parse_args()
|
||||
|
||||
if not (args.source / "latest" / "index.html").is_file():
|
||||
raise FileNotFoundError(args.source / "index.html")
|
||||
|
||||
args.dest.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
if args.release:
|
||||
# remove current latest-released book in the destination
|
||||
for path in args.dest.iterdir():
|
||||
if path.name not in ["v", "meta"]:
|
||||
shutil.rmtree(path)
|
||||
|
||||
new_sitemap = defaultdict[str, dict[str, str]]()
|
||||
for marker_path in args.source.rglob(MARKER_NAME):
|
||||
# add new(?) version to the sitemap
|
||||
marker = SitemapMarker.model_validate_json(marker_path.read_text("utf-8"))
|
||||
new_sitemap[marker.version][marker.lang] = marker.path
|
||||
|
||||
# delete the corresponding directory in the destination
|
||||
shutil.rmtree(args.dest / marker_path.relative_to(args.source))
|
||||
|
||||
sitemap_path = args.dest / "meta" / "sitemap.json"
|
||||
|
||||
if sitemap_path.is_file():
|
||||
sitemap = json.loads(sitemap_path.read_text("utf-8")) | new_sitemap
|
||||
else:
|
||||
sitemap = new_sitemap
|
||||
|
||||
shutil.copytree(args.source, args.dest, dirs_exist_ok=True)
|
||||
write_to_path(sitemap_path, json.dumps(sitemap))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -16,8 +16,8 @@ from hexdoc.utils.deserialize import (
|
|||
decode_and_flatten_json_dict,
|
||||
isinstance_or_raise,
|
||||
)
|
||||
from hexdoc.utils.path import replace_suffixes
|
||||
from hexdoc.utils.resource_loader import LoaderContext
|
||||
from hexdoc.utils.types import replace_suffixes
|
||||
|
||||
|
||||
@total_ordering
|
||||
|
|
40
doc/src/hexdoc/utils/path.py
Normal file
40
doc/src/hexdoc/utils/path.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
from pathlib import Path
|
||||
|
||||
|
||||
def strip_suffixes(path: Path) -> Path:
|
||||
"""Removes all suffixes from a path. This is helpful because `path.with_suffix("")`
|
||||
only removes the last suffix.
|
||||
|
||||
For example:
|
||||
```py
|
||||
path = Path("lang/en_us.flatten.json5")
|
||||
strip_suffixes(path) # lang/en_us
|
||||
path.with_suffix("") # lang/en_us.flatten
|
||||
```
|
||||
"""
|
||||
while path.suffix:
|
||||
path = path.with_suffix("")
|
||||
return path
|
||||
|
||||
|
||||
def replace_suffixes(path: Path, suffix: str) -> Path:
|
||||
"""Replaces all suffixes of a path. This is helpful because `path.with_suffix()`
|
||||
only replaces the last suffix.
|
||||
|
||||
For example:
|
||||
```py
|
||||
path = Path("lang/en_us.flatten.json5")
|
||||
replace_suffixes(path, ".json") # lang/en_us.json
|
||||
path.with_suffix(".json") # lang/en_us.flatten.json
|
||||
```
|
||||
"""
|
||||
return strip_suffixes(path).with_suffix(suffix)
|
||||
|
||||
|
||||
def write_to_path(path: Path, data: str | bytes, encoding: str = "utf-8"):
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
match data:
|
||||
case str():
|
||||
path.write_text(data, encoding)
|
||||
case bytes():
|
||||
path.write_bytes(data)
|
|
@ -9,9 +9,10 @@ from typing import Callable, Literal, Self, TypeVar, overload
|
|||
|
||||
from pydantic.dataclasses import dataclass
|
||||
|
||||
from hexdoc.__version__ import GRADLE_VERSION
|
||||
from hexdoc.utils.deserialize import decode_json_dict
|
||||
from hexdoc.utils.model import DEFAULT_CONFIG, HexdocModel, ValidationContext
|
||||
from hexdoc.utils.types import strip_suffixes
|
||||
from hexdoc.utils.path import strip_suffixes, write_to_path
|
||||
|
||||
from .properties import Properties
|
||||
from .resource import PathResourceDir, ResourceLocation, ResourceType
|
||||
|
@ -77,7 +78,7 @@ class ModResourceLoader:
|
|||
loader.export(
|
||||
path=HexdocMetadata.path(props.modid),
|
||||
data=HexdocMetadata(
|
||||
book_url=props.url,
|
||||
book_url=f"{props.url}/v/{GRADLE_VERSION}",
|
||||
).model_dump_json(),
|
||||
)
|
||||
|
||||
|
@ -364,8 +365,7 @@ class ModResourceLoader:
|
|||
case (str(out_data), Path() as out_path):
|
||||
pass
|
||||
|
||||
out_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
out_path.write_text(out_data, "utf-8")
|
||||
write_to_path(out_path, out_data)
|
||||
|
||||
|
||||
class LoaderContext(ValidationContext):
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import string
|
||||
from abc import ABC, abstractmethod
|
||||
from enum import Enum, unique
|
||||
from pathlib import Path
|
||||
from typing import Any, Mapping, Protocol, TypeVar
|
||||
|
||||
from pydantic import field_validator, model_validator
|
||||
|
@ -101,33 +100,3 @@ class TryGetEnum(Enum):
|
|||
return cls(value)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def strip_suffixes(path: Path) -> Path:
|
||||
"""Removes all suffixes from a path. This is helpful because `path.with_suffix("")`
|
||||
only removes the last suffix.
|
||||
|
||||
For example:
|
||||
```py
|
||||
path = Path("lang/en_us.flatten.json5")
|
||||
strip_suffixes(path) # lang/en_us
|
||||
path.with_suffix("") # lang/en_us.flatten
|
||||
```
|
||||
"""
|
||||
while path.suffix:
|
||||
path = path.with_suffix("")
|
||||
return path
|
||||
|
||||
|
||||
def replace_suffixes(path: Path, suffix: str) -> Path:
|
||||
"""Replaces all suffixes of a path. This is helpful because `path.with_suffix()`
|
||||
only replaces the last suffix.
|
||||
|
||||
For example:
|
||||
```py
|
||||
path = Path("lang/en_us.flatten.json5")
|
||||
replace_suffixes(path, ".json") # lang/en_us.json
|
||||
path.with_suffix(".json") # lang/en_us.flatten.json
|
||||
```
|
||||
"""
|
||||
return strip_suffixes(path).with_suffix(suffix)
|
||||
|
|
|
@ -11,17 +11,21 @@ PROPS = "doc/properties.toml"
|
|||
|
||||
def test_file(tmp_path: Path, snapshot: SnapshotAssertion):
|
||||
# generate output docs html file and assert it hasn't changed vs. the snapshot
|
||||
out_path = tmp_path / "out.html"
|
||||
main(Args.parse_args([PROPS, "-o", out_path.as_posix()]))
|
||||
main(
|
||||
Args.parse_args(
|
||||
[PROPS, "--lang", "en_us", "--release", "-o", tmp_path.as_posix()]
|
||||
)
|
||||
)
|
||||
out_path = tmp_path / "index.html"
|
||||
assert out_path.read_text("utf-8") == snapshot
|
||||
|
||||
|
||||
def test_cmd(tmp_path: Path, snapshot: SnapshotAssertion):
|
||||
# as above, but running the command we actually want to be using
|
||||
out_path = tmp_path / "out.html"
|
||||
subprocess.run(
|
||||
["hexdoc", PROPS, "-o", out_path.as_posix()],
|
||||
["hexdoc", PROPS, "--lang", "en_us", "--release", "-o", tmp_path.as_posix()],
|
||||
stdout=sys.stdout,
|
||||
stderr=sys.stderr,
|
||||
)
|
||||
out_path = tmp_path / "index.html"
|
||||
assert out_path.read_text("utf-8") == snapshot
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
[build-system]
|
||||
requires = ["hatchling", "hatch-gradle-version>=0.3.0"]
|
||||
requires = ["hatchling", "hatch-gradle-version>=0.4.0"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
# project metadata
|
||||
|
@ -34,6 +34,7 @@ dev = [
|
|||
|
||||
[project.scripts]
|
||||
hexdoc = "hexdoc.hexdoc:main"
|
||||
hexdoc_merge = "hexdoc.hexdoc_merge:main"
|
||||
|
||||
# Gradle version/deps
|
||||
|
||||
|
|
Loading…
Reference in a new issue