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/kernel/kernel-data.ts
Views: 687
1
/*
2
* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.
3
* License: MS-RSL – see LICENSE.md for details
4
*/
5
6
/*
7
Use nteracts kernelspecs module to get data about all installed Jupyter kernels.
8
9
The result is cached for 10s to avoid wasted effort in case of a flurry of calls.
10
11
Specs: https://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs
12
*/
13
14
import { findAll } from "kernelspecs";
15
import LRU from "lru-cache";
16
import type { KernelSpec } from "@cocalc/jupyter/types/types";
17
import { field_cmp } from "@cocalc/util/misc";
18
import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
19
20
const cache = new LRU<"kernel_data", KernelSpec[]>({
21
ttl: 15 * 1000,
22
max: 5 /* silly since only one possible key */,
23
});
24
25
/**
26
* just an edge case for Macaulay2. Full data looks like this:
27
* m2: {
28
name: 'm2',
29
files: [ ... ],
30
resources_dir: '...',
31
spec: {
32
argv: [...],
33
display_name: 'M2',
34
language: 'text/x-macaulay2',
35
codemirror_mode: 'macaulay2'
36
}
37
},
38
*/
39
function spec2language(spec): string {
40
if (spec.language === "text/x-macaulay2") {
41
return "Macaulay2";
42
} else {
43
return spec.language;
44
}
45
}
46
47
// this is very expensive and can get called many times at once before
48
// the cache is set, which is very bad... so reuseInFlight.
49
export const get_kernel_data = reuseInFlight(
50
async (): Promise<KernelSpec[]> => {
51
let x = cache.get("kernel_data");
52
if (x != null) {
53
return x;
54
}
55
const kernel_data = await findAll();
56
const v: KernelSpec[] = [];
57
for (const kernel in kernel_data) {
58
const value = kernel_data[kernel];
59
v.push({
60
name: kernel.toLowerCase(),
61
display_name: value.spec.display_name,
62
language: spec2language(value.spec),
63
// @ts-ignore
64
interrupt_mode: value.spec.interrupt_mode,
65
env: value.spec.env ?? {},
66
// @ts-ignore
67
metadata: value.spec.metadata,
68
// kernelspecs incorrectly calls it resources_dir instead of resource_dir.
69
// See https://github.com/nteract/kernelspecs/issues/25
70
// @ts-ignore
71
resource_dir: value.resource_dir ?? value.resources_dir,
72
argv: value.spec.argv,
73
});
74
}
75
v.sort(field_cmp("display_name"));
76
cache.set("kernel_data", v);
77
return v;
78
},
79
);
80
81
export async function getLanguage(kernelName: string): Promise<string> {
82
const kernelSpec = await get_kernel_data_by_name(kernelName);
83
if (kernelSpec != null) {
84
return kernelSpec.language;
85
}
86
throw Error(`unknown kernel ${kernelName}`);
87
}
88
89
export async function get_kernel_data_by_name(
90
name: string,
91
): Promise<KernelSpec> {
92
name = name.toLowerCase();
93
const kernel_data = await get_kernel_data();
94
for (const kernel of kernel_data) {
95
if (kernel.name == name) {
96
return kernel;
97
}
98
}
99
throw Error(`no such kernel '${name}'`);
100
}
101
102