use anyhow::Result;
use console::style;
use stout_cask::InstalledCasks;
use stout_install::cask_scan::scan_caskroom;
use stout_install::cellar::scan_cellar;
use stout_install::relocate_bottle;
use stout_state::{InstalledPackages, Paths};
use crate::cli::import::import_cellar_package;
pub fn check_first_run_import(installed: &mut InstalledPackages, paths: &Paths) -> Result<bool> {
if paths.installed_file().exists() {
return Ok(false);
}
let cellar_packages = scan_cellar(&paths.cellar)?;
let untracked_cellar: Vec<_> = cellar_packages
.iter()
.filter(|pkg| !installed.is_installed(&pkg.name))
.collect();
let brew_casks = scan_caskroom(&paths.prefix).unwrap_or_default();
let cask_state_path = paths.stout_dir.join("casks.json");
let cask_state = InstalledCasks::load(&cask_state_path).unwrap_or_default();
let untracked_casks: Vec<_> = brew_casks
.iter()
.filter(|cask| !cask_state.is_installed(&cask.token))
.collect();
const MIN_UNTRACKED: usize = 5;
let total_untracked = untracked_cellar.len() + untracked_casks.len();
if total_untracked < MIN_UNTRACKED {
return Ok(false);
}
if !crate::output::is_interactive() {
return Ok(false);
}
let state_count = installed.count();
let mut items = Vec::new();
if !untracked_cellar.is_empty() {
items.push(format!("{} packages", untracked_cellar.len()));
}
if !untracked_casks.is_empty() {
items.push(format!("{} casks", untracked_casks.len()));
}
let items_str = items.join(" and ");
let msg = if state_count == 0 {
format!(
"{} {} in Homebrew but none tracked by stout.",
style("Found").cyan(),
items_str
)
} else {
format!(
"{} {} untracked in Homebrew (already tracking {} packages).",
style("Found").cyan(),
items_str,
state_count
)
};
println!("\n{}", msg);
eprint!("{} ", style("Import them? [Y/n]").bold());
let mut input = String::new();
std::io::stdin().read_line(&mut input)?;
let input = input.trim().to_lowercase();
if input == "n" || input == "no" {
installed.save(paths)?;
println!("{}", style("Skipped import.").dim());
return Ok(false);
}
println!("\n{}...", style("Importing from Homebrew").cyan());
for pkg in &untracked_cellar {
import_cellar_package(installed, pkg);
let _ = relocate_bottle(&pkg.path, &paths.prefix);
}
if !untracked_cellar.is_empty() {
installed.save(paths)?;
}
if !untracked_casks.is_empty() {
let mut cask_state = InstalledCasks::load(&cask_state_path).unwrap_or_default();
for cask in &untracked_casks {
let timestamp = crate::cli::import::timestamp_now_iso();
let imported_cask = stout_cask::InstalledCask {
version: cask
.version
.clone()
.unwrap_or_else(|| "unknown".to_string()),
installed_at: timestamp,
artifact_path: std::path::PathBuf::from(""),
auto_updates: false,
artifacts: Vec::new(),
};
cask_state.add(&cask.token, imported_cask);
}
cask_state.save(&cask_state_path)?;
}
println!(
" {} Imported {} items\n",
style("✓").green(),
total_untracked
);
Ok(true)
}