Compare commits
41 commits
Author | SHA1 | Date | |
---|---|---|---|
45fa8a0124 | |||
5827a7434b | |||
0466a423ec | |||
88c55d3d73 | |||
8c22105cf2 | |||
2ced31effd | |||
13c3c6241c | |||
b14e2ccfb1 | |||
8959b13a0d | |||
c395f09556 | |||
a693fb5cd6 | |||
2b190eccb7 | |||
2a59a80b11 | |||
ad63e15564 | |||
f9e5426b1b | |||
3e5b7f99fc | |||
f627fde186 | |||
8a7fdf0f43 | |||
060a6a49eb | |||
db8c33a526 | |||
6cbbe69223 | |||
751d90c840 | |||
69b891d598 | |||
def7d60825 | |||
8390e16616 | |||
c0fb972b5f | |||
c7db79fe13 | |||
0fb6fcc14a | |||
182f75e37a | |||
991429a290 | |||
5d646427bd | |||
992dd14272 | |||
bde6ae681e | |||
750686fd1f | |||
4e2c314c2c | |||
e6ff94c45f | |||
cafa0dcca1 | |||
c7b6273166 | |||
ef7c4f26f7 | |||
2cc3517f37 | |||
d127424b9f |
11 changed files with 459 additions and 235 deletions
28
cmd/command.go
Normal file
28
cmd/command.go
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Command(cmd string) (string, error) {
|
||||||
|
|
||||||
|
command := exec.Command("command", "-v", cmd)
|
||||||
|
|
||||||
|
outputBytes, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) {
|
||||||
|
if exitErr.ExitCode() == 1 {
|
||||||
|
return "", ErrNotFound
|
||||||
|
} else {
|
||||||
|
return "", fmt.Errorf("command error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Trim(string(outputBytes), "\n"), nil
|
||||||
|
|
||||||
|
}
|
38
cmd/node.go
Normal file
38
cmd/node.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var NodeNotFound = errors.New("nodejs not found")
|
||||||
|
|
||||||
|
func Node(options BasicOptions, args ...string) (output string, err error) {
|
||||||
|
|
||||||
|
if _, err := Which("node", BasicOptions{
|
||||||
|
Env: options.Env,
|
||||||
|
Sources: options.Sources,
|
||||||
|
Cwd: options.Cwd,
|
||||||
|
}); err != nil {
|
||||||
|
if errors.Is(err, ErrNotFound) {
|
||||||
|
return "", NodeNotFound
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command := exec.Command("node", args...)
|
||||||
|
|
||||||
|
outputBytes, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) {
|
||||||
|
return "", fmt.Errorf("command error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Trim(string(outputBytes), "\n"), nil
|
||||||
|
|
||||||
|
}
|
37
cmd/pip.go
Normal file
37
cmd/pip.go
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Pip(options BasicOptions, args ...string) (output string, err error) {
|
||||||
|
|
||||||
|
if _, err := Which("python3", BasicOptions{
|
||||||
|
Env: options.Env,
|
||||||
|
Sources: options.Sources,
|
||||||
|
Cwd: options.Cwd,
|
||||||
|
}); err != nil {
|
||||||
|
if errors.Is(err, ErrNotFound) {
|
||||||
|
return "", PythonNotFound
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command := exec.Command("python3", "-m", "pip")
|
||||||
|
command.Args = append(command.Args, args...)
|
||||||
|
|
||||||
|
outputBytes, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) {
|
||||||
|
return "", fmt.Errorf("command error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Trim(string(outputBytes), "\n"), nil
|
||||||
|
|
||||||
|
}
|
38
cmd/python.go
Normal file
38
cmd/python.go
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var PythonNotFound = errors.New("python not found")
|
||||||
|
|
||||||
|
func Python(options BasicOptions, args ...string) (output string, err error) {
|
||||||
|
|
||||||
|
if _, err := Which("python3", BasicOptions{
|
||||||
|
Env: options.Env,
|
||||||
|
Sources: options.Sources,
|
||||||
|
Cwd: options.Cwd,
|
||||||
|
}); err != nil {
|
||||||
|
if errors.Is(err, ErrNotFound) {
|
||||||
|
return "", PythonNotFound
|
||||||
|
} else {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command := exec.Command("python3", args...)
|
||||||
|
|
||||||
|
outputBytes, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) {
|
||||||
|
return "", fmt.Errorf("command error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Trim(string(outputBytes), "\n"), nil
|
||||||
|
|
||||||
|
}
|
49
cmd/which.go
Normal file
49
cmd/which.go
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNotFound = errors.New("which: command not found")
|
||||||
|
|
||||||
|
type BasicOptions struct {
|
||||||
|
Env map[string]string
|
||||||
|
Sources []string
|
||||||
|
Cwd string
|
||||||
|
}
|
||||||
|
|
||||||
|
func Which(cmd string, options BasicOptions) (dir string, err error) {
|
||||||
|
|
||||||
|
var sourceCommand strings.Builder
|
||||||
|
for _, value := range options.Sources {
|
||||||
|
sourceCommand.WriteString(fmt.Sprintf("source %s && ", value))
|
||||||
|
}
|
||||||
|
|
||||||
|
command := exec.Command("which", cmd)
|
||||||
|
|
||||||
|
if options.Cwd != "" {
|
||||||
|
command.Dir = options.Cwd
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v := range options.Env {
|
||||||
|
command.Env = append(command.Env, fmt.Sprintf("%s=%s", k, v))
|
||||||
|
}
|
||||||
|
|
||||||
|
outputBytes, err := command.Output()
|
||||||
|
if err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) {
|
||||||
|
if exitErr.ExitCode() == 1 {
|
||||||
|
return "", ErrNotFound
|
||||||
|
} else {
|
||||||
|
return "", fmt.Errorf("command error: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings.Trim(string(outputBytes), "\n"), nil
|
||||||
|
|
||||||
|
}
|
2
go.mod
2
go.mod
|
@ -1,4 +1,4 @@
|
||||||
module git.shadowhosting.xyz/Eggactyl/shell
|
module git.eggactyl.cloud/Eggactyl/shell
|
||||||
|
|
||||||
go 1.22.5
|
go 1.22.5
|
||||||
|
|
||||||
|
|
18
linux/events.go
Normal file
18
linux/events.go
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
package linux
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventOutput = iota
|
||||||
|
EventExit
|
||||||
|
)
|
||||||
|
|
||||||
|
type EventOutputData struct {
|
||||||
|
Output string
|
||||||
|
CmdOptions CommandOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
type EventExitData struct {
|
||||||
|
HasSucceeded bool
|
||||||
|
ExitCode int
|
||||||
|
CmdOptions CommandOptions
|
||||||
|
Error string
|
||||||
|
}
|
|
@ -2,10 +2,17 @@ package linux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LinuxCommand struct {
|
type LinuxCommand struct {
|
||||||
Options CommandOptions
|
Options CommandOptions
|
||||||
|
handlers map[int]interface{}
|
||||||
|
wg sync.WaitGroup
|
||||||
|
stdout io.ReadCloser
|
||||||
|
stderr io.ReadCloser
|
||||||
|
stdin io.WriteCloser
|
||||||
}
|
}
|
||||||
|
|
||||||
type CommandOptions struct {
|
type CommandOptions struct {
|
||||||
|
@ -13,6 +20,7 @@ type CommandOptions struct {
|
||||||
Sources []string
|
Sources []string
|
||||||
Command string
|
Command string
|
||||||
Args []string
|
Args []string
|
||||||
|
CustomErrors map[int8]error
|
||||||
Cwd string
|
Cwd string
|
||||||
Shell string
|
Shell string
|
||||||
}
|
}
|
||||||
|
@ -23,4 +31,6 @@ var (
|
||||||
ErrRunningCmd = errors.New("error running command")
|
ErrRunningCmd = errors.New("error running command")
|
||||||
ErrCommandNotFound = errors.New("error command not found")
|
ErrCommandNotFound = errors.New("error command not found")
|
||||||
ErrCommandNotExecutable = errors.New("error command not executable")
|
ErrCommandNotExecutable = errors.New("error command not executable")
|
||||||
|
ErrInvalidHandler = errors.New("invalid handler")
|
||||||
|
ErrRunningEvt = errors.New("error running event")
|
||||||
)
|
)
|
||||||
|
|
259
linux/run.go
259
linux/run.go
|
@ -1,10 +1,17 @@
|
||||||
package linux
|
package linux
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"strings"
|
||||||
|
"syscall"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewCommand(options CommandOptions) (*LinuxCommand, error) {
|
func NewCommand(options CommandOptions) (*LinuxCommand, error) {
|
||||||
|
@ -23,59 +30,219 @@ func NewCommand(options CommandOptions) (*LinuxCommand, error) {
|
||||||
|
|
||||||
return &LinuxCommand{
|
return &LinuxCommand{
|
||||||
Options: options,
|
Options: options,
|
||||||
|
handlers: make(map[int]interface{}),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd *LinuxCommand) Run() error {
|
func (cmd *LinuxCommand) AddHandler(handler interface{}) error {
|
||||||
|
|
||||||
var sourceCommand string
|
switch h := handler.(type) {
|
||||||
for _, value := range cmd.Options.Sources {
|
case func(data EventOutputData) error:
|
||||||
sourceCommand += fmt.Sprintf("source %s && ", value)
|
cmd.handlers[EventOutput] = h
|
||||||
}
|
break
|
||||||
|
case func(data EventExitData) error:
|
||||||
command := exec.Command(cmd.Options.Shell, "-c", sourceCommand+cmd.Options.Command)
|
cmd.handlers[EventExit] = h
|
||||||
command.Dir = cmd.Options.Cwd
|
break
|
||||||
command.Args = append(command.Args, cmd.Options.Args...)
|
default:
|
||||||
|
return ErrInvalidHandler
|
||||||
// Loop through env to format and add them to the command.
|
|
||||||
for key, value := range cmd.Options.Env {
|
|
||||||
command.Env = append(command.Env, fmt.Sprintf("%s=%s", key, value))
|
|
||||||
}
|
|
||||||
|
|
||||||
isCommandExecutable, err := cmd.isCommandExecutable(cmd.Options.Command)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isCommandExecutable {
|
|
||||||
return ErrCommandNotExecutable
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := command.Start(); err != nil {
|
|
||||||
var exitErr *exec.ExitError
|
|
||||||
if errors.As(err, &exitErr) {
|
|
||||||
fmt.Println(exitErr.ExitCode())
|
|
||||||
if exitErr.ExitCode() == 127 {
|
|
||||||
return ErrCommandNotFound
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("%s: %w", ErrRunningCmd.Error(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := command.Wait(); err != nil {
|
|
||||||
var exitErr *exec.ExitError
|
|
||||||
if errors.As(err, &exitErr) {
|
|
||||||
fmt.Println(exitErr.ExitCode())
|
|
||||||
if exitErr.ExitCode() == 127 {
|
|
||||||
return ErrCommandNotFound
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("%s: %w", ErrRunningCmd.Error(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cmd *LinuxCommand) Run() error {
|
||||||
|
|
||||||
|
//isCommandExecutable, err := cmd.isCommandExecutable(cmd.Options.Command)
|
||||||
|
//if err != nil {
|
||||||
|
// return err
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//if !isCommandExecutable {
|
||||||
|
// return ErrCommandNotExecutable
|
||||||
|
//}
|
||||||
|
|
||||||
|
var sourceCommand strings.Builder
|
||||||
|
for _, value := range cmd.Options.Sources {
|
||||||
|
sourceCommand.WriteString(fmt.Sprintf("source %s && ", value))
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandOptions strings.Builder
|
||||||
|
commandOptions.WriteString(" ")
|
||||||
|
for index, arg := range cmd.Options.Args {
|
||||||
|
if len(cmd.Options.Args)-1 == index {
|
||||||
|
commandOptions.WriteString(fmt.Sprintf("%s", arg))
|
||||||
|
} else {
|
||||||
|
commandOptions.WriteString(fmt.Sprintf("%s ", arg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
command := exec.Command(cmd.Options.Shell, "-c", sourceCommand.String()+cmd.Options.Command+commandOptions.String())
|
||||||
|
command.SysProcAttr = &unix.SysProcAttr{Setsid: true}
|
||||||
|
command.Dir = cmd.Options.Cwd
|
||||||
|
|
||||||
|
for key, value := range cmd.Options.Env {
|
||||||
|
command.Env = append(command.Env, fmt.Sprintf("%s=%s", key, value))
|
||||||
|
}
|
||||||
|
|
||||||
|
var signalChannel chan os.Signal
|
||||||
|
signalChannel = make(chan os.Signal, 1)
|
||||||
|
signal.Notify(signalChannel, unix.SIGINT, unix.SIGTERM)
|
||||||
|
|
||||||
|
if len(cmd.handlers) != 0 {
|
||||||
|
var err error
|
||||||
|
cmd.stdout, err = command.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.stdin, err = command.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.stderr, err = command.StderrPipe()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := command.Start(); err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) {
|
||||||
|
if exitErr.ExitCode() == 127 {
|
||||||
|
return ErrCommandNotFound
|
||||||
|
} else if _, ok := cmd.Options.CustomErrors[int8(exitErr.ExitCode())]; ok {
|
||||||
|
return cmd.Options.CustomErrors[int8(exitErr.ExitCode())]
|
||||||
|
} else {
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningCmd.Error(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(cmd.handlers) != 0 {
|
||||||
|
cmd.wg.Add(2)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer cmd.wg.Done()
|
||||||
|
scanner := bufio.NewScanner(cmd.stderr)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if h, ok := cmd.handlers[EventOutput]; ok {
|
||||||
|
if err := h.(func(data EventOutputData) error)(EventOutputData{
|
||||||
|
Output: line,
|
||||||
|
CmdOptions: cmd.Options,
|
||||||
|
}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer cmd.wg.Done()
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(cmd.stdout)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if h, ok := cmd.handlers[EventOutput]; ok {
|
||||||
|
if err := h.(func(data EventOutputData) error)(EventOutputData{
|
||||||
|
Output: line,
|
||||||
|
CmdOptions: cmd.Options,
|
||||||
|
}); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.wg.Add(1)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer cmd.wg.Done()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case _, ok := <-signalChannel:
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := unix.Kill(-command.Process.Pid, syscall.SIGINT); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var exitInfo *EventExitData
|
||||||
|
|
||||||
|
if _, ok := cmd.handlers[EventExit]; ok {
|
||||||
|
exitInfo = &EventExitData{
|
||||||
|
HasSucceeded: true,
|
||||||
|
CmdOptions: cmd.Options,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := command.Wait(); err != nil {
|
||||||
|
var exitErr *exec.ExitError
|
||||||
|
if errors.As(err, &exitErr) && exitErr.String() != "signal: interrupt" {
|
||||||
|
if exitErr.ExitCode() == 127 {
|
||||||
|
return ErrCommandNotFound
|
||||||
|
} else if _, ok := cmd.Options.CustomErrors[int8(exitErr.ExitCode())]; ok {
|
||||||
|
if h, ok := cmd.handlers[EventExit]; ok {
|
||||||
|
if exitInfo == nil {
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningCmd.Error(), err)
|
||||||
|
}
|
||||||
|
exitInfo.HasSucceeded = false
|
||||||
|
exitInfo.ExitCode = exitErr.ExitCode()
|
||||||
|
var stdoutData bytes.Buffer
|
||||||
|
if _, err := io.Copy(&stdoutData, cmd.stdout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
exitInfo.Error = stdoutData.String()
|
||||||
|
err := h.(func(data EventExitData) error)(*exitInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningEvt.Error(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cmd.Options.CustomErrors[int8(exitErr.ExitCode())]
|
||||||
|
} else {
|
||||||
|
if h, ok := cmd.handlers[EventExit]; ok {
|
||||||
|
if exitInfo == nil {
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningEvt.Error(), err)
|
||||||
|
}
|
||||||
|
exitInfo.HasSucceeded = false
|
||||||
|
exitInfo.ExitCode = exitErr.ExitCode()
|
||||||
|
var stdoutData bytes.Buffer
|
||||||
|
if _, err := io.Copy(&stdoutData, cmd.stdout); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
exitInfo.Error = stdoutData.String()
|
||||||
|
err := h.(func(data EventExitData) error)(*exitInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningEvt.Error(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningCmd.Error(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if h, ok := cmd.handlers[EventExit]; ok {
|
||||||
|
if exitInfo == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
exitInfo.ExitCode = 0
|
||||||
|
err := h.(func(data EventExitData) error)(*exitInfo)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", ErrRunningEvt.Error(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
close(signalChannel)
|
||||||
|
signal.Stop(signalChannel)
|
||||||
|
cmd.wg.Wait()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package linux
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
cmd2 "git.eggactyl.cloud/Eggactyl/shell/cmd"
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
|
@ -11,11 +12,26 @@ import (
|
||||||
|
|
||||||
func (cmd *LinuxCommand) isCommandExecutable(command string) (bool, error) {
|
func (cmd *LinuxCommand) isCommandExecutable(command string) (bool, error) {
|
||||||
|
|
||||||
|
whichOut, err := cmd2.Which(command, cmd2.BasicOptions{
|
||||||
|
Env: cmd.Options.Env,
|
||||||
|
Sources: cmd.Options.Sources,
|
||||||
|
Cwd: cmd.Options.Cwd,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, cmd2.ErrNotFound) {
|
||||||
if _, err := os.Stat(command); errors.Is(err, fs.ErrNotExist) {
|
if _, err := os.Stat(command); errors.Is(err, fs.ErrNotExist) {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := unix.Access(command, unix.X_OK); err != nil {
|
if len(whichOut) == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Access(whichOut, unix.X_OK); err != nil {
|
||||||
if err == unix.EACCES {
|
if err == unix.EACCES {
|
||||||
return false, nil
|
return false, nil
|
||||||
} else {
|
} else {
|
||||||
|
|
177
main.go
177
main.go
|
@ -1,177 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io/fs"
|
|
||||||
"os"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
|
||||||
)
|
|
||||||
|
|
||||||
var LinuxType string
|
|
||||||
|
|
||||||
var ErrCommandDoesNotExist = errors.New("command Doesn't Exist")
|
|
||||||
var ErrSourceDoesNotExist = errors.New("source Doesn't Exist")
|
|
||||||
|
|
||||||
func RunCommand(command string, args ...string) error {
|
|
||||||
|
|
||||||
if !DoesCommandExist(command) {
|
|
||||||
return ErrCommandDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
|
|
||||||
var mainCommand string
|
|
||||||
|
|
||||||
mainCommand = "/bin/bash"
|
|
||||||
|
|
||||||
bashCommand := exec.Command(mainCommand, "-c", command)
|
|
||||||
bashCommand.Args = append(bashCommand.Args, args...)
|
|
||||||
bashCommand.Stderr = &stderr
|
|
||||||
|
|
||||||
if err := bashCommand.Start(); err != nil {
|
|
||||||
return errors.New(stderr.String() + " " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bashCommand.Wait(); err != nil {
|
|
||||||
return errors.New(stderr.String() + " " + err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func RunCommandWithSource(source string, command string, args ...string) error {
|
|
||||||
|
|
||||||
if !DoesSourceExist(source) {
|
|
||||||
return ErrSourceDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
if !DoesCommandExistWithSource(source, command) {
|
|
||||||
return ErrCommandDoesNotExist
|
|
||||||
}
|
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
|
|
||||||
var mainCommand string
|
|
||||||
|
|
||||||
mainCommand = "/bin/bash"
|
|
||||||
|
|
||||||
bashCommand := exec.Command(mainCommand, "-c", fmt.Sprintf("source %s; %s", source, command))
|
|
||||||
bashCommand.Args = append(bashCommand.Args, args...)
|
|
||||||
bashCommand.Stderr = &stderr
|
|
||||||
|
|
||||||
if err := bashCommand.Start(); err != nil {
|
|
||||||
return errors.New(stderr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bashCommand.Wait(); err != nil {
|
|
||||||
return errors.New(stderr.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func DoesCommandExist(command string) bool {
|
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
|
|
||||||
var mainCommand string
|
|
||||||
|
|
||||||
mainCommand = "/bin/bash"
|
|
||||||
|
|
||||||
bashCommand := exec.Command(mainCommand, "-c", fmt.Sprintf("command -v %s", command))
|
|
||||||
bashCommand.Stderr = &stderr
|
|
||||||
|
|
||||||
if err := bashCommand.Start(); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "1") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bashCommand.Wait(); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "1") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func DoesSourceExist(source string) bool {
|
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
|
|
||||||
var mainCommand string
|
|
||||||
|
|
||||||
mainCommand = "/bin/bash"
|
|
||||||
|
|
||||||
bashCommand := exec.Command(mainCommand, "-c", fmt.Sprintf("source %s", source))
|
|
||||||
bashCommand.Stderr = &stderr
|
|
||||||
|
|
||||||
if err := bashCommand.Start(); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "1") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bashCommand.Wait(); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "1") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func DoesCommandExistWithSource(source string, command string) bool {
|
|
||||||
|
|
||||||
if sourceCheck := DoesSourceExist(source); !sourceCheck {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
|
|
||||||
var mainCommand string
|
|
||||||
|
|
||||||
mainCommand = "/bin/bash"
|
|
||||||
|
|
||||||
bashCommand := exec.Command(mainCommand, "-c", fmt.Sprintf("source %s && command -v %s", source, command))
|
|
||||||
bashCommand.Stderr = &stderr
|
|
||||||
|
|
||||||
if err := bashCommand.Start(); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "1") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := bashCommand.Wait(); err != nil {
|
|
||||||
if strings.Contains(err.Error(), "1") {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func CanExecute(script string) bool {
|
|
||||||
|
|
||||||
if _, err := os.Stat(script); errors.Is(err, fs.ErrNotExist) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := unix.Access(script, unix.X_OK); err != nil {
|
|
||||||
return err == unix.EACCES
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in a new issue