summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCanop <cano.petrole@gmail.com>2019-02-21 09:44:22 +0100
committerCanop <cano.petrole@gmail.com>2019-02-21 09:44:22 +0100
commit433f5bc2aa5c0c9f6a7cdc247c7a74fe33d9ce79 (patch)
tree00989ea690ab7aad87f2f6e3ea82391fce6c0b63
parent8258d419780c08b23cd2bdcc24ff6fbbcb83273b (diff)
fix exernal exec launch failing (not from_shell)
-rw-r--r--src/file_sizes.rs40
-rw-r--r--src/tree_views.rs2
-rw-r--r--src/verbs.rs27
3 files changed, 44 insertions, 25 deletions
diff --git a/src/file_sizes.rs b/src/file_sizes.rs
index 76d38ee..5d9a07d 100644
--- a/src/file_sizes.rs
+++ b/src/file_sizes.rs
@@ -36,9 +36,9 @@ impl Size {
/// If the lifetime expires before complete computation, None is returned.
pub fn from_dir(path: &Path, tl: &TaskLifetime) -> Option<Size> {
lazy_static! {
- static ref size_cache_mutex: Mutex<HashMap<PathBuf, Size>> = Mutex::new(HashMap::new());
+ static ref SIZE_CACHE_MUTEX: Mutex<HashMap<PathBuf, Size>> = Mutex::new(HashMap::new());
}
- let mut size_cache = size_cache_mutex.lock().unwrap();
+ let mut size_cache = SIZE_CACHE_MUTEX.lock().unwrap();
if let Some(s) = size_cache.get(path) {
return Some(*s);
}
@@ -47,12 +47,15 @@ impl Size {
let inodes = Arc::new(Mutex::new(HashSet::<u64>::new())); // to avoid counting twice an inode
let size = Arc::new(AtomicUsize::new(0));
+ // this MPMC channel contains the directory paths which must be handled
let (dirs_sender, dirs_receiver) = unbounded();
+
// busy is the number of directories which are either being processed or queued
// We use this count to determine when threads can stop waiting for tasks
let busy = Arc::new(AtomicIsize::new(0));
busy.fetch_add(1, Ordering::Relaxed);
dirs_sender.send(Some(PathBuf::from(path))).unwrap();
+
let wg = WaitGroup::new();
let period = Duration::from_micros(50);
for _ in 0..8 {
@@ -67,31 +70,26 @@ impl Size {
let o = dirs_receiver.recv_timeout(period);
if let Ok(Some(open_dir)) = o {
if let Ok(entries) = fs::read_dir(&open_dir) {
- for e in entries {
- if let Ok(e) = e {
- if let Ok(md) = e.metadata() {
- if md.is_dir() {
- busy.fetch_add(1, Ordering::Relaxed);
- dirs_sender.send(Some(e.path())).unwrap();
- } else if md.nlink() > 1 {
- let mut inodes = inodes.lock().unwrap();
- if !inodes.insert(md.ino()) {
- // it was already in the set
- continue; // let's not add the size
- }
+ for e in entries.flatten() {
+ if let Ok(md) = e.metadata() {
+ if md.is_dir() {
+ busy.fetch_add(1, Ordering::Relaxed);
+ dirs_sender.send(Some(e.path())).unwrap();
+ } else if md.nlink() > 1 {
+ let mut inodes = inodes.lock().unwrap();
+ if !inodes.insert(md.ino()) {
+ // it was already in the set
+ continue; // let's not add the size
}
- size.fetch_add(md.len() as usize, Ordering::Relaxed);
}
+ size.fetch_add(md.len() as usize, Ordering::Relaxed);
}
}
}
busy.fetch_sub(1, Ordering::Relaxed);
dirs_sender.send(None).unwrap();
- } else {
- let busy_count = busy.load(Ordering::Relaxed);
- if busy_count < 1 {
- break;
- }
+ } else if busy.load(Ordering::Relaxed) < 1 {
+ break;
}
if tl.is_expired() {
break;
@@ -124,7 +122,7 @@ impl Size {
}
format!("{}{}", v, &SIZE_NAMES[i])
}
- pub fn discreet_ratio(self, max: Size, r: u64) -> u64 {
+ pub fn discrete_ratio(self, max: Size, r: u64) -> u64 {
if max.0 == 0 || self.0 == 0 {
0
} else {
diff --git a/src/tree_views.rs b/src/tree_views.rs
index 7002cf8..7cb63ad 100644
--- a/src/tree_views.rs
+++ b/src/tree_views.rs
@@ -147,7 +147,7 @@ impl TreeView for Screen {
fn write_line_size(&mut self, line: &TreeLine, total_size: Size) -> io::Result<()> {
if let Some(s) = line.size {
- let dr: usize = s.discreet_ratio(total_size, 8) as usize;
+ let dr: usize = s.discrete_ratio(total_size, 8) as usize;
let s: Vec<char> = s.to_string().chars().collect();
write!(
self.stdout,
diff --git a/src/verbs.rs b/src/verbs.rs
index 61786d4..357d4cb 100644
--- a/src/verbs.rs
+++ b/src/verbs.rs
@@ -69,14 +69,34 @@ impl Verb {
} else if self.exec_pattern.starts_with(':') {
self.description.to_string()
} else {
- self.exec_token(&path).join(" ")
+ self.shell_exec_string(&path)
}
}
+ // build the token which can be used to launch en executable
pub fn exec_token(&self, path: &Path) -> Vec<String> {
self.exec_pattern
.split_whitespace()
.map(|t| {
if t == "{file}" {
+ path.to_string_lossy().to_string()
+ } else if t == "{directory}" {
+ let mut path = path;
+ if !path.is_dir() {
+ path = path.parent().unwrap();
+ }
+ path.to_string_lossy().to_string()
+ } else {
+ t.to_string()
+ }
+ })
+ .collect()
+ }
+ // build a shell compatible command, with escapings
+ pub fn shell_exec_string(&self, path: &Path) -> String {
+ self.exec_pattern
+ .split_whitespace()
+ .map(|t| {
+ if t == "{file}" {
external::escape_for_shell(path)
} else if t == "{directory}" {
let mut path = path;
@@ -88,7 +108,8 @@ impl Verb {
t.to_string()
}
})
- .collect()
+ .collect::<Vec<String>>()
+ .join(" ")
}
// build the cmd result for a verb defined with an exec pattern.
// Calling this function on a built-in doesn't make sense
@@ -98,7 +119,7 @@ impl Verb {
// new version of the br function: the whole command is exported
// in the passed file
let f = OpenOptions::new().append(true).open(export_path)?;
- writeln!(&f, "{}", self.exec_token(path).join(" "))?;
+ writeln!(&f, "{}", self.shell_exec_string(path))?;
AppStateCmdResult::Quit
} else if let Some(ref export_path) = con.launch_args.file_export_path {
// old version of the br function: only the file is exported