From 17a021bd684cdb3c259ee649f3c4723510384b32 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Thu, 25 Mar 2021 12:20:57 +0200 Subject: [PATCH 01/14] Initial commit --- homework_2/ls/.idea/.gitignore | 8 ++++++++ homework_2/ls/.idea/ls.iml | 11 ++++++++++ homework_2/ls/.idea/modules.xml | 8 ++++++++ homework_2/ls/.idea/vcs.xml | 6 ++++++ homework_2/ls/Cargo.toml | 9 +++++++++ homework_2/ls/src/main.rs | 36 +++++++++++++++++++++++++++++++++ 6 files changed, 78 insertions(+) create mode 100644 homework_2/ls/.idea/.gitignore create mode 100644 homework_2/ls/.idea/ls.iml create mode 100644 homework_2/ls/.idea/modules.xml create mode 100644 homework_2/ls/.idea/vcs.xml create mode 100644 homework_2/ls/Cargo.toml create mode 100644 homework_2/ls/src/main.rs diff --git a/homework_2/ls/.idea/.gitignore b/homework_2/ls/.idea/.gitignore new file mode 100644 index 0000000..73f69e0 --- /dev/null +++ b/homework_2/ls/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/homework_2/ls/.idea/ls.iml b/homework_2/ls/.idea/ls.iml new file mode 100644 index 0000000..c254557 --- /dev/null +++ b/homework_2/ls/.idea/ls.iml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/homework_2/ls/.idea/modules.xml b/homework_2/ls/.idea/modules.xml new file mode 100644 index 0000000..ce4a5a0 --- /dev/null +++ b/homework_2/ls/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/homework_2/ls/.idea/vcs.xml b/homework_2/ls/.idea/vcs.xml new file mode 100644 index 0000000..b2bdec2 --- /dev/null +++ b/homework_2/ls/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/homework_2/ls/Cargo.toml b/homework_2/ls/Cargo.toml new file mode 100644 index 0000000..75457b0 --- /dev/null +++ b/homework_2/ls/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ls" +version = "0.1.0" +authors = ["Maksym-Yurii Rudko "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs new file mode 100644 index 0000000..7f9ead3 --- /dev/null +++ b/homework_2/ls/src/main.rs @@ -0,0 +1,36 @@ +use std::env; +use std::fs; +use std::io; +use std::path::Path; + +fn main() -> io::Result<()> { + // Collecting command line arguments + let args: Vec = env::args().collect(); + + // Making sure there is a filepath provided + assert_eq!(args.len(), 2); + + // Getting that filepath provided to us by the user + let file_path = &args[1]; + let start_path = Path::new(file_path); + + // If the path provided to us is a directory, read its entries + if start_path.is_dir() { + + // Iterate over entries in the directory + for entry in fs::read_dir(start_path)? { + let entry = entry?; + + // If it is a valid entry, print its name, otherwise just skip it + match entry.path().file_name() { + Some(path) => println!("{}", path.to_string_lossy()), + None => continue, + }; + } + } else { + // If the path provided is a single file, just print its name + println!("{}", start_path.file_name().unwrap().to_string_lossy()); + } + + Ok(()) +} From 803d0e8521ae4ca3e4de21ef2c8ee01317dda663 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Thu, 25 Mar 2021 13:10:25 +0200 Subject: [PATCH 02/14] Extract file list reading to a function --- homework_2/ls/src/main.rs | 44 +++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index 7f9ead3..a8b3f92 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -1,7 +1,8 @@ use std::env; use std::fs; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; +use std::io::{Error, ErrorKind}; fn main() -> io::Result<()> { // Collecting command line arguments @@ -16,16 +17,13 @@ fn main() -> io::Result<()> { // If the path provided to us is a directory, read its entries if start_path.is_dir() { - - // Iterate over entries in the directory - for entry in fs::read_dir(start_path)? { - let entry = entry?; - - // If it is a valid entry, print its name, otherwise just skip it - match entry.path().file_name() { - Some(path) => println!("{}", path.to_string_lossy()), - None => continue, - }; + match read_files_in_dir(start_path) { + Ok(file_names) => { + for file_name in file_names { + println!("{}", file_name) + } + } + Err(e) => eprintln!("Error reading files in directory: {}", e) } } else { // If the path provided is a single file, just print its name @@ -34,3 +32,27 @@ fn main() -> io::Result<()> { Ok(()) } + +fn read_files_in_dir(directory: &Path) -> Result, Error> { + let mut file_vector = Vec::new(); + // Iterate over entries in the directory + for entry in fs::read_dir(directory)? { + let entry = entry?; + let entry_path: PathBuf = entry.path(); + + let os_file_name = entry_path.file_name().and_then(|n| n.to_str()); + if let Some(file_name) = os_file_name { + file_vector.push(String::from(file_name)); + } else { + return Err( + Error::new( + ErrorKind::Other, + format!( + "Could not get file name from path: {}", + entry.file_name().to_str().unwrap_or("(Could not convert path to a string)") + ), + )); + } + } + Ok(file_vector) +} From 602cb86a6adc2a45618f0684158e6c0c85a7b5b1 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Thu, 25 Mar 2021 13:17:44 +0200 Subject: [PATCH 03/14] Minor improvement in handling unknown characters in path --- homework_2/ls/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index a8b3f92..89b954d 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -3,6 +3,7 @@ use std::fs; use std::io; use std::path::{Path, PathBuf}; use std::io::{Error, ErrorKind}; +use std::ops::Deref; fn main() -> io::Result<()> { // Collecting command line arguments @@ -40,7 +41,7 @@ fn read_files_in_dir(directory: &Path) -> Result, Error> { let entry = entry?; let entry_path: PathBuf = entry.path(); - let os_file_name = entry_path.file_name().and_then(|n| n.to_str()); + let os_file_name = entry_path.file_name().map(|n| n.to_string_lossy()); if let Some(file_name) = os_file_name { file_vector.push(String::from(file_name)); } else { From a46c6f1e404bb618e04e4434407330db06455201 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Thu, 25 Mar 2021 13:24:24 +0200 Subject: [PATCH 04/14] Clean up code --- homework_2/ls/src/main.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index 89b954d..c84cb4d 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -1,9 +1,8 @@ use std::env; use std::fs; use std::io; -use std::path::{Path, PathBuf}; -use std::io::{Error, ErrorKind}; -use std::ops::Deref; +use std::path::{Path}; +use std::io::{Error}; fn main() -> io::Result<()> { // Collecting command line arguments @@ -39,21 +38,10 @@ fn read_files_in_dir(directory: &Path) -> Result, Error> { // Iterate over entries in the directory for entry in fs::read_dir(directory)? { let entry = entry?; - let entry_path: PathBuf = entry.path(); - let os_file_name = entry_path.file_name().map(|n| n.to_string_lossy()); - if let Some(file_name) = os_file_name { - file_vector.push(String::from(file_name)); - } else { - return Err( - Error::new( - ErrorKind::Other, - format!( - "Could not get file name from path: {}", - entry.file_name().to_str().unwrap_or("(Could not convert path to a string)") - ), - )); - } + // Get file name + let os_file_name = entry.file_name(); + file_vector.push(String::from(os_file_name.to_string_lossy())); } Ok(file_vector) } From dd66a586986509c35f3039baf47651cbc60be81d Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Thu, 25 Mar 2021 16:29:41 +0200 Subject: [PATCH 05/14] Add ability to list sizes and implement model structure --- homework_2/ls/src/main.rs | 32 +++++++++++++++++++------ homework_2/ls/src/models.rs | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 7 deletions(-) create mode 100644 homework_2/ls/src/models.rs diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index c84cb4d..8aaf702 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -1,8 +1,12 @@ +mod models; + use std::env; use std::fs; use std::io; use std::path::{Path}; use std::io::{Error}; +use std::fs::DirEntry; +use crate::models::{FileModel, FileSize}; fn main() -> io::Result<()> { // Collecting command line arguments @@ -18,9 +22,13 @@ fn main() -> io::Result<()> { // If the path provided to us is a directory, read its entries if start_path.is_dir() { match read_files_in_dir(start_path) { - Ok(file_names) => { - for file_name in file_names { - println!("{}", file_name) + Ok(mut file_models) => { + println!("List of files in {}", start_path.to_string_lossy()); + println!("{:36} {:9}", "Name", "Size"); + + file_models.sort_by(|a, b| a.name.cmp(&b.name)); + for model in file_models { + println!("{:36} {:9}", model.name, model.size.to_human_str()) } } Err(e) => eprintln!("Error reading files in directory: {}", e) @@ -33,15 +41,25 @@ fn main() -> io::Result<()> { Ok(()) } -fn read_files_in_dir(directory: &Path) -> Result, Error> { +fn read_files_in_dir(directory: &Path) -> Result, Error> { let mut file_vector = Vec::new(); // Iterate over entries in the directory for entry in fs::read_dir(directory)? { let entry = entry?; - // Get file name - let os_file_name = entry.file_name(); - file_vector.push(String::from(os_file_name.to_string_lossy())); + file_vector.push(parse_dir_entry(&entry)?); } Ok(file_vector) } + +fn parse_dir_entry(entry: &DirEntry) -> io::Result { + let name = { + let os_file_name = entry.file_name(); + String::from(os_file_name.to_string_lossy()) + }; + let metadata = entry.metadata()?; + let size: u64 = metadata.len(); + let is_ro = metadata.permissions().readonly(); + + Ok(FileModel { name, size: FileSize { size }, is_ro }) +} diff --git a/homework_2/ls/src/models.rs b/homework_2/ls/src/models.rs new file mode 100644 index 0000000..a9c1d1c --- /dev/null +++ b/homework_2/ls/src/models.rs @@ -0,0 +1,47 @@ +pub struct FileModel { + pub name: String, + 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" + } + ) + } +} From a007e8bc2e7945c7286e9cf3db20999eac9955c9 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Thu, 25 Mar 2021 16:39:11 +0200 Subject: [PATCH 06/14] Extract file listing to a provider --- homework_2/ls/src/main.rs | 29 +++-------------------------- homework_2/ls/src/providers.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 26 deletions(-) create mode 100644 homework_2/ls/src/providers.rs diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index 8aaf702..fbac580 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -1,12 +1,10 @@ mod models; +mod providers; use std::env; -use std::fs; use std::io; use std::path::{Path}; -use std::io::{Error}; -use std::fs::DirEntry; -use crate::models::{FileModel, FileSize}; +use providers::file_provider; fn main() -> io::Result<()> { // Collecting command line arguments @@ -21,7 +19,7 @@ fn main() -> io::Result<()> { // If the path provided to us is a directory, read its entries if start_path.is_dir() { - match read_files_in_dir(start_path) { + match file_provider::get_files_in_directory(start_path) { Ok(mut file_models) => { println!("List of files in {}", start_path.to_string_lossy()); println!("{:36} {:9}", "Name", "Size"); @@ -41,25 +39,4 @@ fn main() -> io::Result<()> { Ok(()) } -fn read_files_in_dir(directory: &Path) -> Result, Error> { - let mut file_vector = Vec::new(); - // Iterate over entries in the directory - for entry in fs::read_dir(directory)? { - let entry = entry?; - file_vector.push(parse_dir_entry(&entry)?); - } - Ok(file_vector) -} - -fn parse_dir_entry(entry: &DirEntry) -> io::Result { - let name = { - let os_file_name = entry.file_name(); - String::from(os_file_name.to_string_lossy()) - }; - let metadata = entry.metadata()?; - let size: u64 = metadata.len(); - let is_ro = metadata.permissions().readonly(); - - Ok(FileModel { name, size: FileSize { size }, is_ro }) -} diff --git a/homework_2/ls/src/providers.rs b/homework_2/ls/src/providers.rs new file mode 100644 index 0000000..cb253bb --- /dev/null +++ b/homework_2/ls/src/providers.rs @@ -0,0 +1,30 @@ +pub mod file_provider { + use std::path::Path; + use crate::models::{FileModel, FileSize}; + use std::{io, fs}; + use std::fs::DirEntry; + use std::io::Error; + + pub fn get_files_in_directory(directory: &Path) -> Result, Error> { + let mut file_vector = Vec::new(); + // Iterate over entries in the directory + for entry in fs::read_dir(directory)? { + let entry = entry?; + + file_vector.push(parse_dir_entry(&entry)?); + } + Ok(file_vector) + } + + fn parse_dir_entry(entry: &DirEntry) -> io::Result { + let name = { + let os_file_name = entry.file_name(); + String::from(os_file_name.to_string_lossy()) + }; + let metadata = entry.metadata()?; + let size: u64 = metadata.len(); + let is_ro = metadata.permissions().readonly(); + + Ok(FileModel { name, size: FileSize { size }, is_ro }) + } +} \ No newline at end of file From a9da7a6120c33add452b7596ea226b74e309fae8 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 11:23:27 +0200 Subject: [PATCH 07/14] Distinguish files and directories --- homework_2/ls/src/main.rs | 16 +++++++++++++--- homework_2/ls/src/models.rs | 1 + homework_2/ls/src/providers.rs | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index fbac580..93e36da 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -5,6 +5,7 @@ use std::env; use std::io; use std::path::{Path}; use providers::file_provider; +use crate::models::FileModel; fn main() -> io::Result<()> { // Collecting command line arguments @@ -24,9 +25,13 @@ fn main() -> io::Result<()> { println!("List of files in {}", start_path.to_string_lossy()); println!("{:36} {:9}", "Name", "Size"); - file_models.sort_by(|a, b| a.name.cmp(&b.name)); + sort_file_table(file_models); for model in file_models { - println!("{:36} {:9}", model.name, model.size.to_human_str()) + println!( + "{:36} {:9}", + model.name + if model.is_directory { "/" } else { "" }, + model.size.to_human_str() + ) } } Err(e) => eprintln!("Error reading files in directory: {}", e) @@ -39,4 +44,9 @@ fn main() -> io::Result<()> { Ok(()) } - +fn sort_file_table(&mut file_table: Vec) { + file_table.sort_unstable_by(|a, b| a.is_directory + .cmp(&b.is_directory) + .reverse() + .then(a.name.cmp(&b.name))); +} diff --git a/homework_2/ls/src/models.rs b/homework_2/ls/src/models.rs index a9c1d1c..34d15e3 100644 --- a/homework_2/ls/src/models.rs +++ b/homework_2/ls/src/models.rs @@ -1,5 +1,6 @@ pub struct FileModel { pub name: String, + pub is_directory: bool, pub size: FileSize, pub is_ro: bool, } diff --git a/homework_2/ls/src/providers.rs b/homework_2/ls/src/providers.rs index cb253bb..22a1c99 100644 --- a/homework_2/ls/src/providers.rs +++ b/homework_2/ls/src/providers.rs @@ -22,9 +22,10 @@ pub mod file_provider { String::from(os_file_name.to_string_lossy()) }; let metadata = entry.metadata()?; + let is_directory = metadata.is_dir(); let size: u64 = metadata.len(); let is_ro = metadata.permissions().readonly(); - Ok(FileModel { name, size: FileSize { size }, is_ro }) + Ok(FileModel { name, is_directory, size: FileSize { size }, is_ro }) } } \ No newline at end of file From 885df67cb5147481bd96993fe6be78a5410baf10 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 11:25:02 +0200 Subject: [PATCH 08/14] Add property to indicate whether the file is hidden --- homework_2/ls/src/models.rs | 1 + homework_2/ls/src/providers.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/homework_2/ls/src/models.rs b/homework_2/ls/src/models.rs index 34d15e3..dbcc0f8 100644 --- a/homework_2/ls/src/models.rs +++ b/homework_2/ls/src/models.rs @@ -1,5 +1,6 @@ pub struct FileModel { pub name: String, + pub is_hidden: bool, pub is_directory: bool, pub size: FileSize, pub is_ro: bool, diff --git a/homework_2/ls/src/providers.rs b/homework_2/ls/src/providers.rs index 22a1c99..c95b02a 100644 --- a/homework_2/ls/src/providers.rs +++ b/homework_2/ls/src/providers.rs @@ -22,10 +22,12 @@ pub mod file_provider { String::from(os_file_name.to_string_lossy()) }; let metadata = entry.metadata()?; + + let is_hidden = name.starts_with("."); let is_directory = metadata.is_dir(); let size: u64 = metadata.len(); let is_ro = metadata.permissions().readonly(); - Ok(FileModel { name, is_directory, size: FileSize { size }, is_ro }) + Ok(FileModel { name, is_hidden, is_directory, size: FileSize { size }, is_ro }) } } \ No newline at end of file From 583b74318972e98949e0684bf47d770ef5a057e6 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 11:51:37 +0200 Subject: [PATCH 09/14] Organise code --- homework_2/ls/src/main.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index 93e36da..8983d1c 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -22,17 +22,9 @@ fn main() -> io::Result<()> { if start_path.is_dir() { match file_provider::get_files_in_directory(start_path) { Ok(mut file_models) => { - println!("List of files in {}", start_path.to_string_lossy()); - println!("{:36} {:9}", "Name", "Size"); - - sort_file_table(file_models); - for model in file_models { - println!( - "{:36} {:9}", - model.name + if model.is_directory { "/" } else { "" }, - model.size.to_human_str() - ) - } + let start_path = start_path.to_string_lossy(); + sort_file_table(&mut file_models); + print_file_table(start_path.as_ref(), &file_models); } Err(e) => eprintln!("Error reading files in directory: {}", e) } @@ -44,7 +36,20 @@ fn main() -> io::Result<()> { Ok(()) } -fn sort_file_table(&mut file_table: Vec) { +fn print_file_table(start_path: &str, file_table: &Vec) { + println!("List of files in {}", start_path); + println!("{:36} {:9}", "Name", "Size"); + + for model in file_table { + println!( + "{:36} {:9}", + format!("{}{}", model.name, if model.is_directory { "/" } else { "" }), + model.size.to_human_str() + ) + } +} + +fn sort_file_table(file_table: &mut Vec) { file_table.sort_unstable_by(|a, b| a.is_directory .cmp(&b.is_directory) .reverse() From 74504f2b9f21a7de92e8f08344f602114a5ee4d7 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 11:52:00 +0200 Subject: [PATCH 10/14] Add structopt crate --- homework_2/ls/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/homework_2/ls/Cargo.toml b/homework_2/ls/Cargo.toml index 75457b0..627a9bb 100644 --- a/homework_2/ls/Cargo.toml +++ b/homework_2/ls/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +structopt = "0.3.21" From 655b276c8da563611f2326f210cd7b5b7fdc5e20 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 12:14:10 +0200 Subject: [PATCH 11/14] Parse cli arguments, add ability to not print hidden items --- homework_2/ls/src/main.rs | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index 8983d1c..c39db52 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -3,20 +3,25 @@ mod providers; use std::env; use std::io; -use std::path::{Path}; +use std::path::PathBuf; use providers::file_provider; +use structopt::StructOpt; use crate::models::FileModel; +use std::env::args; -fn main() -> io::Result<()> { - // Collecting command line arguments - let args: Vec = env::args().collect(); - - // Making sure there is a filepath provided - assert_eq!(args.len(), 2); +#[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, +} - // Getting that filepath provided to us by the user - let file_path = &args[1]; - let start_path = Path::new(file_path); +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() { @@ -24,6 +29,7 @@ fn main() -> io::Result<()> { 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); } Err(e) => eprintln!("Error reading files in directory: {}", e) @@ -36,6 +42,10 @@ fn main() -> io::Result<()> { Ok(()) } +fn filter_file_table(file_table: &mut Vec, should_show_hidden: bool) { + file_table.retain(|f| !f.is_hidden || should_show_hidden) +} + fn print_file_table(start_path: &str, file_table: &Vec) { println!("List of files in {}", start_path); println!("{:36} {:9}", "Name", "Size"); From c6d9158e706cbe4614a321b163fe0612d8e630e4 Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 12:16:08 +0200 Subject: [PATCH 12/14] Implement human-readable argument --- homework_2/ls/src/main.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index c39db52..fbea913 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -1,13 +1,11 @@ mod models; mod providers; -use std::env; use std::io; use std::path::PathBuf; use providers::file_provider; use structopt::StructOpt; use crate::models::FileModel; -use std::env::args; #[derive(StructOpt)] struct CliArgs { @@ -30,7 +28,7 @@ fn main() -> io::Result<()> { 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); + print_file_table(start_path.as_ref(), &file_models, args.human_readable); } Err(e) => eprintln!("Error reading files in directory: {}", e) } @@ -46,7 +44,7 @@ fn filter_file_table(file_table: &mut Vec, should_show_hidden: bool) file_table.retain(|f| !f.is_hidden || should_show_hidden) } -fn print_file_table(start_path: &str, file_table: &Vec) { +fn print_file_table(start_path: &str, file_table: &Vec, human_readable: bool) { println!("List of files in {}", start_path); println!("{:36} {:9}", "Name", "Size"); @@ -54,7 +52,7 @@ fn print_file_table(start_path: &str, file_table: &Vec) { println!( "{:36} {:9}", format!("{}{}", model.name, if model.is_directory { "/" } else { "" }), - model.size.to_human_str() + if human_readable { model.size.to_human_str() } else { model.size.to_raw_str() } ) } } From cfe01779dfced803fba0b73dfb6c129cf72cb66d Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Fri, 26 Mar 2021 12:30:27 +0200 Subject: [PATCH 13/14] Handle single-file argument properly --- homework_2/ls/src/main.rs | 25 +++++++++++++++++-------- homework_2/ls/src/providers.rs | 8 ++++---- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/homework_2/ls/src/main.rs b/homework_2/ls/src/main.rs index fbea913..20f212a 100644 --- a/homework_2/ls/src/main.rs +++ b/homework_2/ls/src/main.rs @@ -26,15 +26,20 @@ fn main() -> io::Result<()> { 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) + Err(e) => { + eprintln!("Error reading files in directory: {}", e); + return Err(e); + } } } else { - // If the path provided is a single file, just print its name - println!("{}", start_path.file_name().unwrap().to_string_lossy()); + 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(()) @@ -49,14 +54,18 @@ fn print_file_table(start_path: &str, file_table: &Vec, human_readabl println!("{:36} {:9}", "Name", "Size"); for model in file_table { - 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() } - ) + 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) { file_table.sort_unstable_by(|a, b| a.is_directory .cmp(&b.is_directory) diff --git a/homework_2/ls/src/providers.rs b/homework_2/ls/src/providers.rs index c95b02a..78b43fc 100644 --- a/homework_2/ls/src/providers.rs +++ b/homework_2/ls/src/providers.rs @@ -2,7 +2,6 @@ pub mod file_provider { use std::path::Path; use crate::models::{FileModel, FileSize}; use std::{io, fs}; - use std::fs::DirEntry; use std::io::Error; pub fn get_files_in_directory(directory: &Path) -> Result, Error> { @@ -11,14 +10,15 @@ pub mod file_provider { for entry in fs::read_dir(directory)? { let entry = entry?; - file_vector.push(parse_dir_entry(&entry)?); + file_vector.push(parse_dir_entry(&entry.path().as_path())?); } Ok(file_vector) } - fn parse_dir_entry(entry: &DirEntry) -> io::Result { + pub fn parse_dir_entry(entry: &Path) -> io::Result { let name = { - let os_file_name = entry.file_name(); + let os_file_name = entry.file_name() + .expect("Could not read file name from a given path"); String::from(os_file_name.to_string_lossy()) }; let metadata = entry.metadata()?; From f50210431463181d34c988bda7f741bc9b9743cb Mon Sep 17 00:00:00 2001 From: Maksym-Yurii Rudko Date: Tue, 6 Apr 2021 20:17:03 +0300 Subject: [PATCH 14/14] Add Cargo.lock --- homework_2/ls/Cargo.lock | 223 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 homework_2/ls/Cargo.lock diff --git a/homework_2/ls/Cargo.lock b/homework_2/ls/Cargo.lock new file mode 100644 index 0000000..4d3603b --- /dev/null +++ b/homework_2/ls/Cargo.lock @@ -0,0 +1,223 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +dependencies = [ + "ansi_term", + "atty", + "bitflags", + "strsim", + "textwrap", + "unicode-width", + "vec_map", +] + +[[package]] +name = "heck" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cbf45460356b7deeb5e3415b5563308c0a9b057c85e12b06ad551f98d0a6ac" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.91" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7" + +[[package]] +name = "ls" +version = "0.1.0" +dependencies = [ + "structopt", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + +[[package]] +name = "structopt" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5277acd7ee46e63e5168a80734c9f6ee81b1367a7d8772a2d765df2a3705d28c" +dependencies = [ + "clap", + "lazy_static", + "structopt-derive", +] + +[[package]] +name = "structopt-derive" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ba9cdfda491b814720b6b06e0cac513d922fc407582032e8706e9f137976f90" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fd9d1e9976102a03c542daa2eff1b43f9d72306342f3f8b3ed5fb8908195d6f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "unicode-segmentation" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0d2e7be6ae3a5fa87eed5fb451aff96f2573d2694942e40543ae0bbe19c796" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"