A few improvements to du implementation: (#1533)

1. Fixed a bug where `--all` wasn't showing files at the root directories.
2. More use of `Result`'s `map` and `map_err` methods.
3. Making tables be homogeneous so one can, for example, `get directories`.
This commit is contained in:
Jason Gedge 2020-03-29 21:16:09 -04:00 committed by GitHub
parent efbf4f48c6
commit 906d0b920f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -41,7 +41,7 @@ impl PerItemCommand for Du {
.optional("path", SyntaxShape::Pattern, "starting directory") .optional("path", SyntaxShape::Pattern, "starting directory")
.switch( .switch(
"all", "all",
"Output File sizes as well as directory sizes", "Output file sizes as well as directory sizes",
Some('a'), Some('a'),
) )
.switch( .switch(
@ -95,7 +95,7 @@ fn du(args: DuArgs, ctx: &RunnablePerItemContext) -> Result<OutputStream, ShellE
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", x.tag.clone())) .map_err(|e| ShellError::labeled_error(e.msg, "glob error", x.tag.clone()))
})?; })?;
let filter_files = args.path.is_none(); let include_files = args.all;
let paths = match args.path { let paths = match args.path {
Some(p) => { Some(p) => {
let p = p.item.to_str().expect("Why isn't this encoded properly?"); let p = p.item.to_str().expect("Why isn't this encoded properly?");
@ -105,14 +105,14 @@ fn du(args: DuArgs, ctx: &RunnablePerItemContext) -> Result<OutputStream, ShellE
} }
.map_err(|e| ShellError::labeled_error(e.msg, "glob error", tag.clone()))? .map_err(|e| ShellError::labeled_error(e.msg, "glob error", tag.clone()))?
.filter(move |p| { .filter(move |p| {
if filter_files { if include_files {
true
} else {
match p { match p {
Ok(f) if f.is_dir() => true, Ok(f) if f.is_dir() => true,
Err(e) if e.path().is_dir() => true, Err(e) if e.path().is_dir() => true,
_ => false, _ => false,
} }
} else {
true
} }
}) })
.map(|v| v.map_err(glob_err_into)); .map(|v| v.map_err(glob_err_into));
@ -127,7 +127,7 @@ fn du(args: DuArgs, ctx: &RunnablePerItemContext) -> Result<OutputStream, ShellE
tag: tag.clone(), tag: tag.clone(),
min: min_size, min: min_size,
deref, deref,
ex: exclude, exclude,
all, all,
}; };
@ -153,7 +153,7 @@ struct DirBuilder {
tag: Tag, tag: Tag,
min: Option<u64>, min: Option<u64>,
deref: bool, deref: bool,
ex: Option<Pattern>, exclude: Option<Pattern>,
all: bool, all: bool,
} }
@ -218,15 +218,11 @@ impl DirInfo {
for f in d { for f in d {
match f { match f {
Ok(i) => match i.file_type() { Ok(i) => match i.file_type() {
Ok(t) if t.is_dir() => { Ok(t) if t.is_dir() => s = s.add_dir(i.path(), depth, &params),
s = s.add_dir(i.path(), depth, &params); Ok(_t) => s = s.add_file(i.path(), &params),
} Err(e) => s = s.add_error(e.into()),
Ok(_t) => {
s = s.add_file(i.path(), &params);
}
Err(e) => s = s.add_error(ShellError::from(e)),
}, },
Err(e) => s = s.add_error(ShellError::from(e)), Err(e) => s = s.add_error(e.into()),
} }
} }
} }
@ -258,8 +254,11 @@ impl DirInfo {
fn add_file(mut self, f: impl Into<PathBuf>, params: &DirBuilder) -> Self { fn add_file(mut self, f: impl Into<PathBuf>, params: &DirBuilder) -> Self {
let f = f.into(); let f = f.into();
let ex = params.ex.as_ref().map_or(false, |x| x.matches_path(&f)); let include = params
if !ex { .exclude
.as_ref()
.map_or(true, |x| !x.matches_path(&f));
if include {
match FileInfo::new(f, params.deref, self.tag.clone()) { match FileInfo::new(f, params.deref, self.tag.clone()) {
Ok(file) => { Ok(file) => {
let inc = params.min.map_or(true, |s| file.size >= s); let inc = params.min.map_or(true, |s| file.size >= s);
@ -288,49 +287,51 @@ fn glob_err_into(e: GlobError) -> ShellError {
ShellError::from(e) ShellError::from(e)
} }
fn value_from_vec<V>(vec: Vec<V>, tag: &Tag) -> Value
where
V: Into<Value>,
{
if vec.is_empty() {
UntaggedValue::nothing()
} else {
let values = vec.into_iter().map(Into::into).collect::<Vec<Value>>();
UntaggedValue::Table(values)
}
.retag(tag)
}
impl From<DirInfo> for Value { impl From<DirInfo> for Value {
fn from(d: DirInfo) -> Self { fn from(d: DirInfo) -> Self {
let mut r: IndexMap<String, Value> = IndexMap::new(); let mut r: IndexMap<String, Value> = IndexMap::new();
r.insert( r.insert(
"path".to_string(), "path".to_string(),
UntaggedValue::path(d.path).retag(d.tag.clone()), UntaggedValue::path(d.path).retag(&d.tag),
); );
r.insert( r.insert(
"apparent".to_string(), "apparent".to_string(),
UntaggedValue::bytes(d.size).retag(d.tag.clone()), UntaggedValue::bytes(d.size).retag(&d.tag),
); );
r.insert( r.insert(
"physical".to_string(), "physical".to_string(),
UntaggedValue::bytes(d.blocks).retag(d.tag.clone()), UntaggedValue::bytes(d.blocks).retag(&d.tag),
); );
if !d.files.is_empty() {
let v = Value { r.insert("directories".to_string(), value_from_vec(d.dirs, &d.tag));
value: UntaggedValue::Table(
d.files.into_iter().map(Into::into).collect::<Vec<Value>>(), r.insert("files".to_string(), value_from_vec(d.files, &d.tag));
),
tag: d.tag.clone(),
};
r.insert("files".to_string(), v);
}
if !d.dirs.is_empty() {
let v = Value {
value: UntaggedValue::Table(
d.dirs.into_iter().map(Into::into).collect::<Vec<Value>>(),
),
tag: d.tag.clone(),
};
r.insert("directories".to_string(), v);
}
if !d.errors.is_empty() { if !d.errors.is_empty() {
let v = Value { let v = UntaggedValue::Table(
value: UntaggedValue::Table( d.errors
d.errors .into_iter()
.into_iter() .map(move |e| UntaggedValue::Error(e).into_untagged_value())
.map(move |e| UntaggedValue::Error(e).into_untagged_value()) .collect::<Vec<Value>>(),
.collect::<Vec<Value>>(), )
), .retag(&d.tag);
tag: d.tag.clone(),
};
r.insert("errors".to_string(), v); r.insert("errors".to_string(), v);
} }
@ -344,22 +345,32 @@ impl From<DirInfo> for Value {
impl From<FileInfo> for Value { impl From<FileInfo> for Value {
fn from(f: FileInfo) -> Self { fn from(f: FileInfo) -> Self {
let mut r: IndexMap<String, Value> = IndexMap::new(); let mut r: IndexMap<String, Value> = IndexMap::new();
r.insert( r.insert(
"path".to_string(), "path".to_string(),
UntaggedValue::path(f.path).retag(f.tag.clone()), UntaggedValue::path(f.path).retag(&f.tag),
); );
r.insert( r.insert(
"apparent".to_string(), "apparent".to_string(),
UntaggedValue::bytes(f.size).retag(f.tag.clone()), UntaggedValue::bytes(f.size).retag(&f.tag),
); );
let b = match f.blocks {
Some(k) => UntaggedValue::bytes(k).retag(f.tag.clone()), let b = f
None => UntaggedValue::nothing().retag(f.tag.clone()), .blocks
}; .map(UntaggedValue::bytes)
.unwrap_or_else(UntaggedValue::nothing)
.retag(&f.tag);
r.insert("physical".to_string(), b); r.insert("physical".to_string(), b);
Value {
value: UntaggedValue::row(r), r.insert(
tag: f.tag, "directories".to_string(),
} UntaggedValue::nothing().retag(&f.tag),
);
r.insert("files".to_string(), UntaggedValue::nothing().retag(&f.tag));
UntaggedValue::row(r).retag(&f.tag)
} }
} }