@@ -14,42 +14,82 @@ import { execProcess } from "../process.ts";
1414import { resourcePath } from "../resources.ts" ;
1515import { readYamlFromString } from "../yaml.ts" ;
1616
17- import { JupyterCapabilities } from "./types.ts" ;
17+ import { JupyterCapabilities , JupyterKernelspec } from "./types.ts" ;
1818
19- // cache capabiliites per-process
20- let cachedJupyterCaps : JupyterCapabilities | undefined ;
19+ // cache capabilities per language
20+ const kNoLanguage = "(none)" ;
21+ const jupyterCapsCache = new Map < string , JupyterCapabilities > ( ) ;
22+
23+ export async function jupyterCapabilities ( kernelspec ?: JupyterKernelspec ) {
24+ const language = kernelspec ?. language || kNoLanguage ;
25+
26+ if ( ! jupyterCapsCache . has ( language ) ) {
27+
28+ // if we are targeting julia then prefer the julia installed miniconda
29+ const juliaCaps = await getVerifiedJuliaCondaJupyterCapabilities ( ) ;
30+ if ( language === "julia" && juliaCaps ) {
31+ jupyterCapsCache . set ( language , juliaCaps ) ;
32+ return juliaCaps ;
33+ }
2134
22- export async function jupyterCapabilities ( ) {
23- if ( ! cachedJupyterCaps ) {
2435 // if there is an explicit python requested then use it
25- cachedJupyterCaps = await getQuartoJupyterCapabilities ( ) ;
26- if ( cachedJupyterCaps ) {
27- return cachedJupyterCaps ;
36+ const quartoCaps = await getQuartoJupyterCapabilities ( ) ;
37+ if ( quartoCaps ) {
38+ jupyterCapsCache . set ( language , quartoCaps ) ;
39+ return quartoCaps ;
2840 }
2941
3042 // if we are on windows and have PY_PYTHON defined then use the launcher
3143 if ( isWindows ( ) && pyPython ( ) ) {
32- cachedJupyterCaps = await getPyLauncherJupyterCapabilities ( ) ;
44+ const pyLauncherCaps = await getPyLauncherJupyterCapabilities ( ) ;
45+ if ( pyLauncherCaps ) {
46+ jupyterCapsCache . set ( language , pyLauncherCaps ) ;
47+ }
3348 }
3449
3550 // default handling (also a fallthrough if launcher didn't work out)
36- if ( ! cachedJupyterCaps ) {
51+ if ( ! jupyterCapsCache . has ( language ) ) {
3752 // look for python from conda (conda doesn't provide python3 on windows or mac)
38- cachedJupyterCaps = await getJupyterCapabilities ( [ "python" ] ) ;
39-
40- // if it's not conda then probe explicitly for python 3
41- if ( ! cachedJupyterCaps ?. conda ) {
53+ const condaCaps = await getJupyterCapabilities ( [ "python" ] ) ;
54+ if ( condaCaps ?. conda ) {
55+ jupyterCapsCache . set ( language , condaCaps ) ;
56+ } else {
4257 const caps = isWindows ( )
4358 ? await getPyLauncherJupyterCapabilities ( )
4459 : await getJupyterCapabilities ( [ "python3" ] ) ;
4560 if ( caps ) {
46- cachedJupyterCaps = caps ;
61+ jupyterCapsCache . set ( language , caps ) ;
4762 }
4863 }
64+
65+ // if the version we discovered doesn't have jupyter and we have a julia provided
66+ // jupyter then go ahead and use that
67+ if ( ! jupyterCapsCache . get ( language ) ?. jupyter_core && juliaCaps ) {
68+ jupyterCapsCache . set ( language , juliaCaps ) ;
69+ }
4970 }
5071 }
5172
52- return cachedJupyterCaps ;
73+ return jupyterCapsCache . get ( language ) ;
74+ }
75+
76+ async function getVerifiedJuliaCondaJupyterCapabilities ( ) {
77+ const home = isWindows ( ) ? Deno . env . get ( "USERPROFILE" ) : Deno . env . get ( "HOME" ) ;
78+ if ( home ) {
79+ const juliaPython = join (
80+ home ,
81+ ".julia" ,
82+ "conda" ,
83+ "3" ,
84+ isWindows ( ) ? "python.exe" : join ( "bin" , "python3" )
85+ ) ;
86+ if ( existsSync ( juliaPython ) ) {
87+ const caps = await getJupyterCapabilities ( [ juliaPython ] ) ;
88+ if ( caps ?. jupyter_core ) {
89+ return caps ;
90+ }
91+ }
92+ }
5393}
5494
5595function getQuartoJupyterCapabilities ( ) {
0 commit comments