Compare commits

..

10 Commits

Author SHA1 Message Date
andy.boot 07c228fd08 Fix: depth=0 bug for multiple arguments
https://github.com/bootandy/dust/issues/282
2023-01-05 01:11:16 +00:00
andy.boot c457a295b5 fix: bug where hard links could be double counted
When running:
dust dir_a dir_b

if a file was hard linked in both dir_a and dir_b it would be double
counted.

This fix resolves this by keeping the shared hashmap around between runs
for the second and subsequent arguments.
https://github.com/bootandy/dust/issues/282
2023-01-04 22:22:41 +00:00
andy.boot a91aa62060 clippy: Fix new clippy 2023-01-04 20:08:20 +00:00
andy.boot a7b82f32d7 fix: update use of sysinfo.system
System is now much quicker to start but requires an explicit call
to refresh memory else it deafults to 0 (oops)
2023-01-04 20:08:20 +00:00
Guillaume Gomez 72b811c278 Update sysinfo version to 0.26.7 2023-01-04 19:38:40 +00:00
Phil Clifford b478534b22 added deb-get as installation source 2022-10-24 23:25:13 +01:00
DIRE 2ca7177446 FEATURE: support only directories will be displayed. Flag -D 2022-10-05 23:26:10 +01:00
Collin Styles e858f9e976 Read inputs from stdin when applicable 2022-10-01 11:16:14 +01:00
Collin Styles 0a67191054 Add a direct dependency on the atty crate 2022-10-01 11:16:14 +01:00
andy.boot c363e5ff8b Fix: Only create large stack size if enough memory
Small boxes do not have enough memory to create a large stack

Conversely we want a large stack size for large boxes with a very highly
nested directory structure.

Version: New version
2022-08-31 21:14:56 +01:00
16 changed files with 174 additions and 48 deletions
Generated
+33 -1
View File
@@ -118,6 +118,12 @@ dependencies = [
"toml", "toml",
] ]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.6" version = "0.5.6"
@@ -197,10 +203,11 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
[[package]] [[package]]
name = "du-dust" name = "du-dust"
version = "0.8.3-alpha1" version = "0.8.3"
dependencies = [ dependencies = [
"ansi_term", "ansi_term",
"assert_cmd", "assert_cmd",
"atty",
"clap", "clap",
"clap_complete", "clap_complete",
"config-file", "config-file",
@@ -210,6 +217,7 @@ dependencies = [
"regex", "regex",
"serde", "serde",
"stfu8", "stfu8",
"sysinfo",
"tempfile", "tempfile",
"terminal_size", "terminal_size",
"thousands", "thousands",
@@ -322,6 +330,15 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "ntapi"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc51db7b362b205941f71232e56c625156eb9a929f8cf74a428fd5bc094a4afc"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.13.1" version = "1.13.1"
@@ -518,6 +535,21 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "sysinfo"
version = "0.26.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c375d5fd899e32847b8566e10598d6e9f1d9b55ec6de3cdf9e7da4bdc51371bc"
dependencies = [
"cfg-if",
"core-foundation-sys",
"libc",
"ntapi",
"once_cell",
"rayon",
"winapi",
]
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.3.0" version = "3.3.0"
+3 -1
View File
@@ -1,7 +1,7 @@
[package] [package]
name = "du-dust" name = "du-dust"
description = "A more intuitive version of du" description = "A more intuitive version of du"
version = "0.8.3-alpha1" version = "0.8.3"
authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"] authors = ["bootandy <bootandy@gmail.com>", "nebkor <code@ardent.nebcorp.com>"]
edition = "2021" edition = "2021"
readme = "README.md" readme = "README.md"
@@ -28,6 +28,7 @@ strip = true
[dependencies] [dependencies]
ansi_term = "0.12" ansi_term = "0.12"
atty = "0.2.14"
clap = "3.2.17" clap = "3.2.17"
lscolors = "0.7" lscolors = "0.7"
terminal_size = "0.1" terminal_size = "0.1"
@@ -39,6 +40,7 @@ regex = "1"
config-file = "0.2" config-file = "0.2"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
directories = "4" directories = "4"
sysinfo = "0.26"
[target.'cfg(windows)'.dependencies] [target.'cfg(windows)'.dependencies]
winapi-util = "0.1" winapi-util = "0.1"
+5
View File
@@ -30,6 +30,10 @@ Because I want an easy way to see where my disk is being used.
- `pacstall -I dust-bin` - `pacstall -I dust-bin`
#### [deb-get](https://github.com/wimpysworld/deb-get) (Debian/Ubuntu)
- `deb-get install du-dust`
#### Windows: #### Windows:
- Windows GNU version - works - Windows GNU version - works
@@ -59,6 +63,7 @@ Usage: dust -p (full-path - Show fullpath of the subdirectories)
Usage: dust -s (apparent-size - shows the length of the file as opposed to the amount of disk space it uses) Usage: dust -s (apparent-size - shows the length of the file as opposed to the amount of disk space it uses)
Usage: dust -n 30 (Shows 30 directories instead of the default [default is terminal height]) Usage: dust -n 30 (Shows 30 directories instead of the default [default is terminal height])
Usage: dust -d 3 (Shows 3 levels of subdirectories) Usage: dust -d 3 (Shows 3 levels of subdirectories)
Usage: dust -D (Show only directories (eg dust -D))
Usage: dust -r (reverse order of output) Usage: dust -r (reverse order of output)
Usage: dust -H (si print sizes in powers of 1000 instead of 1024) Usage: dust -H (si print sizes in powers of 1000 instead of 1024)
Usage: dust -X ignore (ignore all files and directories with the name 'ignore') Usage: dust -X ignore (ignore all files and directories with the name 'ignore')
+2
View File
@@ -54,6 +54,8 @@ _dust() {
'(-d --depth)--file_types[show only these file types]' \ '(-d --depth)--file_types[show only these file types]' \
'-H[print sizes in powers of 1000 (e.g., 1.1G)]' \ '-H[print sizes in powers of 1000 (e.g., 1.1G)]' \
'--si[print sizes in powers of 1000 (e.g., 1.1G)]' \ '--si[print sizes in powers of 1000 (e.g., 1.1G)]' \
'-D[Only directories will be displayed.]' \
'--only-dir[Only directories will be displayed.]' \
'*::inputs:' \ '*::inputs:' \
&& ret=0 && ret=0
} }
+2
View File
@@ -60,6 +60,8 @@ Register-ArgumentCompleter -Native -CommandName 'dust' -ScriptBlock {
[CompletionResult]::new('--file_types', 'file_types', [CompletionResultType]::ParameterName, 'show only these file types') [CompletionResult]::new('--file_types', 'file_types', [CompletionResultType]::ParameterName, 'show only these file types')
[CompletionResult]::new('-H', 'H', [CompletionResultType]::ParameterName, 'print sizes in powers of 1000 (e.g., 1.1G)') [CompletionResult]::new('-H', 'H', [CompletionResultType]::ParameterName, 'print sizes in powers of 1000 (e.g., 1.1G)')
[CompletionResult]::new('--si', 'si', [CompletionResultType]::ParameterName, 'print sizes in powers of 1000 (e.g., 1.1G)') [CompletionResult]::new('--si', 'si', [CompletionResultType]::ParameterName, 'print sizes in powers of 1000 (e.g., 1.1G)')
[CompletionResult]::new('-D', 'D', [CompletionResultType]::ParameterName, 'Only directories will be displayed.')
[CompletionResult]::new('--only-dir', 'only-dir', [CompletionResultType]::ParameterName, 'Only directories will be displayed.')
break break
} }
}) })
+1 -1
View File
@@ -19,7 +19,7 @@ _dust() {
case "${cmd}" in case "${cmd}" in
dust) dust)
opts="-h -V -d -n -p -X -x -s -r -c -b -z -f -i -v -e -t -w -H --help --version --depth --number-of-lines --full-paths --ignore-directory --limit-filesystem --apparent-size --reverse --no-colors --no-percent-bars --min-size --skip-total --filecount --ignore_hidden --invert-filter --filter --file_types --terminal_width --si <inputs>..." opts="-h -V -d -n -p -X -x -s -r -c -b -z -f -i -v -e -t -w -H -D --help --version --depth --number-of-lines --full-paths --ignore-directory --limit-filesystem --apparent-size --reverse --no-colors --no-percent-bars --min-size --skip-total --filecount --ignore_hidden --invert-filter --filter --file_types --terminal_width --si --only-dir <inputs>..."
if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") )
return 0 return 0
+2
View File
@@ -57,6 +57,8 @@ set edit:completion:arg-completer[dust] = {|@words|
cand --file_types 'show only these file types' cand --file_types 'show only these file types'
cand -H 'print sizes in powers of 1000 (e.g., 1.1G)' cand -H 'print sizes in powers of 1000 (e.g., 1.1G)'
cand --si 'print sizes in powers of 1000 (e.g., 1.1G)' cand --si 'print sizes in powers of 1000 (e.g., 1.1G)'
cand -D 'Only directories will be displayed.'
cand --only-dir 'Only directories will be displayed.'
} }
] ]
$completions[$command] $completions[$command]
+1
View File
@@ -18,3 +18,4 @@ complete -c dust -s f -l filecount -d 'Directory \'size\' is number of child fil
complete -c dust -s i -l ignore_hidden -d 'Do not display hidden files' complete -c dust -s i -l ignore_hidden -d 'Do not display hidden files'
complete -c dust -s t -l file_types -d 'show only these file types' complete -c dust -s t -l file_types -d 'show only these file types'
complete -c dust -s H -l si -d 'print sizes in powers of 1000 (e.g., 1.1G)' complete -c dust -s H -l si -d 'print sizes in powers of 1000 (e.g., 1.1G)'
complete -c dust -s D -l only-dir -d 'Only directories will be displayed.'
+7 -1
View File
@@ -131,5 +131,11 @@ pub fn build_cli() -> Command<'static> {
.long("si") .long("si")
.help("print sizes in powers of 1000 (e.g., 1.1G)") .help("print sizes in powers of 1000 (e.g., 1.1G)")
) )
.arg(Arg::new("inputs").multiple_occurrences(true).default_value(".")) .arg(Arg::new("inputs").multiple_occurrences(true))
.arg(
Arg::new("only_dir")
.short('D')
.long("only-dir")
.help("Only directories will be displayed."),
)
} }
+4
View File
@@ -19,6 +19,7 @@ pub struct Config {
pub ignore_hidden: Option<bool>, pub ignore_hidden: Option<bool>,
pub iso: Option<bool>, pub iso: Option<bool>,
pub min_size: Option<String>, pub min_size: Option<String>,
pub only_dir: Option<bool>,
} }
impl Config { impl Config {
@@ -61,6 +62,9 @@ impl Config {
size_from_param size_from_param
} }
} }
pub fn get_only_dir(&self, options: &ArgMatches) -> bool {
Some(true) == self.only_dir || options.is_present("only_dir")
}
} }
fn convert_min_size(input: &str, iso: bool) -> Option<usize> { fn convert_min_size(input: &str, iso: bool) -> Option<usize> {
+2 -1
View File
@@ -31,12 +31,13 @@ pub struct WalkData<'a> {
pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: WalkData) -> (Vec<Node>, bool) { pub fn walk_it(dirs: HashSet<PathBuf>, walk_data: WalkData) -> (Vec<Node>, bool) {
let permissions_flag = AtomicBool::new(false); let permissions_flag = AtomicBool::new(false);
let mut inodes = HashSet::new();
let top_level_nodes: Vec<_> = dirs let top_level_nodes: Vec<_> = dirs
.into_iter() .into_iter()
.filter_map(|d| { .filter_map(|d| {
clean_inodes( clean_inodes(
walk(d, &permissions_flag, &walk_data, 0)?, walk(d, &permissions_flag, &walk_data, 0)?,
&mut HashSet::new(), &mut inodes,
walk_data.use_apparent_size, walk_data.use_apparent_size,
) )
}) })
+3 -3
View File
@@ -88,7 +88,7 @@ impl DrawData<'_> {
let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32; let mut num_not_my_bar = (chars_in_bar as i32) - num_bars as i32;
let mut new_bar = "".to_string(); let mut new_bar = "".to_string();
let idx = 5 - min(4, max(1, level)); let idx = 5 - level.clamp(1, 4);
for c in self.percent_bar.chars() { for c in self.percent_bar.chars() {
num_not_my_bar -= 1; num_not_my_bar -= 1;
@@ -141,10 +141,10 @@ pub fn draw_it(
let longest_string_length = let longest_string_length =
find_longest_dir_name(root_node, num_indent_chars, allowed_width, !use_full_path); find_longest_dir_name(root_node, num_indent_chars, allowed_width, !use_full_path);
let max_bar_length = if no_percent_bars || longest_string_length + 7 >= allowed_width as usize { let max_bar_length = if no_percent_bars || longest_string_length + 7 >= allowed_width {
0 0
} else { } else {
allowed_width as usize - longest_string_length - 7 allowed_width - longest_string_length - 7
}; };
let first_size_bar = repeat(BLOCKS[0]).take(max_bar_length).collect(); let first_size_bar = repeat(BLOCKS[0]).take(max_bar_length).collect();
+22 -7
View File
@@ -8,6 +8,7 @@ use std::path::PathBuf;
pub fn get_biggest( pub fn get_biggest(
top_level_nodes: Vec<Node>, top_level_nodes: Vec<Node>,
min_size: Option<usize>, min_size: Option<usize>,
only_dir: bool,
n: usize, n: usize,
depth: usize, depth: usize,
using_a_filter: bool, using_a_filter: bool,
@@ -19,18 +20,25 @@ pub fn get_biggest(
let mut heap = BinaryHeap::new(); let mut heap = BinaryHeap::new();
let number_top_level_nodes = top_level_nodes.len(); let number_top_level_nodes = top_level_nodes.len();
let root = get_new_root(top_level_nodes); let root = get_new_root(top_level_nodes);
let mut allowed_nodes = HashSet::new(); let mut allowed_nodes = HashSet::new();
allowed_nodes.insert(root.name.as_path()); allowed_nodes.insert(root.name.as_path());
heap = add_children(using_a_filter, min_size, &root, depth, heap);
for _ in number_top_level_nodes..n { if number_top_level_nodes > 1 {
heap = add_children(using_a_filter, min_size, only_dir, &root, usize::MAX, heap);
} else {
heap = add_children(using_a_filter, min_size, only_dir, &root, depth, heap);
}
let number_of_lines_in_output = n - number_top_level_nodes;
for _ in 0..number_of_lines_in_output {
let line = heap.pop(); let line = heap.pop();
match line { match line {
Some(line) => { Some(line) => {
allowed_nodes.insert(line.name.as_path()); allowed_nodes.insert(line.name.as_path());
heap = add_children(using_a_filter, min_size, line, depth, heap); heap = add_children(using_a_filter, min_size, only_dir, line, depth, heap);
} }
None => break, None => break,
} }
@@ -41,15 +49,22 @@ pub fn get_biggest(
fn add_children<'a>( fn add_children<'a>(
using_a_filter: bool, using_a_filter: bool,
min_size: Option<usize>, min_size: Option<usize>,
only_dir: bool,
file_or_folder: &'a Node, file_or_folder: &'a Node,
depth: usize, depth: usize,
mut heap: BinaryHeap<&'a Node>, mut heap: BinaryHeap<&'a Node>,
) -> BinaryHeap<&'a Node> { ) -> BinaryHeap<&'a Node> {
if depth > file_or_folder.depth { if depth > file_or_folder.depth {
heap.extend(file_or_folder.children.iter().filter(|c| match min_size { heap.extend(
Some(ms) => c.size > ms as u64, file_or_folder
None => !using_a_filter || c.name.is_file() || c.size > 0, .children
})) .iter()
.filter(|c| match min_size {
Some(ms) => c.size > ms as u64,
None => !using_a_filter || c.name.is_file() || c.size > 0,
})
.filter(|c| if only_dir { c.name.is_dir() } else { true }),
)
} }
heap heap
} }
+39 -9
View File
@@ -11,7 +11,9 @@ mod utils;
use crate::cli::build_cli; use crate::cli::build_cli;
use std::collections::HashSet; use std::collections::HashSet;
use std::io::BufRead;
use std::process; use std::process;
use sysinfo::{System, SystemExt};
use self::display::draw_it; use self::display::draw_it;
use clap::Values; use clap::Values;
@@ -19,6 +21,7 @@ use config::get_config;
use dir_walker::{walk_it, WalkData}; use dir_walker::{walk_it, WalkData};
use filter::get_biggest; use filter::get_biggest;
use filter_type::get_all_file_types; use filter_type::get_all_file_types;
use rayon::ThreadPoolBuildError;
use regex::Regex; use regex::Regex;
use std::cmp::max; use std::cmp::max;
use std::path::PathBuf; use std::path::PathBuf;
@@ -89,14 +92,28 @@ fn get_regex_value(maybe_value: Option<Values>) -> Vec<Regex> {
.collect() .collect()
} }
// Returns a list of lines from stdin or `None` if there's nothing to read
fn get_lines_from_stdin() -> Option<Vec<String>> {
atty::isnt(atty::Stream::Stdin).then(|| {
std::io::stdin()
.lock()
.lines()
.collect::<Result<_, _>>()
.expect("Error reading from stdin")
})
}
fn main() { fn main() {
let options = build_cli().get_matches(); let options = build_cli().get_matches();
let config = get_config(); let config = get_config();
let stdin_lines = get_lines_from_stdin();
let target_dirs = options let target_dirs = match options.values_of("inputs") {
.values_of("inputs") Some(values) => values.collect(),
.expect("Should be a default value here") None => stdin_lines.as_ref().map_or(vec!["."], |lines| {
.collect(); lines.iter().map(String::as_str).collect()
}),
};
let summarize_file_types = options.is_present("types"); let summarize_file_types = options.is_present("types");
@@ -154,11 +171,7 @@ fn main() {
by_filecount, by_filecount,
ignore_hidden: config.get_ignore_hidden(&options), ignore_hidden: config.get_ignore_hidden(&options),
}; };
// Larger stack size to handle cases with lots of nested directories let _rayon = init_rayon();
rayon::ThreadPoolBuilder::new()
.stack_size(usize::pow(1024, 3))
.build_global()
.unwrap_or_else(|e| eprintln!("Warning: Could not configure threads {:?}", e));
let iso = config.get_iso(&options); let iso = config.get_iso(&options);
let (top_level_nodes, has_errors) = walk_it(simplified_dirs, walk_data); let (top_level_nodes, has_errors) = walk_it(simplified_dirs, walk_data);
@@ -168,6 +181,7 @@ fn main() {
false => get_biggest( false => get_biggest(
top_level_nodes, top_level_nodes,
config.get_min_size(&options, iso), config.get_min_size(&options, iso),
config.get_only_dir(&options),
number_of_lines, number_of_lines,
depth, depth,
options.values_of("filter").is_some() || options.value_of("invert_filter").is_some(), options.values_of("filter").is_some() || options.value_of("invert_filter").is_some(),
@@ -191,3 +205,19 @@ fn main() {
) )
} }
} }
fn init_rayon() -> Result<(), ThreadPoolBuildError> {
let large_stack = usize::pow(1024, 3);
let mut s = System::new();
s.refresh_memory();
let available = s.available_memory();
if available > large_stack.try_into().unwrap() {
// Larger stack size to handle cases with lots of nested directories
rayon::ThreadPoolBuilder::new()
.stack_size(large_stack)
.build_global()
} else {
Ok(())
}
}
+1
View File
@@ -73,6 +73,7 @@ pub fn test_ignore_dir() {
let output = build_command(vec!["-c", "-X", "dir_substring", "tests/test_dir2/"]); let output = build_command(vec!["-c", "-X", "dir_substring", "tests/test_dir2/"]);
assert!(!output.contains("dir_substring")); assert!(!output.contains("dir_substring"));
} }
// Add test for multiple dirs - with -d 0 and maybe -d 1 check the
#[test] #[test]
pub fn test_with_bad_param() { pub fn test_with_bad_param() {
+47 -24
View File
@@ -17,6 +17,18 @@ fn build_temp_file(dir: &TempDir) -> PathBuf {
file_path file_path
} }
fn link_it(link_path: PathBuf, file_path_s: &str, is_soft: bool) -> String {
let link_name_s = link_path.to_str().unwrap();
let mut c = Command::new("ln");
if is_soft {
c.arg("-s");
}
c.arg(file_path_s);
c.arg(link_name_s);
assert!(c.output().is_ok());
return link_name_s.into();
}
#[cfg_attr(target_os = "windows", ignore)] #[cfg_attr(target_os = "windows", ignore)]
#[test] #[test]
pub fn test_soft_sym_link() { pub fn test_soft_sym_link() {
@@ -26,13 +38,7 @@ pub fn test_soft_sym_link() {
let file_path_s = file.to_str().unwrap(); let file_path_s = file.to_str().unwrap();
let link_name = dir.path().join("the_link"); let link_name = dir.path().join("the_link");
let link_name_s = link_name.to_str().unwrap(); let link_name_s = link_it(link_name, file_path_s, true);
let c = Command::new("ln")
.arg("-s")
.arg(file_path_s)
.arg(link_name_s)
.output();
assert!(c.is_ok());
let c = format!(" ├── {}", link_name_s); let c = format!(" ├── {}", link_name_s);
let b = format!(" ┌── {}", file_path_s); let b = format!(" ┌── {}", file_path_s);
@@ -41,7 +47,7 @@ pub fn test_soft_sym_link() {
let mut cmd = Command::cargo_bin("dust").unwrap(); let mut cmd = Command::cargo_bin("dust").unwrap();
// Mac test runners create long filenames in tmp directories // Mac test runners create long filenames in tmp directories
let output = cmd let output = cmd
.args(["-p", "-c", "-s", "-w 999", dir_s]) .args(["-p", "-c", "-s", "-w", "999", dir_s])
.unwrap() .unwrap()
.stdout; .stdout;
@@ -61,19 +67,14 @@ pub fn test_hard_sym_link() {
let file_path_s = file.to_str().unwrap(); let file_path_s = file.to_str().unwrap();
let link_name = dir.path().join("the_link"); let link_name = dir.path().join("the_link");
let link_name_s = link_name.to_str().unwrap(); link_it(link_name, file_path_s, false);
let c = Command::new("ln")
.arg(file_path_s)
.arg(link_name_s)
.output();
assert!(c.is_ok());
let file_output = format!(" ┌── {}", file_path_s); let file_output = format!(" ┌── {}", file_path_s);
let dirs_output = format!("─┴ {}", dir_s); let dirs_output = format!("─┴ {}", dir_s);
let mut cmd = Command::cargo_bin("dust").unwrap(); let mut cmd = Command::cargo_bin("dust").unwrap();
// Mac test runners create long filenames in tmp directories // Mac test runners create long filenames in tmp directories
let output = cmd.args(["-p", "-c", "-w 999", dir_s]).unwrap().stdout; let output = cmd.args(["-p", "-c", "-w", "999", dir_s]).unwrap().stdout;
// The link should not appear in the output because multiple inodes are now ordered // The link should not appear in the output because multiple inodes are now ordered
// then filtered. // then filtered.
@@ -82,6 +83,34 @@ pub fn test_hard_sym_link() {
assert!(output.contains(file_output.as_str())); assert!(output.contains(file_output.as_str()));
} }
#[cfg_attr(target_os = "windows", ignore)]
#[test]
pub fn test_hard_sym_link_no_dup_multi_arg() {
let dir = Builder::new().tempdir().unwrap();
let dir_link = Builder::new().tempdir().unwrap();
let file = build_temp_file(&dir);
let dir_s = dir.path().to_str().unwrap();
let dir_link_s = dir_link.path().to_str().unwrap();
let file_path_s = file.to_str().unwrap();
let link_name = dir_link.path().join("the_link");
let link_name_s = link_it(link_name, file_path_s, false);
let mut cmd = Command::cargo_bin("dust").unwrap();
// Mac test runners create long filenames in tmp directories
let output = cmd
.args(["-p", "-c", "-w", "999", "-b", dir_link_s, dir_s])
.unwrap()
.stdout;
// The link or the file should appear but not both
let output = str::from_utf8(&output).unwrap();
let has_file_only = output.contains(file_path_s) && !output.contains(&link_name_s);
let has_link_only = !output.contains(file_path_s) && output.contains(&link_name_s);
assert!(has_file_only || has_link_only);
}
#[cfg_attr(target_os = "windows", ignore)] #[cfg_attr(target_os = "windows", ignore)]
#[test] #[test]
pub fn test_recursive_sym_link() { pub fn test_recursive_sym_link() {
@@ -89,14 +118,7 @@ pub fn test_recursive_sym_link() {
let dir_s = dir.path().to_str().unwrap(); let dir_s = dir.path().to_str().unwrap();
let link_name = dir.path().join("the_link"); let link_name = dir.path().join("the_link");
let link_name_s = link_name.to_str().unwrap(); let link_name_s = link_it(link_name, dir_s, true);
let c = Command::new("ln")
.arg("-s")
.arg(dir_s)
.arg(link_name_s)
.output();
assert!(c.is_ok());
let a = format!("─┬ {}", dir_s); let a = format!("─┬ {}", dir_s);
let b = format!(" └── {}", link_name_s); let b = format!(" └── {}", link_name_s);
@@ -107,7 +129,8 @@ pub fn test_recursive_sym_link() {
.arg("-c") .arg("-c")
.arg("-r") .arg("-r")
.arg("-s") .arg("-s")
.arg("-w 999") .arg("-w")
.arg("999")
.arg(dir_s) .arg(dir_s)
.unwrap() .unwrap()
.stdout; .stdout;