summaryrefslogtreecommitdiff
path: root/cli/tools/jupyter/install.rs
blob: d1777d92d5f196c244332daa9defb4ca00ed16d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// 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(())
}