func replCLI(env *Env) { defer fmt.Println("\nbye!") counter := readline.HistorySize() for { buf := bytes.Buffer{} prompt := fmt.Sprintf("[%d]-> ", counter) for { l, err := readline.String(prompt) if err == io.EOF { return } buf.WriteString(l) if validSexp(buf.String()) { break } buf.WriteString("\n") prompt = ": " } result, err := repl(buf.String(), env) if err != nil && err != ErrorEOF { fmt.Println("Error:", err) } else { fmt.Println(result) } readline.AddHistory(buf.String()) counter++ } }
func main() { var err error defer func() { if e := recover(); e != nil { fmt.Fprintf(os.Stderr, "FATAL: %v\n", e) } }() homedir := client.FindHomedir() // command line options var config = flag.String("c", homedir+"/.migrc", "Load configuration from file") var quiet = flag.Bool("q", false, "don't display banners and prompts") var showversion = flag.Bool("V", false, "show build version and exit") flag.Parse() if *showversion { fmt.Println(version) os.Exit(0) } // silence extra output out := os.Stdout if *quiet { out.Close() out, err = os.Open(os.DevNull) if err != nil { panic(err) } } defer out.Close() fmt.Fprintf(out, "\x1b[32;1m"+banner+"\x1b[0m") // append a space after completion readline.CompletionAppendChar = 0x20 // load history historyfile := homedir + "/.mig_history" fi, err := os.Stat(historyfile) if err == nil && fi.Size() > 0 { err = readline.LoadHistory(historyfile) if err != nil { fmt.Fprintf(os.Stderr, "failed to load history from %s\n", historyfile) } } // instanciate an API client conf, err := client.ReadConfiguration(*config) if err != nil { panic(err) } cli, err := client.NewClient(conf, "console-"+version) if err != nil { panic(err) } // print platform status err = printStatus(cli) if err != nil { log.Fatal(err) } fmt.Fprintf(out, "\nConnected to %s. Exit with \x1b[32;1mctrl+d\x1b[0m. Type \x1b[32;1mhelp\x1b[0m for help.\n", cli.Conf.API.URL) for { // completion var symbols = []string{"action", "agent", "create", "command", "help", "history", "exit", "showcfg", "status", "investigator", "search", "where", "and"} readline.Completer = func(query, ctx string) []string { var res []string for _, sym := range symbols { if strings.HasPrefix(sym, query) { res = append(res, sym) } } return res } input, err := readline.String("\x1b[32;1mmig>\x1b[0m ") if err == io.EOF { break } if err != nil { fmt.Println("error: ", err) break } orders := strings.Split(strings.TrimSpace(input), " ") switch orders[0] { case "action": if len(orders) == 2 { err = actionReader(input, cli) if err != nil { log.Println(err) } } else { fmt.Println("error: missing action id in 'action <id>'") } case "agent": err = agentReader(input, cli) if err != nil { log.Println(err) } case "create": if len(orders) == 2 { switch orders[1] { case "action": var a mig.Action err = actionLauncher(a, cli) case "investigator": err = investigatorCreator(cli) default: fmt.Printf("unknown order 'create %s'\n", orders[1]) } if err != nil { log.Println(err) } } else { fmt.Println("error: missing order, must be 'create <action|investigator>'") } case "command": err = commandReader(input, cli) if err != nil { log.Println(err) } case "exit": fmt.Printf("exit\n") goto exit case "help": fmt.Printf(`The following orders are available: action <id> enter interactive action reader mode for action <id> agent <id> enter interactive agent reader mode for agent <id> create action create a new action create investigator create a new investigator, will prompt for name and public key command <id> enter command reader mode for command <id> exit leave help show this help history <count> print last <count> entries in history. count=10 by default. investigator <id> enter interactive investigator management mode for investigator <id> search perform a search. see "search help" for more information. showcfg display running configuration status display platform status: connected agents, latest actions, ... `) case "history": var count int64 = 10 if len(orders) > 1 { count, err = strconv.ParseInt(orders[1], 10, 64) if err != nil { log.Println(err) break } } for i := readline.HistorySize(); i > 0 && count > 0; i, count = i-1, count-1 { fmt.Println(readline.GetHistory(i - 1)) } case "investigator": err = investigatorReader(input, cli) if err != nil { log.Println(err) } case "search": err = search(input, cli) if err != nil { log.Println(err) } case "showcfg": fmt.Printf("homedir = %s\n[api]\n url = %s\n[gpg]\n home = %s\n keyid = %s\n", cli.Conf.API.URL, cli.Conf.Homedir, cli.Conf.GPG.Home, cli.Conf.GPG.KeyID) case "status": err = printStatus(cli) if err != nil { log.Println(err) } case "": break default: fmt.Printf("Unknown order '%s'\n", orders[0]) } readline.AddHistory(input) } exit: fmt.Fprintf(out, footer) err = readline.SaveHistory(historyfile) if err != nil { fmt.Fprintf(os.Stderr, "failed to save history to %s\n", historyfile) } }