1
0
Fork 0
mirror of https://github.com/NixOS/nix.dev.git synced 2024-10-18 14:32:43 -04:00
nix.dev/source/_ext/extractable_code_block.py
Nejc Zupan 02ced7bbff Proof-of-Concept for testing code samples
There are a number of code samples throughout nix.dev. How do we know
they still work? We don't!

This commit introduces a way for us to extract these code samples into files
and then run tests against them in CI. This will hopefully help us catch
regressions in future updates to nix, NixOS and/or this guide.

Additionally, I included a darwin specific nix-shell configuration that I
use personally on my M1 Mac to work on this repo. Might be useful for someone.
2022-04-07 10:16:17 +01:00

82 lines
2.3 KiB
Python

from docutils import nodes
from docutils.nodes import Node
from docutils.parsers.rst import Directive
from docutils.parsers.rst import directives
from sphinx.directives import optional_int
from sphinx.directives.code import CodeBlock
from sphinx.util import logging
from sphinx.util.typing import OptionSpec
from typing import List
import os
import stat
logger = logging.getLogger(__name__)
class ExtractableCodeBlock(CodeBlock):
"""A custom directive to extract code blocks into files.
We want our code samples to be tested in CI. This class overrides the
default `code-block` to allow passing a second argument: the filename
to extract the code block to.
Out-of-the-box Sphinx behaviour:
```python
foo = "bar"
```
Additional extraction of a code block in `mydoc.md` file into
`./extracted/mydoc/foo.py` file:
```python foo.py
foo = "bar"
```
"""
EXTRACT_DIR = "extracted"
optional_arguments = 2
def run(self) -> List[Node]:
# This is out-of-the-box usage of code-blocks, with a single
# argument: the programming language
# Don't do any extraction
if len(self.arguments) < 2:
return super(ExtractableCodeBlock, self).run()
location = self.state_machine.get_source_and_line(self.lineno)
path = os.path.join(
# top-level dir containing extracted code blocks
self.EXTRACT_DIR,
# subdir containing extracted code blocks from a single .md file
os.path.splitext(os.path.basename(self.state.document.current_source))[0],
# file name of the extracted code block
self.arguments[1],
)
logger.info(
f"Extracting code block into {path}",
location=location,
)
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path, "w") as f:
f.write(self.block_text)
# make bash scripts executable
if path.endswith(".sh"):
st = os.stat(path)
os.chmod(path, st.st_mode | stat.S_IEXEC)
return super(ExtractableCodeBlock, self).run()
def setup(app):
app.add_directive("code-block", ExtractableCodeBlock, override=True)
return {
"version": "0.1",
"parallel_read_safe": True,
"parallel_write_safe": True,
}