initial
This commit is contained in:
commit
15eeadf5d3
22
command/cat/cat.go
Normal file
22
command/cat/cat.go
Normal file
@ -0,0 +1,22 @@
|
||||
package cat
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func Cat(in input_parser.Input, env *environment.Env) {
|
||||
file := filepath.Join(env.Path, in.Args)
|
||||
bytea_str, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
fmt.Print(fmt.Sprintf("Error opening file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
fmt.Print(string(bytea_str))
|
||||
|
||||
}
|
||||
|
||||
|
||||
34
command/cd/cd.go
Normal file
34
command/cd/cd.go
Normal file
@ -0,0 +1,34 @@
|
||||
package cd
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func Cd(in input_parser.Input, env *environment.Env) {
|
||||
var new_path string
|
||||
if in.Args == "" {
|
||||
new_path = env.Env["HOME"]
|
||||
} else {
|
||||
if in.Args[0] == '/' {
|
||||
new_path = in.Args
|
||||
} else {
|
||||
new_path = filepath.Join(env.Path, in.Args)
|
||||
}
|
||||
}
|
||||
file, err := os.Stat(new_path)
|
||||
if err != nil {
|
||||
fmt.Print(fmt.Sprintf("Error changing directory %s", err.Error()))
|
||||
return
|
||||
}
|
||||
if !file.IsDir() {
|
||||
fmt.Print("New path is not a directory")
|
||||
return
|
||||
}
|
||||
env.Path = new_path
|
||||
}
|
||||
|
||||
|
||||
89
command/command.go
Normal file
89
command/command.go
Normal file
@ -0,0 +1,89 @@
|
||||
package command
|
||||
|
||||
import (
|
||||
"bbash/command/cat"
|
||||
"bbash/command/cd"
|
||||
"bbash/command/cp"
|
||||
"bbash/command/echo"
|
||||
"bbash/command/head"
|
||||
"bbash/command/help"
|
||||
"bbash/command/ls"
|
||||
"bbash/command/man"
|
||||
"bbash/command/mv"
|
||||
"bbash/command/pwd"
|
||||
"bbash/command/rm"
|
||||
"bbash/command/touch"
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
var path_command []string
|
||||
|
||||
func Init(env *environment.Env) {
|
||||
init_path(env)
|
||||
|
||||
}
|
||||
|
||||
func Run_command(in input_parser.Input, env *environment.Env) {
|
||||
switch in.Instruction {
|
||||
case "pwd": pwd.Pwd(in, env)
|
||||
case "echo": echo.Echo(in, env)
|
||||
case "ls": ls.Ls(in, env)
|
||||
case "cd": cd.Cd(in, env)
|
||||
case "man": man.Man(in, env)
|
||||
case "cat": cat.Cat(in, env)
|
||||
case "head": head.Head(in, env)
|
||||
case "touch": touch.Touch(in, env)
|
||||
case "rm": rm.Rm(in, env)
|
||||
case "cp": cp.Cp(in, env)
|
||||
case "mv": mv.Mv(in,env)
|
||||
case "help": help.Help(in,env)
|
||||
default:
|
||||
if !run_by_path(in, env) {
|
||||
fmt.Println(fmt.Sprintf("No such command! (%s)", in.Instruction))
|
||||
}
|
||||
}
|
||||
}
|
||||
// Returns if anything was run or not
|
||||
func run_by_path(in input_parser.Input, env *environment.Env) bool {
|
||||
fmt.Print(env.Env["PATH"])
|
||||
return false
|
||||
}
|
||||
|
||||
func init_path(env *environment.Env) {
|
||||
path := strings.Split(env.Env["PATH"], ":")
|
||||
for _, a_path := range path {
|
||||
recursive_executable_finder(a_path)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
func recursive_executable_finder(path string) {
|
||||
dir, err := os.ReadDir(path)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, f := range dir {
|
||||
if f.IsDir() {
|
||||
recursive_executable_finder(f.Name())
|
||||
continue
|
||||
}
|
||||
if !is_executable(f.Name()) {
|
||||
println("not exec")
|
||||
continue
|
||||
}
|
||||
println(f.Name())
|
||||
path_command = append(path_command, f.Name())
|
||||
|
||||
}
|
||||
}
|
||||
func is_executable( name string) bool {
|
||||
return true
|
||||
stat, _ := os.Stat(name)
|
||||
mode := stat.Mode()
|
||||
return mode&(1<<0) != 0 || // Others' execute bit
|
||||
mode&(1<<3) != 0 || // Group's execute bit
|
||||
mode.Perm()&(1<<6) != 0 // Owner's execute bit
|
||||
}
|
||||
27
command/command_test.go
Normal file
27
command/command_test.go
Normal file
@ -0,0 +1,27 @@
|
||||
package command
|
||||
|
||||
import(
|
||||
"io/fs"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_is_executable(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // description of this test case
|
||||
// Named input parameters for target function.
|
||||
mode fs.FileMode
|
||||
want bool
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := is_executable(tt.mode)
|
||||
// TODO: update the condition below to compare got with tt.want.
|
||||
if true {
|
||||
t.Errorf("is_executable() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
36
command/cp/cp.go
Normal file
36
command/cp/cp.go
Normal file
@ -0,0 +1,36 @@
|
||||
package cp
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Cp(in input_parser.Input, env *environment.Env) {
|
||||
args := strings.SplitN(in.Args, " ", 2)
|
||||
if len(args) != 2 {
|
||||
fmt.Print("No right amount of args")
|
||||
return
|
||||
}
|
||||
file_path_source := filepath.Join(env.Path, args[0])
|
||||
file_path_dest := filepath.Join(env.Path, args[1])
|
||||
source, err := os.ReadFile(file_path_source)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error opening file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
dest, err := os.Create(file_path_dest)
|
||||
defer dest.Close()
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error opening file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
dest.Write(source)
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
12
command/echo/echo.go
Normal file
12
command/echo/echo.go
Normal file
@ -0,0 +1,12 @@
|
||||
package echo
|
||||
|
||||
import (
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"bbash/environment"
|
||||
)
|
||||
|
||||
func Echo(in input_parser.Input, _ *environment.Env) {
|
||||
fmt.Print(in.Args)
|
||||
}
|
||||
|
||||
50
command/head/head.go
Normal file
50
command/head/head.go
Normal file
@ -0,0 +1,50 @@
|
||||
package head
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Head(in input_parser.Input, env *environment.Env) {
|
||||
args := strings.SplitN(in.Args, " ", 2)
|
||||
var file_path string
|
||||
var lines int
|
||||
if len(args) >= 1 {
|
||||
file_path = strings.TrimSpace(args[0])
|
||||
lines = 10
|
||||
} else {
|
||||
fmt.Print(fmt.Sprintf("No arguments provided"))
|
||||
return
|
||||
}
|
||||
if len(args) == 2 {
|
||||
lines1, err := strconv.Atoi(strings.TrimSpace(args[1]))
|
||||
lines = lines1
|
||||
if err != nil {
|
||||
fmt.Print(fmt.Sprintf("Second argument must be a integer"))
|
||||
return
|
||||
}
|
||||
}
|
||||
file, err := os.Open(file_path)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error opening file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
scanner := bufio.NewScanner(file)
|
||||
for i := 0; i < lines-1; i++ {
|
||||
if(!scanner.Scan()) {
|
||||
return
|
||||
}
|
||||
fmt.Println(scanner.Text())
|
||||
}
|
||||
scanner.Scan()
|
||||
fmt.Print(scanner.Text())
|
||||
}
|
||||
|
||||
|
||||
|
||||
28
command/help/help.go
Normal file
28
command/help/help.go
Normal file
@ -0,0 +1,28 @@
|
||||
package help
|
||||
|
||||
import (
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"bbash/environment"
|
||||
)
|
||||
|
||||
func Help(in input_parser.Input, _ *environment.Env) {
|
||||
fmt.Print(`
|
||||
Welcome to the bornagain bornagain shell!
|
||||
The options are:
|
||||
pwd: Output current working directory
|
||||
echo: Echoes the input argument
|
||||
ls: List Sources in the current working directory
|
||||
cd: Change to directory given in the argument
|
||||
man: Manual for the terminal options
|
||||
cat: Outputs the contents of the given file
|
||||
head: Outputs first lines of a given file. 10 if non provided. Argument <file> <number of lines>
|
||||
touch: Creates the given file
|
||||
rm: Removes the given file
|
||||
cp: Copies the given file. Argument: <source> <destination>
|
||||
mv: Moves a given file. Argument: <source> <destination>
|
||||
help: Prints this message
|
||||
`)
|
||||
}
|
||||
|
||||
|
||||
21
command/ls/ls.go
Normal file
21
command/ls/ls.go
Normal file
@ -0,0 +1,21 @@
|
||||
package ls
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Ls(in input_parser.Input, env *environment.Env) {
|
||||
fs, err := os.ReadDir(env.Path)
|
||||
if err != nil {
|
||||
fmt.Print(fmt.Sprintf("Error opening directory %s", env.Path))
|
||||
}
|
||||
for _, f := range fs {
|
||||
fmt.Print(f.Name())
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
37
command/man/man.go
Normal file
37
command/man/man.go
Normal file
@ -0,0 +1,37 @@
|
||||
package man
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func Man(in input_parser.Input, env *environment.Env) {
|
||||
switch in.Instruction {
|
||||
case "pwd":
|
||||
fmt.Print("Output current working directory")
|
||||
case "echo":
|
||||
fmt.Print("Echoes the input argument")
|
||||
case "ls":
|
||||
fmt.Print("List Sources in the current working directory")
|
||||
case "cd":
|
||||
fmt.Print("Change to directory given in the argument")
|
||||
case "man":
|
||||
fmt.Print("Manual for the terminal options")
|
||||
case "cat":
|
||||
fmt.Print("Outputs the contents of the given file")
|
||||
case "head":
|
||||
fmt.Print("Outputs first lines of a given file. 10 if non provided. Argument <file> <number of lines>")
|
||||
case "touch":
|
||||
fmt.Print("Creates the given file")
|
||||
case "rm":
|
||||
fmt.Print("Removes the given file")
|
||||
case "cp":
|
||||
fmt.Print("Copies the given file. Argument: <source> <destination>")
|
||||
case "mv":
|
||||
fmt.Print("Moves a given file. Argument: <source> <destination>")
|
||||
default: fmt.Println(fmt.Sprintf("No such command! (%s)", in.Instruction))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
47
command/mv/mv.go
Normal file
47
command/mv/mv.go
Normal file
@ -0,0 +1,47 @@
|
||||
package mv
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Mv(in input_parser.Input, env *environment.Env) {
|
||||
args := strings.SplitN(in.Args, " ", 2)
|
||||
if len(args) != 2 {
|
||||
fmt.Print("No right amount of args")
|
||||
return
|
||||
}
|
||||
file_path_source := filepath.Join(env.Path, args[0])
|
||||
file_path_dest := filepath.Join(env.Path, args[1])
|
||||
source, err := os.ReadFile(file_path_source)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error opening file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
dest, err := os.Create(file_path_dest)
|
||||
defer dest.Close()
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error opening file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
_, err = dest.Write(source)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error writing destination: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
err = os.Remove(file_path_source)
|
||||
if err != nil {
|
||||
fmt.Println(fmt.Sprintf("Error removing source: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
12
command/pwd/pwd.go
Normal file
12
command/pwd/pwd.go
Normal file
@ -0,0 +1,12 @@
|
||||
package pwd
|
||||
|
||||
|
||||
import (
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"bbash/environment"
|
||||
)
|
||||
|
||||
func Pwd(in input_parser.Input, env *environment.Env) {
|
||||
fmt.Print(env.Path)
|
||||
}
|
||||
31
command/rm/rm.go
Normal file
31
command/rm/rm.go
Normal file
@ -0,0 +1,31 @@
|
||||
package rm
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func Rm(in input_parser.Input, env *environment.Env) {
|
||||
file_path := filepath.Join(env.Path, in.Args)
|
||||
stat, err := os.Stat(file_path)
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Print(fmt.Sprintf("File does not exist"))
|
||||
return
|
||||
}
|
||||
if stat.IsDir() {
|
||||
fmt.Print(fmt.Sprintf("%s Is a folder, not a file!", file_path))
|
||||
return
|
||||
}
|
||||
err = os.Remove(file_path)
|
||||
if err != nil {
|
||||
fmt.Print(fmt.Sprintf("Error removing file or folder: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
27
command/touch/touch.go
Normal file
27
command/touch/touch.go
Normal file
@ -0,0 +1,27 @@
|
||||
package touch
|
||||
|
||||
import (
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func Touch(in input_parser.Input, env *environment.Env) {
|
||||
file_path := filepath.Join(env.Path, in.Args)
|
||||
_, err := os.Stat(file_path)
|
||||
if !os.IsNotExist(err) {
|
||||
fmt.Print(fmt.Sprintf("File alredy exist!"))
|
||||
return
|
||||
}
|
||||
file, err := os.Create(file_path)
|
||||
if err != nil {
|
||||
fmt.Print(fmt.Sprintf("Error creating file: %s", err.Error()))
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
}
|
||||
|
||||
|
||||
|
||||
13
environment/env_test.go
Normal file
13
environment/env_test.go
Normal file
@ -0,0 +1,13 @@
|
||||
package environment
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func TestEnv(t *testing.T) {
|
||||
env := Get_env()
|
||||
fmt.Print("PATH: ")
|
||||
fmt.Println(env.Path)
|
||||
|
||||
}
|
||||
30
environment/environment.go
Normal file
30
environment/environment.go
Normal file
@ -0,0 +1,30 @@
|
||||
package environment
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Env struct {
|
||||
Path string
|
||||
|
||||
Env map[string]string
|
||||
}
|
||||
|
||||
func Get_env() Env {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
env := make(map[string]string)
|
||||
for _, s_env := range os.Environ() {
|
||||
split := strings.Split(s_env, "=")
|
||||
env[split[0]] = split[1]
|
||||
}
|
||||
return Env{
|
||||
Path: pwd,
|
||||
Env: env,
|
||||
}
|
||||
|
||||
}
|
||||
36
input_parser/input_parser.go
Normal file
36
input_parser/input_parser.go
Normal file
@ -0,0 +1,36 @@
|
||||
package input_parser
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"log"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
type Input struct {
|
||||
// The instruction a.k.a first argument
|
||||
Instruction string
|
||||
|
||||
// The args, currently just the string after the instruction
|
||||
Args string
|
||||
}
|
||||
func Parse() Input {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
input, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
log.Fatal(err.Error())
|
||||
}
|
||||
split := strings.SplitN(string(input), " ", 2)
|
||||
instruction := strings.TrimSpace(split[0])
|
||||
var arg string
|
||||
if len(split) == 2 {
|
||||
arg = strings.TrimSpace(split[1])
|
||||
} else {
|
||||
arg = ""
|
||||
}
|
||||
|
||||
return Input {
|
||||
Instruction: instruction,
|
||||
Args: arg,
|
||||
}
|
||||
}
|
||||
|
||||
16
input_parser/test_test.go
Normal file
16
input_parser/test_test.go
Normal file
@ -0,0 +1,16 @@
|
||||
package input_parser
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
Parse("")
|
||||
Parse("hej")
|
||||
got := Parse("echo \" jej asdsa dsa \"")
|
||||
fmt.Println(got.Instruction)
|
||||
fmt.Println(got.Args)
|
||||
|
||||
|
||||
}
|
||||
21
main.go
Normal file
21
main.go
Normal file
@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bbash/command"
|
||||
"bbash/environment"
|
||||
"bbash/input_parser"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
|
||||
func main() {
|
||||
env := environment.Get_env()
|
||||
command.Init(&env)
|
||||
|
||||
for {
|
||||
fmt.Print(fmt.Sprintf("%s > ", env.Path))
|
||||
in_parsed := input_parser.Parse()
|
||||
command.Run_command(in_parsed, &env)
|
||||
fmt.Println()
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user