mirror of
https://github.com/sagiegurari/duckscript
synced 2024-10-14 11:53:05 +00:00
commit
0fe8f0b2de
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -1,5 +1,16 @@
|
|||
## CHANGELOG
|
||||
|
||||
### v0.6.0
|
||||
|
||||
* New ftp_put command.
|
||||
* New fpt_put_in_memory command.
|
||||
* New ftp_get command.
|
||||
* New ftp_get_in_memory command.
|
||||
* New ftp_list command.
|
||||
* New ftp_nlst command.
|
||||
* New noop command.
|
||||
* \[Breaking Change\] Conditions to support function calls #116
|
||||
|
||||
### v0.5.0 (2020-06-06)
|
||||
|
||||
* Fixed end command bug which directed execution to wrong sub command when multiple script contexts are running #110
|
||||
|
|
235
docs/sdk.md
235
docs/sdk.md
|
@ -2,6 +2,7 @@
|
|||
* [std::Echo (echo)](#std__Echo)
|
||||
* [std::Eval (eval)](#std__Eval)
|
||||
* [std::IsDefined (is_defined)](#std__IsDefined)
|
||||
* [std::Noop (noop)](#std__Noop)
|
||||
* [std::Not (not)](#std__Not)
|
||||
* [std::ReadUserInput (read)](#std__ReadUserInput)
|
||||
* [std::Release (release)](#std__Release)
|
||||
|
@ -111,6 +112,12 @@
|
|||
* [std::net::Hostname (hostname)](#std__net__Hostname)
|
||||
* [std::net::HttpClient (http_client)](#std__net__HttpClient)
|
||||
* [std::net::WGet (wget)](#std__net__WGet)
|
||||
* [std::net::ftp::Get (ftp_get)](#std__net__ftp__Get)
|
||||
* [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)
|
||||
|
@ -238,6 +245,32 @@ exists = is_defined key
|
|||
#### Aliases:
|
||||
is_defined
|
||||
|
||||
<a name="std__Noop"></a>
|
||||
## std::Noop
|
||||
```sh
|
||||
noop
|
||||
```
|
||||
|
||||
Empty function that does nothing and returns none.
|
||||
|
||||
#### Parameters
|
||||
|
||||
All parameters are ignored
|
||||
|
||||
#### Return Value
|
||||
|
||||
None
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
noop
|
||||
```
|
||||
|
||||
|
||||
#### Aliases:
|
||||
noop
|
||||
|
||||
<a name="std__Not"></a>
|
||||
## std::Not
|
||||
```sh
|
||||
|
@ -4141,6 +4174,208 @@ http_client --method "${scope::wget::method}" --output-file "${scope::wget::file
|
|||
#### Aliases:
|
||||
wget
|
||||
|
||||
<a name="std__net__ftp__Get"></a>
|
||||
## std::net::ftp::Get
|
||||
```sh
|
||||
result = ftp_get --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name> --local-file <file name>
|
||||
```
|
||||
|
||||
Invokes the FTP GET 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 download
|
||||
* --local-file - The target local file name
|
||||
|
||||
#### Return Value
|
||||
|
||||
true if operation was completed.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
ftp_get --host myhost --username someuser --password 12345 --remote-file README.md --local-file README.md
|
||||
```
|
||||
|
||||
|
||||
#### Aliases:
|
||||
ftp_get
|
||||
|
||||
<a name="std__net__ftp__GetInMemory"></a>
|
||||
## std::net::ftp::GetInMemory
|
||||
```sh
|
||||
handle = ftp_get_in_memory --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name>
|
||||
```
|
||||
|
||||
Invokes the FTP GET 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 download
|
||||
|
||||
#### Return Value
|
||||
|
||||
The binary data handle.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
handle = ftp_get_in_memory --host myhost --username someuser --password 12345 --remote-file README.md
|
||||
text = bytes_to_string ${handle}
|
||||
```
|
||||
|
||||
|
||||
#### Aliases:
|
||||
ftp_get_in_memory
|
||||
|
||||
<a name="std__net__ftp__List"></a>
|
||||
## std::net::ftp::List
|
||||
```sh
|
||||
handle = ftp_list --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>]
|
||||
```
|
||||
|
||||
Invokes the FTP LIST command from the given connection details and path.<br>
|
||||
Returns a handle to an array of all response entries.
|
||||
|
||||
#### 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
|
||||
|
||||
#### Return Value
|
||||
|
||||
A handle to an array holding all entries.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
handle = ftp_list --host myhost --username someuser --password 12345
|
||||
|
||||
for entry in ${handle}
|
||||
echo ${entry}
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
#### Aliases:
|
||||
ftp_list
|
||||
|
||||
<a name="std__net__ftp__NLst"></a>
|
||||
## std::net::ftp::NLst
|
||||
```sh
|
||||
handle = ftp_nlst --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>]
|
||||
```
|
||||
|
||||
Invokes the FTP NLST command from the given connection details and path.<br>
|
||||
Returns a handle to an array of all response entries.
|
||||
|
||||
#### 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
|
||||
|
||||
#### Return Value
|
||||
|
||||
A handle to an array holding all entries.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
handle = ftp_nlst --host myhost --username someuser --password 12345
|
||||
|
||||
for entry in ${handle}
|
||||
echo ${entry}
|
||||
end
|
||||
```
|
||||
|
||||
|
||||
#### Aliases:
|
||||
ftp_nlst
|
||||
|
||||
<a name="std__net__ftp__Put"></a>
|
||||
## std::net::ftp::Put
|
||||
```sh
|
||||
result = ftp_put --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name> --local-file <file name>
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
<a name="std__net__ftp__PutInMemory"></a>
|
||||
## std::net::ftp::PutInMemory
|
||||
```sh
|
||||
result = ftp_put_in_memory --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name> --content <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
|
||||
|
||||
<a name="std__process__Execute"></a>
|
||||
## std::process::Execute
|
||||
```sh
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
anonymous_parameters,
|
||||
arithmetic_overflow,
|
||||
array_into_iter,
|
||||
asm_sub_register,
|
||||
bindings_with_variant_name,
|
||||
cenum_impl_drop_cast,
|
||||
clashing_extern_declarations,
|
||||
coherence_leak_check,
|
||||
conflicting_repr_hints,
|
||||
confusable_idents,
|
||||
const_err,
|
||||
dead_code,
|
||||
deprecated,
|
||||
|
@ -17,7 +21,9 @@
|
|||
ill_formed_attribute_input,
|
||||
illegal_floating_point_literal_pattern,
|
||||
improper_ctypes,
|
||||
improper_ctypes_definitions,
|
||||
incomplete_features,
|
||||
incomplete_include,
|
||||
indirect_structural_match,
|
||||
inline_no_sanitize,
|
||||
invalid_codeblock_attribute,
|
||||
|
@ -32,6 +38,7 @@
|
|||
missing_crate_level_docs,
|
||||
missing_docs,
|
||||
missing_fragment_specifier,
|
||||
mixed_script_confusables,
|
||||
mutable_borrow_reservation_conflict,
|
||||
mutable_transmutes,
|
||||
no_mangle_const_items,
|
||||
|
@ -59,6 +66,7 @@
|
|||
trivial_numeric_casts,
|
||||
type_alias_bounds,
|
||||
tyvar_behind_raw_pointer,
|
||||
unaligned_references,
|
||||
uncommon_codepoints,
|
||||
unconditional_panic,
|
||||
unconditional_recursion,
|
||||
|
@ -75,6 +83,7 @@
|
|||
unused_attributes,
|
||||
unused_braces,
|
||||
unused_comparisons,
|
||||
unused_crate_dependencies,
|
||||
unused_doc_comments,
|
||||
unused_extern_crates,
|
||||
unused_features,
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
anonymous_parameters,
|
||||
arithmetic_overflow,
|
||||
array_into_iter,
|
||||
asm_sub_register,
|
||||
bindings_with_variant_name,
|
||||
cenum_impl_drop_cast,
|
||||
clashing_extern_declarations,
|
||||
coherence_leak_check,
|
||||
conflicting_repr_hints,
|
||||
confusable_idents,
|
||||
const_err,
|
||||
dead_code,
|
||||
deprecated,
|
||||
|
@ -17,7 +21,9 @@
|
|||
ill_formed_attribute_input,
|
||||
illegal_floating_point_literal_pattern,
|
||||
improper_ctypes,
|
||||
improper_ctypes_definitions,
|
||||
incomplete_features,
|
||||
incomplete_include,
|
||||
indirect_structural_match,
|
||||
inline_no_sanitize,
|
||||
invalid_codeblock_attribute,
|
||||
|
@ -32,6 +38,7 @@
|
|||
missing_crate_level_docs,
|
||||
missing_docs,
|
||||
missing_fragment_specifier,
|
||||
mixed_script_confusables,
|
||||
mutable_borrow_reservation_conflict,
|
||||
mutable_transmutes,
|
||||
no_mangle_const_items,
|
||||
|
@ -59,6 +66,7 @@
|
|||
trivial_numeric_casts,
|
||||
type_alias_bounds,
|
||||
tyvar_behind_raw_pointer,
|
||||
unaligned_references,
|
||||
uncommon_codepoints,
|
||||
unconditional_panic,
|
||||
unconditional_recursion,
|
||||
|
@ -75,6 +83,7 @@
|
|||
unused_attributes,
|
||||
unused_braces,
|
||||
unused_comparisons,
|
||||
unused_crate_dependencies,
|
||||
unused_doc_comments,
|
||||
unused_extern_crates,
|
||||
unused_features,
|
||||
|
|
|
@ -29,6 +29,7 @@ cfg-if = "^0.1"
|
|||
duckscript = { version = "^0.5.0", path = "../duckscript" }
|
||||
fs_extra = "^1"
|
||||
fsio = { version = "^0.1", features = ["temp-path"] }
|
||||
ftp = "^3"
|
||||
glob = "^0.3"
|
||||
home = "^0.5"
|
||||
java-properties = "^1"
|
||||
|
|
|
@ -4,9 +4,13 @@
|
|||
anonymous_parameters,
|
||||
arithmetic_overflow,
|
||||
array_into_iter,
|
||||
asm_sub_register,
|
||||
bindings_with_variant_name,
|
||||
cenum_impl_drop_cast,
|
||||
clashing_extern_declarations,
|
||||
coherence_leak_check,
|
||||
conflicting_repr_hints,
|
||||
confusable_idents,
|
||||
const_err,
|
||||
dead_code,
|
||||
deprecated,
|
||||
|
@ -17,7 +21,9 @@
|
|||
ill_formed_attribute_input,
|
||||
illegal_floating_point_literal_pattern,
|
||||
improper_ctypes,
|
||||
improper_ctypes_definitions,
|
||||
incomplete_features,
|
||||
incomplete_include,
|
||||
indirect_structural_match,
|
||||
inline_no_sanitize,
|
||||
invalid_codeblock_attribute,
|
||||
|
@ -32,6 +38,7 @@
|
|||
missing_crate_level_docs,
|
||||
missing_docs,
|
||||
missing_fragment_specifier,
|
||||
mixed_script_confusables,
|
||||
mutable_borrow_reservation_conflict,
|
||||
mutable_transmutes,
|
||||
no_mangle_const_items,
|
||||
|
@ -59,6 +66,7 @@
|
|||
trivial_numeric_casts,
|
||||
type_alias_bounds,
|
||||
tyvar_behind_raw_pointer,
|
||||
unaligned_references,
|
||||
uncommon_codepoints,
|
||||
unconditional_panic,
|
||||
unconditional_recursion,
|
||||
|
@ -75,6 +83,7 @@
|
|||
unused_attributes,
|
||||
unused_braces,
|
||||
unused_comparisons,
|
||||
unused_crate_dependencies,
|
||||
unused_doc_comments,
|
||||
unused_extern_crates,
|
||||
unused_features,
|
||||
|
|
|
@ -524,8 +524,14 @@ impl Command for ReturnCommand {
|
|||
None => (),
|
||||
};
|
||||
|
||||
let output = if arguments.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(arguments[0].clone())
|
||||
};
|
||||
|
||||
let next_line = call_info.call_line + 1;
|
||||
CommandResult::GoTo(None, GoToValue::Line(next_line))
|
||||
CommandResult::GoTo(output, GoToValue::Line(next_line))
|
||||
} else {
|
||||
push_to_call_stack(state, &call_info);
|
||||
CommandResult::Continue(None)
|
||||
|
|
|
@ -344,7 +344,13 @@ impl Command for IfCommand {
|
|||
self.package.clone(),
|
||||
) {
|
||||
Ok(if_else_info) => {
|
||||
match condition::eval_condition(arguments, state, variables, commands) {
|
||||
match condition::eval_condition(
|
||||
arguments,
|
||||
instructions,
|
||||
state,
|
||||
variables,
|
||||
commands,
|
||||
) {
|
||||
Ok(passed) => {
|
||||
if passed {
|
||||
let next_line = if if_else_info.else_lines.is_empty() {
|
||||
|
@ -422,7 +428,7 @@ impl Command for ElseIfCommand {
|
|||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
_output_variable: Option<String>,
|
||||
_instructions: &Vec<Instruction>,
|
||||
instructions: &Vec<Instruction>,
|
||||
commands: &mut Commands,
|
||||
line: usize,
|
||||
) -> CommandResult {
|
||||
|
@ -436,7 +442,7 @@ impl Command for ElseIfCommand {
|
|||
CommandResult::GoTo(None, GoToValue::Line(next_line))
|
||||
} else {
|
||||
let if_else_info = call_info.meta_info.clone();
|
||||
match condition::eval_condition(arguments, state, variables, commands) {
|
||||
match condition::eval_condition(arguments, instructions, state, variables, commands) {
|
||||
Ok(passed) => {
|
||||
if passed {
|
||||
let next_line = if call_info.else_line_index + 1 < if_else_info.else_lines.len() {
|
||||
|
|
|
@ -10,6 +10,7 @@ mod lib;
|
|||
mod man;
|
||||
mod math;
|
||||
mod net;
|
||||
mod noop;
|
||||
mod not;
|
||||
pub(crate) mod on_error;
|
||||
mod process;
|
||||
|
@ -32,6 +33,7 @@ pub(crate) fn load(commands: &mut Commands) -> Result<(), ScriptError> {
|
|||
commands.set(eval::create(PACKAGE))?;
|
||||
commands.set(is_defined::create(PACKAGE))?;
|
||||
commands.set(man::create(PACKAGE))?;
|
||||
commands.set(noop::create(PACKAGE))?;
|
||||
commands.set(not::create(PACKAGE))?;
|
||||
commands.set(read::create(PACKAGE))?;
|
||||
commands.set(release::create(PACKAGE))?;
|
||||
|
|
26
duckscript_sdk/src/sdk/std/net/ftp/get/help.md
Normal file
26
duckscript_sdk/src/sdk/std/net/ftp/get/help.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
```sh
|
||||
result = ftp_get --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name> --local-file <file name>
|
||||
```
|
||||
|
||||
Invokes the FTP GET 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 download
|
||||
* --local-file - The target local file name
|
||||
|
||||
#### Return Value
|
||||
|
||||
true if operation was completed.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
ftp_get --host myhost --username someuser --password 12345 --remote-file README.md --local-file README.md
|
||||
```
|
97
duckscript_sdk/src/sdk/std/net/ftp/get/mod.rs
Executable file
97
duckscript_sdk/src/sdk/std/net/ftp/get/mod.rs
Executable file
|
@ -0,0 +1,97 @@
|
|||
use crate::sdk::std::net::ftp::{validate_and_run_with_connection, Options};
|
||||
use crate::utils::io::create_empty_file;
|
||||
use crate::utils::pckg;
|
||||
use duckscript::types::command::{Command, CommandResult};
|
||||
use ftp::{FtpError, FtpStream};
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{BufWriter, Error, Read, Write};
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "./mod_test.rs"]
|
||||
mod mod_test;
|
||||
|
||||
fn write_file(reader: &mut dyn Read, target_file: &str) -> Result<(), Error> {
|
||||
let mut file = OpenOptions::new().append(true).open(target_file)?;
|
||||
{
|
||||
let mut writer = BufWriter::new(&mut file);
|
||||
|
||||
let mut buffer = [0; 10240];
|
||||
loop {
|
||||
let read_size = reader.read(&mut buffer)?;
|
||||
if read_size > 0 {
|
||||
writer.write_all(&buffer[0..read_size])?;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
writer.flush()?;
|
||||
}
|
||||
file.sync_all()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct CommandImpl {
|
||||
package: String,
|
||||
}
|
||||
|
||||
impl Command for CommandImpl {
|
||||
fn name(&self) -> String {
|
||||
pckg::concat(&self.package, "Get")
|
||||
}
|
||||
|
||||
fn aliases(&self) -> Vec<String> {
|
||||
vec!["ftp_get".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn run(&self, arguments: Vec<String>) -> 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.local_file.is_none() {
|
||||
Err("Missing local file name.".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 local_file = options_clone.local_file.unwrap();
|
||||
|
||||
match create_empty_file(&local_file) {
|
||||
Ok(_) => {
|
||||
match ftp_stream.retr(&remote_file, |reader| {
|
||||
match write_file(reader, &local_file) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(error) => Err(FtpError::InvalidResponse(error.to_string())),
|
||||
}
|
||||
}) {
|
||||
Ok(_) => CommandResult::Continue(Some(true.to_string())),
|
||||
Err(error) => CommandResult::Error(error.to_string()),
|
||||
}
|
||||
}
|
||||
Err(error) => CommandResult::Error(error),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create(package: &str) -> Box<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
12
duckscript_sdk/src/sdk/std/net/ftp/get/mod_test.rs
Normal file
12
duckscript_sdk/src/sdk/std/net/ftp/get/mod_test.rs
Normal file
|
@ -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_get", "out");
|
||||
}
|
26
duckscript_sdk/src/sdk/std/net/ftp/get_in_memory/help.md
Normal file
26
duckscript_sdk/src/sdk/std/net/ftp/get_in_memory/help.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
```sh
|
||||
handle = ftp_get_in_memory --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name>
|
||||
```
|
||||
|
||||
Invokes the FTP GET 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 download
|
||||
|
||||
#### Return Value
|
||||
|
||||
The binary data handle.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
handle = ftp_get_in_memory --host myhost --username someuser --password 12345 --remote-file README.md
|
||||
text = bytes_to_string ${handle}
|
||||
```
|
80
duckscript_sdk/src/sdk/std/net/ftp/get_in_memory/mod.rs
Executable file
80
duckscript_sdk/src/sdk/std/net/ftp/get_in_memory/mod.rs
Executable file
|
@ -0,0 +1,80 @@
|
|||
use crate::sdk::std::net::ftp::{validate_and_run_with_connection, Options};
|
||||
use crate::utils::pckg;
|
||||
use crate::utils::state::put_handle;
|
||||
use duckscript::types::command::{Command, CommandResult, Commands};
|
||||
use duckscript::types::instruction::Instruction;
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use ftp::FtpStream;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[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, "GetInMemory")
|
||||
}
|
||||
|
||||
fn aliases(&self) -> Vec<String> {
|
||||
vec!["ftp_get_in_memory".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn requires_context(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_with_context(
|
||||
&self,
|
||||
arguments: Vec<String>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
_variables: &mut HashMap<String, String>,
|
||||
_output_variable: Option<String>,
|
||||
_instructions: &Vec<Instruction>,
|
||||
_commands: &mut Commands,
|
||||
_line: usize,
|
||||
) -> 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 {
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
&mut |options: &Options, ftp_stream: &mut FtpStream| -> CommandResult {
|
||||
let options_clone = options.clone();
|
||||
let remote_file = options_clone.remote_file.unwrap();
|
||||
|
||||
match ftp_stream.simple_retr(&remote_file) {
|
||||
Ok(binary) => {
|
||||
let key = put_handle(state, StateValue::ByteArray(binary.into_inner()));
|
||||
|
||||
CommandResult::Continue(Some(key))
|
||||
}
|
||||
Err(error) => CommandResult::Error(error.to_string()),
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create(package: &str) -> Box<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
12
duckscript_sdk/src/sdk/std/net/ftp/get_in_memory/mod_test.rs
Normal file
12
duckscript_sdk/src/sdk/std/net/ftp/get_in_memory/mod_test.rs
Normal file
|
@ -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_get_in_memory", "out");
|
||||
}
|
28
duckscript_sdk/src/sdk/std/net/ftp/list/help.md
Normal file
28
duckscript_sdk/src/sdk/std/net/ftp/list/help.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
```sh
|
||||
handle = ftp_list --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>]
|
||||
```
|
||||
|
||||
Invokes the FTP LIST command from the given connection details and path.<br>
|
||||
Returns a handle to an array of all response entries.
|
||||
|
||||
#### 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
|
||||
|
||||
#### Return Value
|
||||
|
||||
A handle to an array holding all entries.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
handle = ftp_list --host myhost --username someuser --password 12345
|
||||
|
||||
for entry in ${handle}
|
||||
echo ${entry}
|
||||
end
|
||||
```
|
75
duckscript_sdk/src/sdk/std/net/ftp/list/mod.rs
Executable file
75
duckscript_sdk/src/sdk/std/net/ftp/list/mod.rs
Executable file
|
@ -0,0 +1,75 @@
|
|||
use crate::sdk::std::net::ftp::{run_with_connection, Options};
|
||||
use crate::utils::pckg;
|
||||
use crate::utils::state::put_handle;
|
||||
use duckscript::types::command::{Command, CommandResult, Commands};
|
||||
use duckscript::types::instruction::Instruction;
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use ftp::FtpStream;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[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, "List")
|
||||
}
|
||||
|
||||
fn aliases(&self) -> Vec<String> {
|
||||
vec!["ftp_list".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn requires_context(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_with_context(
|
||||
&self,
|
||||
arguments: Vec<String>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
_variables: &mut HashMap<String, String>,
|
||||
_output_variable: Option<String>,
|
||||
_instructions: &Vec<Instruction>,
|
||||
_commands: &mut Commands,
|
||||
_line: usize,
|
||||
) -> CommandResult {
|
||||
run_with_connection(&arguments, &mut |_options: &Options,
|
||||
ftp_stream: &mut FtpStream|
|
||||
-> CommandResult {
|
||||
match ftp_stream.list(None) {
|
||||
Ok(output) => {
|
||||
let mut array = vec![];
|
||||
|
||||
for item in output {
|
||||
array.push(StateValue::String(item));
|
||||
}
|
||||
|
||||
let key = put_handle(state, StateValue::List(array));
|
||||
|
||||
CommandResult::Continue(Some(key))
|
||||
}
|
||||
Err(error) => CommandResult::Error(error.to_string()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create(package: &str) -> Box<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
22
duckscript_sdk/src/sdk/std/net/ftp/list/mod_test.rs
Normal file
22
duckscript_sdk/src/sdk/std/net/ftp/list/mod_test.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
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_error(vec![create("")], "out = ftp_list", "out");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_valid() {
|
||||
test::run_script_and_validate(
|
||||
vec![create("")],
|
||||
"out = ftp_list --host test.rebex.net --username demo --password password",
|
||||
CommandValidation::Contains("out".to_string(), "handle:".to_string()),
|
||||
);
|
||||
}
|
252
duckscript_sdk/src/sdk/std/net/ftp/mod.rs
Normal file
252
duckscript_sdk/src/sdk/std/net/ftp/mod.rs
Normal file
|
@ -0,0 +1,252 @@
|
|||
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};
|
||||
use duckscript::types::error::ScriptError;
|
||||
use ftp::types::{FileType, FormatControl};
|
||||
use ftp::FtpStream;
|
||||
|
||||
static PACKAGE: &str = "ftp";
|
||||
|
||||
pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptError> {
|
||||
let package = pckg::concat(parent, PACKAGE);
|
||||
|
||||
commands.set(get::create(&package))?;
|
||||
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(())
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) enum TransferType {
|
||||
// ascii
|
||||
Ascii,
|
||||
// image/binary
|
||||
Binary,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct Options {
|
||||
host: Option<String>,
|
||||
port: u32,
|
||||
user_name: Option<String>,
|
||||
password: Option<String>,
|
||||
path: Option<String>,
|
||||
transfer_type: Option<TransferType>,
|
||||
remote_file: Option<String>,
|
||||
local_file: Option<String>,
|
||||
content: Option<String>,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
fn new() -> Options {
|
||||
Options {
|
||||
host: None,
|
||||
port: 21,
|
||||
user_name: None,
|
||||
password: None,
|
||||
path: None,
|
||||
transfer_type: None,
|
||||
remote_file: None,
|
||||
local_file: None,
|
||||
content: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum LookingFor {
|
||||
Flag,
|
||||
Host,
|
||||
Port,
|
||||
UserName,
|
||||
Password,
|
||||
Path,
|
||||
TransferType,
|
||||
RemoteFile,
|
||||
LocalFile,
|
||||
Content,
|
||||
}
|
||||
|
||||
pub(crate) fn run_with_connection(
|
||||
arguments: &Vec<String>,
|
||||
func: &mut FnMut(&Options, &mut FtpStream) -> CommandResult,
|
||||
) -> CommandResult {
|
||||
validate_and_run_with_connection(
|
||||
arguments,
|
||||
&|_options: &Options| -> Result<(), String> { Ok(()) },
|
||||
func,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn validate_and_run_with_connection(
|
||||
arguments: &Vec<String>,
|
||||
validate_input: &Fn(&Options) -> Result<(), String>,
|
||||
func: &mut FnMut(&Options, &mut FtpStream) -> CommandResult,
|
||||
) -> CommandResult {
|
||||
match parse_common_options(&arguments) {
|
||||
Ok(options) => match validate_input(&options) {
|
||||
Ok(_) => run_in_ftp_connection_context(
|
||||
&options,
|
||||
&mut |ftp_stream: &mut FtpStream| -> CommandResult { func(&options, ftp_stream) },
|
||||
),
|
||||
Err(error) => CommandResult::Error(error),
|
||||
},
|
||||
Err(error) => CommandResult::Error(error),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_common_options(arguments: &Vec<String>) -> Result<Options, String> {
|
||||
let mut options = Options::new();
|
||||
|
||||
let mut looking_for = LookingFor::Flag;
|
||||
for argument in arguments {
|
||||
match looking_for {
|
||||
LookingFor::Flag => match argument.as_str() {
|
||||
"--host" => looking_for = LookingFor::Host,
|
||||
"--port" => looking_for = LookingFor::Port,
|
||||
"--username" => looking_for = LookingFor::UserName,
|
||||
"--password" => looking_for = LookingFor::Password,
|
||||
"--path" => looking_for = LookingFor::Path,
|
||||
"--type" => looking_for = LookingFor::TransferType,
|
||||
"--remote-file" => looking_for = LookingFor::RemoteFile,
|
||||
"--local-file" => looking_for = LookingFor::LocalFile,
|
||||
"--content" => looking_for = LookingFor::Content,
|
||||
_ => (),
|
||||
},
|
||||
LookingFor::Host => {
|
||||
if !argument.is_empty() {
|
||||
options.host = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::Port => {
|
||||
if !argument.is_empty() {
|
||||
options.port = match argument.parse::<u32>() {
|
||||
Ok(value) => value,
|
||||
Err(error) => return Err(error.to_string()),
|
||||
};
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::UserName => {
|
||||
if !argument.is_empty() {
|
||||
options.user_name = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::Password => {
|
||||
if !argument.is_empty() {
|
||||
options.password = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::Path => {
|
||||
if !argument.is_empty() {
|
||||
options.path = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::TransferType => {
|
||||
if !argument.is_empty() {
|
||||
match argument.as_str() {
|
||||
"A" => options.transfer_type = Some(TransferType::Ascii),
|
||||
"I" => options.transfer_type = Some(TransferType::Binary),
|
||||
_ => {
|
||||
return Err(
|
||||
"Invalid transfer type provided, only A or I are supported."
|
||||
.to_string(),
|
||||
)
|
||||
}
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
}
|
||||
LookingFor::RemoteFile => {
|
||||
if !argument.is_empty() {
|
||||
options.remote_file = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::LocalFile => {
|
||||
if !argument.is_empty() {
|
||||
options.local_file = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
LookingFor::Content => {
|
||||
if !argument.is_empty() {
|
||||
options.content = Some(argument.to_string());
|
||||
}
|
||||
looking_for = LookingFor::Flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(options)
|
||||
}
|
||||
|
||||
fn run_in_ftp_connection_context(
|
||||
options: &Options,
|
||||
func: &mut FnMut(&mut FtpStream) -> CommandResult,
|
||||
) -> CommandResult {
|
||||
match options.host {
|
||||
Some(ref host) => {
|
||||
let mut connection_string = String::new();
|
||||
connection_string.push_str(host);
|
||||
connection_string.push(':');
|
||||
connection_string.push_str(&options.port.to_string());
|
||||
|
||||
match FtpStream::connect(&connection_string) {
|
||||
Ok(mut ftp_stream) => {
|
||||
let options_cloned = options.clone();
|
||||
|
||||
// login if needed
|
||||
if options.user_name.is_some() && options.password.is_some() {
|
||||
let user_name = options_cloned.user_name.unwrap();
|
||||
let password = options_cloned.password.unwrap();
|
||||
|
||||
if let Err(error) = ftp_stream.login(&user_name, &password) {
|
||||
return CommandResult::Error(error.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// move to another directory
|
||||
if let Some(path) = options_cloned.path {
|
||||
if let Err(error) = ftp_stream.cwd(path.as_str()) {
|
||||
return CommandResult::Error(error.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
// set transfer type
|
||||
if let Some(transfer_type) = options_cloned.transfer_type {
|
||||
let file_type = match transfer_type {
|
||||
TransferType::Ascii => FileType::Ascii(FormatControl::Default),
|
||||
TransferType::Binary => FileType::Image,
|
||||
};
|
||||
|
||||
if let Err(error) = ftp_stream.transfer_type(file_type) {
|
||||
return CommandResult::Error(error.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let result = func(&mut ftp_stream);
|
||||
|
||||
ftp_stream.quit().unwrap_or(());
|
||||
|
||||
result
|
||||
}
|
||||
Err(error) => CommandResult::Error(error.to_string()),
|
||||
}
|
||||
}
|
||||
None => CommandResult::Error("No host provided.".to_string()),
|
||||
}
|
||||
}
|
28
duckscript_sdk/src/sdk/std/net/ftp/nlst/help.md
Normal file
28
duckscript_sdk/src/sdk/std/net/ftp/nlst/help.md
Normal file
|
@ -0,0 +1,28 @@
|
|||
```sh
|
||||
handle = ftp_nlst --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>]
|
||||
```
|
||||
|
||||
Invokes the FTP NLST command from the given connection details and path.<br>
|
||||
Returns a handle to an array of all response entries.
|
||||
|
||||
#### 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
|
||||
|
||||
#### Return Value
|
||||
|
||||
A handle to an array holding all entries.
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
handle = ftp_nlst --host myhost --username someuser --password 12345
|
||||
|
||||
for entry in ${handle}
|
||||
echo ${entry}
|
||||
end
|
||||
```
|
75
duckscript_sdk/src/sdk/std/net/ftp/nlst/mod.rs
Executable file
75
duckscript_sdk/src/sdk/std/net/ftp/nlst/mod.rs
Executable file
|
@ -0,0 +1,75 @@
|
|||
use crate::sdk::std::net::ftp::{run_with_connection, Options};
|
||||
use crate::utils::pckg;
|
||||
use crate::utils::state::put_handle;
|
||||
use duckscript::types::command::{Command, CommandResult, Commands};
|
||||
use duckscript::types::instruction::Instruction;
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use ftp::FtpStream;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[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, "NLst")
|
||||
}
|
||||
|
||||
fn aliases(&self) -> Vec<String> {
|
||||
vec!["ftp_nlst".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn requires_context(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn run_with_context(
|
||||
&self,
|
||||
arguments: Vec<String>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
_variables: &mut HashMap<String, String>,
|
||||
_output_variable: Option<String>,
|
||||
_instructions: &Vec<Instruction>,
|
||||
_commands: &mut Commands,
|
||||
_line: usize,
|
||||
) -> CommandResult {
|
||||
run_with_connection(&arguments, &mut |_options: &Options,
|
||||
ftp_stream: &mut FtpStream|
|
||||
-> CommandResult {
|
||||
match ftp_stream.nlst(None) {
|
||||
Ok(output) => {
|
||||
let mut array = vec![];
|
||||
|
||||
for item in output {
|
||||
array.push(StateValue::String(item));
|
||||
}
|
||||
|
||||
let key = put_handle(state, StateValue::List(array));
|
||||
|
||||
CommandResult::Continue(Some(key))
|
||||
}
|
||||
Err(error) => CommandResult::Error(error.to_string()),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create(package: &str) -> Box<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
22
duckscript_sdk/src/sdk/std/net/ftp/nlst/mod_test.rs
Normal file
22
duckscript_sdk/src/sdk/std/net/ftp/nlst/mod_test.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
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_error(vec![create("")], "out = ftp_nlst", "out");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_valid() {
|
||||
test::run_script_and_validate(
|
||||
vec![create("")],
|
||||
"out = ftp_nlst --host test.rebex.net --username demo --password password",
|
||||
CommandValidation::Contains("out".to_string(), "handle:".to_string()),
|
||||
);
|
||||
}
|
26
duckscript_sdk/src/sdk/std/net/ftp/put/help.md
Normal file
26
duckscript_sdk/src/sdk/std/net/ftp/put/help.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
```sh
|
||||
result = ftp_put --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name> --local-file <file name>
|
||||
```
|
||||
|
||||
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
|
||||
```
|
81
duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs
Executable file
81
duckscript_sdk/src/sdk/std/net/ftp/put/mod.rs
Executable file
|
@ -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<String> {
|
||||
vec!["ftp_put".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn run(&self, arguments: Vec<String>) -> 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<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
12
duckscript_sdk/src/sdk/std/net/ftp/put/mod_test.rs
Normal file
12
duckscript_sdk/src/sdk/std/net/ftp/put/mod_test.rs
Normal file
|
@ -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");
|
||||
}
|
26
duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/help.md
Normal file
26
duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/help.md
Normal file
|
@ -0,0 +1,26 @@
|
|||
```sh
|
||||
result = ftp_put_in_memory --host <hostname> [--port 21] [--username <user name>] [--password <password>] [--path <path>] [--type <A/I>] --remote-file <file name> --content <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"
|
||||
```
|
64
duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod.rs
Executable file
64
duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod.rs
Executable file
|
@ -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<String> {
|
||||
vec!["ftp_put_in_memory".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn run(&self, arguments: Vec<String>) -> 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<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
12
duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod_test.rs
Normal file
12
duckscript_sdk/src/sdk/std/net/ftp/put_in_memory/mod_test.rs
Normal file
|
@ -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");
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
mod ftp;
|
||||
mod hostname;
|
||||
mod http_client;
|
||||
mod wget;
|
||||
|
@ -15,5 +16,7 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr
|
|||
commands.set(http_client::create(&package))?;
|
||||
commands.set(wget::create(&package)?)?;
|
||||
|
||||
ftp::load(commands, &package)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
19
duckscript_sdk/src/sdk/std/noop/help.md
Normal file
19
duckscript_sdk/src/sdk/std/noop/help.md
Normal file
|
@ -0,0 +1,19 @@
|
|||
```sh
|
||||
noop
|
||||
```
|
||||
|
||||
Empty function that does nothing and returns none.
|
||||
|
||||
#### Parameters
|
||||
|
||||
All parameters are ignored
|
||||
|
||||
#### Return Value
|
||||
|
||||
None
|
||||
|
||||
#### Examples
|
||||
|
||||
```sh
|
||||
noop
|
||||
```
|
39
duckscript_sdk/src/sdk/std/noop/mod.rs
Executable file
39
duckscript_sdk/src/sdk/std/noop/mod.rs
Executable file
|
@ -0,0 +1,39 @@
|
|||
use crate::utils::pckg;
|
||||
use duckscript::types::command::{Command, CommandResult};
|
||||
|
||||
#[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, "Noop")
|
||||
}
|
||||
|
||||
fn aliases(&self) -> Vec<String> {
|
||||
vec!["noop".to_string()]
|
||||
}
|
||||
|
||||
fn help(&self) -> String {
|
||||
include_str!("help.md").to_string()
|
||||
}
|
||||
|
||||
fn clone_and_box(&self) -> Box<dyn Command> {
|
||||
Box::new((*self).clone())
|
||||
}
|
||||
|
||||
fn run(&self, _arguments: Vec<String>) -> CommandResult {
|
||||
CommandResult::Continue(None)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn create(package: &str) -> Box<dyn Command> {
|
||||
Box::new(CommandImpl {
|
||||
package: package.to_string(),
|
||||
})
|
||||
}
|
22
duckscript_sdk/src/sdk/std/noop/mod_test.rs
Normal file
22
duckscript_sdk/src/sdk/std/noop/mod_test.rs
Normal file
|
@ -0,0 +1,22 @@
|
|||
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 = noop", CommandValidation::None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn run_multiple_args() {
|
||||
test::run_script_and_validate(
|
||||
vec![create("")],
|
||||
"out = noop 1 2 \"3 4\"",
|
||||
CommandValidation::None,
|
||||
);
|
||||
}
|
|
@ -40,14 +40,14 @@ impl Command for CommandImpl {
|
|||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
_output_variable: Option<String>,
|
||||
_instructions: &Vec<Instruction>,
|
||||
instructions: &Vec<Instruction>,
|
||||
commands: &mut Commands,
|
||||
_line: usize,
|
||||
) -> CommandResult {
|
||||
if arguments.is_empty() {
|
||||
CommandResult::Error("Missing condition".to_string())
|
||||
} else {
|
||||
match condition::eval_condition(arguments, state, variables, commands) {
|
||||
match condition::eval_condition(arguments, instructions, state, variables, commands) {
|
||||
Ok(passed) => {
|
||||
let output = !passed;
|
||||
CommandResult::Continue(Some(output.to_string()))
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::types::scope::clear;
|
||||
use crate::types::scope::set_line_context_name;
|
||||
use crate::utils::eval;
|
||||
use crate::utils::state::{get_handles_sub_state, put_handle};
|
||||
use duckscript::types::command::{Command, CommandResult, Commands, GoToValue};
|
||||
use duckscript::parser;
|
||||
use duckscript::types::command::{Command, CommandResult, Commands};
|
||||
use duckscript::types::error::ScriptError;
|
||||
use duckscript::types::instruction::{Instruction, InstructionType};
|
||||
use duckscript::types::instruction::Instruction;
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use duckscript::{parser, runner};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
|
@ -119,77 +120,8 @@ impl Command for AliasCommand {
|
|||
handle_option = Some(handle);
|
||||
}
|
||||
|
||||
let mut line = 0;
|
||||
let mut flow_output = None;
|
||||
let mut flow_result = None;
|
||||
loop {
|
||||
let instruction = if self.instructions.len() > line {
|
||||
self.instructions[line].clone()
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
|
||||
match instruction.instruction_type {
|
||||
InstructionType::Script(ref script_instruction) => {
|
||||
let (command_result, _) = runner::run_instruction(
|
||||
commands,
|
||||
variables,
|
||||
state,
|
||||
&self.instructions,
|
||||
instruction.clone(),
|
||||
line,
|
||||
);
|
||||
|
||||
match command_result {
|
||||
CommandResult::Exit(output) => {
|
||||
flow_result = Some(CommandResult::Exit(output));
|
||||
break;
|
||||
}
|
||||
CommandResult::Error(error) => {
|
||||
flow_result = Some(CommandResult::Error(error));
|
||||
break;
|
||||
}
|
||||
CommandResult::Crash(error) => {
|
||||
flow_result = Some(CommandResult::Crash(error));
|
||||
break;
|
||||
}
|
||||
CommandResult::GoTo(output, goto_value) => {
|
||||
flow_output = output.clone();
|
||||
|
||||
match goto_value {
|
||||
GoToValue::Label(_) => {
|
||||
flow_result = Some(CommandResult::Error(
|
||||
"goto label result not supported in alias command flow.".to_string(),
|
||||
));
|
||||
break;
|
||||
}
|
||||
GoToValue::Line(line_number) => line = line_number,
|
||||
}
|
||||
}
|
||||
CommandResult::Continue(output) => {
|
||||
flow_output = output.clone();
|
||||
|
||||
match script_instruction.output {
|
||||
Some(ref output_variable) => {
|
||||
match output {
|
||||
Some(value) => {
|
||||
variables.insert(output_variable.to_string(), value)
|
||||
}
|
||||
None => variables.remove(output_variable),
|
||||
};
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
|
||||
line = line + 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
line = line + 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
let (flow_result, flow_output) =
|
||||
eval::eval_instructions(&self.instructions, commands, state, variables, 0);
|
||||
|
||||
match handle_option {
|
||||
Some(handle) => {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use crate::utils::eval;
|
||||
use duckscript::types::command::{CommandResult, Commands};
|
||||
use duckscript::types::instruction::Instruction;
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -28,6 +29,7 @@ pub(crate) fn is_true(value: Option<String>) -> bool {
|
|||
|
||||
pub(crate) fn eval_condition(
|
||||
arguments: Vec<String>,
|
||||
instructions: &Vec<Instruction>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
commands: &mut Commands,
|
||||
|
@ -38,7 +40,8 @@ pub(crate) fn eval_condition(
|
|||
let eval_statement = commands.exists(&arguments[0]);
|
||||
|
||||
if eval_statement {
|
||||
match eval::eval_with_error(&arguments, state, variables, commands) {
|
||||
match eval::eval_with_instructions(&arguments, instructions, state, variables, commands)
|
||||
{
|
||||
CommandResult::Continue(value) => {
|
||||
let passed = is_true(value);
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ fn is_true_valid() {
|
|||
fn eval_condition_empty() {
|
||||
let result = eval_condition(
|
||||
vec![],
|
||||
&vec![],
|
||||
&mut HashMap::new(),
|
||||
&mut HashMap::new(),
|
||||
&mut Commands::new(),
|
||||
|
@ -77,6 +78,7 @@ fn eval_condition_empty() {
|
|||
fn eval_condition_value_true() {
|
||||
let result = eval_condition(
|
||||
vec!["true".to_string()],
|
||||
&vec![],
|
||||
&mut HashMap::new(),
|
||||
&mut HashMap::new(),
|
||||
&mut Commands::new(),
|
||||
|
@ -93,6 +95,7 @@ fn eval_condition_value_true() {
|
|||
fn eval_condition_value_false() {
|
||||
let result = eval_condition(
|
||||
vec!["false".to_string()],
|
||||
&vec![],
|
||||
&mut HashMap::new(),
|
||||
&mut HashMap::new(),
|
||||
&mut Commands::new(),
|
||||
|
@ -115,6 +118,7 @@ fn eval_condition_command_true() {
|
|||
|
||||
let result = eval_condition(
|
||||
vec!["test_set".to_string(), "true".to_string()],
|
||||
&vec![],
|
||||
&mut HashMap::new(),
|
||||
&mut HashMap::new(),
|
||||
&mut commands,
|
||||
|
@ -137,6 +141,7 @@ fn eval_condition_command_false() {
|
|||
|
||||
let result = eval_condition(
|
||||
vec!["test_set".to_string(), "false".to_string()],
|
||||
&vec![],
|
||||
&mut HashMap::new(),
|
||||
&mut HashMap::new(),
|
||||
&mut commands,
|
||||
|
@ -159,6 +164,7 @@ fn eval_condition_command_error() {
|
|||
|
||||
let result = eval_condition(
|
||||
vec!["test_error".to_string()],
|
||||
&vec![],
|
||||
&mut HashMap::new(),
|
||||
&mut HashMap::new(),
|
||||
&mut commands,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
use duckscript::parser;
|
||||
use duckscript::runner;
|
||||
use duckscript::types::command::{CommandResult, Commands};
|
||||
use duckscript::types::command::{CommandResult, Commands, GoToValue};
|
||||
use duckscript::types::instruction::{Instruction, InstructionType};
|
||||
use duckscript::types::runtime::StateValue;
|
||||
use std::collections::HashMap;
|
||||
|
||||
|
@ -8,15 +9,7 @@ use std::collections::HashMap;
|
|||
#[path = "./eval_test.rs"]
|
||||
mod eval_test;
|
||||
|
||||
pub(crate) fn eval(
|
||||
arguments: &Vec<String>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
commands: &mut Commands,
|
||||
) -> Result<CommandResult, String> {
|
||||
if arguments.is_empty() {
|
||||
Ok(CommandResult::Continue(None))
|
||||
} else {
|
||||
fn parse(arguments: &Vec<String>) -> Result<Instruction, String> {
|
||||
let mut line_buffer = String::new();
|
||||
for argument in arguments {
|
||||
if argument.contains(" ") {
|
||||
|
@ -35,15 +28,24 @@ pub(crate) fn eval(
|
|||
.replace("\\", "\\\\");
|
||||
|
||||
match parser::parse_text(&line_str) {
|
||||
Ok(instructions) => {
|
||||
let (command_result, _) = runner::run_instruction(
|
||||
commands,
|
||||
variables,
|
||||
state,
|
||||
&vec![],
|
||||
instructions[0].clone(),
|
||||
0,
|
||||
);
|
||||
Ok(instructions) => Ok(instructions[0].clone()),
|
||||
Err(error) => Err(error.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval(
|
||||
arguments: &Vec<String>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
commands: &mut Commands,
|
||||
) -> Result<CommandResult, String> {
|
||||
if arguments.is_empty() {
|
||||
Ok(CommandResult::Continue(None))
|
||||
} else {
|
||||
match parse(arguments) {
|
||||
Ok(instruction) => {
|
||||
let (command_result, _) =
|
||||
runner::run_instruction(commands, variables, state, &vec![], instruction, 0);
|
||||
|
||||
Ok(command_result)
|
||||
}
|
||||
|
@ -66,3 +68,121 @@ pub(crate) fn eval_with_error(
|
|||
Err(error) => CommandResult::Error(error.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_with_instructions(
|
||||
arguments: &Vec<String>,
|
||||
instructions: &Vec<Instruction>,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
commands: &mut Commands,
|
||||
) -> CommandResult {
|
||||
if arguments.is_empty() {
|
||||
CommandResult::Continue(None)
|
||||
} else {
|
||||
match parse(arguments) {
|
||||
Ok(instruction) => {
|
||||
let mut all_instructions = instructions.clone();
|
||||
all_instructions.push(instruction);
|
||||
let (flow_result, flow_output) = eval_instructions(
|
||||
&all_instructions,
|
||||
commands,
|
||||
state,
|
||||
variables,
|
||||
all_instructions.len() - 1,
|
||||
);
|
||||
|
||||
match flow_result {
|
||||
Some(result) => match result.clone() {
|
||||
CommandResult::Crash(error) => CommandResult::Error(error),
|
||||
_ => result,
|
||||
},
|
||||
None => CommandResult::Continue(flow_output),
|
||||
}
|
||||
}
|
||||
Err(error) => CommandResult::Error(error),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn eval_instructions(
|
||||
instructions: &Vec<Instruction>,
|
||||
commands: &mut Commands,
|
||||
state: &mut HashMap<String, StateValue>,
|
||||
variables: &mut HashMap<String, String>,
|
||||
start_line: usize,
|
||||
) -> (Option<CommandResult>, Option<String>) {
|
||||
let mut line = start_line;
|
||||
let mut flow_output = None;
|
||||
let mut flow_result = None;
|
||||
loop {
|
||||
let instruction = if instructions.len() > line {
|
||||
instructions[line].clone()
|
||||
} else {
|
||||
break;
|
||||
};
|
||||
|
||||
match instruction.instruction_type {
|
||||
InstructionType::Script(ref script_instruction) => {
|
||||
let (command_result, _) = runner::run_instruction(
|
||||
commands,
|
||||
variables,
|
||||
state,
|
||||
&instructions,
|
||||
instruction.clone(),
|
||||
line,
|
||||
);
|
||||
|
||||
match command_result {
|
||||
CommandResult::Exit(output) => {
|
||||
flow_result = Some(CommandResult::Exit(output));
|
||||
break;
|
||||
}
|
||||
CommandResult::Error(error) => {
|
||||
flow_result = Some(CommandResult::Error(error));
|
||||
break;
|
||||
}
|
||||
CommandResult::Crash(error) => {
|
||||
flow_result = Some(CommandResult::Crash(error));
|
||||
break;
|
||||
}
|
||||
CommandResult::GoTo(output, goto_value) => {
|
||||
flow_output = output.clone();
|
||||
|
||||
match goto_value {
|
||||
GoToValue::Label(_) => {
|
||||
flow_result = Some(CommandResult::Error(
|
||||
"goto label result not supported in alias command flow."
|
||||
.to_string(),
|
||||
));
|
||||
break;
|
||||
}
|
||||
GoToValue::Line(line_number) => line = line_number,
|
||||
}
|
||||
}
|
||||
CommandResult::Continue(output) => {
|
||||
flow_output = output.clone();
|
||||
|
||||
match script_instruction.output {
|
||||
Some(ref output_variable) => {
|
||||
match output {
|
||||
Some(value) => {
|
||||
variables.insert(output_variable.to_string(), value)
|
||||
}
|
||||
None => variables.remove(output_variable),
|
||||
};
|
||||
}
|
||||
None => (),
|
||||
};
|
||||
|
||||
line = line + 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
_ => {
|
||||
line = line + 1;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
(flow_result, flow_output)
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ fn clear_not_empty
|
|||
result = array_is_empty ${handle}
|
||||
assert_false ${result}
|
||||
|
||||
result array_clear ${handle}
|
||||
result = array_clear ${handle}
|
||||
assert ${result}
|
||||
|
||||
result = array_is_empty ${handle}
|
||||
|
@ -19,7 +19,7 @@ end
|
|||
fn clear_empty
|
||||
handle = array
|
||||
|
||||
result array_clear ${handle}
|
||||
result = array_clear ${handle}
|
||||
assert ${result}
|
||||
|
||||
result = array_is_empty ${handle}
|
||||
|
|
|
@ -117,3 +117,46 @@ fn test_nested_if2
|
|||
|
||||
assert ${valid}
|
||||
end
|
||||
|
||||
fn test_if_call_to_functions
|
||||
value = _test_return_true
|
||||
valid = set false
|
||||
if ${value}
|
||||
valid = set true
|
||||
end
|
||||
assert ${valid}
|
||||
|
||||
value = _test_return_false
|
||||
valid = set true
|
||||
if ${value}
|
||||
valid = set false
|
||||
end
|
||||
assert ${valid}
|
||||
|
||||
valid = set false
|
||||
if _test_return_true
|
||||
valid = set true
|
||||
end
|
||||
assert ${valid}
|
||||
|
||||
valid = set true
|
||||
if _test_return_false
|
||||
valid = set false
|
||||
end
|
||||
assert ${valid}
|
||||
|
||||
valid = set false
|
||||
if not _test_return_false
|
||||
valid = set true
|
||||
end
|
||||
assert ${valid}
|
||||
end
|
||||
|
||||
fn _test_return_true
|
||||
return true
|
||||
end
|
||||
|
||||
fn _test_return_false
|
||||
return false
|
||||
end
|
||||
|
||||
|
|
14
test/std/net/ftp/ftp_get_in_memory_test.ds
Normal file
14
test/std/net/ftp/ftp_get_in_memory_test.ds
Normal file
|
@ -0,0 +1,14 @@
|
|||
|
||||
fn test_valid
|
||||
handle = ftp_get_in_memory --host test.rebex.net --username demo --password password --remote-file readme.txt
|
||||
|
||||
text = bytes_to_string ${handle}
|
||||
release ${handle}
|
||||
|
||||
empty = is_empty ${text}
|
||||
assert_false ${empty}
|
||||
|
||||
found = contains ${text} Welcome
|
||||
assert ${found}
|
||||
end
|
||||
|
16
test/std/net/ftp/ftp_get_test.ds
Normal file
16
test/std/net/ftp/ftp_get_test.ds
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
fn test_valid
|
||||
filename = set ./target/_duckscript_test/net/ftp/get/readme.txt
|
||||
result = ftp_get --host test.rebex.net --username demo --password password --remote-file readme.txt --local-file ${filename}
|
||||
|
||||
assert ${result}
|
||||
|
||||
text = readfile ${filename}
|
||||
|
||||
empty = is_empty ${text}
|
||||
assert_false ${empty}
|
||||
|
||||
found = contains ${text} Welcome
|
||||
assert ${found}
|
||||
end
|
||||
|
27
test/std/net/ftp/ftp_list_test.ds
Normal file
27
test/std/net/ftp/ftp_list_test.ds
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
fn test_valid
|
||||
arr = ftp_list --host test.rebex.net --username demo --password password
|
||||
|
||||
empty = array_is_empty ${arr}
|
||||
assert_false ${empty}
|
||||
|
||||
merged = array_join ${arr} ,
|
||||
found = contains ${merged} pub
|
||||
assert ${found}
|
||||
|
||||
release ${arr}
|
||||
end
|
||||
|
||||
fn test_with_path
|
||||
arr = ftp_list --host test.rebex.net --username demo --password password --path pub
|
||||
|
||||
empty = array_is_empty ${arr}
|
||||
assert_false ${empty}
|
||||
|
||||
merged = array_join ${arr} ,
|
||||
found = contains ${merged} example
|
||||
assert ${found}
|
||||
|
||||
release ${arr}
|
||||
end
|
||||
|
27
test/std/net/ftp/ftp_nlst_test.ds
Normal file
27
test/std/net/ftp/ftp_nlst_test.ds
Normal file
|
@ -0,0 +1,27 @@
|
|||
|
||||
fn test_valid
|
||||
arr = ftp_nlst --host test.rebex.net --username demo --password password
|
||||
|
||||
empty = array_is_empty ${arr}
|
||||
assert_false ${empty}
|
||||
|
||||
merged = array_join ${arr} ,
|
||||
found = contains ${merged} pub
|
||||
assert ${found}
|
||||
|
||||
release ${arr}
|
||||
end
|
||||
|
||||
fn test_with_path
|
||||
arr = ftp_nlst --host test.rebex.net --username demo --password password --path pub
|
||||
|
||||
empty = array_is_empty ${arr}
|
||||
assert_false ${empty}
|
||||
|
||||
merged = array_join ${arr} ,
|
||||
found = contains ${merged} example
|
||||
assert ${found}
|
||||
|
||||
release ${arr}
|
||||
end
|
||||
|
14
test/std/net/ftp/ftp_put_in_memory_test.ds
Normal file
14
test/std/net/ftp/ftp_put_in_memory_test.ds
Normal file
|
@ -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
|
||||
|
17
test/std/net/ftp/ftp_put_test.ds
Normal file
17
test/std/net/ftp/ftp_put_test.ds
Normal file
|
@ -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
|
||||
|
17
test/std/noop_test.ds
Normal file
17
test/std/noop_test.ds
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
fn test_no_args
|
||||
value = noop
|
||||
|
||||
defined = is_defined value
|
||||
|
||||
assert_false ${value}
|
||||
end
|
||||
|
||||
fn test_multiple_args
|
||||
value = noop 1 2 3 4
|
||||
|
||||
defined = is_defined value
|
||||
|
||||
assert_false ${value}
|
||||
end
|
||||
|
Loading…
Reference in a new issue