Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for structurizr includes. #22

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion sphinxcontrib/kroki/kroki.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from hashlib import sha1
from pathlib import Path
from typing import Any, Dict, List, Optional, Union
from typing import Any, Dict, List, Optional, Tuple, Union, Callable

import requests
import yaml
Expand All @@ -14,6 +14,8 @@
from sphinx.util.docutils import SphinxDirective
from sphinx.util.i18n import search_image_for_language

from .util import process_structurizr_includes

formats = ("png", "svg", "jpeg", "base64", "txt", "utxt")

types = {
Expand Down Expand Up @@ -45,6 +47,13 @@
"wavedrom": "wavedrom",
}

Preprocessor = Callable[[str, Path], Tuple[str, List[Path]]]
"""A preprocessor takes a file's contents and its path and returns the preprocessed contents and a list of dependencies."""

preprocessors: Dict[str, Preprocessor] = {
"structurizr": process_structurizr_includes
}

extension_type_map = {
"bob": "svgbob",
"c4": "c4plantuml",
Expand Down Expand Up @@ -198,6 +207,23 @@ def run(self) -> List[Node]:
)
]

if diagram_type in preprocessors:
try:
(source, dependencies) = preprocessors[diagram_type](source, Path(filename))
source = source.strip()
for dependency in dependencies:
self.env.note_dependency(str(dependency.absolute()))

except FileNotFoundError as e:
return [
document.reporter.warning(
__(
"Kroki structurizr directive failed to process includes: %s"
) % e,
line=self.lineno,
)
]

if "format" in self.options:
if output_format is not None:
return [
Expand Down Expand Up @@ -273,6 +299,10 @@ def render_kroki(
f.write(chunk)

return outfn
except requests.exceptions.HTTPError as e:
raise KrokiError(
__("kroki did not produce a diagram, returned HTTP error: %s, reason: %s") % (e.response.status_code, e.response.reason)
) from e
except requests.exceptions.RequestException as e:
raise KrokiError(__("kroki did not produce a diagram")) from e
except IOError as e:
Expand Down
32 changes: 32 additions & 0 deletions sphinxcontrib/kroki/util.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,35 @@
import re
from pathlib import Path
from typing import Tuple, List

from sphinx.util import logging

logger = logging.getLogger(__name__)


def process_structurizr_includes(
contents: str, path: Path
) -> Tuple[str, List[Path]]:
"""Reads the input file and preprocesses any includes, returning the resulting file contents and dependencies."""
dependencies: List[Path] = []
lines = contents.split("\n")
for i, line in enumerate(lines):
match = re.match(r"^\s*!include\s+\"([^\"]+)\"\s*$", line)
if match:
include_path = path.parent / match.group(1)
if not include_path.exists():
raise FileNotFoundError(
f"Include file {include_path} not found, included from {include_path}:{i}"
)

dependencies.append(include_path)
with open(include_path, "r") as f:
include_contents = f.read()

(include_contents, new_dependencies) = (
process_structurizr_includes(include_contents, include_path)
)
lines[i] = include_contents
dependencies.extend(new_dependencies)

return ("\n".join(lines), dependencies)