CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
sagemathinc

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: sagemathinc/cocalc
Path: blob/master/src/packages/jupyter/redux/handle-nbconvert-change.ts
Views: 687
1
/*
2
Client sets this:
3
{type:'nbconvert', args:[...], state:'start'}
4
5
Then:
6
1. All clients show status bar that export is happening.
7
2. Commands to export are disabled during export.
8
3. Unless timeout exceeded.
9
10
The code in this file implements what the project does.
11
12
- Project sees export entry in table. If currently exporting, does nothing.
13
If not exporting, starts exporting and sets:
14
15
{type:'nbconvert', args:[...], state:'run', start:[time in ms]}
16
17
- When done, project sets
18
19
{type:'nbconvert', args:[...], state:'done'}
20
21
- If error, project stores the error in the key:value store and sets:
22
23
{type:'nbconvert', args:[...], state:'done', error:'message' or {key:'xlkjdf'}}
24
*/
25
26
import type { JupyterActions } from "./project-actions";
27
import { is_array, trunc } from "@cocalc/util/misc";
28
29
import { getLogger } from "@cocalc/backend/logger";
30
const log = getLogger("jupyter:handle-nbconvert-change");
31
32
// nbconvert can output arbitrarily large errors, so we truncate.
33
// But don't truncate too small! https://github.com/sagemathinc/cocalc/issues/5878
34
const MAX_ERROR_LENGTH = 100000;
35
36
interface Value {
37
state: string;
38
args: string[];
39
}
40
41
export default async function handleChange(
42
actions: JupyterActions,
43
oldVal?: Value,
44
newVal?: Value
45
): Promise<void> {
46
log.debug("got a change:", oldVal, newVal);
47
if (newVal == null) {
48
log.debug("delete nbconvert; no op");
49
return;
50
}
51
if (newVal.state != "start") {
52
log.debug(
53
`nothing to do -- requesting to change state to '${newVal.state}'.`
54
);
55
return;
56
}
57
const { args } = newVal;
58
if (!is_array(args)) {
59
log.debug("invalid args -- must be an array");
60
actions.syncdb.set({
61
type: "nbconvert",
62
state: "done",
63
error: "args must be an array",
64
});
65
actions.syncdb.commit();
66
return;
67
}
68
69
log.debug("tell client that we started running");
70
let error: any = null;
71
actions.syncdb.set({
72
type: "nbconvert",
73
state: "run",
74
start: new Date().getTime(),
75
error,
76
});
77
actions.syncdb.commit();
78
actions.ensure_backend_kernel_setup();
79
80
try {
81
log.debug(
82
"saving file to disk first, since some nbconvert functionality uses that file is on disk."
83
);
84
await actions.save_ipynb_file();
85
86
log.debug(
87
"now actually run nbconvert command (which may or may not actually use upstream nbconvert...)"
88
);
89
if (actions.jupyter_kernel == null) {
90
throw Error("no kernel, so can't run nbconvert");
91
}
92
93
await actions.jupyter_kernel.nbconvert(args);
94
log.debug("success");
95
} catch (err) {
96
error = trunc(`${err}`, MAX_ERROR_LENGTH);
97
log.debug("error", error);
98
}
99
actions.syncdb.set({
100
type: "nbconvert",
101
state: "done",
102
error,
103
time: new Date().getTime(),
104
});
105
actions.syncdb.commit();
106
}
107
108