diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 0d48f9b..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-# IDE
-.vscode
-.idea
-.fleet
-
-# Build Directory
-build
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..d7b24a1
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/shell.iml b/.idea/shell.iml
new file mode 100644
index 0000000..5e764c4
--- /dev/null
+++ b/.idea/shell.iml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/cmd/command.go b/cmd/command.go
deleted file mode 100644
index 24c2920..0000000
--- a/cmd/command.go
+++ /dev/null
@@ -1,28 +0,0 @@
-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
-
-}
diff --git a/cmd/node.go b/cmd/node.go
deleted file mode 100644
index 32bc6f2..0000000
--- a/cmd/node.go
+++ /dev/null
@@ -1,38 +0,0 @@
-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
-
-}
diff --git a/cmd/pip.go b/cmd/pip.go
deleted file mode 100644
index 974b3ee..0000000
--- a/cmd/pip.go
+++ /dev/null
@@ -1,37 +0,0 @@
-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
-
-}
diff --git a/cmd/python.go b/cmd/python.go
deleted file mode 100644
index 2945854..0000000
--- a/cmd/python.go
+++ /dev/null
@@ -1,38 +0,0 @@
-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
-
-}
diff --git a/cmd/which.go b/cmd/which.go
deleted file mode 100644
index 168abdd..0000000
--- a/cmd/which.go
+++ /dev/null
@@ -1,49 +0,0 @@
-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
-
-}
diff --git a/go.mod b/go.mod
index 37646fa..39d0fc5 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,5 @@
module git.shadowhosting.xyz/Eggactyl/shell
-go 1.22.5
+go 1.22.4
require golang.org/x/sys v0.22.0
diff --git a/linux/events.go b/linux/events.go
deleted file mode 100644
index f8168b5..0000000
--- a/linux/events.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package linux
-
-const (
- EventOutput = iota
- EventExit
-)
-
-type EventOutputData struct {
- Output string
- CmdOptions CommandOptions
-}
-
-type EventExitData struct {
- HasSucceeded bool
- ExitCode int
- CmdOptions CommandOptions
-}
diff --git a/linux/interface.go b/linux/interface.go
deleted file mode 100644
index 2e7950c..0000000
--- a/linux/interface.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package linux
-
-import (
- "errors"
- "io"
- "sync"
-)
-
-type LinuxCommand struct {
- Options CommandOptions
- handlers map[int]interface{}
- wg sync.WaitGroup
- stdout io.ReadCloser
- stderr io.ReadCloser
- stdin io.WriteCloser
-}
-
-type CommandOptions struct {
- Env map[string]string
- Sources []string
- Command string
- Args []string
- CustomErrors map[int8]error
- Cwd string
- Shell string
-}
-
-// Errors
-var (
- ErrFetchingCwd = errors.New("error fetching cwd")
- ErrRunningCmd = errors.New("error running command")
- ErrCommandNotFound = errors.New("error command not found")
- ErrCommandNotExecutable = errors.New("error command not executable")
- ErrInvalidHandler = errors.New("invalid handler")
- ErrRunningEvt = errors.New("error running event")
-)
diff --git a/linux/run.go b/linux/run.go
deleted file mode 100644
index ad1c76d..0000000
--- a/linux/run.go
+++ /dev/null
@@ -1,235 +0,0 @@
-package linux
-
-import (
- "bufio"
- "errors"
- "fmt"
- "golang.org/x/sys/unix"
- "os"
- "os/exec"
- "os/signal"
- "strings"
- "syscall"
-)
-
-func NewCommand(options CommandOptions) (*LinuxCommand, error) {
-
- if len(options.Shell) == 0 {
- options.Shell = "/bin/bash"
- }
-
- if len(options.Cwd) == 0 {
- cwd, err := os.Getwd()
- if err != nil {
- return nil, ErrFetchingCwd
- }
- options.Cwd = cwd
- }
-
- return &LinuxCommand{
- Options: options,
- handlers: make(map[int]interface{}),
- }, nil
-
-}
-
-func (cmd *LinuxCommand) AddHandler(handler interface{}) error {
-
- switch h := handler.(type) {
- case func(data EventOutputData) error:
- cmd.handlers[EventOutput] = h
- break
- case func(data EventExitData) error:
- cmd.handlers[EventExit] = h
- default:
- return ErrInvalidHandler
- }
-
- 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()
- 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()
- 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
-
-}
diff --git a/linux/utils.go b/linux/utils.go
deleted file mode 100644
index 5d21199..0000000
--- a/linux/utils.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package linux
-
-import (
- "errors"
- "fmt"
- cmd2 "git.shadowhosting.xyz/Eggactyl/shell/cmd"
- "golang.org/x/sys/unix"
- "io/fs"
- "os"
- "os/exec"
-)
-
-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) {
- return false, err
- }
- } else {
- return false, err
- }
- }
-
- if len(whichOut) == 0 {
- return false, nil
- }
-
- if err := unix.Access(whichOut, unix.X_OK); err != nil {
- if err == unix.EACCES {
- return false, nil
- } else {
- fmt.Println(err)
- return false, err
- }
- }
-
- return true, nil
-
-}
-
-func (cmd *LinuxCommand) doesCommandExist(command string) (bool, error) {
-
- shellCmd := exec.Command(cmd.Options.Shell, "-c", fmt.Sprintf("command -v %s", command))
-
- if err := shellCmd.Start(); err != nil {
- var exitErr *exec.ExitError
- if errors.As(err, &exitErr) {
- if exitErr.ExitCode() == 1 {
- return false, nil
- } else {
- return false, ErrRunningCmd
- }
- }
- }
-
- if err := shellCmd.Wait(); err != nil {
- var exitErr *exec.ExitError
- if errors.As(err, &exitErr) {
- if exitErr.ExitCode() == 1 {
- return false, nil
- } else {
- return false, ErrRunningCmd
- }
- }
- }
-
- return true, nil
-
-}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..31c1b00
--- /dev/null
+++ b/main.go
@@ -0,0 +1,177 @@
+package shell
+
+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
+
+}