Skip to content

Commit

Permalink
allow users to set Kaleido path via envionment variable
Browse files Browse the repository at this point in the history
 - introduced a new feature to allow users to download Kaleido at
   compile time when the applications are targeted for the host machine
 - this can be overriden by the runtime environment variable

Signed-off-by: Andrei Gherghescu <[email protected]>
  • Loading branch information
andrei-ng committed Dec 20, 2024
1 parent ea8d95c commit f0adfda
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 67 deletions.
8 changes: 6 additions & 2 deletions examples/kaleido/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
[package]
name = "kaleido"
version = "0.1.0"
authors = ["Michael Freeborn <[email protected]>"]
authors = [
"Michael Freeborn <[email protected]>",
"Andrei Gherghescu [email protected]",
]
edition = "2021"

[dependencies]
plotly = { path = "../../plotly", features = ["kaleido"] }
plotly = { path = "../../plotly", features = ["kaleido", "kaleido_fetch"] }
# plotly = { path = "../../plotly", features = ["kaleido"] }
8 changes: 6 additions & 2 deletions plotly/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,12 @@ exclude = ["target/*"]

[features]
kaleido = ["plotly_kaleido"]
kaleido_fetch = ["plotly_kaleido/download"]

plotly_ndarray = ["ndarray"]
plotly_image = ["image"]
# Embed JavaScript into library and templates for offline use
plotly_embed_js = []

wasm = ["getrandom", "js-sys", "wasm-bindgen", "wasm-bindgen-futures"]
with-axum = ["rinja/with-axum", "rinja_axum"]

Expand Down Expand Up @@ -48,6 +50,8 @@ image = "0.25"
itertools = ">=0.10, <0.14"
itertools-num = "0.1"
ndarray = "0.16"
plotly_kaleido = { version = "0.11", path = "../plotly_kaleido" }
plotly_kaleido = { version = "0.11", path = "../plotly_kaleido", features = [
"download",
] }
rand_distr = "0.4"
base64 = "0.22"
2 changes: 1 addition & 1 deletion plotly/src/plot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ impl PartialEq for Plot {
mod tests {
use std::path::PathBuf;

use base64::{engine::general_purpose, Engine as _};

use serde_json::{json, to_value};

use super::*;
Expand Down
11 changes: 10 additions & 1 deletion plotly_kaleido/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
name = "plotly_kaleido"
version = "0.11.0"
description = "Additional output format support for plotly using Kaleido"
authors = ["Ioannis Giagkiozis <[email protected]>"]
authors = [
"Ioannis Giagkiozis <[email protected]>",
"Andrei Gherghescu [email protected]",
]
license = "MIT"
readme = "README.md"
workspace = ".."
Expand All @@ -14,13 +17,19 @@ keywords = ["plot", "chart", "plotly", "ndarray"]

exclude = ["target/*", "kaleido/*", "examples/*"]

[features]
download = []

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
base64 = "0.22"
dunce = "1.0"
directories = ">=4, <6"

[dev-dependencies]
plotly_kaleido = { version = "0.11", path = ".", features = ["download"] }

[build-dependencies]
zip = "2.1"
directories = ">=4, <6"
82 changes: 50 additions & 32 deletions plotly_kaleido/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,12 @@ const KALEIDO_URL: &str =
const KALEIDO_URL: &str =
"https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_mac_arm64.zip";

#[cfg(target_os = "linux")]
#[cfg(any(target_os = "linux", target_os = "macos"))]
const KALEIDO_BIN: &str = "kaleido";

#[cfg(target_os = "windows")]
const KALEIDO_BIN: &str = "kaleido.exe";

#[cfg(target_os = "macos")]
const KALEIDO_BIN: &str = "kaleido";

fn extract_zip(p: &Path, zip_file: &Path) -> Result<()> {
let file = fs::File::open(zip_file).unwrap();
let mut archive = zip::ZipArchive::new(file).unwrap();
Expand Down Expand Up @@ -95,35 +92,56 @@ fn extract_zip(p: &Path, zip_file: &Path) -> Result<()> {
}

fn main() -> Result<()> {
let project_dirs = ProjectDirs::from("org", "plotly", "kaleido")
.expect("Could not create plotly_kaleido config directory.");
let dst: PathBuf = project_dirs.config_dir().into();
if cfg!(feature = "download") {
let project_dirs = ProjectDirs::from("org", "plotly", "kaleido")
.expect("Could not create Kaleido config directory path.");
let dst: PathBuf = project_dirs.config_dir().into();

let kaleido_binary = dst.join("bin").join(KALEIDO_BIN);

println!("cargo:rerun-if-changed=src/lib.rs");
println!(
"cargo::rerun-if-changed={}",
kaleido_binary.to_string_lossy()
);

println!(
"cargo:rustc-env=KALEIDO_COMPILE_TIME_DLD_PATH={}",
dst.to_string_lossy()
);

if kaleido_binary.exists() {
return Ok(());
}

let kaleido_binary = dst.join("bin").join(KALEIDO_BIN);
if kaleido_binary.exists() {
return Ok(());
let msg = format!(
"Downloaded Plotly Kaleido from {KALEIDO_URL} to '{}'",
dst.to_string_lossy()
);
println!("cargo::warning={msg}");

let p = PathBuf::from(env::var("OUT_DIR").unwrap());
let kaleido_zip_file = p.join("kaleido.zip");

let mut cmd = Command::new("cargo")
.args(["install", "ruget"])
.spawn()
.unwrap();
cmd.wait()?;

let mut cmd = Command::new("ruget")
.args([
KALEIDO_URL,
"-o",
kaleido_zip_file.as_path().to_str().unwrap(),
])
.spawn()
.unwrap();
cmd.wait()?;

extract_zip(&dst, &kaleido_zip_file)?;
} else {
println!("'download' feature disabled. Kaleido binary won't be downloaded and must be installed manually.")
}

let p = PathBuf::from(env::var("OUT_DIR").unwrap());
let kaleido_zip_file = p.join("kaleido.zip");

let mut cmd = Command::new("cargo")
.args(["install", "ruget"])
.spawn()
.unwrap();
cmd.wait()?;

let mut cmd = Command::new("ruget")
.args([
KALEIDO_URL,
"-o",
kaleido_zip_file.as_path().to_str().unwrap(),
])
.spawn()
.unwrap();
cmd.wait()?;

extract_zip(&dst, &kaleido_zip_file)?;
println!("cargo:rerun-if-changed=src/lib.rs");
Ok(())
}
76 changes: 47 additions & 29 deletions plotly_kaleido/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};

use base64::{engine::general_purpose, Engine as _};
use directories::ProjectDirs;
use serde::{Deserialize, Serialize};
use serde_json::Value;

Expand Down Expand Up @@ -77,49 +76,59 @@ pub struct Kaleido {
}

impl Kaleido {
const KALEIDO_PATH_ENV: &str = "KALEIDO_PATH";

pub fn new() -> Kaleido {
let path = match Kaleido::binary_path() {
Ok(path) => path,
Err(msg) => panic!("{}", msg),
use std::env;

let path = match env::var(Self::KALEIDO_PATH_ENV) {
Ok(runtime_env) => runtime_env,
Err(runtime_env_err) => match option_env!("KALEIDO_COMPILE_TIME_DLD_PATH") {
Some(compile_time_path) => compile_time_path.to_string(),
None => {
println!("{}: {}", Self::KALEIDO_PATH_ENV, runtime_env_err);
println!("Use `kaleido_fetch` feature to automatically download, install and use Kaleido when targeting applications that run on the host machine.");
println!("Use `{}` environment variable when targeting applications intended to run on different machines. Manually install Kaleido on the target machine and point {} to the installation location.", Self::KALEIDO_PATH_ENV, Self::KALEIDO_PATH_ENV
);
std::process::exit(1);
}
},
};

Kaleido { cmd_path: path }
}
let path = match Kaleido::binary_path(&path) {
Ok(kaleido_path) => kaleido_path,
Err(msg) => panic!("Failed tu use Kaleido binary at {} due to {}", path, msg),
};

fn root_dir() -> Result<PathBuf, &'static str> {
let project_dirs = ProjectDirs::from("org", "plotly", "kaleido")
.expect("Could not create plotly_kaleido config directory.");
Ok(project_dirs.config_dir().into())
Kaleido { cmd_path: path }
}

#[cfg(target_os = "linux")]
fn binary_path() -> Result<PathBuf, &'static str> {
let mut p = Kaleido::root_dir()?;
p = p.join("kaleido").canonicalize().unwrap();
fn binary_path(dld_path: &str) -> Result<PathBuf, &'static str> {
let mut p = PathBuf::from(dld_path);
p = Self::os_binary_path(p);
if !p.exists() {
return Err("could not find kaleido executable in path");
}
Ok(p)
}

#[cfg(target_os = "macos")]
fn binary_path() -> Result<PathBuf, &'static str> {
let mut p = Kaleido::root_dir()?;
p = p.join("kaleido").canonicalize().unwrap();
if !p.exists() {
return Err("could not find kaleido executable in path");
#[cfg(any(target_os = "linux", target_os = "macos"))]
fn os_binary_path(path: PathBuf) -> PathBuf {
match path.join("kaleido").canonicalize() {
Ok(v) => v,
Err(e) => {
println!(
"Failed to find Kaleido binary at '{}': {e}",
path.to_string_lossy()
);
panic!("{e}");
}
}
Ok(p)
}

#[cfg(target_os = "windows")]
fn binary_path() -> Result<PathBuf, &'static str> {
let mut p = Kaleido::root_dir()?;
p = p.join("kaleido.cmd");
if !p.exists() {
return Err("could not find kaleido executable in path");
}
Ok(p)
fn os_binary_path(path: PathBuf) -> PathBuf {
p.join("kaleido.cmd")
}

/// Generate a static image from a Plotly graph and save it to a file
Expand Down Expand Up @@ -193,7 +202,16 @@ impl Kaleido {
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("failed to spawn Kaleido binary");
.unwrap_or_else(|_| {
panic!(
"{}",
format!(
"failed to spawn Kaleido binary at {}",
self.cmd_path.to_string_lossy()
)
.to_string()
)
});

{
let plot_data = PlotData::new(plotly_data, format, width, height, scale).to_json();
Expand Down

0 comments on commit f0adfda

Please sign in to comment.