kernel_sidecar/
kernels.rs

1use crate::jupyter::connection_file::ConnectionInfo;
2use std::path::PathBuf;
3use std::process::{Child, Command};
4
5#[derive(Debug)]
6pub struct JupyterKernel {
7    process: Child,
8    pub connection_info: ConnectionInfo,
9    pub connection_file: PathBuf,
10}
11
12impl JupyterKernel {
13    fn start_process(cmd: Vec<&str>, silent: bool) -> Child {
14        Command::new(cmd[0])
15            .args(&cmd[1..])
16            .stdout(if silent {
17                std::process::Stdio::null()
18            } else {
19                std::process::Stdio::inherit()
20            })
21            .spawn()
22            .expect("Failed to start Jupyter Kernel")
23    }
24
25    // start a Python (ipykernel) kernel
26    pub fn ipython(silent: bool) -> Self {
27        let kernel_name = "ipykernel".to_string();
28        let connection_info = ConnectionInfo::new(Some(kernel_name)).unwrap();
29        let file_path = connection_info.to_temp_file().unwrap();
30        let cmd = vec![
31            "python",
32            "-m",
33            "ipykernel_launcher",
34            "-f",
35            file_path.to_str().unwrap(),
36        ];
37        let process = Self::start_process(cmd, silent);
38        Self {
39            process,
40            connection_info,
41            connection_file: file_path,
42        }
43    }
44
45    // start a Rust (evcxr) kernel
46    pub fn evcxr(silent: bool) -> Self {
47        let kernel_name = "evcxr".to_string();
48        let connection_info = ConnectionInfo::new(Some(kernel_name)).unwrap();
49        let file_path = connection_info.to_temp_file().unwrap();
50        let cmd = vec![
51            "evcxr_jupyter",
52            "--control_file",
53            file_path.to_str().unwrap(),
54        ];
55        let process = Self::start_process(cmd, silent);
56        Self {
57            process,
58            connection_info,
59            connection_file: file_path,
60        }
61    }
62
63    // Start an R (irkernel) kernel
64    pub fn irkernel(silent: bool) -> Self {
65        let kernel_name = "ir".to_string();
66        let connection_info = ConnectionInfo::new(Some(kernel_name)).unwrap();
67        let file_path = connection_info.to_temp_file().unwrap();
68        let cmd = vec![
69            "R",
70            "-e",
71            "IRkernel::main()",
72            "--args",
73            file_path.to_str().unwrap(),
74        ];
75        let process = Self::start_process(cmd, silent);
76        Self {
77            process,
78            connection_info,
79            connection_file: file_path,
80        }
81    }
82
83    // Start a Typescript (deno) kernel
84    pub fn deno(silent: bool) -> Self {
85        let kernel_name = "deno".to_string();
86        let connection_info = ConnectionInfo::new(Some(kernel_name)).unwrap();
87        let file_path = connection_info.to_temp_file().unwrap();
88        let cmd = vec![
89            "deno",
90            "jupyter",
91            "--unstable",
92            "--kernel",
93            "--conn",
94            file_path.to_str().unwrap(),
95        ];
96        let process = Self::start_process(cmd, silent);
97        Self {
98            process,
99            connection_info,
100            connection_file: file_path,
101        }
102    }
103}
104
105impl Drop for JupyterKernel {
106    fn drop(&mut self) {
107        self.process.kill().expect("Failed to kill Kernel process");
108        self.connection_file
109            .as_path()
110            .to_owned()
111            .into_os_string()
112            .into_string()
113            .expect("Failed to convert connection_file to string");
114        std::fs::remove_file(&self.connection_file).expect("Failed to remove connection_file");
115    }
116}