### Go: Execute Default Script Commands Source: https://context7.com/rsc/script/llms.txt Demonstrates executing a variety of default commands provided by the rsc.io/script package in Go. It covers file operations, text matching, environment variables, and more. This script requires a Go environment with the rsc.io/script library installed. ```go package main import ( "bufio" "context" "os" "strings" "rsc.io/script" ) func main() { engine := script.NewEngine() state, _ := script.NewState(context.Background(), "/tmp/test", nil) defer state.CloseAndWait(os.Stdout) testScript := ` # File operations mkdir -p data/logs cd data echo 'content' > file.txt cat file.txt cp file.txt file-backup.txt mv file-backup.txt backup.txt chmod 0644 backup.txt exists backup.txt rm backup.txt # Text matching and comparison echo 'Error: something failed' > output.txt grep 'Error:' output.txt ! grep 'Success' output.txt echo 'expected' > expected.txt echo 'expected' > actual.txt cmp actual.txt expected.txt cmpenv actual.txt expected.txt # With env var expansion # Output buffer inspection echo 'test output' stdout 'test output' ! stderr . # Pattern matching with regex echo 'Version 1.2.3' stdout 'Version [0-9]+\.[0-9]+\.[0-9]+' # Exact count matching echo -e 'line1\nline2\nline3' stdout -count=3 'line[0-9]' # Environment variables env FOO=bar BAZ=qux env FOO # Print value env # Print all vars # String replacement echo 'hello world' > file.txt replace hello goodbye file.txt cat file.txt # Output: goodbye world # Symlinks symlink link.txt -> target.txt # Background execution sleep 5s & sleep 2s & wait # Wait for all background commands # Conditional stop [GOOS:windows] stop 'Skipping on Windows' exec ./run-test.sh ` reader := bufio.NewReader(strings.NewReader(testScript)) engine.Execute(state, "demo.txt", reader, os.Stdout) } ``` -------------------------------- ### Create and Configure Script Engine (Go) Source: https://context7.com/rsc/script/llms.txt Demonstrates how to create a new script engine with default or custom commands and conditions. It also shows how to initialize the execution state with a context, working directory, and environment variables. The state should be closed after use to clean up resources. ```go package main import ( "context" "os" "rsc.io/script" ) func main() { // Create a new engine with default commands and conditions engine := script.NewEngine() // Or build a custom engine with specific commands customEngine := &script.Engine{ Cmds: map[string]script.Cmd{ "cat": script.Cat(), "echo": script.Echo(), "exec": script.Exec(nil, 0), }, Conds: map[string]script.Cond{ "GOOS": script.PrefixCondition( "runtime.GOOS == ", func(_ *script.State, suffix string) (bool, error) { return suffix == "linux", nil }), }, Quiet: false, // Set to true to suppress section logs } // Create execution state state, err := script.NewState(context.Background(), "/tmp/workdir", os.Environ()) if err != nil { panic(err) } defer state.CloseAndWait(os.Stdout) } ``` -------------------------------- ### Creating and Configuring a Script Engine Source: https://context7.com/rsc/script/llms.txt This section details how to create a new script engine, either with default commands or a custom set of commands and conditions. It also shows how to initialize the execution state. ```APIDOC ## Creating and Configuring a Script Engine ### Description Demonstrates the creation of a new `script.Engine` with default configurations or a customized set of commands and conditions. It also covers initializing the `script.State` for script execution. ### Method ```go // For Engine creation: engine := script.NewEngine() customEngine := &script.Engine{...} // For State creation: state, err := script.NewState(context.Background(), "/tmp/workdir", os.Environ()) ``` ### Endpoint N/A (Package API) ### Parameters #### Request Body (N/A for engine creation) #### Script.Engine Fields - **Cmds** (map[string]script.Cmd) - A map of command names to their implementations. - **Conds** (map[string]script.Cond) - A map of condition names to their implementations. - **Quiet** (bool) - If true, suppresses section logs. #### Script.NewState Parameters - **ctx** (context.Context) - The context for the operation. - **workdir** (string) - The working directory for script execution. - **environ** ([]string) - A slice of environment variables in `KEY=value` format. ### Request Example ```go package main import ( "context" "os" "rsc.io/script" ) func main() { // Create a new engine with default commands engine := script.NewEngine() // Create execution state state, err := script.NewState(context.Background(), "/tmp/workdir", os.Environ()) if err != nil { panic(err) } defer state.CloseAndWait(os.Stdout) } ``` ### Response #### Success Response (200) - **engine** (*script.Engine) - A new script engine instance. - **state** (*script.State) - The initialized script execution state. #### Response Example ```json { "engine": "", "state": "" } ``` ``` -------------------------------- ### List Commands and Conditions in Go Source: https://context7.com/rsc/script/llms.txt Demonstrates listing all available commands with brief and full details, and listing all conditions with their current state. It also shows how to list specific commands and conditions. This functionality is useful for understanding the scripting engine's capabilities and for debugging. ```go package main import ( "context" "os" "rsc.io/script" ) func main() { engine := script.NewEngine() state, _ := script.NewState(context.Background(), "/tmp", nil) // List all commands (brief) engine.ListCmds(os.Stdout, false) // Output: // cat files... [&] // concatenate files and print to the script's stdout buffer // cd dir // change the working directory // ... // List specific commands with full details engine.ListCmds(os.Stdout, true, "cat", "grep") // List all conditions with their current state engine.ListConds(os.Stdout, state) // Output: // [GOOS:*] // runtime.GOOS == // [GOARCH:*] // runtime.GOARCH == // [root] // os.Geteuid() == 0 // List specific conditions engine.ListConds(os.Stdout, state, "GOOS:linux", "root") } ``` -------------------------------- ### Integrate rsc.io/script with Go Testing Framework Source: https://context7.com/rsc/script/llms.txt Shows how to use the scripttest package to run script files (.txt) as part of Go tests. It demonstrates setting up a test engine with default or custom commands/conditions and running multiple scripts from a directory or a single archive. ```go package mypackage_test import ( "context" "os" "testing" "rsc.io/script" "rsc.io/script/scripttest" ) func TestMyTool(t *testing.T) { // Create engine with test-specific commands and conditions engine := &script.Engine{ Cmds: scripttest.DefaultCmds(), // Includes "skip" command Conds: scripttest.DefaultConds(), // Includes "exec:foo", "short", "verbose" } // Add custom command for your tool engine.Cmds["mytool"] = script.Program( "/usr/local/bin/mytool", nil, // cancel function 0, // wait delay ) // Run all .txt files in testdata directory scripttest.Test(t, context.Background(), engine, os.Environ(), "testdata/*.txt") } func TestSingleScript(t *testing.T) { engine := &script.Engine{ Cmds: scripttest.DefaultCmds(), Conds: scripttest.DefaultConds(), } workdir := t.TempDir() state, err := script.NewState(context.Background(), workdir, os.Environ()) if err != nil { t.Fatal(err) } // Extract txtar archive files to working directory archive := []byte(` -- input.txt -- test data -- expected.txt -- processed data `) script := []byte(` # Process the input file cat input.txt exec mytool input.txt output.txt cmp output.txt expected.txt `) scripttest.Run(t, engine, state, "test.txt", bytes.NewReader(script)) } ``` -------------------------------- ### Executing Scripts Source: https://context7.com/rsc/script/llms.txt This section explains how to execute a script using the `script.Engine.Execute` method. It covers script content, error handling, and demonstrates conditional and background execution. ```APIDOC ## Executing Scripts ### Description This section demonstrates how to execute a script using the `engine.Execute` method. It covers loading script content from a reader, handling execution errors, and showcases features like conditional execution and background process management. ### Method ```go err := engine.Execute(state, "script.name", reader, os.Stdout) ``` ### Endpoint N/A (Package API) ### Parameters #### Execute Parameters - **state** (*script.State) - The current execution state. - **name** (string) - The name of the script (used for error reporting). - **reader** (io.Reader) - An interface for reading the script content. - **w** (io.Writer) - The writer for script output. ### Request Example ```go package main import ( "bufio" "context" "os" "strings" "rsc.io/script" ) func main() { engine := script.NewEngine() state, _ := script.NewState(context.Background(), "/tmp/work", os.Environ()) defer state.CloseAndWait(os.Stdout) scriptContent := ` # Test basic file operations mkdir mydir cd mydir echo 'Hello, World!' > output.txt cat output.txt stdout 'Hello, World!' # Test conditional execution [GOOS:linux] echo 'Running on Linux' [!GOOS:windows] echo 'Not running on Windows' # Test background execution sleep 1s & wait ` reader := bufio.NewReader(strings.NewReader(scriptContent)) err := engine.Execute(state, "test.script", reader, os.Stdout) if err != nil { // Error includes file:line information panic(err) // Output: test.script:3: mkdir: file already exists } } ``` ### Response #### Success Response (200) No explicit return value on success, but script execution completes without error. #### Error Response - **error** (error) - An error object describing the failure, often including file and line information (e.g., `test.script:3: mkdir: file already exists`). #### Response Example (On error, the program typically panics or returns the error) ``` panic: test.script:3: mkdir: file already exists ``` ``` -------------------------------- ### Manage Script Execution State (Go) Source: https://context7.com/rsc/script/llms.txt Illustrates various methods for managing the state of a script execution, including changing directories, setting and looking up environment variables, expanding environment variables within strings, accessing standard output and error streams, converting paths, and logging. Proper cleanup using CloseAndWait is essential. ```go package main import ( "context" "fmt" "os" "rsc.io/script" ) func main() { state, _ := script.NewState(context.Background(), "/tmp/work", []string{ "PATH=/usr/bin:/bin", "HOME=/home/user", "CUSTOM_VAR=value", }) // Change working directory state.Chdir("subdir") fmt.Println(state.Getwd()) // Output: /tmp/work/subdir // Set environment variables state.Setenv("DEBUG", "true") // Look up environment variables if val, ok := state.LookupEnv("DEBUG"); ok { fmt.Println(val) // Output: true } // Expand environment variables in strings expanded := state.ExpandEnv("Home is $HOME", false) fmt.Println(expanded) // Output: Home is /home/user // Access command output buffers fmt.Println(state.Stdout()) // stdout from last command fmt.Println(state.Stderr()) // stderr from last command // Convert script paths to absolute paths absPath := state.Path("data/file.txt") fmt.Println(absPath) // Output: /tmp/work/subdir/data/file.txt // Log to the script's internal log state.Logf("Debug: Processing item %d\n", 42) // Clean up and wait for background processes state.CloseAndWait(os.Stdout) } ``` -------------------------------- ### Managing Script State Source: https://context7.com/rsc/script/llms.txt This section details how to manage the script execution state, including changing directories, setting/getting environment variables, expanding variables, accessing output buffers, converting paths, and logging. ```APIDOC ## Managing Script State ### Description This section covers the management of the `script.State` object, which holds the execution context for a script. It details operations such as changing the working directory, manipulating environment variables, expanding variables within strings, accessing standard output and error streams from executed commands, converting paths, and logging. ### Method ```go // State modification and access methods: state.Chdir(dir string) state.Setenv(key, val string) state.LookupEnv(key string) (string, bool) state.ExpandEnv(s string, nonempty bool) string state.Stdout() string state.Stderr() string state.Path(rel string) string state.Logf(format string, args ...interface{}) state.CloseAndWait(w io.Writer) ``` ### Endpoint N/A (Package API) ### Parameters #### Script.State Methods - **Chdir(dir string)**: Changes the current working directory. - **Setenv(key, val string)**: Sets an environment variable. - **LookupEnv(key string) (string, bool)**: Looks up an environment variable. Returns the value and a boolean indicating if it was found. - **ExpandEnv(s string, nonempty bool) string**: Expands environment variables in a string. If `nonempty` is true, unset variables are replaced with an empty string. - **Stdout() string**: Returns the captured standard output of the last command. - **Stderr() string**: Returns the captured standard error of the last command. - **Path(rel string) string**: Converts a relative path to an absolute path within the state's working directory. - **Logf(format string, args ...interface{})**: Writes a formatted log message to the script's internal log. - **CloseAndWait(w io.Writer)**: Cleans up resources and waits for any background processes to complete, writing their output to `w`. ### Request Example ```go package main import ( "context" "fmt" "os" "rsc.io/script" ) func main() { state, _ := script.NewState(context.Background(), "/tmp/work", []string{ "PATH=/usr/bin:/bin", "HOME=/home/user", "CUSTOM_VAR=value", }) // Change working directory state.Chdir("subdir") fmt.Println(state.Getwd()) // Output: /tmp/work/subdir // Set environment variables state.Setenv("DEBUG", "true") // Look up environment variables if val, ok := state.LookupEnv("DEBUG"); ok { fmt.Println(val) // Output: true } // Expand environment variables in strings expanded := state.ExpandEnv("Home is $HOME", false) fmt.Println(expanded) // Output: Home is /home/user // Access command output buffers fmt.Println(state.Stdout()) // stdout from last command fmt.Println(state.Stderr()) // stderr from last command // Convert script paths to absolute paths absPath := state.Path("data/file.txt") fmt.Println(absPath) // Output: /tmp/work/subdir/data/file.txt // Log to the script's internal log state.Logf("Debug: Processing item %d\n", 42) // Clean up and wait for background processes state.CloseAndWait(os.Stdout) } ``` ### Response #### Success Response (200) - **State Modifications**: Operations like `Chdir`, `Setenv` modify the internal state. - **Output**: Methods like `Getwd`, `LookupEnv`, `ExpandEnv`, `Stdout`, `Stderr`, `Path` return specific values. - **Logging**: `Logf` writes to an internal buffer. - **Cleanup**: `CloseAndWait` performs cleanup and waits for processes. #### Response Example ```json { "Getwd": "/tmp/work/subdir", "LookupEnv_DEBUG": "true", "ExpandEnv_Home": "Home is /home/user", "Stdout": "", "Stderr": "", "Path_data_file_txt": "/tmp/work/subdir/data/file.txt", "Logf": "Debug: Processing item 42\n" } ``` ``` -------------------------------- ### Go: Script Language Features Source: https://context7.com/rsc/script/llms.txt Illustrates advanced features of the rsc.io/script language using Go. This includes environment variable expansion, quoting rules, conditional execution based on system properties, background commands, and output verification. It's designed to showcase the flexibility and power of the script syntax. ```go // Example script demonstrating all language features scriptText := ` # Comments start with # and explain what's being tested # Blank lines are ignored # Environment variable expansion (using script's environment) echo $HOME echo ${PATH} # Special variables: ${/} = path separator, ${:} = path list separator echo 'Path: C:${/}Users${/}Name' # Quoting disables variable expansion and preserves spaces echo '$HOME is not expanded' echo 'This is a single argument with spaces' # Use '' to embed single quotes echo 'Don''t expand $VAR' # Command prefixes for error handling ! grep 'missing' file.txt # Must fail (negation) ? grep 'maybe' file.txt # May succeed or fail (optional) # Conditional execution with [condition] [GOOS:linux] echo 'Only on Linux' [GOARCH:amd64] echo 'Only on amd64' [!windows] echo 'Not on Windows' # Multiple conditions (all must be true) [linux] [amd64] echo 'Linux on amd64' # Custom conditions with prefix:suffix syntax [env:DEBUG] echo 'DEBUG is set' # Background execution with & sleep 10s & echo 'This runs immediately' wait # Wait for background commands to complete # Command output is captured to stdout/stderr buffers echo 'hello' stdout 'hello' # Verify stdout contains pattern exec ./myprogram arg1 arg2 stderr 'ERROR' # Verify stderr contains pattern ! stdout . # Verify stdout is empty # Stop script execution (not an error) [short] stop 'Skipping slow test in short mode' exec ./long-running-test ` ``` -------------------------------- ### Create Synchronous and Asynchronous Go Commands for rsc.io/script Source: https://context7.com/rsc/script/llms.txt Demonstrates how to define custom synchronous and asynchronous commands using the script.Command function. Synchronous commands execute and return output immediately, while asynchronous commands can run in the background. Both require a WaitFunc to return output or indicate completion. ```go package main import ( "fmt" "os" "strings" "time" "rsc.io/script" ) func main() { // Simple synchronous command greetCmd := script.Command( script.CmdUsage{ Summary: "greet a user by name", Args: "name", Detail: []string{"Prints a greeting message to stdout."}, }, func(s *script.State, args ...string) (script.WaitFunc, error) { if len(args) != 1 { return nil, script.ErrUsage } name := args[0] // Return WaitFunc for commands that produce output return func(*script.State) (stdout, stderr string, err error) { return fmt.Sprintf("Hello, %s!\n", name), "", nil }, nil }, ) // Asynchronous command that can run in background countCmd := script.Command( script.CmdUsage{ Summary: "count from 1 to N", Args: "max", Async: true, // Enables background execution with & }, func(s *script.State, args ...string) (script.WaitFunc, error) { if len(args) != 1 { return nil, script.ErrUsage } max := 5 // parse from args[0] done := make(chan string) // Start work in goroutine go func() { var out strings.Builder for i := 1; i <= max; i++ { fmt.Fprintf(&out, "%d\n", i) time.Sleep(100 * time.Millisecond) } done <- out.String() }() // Return WaitFunc that blocks until completion return func(*script.State) (stdout, stderr string, err error) { output := <-done return output, "", nil }, nil }, ) // Register commands with engine engine := script.NewEngine() engine.Cmds["greet"] = greetCmd engine.Cmds["count"] = countCmd } ``` -------------------------------- ### Define Custom Conditions for rsc.io/script in Go Source: https://context7.com/rsc/script/llms.txt Illustrates various ways to define custom conditions for the script engine. This includes simple boolean conditions, dynamic conditions that evaluate at runtime, prefix conditions with suffixes, and cached conditions for performance. ```go package main import ( "os" "runtime" "rsc.io/script" ) func main() { engine := script.NewEngine() // Simple boolean condition (no suffix) engine.Conds["ci"] = script.BoolCondition( "running in CI environment", os.Getenv("CI") == "true", ) // Dynamic condition that evaluates per execution engine.Conds["debug"] = script.Condition( "DEBUG environment variable is set", func(s *script.State) (bool, error) { val, ok := s.LookupEnv("DEBUG") return ok && val != "" && val != "false", nil }, ) // Prefix condition with suffix parameter engine.Conds["env"] = script.PrefixCondition( "environment variable is non-empty", func(s *script.State, suffix string) (bool, error) { val, ok := s.LookupEnv(suffix) return ok && val != "", nil }, ) // Cached condition (evaluated once and reused) engine.Conds["arch"] = script.OnceCondition( "running on amd64 architecture", func() (bool, error) { return runtime.GOARCH == "amd64", nil }, ) // Prefix condition with caching per suffix engine.Conds["fileexists"] = script.CachedCondition( "file exists", func(path string) (bool, error) { _, err := os.Stat(path) return err == nil, nil }, ) } ``` -------------------------------- ### Execute Script Content with Engine (Go) Source: https://context7.com/rsc/script/llms.txt Shows how to execute a script defined as a string using a script engine. The script can include commands for file operations, conditional execution based on environment variables, and background processes. Errors during execution are captured and can be used for debugging. ```go package main import ( "bufio" "context" "os" "strings" "rsc.io/script" ) func main() { engine := script.NewEngine() state, _ := script.NewState(context.Background(), "/tmp/work", os.Environ()) defer state.CloseAndWait(os.Stdout) scriptContent := ` # Test basic file operations mkdir mydir cd mydir echo 'Hello, World!' > output.txt cat output.txt stdout 'Hello, World!' # Test conditional execution [GOOS:linux] echo 'Running on Linux' [!GOOS:windows] echo 'Not running on Windows' # Test background execution sleep 1s & wait ` reader := bufio.NewReader(strings.NewReader(scriptContent)) err := engine.Execute(state, "test.script", reader, os.Stdout) if err != nil { // Error includes file:line information panic(err) // Output: test.script:3: mkdir: file already exists } } ``` -------------------------------- ### Go: Script Error Handling Source: https://context7.com/rsc/script/llms.txt Demonstrates how to handle errors when executing scripts with rsc.io/script in Go. It shows how to catch command execution errors, identify specific error types like `CommandError`, `ErrUnexpectedSuccess`, and `ErrUsage`, and extract detailed information about the failure. This is crucial for robust script execution and debugging. ```go package main import ( "bufio" "context" "errors" "fmt" "os" "strings" "rsc.io/script" ) func main() { engine := script.NewEngine() state, _ := script.NewState(context.Background(), "/tmp/work", nil) defer state.CloseAndWait(os.Stdout) badScript := ` mkdir testdir cd nonexistent # This will fail echo 'never executed' ` reader := bufio.NewReader(strings.NewReader(badScript)) err := engine.Execute(state, "test.txt", reader, os.Stdout) if err != nil { // Errors include file and line information fmt.Println(err) // Output: test.txt:2: cd nonexistent: Chdir: stat /tmp/work/nonexistent: no such file or directory // Check for specific error types var cmdErr *script.CommandError if errors.As(err, &cmdErr) { fmt.Printf("Command: %s\n", cmdErr.Op) // cd fmt.Printf("Line: %d\n", cmdErr.Line) // 2 fmt.Printf("Args: %v\n", cmdErr.Args) // [nonexistent] fmt.Printf("Error: %v\n", cmdErr.Unwrap()) // underlying error } // ErrUnexpectedSuccess when ! command succeeds if errors.Is(err, script.ErrUnexpectedSuccess) { fmt.Println("Command was expected to fail but succeeded") } // ErrUsage for invalid command arguments if errors.Is(err, script.ErrUsage) { fmt.Println("Command used with invalid arguments") } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.