Files
chrome-use/cli/src/install.rs
T
Chris Tate 79863a5180 Fix: CLI: state load / profile persistence not usable in v0.7.6 (#268)
* Fix: CLI: state load / profile persistence not usable in v0.7.6

This PR addresses issue #259

* Fix issues identified in code review
2026-01-25 13:45:17 -06:00

226 lines
7.3 KiB
Rust

use crate::color;
use std::process::{exit, Command, Stdio};
pub fn run_install(with_deps: bool) {
let is_linux = cfg!(target_os = "linux");
if is_linux {
if with_deps {
println!("{}", color::cyan("Installing system dependencies..."));
let (pkg_mgr, deps) = if which_exists("apt-get") {
let libasound = if package_exists_apt("libasound2t64") {
"libasound2t64"
} else {
"libasound2"
};
(
"apt-get",
vec![
"libxcb-shm0",
"libx11-xcb1",
"libx11-6",
"libxcb1",
"libxext6",
"libxrandr2",
"libxcomposite1",
"libxcursor1",
"libxdamage1",
"libxfixes3",
"libxi6",
"libgtk-3-0",
"libpangocairo-1.0-0",
"libpango-1.0-0",
"libatk1.0-0",
"libcairo-gobject2",
"libcairo2",
"libgdk-pixbuf-2.0-0",
"libxrender1",
libasound,
"libfreetype6",
"libfontconfig1",
"libdbus-1-3",
"libnss3",
"libnspr4",
"libatk-bridge2.0-0",
"libdrm2",
"libxkbcommon0",
"libatspi2.0-0",
"libcups2",
"libxshmfence1",
"libgbm1",
],
)
} else if which_exists("dnf") {
(
"dnf",
vec![
"nss",
"nspr",
"atk",
"at-spi2-atk",
"cups-libs",
"libdrm",
"libXcomposite",
"libXdamage",
"libXrandr",
"mesa-libgbm",
"pango",
"alsa-lib",
"libxkbcommon",
"libxcb",
"libX11-xcb",
"libX11",
"libXext",
"libXcursor",
"libXfixes",
"libXi",
"gtk3",
"cairo-gobject",
],
)
} else if which_exists("yum") {
(
"yum",
vec![
"nss",
"nspr",
"atk",
"at-spi2-atk",
"cups-libs",
"libdrm",
"libXcomposite",
"libXdamage",
"libXrandr",
"mesa-libgbm",
"pango",
"alsa-lib",
"libxkbcommon",
],
)
} else {
eprintln!(
"{} No supported package manager found (apt-get, dnf, or yum)",
color::error_indicator()
);
exit(1);
};
let install_cmd = match pkg_mgr {
"apt-get" => {
format!(
"sudo apt-get update && sudo apt-get install -y {}",
deps.join(" ")
)
}
_ => format!("sudo {} install -y {}", pkg_mgr, deps.join(" ")),
};
println!("Running: {}", install_cmd);
let status = Command::new("sh").arg("-c").arg(&install_cmd).status();
match status {
Ok(s) if s.success() => {
println!("{} System dependencies installed", color::success_indicator())
}
Ok(_) => eprintln!(
"{} Failed to install some dependencies. You may need to run manually with sudo.",
color::warning_indicator()
),
Err(e) => eprintln!("{} Could not run install command: {}", color::warning_indicator(), e),
}
} else {
println!(
"{} Linux detected. If browser fails to launch, run:",
color::warning_indicator()
);
println!(" agent-browser install --with-deps");
println!(" or: npx playwright install-deps chromium");
println!();
}
}
println!("{}", color::cyan("Installing Chromium browser..."));
// On Windows, we need to use cmd.exe to run npx because npx is actually npx.cmd
// and Command::new() doesn't resolve .cmd files the way the shell does.
// Pass the entire command as a single string to /c to handle paths with spaces.
#[cfg(windows)]
let status = Command::new("cmd")
.args(["/c", "npx playwright install chromium"])
.status();
#[cfg(not(windows))]
let status = Command::new("npx")
.args(["playwright", "install", "chromium"])
.status();
match status {
Ok(s) if s.success() => {
println!(
"{} Chromium installed successfully",
color::success_indicator()
);
if is_linux && !with_deps {
println!();
println!(
"{} If you see \"shared library\" errors when running, use:",
color::yellow("Note:")
);
println!(" agent-browser install --with-deps");
}
}
Ok(_) => {
eprintln!("{} Failed to install browser", color::error_indicator());
if is_linux {
println!(
"{} Try installing system dependencies first:",
color::yellow("Tip:")
);
println!(" agent-browser install --with-deps");
}
exit(1);
}
Err(e) => {
eprintln!("{} Failed to run npx: {}", color::error_indicator(), e);
eprintln!("Make sure Node.js is installed and npx is in your PATH");
exit(1);
}
}
}
fn which_exists(cmd: &str) -> bool {
#[cfg(unix)]
{
Command::new("which")
.arg(cmd)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
#[cfg(windows)]
{
Command::new("where")
.arg(cmd)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
}
fn package_exists_apt(pkg: &str) -> bool {
Command::new("apt-cache")
.arg("show")
.arg(pkg)
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}