Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions homework_2/ls/.idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions homework_2/ls/.idea/ls.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions homework_2/ls/.idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions homework_2/ls/.idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

223 changes: 223 additions & 0 deletions homework_2/ls/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions homework_2/ls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "ls"
version = "0.1.0"
authors = ["Maksym-Yurii Rudko <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
structopt = "0.3.21"
74 changes: 74 additions & 0 deletions homework_2/ls/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
mod models;
mod providers;

use std::io;
use std::path::PathBuf;
use providers::file_provider;
use structopt::StructOpt;
use crate::models::FileModel;

#[derive(StructOpt)]
struct CliArgs {
#[structopt(short, long = "human")]
human_readable: bool,
#[structopt(name = "Show all", short = "a", long = "all")]
show_hidden: bool,
#[structopt(parse(from_os_str), default_value = ".")]
start_dir: PathBuf,
}

fn main() -> io::Result<()> {
let args: CliArgs = CliArgs::from_args();
let start_path = args.start_dir.as_path();

// If the path provided to us is a directory, read its entries
if start_path.is_dir() {
match file_provider::get_files_in_directory(start_path) {
Ok(mut file_models) => {
let start_path = start_path.to_string_lossy();

sort_file_table(&mut file_models);
filter_file_table(&mut file_models, args.show_hidden);
print_file_table(start_path.as_ref(), &file_models, args.human_readable);
}
Err(e) => {
eprintln!("Error reading files in directory: {}", e);
return Err(e);
}
}
} else {
let parsed_file = file_provider::parse_dir_entry(start_path)?;
// If the path provided is a single file, just print its data
print_file_model(&parsed_file, args.human_readable);
}

Ok(())
}

fn filter_file_table(file_table: &mut Vec<FileModel>, should_show_hidden: bool) {
file_table.retain(|f| !f.is_hidden || should_show_hidden)
}

fn print_file_table(start_path: &str, file_table: &Vec<FileModel>, human_readable: bool) {
println!("List of files in {}", start_path);
println!("{:36} {:9}", "Name", "Size");

for model in file_table {
print_file_model(model, human_readable)
}
}

fn print_file_model(model: &FileModel, human_readable: bool) {
println!(
"{:36} {:9}",
format!("{}{}", model.name, if model.is_directory { "/" } else { "" }),
if human_readable { model.size.to_human_str() } else { model.size.to_raw_str() }
)
}

fn sort_file_table(file_table: &mut Vec<FileModel>) {
file_table.sort_unstable_by(|a, b| a.is_directory
.cmp(&b.is_directory)
.reverse()
.then(a.name.cmp(&b.name)));
}
49 changes: 49 additions & 0 deletions homework_2/ls/src/models.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
pub struct FileModel {
pub name: String,
pub is_hidden: bool,
pub is_directory: bool,
pub size: FileSize,
pub is_ro: bool,
}

pub struct FileSize {
pub size: u64
}

impl FileSize {
pub fn to_raw_str(&self) -> String {
format!("{} B", self.size)
}

pub fn to_human_str(&self) -> String {
if self.size < 1024 {
self.to_raw_str()
} else {
let mut i: u8 = 0;
let mut human_size: f64 = self.size as f64;
loop {
human_size /= 1024.0;
i += 1;

if human_size < 1024.0 {
break;
}
}
format!("{:.2} {}", human_size, FileSize::get_size_label(i))
}
}

fn get_size_label(size_order: u8) -> String {
String::from(
match size_order {
0 => "B",
1 => "KiB",
2 => "MiB",
3 => "GiB",
4 => "TiB",
5 => "EiB",
_ => "B"
}
)
}
}
Loading