mirror of
https://github.com/NixOS/nix.dev.git
synced 2024-10-18 14:32:43 -04:00
82 lines
2.3 KiB
Python
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,
|
||
|
}
|