// Copyright GoFrame Author(https://goframe.org). All Rights Reserved. // // This Source Code Form is subject to the terms of the MIT License. // If a copy of the MIT was not distributed with this file, // You can obtain one at https://github.com/gogf/gf. package gproc import ( "bytes" "context" "fmt" "io" "runtime" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/propagation" "github.com/gogf/gf/v2/os/gfile" ) // Shell executes command `cmd` synchronously with given input pipe `in` and output pipe `out`. // The command `cmd` reads the input parameters from input pipe `in`, and writes its output automatically // to output pipe `out`. func Shell(ctx context.Context, cmd string, out io.Writer, in io.Reader) error { p := NewProcess( getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), ) p.Stdin = in p.Stdout = out return p.Run(ctx) } // ShellRun executes given command `cmd` synchronously and outputs the command result to the stdout. func ShellRun(ctx context.Context, cmd string) error { p := NewProcess( getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), ) return p.Run(ctx) } // ShellExec executes given command `cmd` synchronously and returns the command result. func ShellExec(ctx context.Context, cmd string, environment ...[]string) (result string, err error) { var ( buf = bytes.NewBuffer(nil) p = NewProcess( getShell(), append([]string{getShellOption()}, parseCommand(cmd)...), environment..., ) ) p.Stdout = buf p.Stderr = buf err = p.Run(ctx) result = buf.String() return } // parseCommand parses command `cmd` into slice arguments. // // Note that it just parses the `cmd` for "cmd.exe" binary in windows, but it is not necessary // parsing the `cmd` for other systems using "bash"/"sh" binary. func parseCommand(cmd string) (args []string) { return []string{cmd} } // getShell returns the shell command depending on current working operating system. // It returns "cmd.exe" for windows, and "bash" or "sh" for others. func getShell() string { switch runtime.GOOS { case "windows": return SearchBinary("cmd.exe") default: // Check the default binary storage path. if gfile.Exists("/bin/bash") { return "/bin/bash" } if gfile.Exists("/bin/sh") { return "/bin/sh" } // Else search the env PATH. path := SearchBinary("bash") if path == "" { path = SearchBinary("sh") } return path } } // getShellOption returns the shell option depending on current working operating system. // It returns "/c" for windows, and "-c" for others. func getShellOption() string { switch runtime.GOOS { case "windows": return "/c" default: return "-c" } } // tracingEnvFromCtx converts OpenTelemetry propagation data as environment variables. func tracingEnvFromCtx(ctx context.Context) []string { var ( a = make([]string, 0) m = make(map[string]string) ) otel.GetTextMapPropagator().Inject(ctx, propagation.MapCarrier(m)) for k, v := range m { a = append(a, fmt.Sprintf(`%s=%s`, k, v)) } return a }