mirror of
https://github.com/denoland/deno.git
synced 2024-12-22 23:34:47 -05:00
bf07604113
This commit adds "deno jupyter" subcommand which provides a Deno kernel for Jupyter notebooks. The implementation is mostly based on Deno's REPL and reuses large parts of it (though there's some clean up that needs to happen in follow up PRs). Not all functionality of Jupyter kernel is implemented and some message type are still not implemented (eg. "inspect_request") but the kernel is fully working and provides all the capatibilities that the Deno REPL has; including TypeScript transpilation and npm packages support. Closes https://github.com/denoland/deno/issues/13016 --------- Co-authored-by: Adam Powers <apowers@ato.ms> Co-authored-by: Kyle Kelley <rgbkrk@gmail.com>
95 lines
2.8 KiB
Rust
95 lines
2.8 KiB
Rust
// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
|
||
|
||
use deno_core::anyhow::bail;
|
||
use deno_core::anyhow::Context;
|
||
use deno_core::error::AnyError;
|
||
use deno_core::serde_json;
|
||
use deno_core::serde_json::json;
|
||
use std::env::current_exe;
|
||
use std::io::Write;
|
||
use std::path::Path;
|
||
use tempfile::TempDir;
|
||
|
||
const DENO_ICON_32: &[u8] = include_bytes!("./resources/deno-logo-32x32.png");
|
||
const DENO_ICON_64: &[u8] = include_bytes!("./resources/deno-logo-64x64.png");
|
||
|
||
pub fn status() -> Result<(), AnyError> {
|
||
let output = std::process::Command::new("jupyter")
|
||
.args(["kernelspec", "list", "--json"])
|
||
.output()
|
||
.context("Failed to get list of installed kernelspecs")?;
|
||
let json_output: serde_json::Value =
|
||
serde_json::from_slice(&output.stdout)
|
||
.context("Failed to parse JSON from kernelspec list")?;
|
||
|
||
if let Some(specs) = json_output.get("kernelspecs") {
|
||
if let Some(specs_obj) = specs.as_object() {
|
||
if specs_obj.contains_key("deno") {
|
||
println!("✅ Deno kernel already installed");
|
||
return Ok(());
|
||
}
|
||
}
|
||
}
|
||
|
||
println!("ℹ️ Deno kernel is not yet installed, run `deno jupyter --unstable --install` to set it up");
|
||
Ok(())
|
||
}
|
||
|
||
fn install_icon(
|
||
dir_path: &Path,
|
||
filename: &str,
|
||
icon_data: &[u8],
|
||
) -> Result<(), AnyError> {
|
||
let path = dir_path.join(filename);
|
||
let mut file = std::fs::File::create(path)?;
|
||
file.write_all(icon_data)?;
|
||
Ok(())
|
||
}
|
||
|
||
pub fn install() -> Result<(), AnyError> {
|
||
let temp_dir = TempDir::new().unwrap();
|
||
let kernel_json_path = temp_dir.path().join("kernel.json");
|
||
|
||
// TODO(bartlomieju): add remaining fields as per
|
||
// https://jupyter-client.readthedocs.io/en/stable/kernels.html#kernel-specs
|
||
// FIXME(bartlomieju): replace `current_exe` before landing?
|
||
let json_data = json!({
|
||
"argv": [current_exe().unwrap().to_string_lossy(), "--unstable", "jupyter", "--kernel", "--conn", "{connection_file}"],
|
||
"display_name": "Deno",
|
||
"language": "typescript",
|
||
});
|
||
|
||
let f = std::fs::File::create(kernel_json_path)?;
|
||
serde_json::to_writer_pretty(f, &json_data)?;
|
||
install_icon(temp_dir.path(), "icon-32x32.png", DENO_ICON_32)?;
|
||
install_icon(temp_dir.path(), "icon-64x64.png", DENO_ICON_64)?;
|
||
|
||
let child_result = std::process::Command::new("jupyter")
|
||
.args([
|
||
"kernelspec",
|
||
"install",
|
||
"--user",
|
||
"--name",
|
||
"deno",
|
||
&temp_dir.path().to_string_lossy(),
|
||
])
|
||
.spawn();
|
||
|
||
if let Ok(mut child) = child_result {
|
||
let wait_result = child.wait();
|
||
match wait_result {
|
||
Ok(status) => {
|
||
if !status.success() {
|
||
bail!("Failed to install kernelspec, try again.");
|
||
}
|
||
}
|
||
Err(err) => {
|
||
bail!("Failed to install kernelspec: {}", err);
|
||
}
|
||
}
|
||
}
|
||
|
||
let _ = std::fs::remove_dir(temp_dir);
|
||
println!("✅ Deno kernelspec installed successfully.");
|
||
Ok(())
|
||
}
|