use std::{
path::{Path, PathBuf},
process::{Command, Output},
};
static ARDUINO_CLI_BYTES: &[u8] = include_bytes!(env!("ARDUINO_CLI_PATH"));
pub fn extract_arduino_cli(cache_dir: PathBuf) -> Result<PathBuf, ArduinoError> {
std::fs::create_dir_all(&cache_dir)?;
let name = if cfg!(windows) { "arduino-cli.exe" } else { "arduino-cli" };
let dest = cache_dir.join(name);
if !dest.exists() {
std::fs::write(&dest, ARDUINO_CLI_BYTES)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&dest, std::fs::Permissions::from_mode(0o755))?;
}
}
Ok(dest)
}
pub fn install_libraries(cli: &Path, libraries: &[String]) -> Result<(), ArduinoError> {
if libraries.is_empty() {
return Ok(());
}
let args: Vec<&str> = std::iter::once("lib")
.chain(std::iter::once("install"))
.chain(libraries.iter().map(String::as_str))
.collect();
run(cli, &args)?;
Ok(())
}
pub fn run(cli: &Path, args: &[&str]) -> Result<Output, ArduinoError> {
let output = Command::new(cli)
.args(args)
.output()
.map_err(ArduinoError::Spawn)?;
if !output.status.success() {
return Err(ArduinoError::CliError(
String::from_utf8_lossy(&output.stderr).to_string(),
));
}
Ok(output)
}
#[derive(Debug, thiserror::Error)]
pub enum ArduinoError {
#[error("failed to spawn arduino-cli: {0}")]
Spawn(std::io::Error),
#[error("io error: {0}")]
Io(#[from] std::io::Error),
#[error("arduino-cli error: {0}")]
CliError(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn arduino_cli_version_succeeds() {
let tmp = std::env::temp_dir().join("loop_arduino_shared_test");
let path = extract_arduino_cli(tmp).unwrap();
let output = Command::new(&path).arg("version").output().unwrap();
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(stdout.contains("arduino-cli"));
}
}