mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-25 08:41:05 +00:00
fix: sync config with state when do ya pack -i or -u
This commit is contained in:
parent
ea75fe2b5c
commit
14890b0ec1
2 changed files with 130 additions and 14 deletions
|
|
@ -1,34 +1,46 @@
|
||||||
use anyhow::{Context, Result, bail};
|
use anyhow::{Context, Result, bail};
|
||||||
use tokio::fs;
|
use tokio::fs::{self, remove_dir_all};
|
||||||
use yazi_shared::{Xdg, fs::{copy_dir_all, maybe_exists, must_exists}};
|
use yazi_shared::{Xdg, fs::{copy_dir_all, maybe_exists, must_exists, remove_dir_clean}};
|
||||||
|
|
||||||
use super::Package;
|
use super::{DiffAction, Package};
|
||||||
|
use crate::package::Git;
|
||||||
|
|
||||||
const TRACKER: &str = "DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY";
|
const TRACKER: &str = "DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY";
|
||||||
|
|
||||||
impl Package {
|
impl Package {
|
||||||
pub(super) async fn deploy(&mut self) -> Result<()> {
|
pub(super) async fn deploy(&mut self) -> Result<()> {
|
||||||
let Some(name) = self.name().map(ToOwned::to_owned) else { bail!("Invalid package url") };
|
let Some(name) = self.name().map(ToOwned::to_owned) else { bail!("Invalid package url") };
|
||||||
let from = self.local().join(&self.child);
|
let origin = self.local().join(&self.child);
|
||||||
|
|
||||||
self.header("Deploying package `{name}`")?;
|
self.header("Deploying package `{name}`")?;
|
||||||
self.is_flavor = maybe_exists(&from.join("flavor.toml")).await;
|
self.is_flavor = maybe_exists(&origin.join("flavor.toml")).await;
|
||||||
let to = if self.is_flavor {
|
let dest = if self.is_flavor {
|
||||||
Xdg::config_dir().join(format!("flavors/{name}"))
|
Xdg::config_dir().join(format!("flavors/{name}"))
|
||||||
} else {
|
} else {
|
||||||
Xdg::config_dir().join(format!("plugins/{name}"))
|
Xdg::config_dir().join(format!("plugins/{name}"))
|
||||||
};
|
};
|
||||||
|
|
||||||
let tracker = to.join(TRACKER);
|
let tracker = dest.join(TRACKER);
|
||||||
if maybe_exists(&to).await && !must_exists(&tracker).await {
|
if maybe_exists(&dest).await && !must_exists(&tracker).await {
|
||||||
bail!(
|
bail!(
|
||||||
"A user package with the same name `{name}` already exists.
|
"A user package with the same name `{name}` already exists.
|
||||||
For safety, please manually delete it from your plugin/flavor directory and re-run the command."
|
For safety, please manually delete it from your plugin/flavor directory and re-run the command."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::create_dir_all(&to).await?;
|
fs::create_dir_all(&dest).await?;
|
||||||
fs::write(tracker, []).await?;
|
|
||||||
|
let mut dirs = &["assets"][..];
|
||||||
|
let mut diff_actions = vec![];
|
||||||
|
if tracker.exists() {
|
||||||
|
let prev_rev = String::from_utf8(fs::read(&tracker).await?)?;
|
||||||
|
|
||||||
|
if prev_rev != self.rev {
|
||||||
|
diff_actions = Git::diff(&self.local().join(&self.child), &prev_rev, dirs).await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::write(tracker, &self.rev.trim_start_matches('=')).await?;
|
||||||
|
|
||||||
let files = if self.is_flavor {
|
let files = if self.is_flavor {
|
||||||
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
|
&["flavor.toml", "tmtheme.xml", "README.md", "preview.png", "LICENSE", "LICENSE-tmtheme"][..]
|
||||||
|
|
@ -36,20 +48,61 @@ For safety, please manually delete it from your plugin/flavor directory and re-r
|
||||||
&["init.lua", "README.md", "LICENSE"][..]
|
&["init.lua", "README.md", "LICENSE"][..]
|
||||||
};
|
};
|
||||||
|
|
||||||
let dirs = &["assets"][..];
|
|
||||||
|
|
||||||
for file in files {
|
for file in files {
|
||||||
let (from, to) = (from.join(file), to.join(file));
|
let (from, to) = (origin.join(file), dest.join(file));
|
||||||
|
|
||||||
fs::copy(&from, &to)
|
fs::copy(&from, &to)
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?;
|
.with_context(|| format!("failed to copy `{}` to `{}`", from.display(), to.display()))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for action in diff_actions.as_slice() {
|
||||||
|
match action {
|
||||||
|
DiffAction::Add { file } => {
|
||||||
|
let (from, to) = (origin.join(file), dest.join(file));
|
||||||
|
fs::create_dir_all(&to).await?;
|
||||||
|
fs::copy(&from, &to).await.with_context(|| {
|
||||||
|
format!("failed to copy `{}` to `{}`", from.display(), to.display())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
DiffAction::Delete { file } => {
|
||||||
|
let file = dest.join(file);
|
||||||
|
fs::remove_file(&file)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to remove `{}`", file.display()))?;
|
||||||
|
}
|
||||||
|
DiffAction::Rename { old, new } => {
|
||||||
|
let (from, to) = (dest.join(old), dest.join(new));
|
||||||
|
fs::create_dir_all(&to).await?;
|
||||||
|
fs::rename(&from, &to).await.with_context(|| {
|
||||||
|
format!("failed to rename `{}` to `{}`", from.display(), to.display())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
DiffAction::Copy { old, new } => {
|
||||||
|
let (from, to) = (dest.join(old), dest.join(new));
|
||||||
|
fs::create_dir_all(&to).await?;
|
||||||
|
fs::copy(&from, &to).await.with_context(|| {
|
||||||
|
format!("failed to copy `{}` to `{}`", from.display(), to.display())
|
||||||
|
})?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_dir_clean(&dest).await;
|
||||||
|
|
||||||
|
if !diff_actions.is_empty() {
|
||||||
|
dirs = &[];
|
||||||
|
}
|
||||||
|
|
||||||
for dir in dirs {
|
for dir in dirs {
|
||||||
let (from, to) = (from.join(dir), to.join(dir));
|
let (from, to) = (origin.join(dir), dest.join(dir));
|
||||||
|
|
||||||
if !from.exists() {
|
if !from.exists() {
|
||||||
|
if to.exists() {
|
||||||
|
remove_dir_all(&to)
|
||||||
|
.await
|
||||||
|
.with_context(|| format!("failed to prune no-longer exist folder {}", to.display()))?;
|
||||||
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,13 @@ use yazi_shared::strip_trailing_newline;
|
||||||
|
|
||||||
pub(super) struct Git;
|
pub(super) struct Git;
|
||||||
|
|
||||||
|
pub(super) enum DiffAction {
|
||||||
|
Add { file: String },
|
||||||
|
Delete { file: String },
|
||||||
|
Rename { old: String, new: String },
|
||||||
|
Copy { old: String, new: String },
|
||||||
|
}
|
||||||
|
|
||||||
impl Git {
|
impl Git {
|
||||||
pub(super) async fn clone(url: &str, path: &Path) -> Result<()> {
|
pub(super) async fn clone(url: &str, path: &Path) -> Result<()> {
|
||||||
Self::exec(|c| c.args(["clone", url]).arg(path)).await
|
Self::exec(|c| c.args(["clone", url]).arg(path)).await
|
||||||
|
|
@ -42,6 +49,48 @@ impl Git {
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) async fn diff(path: &Path, rev: &str, filter: &[&str]) -> Result<Vec<DiffAction>> {
|
||||||
|
let mut command = Command::new("git");
|
||||||
|
command.current_dir(path).args(["diff", "-M100", "-C100", rev, "origin/HEAD", "--name-status"]);
|
||||||
|
if !filter.is_empty() {
|
||||||
|
command.arg("--");
|
||||||
|
}
|
||||||
|
for f in filter {
|
||||||
|
command.arg(*f);
|
||||||
|
}
|
||||||
|
let output = command.output().await.context("Failed to run git diff")?;
|
||||||
|
|
||||||
|
if !output.status.success() {
|
||||||
|
bail!("git diff failed: {}", output.status);
|
||||||
|
}
|
||||||
|
|
||||||
|
let stdout = String::from_utf8(output.stdout).context("Failed to parse git diff output")?;
|
||||||
|
let mut diff_actions = Vec::new();
|
||||||
|
|
||||||
|
for line in stdout.lines() {
|
||||||
|
let parts: Vec<&str> = line.split_whitespace().collect();
|
||||||
|
if parts.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match parts[0] {
|
||||||
|
"A" | "M" if parts.len() == 2 => {
|
||||||
|
diff_actions.push(DiffAction::Add { file: parts[1].to_string() })
|
||||||
|
}
|
||||||
|
"D" if parts.len() == 2 => {
|
||||||
|
diff_actions.push(DiffAction::Delete { file: parts[1].to_string() })
|
||||||
|
}
|
||||||
|
"R100" if parts.len() == 3 => diff_actions
|
||||||
|
.push(DiffAction::Rename { old: parts[1].to_string(), new: parts[2].to_string() }),
|
||||||
|
"C100" if parts.len() == 3 => diff_actions
|
||||||
|
.push(DiffAction::Copy { old: parts[1].to_string(), new: parts[2].to_string() }),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(diff_actions)
|
||||||
|
}
|
||||||
|
|
||||||
async fn exec(f: impl FnOnce(&mut Command) -> &mut Command) -> Result<()> {
|
async fn exec(f: impl FnOnce(&mut Command) -> &mut Command) -> Result<()> {
|
||||||
let status =
|
let status =
|
||||||
f(&mut Command::new("git")).status().await.context("Failed to execute `git` command")?;
|
f(&mut Command::new("git")).status().await.context("Failed to execute `git` command")?;
|
||||||
|
|
@ -53,3 +102,17 @@ impl Git {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl DiffAction {
|
||||||
|
pub(super) fn is_in(&self, dirs: &[&str]) -> bool {
|
||||||
|
for dir in dirs {
|
||||||
|
match self {
|
||||||
|
DiffAction::Add { file } => return file.contains(dir),
|
||||||
|
DiffAction::Delete { file } => return file.contains(dir),
|
||||||
|
DiffAction::Rename { old: _, new } => return new.contains(dir),
|
||||||
|
DiffAction::Copy { old: _, new } => return new.contains(dir),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue