openrunner-rs 1.0.1

A Rust library for running OpenScript
Documentation
use openrunner_rs::{run, spawn, ScriptOptions, Error};
use std::time::Duration;
use tokio::time::sleep;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("Running advanced OpenRunner examples...\n");

    // Example 1: Timeout handling
    println!("Example 1: Timeout handling");
    let options = ScriptOptions::new()
        .openscript_path("/bin/sh")
        .timeout(Duration::from_secs(2));
    
    let start = std::time::Instant::now();
    let result = run("sleep 5 && echo 'This should timeout'", options).await?;
    
    println!("   Timed out: {}", result.timed_out);
    println!("   Duration: {:?}", start.elapsed());
    println!("   Exit code: {}", result.exit_code);

    // Example 2: Parallel execution
    println!("\nExample 2: Parallel script execution");
    let scripts = vec![
        "sleep 1 && echo 'Task 1 completed'",
        "sleep 1 && echo 'Task 2 completed'", 
        "sleep 1 && echo 'Task 3 completed'",
    ];
    
    let start = std::time::Instant::now();
    let futures: Vec<_> = scripts.into_iter().enumerate().map(|(i, script)| {
        let options = ScriptOptions::new()
            .openscript_path("/bin/sh")
            .env("TASK_ID", format!("{}", i + 1));
        run(script, options)
    }).collect();
    
    let results = futures::future::try_join_all(futures).await?;
    println!("   Parallel execution completed in: {:?}", start.elapsed());
    for (i, result) in results.iter().enumerate() {
        println!("   Task {}: {}", i + 1, result.stdout.trim());
    }

    // Example 3: Background process spawning
    println!("\nExample 3: Background process management");
    let options = ScriptOptions::new().openscript_path("/bin/sh");
    
    let spawn_result = spawn(r#"
        echo "Background task started"
        for i in 1 2 3 4 5; do
            echo "Processing item $i"
            sleep 1
        done
        echo "Background task completed"
    "#, options).await?;
    
    println!("   Spawned process with PID: {:?}", spawn_result.child.id());
    
    // Do other work while process runs
    for i in 1..=3 {
        println!("   Main thread working... step {}", i);
        sleep(Duration::from_secs(1)).await;
    }
    
    // Wait for completion
    let output = spawn_result.child.wait_with_output().await?;
    println!("   Background process output:");
    for line in String::from_utf8_lossy(&output.stdout).lines() {
        println!("     {}", line);
    }

    // Example 4: Comprehensive error handling
    println!("\nExample 4: Comprehensive error handling");
    
    let test_cases = vec![
        ("exit 0", "Success case"),
        ("exit 1", "Non-zero exit code"),
        ("nonexistent_command", "Command not found"),
        ("sleep 10", "Timeout case"),
    ];
    
    for (script, description) in test_cases {
        println!("   Testing: {}", description);
        let options = ScriptOptions::new()
            .openscript_path("/bin/sh")
            .timeout(Duration::from_secs(2));
            
        match run(script, options).await {
            Ok(result) => {
                if result.timed_out {
                    println!("     TIMEOUT: Script timed out");
                } else if result.exit_code == 0 {
                    println!("     SUCCESS: {}", result.stdout.trim());
                } else {
                    println!("     FAILED: Failed with exit code: {}", result.exit_code);
                    if !result.stderr.is_empty() {
                        println!("     Error output: {}", result.stderr.trim());
                    }
                }
            }
            Err(Error::Timeout { duration }) => {
                println!("     TIMEOUT: Timeout after {:?}", duration);
            }
            Err(Error::CommandFailed { message }) => {
                println!("     ERROR: Command failed: {}", message);
            }
            Err(e) => {
                println!("     ERROR: {}", e);
            }
        }
    }

    // Example 5: Environment isolation
    println!("\nExample 5: Environment isolation");
    
    // First, show current PATH
    let options = ScriptOptions::new().openscript_path("/bin/sh");
    let result = run("echo PATH has $(echo $PATH | tr ':' '\\n' | wc -l) entries", options).await?;
    println!("   Current environment: {}", result.stdout.trim());
    
    // Now with cleared environment
    let options = ScriptOptions::new()
        .openscript_path("/bin/sh")
        .clear_env(true)
        .env("PATH", "/bin:/usr/bin")
        .env("CUSTOM_VAR", "isolated_value");
    
    let result = run(r#"
        echo "PATH entries: $(echo $PATH | tr ':' '\n' | wc -l)"
        echo "Custom var: $CUSTOM_VAR"
        echo "HOME var: ${HOME:-<not set>}"
    "#, options).await?;
    
    println!("   Isolated environment:");
    for line in result.stdout.lines() {
        println!("     {}", line);
    }

    // Example 6: Data processing pipeline
    println!("\nExample 6: Data processing pipeline");
    
    let data = ["apple", "banana", "cherry", "date", "elderberry"];
    let data_str = data.join("\n");
    
    let options = ScriptOptions::new()
        .openscript_path("/bin/sh")
        .env("DATA", &data_str);
    
    let result = run(r#"
        echo "$DATA" | while read item; do
            echo "Processing: $item ($(echo $item | wc -c) chars)"
        done | head -3
    "#, options).await?;
    
    println!("   Pipeline results:");
    for line in result.stdout.lines() {
        println!("     {}", line);
    }

    println!("\nAdvanced examples completed successfully!");
    Ok(())
}