mirror of
https://github.com/sxyazi/yazi.git
synced 2026-07-21 23:01:05 +00:00
fix: introduce own CWD instead of chdir to avoid potential race conditions (#2008)
This commit is contained in:
parent
adb1426539
commit
8ec944dbd3
17 changed files with 106 additions and 47 deletions
45
Cargo.lock
generated
45
Cargo.lock
generated
|
|
@ -127,6 +127,12 @@ version = "1.4.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223"
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457"
|
||||
|
||||
[[package]]
|
||||
name = "arg_enum_proc_macro"
|
||||
version = "0.3.4"
|
||||
|
|
@ -327,9 +333,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.2"
|
||||
version = "1.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc"
|
||||
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
|
||||
dependencies = [
|
||||
"jobserver",
|
||||
"libc",
|
||||
|
|
@ -1349,9 +1355,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.74"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
|
|
@ -1882,9 +1888,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "png"
|
||||
version = "0.17.14"
|
||||
version = "0.17.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52f9d46a34a05a6a57566bc2bfae066ef07585a6e3fa30fbbdff5936380623f0"
|
||||
checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"crc32fast",
|
||||
|
|
@ -2766,9 +2772,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "trash"
|
||||
version = "5.2.0"
|
||||
version = "5.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "defe1fdd4232e407b312377885a2c5396764972bddad87baf304753374a1bfc8"
|
||||
checksum = "a8e5ca62c20366b4685e3e41fba17bc7c9bbdcb82e65a89d6fda2ceea5fffd2f"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"libc",
|
||||
|
|
@ -2776,6 +2782,7 @@ dependencies = [
|
|||
"objc2",
|
||||
"objc2-foundation",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"scopeguard",
|
||||
"urlencoding",
|
||||
"windows",
|
||||
|
|
@ -2989,9 +2996,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.97"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
|
|
@ -3000,13 +3007,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.97"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
|
|
@ -3015,9 +3021,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.97"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
|
|
@ -3025,9 +3031,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.97"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
@ -3038,9 +3044,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.97"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
|
||||
[[package]]
|
||||
name = "weezl"
|
||||
|
|
@ -3515,6 +3521,7 @@ name = "yazi-fs"
|
|||
version = "0.3.3"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
"bitflags 2.6.0",
|
||||
"dirs",
|
||||
"futures",
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub(crate) struct Chafa;
|
|||
|
||||
impl Chafa {
|
||||
pub(crate) async fn image_show(path: &Path, max: Rect) -> Result<Rect> {
|
||||
let output = Command::new("chafa")
|
||||
let child = Command::new("chafa")
|
||||
.args([
|
||||
"-f",
|
||||
"symbols",
|
||||
|
|
@ -32,9 +32,9 @@ impl Chafa {
|
|||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
.kill_on_drop(true)
|
||||
.output()
|
||||
.await?;
|
||||
.spawn()?;
|
||||
|
||||
let output = child.wait_with_output().await?;
|
||||
if !output.status.success() {
|
||||
bail!("chafa failed with status: {}", output.status);
|
||||
} else if output.stdout.is_empty() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use std::{collections::HashSet, ffi::OsString, path::PathBuf};
|
||||
|
||||
use serde::Serialize;
|
||||
use yazi_fs::{Xdg, current_cwd, expand_path};
|
||||
use yazi_fs::{CWD, Xdg, expand_path};
|
||||
|
||||
#[derive(Debug, Default, Serialize)]
|
||||
pub struct Boot {
|
||||
|
|
@ -20,7 +20,7 @@ pub struct Boot {
|
|||
impl Boot {
|
||||
fn parse_entries(entries: &[PathBuf]) -> (Vec<PathBuf>, Vec<OsString>) {
|
||||
if entries.is_empty() {
|
||||
return (vec![current_cwd().unwrap()], vec![OsString::new()]);
|
||||
return (vec![CWD.load().to_path_buf()], vec![OsString::new()]);
|
||||
}
|
||||
|
||||
let mut cwds = Vec::with_capacity(entries.len());
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use clap::Parser;
|
|||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
yazi_shared::init();
|
||||
yazi_fs::init();
|
||||
|
||||
if std::env::args_os().nth(1).is_some_and(|s| s == "-V" || s == "--version") {
|
||||
println!(
|
||||
|
|
|
|||
|
|
@ -12,11 +12,11 @@ impl Git {
|
|||
}
|
||||
|
||||
pub(super) async fn fetch(path: &Path) -> Result<()> {
|
||||
Self::exec(|c| c.current_dir(path).arg("fetch")).await
|
||||
Self::exec(|c| c.arg("fetch").current_dir(path)).await
|
||||
}
|
||||
|
||||
pub(super) async fn checkout(path: &Path, rev: &str) -> Result<()> {
|
||||
Self::exec(|c| c.current_dir(path).args(["checkout", rev])).await
|
||||
Self::exec(|c| c.args(["checkout", rev]).current_dir(path)).await
|
||||
}
|
||||
|
||||
pub(super) async fn pull(path: &Path) -> Result<()> {
|
||||
|
|
@ -27,8 +27,8 @@ impl Git {
|
|||
|
||||
pub(super) async fn hash(path: &Path) -> Result<String> {
|
||||
let output = Command::new("git")
|
||||
.current_dir(path)
|
||||
.args(["rev-parse", "--short", "HEAD"])
|
||||
.current_dir(path)
|
||||
.output()
|
||||
.await
|
||||
.context("Failed to get current revision")?;
|
||||
|
|
|
|||
|
|
@ -1,16 +1,15 @@
|
|||
use std::{env, path::MAIN_SEPARATOR};
|
||||
use std::path::MAIN_SEPARATOR;
|
||||
|
||||
use crossterm::{execute, terminal::SetTitle};
|
||||
use yazi_config::MANAGER;
|
||||
use yazi_fs::CWD;
|
||||
use yazi_shared::event::CmdCow;
|
||||
|
||||
use crate::{manager::Manager, tasks::Tasks};
|
||||
|
||||
impl Manager {
|
||||
pub fn refresh(&mut self, _: CmdCow, tasks: &Tasks) {
|
||||
env::set_current_dir(self.cwd()).ok();
|
||||
env::set_var("PWD", self.cwd());
|
||||
|
||||
CWD.set(self.cwd());
|
||||
if !MANAGER.title_format.is_empty() {
|
||||
execute!(std::io::stderr(), SetTitle(self.title())).ok();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ async fn main() -> anyhow::Result<()> {
|
|||
|
||||
yazi_shared::init();
|
||||
|
||||
yazi_fs::init();
|
||||
|
||||
yazi_config::init()?;
|
||||
|
||||
yazi_adapter::init()?;
|
||||
|
|
|
|||
|
|
@ -14,12 +14,13 @@ yazi-shared = { path = "../yazi-shared", version = "0.3.3" }
|
|||
|
||||
# External dependencies
|
||||
anyhow = { workspace = true }
|
||||
arc-swap = "1.7.1"
|
||||
bitflags = { workspace = true }
|
||||
dirs = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
regex = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
|
||||
[target."cfg(unix)".dependencies]
|
||||
libc = { workspace = true }
|
||||
|
|
|
|||
35
yazi-fs/src/cwd.rs
Normal file
35
yazi-fs/src/cwd.rs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
use std::{ops::Deref, path::PathBuf, sync::Arc};
|
||||
|
||||
use arc_swap::ArcSwap;
|
||||
use yazi_shared::{RoCell, url::Url};
|
||||
|
||||
pub static CWD: RoCell<Cwd> = RoCell::new();
|
||||
|
||||
pub struct Cwd {
|
||||
inner: ArcSwap<Url>,
|
||||
}
|
||||
|
||||
impl Deref for Cwd {
|
||||
type Target = ArcSwap<Url>;
|
||||
|
||||
fn deref(&self) -> &Self::Target { &self.inner }
|
||||
}
|
||||
|
||||
impl Default for Cwd {
|
||||
fn default() -> Self {
|
||||
let p = std::env::var_os("PWD")
|
||||
.map(PathBuf::from)
|
||||
.filter(|p| p.is_absolute())
|
||||
.or_else(|| std::env::current_dir().ok())
|
||||
.expect("failed to get current working directory");
|
||||
|
||||
Self { inner: ArcSwap::new(Arc::new(Url::from(p))) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Cwd {
|
||||
pub fn set(&self, url: &Url) {
|
||||
self.inner.store(Arc::new(url.clone()));
|
||||
std::env::set_var("PWD", self.inner.load().as_ref());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +1,5 @@
|
|||
#![allow(clippy::if_same_then_else, clippy::option_map_unit_fn)]
|
||||
|
||||
yazi_macro::mod_flat!(cha file files filter fns op path sorter sorting stage step xdg);
|
||||
yazi_macro::mod_flat!(cha cwd file files filter fns op path sorter sorting stage step xdg);
|
||||
|
||||
pub fn init() { CWD.init(<_>::default()); }
|
||||
|
|
|
|||
|
|
@ -3,12 +3,7 @@ use std::{borrow::Cow, env, ffi::OsString, future::Future, io, path::{Component,
|
|||
use tokio::fs;
|
||||
use yazi_shared::url::{Loc, Url};
|
||||
|
||||
pub fn current_cwd() -> Option<PathBuf> {
|
||||
env::var_os("PWD")
|
||||
.map(PathBuf::from)
|
||||
.filter(|p| p.is_absolute())
|
||||
.or_else(|| env::current_dir().ok())
|
||||
}
|
||||
use crate::CWD;
|
||||
|
||||
#[inline]
|
||||
pub fn clean_path(path: impl AsRef<Path>) -> PathBuf { _clean_path(path.as_ref()) }
|
||||
|
|
@ -65,10 +60,8 @@ fn _expand_path(p: &Path) -> PathBuf {
|
|||
clean_path(dirs::home_dir().unwrap_or_default().join(rest))
|
||||
} else if p.is_absolute() {
|
||||
clean_path(p)
|
||||
} else if let Some(cwd) = current_cwd() {
|
||||
clean_path(cwd.join(p))
|
||||
} else {
|
||||
clean_path(p)
|
||||
clean_path(CWD.load().join(p))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ impl Clipboard {
|
|||
use std::os::unix::prelude::OsStringExt;
|
||||
|
||||
use tokio::process::Command;
|
||||
use yazi_fs::CWD;
|
||||
use yazi_shared::in_ssh_connection;
|
||||
|
||||
if in_ssh_connection() {
|
||||
|
|
@ -30,7 +31,13 @@ impl Clipboard {
|
|||
];
|
||||
|
||||
for (bin, args) in all {
|
||||
let Ok(output) = Command::new(bin).args(args).kill_on_drop(true).output().await else {
|
||||
let Ok(output) = Command::new(bin)
|
||||
.args(args)
|
||||
.current_dir(CWD.load().as_ref())
|
||||
.kill_on_drop(true)
|
||||
.output()
|
||||
.await
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
if output.status.success() {
|
||||
|
|
@ -58,6 +65,7 @@ impl Clipboard {
|
|||
|
||||
use crossterm::execute;
|
||||
use tokio::{io::AsyncWriteExt, process::Command};
|
||||
use yazi_fs::CWD;
|
||||
|
||||
s.as_ref().clone_into(&mut self.content.lock());
|
||||
execute!(BufWriter::new(stderr()), osc52::SetClipboard::new(s.as_ref())).ok();
|
||||
|
|
@ -72,6 +80,7 @@ impl Clipboard {
|
|||
for (bin, args) in all {
|
||||
let cmd = Command::new(bin)
|
||||
.args(args)
|
||||
.current_dir(CWD.load().as_ref())
|
||||
.stdin(Stdio::piped())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
|
|
|
|||
3
yazi-plugin/src/external/fd.rs
vendored
3
yazi-plugin/src/external/fd.rs
vendored
|
|
@ -2,7 +2,7 @@ use std::process::Stdio;
|
|||
|
||||
use anyhow::Result;
|
||||
use tokio::{io::{AsyncBufReadExt, BufReader}, process::{Child, Command}, sync::mpsc::{self, UnboundedReceiver}};
|
||||
use yazi_fs::File;
|
||||
use yazi_fs::{CWD, File};
|
||||
use yazi_shared::url::Url;
|
||||
|
||||
pub struct FdOpt {
|
||||
|
|
@ -37,6 +37,7 @@ fn spawn(program: &str, opt: &FdOpt) -> std::io::Result<Child> {
|
|||
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
|
||||
.args(&opt.args)
|
||||
.arg(&opt.subject)
|
||||
.current_dir(CWD.load().as_ref())
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
|
|
|
|||
2
yazi-plugin/src/external/rg.rs
vendored
2
yazi-plugin/src/external/rg.rs
vendored
|
|
@ -14,11 +14,11 @@ pub struct RgOpt {
|
|||
|
||||
pub fn rg(opt: RgOpt) -> Result<UnboundedReceiver<File>> {
|
||||
let mut child = Command::new("rg")
|
||||
.current_dir(&opt.cwd)
|
||||
.args(["--color=never", "--files-with-matches", "--smart-case"])
|
||||
.arg(if opt.hidden { "--hidden" } else { "--no-hidden" })
|
||||
.args(opt.args)
|
||||
.arg(opt.subject)
|
||||
.current_dir(&opt.cwd)
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::null())
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::process::Stdio;
|
|||
|
||||
use mlua::{AnyUserData, ExternalError, IntoLuaMulti, Lua, Table, UserData, Value};
|
||||
use tokio::process::{ChildStderr, ChildStdin, ChildStdout};
|
||||
use yazi_fs::CWD;
|
||||
|
||||
use super::{Child, output::Output};
|
||||
use crate::{Error, process::Status};
|
||||
|
|
@ -18,7 +19,12 @@ impl Command {
|
|||
pub fn install(lua: &Lua) -> mlua::Result<()> {
|
||||
let new = lua.create_function(|_, (_, program): (Table, String)| {
|
||||
let mut inner = tokio::process::Command::new(program);
|
||||
inner.kill_on_drop(true).stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null());
|
||||
inner
|
||||
.current_dir(CWD.load().as_ref())
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null());
|
||||
|
||||
Ok(Self { inner })
|
||||
})?;
|
||||
|
|
|
|||
|
|
@ -30,4 +30,4 @@ tracing = { workspace = true }
|
|||
libc = { workspace = true }
|
||||
|
||||
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||
trash = "5.2.0"
|
||||
trash = "5.2.1"
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ use std::{ffi::OsString, process::Stdio};
|
|||
|
||||
use anyhow::Result;
|
||||
use tokio::process::{Child, Command};
|
||||
use yazi_fs::CWD;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct ShellOpt {
|
||||
|
|
@ -29,6 +30,7 @@ pub fn shell(opt: ShellOpt) -> Result<Child> {
|
|||
return Ok(unsafe {
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
.current_dir(CWD.load().as_ref())
|
||||
.stdin(opt.stdio())
|
||||
.stdout(opt.stdio())
|
||||
.stderr(opt.stdio())
|
||||
|
|
@ -50,6 +52,7 @@ pub fn shell(opt: ShellOpt) -> Result<Child> {
|
|||
Command::new("cmd.exe")
|
||||
.raw_arg("/C")
|
||||
.raw_arg(parser::parse(&opt.cmd, &opt.args))
|
||||
.current_dir(CWD.load().as_ref())
|
||||
.stdin(opt.stdio())
|
||||
.stdout(opt.stdio())
|
||||
.stderr(opt.stdio())
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue