Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
514 changes: 225 additions & 289 deletions README.md

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions creationflags_nonwindows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//go:build !windows

package execx

const (
// CreateNewProcessGroup starts the process in a new process group.
CreateNewProcessGroup = 0x00000200
// CreateNewConsole creates a new console for the process.
CreateNewConsole = 0x00000010
// CreateNoWindow prevents console windows from being created.
CreateNoWindow = 0x08000000
)
14 changes: 14 additions & 0 deletions creationflags_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build windows

package execx

import "syscall"

const (
// CreateNewProcessGroup starts the process in a new process group.
CreateNewProcessGroup = syscall.CREATE_NEW_PROCESS_GROUP
// CreateNewConsole creates a new console for the process.
CreateNewConsole = syscall.CREATE_NEW_CONSOLE
// CreateNoWindow prevents console windows from being created.
CreateNoWindow = syscall.CREATE_NO_WINDOW
)
6 changes: 3 additions & 3 deletions examples/arg/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ func main() {
// Arg appends arguments to the command.

// Example: add args
cmd := execx.Command("go", "env").Arg("GOOS")
cmd := execx.Command("printf").Arg("hello")
out, _ := cmd.Output()
fmt.Println(out != "")
// #bool true
fmt.Print(out)
// hello
}
10 changes: 7 additions & 3 deletions examples/combinedoutput/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ func main() {
// CombinedOutput executes the command and returns stdout+stderr and any error.

// Example: combined output
out, _ := execx.Command("go", "env", "GOOS").CombinedOutput()
fmt.Println(out != "")
// #bool true
out, err := execx.Command("go", "env", "-badflag").CombinedOutput()
fmt.Print(out)
fmt.Println(err == nil)
// flag provided but not defined: -badflag
// usage: go env [-json] [-changed] [-u] [-w] [var ...]
// Run 'go help env' for details.
// false
}
6 changes: 3 additions & 3 deletions examples/command/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ func main() {
// Command constructs a new command without executing it.

// Example: command
cmd := execx.Command("go", "env", "GOOS")
cmd := execx.Command("printf", "hello")
out, _ := cmd.Output()
fmt.Println(out != "")
// #bool true
fmt.Print(out)
// hello
}
10 changes: 4 additions & 6 deletions examples/creationflags/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import (
)

func main() {
// CreationFlags sets Windows creation flags.
// CreationFlags sets Windows process creation flags (for example, create a new process group).

// Example: creation flags
fmt.Println(execx.Command("go", "env", "GOOS").CreationFlags(0) != nil)
// #bool true
// Example: creation flags
fmt.Println(execx.Command("go", "env", "GOOS").CreationFlags(0) != nil)
// #bool true
out, _ := execx.Command("printf", "ok").CreationFlags(execx.CreateNewProcessGroup).Output()
fmt.Print(out)
// ok
}
4 changes: 2 additions & 2 deletions examples/gracefulshutdown/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func main() {
// Example: graceful shutdown
proc := execx.Command("sleep", "2").Start()
_ = proc.GracefulShutdown(os.Interrupt, 100*time.Millisecond)
res, err := proc.Wait()
fmt.Println(err != nil || res.ExitCode != 0)
res, _ := proc.Wait()
fmt.Println(res.IsSignal(os.Interrupt))
// #bool true
}
10 changes: 4 additions & 6 deletions examples/hidewindow/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@ import (
)

func main() {
// HideWindow controls window visibility and sets CREATE_NO_WINDOW for console apps.
// HideWindow hides console windows and sets CREATE_NO_WINDOW for console apps.

// Example: hide window
fmt.Println(execx.Command("go", "env", "GOOS").HideWindow(true) != nil)
// #bool true
// Example: hide window
fmt.Println(execx.Command("go", "env", "GOOS").HideWindow(true) != nil)
// #bool true
out, _ := execx.Command("printf", "ok").HideWindow(true).Output()
fmt.Print(out)
// ok
}
6 changes: 3 additions & 3 deletions examples/interrupt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func main() {
// Example: interrupt
proc := execx.Command("sleep", "2").Start()
_ = proc.Interrupt()
res, err := proc.Wait()
fmt.Println(err != nil || res.ExitCode != 0)
// #bool true
res, _ := proc.Wait()
fmt.Printf("%+v", res)
// {Stdout: Stderr: ExitCode:-1 Err:<nil> Duration:75.987ms signal:interrupt}
}
6 changes: 3 additions & 3 deletions examples/killafter/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {
// Example: kill after
proc := execx.Command("sleep", "2").Start()
proc.KillAfter(100 * time.Millisecond)
res, err := proc.Wait()
fmt.Println(err != nil || res.ExitCode != 0)
// #bool true
res, _ := proc.Wait()
fmt.Printf("%+v", res)
// {Stdout: Stderr: ExitCode:-1 Err:<nil> Duration:100.456ms signal:killed}
}
50 changes: 50 additions & 0 deletions examples/kitchensink/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//go:build ignore
// +build ignore

package main

import (
"context"
"fmt"
"github.com/goforj/execx"
"log"
"time"
)

func main() {
// Run executes the command and returns the result and any error.

ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()

res, err := execx.
Command("printf", "hello\nworld\n").
Pipe("tr", "a-z", "A-Z").
Env("MODE=demo").
WithContext(ctx).
OnStdout(func(line string) {
fmt.Println("OUT:", line)
}).
OnStderr(func(line string) {
fmt.Println("ERR:", line)
}).
Run()

if !res.OK() {
log.Fatalf("command failed: %v", err)
}

fmt.Printf("Stdout: %q\n", res.Stdout)
fmt.Printf("Stderr: %q\n", res.Stderr)
fmt.Printf("ExitCode: %d\n", res.ExitCode)
fmt.Printf("Error: %v\n", res.Err)
fmt.Printf("Duration: %v\n", res.Duration)
// OUT: HELLO
// OUT: WORLD
// Stdout: "HELLO\nWORLD\n"
// Stderr: ""
// ExitCode: 0
// Error: <nil>
// Duration: 10.123456ms

}
2 changes: 1 addition & 1 deletion examples/onstderr/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ func main() {
// flag provided but not defined: -badflag
// usage: go env [-json] [-changed] [-u] [-w] [var ...]
// Run 'go help env' for details.
// true
// false
}
4 changes: 2 additions & 2 deletions examples/onstdout/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ func main() {
// OnStdout registers a line callback for stdout.

// Example: stdout lines
_, _ = execx.Command("go", "env", "GOOS").
_, _ = execx.Command("printf", "hi\n").
OnStdout(func(line string) { fmt.Println(line) }).
Run()
// darwin
// hi
}
6 changes: 3 additions & 3 deletions examples/output/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
// Output executes the command and returns stdout and any error.

// Example: output
out, _ := execx.Command("go", "env", "GOOS").Output()
fmt.Println(out != "")
// #bool true
out, _ := execx.Command("printf", "hello").Output()
fmt.Print(out)
// hello
}
6 changes: 3 additions & 3 deletions examples/outputbytes/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
// OutputBytes executes the command and returns stdout bytes and any error.

// Example: output bytes
out, _ := execx.Command("go", "env", "GOOS").OutputBytes()
fmt.Println(len(out) > 0)
// #bool true
out, _ := execx.Command("printf", "hello").OutputBytes()
fmt.Println(string(out))
// #string hello
}
6 changes: 3 additions & 3 deletions examples/outputtrimmed/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func main() {
// OutputTrimmed executes the command and returns trimmed stdout and any error.

// Example: output trimmed
out, _ := execx.Command("go", "env", "GOOS").OutputTrimmed()
fmt.Println(out != "")
// #bool true
out, _ := execx.Command("printf", "hello\n").OutputTrimmed()
fmt.Println(out)
// #string hello
}
14 changes: 5 additions & 9 deletions examples/pdeathsig/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@ package main
import (
"fmt"
"github.com/goforj/execx"
"syscall"
)

func main() {
// Pdeathsig sets a parent-death signal on Linux.
// Pdeathsig sets a parent-death signal on Linux so the child is signaled if the parent exits.

// Example: pdeathsig
fmt.Println(execx.Command("go", "env", "GOOS").Pdeathsig(0) != nil)
// #bool true
// Example: pdeathsig
fmt.Println(execx.Command("go", "env", "GOOS").Pdeathsig(0) != nil)
// #bool true
// Example: pdeathsig
fmt.Println(execx.Command("go", "env", "GOOS").Pdeathsig(0) != nil)
// #bool true
out, _ := execx.Command("printf", "ok").Pdeathsig(syscall.SIGTERM).Output()
fmt.Print(out)
// ok
}
6 changes: 3 additions & 3 deletions examples/pipebesteffort/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ func main() {
// PipeBestEffort sets best-effort pipeline semantics (run all stages, surface the first error).

// Example: best effort
res, err := execx.Command("false").
res, _ := execx.Command("false").
Pipe("printf", "ok").
PipeBestEffort().
Run()
fmt.Println(err == nil && res.Stdout == "ok")
// #bool true
fmt.Print(res.Stdout)
// ok
}
9 changes: 6 additions & 3 deletions examples/pipelineresults/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,12 @@ func main() {
// PipelineResults executes the command and returns per-stage results and any error.

// Example: pipeline results
results, err := execx.Command("printf", "go").
results, _ := execx.Command("printf", "go").
Pipe("tr", "a-z", "A-Z").
PipelineResults()
fmt.Println(err == nil && len(results) == 2)
// #bool true
fmt.Printf("%+v", results)
// [
// {Stdout:go Stderr: ExitCode:0 Err:<nil> Duration:6.367208ms signal:<nil>}
// {Stdout:GO Stderr: ExitCode:0 Err:<nil> Duration:4.976291ms signal:<nil>}
// ]
}
6 changes: 3 additions & 3 deletions examples/send/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func main() {
// Example: send signal
proc := execx.Command("sleep", "2").Start()
_ = proc.Send(os.Interrupt)
res, err := proc.Wait()
fmt.Println(err != nil || res.ExitCode != 0)
// #bool true
res, _ := proc.Wait()
fmt.Printf("%+v", res)
// {Stdout: Stderr: ExitCode:-1 Err:<nil> Duration:80.123ms signal:interrupt}
}
13 changes: 4 additions & 9 deletions examples/setpgid/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@ import (
)

func main() {
// Setpgid sets the process group ID behavior.
// Setpgid places the child in a new process group for group signals.

// Example: setpgid
fmt.Println(execx.Command("go", "env", "GOOS").Setpgid(true) != nil)
// #bool true
// Example: setpgid
fmt.Println(execx.Command("go", "env", "GOOS").Setpgid(true) != nil)
// #bool true
// Example: setpgid
fmt.Println(execx.Command("go", "env", "GOOS").Setpgid(true) != nil)
// #bool true
out, _ := execx.Command("printf", "ok").Setpgid(true).Output()
fmt.Print(out)
// ok
}
13 changes: 4 additions & 9 deletions examples/setsid/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,10 @@ import (
)

func main() {
// Setsid sets the session ID behavior.
// Setsid starts the child in a new session, detaching it from the terminal.

// Example: setsid
fmt.Println(execx.Command("go", "env", "GOOS").Setsid(true) != nil)
// #bool true
// Example: setsid
fmt.Println(execx.Command("go", "env", "GOOS").Setsid(true) != nil)
// #bool true
// Example: setsid
fmt.Println(execx.Command("go", "env", "GOOS").Setsid(true) != nil)
// #bool true
out, _ := execx.Command("printf", "ok").Setsid(true).Output()
fmt.Print(out)
// ok
}
15 changes: 15 additions & 0 deletions examples/shadowprint/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//go:build ignore
// +build ignore

package main

import "github.com/goforj/execx"

func main() {
// ShadowPrint writes the shell-escaped command to stderr before and after execution.

// Example: shadow print
_, _ = execx.Command("printf", "hi").ShadowPrint().Run()
// execx > printf hi
// execx > printf hi (1ms)
}
21 changes: 21 additions & 0 deletions examples/shadowprintformatter/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build ignore
// +build ignore

package main

import (
"fmt"
"github.com/goforj/execx"
)

func main() {
// ShadowPrintFormatter sets a formatter for ShadowPrint output.

// Example: shadow print formatter
formatter := func(ev execx.ShadowEvent) string {
return fmt.Sprintf("shadow: %s %s", ev.Phase, ev.Command)
}
_, _ = execx.Command("printf", "hi").ShadowPrintFormatter(formatter).Run()
// shadow: before printf hi
// shadow: after printf hi
}
21 changes: 21 additions & 0 deletions examples/shadowprintmask/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//go:build ignore
// +build ignore

package main

import (
"github.com/goforj/execx"
"strings"
)

func main() {
// ShadowPrintMask sets a command masker for ShadowPrint output.

// Example: shadow print mask
mask := func(cmd string) string {
return strings.ReplaceAll(cmd, "secret", "***")
}
_, _ = execx.Command("printf", "secret").ShadowPrintMask(mask).Run()
// execx > printf ***
// execx > printf *** (1ms)
}
Loading
Loading