blob: a1edd5539438dd92a50a6a6610db59146526857e [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
Jiri Simsa764efb72014-12-25 20:57:03 -080012 "v.io/core/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 Nicolaou28f35c32014-12-01 20:36:27 -080025 "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 "assertOneOf": {-1, "val1 val...", false, assertOneOf},
33 "read": {-1, "read <handle> [var]", true, read},
34 "eval": {1, "eval <handle>", true, eval},
35 "wait": {1, "wait <handle>", true, wait},
36 "stop": {1, "stop <handle>", true, stop},
37 "stderr": {1, "stderr <handle>", true, stderr},
38 "list": {0, "list", false, list},
39 "quit": {0, "quit", false, quit},
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070040}
41
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070042func init() {
43 builtins["help"].fn = help
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070044}
45
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070046func print(_ *modules.Shell, _ *cmdState, args ...string) (string, error) {
47 r := strings.Join(args, " ")
48 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070049}
50
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -070051func splitEP(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
52 ep := strings.TrimLeft(args[0], "/")
53 ep = strings.TrimRight(ep, "/")
54 ep = strings.TrimLeft(ep, "@")
55 ep = strings.TrimRight(ep, "@")
56 parts := strings.Split(ep, "@")
57 sh.SetVar("PN", fmt.Sprintf("%d", len(parts)))
58 for i, p := range parts {
59 sh.SetVar(fmt.Sprintf("P%d", i), p)
60 }
61 return "", nil
62}
63
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070064func help(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
65 r := ""
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070066 if len(args) == 0 {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070067 for k, _ := range builtins {
68 if k == "help" {
69 continue
70 }
71 r += k + ", "
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070072 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070073 r += sh.String()
74 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070075 } else {
76 for _, a := range args {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070077 if v := builtins[a]; v != nil {
78 r += v.usage + "\n"
79 continue
80 }
81 h := sh.Help(a)
82 if len(h) == 0 {
83 return "", fmt.Errorf("unknown command: %q", a)
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070084 } else {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070085 r += h
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070086 }
87 }
88 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070089 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070090}
91
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070092func parseVar(expr string) (string, string, error) {
93 m := varRE.FindAllStringSubmatch(expr, 1)
94 if len(m) != 1 || len(m[0]) != 3 {
95 return "", "", fmt.Errorf("%q is not an assignment statement", expr)
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070096 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -070097 return m[0][1], m[0][2], nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -070098}
99
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700100func set(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
101 r := ""
102 if len(args) == 0 {
103 for _, v := range sh.Env() {
104 r += v + "\n"
105 }
106 return r, nil
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -0700107 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700108 for _, a := range args {
109 k, v, err := parseVar(a)
110 if err != nil {
111 return "", err
112 }
113 sh.SetVar(k, v)
114 }
115 return "", nil
116}
117
118func assert(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
119 if args[0] != args[1] {
120 return "", fmt.Errorf("assertion failed: %q != %q", args[0], args[1])
121 }
122 return "", nil
123}
124
Cosmos Nicolaou28f35c32014-12-01 20:36:27 -0800125func assertOneOf(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
126 if len(args) < 2 {
127 return "", fmt.Errorf("missing assertOneOf args")
128 }
129 expected := args[0]
130 for _, a := range args[1:] {
131 if a == expected {
132 return "", nil
133 }
134 }
135 return "", fmt.Errorf("assertion failed: %q not in %v", expected, args[1:])
136}
137
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700138func stderr(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
139 state.Session.Finish(nil)
140 delete(handles, args[0])
141 return readStderr(state)
142}
143
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700144func readStderr(state *cmdState) (string, error) {
145 var b bytes.Buffer
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700146 if err := state.Handle.Shutdown(nil, &b); err != nil && err != io.EOF {
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700147 return b.String(), err
148 }
149 return b.String(), nil
150}
151
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700152func handleWrapper(sh *modules.Shell, fn builtinCmd, args ...string) (string, error) {
153 if len(args) < 1 {
154 return "", fmt.Errorf("missing handle argument")
155 }
156 state := handles[args[0]]
157 if state == nil {
158 return "", fmt.Errorf("invalid handle")
159 }
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700160 errstr := ""
161 r, err := fn(sh, state, args...)
162 if err != nil {
163 errstr, _ = readStderr(state)
164 errstr = strings.TrimSuffix(errstr, "\n")
165 if len(errstr) > 0 {
166 err = fmt.Errorf("%s: %v", errstr, err)
167 }
168 }
169 return r, err
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700170}
171
172func read(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
173 l := state.Session.ReadLine()
174 for _, a := range args[1:] {
175 sh.SetVar(a, l)
176 }
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700177 return l, state.Session.OriginalError()
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700178}
179
180func eval(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
181 l := state.Session.ReadLine()
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700182 if err := state.Session.OriginalError(); err != nil {
183 return l, err
184 }
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700185 k, v, err := parseVar(l)
186 if err != nil {
187 return "", err
188 }
189 sh.SetVar(k, v)
190 return l, nil
191}
192
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700193func stop(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700194 state.Handle.CloseStdin()
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700195 return wait(sh, state, args...)
196}
197
198func wait(sh *modules.Shell, state *cmdState, args ...string) (string, error) {
199 // Read and return stdout
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700200 r, err := state.Session.Finish(nil)
201 delete(handles, args[0])
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700202 if err != nil {
203 return r, err
204 }
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700205 // Now read and return the contents of stderr as a string
Cosmos Nicolaou19a7cd42014-09-25 09:52:16 -0700206 if str, err := readStderr(state); err != nil && err != io.EOF {
207 return str, err
208 }
209 return r, nil
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700210}
211
212func list(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
213 r := ""
214 for h, v := range handles {
215 r += h + ": " + v.line + "\n"
216 }
217 return r, nil
218}
219
220func quit(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
221 r := ""
222 for k, h := range handles {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700223 if err := h.Handle.Shutdown(os.Stdout, os.Stdout); err != nil {
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700224 r += fmt.Sprintf("%s: %v\n", k, err)
225 } else {
226 r += fmt.Sprintf("%s: ok\n", k)
227 }
228 }
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700229 fmt.Fprintf(os.Stdout, "%s\n", r)
Cosmos Nicolaou9c9918d2014-09-23 08:45:56 -0700230 os.Exit(0)
231 panic("unreachable")
232}
233
234func getLine(sh *modules.Shell, args ...string) (string, error) {
235 handle := handles[args[0]]
236 if handle == nil {
237 return "", fmt.Errorf("invalid handle")
238 }
239 l := handle.Session.ReadLine()
240 return l, handle.Session.Error()
Cosmos Nicolaou7c659ac2014-06-09 22:47:04 -0700241}
Cosmos Nicolaoub44f2392014-10-28 22:41:49 -0700242
243func json_set(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
244 for _, k := range args {
245 if v, present := sh.GetVar(k); present {
246 jsonDict[k] = v
247 } else {
248 return "", fmt.Errorf("unrecognised variable: %q", k)
249 }
250 }
251 return "", nil
252}
253
254func json_print(sh *modules.Shell, _ *cmdState, args ...string) (string, error) {
255 bytes, err := json.Marshal(jsonDict)
256 if err != nil {
257 return "", err
258 }
259 return string(bytes), nil
260}