Merge branch 'master' of ssh://stash.wolfram.com:7999/se/wolframlanguageforjupyter

This commit is contained in:
Arnoud Buzing 2018-11-07 09:16:10 -06:00
commit b7d499e3b1
4 changed files with 374 additions and 207 deletions

View File

View File

@ -72,11 +72,17 @@ SetAttributes[jupEval, HoldAll];
sendFrame[socket_, frame_Association] := Module[{},
ZeroMQLink`ZMQSocketWriteMessage[
socket,
frame["ident"],
"Multipart" -> True
];
ZeroMQLink`ZMQSocketWriteMessage[
socket,
StringToByteArray[#1],
"Multipart" -> True
]& /@ Lookup[frame, {"uuid", "idsmsg", "signature", "header", "pheader", "metadata"}];
]& /@ Lookup[frame, {"idsmsg", "signature", "header", "pheader", "metadata"}];
ZeroMQLink`ZMQSocketWriteMessage[
socket,
@ -141,12 +147,12 @@ getFrameAssoc[frame_Association, replyType_String, replyContent_String, branchOf
header = frame["header"];
content = frame["content"];
AssociateTo[res, {"header" -> Association[ImportString[header, "JSON"]], "content" -> Association[ImportString[content, "JSON"]]}];
AssociateTo[res, {"header" -> Association[ImportByteArray[StringToByteArray[header], "JSON"]], "content" -> Association[ImportByteArray[StringToByteArray[content], "JSON"]]}];
AssociateTo[
res,
"replyMsg" ->
Association[
"uuid" -> res["header"]["session"],
"ident" -> If[KeyExistsQ[frame, "ident"], frame["ident"], ByteArray[{0, 0, 0, 0, 0}]],
"idsmsg" -> "<IDS|MSG>",
"header" -> ExportString[Append[res["header"], {"date" -> DateString["ISODateTime"], "msg_type" -> replyType, "msg_id" -> StringInsert[StringReplace[CreateUUID[], "-" -> ""], "-", 9]}], "JSON", "Compact" -> True],
"pheader" -> If[branchOff, "{}", header],
@ -175,17 +181,17 @@ getFrameAssoc[frame_Association, replyType_String, replyContent_String, branchOf
Return[res];
];
getFrameAssoc[baFrame_ByteArray, replyType_String, replyContent_String, branchOff:(True|False)] := Module[{frameStr, res = Association[], header, pheader, metadata, content},
getFrameAssoc[baFrame_ByteArray, replyType_String, replyContent_String, branchOff:(True|False)] := Module[{frameStr, res = Association[], identLen, header, pheader, metadata, content},
frameStr = Quiet[ByteArrayToString[baFrame]];
{header, pheader, metadata, content} = First[StringCases[frameStr,
"<IDS|MSG>" ~~ ___ ~~ "{" ~~ json1___ ~~ "}" ~~ "{" ~~ json2___ ~~ "}" ~~ "{" ~~ json3___ ~~ "}" ~~ "{" ~~ json4___ ~~ "}" ~~ EndOfString :>
(StringJoin["{",#1,"}"] &) /@ {json1,json2,json3,json4}
{identLen, header, pheader, metadata, content} = First[StringCases[frameStr,
ident1___ ~~ "<IDS|MSG>" ~~ ___ ~~ "{" ~~ json1___ ~~ "}" ~~ "{" ~~ json2___ ~~ "}" ~~ "{" ~~ json3___ ~~ "}" ~~ "{" ~~ json4___ ~~ "}" ~~ EndOfString :>
Prepend[(StringJoin["{",#1,"}"] &) /@ {json1,json2,json3,json4}, StringLength[ident1]]
]];
Return[
getFrameAssoc[
Association["header" -> header, "content" -> content],
Association["ident" -> baFrame[[;;identLen]], "header" -> header, "content" -> content],
replyType,
replyContent,
branchOff
@ -249,142 +255,162 @@ ioPubReplyFrame = Association[];
doShutdown = False;
While[
True,
Switch[
First[SocketWaitNext[{shellSocket}]],
shellSocket,
srm = SocketReadMessage[shellSocket, "Multipart" -> True];
frameAssoc = getFrameAssoc[srm, "", "{}", False];
Switch[
frameAssoc["header"]["msg_type"],
"kernel_info_request",
replyMsgType = "kernel_info_reply";
replyContent = "{\"protocol_version\":\"5.3.0\",\"implementation\":\"WL\"}";,
"is_complete_request",
(* Add syntax-Q checking *)
replyMsgType = "is_complete_reply";
replyContent = "{\"status\":\"unknown\"}";,
"execute_request",
jupyterEvaluationLoop[] :=
Module[
{
srm,
frameAssoc,
replyMsgType,
replyContent,
$jupResEval,
$res,
$msgs,
ioPubReplyContent,
statReplyFrame,
shellReplyFrame
},
replyMsgType = "execute_reply";
replyContent = ExportString[Association["status" -> "ok", "execution_count" -> executionCount, "user_expressions" -> {}], "JSON", "Compact" -> True];
While[
True,
Switch[
First[SocketWaitNext[{shellSocket}]],
shellSocket,
srm = SocketReadMessage[shellSocket, "Multipart" -> True];
frameAssoc = getFrameAssoc[srm, "", "{}", False];
Switch[
frameAssoc["header"]["msg_type"],
"kernel_info_request",
replyMsgType = "kernel_info_reply";
replyContent = "{\"protocol_version\":\"5.3.0\",\"implementation\":\"WL\"}";,
"is_complete_request",
(* Add syntax-Q checking *)
replyMsgType = "is_complete_reply";
replyContent = "{\"status\":\"unknown\"}";,
"execute_request",
$jupResEval = ToExpression[frameAssoc["content"]["code"], InputForm, Uninteract];
$res = $jupResEval["res"];
$msgs = $jupResEval["msgs"];
If[FailureQ[$jupResEval],
$res=$Failed;
$msgs=jupEval[ToExpression[frameAssoc["content"]["code"], InputForm]]["msgs"];
];
replyMsgType = "execute_reply";
replyContent = ExportString[Association["status" -> "ok", "execution_count" -> executionCount, "user_expressions" -> {}], "JSON", "Compact" -> True];
If[TrueQ[InteractQ[ToExpression[frameAssoc["content"]["code"], InputForm, Hold]]] && $CloudConnected,
ioPubReplyContent = ExportString[
Association[
"execution_count" -> executionCount,
"data" -> {"text/html" -> StringJoin[
"<div><img alt=\"\" src=\"data:image/png;base64,",
BaseEncode[ExportByteArray[Rasterize[Style[$msgs, Darker[Red]]], "PNG"]],
"\">",
EmbedCode[CloudDeploy[$res], "HTML"][[1]]["CodeSection"]["Content"],
"</div>"
]
},
"metadata" -> {"text/html" -> {}}
],
"JSON",
"Compact" -> True
];
,
If[doText[$res],
ioPubReplyContent = ExportString[
Association[
"execution_count" -> executionCount,
"data" -> {"text/html" -> StringJoin[
"<div>",
If[StringLength[$msgs] == 0,
{},
{
"<pre style=\"",
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
"\">",
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
"</pre>"
}
],
"<pre style=\"",
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["font-family: \"Courier New\",Courier,monospace;"]],
"\">",
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[ToString[$res]]],
"</pre></div>"
]
},
"metadata" -> {"text/html" -> {}}
],
"JSON",
"Compact" -> True
];,
ioPubReplyContent = ExportString[
Association[
"execution_count" -> executionCount,
"data" -> {"text/html" -> StringJoin[
"<div>",
Sequence @@ If[StringLength[$msgs] == 0,
{},
{
"<pre style=\"",
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
"\">",
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
"</pre>"
}
],
"<img alt=\"Output\" src=\"data:image/png;base64,",
BaseEncode[
ExportByteArray[
If[Head[$res] === Manipulate, $res, Rasterize[$res]],
"PNG"
]
],
"\"></div>"
]
},
"metadata" -> {"text/html" -> {}}
],
"JSON",
"Compact" -> True
$jupResEval = ToExpression[frameAssoc["content"]["code"], InputForm, Uninteract];
$res = $jupResEval["res"];
$msgs = $jupResEval["msgs"];
If[FailureQ[$jupResEval],
$res=$Failed;
$msgs=jupEval[ToExpression[frameAssoc["content"]["code"], InputForm]]["msgs"];
];
If[TrueQ[InteractQ[ToExpression[frameAssoc["content"]["code"], InputForm, Hold]]] && $CloudConnected,
ioPubReplyContent = ExportString[
Association[
"execution_count" -> executionCount,
"data" -> {"text/html" -> StringJoin[
"<div><img alt=\"\" src=\"data:image/png;base64,",
BaseEncode[ExportByteArray[Rasterize[Style[$msgs, Darker[Red]]], "PNG"]],
"\">",
EmbedCode[CloudDeploy[$res], "HTML"][[1]]["CodeSection"]["Content"],
"</div>"
]
},
"metadata" -> {"text/html" -> {}}
],
"JSON",
"Compact" -> True
];
,
If[doText[$res],
ioPubReplyContent = ExportString[
Association[
"execution_count" -> executionCount,
"data" -> {"text/html" -> StringJoin[
"<div>",
If[StringLength[$msgs] == 0,
{},
{
"<pre style=\"",
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
"\">",
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
"</pre>"
}
],
"<pre style=\"",
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["font-family: \"Courier New\",Courier,monospace;"]],
"\">",
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[ToString[$res]]],
"</pre></div>"
]
},
"metadata" -> {"text/html" -> {}}
],
"JSON",
"Compact" -> True
];,
ioPubReplyContent = ExportString[
Association[
"execution_count" -> executionCount,
"data" -> {"text/html" -> StringJoin[
"<div>",
Sequence @@ If[StringLength[$msgs] == 0,
{},
{
"<pre style=\"",
StringJoin[{"&#",ToString[#1], ";"} & /@ ToCharacterCode["color:red; font-family: \"Courier New\",Courier,monospace;"]],
"\">",
StringJoin[{"&#", ToString[#1], ";"} & /@ ToCharacterCode[$msgs]],
"</pre>"
}
],
"<img alt=\"Output\" src=\"data:image/png;base64,",
BaseEncode[
ExportByteArray[
If[Head[$res] === Manipulate, $res, Rasterize[$res]],
"PNG"
]
],
"\"></div>"
]
},
"metadata" -> {"text/html" -> {}}
],
"JSON",
"Compact" -> True
];
];
];
ioPubReplyFrame = getFrameAssoc[srm, "execute_result", ioPubReplyContent, False];
executionCount++;,
"shutdown_request",
replyMsgType = "shutdown_reply";
replyContent = "{\"restart\":false}";
doShutdown = True;,
_,
Continue[];
];
statReplyFrame = getFrameAssoc[srm, "status", "{\"execution_state\":\"busy\"}", True]["replyMsg"];
sendFrame[ioPubSocket, statReplyFrame];
shellReplyFrame = getFrameAssoc[srm, replyMsgType, replyContent, False];
sendFrame[shellSocket, shellReplyFrame["replyMsg"]];
If[!(ioPubReplyFrame === Association[]),
sendFrame[ioPubSocket, ioPubReplyFrame["replyMsg"]];
ioPubReplyFrame = Association[];
];
sendFrame[ioPubSocket, getFrameAssoc[statReplyFrame, "status", "{\"execution_state\":\"idle\"}", False]["replyMsg"]];
If[doShutdown, Quit[];];
,
_,
Continue[];
];
ioPubReplyFrame = getFrameAssoc[srm, "execute_result", ioPubReplyContent, False];
executionCount++;,
"shutdown_request",
replyMsgType = "shutdown_reply";
replyContent = "{\"restart\":false}";
doShutdown = True;,
_,
Continue[];
];
statReplyFrame = getFrameAssoc[srm, "status", "{\"execution_state\":\"busy\"}", True]["replyMsg"];
sendFrame[ioPubSocket, statReplyFrame];
shellReplyFrame = getFrameAssoc[srm, replyMsgType, replyContent, False];
sendFrame[shellSocket, shellReplyFrame["replyMsg"]];
If[!(ioPubReplyFrame === Association[]),
sendFrame[ioPubSocket, ioPubReplyFrame["replyMsg"]];
ioPubReplyFrame = Association[];
];
sendFrame[ioPubSocket, getFrameAssoc[statReplyFrame, "status", "{\"execution_state\":\"idle\"}", False]["replyMsg"]];
If[doShutdown, Quit[];];
,
_,
Continue[];
];
];
End[];
End[];
(* This setup does not preclude dynamics or widgets. *)
WolframLanguageForJupyter`Private`jupyterEvaluationLoop[];

View File

@ -1,27 +1,52 @@
BeginPackage["WolframLanguageForJupyter`"];
AddKernelToJupyter::usage = "AddKernelToJupyter[] attempts to add the Wolfram kernel to the Jupyter installation on Environment[\"PATH\"].
(* AddKernelToJupyter::usage = "AddKernelToJupyter[] attempts to add the Wolfram Language kernel to the Jupyter installation on Environment[\"PATH\"].
AddKernelToJupyter[\"\!\(\*
StyleBox[\"path\", \"TI\"]\)\"] adds the Wolfram kernel to the location of the Jupyter binary at \!\(\*
StyleBox[\"path\", \"TI\"]\).";
StyleBox[\"path\", \"TI\"]\)\"] adds the Wolfram Language kernel to the location of the Jupyter binary at \!\(\*
StyleBox[\"path\", \"TI\"]\)."; *)
AddKernelToJupyter::usage = "AddKernelToJupyter[] adds a Wolfram Language kernel to a Jupyter binary on Environment[\"PATH\"].
AddKernelToJupyter[\"jupyter\"] adds a Wolfram Language kernel to the provided Jupyter binary path.
AddKernelToJupyter[\"jupyter\", \"kernel\"] adds the provided absolute Wolfram Language kernel binary path to the provided Jupyter binary path.";
AddKernelToJupyter::notfound = "Jupyter installation on Environment[\"PATH\"] not found.";
AddKernelToJupyter::isdir = "Provided path is a directory. Please provide the path to the Jupyter binary."
AddKernelToJupyter::nobin = "Provided path does not exist.";
AddKernelToJupyter::notadded = "An error has occurred. There is still no Wolfram kernel in \"jupyter kernelspec list.\"";
AddKernelToJupyter::isdir = "Provided `1` binary path is a directory. Please provide the path to the `1` binary.";
AddKernelToJupyter::nobin = "Provided `1` binary path does not exist.";
AddKernelToJupyter::notadded = "An error has occurred. There is still no Wolfram Language kernel in \"jupyter kernelspec list.\"";
RemoveKernelFromJupyter::usage = "RemoveKernelFromJupyter[] attempts to remove any Wolfram kernels from the Jupyter installation on Environment[\"PATH\"].
(* RemoveKernelFromJupyter::usage = "RemoveKernelFromJupyter[] attempts to remove any Wolfram Language kernels from the Jupyter installation on Environment[\"PATH\"].
RemoveKernelFromJupyter[\"\!\(\*
StyleBox[\"path\", \"TI\"]\)\"] removes any Wolfram kernels from the location of the Jupyter binary at \!\(\*
StyleBox[\"path\", \"TI\"]\).";
StyleBox[\"path\", \"TI\"]\)\"] removes any Wolfram Language kernels from the location of the Jupyter binary at \!\(\*
StyleBox[\"path\", \"TI\"]\)."; *)
RemoveKernelFromJupyter::usage = "RemoveKernelFromJupyter[] removes any Wolfram Language kernels found on a Jupyter binary on Environment[\"PATH\"].
RemoveKernelFromJupyter[\"jupyter\"] removes any Wolfram Language kernels found on the provided Jupyter binary path.";
RemoveKernelFromJupyter::notfound = AddKernelToJupyter::notfound;
RemoveKernelFromJupyter::isdir = AddKernelToJupyter::isdir;
RemoveKernelFromJupyter::nobin = AddKernelToJupyter::nobin;
RemoveKernelFromJupyter::notremoved = "An error has occurred. There is a Wolfram kernel still in \"jupyter kernelspec list.\"";
RemoveKernelFromJupyter::notremoved = "An error has occurred. There is a Wolfram Language kernel still in \"jupyter kernelspec list.\"";
Begin["`Private`"];
(* globalKernelUUID = "11a8cf20-da0e-4976-83e5-27579d6360b3"; *)
globalKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
hashedKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
names = StringCases[$Version, name___ ~~ " for " ~~ ("Mac" | "Microsoft" | "Windows" | "Linux") -> name];
If[Length[names] > 0,
globalKernelUUID =
ToLowerCase[StringJoin[
"WolframLanguage-",
StringReplace[First[names], Whitespace -> "-"]
]];
displayName =
StringJoin[
"Wolfram Language (",
Capitalize[
First[names],
"AllWords"
],
")"
];
,
globalKernelUUID = hashedKernelUUID;
displayName = "Wolfram Language";
];
pacletHome = DirectoryName[$InputFileName];
@ -73,23 +98,84 @@ RemoveKernelFromJupyter[] :=
];
getKernelspecAssoc[jupyterPath_String] :=
Replace[
ImportString[RunProcess[{jupyterPath, "kernelspec", "list", "--json"}, "StandardOutput"], "JSON"],
part_List /; AllTrue[part, Head[#1] === Rule &] -> Association @ part,
{0, Infinity}
Module[{json},
json = Quiet[ImportString[RunProcess[{jupyterPath, "kernelspec", "list", "--json"}, "StandardOutput"], "JSON"]];
If[
FailureQ[json],
Return[Association[]];
];
Return[
Replace[
json,
part_List /; AllTrue[part, Head[#1] === Rule &] -> Association @ part,
{0, Infinity}
]
];
];
AddKernelToJupyter[jupyterPath_String] :=
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID},
AddKernelToJupyter[jupyterPath_String] := AddKernelToJupyter[jupyterPath, mathBin];
RemoveKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
Module[{exitCodeOld, exitCode, kernelspecAssoc, kernelspecs, oldEnv},
If[DirectoryQ[jupyterPath],
Message[AddKernelToJupyter::isdir];
Message[RemoveKernelFromJupyter::isdir, "Jupyter"];
Return[$Failed];
];
If[!FileExistsQ[jupyterPath],
Message[AddKernelToJupyter::nobin];
Message[RemoveKernelFromJupyter::nobin, "Jupyter"];
Return[$Failed];
];
oldEnv = Environment["PATH"];
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
exitCodeOld = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", hashedKernelUUID}, "ExitCode"];
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", globalKernelUUID}, "ExitCode"];
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
If[
KeyExistsQ[kernelspecAssoc, "kernelspecs"],
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];,
kernelspecs = {};
];
If[MemberQ[
kernelspecs,
(* kernelUUID *)
globalKernelUUID
],
Message[RemoveKernelFromJupyter::notremoved];
Return[$Failed];
];
SetEnvironment["PATH" -> oldEnv];
(* Return[kernelUUID]; *)
];
AddKernelToJupyter[jupyterPath_String, mathB_String] :=
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID, oldEnv},
If[DirectoryQ[jupyterPath],
Message[AddKernelToJupyter::isdir, "Jupyter"];
Return[$Failed];
];
If[!FileExistsQ[jupyterPath],
Message[AddKernelToJupyter::nobin, "Jupyter"];
Return[$Failed];
];
If[DirectoryQ[mathB],
Message[AddKernelToJupyter::isdir, "Wolfram Language kernel"];
Return[$Failed];
];
If[!FileExistsQ[mathB],
Message[AddKernelToJupyter::nobin, "Wolfram Language kernel"];
Return[$Failed];
];
oldEnv = Environment["PATH"];
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
kernelUUID = CreateUUID[];
tempDir = CreateDirectory[
FileNameJoin[{
@ -102,8 +188,8 @@ AddKernelToJupyter[jupyterPath_String] :=
Export[
FileNameJoin[{tempDir, "kernel.json"}],
Association[
"argv" -> {mathBin, "-script", FileNameJoin[{pacletHome, "Resources", "kernel.wl"}], "{connection_file}"},
"display_name" -> "Wolfram Language",
"argv" -> {mathB, "-script", FileNameJoin[{pacletHome, "Resources", "kernel.wl"}], "{connection_file}"},
"display_name" -> displayName,
"language" -> "Wolfram Language"
]
];
@ -118,7 +204,11 @@ AddKernelToJupyter[jupyterPath_String] :=
DeleteDirectory[DirectoryName[tempDir], DeleteContents -> True];
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];
If[
KeyExistsQ[kernelspecAssoc, "kernelspecs"],
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];,
kernelspecs = {};
];
If[!MemberQ[
kernelspecs,
@ -129,24 +219,7 @@ AddKernelToJupyter[jupyterPath_String] :=
Return[$Failed];
];
(* Return[kernelUUID]; *)
];
RemoveKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
Module[{exitCode, kernelspecAssoc, kernelspecs},
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", (* kernelUUID *) globalKernelUUID}, "ExitCode"];
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];
If[MemberQ[
kernelspecs,
(* kernelUUID *)
globalKernelUUID
],
Message[RemoveKernelFromJupyter::notremoved];
Return[$Failed];
];
SetEnvironment["PATH" -> oldEnv];
(* Return[kernelUUID]; *)
];

View File

@ -3,15 +3,37 @@ Begin["WolframLanguageForJupyter`Private`"];
notfound = "install.wls: Jupyter installation on Environment[\"PATH\"] not found.";
isdir = "install.wls: Provided Jupyter binary path is a directory. Please provide the path to the Jupyter binary."
nobin = "install.wls: Provided Jupyter binary path does not exist.";
notadded = "install.wls: An error has occurred. There is still no Wolfram kernel in \"jupyter kernelspec list.\"";
notremoved = "install.wls: An error has occurred. There is a Wolfram kernel still in \"jupyter kernelspec list.\"";
isdirMath = "install.wls: Provided Wolfram Language kernel binary path is a directory. Please provide the path to the Wolfram Language kernel binary."
nobinMath = "install.wls: Provided Wolfram Language kernel binary path does not exist.";
notadded = "install.wls: An error has occurred. There is still no Wolfram Language kernel in \"jupyter kernelspec list.\"";
notremoved = "install.wls: An error has occurred. There is a Wolfram Language kernel still in \"jupyter kernelspec list.\"";
nopaclet = "install.wls: WolframLanguageForJupyter paclet source not detected. Are you running the script in the root project directory?";
(* globalKernelUUID = "11a8cf20-da0e-4976-83e5-27579d6360b3"; *)
globalKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
hashedKernelUUID = Hash[$InstallationDirectory, "SHA", "HexString"];
names = StringCases[$Version, name___ ~~ " for " ~~ ("Mac" | "Microsoft" | "Windows" | "Linux") -> name];
If[Length[names] > 0,
globalKernelUUID =
ToLowerCase[StringJoin[
"WolframLanguage-",
StringReplace[First[names], Whitespace -> "-"]
]];
displayName =
StringJoin[
"Wolfram Language (",
Capitalize[
First[names],
"AllWords"
],
")"
];
,
globalKernelUUID = hashedKernelUUID;
displayName = "Wolfram Language";
];
kernelScript = FileNameJoin[{projectHome, "WolframLanguageForJupyter", "Resources", "kernel.wl"}];
projectHome = Directory[];
kernelScript = FileNameJoin[{projectHome, "WolframLanguageForJupyter", "Resources", "kernel.wl"}];
If[
!FileExistsQ[kernelScript],
Print[nopaclet];
@ -120,8 +142,10 @@ getKernelspecAssoc[jupyterPath_String] :=
];
];
addKernelToJupyter[jupyterPath_String] :=
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID},
addKernelToJupyter[jupyterPath_String] := addKernelToJupyter[jupyterPath, mathBin];
removeKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
Module[{exitCodeOld, exitCode, kernelspecAssoc, kernelspecs, oldEnv},
If[DirectoryQ[jupyterPath],
Print[isdir];
Return[$Failed];
@ -131,6 +155,56 @@ addKernelToJupyter[jupyterPath_String] :=
Return[$Failed];
];
oldEnv = Environment["PATH"];
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
exitCodeOld = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", hashedKernelUUID}, "ExitCode"];
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", globalKernelUUID}, "ExitCode"];
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
If[
KeyExistsQ[kernelspecAssoc, "kernelspecs"],
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];,
kernelspecs = {};
];
If[MemberQ[
kernelspecs,
(* kernelUUID *)
globalKernelUUID
],
Print[notremoved];
Return[$Failed];
];
SetEnvironment["PATH" -> oldEnv];
(* Return[kernelUUID]; *)
];
addKernelToJupyter[jupyterPath_String, mathB_String] :=
Module[{baseDir, tempDir, exitCode, kernelspecAssoc, kernelspecs, kernelUUID, oldEnv},
If[DirectoryQ[jupyterPath],
Print[isdir];
Return[$Failed];
];
If[!FileExistsQ[jupyterPath],
Print[nobin];
Return[$Failed];
];
If[DirectoryQ[mathB],
Print[isdirMath];
Return[$Failed];
];
If[!FileExistsQ[mathB],
Print[nobinMath];
Return[$Failed];
];
oldEnv = Environment["PATH"];
SetEnvironment["PATH" -> StringJoin[Environment["PATH"], pathSeperator, DirectoryName[jupyterPath]]];
kernelUUID = CreateUUID[];
tempDir = CreateDirectory[
FileNameJoin[{
@ -143,8 +217,8 @@ addKernelToJupyter[jupyterPath_String] :=
Export[
FileNameJoin[{tempDir, "kernel.json"}],
Association[
"argv" -> {mathBin, "-script", kernelScript, "{connection_file}"},
"display_name" -> "Wolfram Language",
"argv" -> {mathB, "-script", kernelScript, "{connection_file}"},
"display_name" -> displayName,
"language" -> "Wolfram Language"
]
];
@ -174,32 +248,18 @@ addKernelToJupyter[jupyterPath_String] :=
Return[$Failed];
];
(* Return[kernelUUID]; *)
];
removeKernelFromJupyter[jupyterPath_String (*, kernelUUID_String *)] :=
Module[{exitCode, kernelspecAssoc, kernelspecs},
exitCode = RunProcess[{jupyterPath, "kernelspec", "remove", "-f", (* kernelUUID *) globalKernelUUID}, "ExitCode"];
kernelspecAssoc = getKernelspecAssoc[jupyterPath];
kernelspecs = Keys[kernelspecAssoc["kernelspecs"]];
If[MemberQ[
kernelspecs,
(* kernelUUID *)
globalKernelUUID
],
Print[notremoved];
Return[$Failed];
];
SetEnvironment["PATH" -> oldEnv];
(* Return[kernelUUID]; *)
];
templateJupyterPath = FileNameJoin[{"path", "to", "Jupyter", "binary"}];
templateWLPath = FileNameJoin[{"", "absolute", "path", "to", "Wolfram", "Language", "kernel", "binary"}];
helpMessage = StringJoin[
"install.wls: Usage: install.wls add [", templateJupyterPath, "]\ninstall.wls: Usage:\tadds a Wolfram kernel to a Jupyter binary on PATH, or optional provided Jupyter binary path\ninstall.wls: Usage: install.wls remove [", templateJupyterPath ,"]\ninstall.wls: Usage:\tremoves any Wolfram kernels found on a Jupyter binary on PATH, or optional provided Jupyter binary path"
"install.wls: Usage: install.wls add [", templateJupyterPath, "]\ninstall.wls: Usage:\tadds a Wolfram Language kernel to a Jupyter binary on PATH, or optional provided Jupyter binary path\n",
"install.wls: Usage: install.wls add ", templateJupyterPath, " ", templateWLPath, "\ninstall.wls: Usage:\tadds the provided absolute Wolfram Language kernel binary path to the provided Jupyter binary path\n",
"install.wls: Usage: install.wls remove [", templateJupyterPath ,"]\ninstall.wls: Usage:\tremoves any Wolfram Language kernels found on a Jupyter binary on PATH, or optional provided Jupyter binary path"
];
If[Length[$ScriptCommandLine] == 1 || $ScriptCommandLine[[2]] === "help",
@ -210,10 +270,18 @@ If[Length[$ScriptCommandLine] == 1 || $ScriptCommandLine[[2]] === "help",
command = addKernelToJupyter;
];
If[Length[$ScriptCommandLine] > 2,
Switch[
Length[$ScriptCommandLine],
4,
command[
$ScriptCommandLine[[3]]
StringTrim[$ScriptCommandLine[[3]], "*"],
StringTrim[$ScriptCommandLine[[4]], "*"]
];,
3,
command[
StringTrim[$ScriptCommandLine[[3]], "*"]
];,
_,
command[];
];
];