a3s_box_sdk/sandbox/
script.rs1use std::time::Duration;
2
3use super::{CommandResult, CommandRunOptions, Commands, SandboxCommand};
4use crate::{ClientError, Result};
5
6#[derive(Debug, Clone)]
11pub struct ScriptBuilder {
12 commands: Commands,
13 source: Vec<u8>,
14 interpreter: Vec<String>,
15 options: CommandRunOptions,
16}
17
18impl ScriptBuilder {
19 pub(crate) fn new(commands: Commands, source: impl AsRef<[u8]>) -> Self {
20 Self {
21 commands,
22 source: source.as_ref().to_vec(),
23 interpreter: vec!["/bin/sh".to_string(), "-se".to_string()],
24 options: CommandRunOptions::default(),
25 }
26 }
27
28 pub fn interpreter(mut self, command: impl IntoIterator<Item = impl Into<String>>) -> Self {
30 self.interpreter = command.into_iter().map(Into::into).collect();
31 self
32 }
33
34 pub const fn timeout(mut self, timeout: Duration) -> Self {
35 self.options.timeout = Some(timeout);
36 self
37 }
38
39 pub fn env(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
40 self.options.envs.insert(key.into(), value.into());
41 self
42 }
43
44 pub fn cwd(mut self, cwd: impl Into<String>) -> Self {
45 self.options.cwd = Some(cwd.into());
46 self
47 }
48
49 pub fn user(mut self, user: impl Into<String>) -> Self {
50 self.options.user = Some(user.into());
51 self
52 }
53
54 pub async fn run(mut self) -> Result<CommandResult> {
55 if self.source.is_empty() {
56 return Err(ClientError::Validation(
57 "script source cannot be empty".to_string(),
58 ));
59 }
60 if self.interpreter.is_empty() {
61 return Err(ClientError::Validation(
62 "script interpreter cannot be empty".to_string(),
63 ));
64 }
65 self.options.stdin = Some(self.source);
66 self.commands
67 .run_with_options(SandboxCommand::Argv(self.interpreter), self.options)
68 .await
69 }
70}
71
72impl Commands {
73 pub fn script(&self, source: impl AsRef<[u8]>) -> ScriptBuilder {
75 ScriptBuilder::new(self.clone(), source)
76 }
77}