Skip to main content

BashBuilder

Struct BashBuilder 

Source
pub struct BashBuilder { /* private fields */ }

Implementations§

Source§

impl BashBuilder

Source

pub fn fs(self, fs: Arc<dyn FileSystem>) -> Self

Set a custom filesystem.

Source

pub fn env(self, key: impl Into<String>, value: impl Into<String>) -> Self

Set an environment variable.

Source

pub fn cwd(self, cwd: impl Into<PathBuf>) -> Self

Set the current working directory.

Source

pub fn limits(self, limits: ExecutionLimits) -> Self

Set execution limits.

Source

pub fn username(self, username: impl Into<String>) -> Self

Set the sandbox username.

This configures whoami and id builtins to return this username, and automatically sets the USER environment variable.

Source

pub fn hostname(self, hostname: impl Into<String>) -> Self

Set the sandbox hostname.

This configures hostname and uname -n builtins to return this hostname.

Source

pub fn builtin(self, name: impl Into<String>, builtin: Box<dyn Builtin>) -> Self

Register a custom builtin command.

Custom builtins extend bashkit with domain-specific commands that can be invoked from bash scripts. They have full access to the execution context including arguments, environment, shell variables, and the virtual filesystem.

Custom builtins can override default builtins if registered with the same name.

§Arguments
  • name - The command name (e.g., “psql”, “kubectl”)
  • builtin - A boxed implementation of the Builtin trait
§Example
use bashkit::{Bash, Builtin, BuiltinContext, ExecResult, async_trait};

struct Greet {
    default_name: String,
}

#[async_trait]
impl Builtin for Greet {
    async fn execute(&self, ctx: BuiltinContext<'_>) -> bashkit::Result<ExecResult> {
        let name = ctx.args.first()
            .map(|s| s.as_str())
            .unwrap_or(&self.default_name);
        Ok(ExecResult::ok(format!("Hello, {}!\n", name)))
    }
}

let bash = Bash::builder()
    .builtin("greet", Box::new(Greet { default_name: "World".into() }))
    .build();
Source

pub fn mount_text( self, path: impl Into<PathBuf>, content: impl Into<String>, ) -> Self

Mount a text file in the virtual filesystem.

This creates a regular file (mode 0o644) with the specified content at the given path. Parent directories are created automatically.

Mounted files are added via an OverlayFs layer on top of the base filesystem. This means:

  • The base filesystem remains unchanged
  • Mounted files take precedence over base filesystem files
  • Works with any filesystem implementation
§Example
use bashkit::Bash;

let mut bash = Bash::builder()
    .mount_text("/config/app.conf", "debug=true\nport=8080\n")
    .mount_text("/data/users.json", r#"["alice", "bob"]"#)
    .build();

let result = bash.exec("cat /config/app.conf").await?;
assert_eq!(result.stdout, "debug=true\nport=8080\n");
Source

pub fn mount_readonly_text( self, path: impl Into<PathBuf>, content: impl Into<String>, ) -> Self

Mount a readonly text file in the virtual filesystem.

This creates a readonly file (mode 0o444) with the specified content. Parent directories are created automatically.

Readonly files are useful for:

  • Configuration that shouldn’t be modified by scripts
  • Reference data that should remain immutable
  • Simulating system files like /etc/passwd

Mounted files are added via an OverlayFs layer on top of the base filesystem. This means:

  • The base filesystem remains unchanged
  • Mounted files take precedence over base filesystem files
  • Works with any filesystem implementation
§Example
use bashkit::Bash;

let mut bash = Bash::builder()
    .mount_readonly_text("/etc/version", "1.2.3")
    .mount_readonly_text("/etc/app.conf", "production=true\n")
    .build();

// Can read the file
let result = bash.exec("cat /etc/version").await?;
assert_eq!(result.stdout, "1.2.3");

// File has readonly permissions
let stat = bash.fs().stat(std::path::Path::new("/etc/version")).await?;
assert_eq!(stat.mode, 0o444);
Source

pub fn build(self) -> Bash

Build the Bash instance.

If mounted files are specified, they are added via an OverlayFs layer on top of the base filesystem. This means:

  • The base filesystem remains unchanged
  • Mounted files take precedence over base filesystem files
  • Works with any filesystem implementation
§Example
use bashkit::{Bash, InMemoryFs};
use std::sync::Arc;

// Works with default InMemoryFs
let mut bash = Bash::builder()
    .mount_text("/config/app.conf", "debug=true\n")
    .build();

// Also works with custom filesystems
let custom_fs = Arc::new(InMemoryFs::new());
let mut bash = Bash::builder()
    .fs(custom_fs)
    .mount_text("/config/app.conf", "debug=true\n")
    .mount_readonly_text("/etc/version", "1.0.0")
    .build();

let result = bash.exec("cat /config/app.conf").await?;
assert_eq!(result.stdout, "debug=true\n");

Trait Implementations§

Source§

impl Default for BashBuilder

Source§

fn default() -> BashBuilder

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.