mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
187 lines
4.1 KiB
Rust
187 lines
4.1 KiB
Rust
use std::{path::PathBuf, str::FromStr};
|
|
|
|
use anyhow::{Context, Result, bail};
|
|
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
|
use yazi_fs::{Xdg, provider::{Provider, local::Local}};
|
|
use yazi_macro::{ok_or_not_found, outln};
|
|
|
|
use super::Dependency;
|
|
|
|
#[derive(Default)]
|
|
pub(crate) struct Package {
|
|
pub(crate) plugins: Vec<Dependency>,
|
|
pub(crate) flavors: Vec<Dependency>,
|
|
}
|
|
|
|
impl Package {
|
|
pub(crate) async fn load() -> Result<Self> {
|
|
let s = ok_or_not_found!(Local::regular(&Self::toml()).read_to_string().await);
|
|
Ok(toml::from_str(&s)?)
|
|
}
|
|
|
|
pub(crate) async fn add_many(&mut self, uses: &[String]) -> Result<()> {
|
|
for u in uses {
|
|
let r = self.add(u).await;
|
|
self.save().await?;
|
|
r?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn delete_many(&mut self, uses: &[String], discard: bool) -> Result<()> {
|
|
for u in uses {
|
|
let r = self.delete(u, discard).await;
|
|
self.save().await?;
|
|
r?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn install(&mut self, discard: bool) -> Result<()> {
|
|
macro_rules! go {
|
|
($dep:expr) => {
|
|
let r = $dep.install(discard).await;
|
|
self.save().await?;
|
|
r?;
|
|
};
|
|
}
|
|
|
|
for i in 0..self.plugins.len() {
|
|
go!(self.plugins[i]);
|
|
}
|
|
for i in 0..self.flavors.len() {
|
|
go!(self.flavors[i]);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) async fn upgrade_many(&mut self, uses: &[String], discard: bool) -> Result<()> {
|
|
macro_rules! go {
|
|
($dep:expr) => {
|
|
if uses.is_empty() || uses.contains(&$dep.r#use) {
|
|
let r = $dep.upgrade(discard).await;
|
|
self.save().await?;
|
|
r?;
|
|
}
|
|
};
|
|
}
|
|
|
|
for i in 0..self.plugins.len() {
|
|
go!(self.plugins[i]);
|
|
}
|
|
for i in 0..self.flavors.len() {
|
|
go!(self.flavors[i]);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn print(&self) -> Result<()> {
|
|
outln!("Plugins:")?;
|
|
for d in &self.plugins {
|
|
if d.rev.is_empty() {
|
|
outln!("\t{}", d.r#use)?;
|
|
} else {
|
|
outln!("\t{} ({})", d.r#use, d.rev)?;
|
|
}
|
|
}
|
|
|
|
outln!("Flavors:")?;
|
|
for d in &self.flavors {
|
|
if d.rev.is_empty() {
|
|
outln!("\t{}", d.r#use)?;
|
|
} else {
|
|
outln!("\t{} ({})", d.r#use, d.rev)?;
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
async fn add(&mut self, r#use: &str) -> Result<()> {
|
|
let mut dep = Dependency::from_str(r#use)?;
|
|
if let Some(d) = self.identical(&dep) {
|
|
bail!(
|
|
"{} `{}` already exists in package.toml",
|
|
if d.is_flavor { "Flavor" } else { "Plugin" },
|
|
dep.name
|
|
)
|
|
}
|
|
|
|
dep.add(false).await?;
|
|
if dep.is_flavor {
|
|
self.flavors.push(dep);
|
|
} else {
|
|
self.plugins.push(dep);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
async fn delete(&mut self, r#use: &str, discard: bool) -> Result<()> {
|
|
let Some(dep) = self.identical(&Dependency::from_str(r#use)?).cloned() else {
|
|
bail!("`{}` was not found in package.toml", r#use)
|
|
};
|
|
|
|
dep.delete(discard).await?;
|
|
if dep.is_flavor {
|
|
self.flavors.retain(|d| !d.identical(&dep));
|
|
} else {
|
|
self.plugins.retain(|d| !d.identical(&dep));
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
async fn save(&self) -> Result<()> {
|
|
let s = toml::to_string_pretty(self)?;
|
|
Local::regular(&Self::toml()).write(s).await.context("Failed to write package.toml")
|
|
}
|
|
|
|
fn toml() -> PathBuf { Xdg::config_dir().join("package.toml") }
|
|
|
|
fn identical(&self, other: &Dependency) -> Option<&Dependency> {
|
|
self.plugins.iter().chain(&self.flavors).find(|d| d.identical(other))
|
|
}
|
|
}
|
|
|
|
impl<'de> Deserialize<'de> for Package {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: Deserializer<'de>,
|
|
{
|
|
#[derive(Deserialize)]
|
|
struct Outer {
|
|
#[serde(default)]
|
|
plugin: Shadow,
|
|
#[serde(default)]
|
|
flavor: Shadow,
|
|
}
|
|
#[derive(Default, Deserialize)]
|
|
struct Shadow {
|
|
deps: Vec<Dependency>,
|
|
}
|
|
|
|
let mut outer = Outer::deserialize(deserializer)?;
|
|
outer.flavor.deps.iter_mut().for_each(|d| d.is_flavor = true);
|
|
|
|
Ok(Self { plugins: outer.plugin.deps, flavors: outer.flavor.deps })
|
|
}
|
|
}
|
|
|
|
impl Serialize for Package {
|
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
|
where
|
|
S: Serializer,
|
|
{
|
|
#[derive(Serialize)]
|
|
struct Outer<'a> {
|
|
plugin: Shadow<'a>,
|
|
flavor: Shadow<'a>,
|
|
}
|
|
#[derive(Serialize)]
|
|
struct Shadow<'a> {
|
|
deps: &'a [Dependency],
|
|
}
|
|
|
|
Outer { plugin: Shadow { deps: &self.plugins }, flavor: Shadow { deps: &self.flavors } }
|
|
.serialize(serializer)
|
|
}
|
|
}
|