Skip to content

Commit a8ed1d4

Browse files
committed
Add ability to revive rendered outputs if present
This reduces preview overhead as rendered notebook outputs will be preserved. Full renders still render all since the output directory is cleared.
1 parent 9eb2c74 commit a8ed1d4

File tree

8 files changed

+92
-8
lines changed

8 files changed

+92
-8
lines changed

src/format/html/format-html-notebook-preview.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export const notebookPreviewer = (
9393
const notebookPaths = previewQueue.map((work) => (work.nbPath));
9494
const uniquePaths = ld.uniq(notebookPaths);
9595
const toRenderPaths = uniquePaths.filter((nbPath) => {
96-
return services.notebook.get(nbPath) === undefined;
96+
return services.notebook.get(nbPath, project) === undefined;
9797
});
9898
const haveRenderedPaths: string[] = [];
9999
if (toRenderPaths.length > 0 && !quiet) {
@@ -126,7 +126,7 @@ export const notebookPreviewer = (
126126
nbDescriptors[relative(dirname(input), nbPath)];
127127
const nbAbsPath = isAbsolute(nbPath) ? nbPath : join(inputDir, nbPath);
128128
const nbContext = services.notebook;
129-
const notebook = nbContext.get(nbAbsPath);
129+
const notebook = nbContext.get(nbAbsPath, project);
130130

131131
const resolvedTitle = descriptor?.title || title || basename(nbAbsPath);
132132

@@ -185,7 +185,7 @@ export const notebookPreviewer = (
185185
}
186186
}
187187

188-
const renderedNotebook = nbContext.get(nbAbsPath);
188+
const renderedNotebook = nbContext.get(nbAbsPath, project);
189189
if (!renderedNotebook || !renderedNotebook[kHtmlPreview].output) {
190190
throw new InternalError(
191191
"We just ensured that notebooks had rendered previews, but the preview then didn't exist.",

src/format/jats/format-jats-postprocess.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export const renderSubarticlePostProcessor = (
3535
// for each of our articles. If needed, render any that
3636
// aren't already rendered.
3737
const subArticlesToRender = subArticles.filter((subArticle) => {
38-
return services.notebook.get(subArticle.input) === undefined;
38+
return services.notebook.get(subArticle.input, project) === undefined;
3939
});
4040
const total = subArticlesToRender.length;
4141
if (subArticlesToRender.length > 0 && !quiet) {

src/project/types/manuscript/manuscript-render.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ export const manuscriptRenderer = (
101101
const result = [];
102102

103103
// Use the executed file to render the output ipynb
104-
const notebook = nbContext.get(input);
104+
const notebook = nbContext.get(input, context);
105105
let downloadHref;
106106
if (!notebook || !notebook[kRenderedIPynb]) {
107107
progressMessage("Rendering output notebook");

src/render/notebook/notebook-context.ts

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@ import { jatsContributor } from "./notebook-contributor-jats.ts";
2424
import { htmlNotebookContributor } from "./notebook-contributor-html.ts";
2525
import { outputNotebookContributor } from "./notebook-contributor-ipynb.ts";
2626
import { Format } from "../../config/types.ts";
27-
import { safeRemoveIfExists } from "../../core/path.ts";
27+
import { safeExistsSync, safeRemoveIfExists } from "../../core/path.ts";
28+
import { relative } from "path/mod.ts";
29+
import { projectOutputDir } from "../../project/project-shared.ts";
2830

2931
const contributors: Record<RenderType, NotebookContributor | undefined> = {
3032
[kJatsSubarticle]: jatsContributor,
@@ -50,6 +52,7 @@ export function notebookContext(): NotebookContext {
5052
};
5153
};
5254

55+
// Adds a rendering of a notebook to the notebook context
5356
const addRendering = (
5457
nbAbsPath: string,
5558
renderType: RenderType,
@@ -66,6 +69,11 @@ export function notebookContext(): NotebookContext {
6669
nb[renderType].output = output;
6770
notebooks[nbAbsPath] = nb;
6871
};
72+
73+
// Removes a rendering of a notebook from the notebook context
74+
// which includes cleaning up the files. This should only be
75+
// used when the caller knows other callers will not need the
76+
// notebook.
6977
const removeRendering = (
7078
nbAbsPath: string,
7179
renderType: RenderType,
@@ -97,6 +105,7 @@ export function notebookContext(): NotebookContext {
97105
}
98106
};
99107

108+
// Get a contribute for a render type
100109
function contributor(renderType: RenderType) {
101110
const contributor = contributors[renderType];
102111
if (contributor) {
@@ -108,6 +117,7 @@ export function notebookContext(): NotebookContext {
108117
}
109118
}
110119

120+
// Add metadata to a given notebook rendering
111121
function addMetadata(
112122
nbAbsPath: string,
113123
renderType: RenderType,
@@ -120,8 +130,60 @@ export function notebookContext(): NotebookContext {
120130
notebooks[nbAbsPath] = nb;
121131
}
122132

133+
function reviveOutput(
134+
nbAbsPath: string,
135+
renderType: RenderType,
136+
nbOutputDir: string,
137+
) {
138+
const contrib = contributor(renderType);
139+
const outFile = contrib.outputFile(nbAbsPath);
140+
const outPath = join(nbOutputDir, outFile);
141+
if (safeExistsSync(outPath)) {
142+
const inputTime = Deno.statSync(nbAbsPath).mtime?.valueOf() || 0;
143+
const outputTime = Deno.statSync(outPath).mtime?.valueOf() || 0;
144+
if (inputTime <= outputTime) {
145+
addRendering(nbAbsPath, renderType, {
146+
file: outPath,
147+
supporting: [],
148+
resourceFiles: {
149+
globs: [],
150+
files: [],
151+
},
152+
});
153+
}
154+
}
155+
}
156+
123157
return {
124-
get: (nbAbsPath: string) => {
158+
get: (nbAbsPath: string, context?: ProjectContext) => {
159+
const notebook = notebooks[nbAbsPath];
160+
const reviveRenders: RenderType[] = [];
161+
if (notebook) {
162+
// We already have a notebook, try to complete its renderings
163+
// by reviving any outputs that are valid
164+
[kJatsSubarticle, kHtmlPreview, kRenderedIPynb].forEach(
165+
(renderTypeStr) => {
166+
const renderType = renderTypeStr as RenderType;
167+
if (!notebook[renderType].output) {
168+
reviveRenders.push(renderType);
169+
}
170+
},
171+
);
172+
} else {
173+
reviveRenders.push(kHtmlPreview);
174+
reviveRenders.push(kJatsSubarticle);
175+
reviveRenders.push(kRenderedIPynb);
176+
}
177+
178+
if (context) {
179+
const nbRelative = relative(context.dir, dirname(nbAbsPath));
180+
const nbOutputDir = join(projectOutputDir(context), nbRelative);
181+
182+
// See if an up to date rendered result exists for each contributor
183+
for (const renderType of reviveRenders) {
184+
reviveOutput(nbAbsPath, renderType, nbOutputDir);
185+
}
186+
}
125187
return notebooks[nbAbsPath];
126188
},
127189
resolve: (

src/render/notebook/notebook-contributor-html.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,15 @@ import { Format } from "../../config/types.ts";
4646
export const htmlNotebookContributor: NotebookContributor = {
4747
resolve: resolveHtmlNotebook,
4848
render: renderHtmlNotebook,
49+
outputFile,
4950
};
5051

52+
function outputFile(
53+
nbAbsPath: string,
54+
): string {
55+
return `${basename(nbAbsPath)}.html`;
56+
}
57+
5158
async function resolveHtmlNotebook(
5259
nbAbsPath: string,
5360
_token: string,

src/render/notebook/notebook-contributor-ipynb.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,15 @@ import { ipynbTitleTemplatePath } from "../../format/ipynb/format-ipynb.ts";
3333
export const outputNotebookContributor: NotebookContributor = {
3434
resolve: resolveOutputNotebook,
3535
render: renderOutputNotebook,
36+
outputFile,
3637
};
3738

39+
function outputFile(
40+
nbAbsPath: string,
41+
): string {
42+
return ipynbOutputFile(nbAbsPath);
43+
}
44+
3845
function resolveOutputNotebook(
3946
nbAbsPath: string,
4047
_token: string,

src/render/notebook/notebook-contributor-jats.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,15 @@ import { Format } from "../../config/types.ts";
3939
export const jatsContributor: NotebookContributor = {
4040
resolve: resolveJats,
4141
render: renderJats,
42+
outputFile,
4243
};
4344

45+
function outputFile(
46+
nbAbsPath: string,
47+
): string {
48+
return jatsOutputFile(nbAbsPath);
49+
}
50+
4451
function resolveJats(
4552
nbAbsPath: string,
4653
token: string,

src/render/notebook/notebook-types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export interface NotebookTemplateMetadata extends NotebookMetadata {
6767

6868
export interface NotebookContext {
6969
// Retrieves the notebook from the context.
70-
get: (nbPath: string, outputFile?: string) => Notebook | undefined;
70+
get: (nbPath: string, context?: ProjectContext) => Notebook | undefined;
7171
// Resolves the data on an executedFile into data that will
7272
// create a `renderType` output when rendered.
7373
resolve: (
@@ -105,6 +105,7 @@ export interface NotebookContext {
105105
}
106106

107107
export interface NotebookContributor {
108+
outputFile(nbAbsPath: string): string;
108109
resolve(
109110
nbAbsPath: string,
110111
token: string,

0 commit comments

Comments
 (0)