use anyhow::{bail, Context, Result};
use clap::Args as ClapArgs;
use console::style;
use stout_index::{Database, IndexSync};
use stout_state::{Config, Paths};
#[cfg(target_os = "linux")]
use tracing::warn;
#[derive(ClapArgs)]
pub struct Args {
pub formula: Option<String>,
}
pub async fn run(args: Args) -> Result<()> {
let paths = Paths::default();
let config = Config::load(&paths)?;
let url = if let Some(ref name) = args.formula {
let db = Database::open(paths.index_db())
.context("Failed to open index. Run 'stout update' first.")?;
if !db.is_initialized()? {
bail!("Index not initialized. Run 'stout update' first.");
}
let sync = IndexSync::with_security_policy(
Some(&config.index.base_url),
&paths.stout_dir,
config.security.to_security_policy(),
)?;
if let Ok(formula) = sync.fetch_formula_cached(name, None).await {
if let Some(homepage) = formula.homepage {
homepage
} else {
bail!("Formula '{}' has no homepage", name);
}
} else if let Ok(cask) = sync.fetch_cask_cached(name, None).await {
if let Some(homepage) = cask.homepage {
homepage
} else {
bail!("Cask '{}' has no homepage", name);
}
} else {
bail!("Formula or cask '{}' not found", name);
}
} else {
"https://brew.sh".to_string()
};
println!(
"{} Opening {}",
style("==>").blue().bold(),
style(&url).cyan().underlined()
);
open_url(&url)?;
Ok(())
}
fn open_url(url: &str) -> Result<()> {
#[cfg(target_os = "macos")]
{
std::process::Command::new("open")
.arg(url)
.spawn()
.context("Failed to open URL")?;
}
#[cfg(target_os = "linux")]
{
if let Err(e) = std::process::Command::new("xdg-open").arg(url).spawn() {
warn!("Failed to open URL with xdg-open: {}", e);
for browser in &["firefox", "chromium", "google-chrome", "brave"] {
if std::process::Command::new(browser).arg(url).spawn().is_ok() {
return Ok(());
}
}
bail!("Could not find a browser to open URL. Install xdg-utils or a web browser.");
}
}
#[cfg(target_os = "windows")]
{
std::process::Command::new("cmd")
.args(["/C", "start", url])
.spawn()
.context("Failed to open URL")?;
}
Ok(())
}