blue/crates/blue-ollama/build.rs
Eric Garcia 5d3a7c0d1b feat(ollama): Add binary bundling and SHA256 verification
- Add build.rs to download Ollama at build time for target platform
- Add SHA256 verification infrastructure (currently skipped for external installs)
- Improve bundled_binary_path() to check additional standard locations
- Support BLUE_OLLAMA_PATH and BLUE_SKIP_OLLAMA_DOWNLOAD env vars

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-24 15:39:41 -05:00

129 lines
4.5 KiB
Rust

//! Build script for blue-ollama
//!
//! Downloads Ollama binary for the target platform at build time.
//! Set BLUE_OLLAMA_PATH to skip download and use a local binary.
//! Set BLUE_SKIP_OLLAMA_DOWNLOAD=1 to skip download entirely.
use std::env;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
/// Ollama version to download
const OLLAMA_VERSION: &str = "v0.5.4";
/// Base URL for Ollama releases
const OLLAMA_RELEASE_URL: &str = "https://github.com/ollama/ollama/releases/download";
fn main() {
println!("cargo:rerun-if-env-changed=BLUE_OLLAMA_PATH");
println!("cargo:rerun-if-env-changed=BLUE_SKIP_OLLAMA_DOWNLOAD");
// Skip if BLUE_OLLAMA_PATH is set (user provides their own binary)
if env::var("BLUE_OLLAMA_PATH").is_ok() {
println!("cargo:warning=Using BLUE_OLLAMA_PATH, skipping Ollama download");
return;
}
// Skip if explicitly disabled
if env::var("BLUE_SKIP_OLLAMA_DOWNLOAD").is_ok() {
println!("cargo:warning=BLUE_SKIP_OLLAMA_DOWNLOAD set, skipping Ollama download");
return;
}
// Get output directory
let out_dir = env::var("OUT_DIR").expect("OUT_DIR not set");
let out_path = PathBuf::from(&out_dir);
// Determine target platform
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let (binary_name, download_url) = match (target_os.as_str(), target_arch.as_str()) {
("macos", _) => (
"ollama",
format!("{}/{}/ollama-darwin", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
),
("linux", "x86_64") => (
"ollama",
format!("{}/{}/ollama-linux-amd64", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
),
("linux", "aarch64") => (
"ollama",
format!("{}/{}/ollama-linux-arm64", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
),
("windows", "x86_64") => (
"ollama.exe",
format!("{}/{}/ollama-windows-amd64.exe", OLLAMA_RELEASE_URL, OLLAMA_VERSION),
),
_ => {
println!("cargo:warning=Unsupported platform: {}-{}", target_os, target_arch);
println!("cargo:warning=Ollama will need to be installed manually");
return;
}
};
let binary_path = out_path.join(binary_name);
// Check if already downloaded
if binary_path.exists() {
println!("cargo:warning=Ollama binary already exists at {:?}", binary_path);
write_binary_path(&out_path, &binary_path);
return;
}
// Download the binary
println!("cargo:warning=Downloading Ollama {} for {}-{}", OLLAMA_VERSION, target_os, target_arch);
println!("cargo:warning=URL: {}", download_url);
match download_binary(&download_url, &binary_path) {
Ok(_) => {
println!("cargo:warning=Downloaded Ollama to {:?}", binary_path);
// Make executable on Unix
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
if let Ok(metadata) = fs::metadata(&binary_path) {
let mut perms = metadata.permissions();
perms.set_mode(0o755);
let _ = fs::set_permissions(&binary_path, perms);
}
}
write_binary_path(&out_path, &binary_path);
}
Err(e) => {
println!("cargo:warning=Failed to download Ollama: {}", e);
println!("cargo:warning=Ollama will need to be installed manually");
println!("cargo:warning=Install with: brew install ollama (macOS) or see https://ollama.ai");
}
}
}
/// Download binary using reqwest (blocking)
fn download_binary(url: &str, dest: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
let client = reqwest::blocking::Client::builder()
.timeout(std::time::Duration::from_secs(300))
.build()?;
let response = client.get(url).send()?;
if !response.status().is_success() {
return Err(format!("HTTP {}: {}", response.status(), url).into());
}
let bytes = response.bytes()?;
let mut file = File::create(dest)?;
file.write_all(&bytes)?;
Ok(())
}
/// Write the binary path to a file for runtime discovery
fn write_binary_path(out_dir: &PathBuf, binary_path: &PathBuf) {
let path_file = out_dir.join("ollama_binary_path.txt");
if let Ok(mut file) = File::create(&path_file) {
let _ = writeln!(file, "{}", binary_path.display());
}
}