From b226effff01993e00fe05d96338a5d9db590ce8e Mon Sep 17 00:00:00 2001 From: Ian Adam Naval Date: Tue, 16 Sep 2014 20:51:52 -0400 Subject: [PATCH 1/6] Add free and ls to Makefile --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index f09e56f..1669773 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ COVER_DIR=cover # Package lists TOPLEVEL_PKG := jsh -CMD_LIST := jsh/ps +CMD_LIST := jsh/ps jsh/free jsh/ls # List building ALL_LIST = $(TOPLEVEL_PKG) $(CMD_LIST) From 1d57896123a08265750d7ec06d9005b37d9ada40 Mon Sep 17 00:00:00 2001 From: Ian Adam Naval Date: Tue, 16 Sep 2014 20:52:57 -0400 Subject: [PATCH 2/6] gofmt --- common.go | 3 +- free.go | 16 ++--- free/main.go | 186 +++++++++++++++++++++++++-------------------------- ls/main.go | 123 +++++++++++++++++----------------- ps/main.go | 2 +- utils.go | 4 +- 6 files changed, 167 insertions(+), 167 deletions(-) diff --git a/common.go b/common.go index 9b7f21b..54482de 100644 --- a/common.go +++ b/common.go @@ -13,8 +13,9 @@ type JshOutput struct { // Size prefixes as integers, using binary representation type Unit int + const ( - B Unit = 2 ^ 0 + B Unit = 2 ^ 0 KB Unit = 2 ^ 10 MB Unit = 2 ^ 20 GB Unit = 2 ^ 30 diff --git a/free.go b/free.go index 69a5a49..4760d7f 100644 --- a/free.go +++ b/free.go @@ -1,8 +1,8 @@ -/* File for free-related structs and methods */ - -package jsh - -type MemStat struct { - Stat int - Units Unit -} +/* File for free-related structs and methods */ + +package jsh + +type MemStat struct { + Stat int + Units Unit +} diff --git a/free/main.go b/free/main.go index b84ccd8..313310c 100644 --- a/free/main.go +++ b/free/main.go @@ -1,93 +1,93 @@ -package main - -import ( - "bufio" - "errors" - "flag" - "fmt" - "jsh" - "regexp" - "os" - "strconv" -) - -func convertUnit(stringUnit string) (jsh.Unit, error) { - switch stringUnit { - case "B": - return jsh.B, nil - case "kB": - return jsh.KB, nil - case "mB": - return jsh.MB, nil - case "gB": - return jsh.GB, nil - case "tB": - return jsh.TB, nil - default: - return 0, errors.New(fmt.Sprintln("Unknown unit %s", stringUnit)) - } -} - -func parseLine(line string) (string, jsh.MemStat, error) { - // Recognizes a alphanumeric or () word, the : character, whitespace, the number we're looking for, - // more whitespace, and possibly the unit - lineRegex := regexp.MustCompile("(?P^[\\w()]+):\\s+(?P\\d+)(\\s+)?(?P\\w+)?") - - // Parse the line, and construct a map of the valid matches - parsedLine := lineRegex.FindStringSubmatch(line) - names := lineRegex.SubexpNames() - matchedVals := map[string]string{} - for i, n := range parsedLine { - matchedVals[names[i]] = n - } - - key := matchedVals["key"] - val, err := strconv.Atoi(matchedVals["val"]) - if err != nil { - return "", jsh.MemStat{}, err - } - unit, err := convertUnit(matchedVals["unit"]) - if err != nil { - return "", jsh.MemStat{}, err - } - return key, jsh.MemStat{val, unit}, nil -} - -func parseMemInfo() jsh.JshOutput { - file, err := os.Open("/proc/meminfo") - if err != nil { - return jsh.JshOutput{[]string{}, []error{err}} - } - defer file.Close() - - scanner := bufio.NewScanner(file) - memInfo := make(map[string]jsh.MemStat) - errors := []error{} - // Read in each line of the meminfo file, and place it in the map - for scanner.Scan() { - key, val, err := parseLine(scanner.Text()) - if err != nil { - errors = append(errors, err) - } - memInfo[key] = val - } - - finalOut := jsh.JshOutput{memInfo, errors} - return finalOut -} - -func runJsonMode() { - output := parseMemInfo() - fmt.Println("%s", *output.ToJson()) -} - -func main() { - jsonModePtr := flag.Bool("json", false, "whether to use json mode for output") - flag.Parse() - - if !*jsonModePtr { - fmt.Printf("%s", jsh.Fallback("/usr/bin/free")) - } else { - runJsonMode() - } -} +package main + +import ( + "bufio" + "errors" + "flag" + "fmt" + "jsh" + "os" + "regexp" + "strconv" +) + +func convertUnit(stringUnit string) (jsh.Unit, error) { + switch stringUnit { + case "B": + return jsh.B, nil + case "kB": + return jsh.KB, nil + case "mB": + return jsh.MB, nil + case "gB": + return jsh.GB, nil + case "tB": + return jsh.TB, nil + default: + return 0, errors.New(fmt.Sprintln("Unknown unit %s", stringUnit)) + } +} + +func parseLine(line string) (string, jsh.MemStat, error) { + // Recognizes a alphanumeric or () word, the : character, whitespace, the number we're looking for, + // more whitespace, and possibly the unit + lineRegex := regexp.MustCompile("(?P^[\\w()]+):\\s+(?P\\d+)(\\s+)?(?P\\w+)?") + + // Parse the line, and construct a map of the valid matches + parsedLine := lineRegex.FindStringSubmatch(line) + names := lineRegex.SubexpNames() + matchedVals := map[string]string{} + for i, n := range parsedLine { + matchedVals[names[i]] = n + } + + key := matchedVals["key"] + val, err := strconv.Atoi(matchedVals["val"]) + if err != nil { + return "", jsh.MemStat{}, err + } + unit, err := convertUnit(matchedVals["unit"]) + if err != nil { + return "", jsh.MemStat{}, err + } + return key, jsh.MemStat{val, unit}, nil +} + +func parseMemInfo() jsh.JshOutput { + file, err := os.Open("/proc/meminfo") + if err != nil { + return jsh.JshOutput{[]string{}, []error{err}} + } + defer file.Close() + + scanner := bufio.NewScanner(file) + memInfo := make(map[string]jsh.MemStat) + errors := []error{} + // Read in each line of the meminfo file, and place it in the map + for scanner.Scan() { + key, val, err := parseLine(scanner.Text()) + if err != nil { + errors = append(errors, err) + } + memInfo[key] = val + } + + finalOut := jsh.JshOutput{memInfo, errors} + return finalOut +} + +func runJsonMode() { + output := parseMemInfo() + fmt.Println("%s", *output.ToJson()) +} + +func main() { + jsonModePtr := flag.Bool("json", false, "whether to use json mode for output") + flag.Parse() + + if !*jsonModePtr { + fmt.Printf("%s", jsh.Fallback("/usr/bin/free")) + } else { + runJsonMode() + } +} diff --git a/ls/main.go b/ls/main.go index 42cadd1..392f364 100644 --- a/ls/main.go +++ b/ls/main.go @@ -1,76 +1,75 @@ package main import ( - "io/ioutil" - "fmt" - "flag" - "log" - "syscall" - "strconv" + "flag" + "fmt" + "io/ioutil" + "log" + "strconv" + "syscall" ) - -func get_fileinfo(f string, size bool, mode bool, inode bool) string{ - var stat syscall.Stat_t - var ret string - ret = "{\"name\":\"" + f + "\"" - if err := syscall.Stat(f, &stat); err != nil { - log.Fatal(err) - } - if(size){ - ret = ret + ", \"size\":" + strconv.FormatInt(stat.Size,10) - } - if(mode){ - ret = ret + ", \"mode\":" + strconv.Itoa(int(stat.Mode)) - } - if(inode){ - ret = ret + ", \"inode\":" + strconv.FormatUint(stat.Ino,10) - } - ret = ret + "}" - return ret +func get_fileinfo(f string, size bool, mode bool, inode bool) string { + var stat syscall.Stat_t + var ret string + ret = "{\"name\":\"" + f + "\"" + if err := syscall.Stat(f, &stat); err != nil { + log.Fatal(err) + } + if size { + ret = ret + ", \"size\":" + strconv.FormatInt(stat.Size, 10) + } + if mode { + ret = ret + ", \"mode\":" + strconv.Itoa(int(stat.Mode)) + } + if inode { + ret = ret + ", \"inode\":" + strconv.FormatUint(stat.Ino, 10) + } + ret = ret + "}" + return ret } func main() { - // here be the ls flags + // here be the ls flags - var a_flag bool // all files, even ones starting with . - var mode_flag bool // flags - var inode_flag bool // inode - var size_flag bool // size - var first = true + var a_flag bool // all files, even ones starting with . + var mode_flag bool // flags + var inode_flag bool // inode + var size_flag bool // size + var first = true - flag.BoolVar(&a_flag, "a", false, "lists all files in directory, even hidden ones") - flag.BoolVar(&mode_flag, "f", false, "include flags for file") - flag.BoolVar(&inode_flag, "i", false, "include flags for file") - flag.BoolVar(&size_flag, "s", false, "include flags for file") - // end ls flag + flag.BoolVar(&a_flag, "a", false, "lists all files in directory, even hidden ones") + flag.BoolVar(&mode_flag, "f", false, "include flags for file") + flag.BoolVar(&inode_flag, "i", false, "include flags for file") + flag.BoolVar(&size_flag, "s", false, "include flags for file") + // end ls flag - flag.Parse() - root := "."//flag.Arg(0) - dir,_ := ioutil.ReadDir(root) + flag.Parse() + root := "." //flag.Arg(0) + dir, _ := ioutil.ReadDir(root) - fmt.Printf("[\n") - - if(!a_flag){ - for _,entry := range dir{ - if(entry.Name()[0]!='.'){ - if(!first){ - fmt.Printf(",") - }else{ - first = false + fmt.Printf("[\n") + + if !a_flag { + for _, entry := range dir { + if entry.Name()[0] != '.' { + if !first { + fmt.Printf(",") + } else { + first = false + } + fmt.Printf("%s\n", get_fileinfo(entry.Name(), size_flag, mode_flag, inode_flag)) + } + } + } else { + for _, entry := range dir { + if !first { + fmt.Printf(",") + } else { + first = false + } + fmt.Printf("%s\n", get_fileinfo(entry.Name(), size_flag, mode_flag, inode_flag)) + } } - fmt.Printf("%s\n", get_fileinfo(entry.Name(), size_flag, mode_flag, inode_flag)) - } - } - }else{ - for _,entry := range dir{ - if(!first){ - fmt.Printf(",") - }else{ - first = false - } - fmt.Printf("%s\n", get_fileinfo(entry.Name(), size_flag, mode_flag, inode_flag)) - } - } - fmt.Printf("]\n") + fmt.Printf("]\n") } diff --git a/ps/main.go b/ps/main.go index 8d8d181..fd047c7 100644 --- a/ps/main.go +++ b/ps/main.go @@ -25,7 +25,7 @@ func PsOutputToProcesses(out string) *[]jsh.Process { func runJsonMode() { // Run procps-ng "ps" with full output - psOut := string(*jsh.FallbackWithArgs("/usr/bin/ps", []string{"auxww"})) + psOut := string(*jsh.FallbackWithArgs("/usr/bin/ps", []string{"auxww"})) processesPtr := PsOutputToProcesses(psOut) finalOut := jsh.JshOutput{*processesPtr, []string{}} diff --git a/utils.go b/utils.go index 87d21f9..7f6561e 100644 --- a/utils.go +++ b/utils.go @@ -2,9 +2,9 @@ package jsh import ( "math" - "unicode" "os" "os/exec" + "unicode" ) // FieldsN slices s into substrings after each instance of a whitespace @@ -56,7 +56,7 @@ func FallbackWithArgs(program string, args []string) *[]byte { if err != nil { panic(err) } - return &out + return &out } func Fallback(program string) *[]byte { From fb8165fa805d3b459bf2e9f3ce01390a9afff520 Mon Sep 17 00:00:00 2001 From: Ian Adam Naval Date: Tue, 16 Sep 2014 21:43:43 -0400 Subject: [PATCH 3/6] Make ps follow new standard --- common.go | 29 ++++++++++++++++++++++++++--- free/main.go | 6 +++--- ps/main.go | 11 ++++++++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/common.go b/common.go index 54482de..964addb 100644 --- a/common.go +++ b/common.go @@ -4,9 +4,10 @@ package jsh import ( "encoding/json" + "fmt" ) -type JshOutput struct { +type JshFrame struct { StdOut interface{} StdErr interface{} } @@ -22,8 +23,8 @@ const ( TB Unit = 2 ^ 40 ) -// Converts a Jshoutput into a JSON string -func (j JshOutput) ToJson() *string { +// Converts a JshFrame into a JSON string +func (j JshFrame) ToJson() *string { jsonOut, err := json.Marshal(j) if err != nil { panic(err) @@ -31,3 +32,25 @@ func (j JshOutput) ToJson() *string { jsonString := string(jsonOut) return &jsonString } + +// goroutine for outputing frames. Pass it a channel of pointers to JshFrames, +// and it will send "true" to the done channel once you close the queue channel. +func OutputFrames(queue chan *JshFrame, done chan bool) { + fmt.Printf("[") + isFirst := true + for { + frame, more := <-queue + if more { + if !isFirst { + fmt.Printf(",") + } else { + isFirst = false + } + fmt.Printf(*frame.ToJson()) + } else { + fmt.Printf("]\n") + done <- true + return + } + } +} diff --git a/free/main.go b/free/main.go index 313310c..add8c89 100644 --- a/free/main.go +++ b/free/main.go @@ -53,10 +53,10 @@ func parseLine(line string) (string, jsh.MemStat, error) { return key, jsh.MemStat{val, unit}, nil } -func parseMemInfo() jsh.JshOutput { +func parseMemInfo() jsh.JshFrame { file, err := os.Open("/proc/meminfo") if err != nil { - return jsh.JshOutput{[]string{}, []error{err}} + return jsh.JshFrame{[]string{}, []error{err}} } defer file.Close() @@ -72,7 +72,7 @@ func parseMemInfo() jsh.JshOutput { memInfo[key] = val } - finalOut := jsh.JshOutput{memInfo, errors} + finalOut := jsh.JshFrame{memInfo, errors} return finalOut } diff --git a/ps/main.go b/ps/main.go index fd047c7..9df6a7b 100644 --- a/ps/main.go +++ b/ps/main.go @@ -26,10 +26,15 @@ func PsOutputToProcesses(out string) *[]jsh.Process { func runJsonMode() { // Run procps-ng "ps" with full output psOut := string(*jsh.FallbackWithArgs("/usr/bin/ps", []string{"auxww"})) - processesPtr := PsOutputToProcesses(psOut) - finalOut := jsh.JshOutput{*processesPtr, []string{}} - fmt.Printf("%s", *finalOut.ToJson()) + frame := jsh.JshFrame{*processesPtr, []string{}} + + queue := make(chan *jsh.JshFrame) + done := make(chan bool) + go jsh.OutputFrames(queue, done) + queue <- &frame + close(queue) + <-done } func main() { From d621f8d76526a01a1675ffc17731225f05d05c77 Mon Sep 17 00:00:00 2001 From: Ian Adam Naval Date: Tue, 16 Sep 2014 21:55:37 -0400 Subject: [PATCH 4/6] Add blank case for convertUnit Assumes that it's in bytes. On my system (Arch Linux), values of 0 have no unit printed next to them. --- free/main.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/free/main.go b/free/main.go index add8c89..66c3e47 100644 --- a/free/main.go +++ b/free/main.go @@ -23,8 +23,10 @@ func convertUnit(stringUnit string) (jsh.Unit, error) { return jsh.GB, nil case "tB": return jsh.TB, nil + case "": + return jsh.B, nil default: - return 0, errors.New(fmt.Sprintln("Unknown unit %s", stringUnit)) + return 0, errors.New(fmt.Sprintf("Unknown unit: %s\n", stringUnit)) } } From dc064e8ea75dffbc7e8b8d419bc09cf660e4d6ec Mon Sep 17 00:00:00 2001 From: Ian Adam Naval Date: Tue, 16 Sep 2014 22:00:50 -0400 Subject: [PATCH 5/6] Make free standards compliant --- free/main.go | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/free/main.go b/free/main.go index 66c3e47..0849aef 100644 --- a/free/main.go +++ b/free/main.go @@ -74,13 +74,20 @@ func parseMemInfo() jsh.JshFrame { memInfo[key] = val } - finalOut := jsh.JshFrame{memInfo, errors} + // Wrap with array + stdOut := []map[string]jsh.MemStat{memInfo} + finalOut := jsh.JshFrame{stdOut, errors} return finalOut } func runJsonMode() { output := parseMemInfo() - fmt.Println("%s", *output.ToJson()) + queue := make(chan *jsh.JshFrame) + done := make(chan bool) + go jsh.OutputFrames(queue, done) + queue <- &output + close(queue) + <-done } func main() { From 58009824b627b39d542db1f948ce80212cbbc8cf Mon Sep 17 00:00:00 2001 From: Ian Adam Naval Date: Tue, 16 Sep 2014 22:08:12 -0400 Subject: [PATCH 6/6] Make ls standards compliant Except we aren't using the standard JshFrame struct. We should probably have a meeting to discuss how we're going to organize that going forward. --- ls/main.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ls/main.go b/ls/main.go index 392f364..954bd0e 100644 --- a/ls/main.go +++ b/ls/main.go @@ -12,7 +12,7 @@ import ( func get_fileinfo(f string, size bool, mode bool, inode bool) string { var stat syscall.Stat_t var ret string - ret = "{\"name\":\"" + f + "\"" + ret = "{\"files\": [{\"name\":\"" + f + "\"" if err := syscall.Stat(f, &stat); err != nil { log.Fatal(err) } @@ -25,7 +25,7 @@ func get_fileinfo(f string, size bool, mode bool, inode bool) string { if inode { ret = ret + ", \"inode\":" + strconv.FormatUint(stat.Ino, 10) } - ret = ret + "}" + ret = ret + "}]}" return ret } @@ -48,7 +48,7 @@ func main() { root := "." //flag.Arg(0) dir, _ := ioutil.ReadDir(root) - fmt.Printf("[\n") + fmt.Printf("[{\"StdOut\": [\n") if !a_flag { for _, entry := range dir { @@ -71,5 +71,5 @@ func main() { fmt.Printf("%s\n", get_fileinfo(entry.Name(), size_flag, mode_flag, inode_flag)) } } - fmt.Printf("]\n") + fmt.Printf("], \"StdErr\": []}]\n") }