Skip to content

Commit 6292486

Browse files
committed
fixes #1656
1 parent 36b891b commit 6292486

4 files changed

Lines changed: 25 additions & 10 deletions

File tree

‎nbdev/quarto.py‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from fastcore.meta import delegates
2424
from .serve import proc_nbs,_proc_file
2525
from . import serve_drv
26-
from .quarto_render import render_quarto
26+
from .quarto_render import render_quarto, quarto_stale
2727
import yaml
2828

2929
# %% ../nbs/api/14_quarto.ipynb #aae2d2be-ad03-4536-bf70-c4575f39cea3
@@ -392,7 +392,7 @@ def nbdev_preview(
392392
cache,cfg,path = _pre_docs(path, n_workers=n_workers, **kwargs)
393393
site = cache/cfg.doc_path.name
394394
if not (render or site.exists()) and cfg.doc_path.exists(): copytree(cfg.doc_path, site)
395-
if render or not site.exists(): render_quarto(cache, site, n_workers=n_workers)
395+
if render or not site.exists() or quarto_stale(cache, site): render_quarto(cache, site, n_workers=n_workers)
396396
xtra = []
397397
if port: xtra += ['--port', str(port)]
398398
if host: xtra += ['--host', host]

‎nbdev/quarto_render.py‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
"Parallel Quarto website rendering in isolated project copies."
22

33
import json, shutil, subprocess, tempfile
4-
from pathlib import Path
54
from xml.etree import ElementTree as ET
65
from fastcore.parallel import parallel
7-
from fastcore.utils import defaults
6+
from fastcore.utils import *
87

98

109
def _quarto(path, *args):
@@ -13,6 +12,17 @@ def _quarto(path, *args):
1312
return res.stdout
1413

1514

15+
def quarto_stale(path, output_dir):
16+
"Whether a page's HTML output is missing or older than its processed source."
17+
path, output_dir = Path(path).resolve(), Path(output_dir).resolve()
18+
info = loads(_quarto(path, 'inspect'))
19+
for name,entry in info['fileInformation'].items():
20+
p = Path(name)
21+
output = output_dir/p.parent/(entry['metadata'].get('output-file') or p.with_suffix('.html').name)
22+
if not output.exists() or (path/p).stat().st_mtime>output.stat().st_mtime: return True
23+
return False
24+
25+
1626
def _render_batch(job):
1727
path, inputs, output = job
1828
_quarto(path, 'render', *inputs, '--no-cache', '--no-clean', '--output-dir', output)

‎nbs/api/14_quarto.ipynb‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"from fastcore.meta import delegates\n",
5151
"from nbdev.serve import proc_nbs,_proc_file\n",
5252
"from nbdev import serve_drv\n",
53-
"from nbdev.quarto_render import render_quarto\n",
53+
"from nbdev.quarto_render import render_quarto, quarto_stale\n",
5454
"import yaml"
5555
]
5656
},
@@ -737,7 +737,7 @@
737737
"source": [
738738
"## Preview\n",
739739
"\n",
740-
"`nbdev-preview` keeps its own copy of the site in the `_proc` cache, rendering new or changed pages on startup and as you edit; it doesn't change `doc_path`. When the cache has no site it starts from a copy of the one in `doc_path`, so unchanged pages from the last `nbdev-docs` run aren't rendered again. With neither, it builds all pages in parallel using the same `--n-workers` setting as `nbdev-docs`. Use `nbdev-preview --render` to rebuild everything, including changes to shared configuration or filters."
740+
"`nbdev-preview` keeps its own copy of the site in the `_proc` cache, rendering new or changed pages on startup and as you edit; it doesn't change `doc_path`. When the cache has no site it starts from a copy of the one in `doc_path`, so unchanged pages from the last `nbdev-docs` run aren't rendered again. If any processed page has missing or older HTML output, it rebuilds the site in parallel using the same `--n-workers` setting as `nbdev-docs`, then starts Quarto's usual preview and input watching. Use `nbdev-preview --render` to rebuild everything, including changes to shared configuration or filters."
741741
]
742742
},
743743
{
@@ -787,7 +787,7 @@
787787
" cache,cfg,path = _pre_docs(path, n_workers=n_workers, **kwargs)\n",
788788
" site = cache/cfg.doc_path.name\n",
789789
" if not (render or site.exists()) and cfg.doc_path.exists(): copytree(cfg.doc_path, site)\n",
790-
" if render or not site.exists(): render_quarto(cache, site, n_workers=n_workers)\n",
790+
" if render or not site.exists() or quarto_stale(cache, site): render_quarto(cache, site, n_workers=n_workers)\n",
791791
" xtra = []\n",
792792
" if port: xtra += ['--port', str(port)]\n",
793793
" if host: xtra += ['--host', host]\n",

‎tests/test_quarto_render.py‎

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import json, shutil, subprocess, pytest
22
from xml.etree import ElementTree as ET
33
from fastcore.test import test_eq as teq
4-
from nbdev.quarto_render import render_quarto
4+
from nbdev.quarto_render import render_quarto, quarto_stale
55
from nbdev.quarto import nbdev_readme, refresh_quarto_yml
66
from nbdev.readme_filter import doc_link
77
from fastcore.nbio import new_nb, mk_cell, write_nb
@@ -65,14 +65,17 @@ def test_website(tmp_path):
6565
Page {name}. [Alpha](alpha.qmd#detail). [Download](data.txt).
6666
''')
6767
(root/'data.txt').write_text('shared resource')
68-
serial, parallel = tmp_path/'serial', tmp_path/'parallel'
68+
(root/'other.qmd').write_text('---\noutput-file: renamed.html\n---\n# Other')
69+
serial, parallel = tmp_path/'serial', root/'_site'
70+
assert quarto_stale(root, parallel)
6971
render_quarto(root, serial, n_workers=1)
7072
render_quarto(root, parallel, n_workers=2)
73+
assert not quarto_stale(root, parallel)
7174
search = lambda d: {e['href']: e['text'] for e in json.loads((d/'search.json').read_text())}
7275
urls = lambda d: {e.text for e in ET.parse(d/'sitemap.xml').findall('.//{*}loc')}
7376
teq(search(serial), search(parallel))
7477
teq(urls(serial), urls(parallel))
75-
teq(len(urls(parallel)), 3)
78+
teq(len(urls(parallel)), 4)
7679
for name in ('index', 'alpha', 'beta'):
7780
html = (parallel/f'{name}.html').read_text()
7881
assert 'alpha.html#detail' in html and 'data.txt' in html
@@ -81,7 +84,9 @@ def test_website(tmp_path):
8184
assert (parallel/'site_libs').is_dir()
8285
assert 'http-equiv="refresh"' not in (parallel/'index.html').read_text()
8386
(root/'beta.qmd').write_text('---\ntitle: beta\n---\n## Detail\n\nUpdated beta.')
87+
assert quarto_stale(root, parallel)
8488
subprocess.run(['quarto', 'render', 'beta.qmd', '--quiet', '--output-dir', str(parallel)], cwd=root, check=True)
89+
assert not quarto_stale(root, parallel)
8590
teq(set(search(serial)), set(search(parallel)))
8691
assert 'Updated beta.' in search(parallel)['beta.html#detail']
8792
(root/'beta.qmd').write_text('---\nfilters: [missing.lua]\n---\nBroken.')

0 commit comments

Comments
 (0)