Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hometask #10

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
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