diff options
author | Canop <cano.petrole@gmail.com> | 2019-02-21 09:44:22 +0100 |
---|---|---|
committer | Canop <cano.petrole@gmail.com> | 2019-02-21 09:44:22 +0100 |
commit | 433f5bc2aa5c0c9f6a7cdc247c7a74fe33d9ce79 (patch) | |
tree | 00989ea690ab7aad87f2f6e3ea82391fce6c0b63 | |
parent | 8258d419780c08b23cd2bdcc24ff6fbbcb83273b (diff) |
fix exernal exec launch failing (not from_shell)
-rw-r--r-- | src/file_sizes.rs | 40 | ||||
-rw-r--r-- | src/tree_views.rs | 2 | ||||
-rw-r--r-- | src/verbs.rs | 27 |
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 |