Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

Commit

Permalink
add child() operation
Browse files Browse the repository at this point in the history
It executes an executable as a child process, ignoring the cycle.await
  • Loading branch information
Alonely0 committed Nov 14, 2021
1 parent 7a9f03b commit ce7b1f5
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 16 deletions.
1 change: 1 addition & 0 deletions voila/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ path-absolutize = "3.0.11"
serde = "1.0.130"
serde_derive = "1.0.130"
bincode = "1.3.3"
tinytest = "0.1.0"

[dev-dependencies]
criterion = "0.3.5"
Expand Down
47 changes: 35 additions & 12 deletions voila/src/ast/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,16 @@ pub enum Function {
/// # Safety
/// `create` will modify the file system!
Create { safe: bool },
/// Execute an executable as a child process, ignoring the cycle.await
///
/// # Call format
/// `child` receives either a binary or a path pointing to a executable. All other arguments
/// are passed as arguments
///
/// # Safety
/// As safe as the executable is. Like in the shell function, the safety checker will treat
/// arguments as access, modify and created as has 0 information about what the executable will do
Child { safe: bool },
}

impl Function {
Expand All @@ -132,7 +142,8 @@ impl Function {
Self::Delete { safe: _ }
| Self::Shell { safe: _ }
| Self::Mkdir { safe: _ }
| Self::Create { safe: _ } => 1,
| Self::Create { safe: _ }
| Self::Child { safe: _ } => 1,
Self::Print { safe: _ } => 0,
}
}
Expand All @@ -147,20 +158,22 @@ impl Function {
"mkdir" => Self::Mkdir { safe },
"print" => Self::Print { safe },
"create" => Self::Create { safe },
"child" => Self::Child { safe },
_ => return None,
})
}
fn is_safe(&self) -> bool {
match *self {
Function::Mkdir { safe } => safe,
Function::Print { safe } => safe,
Function::Shell { safe } => safe,
Function::Delete { safe } => safe,
Function::Move { safe } => safe,
Function::Copy { safe } => safe,
Function::GzipCompress { safe } => safe,
Function::GzipDecompress { safe } => safe,
Function::Create { safe } => safe,
Function::Mkdir { safe }
| Function::Print { safe }
| Function::Shell { safe }
| Function::Delete { safe }
| Function::Copy { safe }
| Function::Move { safe }
| Function::GzipCompress { safe }
| Function::GzipDecompress { safe }
| Function::Create { safe }
| Function::Child { safe } => safe,
}
}
}
Expand All @@ -177,6 +190,7 @@ impl fmt::Display for Function {
Self::Mkdir { safe: _ } => "mkdir",
Self::Print { safe: _ } => "print",
Self::Create { safe: _ } => "create",
Self::Child { safe: _ } => "child",
})
}
}
Expand Down Expand Up @@ -270,7 +284,7 @@ pub fn run_call(call: &Call, cache: Arc<Mutex<Cache>>) -> Result<(), ErrorKind>
// note: already considered streaming the arguments instead
// of collecting all of them, but the number of arguments is very low (1 or 2),
// so there is no real performance hit if we evaluate all of them now.
let args: Vec<String> = call
let mut args: Vec<String> = call
.arguments
.iter()
// note: grabbing the cache lock on each argument separately to prevent locking
Expand Down Expand Up @@ -299,6 +313,7 @@ pub fn run_call(call: &Call, cache: Arc<Mutex<Cache>>) -> Result<(), ErrorKind>
Function::GzipCompress { safe: _ } => gzc(&args[0], &args[1]),
Function::GzipDecompress { safe: _ } => gzd(&args[0], &args[1]),
Function::Shell { safe: _ } => shell(args),
Function::Child { safe: _ } => child(&args.remove(0), args),
}
.map_err(Into::into)
}
Expand Down Expand Up @@ -410,8 +425,9 @@ fn gzd(source: &str, dest: &str) -> Result<(), io::Error> {
archive.unpack(dest)
}

use std::process::Command;

fn shell(commands: Vec<String>) -> Result<(), io::Error> {
use std::process::Command;
commands.into_iter().try_for_each(|cmd| {
let complete_command: Result<_, std::io::Error> = {
#[cfg(windows)]
Expand Down Expand Up @@ -444,3 +460,10 @@ fn shell(commands: Vec<String>) -> Result<(), io::Error> {
Ok(())
})
}

fn child(executable: &str, arguments: Vec<String>) -> Result<(), io::Error> {
Command::new(executable)
.args(arguments)
.spawn()
.map(|_| ())
}
12 changes: 12 additions & 0 deletions voila/src/lexer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,15 @@ impl fmt::Display for Token {
}
}
}

use tinytest::unit_test;

unit_test!(
token_slices,
|| {
Token::lexer(crate::TEST_SCRIPT)
.map(|tok| format!("{tok}"))
.collect::<Vec<String>>()
},
crate::TEST_SCRIPT_TOKENS
);
7 changes: 6 additions & 1 deletion voila/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
#![feature(format_args_capture)]
#![feature(once_cell)]
#![feature(decl_macro)]
#![feature(option_result_unwrap_unchecked)]
#![feature(never_type)]
#![allow(dead_code)]

#[cfg(test)]
const TEST_SCRIPT: &str = "";

#[cfg(test)]
const TEST_SCRIPT_TOKENS: Vec<String> = vec![];

use std::error::Error;

mod ast;
Expand Down
4 changes: 1 addition & 3 deletions voila/src/safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,7 @@ impl<'source> crate::ast::Script<'source> {
match func {
Mkdir { safe: true } | Create { safe: true } => created = Some(args),
Print { safe: true } => accessed = Some(args),
Shell { safe: true } => {
created = Some(args.clone());
accessed = Some(args.clone());
Shell { safe: true } | Child { safe: true } => {
modified = Some(args);
},
Delete { safe: true } => {
Expand Down

0 comments on commit ce7b1f5

Please sign in to comment.