use std::collections::HashSet; use std::fs::read_to_string; use std::path::PathBuf; use anyhow::{Context, Result}; use serde_json::Value; use crate::backend::backend_trait::*; use crate::{impl_backend_constants, Group, Package}; pub(crate) struct Rust { pub(crate) packages: HashSet, } const BINARY: Text = "cargo"; const SECTION: Text = "rust"; const SWITCHES_INSTALL: Switches = &["install"]; const SWITCHES_REMOVE: Switches = &["uninstall"]; impl Backend for Rust { impl_backend_constants!(); fn get_all_installed_packages(&self) -> Result> { let file = get_crates_file().context("getting path to crates file")?; let content = read_to_string(file).context("reading crates file")?; let json: Value = serde_json::from_str(&content).context("parsing JSON")?; extract_packages(json).context("extracing packages from JSON") } fn get_explicitly_installed_packages(&self) -> Result> { self.get_all_installed_packages() .context("getting all installed packages") } } fn extract_packages(json: Value) -> Result> { let result: HashSet<_> = json .get("installs") .context("get 'installs' field from json")? .as_object() .context("getting object")? .into_iter() .map(|(name, _)| name) .map(|name| { name.split_whitespace() .next() .expect("identifier is whitespace-delimited") }) .map(|name| Package::try_from(name).expect("name is valid")) .collect(); Ok(result) } impl Rust { pub(crate) fn new() -> Self { Self { packages: HashSet::new(), } } } fn get_crates_file() -> Result { let mut result = crate::path::get_home_dir().context("getting home dir")?; result.push(".cargo"); result.push(".crates2.json"); Ok(result) }