plotly_kaleido 0.12.0

Additional output format support for plotly using Kaleido
Documentation
extern crate directories;
extern crate zip;

use std::env;
use std::fs;
use std::io;
use std::io::Result;
use std::path::{Path, PathBuf};
use std::process::Command;

use directories::ProjectDirs;

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
const KALEIDO_URL: &str =
    "https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_linux_x64.zip";

#[cfg(all(target_arch = "aarch64", target_os = "linux"))]
const KALEIDO_URL: &str =
    "https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_linux_arm64.zip";

#[cfg(target_os = "windows")]
const KALEIDO_URL: &str =
    "https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_win_x64.zip";

#[cfg(all(target_arch = "x86_64", target_os = "macos"))]
const KALEIDO_URL: &str =
    "https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_mac_x64.zip";

#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
const KALEIDO_URL: &str =
    "https://github.com/plotly/Kaleido/releases/download/v0.2.1/kaleido_mac_arm64.zip";

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

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

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();

    for i in 0..archive.len() {
        let mut file = archive.by_index(i).unwrap();
        let outpath = file.mangled_name();
        let outpath = p.join(outpath);
        println!("outpath: {:?}", outpath);

        {
            let comment = file.comment();
            if !comment.is_empty() {
                println!("File {} comment: {}", i, comment);
            }
        }

        if (file.name()).ends_with('/') {
            println!(
                "File {} extracted to \"{}\"",
                i,
                outpath.as_path().display()
            );
            fs::create_dir_all(&outpath).unwrap();
        } else {
            println!(
                "File {} extracted to \"{}\" ({} bytes)",
                i,
                outpath.as_path().display(),
                file.size()
            );
            if let Some(p) = outpath.parent() {
                if !p.exists() {
                    fs::create_dir_all(p).unwrap();
                }
            }
            let mut outfile = fs::File::create(&outpath).unwrap();
            io::copy(&mut file, &mut outfile).unwrap();
        }

        // Get and Set permissions
        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;

            if let Some(mode) = file.unix_mode() {
                fs::set_permissions(&outpath, fs::Permissions::from_mode(mode)).unwrap();
            }
        }
    }

    fs::remove_file(zip_file)?;
    Ok(())
}

fn main() -> Result<()> {
    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 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 {
        let msg = "'download' feature disabled. Please install Kaleido manually and make the environment variable 'KALEIDO_PATH' point to it.".to_string();
        println!("cargo::warning={msg}");
    }
    Ok(())
}