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
use super::*;

/// To install/overwrite a new kernel to jupyter.
#[derive(Clone, Debug, Parser)]
pub struct InstallAction {
    /// Optional name to operate on
    name: Option<String>,
}

#[derive(Clone, Debug, Serialize)]
struct KernelConfig {
    argv: Vec<String>,
    display_name: String,
    language: String,
    interrupt_mode: String,
    metadata: Metadata,
}

#[derive(Clone, Debug, Serialize)]
struct Metadata {
    debugger: bool,
}

impl InstallAction {
    /// Run the install action.
    pub fn run<T>(&self, engine: T) -> JupyterResult<()>
    where
        T: JupyterKernelProtocol,
    {
        do_install(&engine)
    }
}

impl KernelConfig {
    pub fn new(language: &str, display: &str) -> JupyterResult<Self> {
        match std::env::current_exe() {
            Ok(path) => Ok(Self {
                argv: vec![
                    path.to_string_lossy().to_string(),
                    "start".to_string(),
                    "--control-file".to_string(),
                    "{connection_file}".to_string(),
                ],
                display_name: display.to_string(),
                language: language.to_string(),
                interrupt_mode: "message".to_string(),
                metadata: Metadata { debugger: true },
            }),
            Err(e) => {
                // "current exe path isn't valid UTF-8"
                panic!("Couldn't get current exe path: {}", e);
            }
        }
    }
}

pub(crate) fn do_install<T: JupyterKernelProtocol>(info: &T) -> JupyterResult<()> {
    let info = info.language_info();
    let kernel_dir = get_kernel_dir(&info.language_key)?;
    std::fs::create_dir_all(&kernel_dir)?;
    let kernel_config = KernelConfig::new(&info.language_key, &info.language)?;
    let kernel_json = to_string_pretty(&kernel_config)?;
    let kernel_json_filename = kernel_dir.join("kernel.json");
    tracing::info!("Writing {}", kernel_json_filename.to_string_lossy());
    // prerry print json
    let mut file = std::fs::File::create(&kernel_json_filename)?;
    file.write_all(kernel_json.as_bytes())?;

    install_resource(&kernel_dir, "logo-32x32.png", info.png_32)?;
    install_resource(&kernel_dir, "logo-64x64.png", info.png_64)?;
    install_resource(&kernel_dir, "kernel.js", KERNEL_JS)?;
    install_resource(&kernel_dir, "lint.js", LINT_JS)?;
    install_resource(&kernel_dir, "lint.css", LINT_CSS)?;
    install_resource(&kernel_dir, "lint-LICENSE", LINT_LICENSE)?;
    // install_resource(&kernel_dir, "version.txt", VERSION_TXT)?;
    tracing::info!("Installation complete");
    Ok(())
}
pub(crate) fn install_resource(dir: &Path, filename: &str, bytes: &'static [u8]) -> JupyterResult<()> {
    let res_path = dir.join(filename);
    tracing::info!("Writing {}", res_path.to_string_lossy());
    let mut file = std::fs::File::create(res_path)?;
    file.write_all(bytes)?;
    Ok(())
}