From f49520025810adc494e48ddc84e49d444486be21 Mon Sep 17 00:00:00 2001 From: sagie gur ari Date: Tue, 30 Jun 2020 21:23:59 +0000 Subject: [PATCH] New ftp_put and ftp_put_in_memory commands --- CHANGELOG.md | 2 + docs/sdk.md | 68 ++++++++++++++++ duckscript_sdk/src/sdk/std/net/ftp/mod.rs | 14 ++++ .../src/sdk/std/net/ftp/put/help.md | 26 ++++++ duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs | 81 +++++++++++++++++++ .../src/sdk/std/net/ftp/put/mod_test.rs | 12 +++ .../src/sdk/std/net/ftp/put_in_memory/help.md | 26 ++++++ .../src/sdk/std/net/ftp/put_in_memory/mod.rs | 64 +++++++++++++++ .../sdk/std/net/ftp/put_in_memory/mod_test.rs | 12 +++ test/std/net/ftp/ftp_put_in_memory_test.ds | 14 ++++ test/std/net/ftp/ftp_put_test.ds | 17 ++++ 11 files changed, 336 insertions(+) create mode 100644 duckscript_sdk/src/sdk/std/net/ftp/put/help.md create mode 100755 duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/net/ftp/put/mod_test.rs create mode 100644 duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/help.md create mode 100755 duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod.rs create mode 100644 duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod_test.rs create mode 100644 test/std/net/ftp/ftp_put_in_memory_test.ds create mode 100644 test/std/net/ftp/ftp_put_test.ds diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f2b95c..19297ee 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ### v0.5.1 +* New ftp_put command. +* New fpt_put_in_memory command. * New ftp_get command. * New ftp_get_in_memory command. * New ftp_list command. diff --git a/docs/sdk.md b/docs/sdk.md index 6c88e84..f0e84b6 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -115,6 +115,8 @@ * [std::net::ftp::GetInMemory (ftp_get_in_memory)](#std__net__ftp__GetInMemory) * [std::net::ftp::List (ftp_list)](#std__net__ftp__List) * [std::net::ftp::NLst (ftp_nlst)](#std__net__ftp__NLst) +* [std::net::ftp::Put (ftp_put)](#std__net__ftp__Put) +* [std::net::ftp::PutInMemory (ftp_put_in_memory)](#std__net__ftp__PutInMemory) * [std::process::Execute (exec)](#std__process__Execute) * [std::process::Exit (exit, quit, q)](#std__process__Exit) * [std::process::ProcessID (pid, process_id)](#std__process__ProcessID) @@ -4281,6 +4283,72 @@ end #### Aliases: ftp_nlst + +## std::net::ftp::Put +```sh +result = ftp_put --host [--port 21] [--username ] [--password ] [--path ] [--type ] --remote-file --local-file +``` + +Invokes the FTP PUT command from the given connection and file details. + +#### Parameters + +* --host - The host name or IP to connect to +* --port - Optional port number to use (by default 21) +* --username - Optional user name used to login (if not user or password provided, no login operation will be invoked) +* --password - Optional password used to login (if not user or password provided, no login operation will be invoked) +* --path - Optional path on the remote server to invoke operation on +* --type - Optional setting of the transfer type as A (ascii) I (image, binary) +* --remote-file - The remote file to upload +* --local-file - The source local file to upload + +#### Return Value + +true if operation was completed. + +#### Examples + +```sh +ftp_put --host myhost --username someuser --password 12345 --remote-file README.md --local-file README.md +``` + + +#### Aliases: +ftp_put + + +## std::net::ftp::PutInMemory +```sh +result = ftp_put_in_memory --host [--port 21] [--username ] [--password ] [--path ] [--type ] --remote-file --content +``` + +Invokes the FTP PUT command from the given connection and file details. + +#### Parameters + +* --host - The host name or IP to connect to +* --port - Optional port number to use (by default 21) +* --username - Optional user name used to login (if not user or password provided, no login operation will be invoked) +* --password - Optional password used to login (if not user or password provided, no login operation will be invoked) +* --path - Optional path on the remote server to invoke operation on +* --type - Optional setting of the transfer type as A (ascii) I (image, binary) +* --remote-file - The remote file to upload +* --content - The textual content to upload + +#### Return Value + +true if operation was completed. + +#### Examples + +```sh +ftp_put_in_memory --host myhost --username someuser --password 12345 --remote-file README.md --content "This is the README content" +``` + + +#### Aliases: +ftp_put_in_memory + ## std::process::Execute ```sh diff --git a/duckscript_sdk/src/sdk/std/net/ftp/mod.rs b/duckscript_sdk/src/sdk/std/net/ftp/mod.rs index 68f6ec1..ff97726 100644 --- a/duckscript_sdk/src/sdk/std/net/ftp/mod.rs +++ b/duckscript_sdk/src/sdk/std/net/ftp/mod.rs @@ -2,6 +2,8 @@ mod get; mod get_in_memory; mod list; mod nlst; +mod put; +mod put_in_memory; use crate::utils::pckg; use duckscript::types::command::{CommandResult, Commands}; @@ -18,6 +20,8 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr commands.set(get_in_memory::create(&package))?; commands.set(list::create(&package))?; commands.set(nlst::create(&package))?; + commands.set(put::create(&package))?; + commands.set(put_in_memory::create(&package))?; Ok(()) } @@ -40,6 +44,7 @@ pub(crate) struct Options { transfer_type: Option, remote_file: Option, local_file: Option, + content: Option, } impl Options { @@ -53,6 +58,7 @@ impl Options { transfer_type: None, remote_file: None, local_file: None, + content: None, } } } @@ -67,6 +73,7 @@ enum LookingFor { TransferType, RemoteFile, LocalFile, + Content, } pub(crate) fn run_with_connection( @@ -112,6 +119,7 @@ fn parse_common_options(arguments: &Vec) -> Result { "--type" => looking_for = LookingFor::TransferType, "--remote-file" => looking_for = LookingFor::RemoteFile, "--local-file" => looking_for = LookingFor::LocalFile, + "--content" => looking_for = LookingFor::Content, _ => (), }, LookingFor::Host => { @@ -174,6 +182,12 @@ fn parse_common_options(arguments: &Vec) -> Result { } looking_for = LookingFor::Flag; } + LookingFor::Content => { + if !argument.is_empty() { + options.content = Some(argument.to_string()); + } + looking_for = LookingFor::Flag; + } } } diff --git a/duckscript_sdk/src/sdk/std/net/ftp/put/help.md b/duckscript_sdk/src/sdk/std/net/ftp/put/help.md new file mode 100644 index 0000000..f66c6e2 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/net/ftp/put/help.md @@ -0,0 +1,26 @@ +```sh +result = ftp_put --host [--port 21] [--username ] [--password ] [--path ] [--type ] --remote-file --local-file +``` + +Invokes the FTP PUT command from the given connection and file details. + +#### Parameters + +* --host - The host name or IP to connect to +* --port - Optional port number to use (by default 21) +* --username - Optional user name used to login (if not user or password provided, no login operation will be invoked) +* --password - Optional password used to login (if not user or password provided, no login operation will be invoked) +* --path - Optional path on the remote server to invoke operation on +* --type - Optional setting of the transfer type as A (ascii) I (image, binary) +* --remote-file - The remote file to upload +* --local-file - The source local file to upload + +#### Return Value + +true if operation was completed. + +#### Examples + +```sh +ftp_put --host myhost --username someuser --password 12345 --remote-file README.md --local-file README.md +``` diff --git a/duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs b/duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs new file mode 100755 index 0000000..a940e14 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs @@ -0,0 +1,81 @@ +use crate::sdk::std::net::ftp::{validate_and_run_with_connection, Options}; +use crate::utils::pckg; +use duckscript::types::command::{Command, CommandResult}; +use fsio::path::as_path::AsPath; +use ftp::FtpStream; +use std::fs::File; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "Put") + } + + fn aliases(&self) -> Vec { + vec!["ftp_put".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn run(&self, arguments: Vec) -> CommandResult { + validate_and_run_with_connection( + &arguments, + &|options: &Options| -> Result<(), String> { + if options.remote_file.is_none() { + Err("Missing remote file name".to_string()) + } else { + let options_clone = options.clone(); + match options_clone.local_file { + Some(local_file) => { + let file_path = local_file.as_path(); + + if file_path.exists() { + if file_path.is_file() { + Ok(()) + } else { + Err("Local path is a directory.".to_string()) + } + } else { + Err("Local file not found.".to_string()) + } + } + None => Err("Missing local file name.".to_string()), + } + } + }, + &mut |options: &Options, ftp_stream: &mut FtpStream| -> CommandResult { + let options_clone = options.clone(); + let remote_file = options_clone.remote_file.unwrap(); + let local_file = options_clone.local_file.unwrap(); + + match File::open(local_file) { + Ok(mut file) => match ftp_stream.put(&remote_file, &mut file) { + Ok(_) => CommandResult::Continue(Some(true.to_string())), + Err(error) => CommandResult::Error(error.to_string()), + }, + Err(error) => CommandResult::Error(error.to_string()), + } + }, + ) + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/net/ftp/put/mod_test.rs b/duckscript_sdk/src/sdk/std/net/ftp/put/mod_test.rs new file mode 100644 index 0000000..195d957 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/net/ftp/put/mod_test.rs @@ -0,0 +1,12 @@ +use super::*; +use crate::test; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = ftp_put", "out"); +} diff --git a/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/help.md b/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/help.md new file mode 100644 index 0000000..4b98ccb --- /dev/null +++ b/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/help.md @@ -0,0 +1,26 @@ +```sh +result = ftp_put_in_memory --host [--port 21] [--username ] [--password ] [--path ] [--type ] --remote-file --content +``` + +Invokes the FTP PUT command from the given connection and file details. + +#### Parameters + +* --host - The host name or IP to connect to +* --port - Optional port number to use (by default 21) +* --username - Optional user name used to login (if not user or password provided, no login operation will be invoked) +* --password - Optional password used to login (if not user or password provided, no login operation will be invoked) +* --path - Optional path on the remote server to invoke operation on +* --type - Optional setting of the transfer type as A (ascii) I (image, binary) +* --remote-file - The remote file to upload +* --content - The textual content to upload + +#### Return Value + +true if operation was completed. + +#### Examples + +```sh +ftp_put_in_memory --host myhost --username someuser --password 12345 --remote-file README.md --content "This is the README content" +``` diff --git a/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod.rs b/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod.rs new file mode 100755 index 0000000..689a937 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod.rs @@ -0,0 +1,64 @@ +use crate::sdk::std::net::ftp::{validate_and_run_with_connection, Options}; +use crate::utils::pckg; +use duckscript::types::command::{Command, CommandResult}; +use ftp::FtpStream; +use std::io::Cursor; + +#[cfg(test)] +#[path = "./mod_test.rs"] +mod mod_test; + +#[derive(Clone)] +pub(crate) struct CommandImpl { + package: String, +} + +impl Command for CommandImpl { + fn name(&self) -> String { + pckg::concat(&self.package, "PutInMemory") + } + + fn aliases(&self) -> Vec { + vec!["ftp_put_in_memory".to_string()] + } + + fn help(&self) -> String { + include_str!("help.md").to_string() + } + + fn clone_and_box(&self) -> Box { + Box::new((*self).clone()) + } + + fn run(&self, arguments: Vec) -> CommandResult { + validate_and_run_with_connection( + &arguments, + &|options: &Options| -> Result<(), String> { + if options.remote_file.is_none() { + Err("Missing remote file name".to_string()) + } else if options.content.is_none() { + Err("Missing content".to_string()) + } else { + Ok(()) + } + }, + &mut |options: &Options, ftp_stream: &mut FtpStream| -> CommandResult { + let options_clone = options.clone(); + let remote_file = options_clone.remote_file.unwrap(); + let content = options_clone.content.unwrap(); + + let mut reader = Cursor::new(content.as_bytes()); + match ftp_stream.put(&remote_file, &mut reader) { + Ok(_) => CommandResult::Continue(Some(true.to_string())), + Err(error) => CommandResult::Error(error.to_string()), + } + }, + ) + } +} + +pub(crate) fn create(package: &str) -> Box { + Box::new(CommandImpl { + package: package.to_string(), + }) +} diff --git a/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod_test.rs b/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod_test.rs new file mode 100644 index 0000000..a4b7ff0 --- /dev/null +++ b/duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod_test.rs @@ -0,0 +1,12 @@ +use super::*; +use crate::test; + +#[test] +fn common_functions() { + test::test_common_command_functions(create("")); +} + +#[test] +fn run_no_args() { + test::run_script_and_error(vec![create("")], "out = ftp_put_in_memory", "out"); +} diff --git a/test/std/net/ftp/ftp_put_in_memory_test.ds b/test/std/net/ftp/ftp_put_in_memory_test.ds new file mode 100644 index 0000000..978bd7e --- /dev/null +++ b/test/std/net/ftp/ftp_put_in_memory_test.ds @@ -0,0 +1,14 @@ + +fn test_auth_error + test_enabled = equals ${TEST_FTP_PUT} true + + if ${test_enabled} + ftp_put_in_memory --host test.rebex.net --username demo --password password --remote-file readme2.txt --content "test content" + + assert_false ${result} + last_error = get_last_error + found = contains "${last_error}" 550 + assert ${found} + end +end + diff --git a/test/std/net/ftp/ftp_put_test.ds b/test/std/net/ftp/ftp_put_test.ds new file mode 100644 index 0000000..173f79a --- /dev/null +++ b/test/std/net/ftp/ftp_put_test.ds @@ -0,0 +1,17 @@ + +fn test_auth_error + test_enabled = equals ${TEST_FTP_PUT} true + + if ${test_enabled} + filename = set ./target/_duckscript_test/net/ftp/put/readme.txt + writefile ${filename} "test content" + + result = ftp_put --host test.rebex.net --username demo --password password --remote-file readme2.txt --local-file ${filename} + + assert_false ${result} + last_error = get_last_error + found = contains "${last_error}" 550 + assert ${found} + end +end +