blob: cf82ed2c93ea50f381665bc074aed8ad3a3081e9 [file] [log] [blame]
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -07001package main
2
3import (
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -07004 "bytes"
Cosmos Nicolaoub44f2392014-10-28 22:41:49 -07005 "encoding/json"
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -07006 "fmt"
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -07007 "io"
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -07008 "os"
9 "regexp"
10 "strings"
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070011
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070012 "veyron.io/veyron/veyron/lib/modules"
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070013)
14
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070015type builtinCmd func(sh *modules.Shell, state *cmdState, args ...string) (string, error)
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070016
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070017var varRE = regexp.MustCompile("(.*?)=(.*)")
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070018
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070019var builtins = map[string]*struct {
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070020 nargs int // -1 means a variable # of args.
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070021 usage string
22 needsHandle bool
23 fn builtinCmd
24}{
Cosmos Nicolaoub44f2392014-10-28 22:41:49 -070025 "print": {-1, "print <args>...", false, print},
26 "help": {-1, "help", false, nil},
27 "set": {-1, "set <var>=<val>...", false, set},
28 "json_set": {-1, "<var>...", false, json_set},
29 "json_print": {0, "", false, json_print},
30 "splitEP": {-1, "splitEP", false, splitEP},
31 "assert": {2, "val1 val2", false, assert},
32 "read": {-1, "read <handle> [var]", true, read},
33 "eval": {1, "eval <handle>", true, eval},
34 "wait": {1, "wait <handle>", true, wait},
35 "stop": {1, "stop <handle>", true, stop},
36 "stderr": {1, "stderr <handle>", true, stderr},
37 "list": {0, "list", false, list},
38 "quit": {0, "quit", false, quit},
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070039}
40
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070041func init() {
42 builtins["help"].fn = help
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070043}
44
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070045func print(_ *modules.Shell, _ *cmdState, args ...string) (string, error) {
46 r := strings.Join(args, " ")
47 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070048}
49
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070050func splitEP(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
51 ep := strings.TrimLeft(args[0], "/")
52 ep = strings.TrimRight(ep, "/")
53 ep = strings.TrimLeft(ep, "@")
54 ep = strings.TrimRight(ep, "@")
55 parts := strings.Split(ep, "@")
56 sh.SetVar("PN", fmt.Sprintf("%d", len(parts)))
57 for i, p := range parts {
58 sh.SetVar(fmt.Sprintf("P%d", i), p)
59 }
60 return "", nil
61}
62
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070063func help(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
64 r := ""
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070065 if len(args) == 0 {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070066 for k, _ := range builtins {
67 if k == "help" {
68 continue
69 }
70 r += k + ", "
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070071 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070072 r += sh.String()
73 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070074 } else {
75 for _, a := range args {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070076 if v := builtins[a]; v != nil {
77 r += v.usage + "\n"
78 continue
79 }
80 h := sh.Help(a)
81 if len(h) == 0 {
82 return "", fmt.Errorf("unknown command: %q", a)
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070083 } else {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070084 r += h
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070085 }
86 }
87 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070088 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070089}
90
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070091func parseVar(expr string) (string, string, error) {
92 m := varRE.FindAllStringSubmatch(expr, 1)
93 if len(m) != 1 || len(m[0]) != 3 {
94 return "", "", fmt.Errorf("%q is not an assignment statement", expr)
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070095 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070096 return m[0][1], m[0][2], nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070097}
98
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070099func set(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
100 r := ""
101 if len(args) == 0 {
102 for _, v := range sh.Env() {
103 r += v + "\n"
104 }
105 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -0700106 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700107 for _, a := range args {
108 k, v, err := parseVar(a)
109 if err != nil {
110 return "", err
111 }
112 sh.SetVar(k, v)
113 }
114 return "", nil
115}
116
117func assert(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
118 if args[0] != args[1] {
119 return "", fmt.Errorf("assertion failed: %q != %q", args[0], args[1])
120 }
121 return "", nil
122}
123
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700124func stderr(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
125 state.Session.Finish(nil)
126 delete(handles, args[0])
127 return readStderr(state)
128}
129
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700130func readStderr(state *cmdState) (string, error) {
131 var b bytes.Buffer
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700132 if err := state.Handle.Shutdown(nil, &b); err != nil && err != io.EOF {
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700133 return b.String(), err
134 }
135 return b.String(), nil
136}
137
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700138func handleWrapper(sh *modules.Shell, fn builtinCmd, args ...string) (string, error) {
139 if len(args) < 1 {
140 return "", fmt.Errorf("missing handle argument")
141 }
142 state := handles[args[0]]
143 if state == nil {
144 return "", fmt.Errorf("invalid handle")
145 }
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700146 errstr := ""
147 r, err := fn(sh, state, args...)
148 if err != nil {
149 errstr, _ = readStderr(state)
150 errstr = strings.TrimSuffix(errstr, "\n")
151 if len(errstr) > 0 {
152 err = fmt.Errorf("%s: %v", errstr, err)
153 }
154 }
155 return r, err
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700156}
157
158func read(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
159 l := state.Session.ReadLine()
160 for _, a := range args[1:] {
161 sh.SetVar(a, l)
162 }
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700163 return l, state.Session.OriginalError()
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700164}
165
166func eval(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
167 l := state.Session.ReadLine()
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700168 if err := state.Session.OriginalError(); err != nil {
169 return l, err
170 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700171 k, v, err := parseVar(l)
172 if err != nil {
173 return "", err
174 }
175 sh.SetVar(k, v)
176 return l, nil
177}
178
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700179func stop(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700180 state.Handle.CloseStdin()
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700181 return wait(sh, state, args...)
182}
183
184func wait(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
185 // Read and return stdout
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700186 r, err := state.Session.Finish(nil)
187 delete(handles, args[0])
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700188 if err != nil {
189 return r, err
190 }
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700191 // Now read and return the contents of stderr as a string
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700192 if str, err := readStderr(state); err != nil && err != io.EOF {
193 return str, err
194 }
195 return r, nil
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700196}
197
198func list(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
199 r := ""
200 for h, v := range handles {
201 r += h + ": " + v.line + "\n"
202 }
203 return r, nil
204}
205
206func quit(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
207 r := ""
208 for k, h := range handles {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700209 if err := h.Handle.Shutdown(os.Stdout, os.Stdout); err != nil {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700210 r += fmt.Sprintf("%s: %v\n", k, err)
211 } else {
212 r += fmt.Sprintf("%s: ok\n", k)
213 }
214 }
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700215 fmt.Fprintf(os.Stdout, "%s\n", r)
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700216 os.Exit(0)
217 panic("unreachable")
218}
219
220func getLine(sh *modules.Shell, args ...string) (string, error) {
221 handle := handles[args[0]]
222 if handle == nil {
223 return "", fmt.Errorf("invalid handle")
224 }
225 l := handle.Session.ReadLine()
226 return l, handle.Session.Error()
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -0700227}
Cosmos Nicolaoub44f2392014-10-28 22:41:49 -0700228
229func json_set(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
230 for _, k := range args {
231 if v, present := sh.GetVar(k); present {
232 jsonDict[k] = v
233 } else {
234 return "", fmt.Errorf("unrecognised variable: %q", k)
235 }
236 }
237 return "", nil
238}
239
240func json_print(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
241 bytes, err := json.Marshal(jsonDict)
242 if err != nil {
243 return "", err
244 }
245 return string(bytes), nil
246}