// Password retrieves a password from stdin without echoing it. func Password(prefix string) (string, error) { var err error line := "" term, err := NewTerminal() if err != nil { return "", err } defer term.Close() for line == "" { line, err = term.Password(prefix + ": ") if err != nil && err != io.EOF { se := errors.IsStackError(err) if se == nil || se.Err != io.EOF { return "", err } } if line == "" { log.Fprintln(os.Stderr, "red", prefix, errors.ErrEmpty) } } return line, nil }
// Basic gets input and if required tests to ensure input was given. func Basic(prefix string, required bool) (string, error) { return Custom(prefix, func(input string) (string, bool) { if required && input == "" { log.Fprintln(os.Stderr, "red", prefix, errors.ErrEmpty) return "", false } return input, true }) }
// getToken gets the login information for a developer and gets a new token. func getToken(dev *db.Developer) error { var err error i := 0 token := "" // Get email and password up to 5 times, then report the error. for token == "" && i < 5 { validEmail := false email := "" pass := "" for !validEmail { email, err = prompt.Basic("Email", true) if err != nil { return err } _, err = mail.ParseAddress(email) if err == nil { validEmail = true } else { log.Println("yellow", "Try again! Valid email address required.") } } pass, err = prompt.Password("Password") if err != nil { return err } log.Debug("Collected email", email, "pass", pass) token, err = broome.GetTokenByLogin(email, pass) if err != nil { if i < 4 { log.Fprintln(os.Stderr, "red", errors.Newf(errors.ErrLoginRetryTmpl, err)) } i++ } } if err != nil { if err == errors.ErrInvalidLogin { err = errors.ErrTooManyLogins } return err } log.Debug("Got token", token) dev.Token = token return dev.Save() }
func main() { if env == "" { env = "production" } // Remove any previous executables, ignore errors as it isn't essential. exec, _ := osext.Executable() if exec != "" { os.Remove(filepath.Join(filepath.Dir(exec), ".old_bowery"+filepath.Ext(exec))) } // Set up error and analytics reporting. keen := &keen.Client{ WriteKey: "8bbe0d9425a22a6c31e6da9ae3012c738ee21000b533c351a419bb0e3d08431456359d1bea654a39c2065df0b1df997ecde7e3cf49a9be0cd44341b15c1ff5523f13d26d8060373390f47bcc6a33b80e69e2b2c1101cde4ddb3d20b16a53a439a98043919e809c09c30e4856dedc963f", ProjectID: "52c08d6736bf5a4a4b000005", } rollbar := &rollbar.Client{ Token: "a7c4e78074034f04b1882af596657295", Env: env, } // Parse flags and get arguments. flag.Usage = func() { Cmds["help"].Run(keen, rollbar) } flag.Parse() args := flag.Args() command := "help" if len(args) >= 1 { command = args[0] args = args[1:] } // Run command, and handle invalid commands. cmd, ok := Cmds[command] if !ok { keen.AddEvent("invalid command", map[string]string{"command": command}) log.Fprintln(os.Stderr, "red", errors.ErrInvalidCommand, command) os.Exit(Cmds["help"].Run(keen, rollbar)) } cmd.Force = force os.Exit(cmd.Run(keen, rollbar, args...)) }
// Ask gets input and checks if it's truthy or not, and returns that // in a boolean fashion. func Ask(question string) (bool, error) { line, err := Custom(question+"?(y/n)", func(input string) (string, bool) { if input == "" { log.Fprintln(os.Stderr, "red", "Answer", errors.ErrEmpty) return "", false } input = strings.ToLower(input) if input == "y" || input == "yes" { return "yes", true } return "", true }) ok := false if line != "" { ok = true } return ok, err }
func saveRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int { if len(args) <= 0 { fmt.Fprintln(os.Stderr, "Usage: bowery "+Cmds["save"].Usage, "\n\n"+Cmds["save"].Short) return 2 } dev, err := getDeveloper() if err != nil { rollbar.Report(err) return 1 } state, err := db.GetState() if err != nil { rollbar.Report(err) return 1 } // Create slices of service names, and find the requested service. var service *schemas.Service services := make([]string, len(state.App.Services)) for i, v := range state.App.Services { services[i] = v.Name if args[0] == v.Name { service = v break } } // Handle no service found. if service == nil { log.Fprintln(os.Stderr, "red", errors.ErrInvalidService, args[0]) log.Println("yellow", "Valid services:", strings.Join(services, ", ")) return 1 } log.Debug("Found service", service.Name, "public addr:", service.PublicAddr) // Get image name log.Println("yellow", "What would you like to call this image?") imageName, err := prompt.Basic("Image Name", true) if err != nil { rollbar.Report(err) return 1 } log.Debug("Collected Image Name", imageName) imageDesc, err := prompt.Basic("Description", true) if err != nil { rollbar.Report(err) return 1 } log.Debug("Collected Description", imageDesc) log.Println("yellow", "A new image is being created and saved to our registry...") log.Println("yellow", "This may take a couple minutes.") err = api.SaveService(state, dev, service.Name, service.PublicAddr, imageName, imageDesc) if err != nil { errmsg := err.Error() if errmsg == imageName+" is an invalid service name" || errmsg == "Image already exists" { log.Println("yellow", err) } else { rollbar.Report(err) } return 1 } log.Println("yellow", imageName+" successfully created.") keen.AddEvent("bowery save", map[string]string{ "serviceName": service.Name, "imageName": imageName, "appId": state.App.ID, }) return 0 }
func restartRun(keen *keen.Client, rollbar *rollbar.Client, args ...string) int { if len(args) <= 0 { fmt.Fprintln(os.Stderr, "Usage: bowery "+Cmds["restart"].Usage, "\n\n"+Cmds["restart"].Short) return 2 } dev, err := getDeveloper() if err != nil { rollbar.Report(err) return 1 } state, err := db.GetState() if err != nil { rollbar.Report(err) return 1 } // Create slices of service names, and find the requested service. var service *schemas.Service services := make([]string, len(state.App.Services)) serviceIdx := -1 for i, v := range state.App.Services { services[i] = v.Name if args[0] == v.Name { service = v serviceIdx = i break } } // Handle no service found. if service == nil { log.Fprintln(os.Stderr, "red", errors.ErrInvalidService, args[0]) log.Println("yellow", "Valid services:", strings.Join(services, ", ")) return 1 } log.Debug("Found service", service.Name) newService, err := api.RestartService(service.DockerID, dev.Token) if err != nil { rollbar.Report(err) return 1 } if newService != nil { state.App.Services[serviceIdx] = newService service = newService err = state.Save() if err != nil { rollbar.Report(err) return 1 } } keen.AddEvent("bowery restart", map[string]string{ "name": service.Name, "appId": state.App.ID, }) return 0 }