mirror of
https://github.com/uutils/coreutils
synced 2024-12-13 23:02:38 +00:00
Adding skeleton of ls
This commit is contained in:
parent
e382ee637b
commit
9716862cfe
5 changed files with 277 additions and 0 deletions
|
@ -50,6 +50,7 @@ generic = [
|
||||||
"head",
|
"head",
|
||||||
"link",
|
"link",
|
||||||
"ln",
|
"ln",
|
||||||
|
"ls",
|
||||||
"mkdir",
|
"mkdir",
|
||||||
"nl",
|
"nl",
|
||||||
"nproc",
|
"nproc",
|
||||||
|
@ -119,6 +120,7 @@ id = { optional=true, path="src/id" }
|
||||||
kill = { optional=true, path="src/kill" }
|
kill = { optional=true, path="src/kill" }
|
||||||
link = { optional=true, path="src/link" }
|
link = { optional=true, path="src/link" }
|
||||||
ln = { optional=true, path="src/ln" }
|
ln = { optional=true, path="src/ln" }
|
||||||
|
ls = { optional=true, path="src/ls" }
|
||||||
logname = { optional=true, path="src/logname" }
|
logname = { optional=true, path="src/logname" }
|
||||||
mkdir = { optional=true, path="src/mkdir" }
|
mkdir = { optional=true, path="src/mkdir" }
|
||||||
mktemp = { optional=true, path="src/mktemp" }
|
mktemp = { optional=true, path="src/mktemp" }
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -58,6 +58,7 @@ PROGS := \
|
||||||
head \
|
head \
|
||||||
link \
|
link \
|
||||||
ln \
|
ln \
|
||||||
|
ls \
|
||||||
mkdir \
|
mkdir \
|
||||||
mktemp \
|
mktemp \
|
||||||
nl \
|
nl \
|
||||||
|
|
18
src/ls/Cargo.toml
Normal file
18
src/ls/Cargo.toml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
[package]
|
||||||
|
name = "ls"
|
||||||
|
version = "0.0.1"
|
||||||
|
authors = ["Jeremiah Peschka <jeremiah.peschkak@gmail.com>"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "uu_ls"
|
||||||
|
path = "ls.rs"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
getopts = "*"
|
||||||
|
libc = "*"
|
||||||
|
uucore = { path="../uucore" }
|
||||||
|
pretty-bytes = "0.1.0"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "ls"
|
||||||
|
path = "main.rs"
|
251
src/ls/ls.rs
Normal file
251
src/ls/ls.rs
Normal file
|
@ -0,0 +1,251 @@
|
||||||
|
#![crate_name = "uu_ls"]
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file is part of the uutils coreutils package.
|
||||||
|
*
|
||||||
|
* (c) Jeremiah Peschka <jeremiah.peschka@gmail.com>
|
||||||
|
*
|
||||||
|
* For the full copyright and license information, please view the LICENSE file
|
||||||
|
* that was distributed with this source code.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern crate getopts;
|
||||||
|
extern crate pretty_bytes;
|
||||||
|
use pretty_bytes::converter::convert;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate uucore;
|
||||||
|
|
||||||
|
use getopts::Options;
|
||||||
|
use std::fs;
|
||||||
|
use std::fs::{ReadDir, DirEntry, FileType, Metadata};
|
||||||
|
use std::ffi::{OsString};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
|
enum Mode {
|
||||||
|
Help,
|
||||||
|
Version,
|
||||||
|
List
|
||||||
|
}
|
||||||
|
|
||||||
|
static NAME: &'static str = "ls";
|
||||||
|
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
|
let mut opts = Options::new();
|
||||||
|
|
||||||
|
opts.optflag("", "help", "display this help and exit");
|
||||||
|
opts.optflag("", "version", "output version information and exit");
|
||||||
|
|
||||||
|
opts.optflag("a", "all", "Do not ignore hidden files (files with names that start with '.').");
|
||||||
|
opts.optflag("A", "almost-all", "In a directory, do not ignore all file names that start with '.', only ignore '.' and '..'.");
|
||||||
|
opts.optflag("B", "ignore-backups", "Ignore files that end with ~. Equivalent to using `--ignore='*~'` or `--ignore='.*~'.");
|
||||||
|
opts.optflag("d", "directory", "Only list the names of directories, rather than listing directory contents. This will not follow symbolic links unless one of `--dereference-command-line (-H)`, `--dereference (-L)`, or `--dereference-command-line-symlink-to-dir` is specified.");
|
||||||
|
opts.optflag("H", "dereference-command-line", "If a command line argument specifies a symbolic link, show information about the linked file rather than the link itself.");
|
||||||
|
opts.optflag("h", "human-readable", "Print human readable file sizes (e.g. 1K 234M 56G).");
|
||||||
|
|
||||||
|
let matches = match opts.parse(&args[1..]) {
|
||||||
|
Ok(m) => m,
|
||||||
|
Err(e) => {
|
||||||
|
show_error!("{}", e);
|
||||||
|
panic!()
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let mode = if matches.opt_present("version") {
|
||||||
|
Mode::Version
|
||||||
|
} else if matches.opt_present("help") {
|
||||||
|
Mode::Help
|
||||||
|
} else {
|
||||||
|
Mode::List
|
||||||
|
};
|
||||||
|
|
||||||
|
match mode {
|
||||||
|
Mode::Version => version(),
|
||||||
|
Mode::Help => help(),
|
||||||
|
Mode::List => list(matches)
|
||||||
|
}
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn version() {
|
||||||
|
println!("{} {}", NAME, VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn help() {
|
||||||
|
let msg = format!("{0} {1}\n\n\
|
||||||
|
Usage: {0} [OPTION]... DIRECTORY \n \
|
||||||
|
or: {0} [OPTION]... [FILE]... \n \
|
||||||
|
\n \
|
||||||
|
By default, ls will list the files and contents of any directories on \
|
||||||
|
the command line, expect that it will ignore files and directories \
|
||||||
|
whose names start with '.'. \n\
|
||||||
|
\n", NAME, VERSION);
|
||||||
|
println!("{}", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn list(options: getopts::Matches) {
|
||||||
|
let locs: Vec<String> = if options.free.is_empty() {
|
||||||
|
show_error!("Missing DIRECTORY or FILES argument. Try --help.");
|
||||||
|
panic!();
|
||||||
|
} else {
|
||||||
|
options.free.iter().cloned().collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
for loc in locs {
|
||||||
|
let p = Path::new(&loc);
|
||||||
|
|
||||||
|
if !p.exists() {
|
||||||
|
show_error!("Cannot find path '{}' because it does not exist.", loc);
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.is_dir() {
|
||||||
|
match fs::read_dir(p) {
|
||||||
|
Err(e) => {
|
||||||
|
show_error!("Cannot read directory '{}'. \n Reason: {}", loc, e);
|
||||||
|
panic!();
|
||||||
|
},
|
||||||
|
Ok(entries) => enter_directory(entries, &options),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.is_file() {
|
||||||
|
display_item(Path::new(p), &options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enter_directory(contents: ReadDir, options: &getopts::Matches) {
|
||||||
|
for entry in contents {
|
||||||
|
let entry = match entry {
|
||||||
|
Err(err) => {
|
||||||
|
show_error!("{}", err);
|
||||||
|
panic!();
|
||||||
|
},
|
||||||
|
Ok(en) => en
|
||||||
|
};
|
||||||
|
|
||||||
|
// Currently have a DirEntry that we can believe in.
|
||||||
|
display_dir_entry(entry, options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_dir_entry(entry: DirEntry, options: &getopts::Matches) {
|
||||||
|
let md = match entry.metadata() {
|
||||||
|
Err(e) => {
|
||||||
|
show_error!("Unable to retrieve metadata for {}. \n Error: {}",
|
||||||
|
display_file_name(entry.file_name()), e);
|
||||||
|
panic!();
|
||||||
|
},
|
||||||
|
Ok(md) => md
|
||||||
|
};
|
||||||
|
|
||||||
|
println!(" {}{} {} somebody somegroup {: >9} {}",
|
||||||
|
display_file_type(entry.file_type()),
|
||||||
|
display_permissions(&md),
|
||||||
|
display_symlink_count(&md),
|
||||||
|
display_file_size(&md, options),
|
||||||
|
display_file_name(entry.file_name())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_file_size(metadata: &Metadata, options: &getopts::Matches) -> String {
|
||||||
|
if options.opt_present("human-readable") {
|
||||||
|
convert(metadata.len() as f64)
|
||||||
|
} else {
|
||||||
|
metadata.len().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_file_type(file_type: Result<FileType, std::io::Error>) -> String {
|
||||||
|
let file_type = match file_type {
|
||||||
|
Err(e) => {
|
||||||
|
show_error!("{}", e);
|
||||||
|
panic!()
|
||||||
|
},
|
||||||
|
Ok(ft) => ft
|
||||||
|
};
|
||||||
|
|
||||||
|
if file_type.is_dir() {
|
||||||
|
"d".to_string()
|
||||||
|
} else if file_type.is_symlink() {
|
||||||
|
"l".to_string()
|
||||||
|
} else {
|
||||||
|
"-".to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display_file_name(name: OsString) -> String {
|
||||||
|
name.to_string_lossy().into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn display_symlink_count(metadata: &Metadata) -> String {
|
||||||
|
// Currently not sure of how to get this on Windows, so I'm punting.
|
||||||
|
// Git Bash looks like it may do the same thing.
|
||||||
|
String::from("1")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
fn display_symlink_count(metadata: &Metadata) -> String {
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
|
md.nlink().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "windows")]
|
||||||
|
#[allow(unused_variables)]
|
||||||
|
fn display_permissions(metadata: &Metadata) -> String {
|
||||||
|
String::from("---------")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_family = "unix")]
|
||||||
|
fn display_permissions(metadata: &Metadata) -> String {
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
|
||||||
|
"lolwtfbbq".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fn list_directory_contents(directory: &Path, options: &getopts::Matches) {
|
||||||
|
// let rd = fs::read_dir(directory);
|
||||||
|
|
||||||
|
// match rd {
|
||||||
|
// Err(err) => println!("ERROR! {}", err),
|
||||||
|
// Ok(entries) => display_directory_contents(entries, &options),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// fn display_directory_contents(contents: ReadDir, options: &getopts::Matches) {
|
||||||
|
// for entry in contents {
|
||||||
|
// let entry = match entry {
|
||||||
|
// Err(err) => {
|
||||||
|
// println!("ERROR! {}", err);
|
||||||
|
// panic!()
|
||||||
|
// },
|
||||||
|
// Ok(en) => en
|
||||||
|
// };
|
||||||
|
// display_item(entry.path().as_path(), &options);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
fn display_item(item: &Path, options: &getopts::Matches) {
|
||||||
|
// let fileType = item.file
|
||||||
|
// let mut fileMeta = String::new();
|
||||||
|
|
||||||
|
// fileMeta = fileMeta + if item.is_dir() {
|
||||||
|
// "d"
|
||||||
|
// } else if item.sy
|
||||||
|
// } else {
|
||||||
|
// "-"
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// println!("{}{}", displayString, item.display());
|
||||||
|
}
|
5
src/ls/main.rs
Normal file
5
src/ls/main.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
extern crate uu_ls;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
std::process::exit(uu_ls::uumain(std::env::args().collect()));
|
||||||
|
}
|
Loading…
Reference in a new issue