use anyhow::{bail, Context as _, Result};
use std::fs;
use crate::{context::Context, util::not_found_err};
use super::Package;
pub struct EditableConfig {
ctx: Context,
doc: toml_edit::DocumentMut,
}
impl EditableConfig {
pub fn load(ctx: &Context) -> Result<Self> {
let buf = match fs::read_to_string(&ctx.config_file) {
Err(e) if not_found_err(&e) => include_str!("packages.toml").to_owned(),
buf => buf.with_context(|| format!("failed to read {}", ctx.config_file.display()))?,
};
let ctx = ctx.clone();
let mut doc: toml_edit::DocumentMut = buf.parse().context("failed to parse TOML")?;
match &mut doc["pkgs"] {
item @ toml_edit::Item::None => {
let mut pkgs = toml_edit::Table::new();
pkgs.set_implicit(true);
*item = toml_edit::Item::Table(pkgs);
}
toml_edit::Item::Table(_) => {}
_ => bail!("current `pkgs` entry is not a table"),
}
Ok(Self { ctx, doc })
}
pub fn save(&self) -> Result<()> {
fs::write(&self.ctx.config_file, self.doc.to_string())
.with_context(|| format!("failed to write {}", self.ctx.config_file.display()))
}
pub fn upsert(&mut self, pkg: &Package) -> Result<()> {
let name = &pkg.name;
let is_default_source = pkg.source.is_default();
let pkg = toml::to_string_pretty(pkg)
.context("failed to serialize package")?
.parse::<toml_edit::DocumentMut>()
.context("failed to serialized package")?;
match &mut self.doc["pkgs"][name] {
item @ toml_edit::Item::None => {
let mut table = toml_edit::table();
for (k, v) in pkg.as_table().iter() {
if k == "source" && is_default_source {
continue;
}
table[k] = v.clone();
}
*item = table;
}
_ => bail!("package with name `{name}` already exists"),
}
Ok(())
}
pub fn contains(&mut self, name: &str) -> bool {
self.doc
.get("pkgs")
.and_then(|pkgs| pkgs.get(name))
.is_some()
}
}