From 768a50b502d56530bd455a57dbbd8a58c32de053 Mon Sep 17 00:00:00 2001 From: sagie gur ari Date: Fri, 3 Jan 2020 11:38:45 +0000 Subject: [PATCH] ls command #9 --- CHANGELOG.md | 1 + docs/sdk.md | 51 ++++++ duckscript_sdk/src/sdk/std/fs/list/help.md | 43 +++++ duckscript_sdk/src/sdk/std/fs/list/mod.rs | 157 ++++++++++++++++++ .../src/sdk/std/fs/list/mod_test.rs | 71 ++++++++ duckscript_sdk/src/sdk/std/fs/mod.rs | 2 + duckscript_sdk/src/sdk/std/fs/print/mod.rs | 3 +- examples/ls.ds | 21 +++ 8 files changed, 347 insertions(+), 2 deletions(-) create mode 100644 duckscript_sdk/src/sdk/std/fs/list/help.md create mode 100755 duckscript_sdk/src/sdk/std/fs/list/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/fs/list/mod_test.rs create mode 100644 examples/ls.ds diff --git a/CHANGELOG.md b/CHANGELOG.md index 270454f..815eeb6 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ### v0.1.2 +* New **ls** command #9 * New **cp** command #7 * New **man** command #16 * New **calc** command #10 diff --git a/docs/sdk.md b/docs/sdk.md index c286132..b900f01 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -25,6 +25,7 @@ * [sdk::fs::GetCanonicalPath (canonicalize)](#sdk__fs__GetCanonicalPath) * [sdk::fs::GetFileName (basename)](#sdk__fs__GetFileName) * [sdk::fs::GetParentDirectory (dirname)](#sdk__fs__GetParentDirectory) +* [sdk::fs::List (ls)](#sdk__fs__List) * [sdk::fs::MovePath (mv)](#sdk__fs__MovePath) * [sdk::fs::Print (cat)](#sdk__fs__Print) * [sdk::fs::Read (readfile)](#sdk__fs__Read) @@ -973,6 +974,56 @@ directory = dirname ./dir/file.txt #### Aliases: dirname + +## sdk::fs::List +```sh +var = ls [flags] [path] +``` + +Lists the file/directory contents.
+If no path is provided, the current working directory will be used.
+The supported flags are: + +* -l - Shows extended information + +#### Parameters + +* Optional flags (currently only -l is supported) +* Optional path (if not provided, current working directory is used) + +#### Return Value + +**true** is operation was successful. + +#### Examples + +```sh +# prints current directory content +ls + +# prints current directory content +ls . + +# prints examples directory content +ls ./examples + +# prints examples directory content with extended info +ls -l ./examples + +# prints current directory content with extended info +ls -l + +# prints file name +ls ./examples/ls.ds + +# prints file name with extended info +ls -l ./examples/ls.ds +``` + + +#### Aliases: +ls + ## sdk::fs::MovePath ```sh diff --git a/duckscript_sdk/src/sdk/std/fs/list/help.md b/duckscript_sdk/src/sdk/std/fs/list/help.md new file mode 100644 index 0000000..91690e9 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/fs/list/help.md @@ -0,0 +1,43 @@ +```sh +var = ls [flags] [path] +``` + +Lists the file/directory contents.
+If no path is provided, the current working directory will be used.
+The supported flags are: + +* -l - Shows extended information + +#### Parameters + +* Optional flags (currently only -l is supported) +* Optional path (if not provided, current working directory is used) + +#### Return Value + +**true** is operation was successful. + +#### Examples + +```sh +# prints current directory content +ls + +# prints current directory content +ls . + +# prints examples directory content +ls ./examples + +# prints examples directory content with extended info +ls -l ./examples + +# prints current directory content with extended info +ls -l + +# prints file name +ls ./examples/ls.ds + +# prints file name with extended info +ls -l ./examples/ls.ds +``` diff --git a/duckscript_sdk/src/sdk/std/fs/list/mod.rs b/duckscript_sdk/src/sdk/std/fs/list/mod.rs new file mode 100755 index 0000000..6009992 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/fs/list/mod.rs @@ -0,0 +1,157 @@ +use crate::utils::{flags, io, pckg}; +use duckscript::types::command::{Command, CommandResult}; +use fs_extra::dir::{ls, DirEntryAttr, DirEntryValue}; +use std::collections::{HashMap, HashSet}; +use std::path::Path; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +fn get_string_value( + key: DirEntryAttr, + attributes: &HashMap, +) -> String { + match attributes.get(&key) { + Some(ref entry_value) => match entry_value { + DirEntryValue::String(value) => value.to_string(), + _ => "".to_string(), + }, + None => "".to_string(), + } +} + +fn get_u64_value(key: DirEntryAttr, attributes: &HashMap) -> String { + match attributes.get(&key) { + Some(ref entry_value) => match entry_value { + DirEntryValue::U64(value) => value.to_string(), + _ => "".to_string(), + }, + None => "".to_string(), + } +} + +fn get_boolean_value(key: DirEntryAttr, attributes: &HashMap) -> bool { + match attributes.get(&key) { + Some(ref entry_value) => match entry_value { + DirEntryValue::Boolean(value) => *value, + _ => false, + }, + None => false, + } +} + +fn print_entry(item: &HashMap, extended_details: bool) { + if extended_details { + let directory_flag = if get_boolean_value(DirEntryAttr::IsDir, &item) { + "" + } else { + "" + }; + + println!( + "{}\t{}\t{}", + get_u64_value(DirEntryAttr::FileSize, &item), + directory_flag, + get_string_value(DirEntryAttr::FullName, &item) + ); + } else { + println!("{} ", get_string_value(DirEntryAttr::FullName, &item)); + } +} + +struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "List") + } + + fn aliases(&self) -> Vec { + vec!["ls".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn run(&self, arguments: Vec) -> CommandResult { + let (path_str, flags) = if arguments.is_empty() { + (".", "") + } else if arguments.len() == 1 { + if flags::is_unix_flags_argument(&arguments[0]) { + (".", arguments[0].as_str()) + } else { + (arguments[0].as_str(), "") + } + } else if flags::is_unix_flags_argument(&arguments[0]) { + (arguments[1].as_str(), arguments[0].as_str()) + } else { + (arguments[0].as_str(), "") + }; + + let path = Path::new(path_str); + + if !path.exists() { + CommandResult::Continue(Some("false".to_string())) + } else { + let extended_details = flags::is_unix_flag_exists('l', flags); + + let mut config = HashSet::new(); + config.insert(DirEntryAttr::FullName); + + if extended_details { + config.insert(DirEntryAttr::FileSize); + config.insert(DirEntryAttr::IsDir); + } + + let (is_file, query_path) = if path.is_file() { + match io::get_parent_directory_name(path_str) { + Some(value) => (true, value), + None => return CommandResult::Continue(Some("false".to_string())), + } + } else { + (false, path_str.to_string()) + }; + + let result = ls(&query_path, &config); + + match result { + Ok(ls_result) => { + let items = ls_result.items; + + if is_file { + let file_name = match io::get_base_name(path_str) { + Some(value) => value, + None => path_str.to_string(), + }; + + for item in items { + let item_name = get_string_value(DirEntryAttr::FullName, &item); + + if item_name == file_name { + print_entry(&item, extended_details); + break; + } + } + } else { + for item in items { + print_entry(&item, extended_details); + } + } + + CommandResult::Continue(Some("true".to_string())) + } + Err(_) => CommandResult::Continue(Some("false".to_string())), + } + } + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/fs/list/mod_test.rs b/duckscript_sdk/src/sdk/std/fs/list/mod_test.rs new file mode 100644 index 0000000..c6f2ece --- /dev/null +++ b/duckscript_sdk/src/sdk/std/fs/list/mod_test.rs @@ -0,0 +1,71 @@ +use super::*; +use crate::test; +use crate::test::CommandValidation; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_validate( + vec![create("")], + "out = ls", + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_flag_only() { + test::run_script_and_validate( + vec![create("")], + "out = ls -l", + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_current_directory() { + test::run_script_and_validate( + vec![create("")], + "out = ls .", + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_current_directory_and_flags() { + test::run_script_and_validate( + vec![create("")], + "out = ls -l .", + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_current_directory_does_not_exist() { + test::run_script_and_validate( + vec![create("")], + "out = ls ./baddirname", + CommandValidation::Match("out".to_string(), "false".to_string()), + ); +} + +#[test] +fn run_file() { + test::run_script_and_validate( + vec![create("")], + "out = ls ./Cargo.toml", + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} + +#[test] +fn run_file_with_flags() { + test::run_script_and_validate( + vec![create("")], + "out = ls -l ./Cargo.toml", + CommandValidation::Match("out".to_string(), "true".to_string()), + ); +} diff --git a/duckscript_sdk/src/sdk/std/fs/mod.rs b/duckscript_sdk/src/sdk/std/fs/mod.rs index 6b6c021..e2d5815 100755 --- a/duckscript_sdk/src/sdk/std/fs/mod.rs +++ b/duckscript_sdk/src/sdk/std/fs/mod.rs @@ -2,6 +2,7 @@ mod basename; mod canonical; mod cp; mod dirname; +mod list; mod mkdir; mod mv; mod print; @@ -24,6 +25,7 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr commands.set(canonical::create(&package))?; commands.set(cp::create(&package))?; commands.set(dirname::create(&package))?; + commands.set(list::create(&package))?; commands.set(mkdir::create(&package))?; commands.set(mv::create(&package))?; commands.set(print::create(&package))?; diff --git a/duckscript_sdk/src/sdk/std/fs/print/mod.rs b/duckscript_sdk/src/sdk/std/fs/print/mod.rs index 19d62a4..4972d52 100755 --- a/duckscript_sdk/src/sdk/std/fs/print/mod.rs +++ b/duckscript_sdk/src/sdk/std/fs/print/mod.rs @@ -1,5 +1,4 @@ -use crate::utils::io; -use crate::utils::pckg; +use crate::utils::{io, pckg}; use duckscript::types::command::{Command, CommandResult}; #[cfg(test)] diff --git a/examples/ls.ds b/examples/ls.ds new file mode 100644 index 0000000..d15ae61 --- /dev/null +++ b/examples/ls.ds @@ -0,0 +1,21 @@ + +# prints current directory content +ls + +# prints current directory content +ls . + +# prints examples directory content +ls ./examples + +# prints examples directory content with extended info +ls -l ./examples + +# prints current directory content with extended info +ls -l + +# prints file name +ls ./examples/ls.ds + +# prints file name with extended info +ls -l ./examples/ls.ds