Handle errors instead of fail!()ing

Dir::readdir and File::from path now both return IoResults, rather than just calling fail! and exiting. This allows the program to continue after an error.
This commit is contained in:
Ben S 2014-06-20 21:07:53 +01:00
parent 355ca51617
commit 92b45e6908
3 changed files with 37 additions and 22 deletions

26
dir.rs
View File

@ -1,4 +1,4 @@
use std::io::fs; use std::io::{fs, IoResult};
use file::File; use file::File;
// The purpose of a Dir is to provide a cached list of the file paths // The purpose of a Dir is to provide a cached list of the file paths
@ -12,17 +12,27 @@ pub struct Dir<'a> {
} }
impl<'a> Dir<'a> { impl<'a> Dir<'a> {
pub fn readdir(path: Path) -> Dir<'a> { pub fn readdir(path: Path) -> IoResult<Dir<'a>> {
match fs::readdir(&path) { fs::readdir(&path).map(|paths| Dir {
Ok(paths) => Dir {
contents: paths, contents: paths,
}, })
Err(e) => fail!("readdir: {}", e),
}
} }
pub fn files(&'a self) -> Vec<File<'a>> { pub fn files(&'a self) -> Vec<File<'a>> {
self.contents.iter().map(|path| File::from_path(path, self)).collect() let mut files = vec![];
for path in self.contents.iter() {
match File::from_path(path, self) {
Ok(file) => {
files.push(file);
}
Err(e) => {
println!("{}: {}", path.filename_str().unwrap(), e);
}
}
}
files
} }
pub fn contains(&self, path: &Path) -> bool { pub fn contains(&self, path: &Path) -> bool {

15
exa.rs
View File

@ -35,14 +35,23 @@ fn main() {
}; };
for dir in strs.move_iter() { for dir in strs.move_iter() {
exa(&opts, Path::new(dir)) exa(&opts, dir)
} }
} }
}; };
} }
fn exa(options: &Options, path: Path) { fn exa(options: &Options, string: String) {
let dir = Dir::readdir(path); let path = Path::new(string.clone());
let dir = match Dir::readdir(path) {
Ok(dir) => dir,
Err(e) => {
println!("{}: {}", string, e);
return;
}
};
let unsorted_files = dir.files(); let unsorted_files = dir.files();
let files: Vec<&File> = options.transform_files(&unsorted_files); let files: Vec<&File> = options.transform_files(&unsorted_files);

14
file.rs
View File

@ -1,5 +1,5 @@
use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan, Fixed}; use colours::{Plain, Style, Black, Red, Green, Yellow, Blue, Purple, Cyan};
use std::io::fs; use std::io::{fs, IoResult};
use std::io; use std::io;
use column::{Column, Permissions, FileName, FileSize, User, Group}; use column::{Column, Permissions, FileName, FileSize, User, Group};
@ -26,7 +26,7 @@ pub struct File<'a> {
} }
impl<'a> File<'a> { impl<'a> File<'a> {
pub fn from_path(path: &'a Path, parent: &'a Dir) -> File<'a> { pub fn from_path(path: &'a Path, parent: &'a Dir) -> IoResult<File<'a>> {
// Getting the string from a filename fails whenever it's not // Getting the string from a filename fails whenever it's not
// UTF-8 representable - just assume it is for now. // UTF-8 representable - just assume it is for now.
let filename: &str = path.filename_str().unwrap(); let filename: &str = path.filename_str().unwrap();
@ -34,19 +34,15 @@ impl<'a> File<'a> {
// Use lstat here instead of file.stat(), as it doesn't follow // Use lstat here instead of file.stat(), as it doesn't follow
// symbolic links. Otherwise, the stat() call will fail if it // symbolic links. Otherwise, the stat() call will fail if it
// encounters a link that's target is non-existent. // encounters a link that's target is non-existent.
let stat: io::FileStat = match fs::lstat(path) {
Ok(stat) => stat,
Err(e) => fail!("Couldn't stat {}: {}", filename, e),
};
return File { fs::lstat(path).map(|stat| File {
path: path, path: path,
dir: parent, dir: parent,
stat: stat, stat: stat,
name: filename, name: filename,
ext: File::ext(filename), ext: File::ext(filename),
parts: SortPart::split_into_parts(filename), parts: SortPart::split_into_parts(filename),
}; })
} }
fn ext(name: &'a str) -> Option<&'a str> { fn ext(name: &'a str) -> Option<&'a str> {