| Crates.io | openrunner-rs |
| lib.rs | openrunner-rs |
| version | 1.0.1 |
| created_at | 2025-06-08 23:35:16.467275+00 |
| updated_at | 2025-06-09 02:18:39.599025+00 |
| description | A Rust library for running OpenScript |
| homepage | https://github.com/openrunner-dev/openrunner-rs |
| repository | https://github.com/openrunner-dev/openrunner-rs |
| max_upload_size | |
| id | 1705325 |
| size | 145,272 |
OpenRunner-RS is a powerful, async-first Rust library for executing OpenScript code and shell scripts with fine-grained control over execution environment, I/O redirection, process lifecycle, and error handling.
Add to your Cargo.toml:
[dependencies]
openrunner-rs = "1.0"
tokio = { version = "1", features = ["full"] }
use openrunner_rs::{run, ScriptOptions};
#[tokio::main]
async fn main() -> openrunner_rs::Result<()> {
// Simple script execution
let options = ScriptOptions::new().openscript_path("/bin/sh");
let result = run("echo 'Hello, OpenRunner!'", options).await?;
println!("Exit code: {}", result.exit_code);
println!("Output: {}", result.stdout);
println!("Duration: {:?}", result.duration);
Ok(())
}
use openrunner_rs::{run, ScriptOptions};
use std::time::Duration;
#[tokio::main]
async fn main() -> openrunner_rs::Result<()> {
let options = ScriptOptions::new()
.openscript_path("/bin/bash")
.working_directory("/tmp")
.env("LOG_LEVEL", "debug")
.env("API_KEY", "secret")
.timeout(Duration::from_secs(30))
.args(vec!["arg1".to_string(), "arg2".to_string()]);
let result = run(r#"
echo "Working in: $(pwd)"
echo "Log level: $LOG_LEVEL"
echo "Arguments: $1 $2"
sleep 2
echo "Task completed!"
"#, options).await?;
if result.timed_out {
println!("Script timed out!");
} else {
println!("Script completed successfully: {}", result.stdout);
}
Ok(())
}
use openrunner_rs::{spawn, ScriptOptions};
#[tokio::main]
async fn main() -> openrunner_rs::Result<()> {
let options = ScriptOptions::new().openscript_path("/bin/sh");
// Spawn a long-running background process
let spawn_result = spawn(r#"
for i in {1..10}; do
echo "Processing item $i"
sleep 1
done
"#, options).await?;
println!("Spawned process with PID: {:?}", spawn_result.child.id());
// Do other work while process runs...
tokio::time::sleep(tokio::time::Duration::from_secs(2)).await;
// Wait for completion
let output = spawn_result.child.wait_with_output().await?;
println!("Process completed: {}", String::from_utf8_lossy(&output.stdout));
Ok(())
}
| Function | Description |
|---|---|
run(script, options) |
Execute script and wait for completion |
run_file(path, options) |
Execute script from file |
spawn(script, options) |
Spawn script process without waiting |
spawn_file(path, options) |
Spawn script from file |
| Macro | Description |
|---|---|
run_script!(script, options?) |
Simplified script execution |
spawn_script!(script, options?) |
Simplified script spawning |
run_file_script!(path, options?) |
Simplified file execution |
ScriptOptions::new()
.openscript_path("/path/to/interpreter") // Script interpreter
.working_directory("/working/dir") // Working directory
.env("KEY", "value") // Environment variables
.args(vec!["arg1", "arg2"]) // Command arguments
.timeout(Duration::from_secs(30)) // Execution timeout
.stdin(IoOptions::Pipe) // Stdin handling
.stdout(IoOptions::Pipe) // Stdout handling
.stderr(IoOptions::Pipe) // Stderr handling
.clear_env(true) // Clear environment
.exit_on_error(false) // Continue on errors
.print_commands(true) // Debug output
use openrunner_rs::{run_file, ScriptOptions};
use std::path::PathBuf;
#[tokio::main]
async fn main() -> openrunner_rs::Result<()> {
let script_path = PathBuf::from("./scripts/deploy.sh");
let options = ScriptOptions::new()
.openscript_path("/bin/bash")
.env("ENVIRONMENT", "production");
let result = run_file(&script_path, options).await?;
println!("Deployment result: {}", result.stdout);
Ok(())
}
use openrunner_rs::{run, ScriptOptions, Error};
#[tokio::main]
async fn main() {
let options = ScriptOptions::new().openscript_path("/bin/sh");
match run("exit 1", options).await {
Ok(result) => {
if result.exit_code != 0 {
println!("Script failed with code: {}", result.exit_code);
println!("Error output: {}", result.stderr);
}
}
Err(Error::Timeout(duration)) => {
println!("Script timed out after {:?}", duration);
}
Err(Error::OpenScriptNotFound) => {
println!("Script interpreter not found in PATH");
}
Err(e) => {
println!("Execution error: {}", e);
}
}
}
use openrunner_rs::{run_script, spawn_script, ScriptOptions};
#[tokio::main]
async fn main() -> openrunner_rs::Result<()> {
let options = ScriptOptions::new().openscript_path("/bin/sh");
// Quick execution with macro
let result = run_script!("echo 'Hello from macro!'", options).await?;
println!("Macro result: {}", result.stdout);
// Spawn with macro
let spawn_result = spawn_script!("sleep 5 && echo 'Background task'", options).await?;
let output = spawn_result.child.wait_with_output().await?;
println!("Background result: {}", String::from_utf8_lossy(&output.stdout));
Ok(())
}
Run the test suite:
# Run all tests
cargo test
# Run with output
cargo test -- --nocapture
# Run integration tests only
cargo test --test integration_test
# Run with coverage
cargo install cargo-tarpaulin
cargo tarpaulin --out Html
Build and test in Docker:
# Build the container
docker build -t openrunner-rs .
# Run tests in container
docker run --rm openrunner-rs cargo test
# Run examples
docker run --rm openrunner-rs cargo run --example basic
Run performance benchmarks:
# Run all benchmarks
cargo bench
# Run specific benchmark
cargo bench --bench script_execution
# Generate benchmark report
cargo bench -- --output-format html
OpenRunner-RS works across platforms:
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
# Clone the repository
git clone https://github.com/openrunner-dev/openrunner-rs.git
cd openrunner-rs
# Install development dependencies
cargo install cargo-watch cargo-tarpaulin
# Run tests with file watching
cargo watch -x test
# Check code quality
cargo clippy --all-targets --all-features
cargo fmt --check
See CHANGELOG.md for version history and breaking changes.
This project is licensed under either of
at your option.