func (command *DestroyPipelineCommand) Execute(args []string) error { client, err := rc.TargetClient(Fly.Target) if err != nil { return err } err = rc.ValidateClient(client, Fly.Target) if err != nil { return err } pipelineName := command.Pipeline fmt.Printf("!!! this will remove all data for pipeline `%s`\n\n", pipelineName) confirm := command.SkipInteractive if !confirm { err := interact.NewInteraction("are you sure?").Resolve(&confirm) if err != nil || !confirm { fmt.Println("bailing out") return err } } found, err := client.DeletePipeline(pipelineName) if err != nil { return err } if !found { fmt.Printf("`%s` does not exist\n", pipelineName) } else { fmt.Printf("`%s` deleted\n", pipelineName) } return nil }
func (example Example) Run() { input := bytes.NewBufferString(example.Input) output := gbytes.NewBuffer() interaction := interact.NewInteraction(example.Prompt, choices...) interaction.Input = input interaction.Output = output resolveErr := interaction.Resolve(destination) if example.ExpectedErr != nil { Expect(resolveErr).To(Equal(example.ExpectedErr)) } else { Expect(resolveErr).ToNot(HaveOccurred()) } var finalDestination interface{} switch d := destination.(type) { case interact.RequiredDestination: finalDestination = d.Destination default: finalDestination = destination } Expect(reflect.Indirect(reflect.ValueOf(finalDestination)).Interface()).To(Equal(example.ExpectedAnswer)) Expect(output.Contents()).To(Equal([]byte(example.ExpectedOutput))) }
// DisplayBoolPrompt outputs the prompt and waits for user input. It only // allows for a boolean response. A default boolean response can be set with // defaultResponse. func (ui *UI) DisplayBoolPrompt(prompt string, defaultResponse bool) (bool, error) { response := defaultResponse fullPrompt := fmt.Sprintf("%s%s", prompt, ui.colorize(">>", cyan, true)) interactivePrompt := interact.NewInteraction(fullPrompt) interactivePrompt.Input = ui.In interactivePrompt.Output = ui.Out err := interactivePrompt.Resolve(&response) return response, err }
func (command *LoginCommand) Execute(args []string) error { var connection concourse.Connection var err error if command.ATCURL != "" { connection, err = rc.NewConnection(command.ATCURL, command.Insecure) } else { connection, err = rc.CommandTargetConnection(Fly.Target, &command.Insecure) } if err != nil { return err } client := concourse.NewClient(connection) authMethods, err := client.ListAuthMethods() if err != nil { return err } var chosenMethod atc.AuthMethod switch len(authMethods) { case 0: fmt.Println("no auth methods configured; updating target data") err := rc.SaveTarget( Fly.Target, connection.URL(), command.Insecure, &rc.TargetToken{}, ) if err != nil { return err } return nil case 1: chosenMethod = authMethods[0] default: choices := make([]interact.Choice, len(authMethods)) for i, method := range authMethods { choices[i] = interact.Choice{ Display: method.DisplayName, Value: method, } } err = interact.NewInteraction("choose an auth method", choices...).Resolve(&chosenMethod) if err != nil { return err } } return command.loginWith(chosenMethod, connection) }
func (atcConfig ATCConfig) ApplyConfigInteraction() bool { if atcConfig.SkipInteraction { return true } confirm := false err := interact.NewInteraction("apply configuration?").Resolve(&confirm) if err != nil { return false } return confirm }
func (command *SetTeamCommand) Execute([]string) error { client, err := rc.TargetClient(Fly.Target) if err != nil { return err } err = rc.ValidateClient(client, Fly.Target) if err != nil { return err } hasBasicAuth, hasGitHubAuth, err := command.ValidateFlags() if err != nil { return err } fmt.Println("Team Name:", command.TeamName) fmt.Println("Basic Auth:", authMethodStatusDescription(hasBasicAuth)) fmt.Println("GitHub Auth:", authMethodStatusDescription(hasGitHubAuth)) confirm := false err = interact.NewInteraction("apply configuration?").Resolve(&confirm) if err != nil { return err } if !confirm { displayhelpers.Failf("bailing out") } team := command.GetTeam(hasBasicAuth, hasGitHubAuth) _, _, _, err = client.SetTeam(command.TeamName, team) if err != nil { return err } fmt.Println("team created") return nil }
func diff(existingConfig atc.Config, newConfig atc.Config) { indent := gexec.NewPrefixedWriter(" ", os.Stdout) groupDiffs := diffIndices(GroupIndex(existingConfig.Groups), GroupIndex(newConfig.Groups)) if len(groupDiffs) > 0 { fmt.Println("groups:") for _, diff := range groupDiffs { diff.Render(indent, "group") } } resourceDiffs := diffIndices(ResourceIndex(existingConfig.Resources), ResourceIndex(newConfig.Resources)) if len(resourceDiffs) > 0 { fmt.Println("resources:") for _, diff := range resourceDiffs { diff.Render(indent, "resource") } } jobDiffs := diffIndices(JobIndex(existingConfig.Jobs), JobIndex(newConfig.Jobs)) if len(jobDiffs) > 0 { fmt.Println("jobs:") for _, diff := range jobDiffs { diff.Render(indent, "job") } } confirm := false err := interact.NewInteraction("apply configuration?").Resolve(&confirm) if err != nil || !confirm { fmt.Println("bailing out") os.Exit(1) } }
func main() { // Well? [yN]: boolAnsFalseDefault := false err := interact.NewInteraction("Well?").Resolve(&boolAnsFalseDefault) if err != nil { fatal(err) } fmt.Println(boolAnsFalseDefault) // Well? [Yn]: boolAnsTrueDefault := true err = interact.NewInteraction("Well?").Resolve(&boolAnsTrueDefault) if err != nil { fatal(err) } fmt.Println(boolAnsTrueDefault) // Well? [yn]: var boolAnsNoDefault bool err = interact.NewInteraction("Well?").Resolve(interact.Required(&boolAnsNoDefault)) if err != nil { fatal(err) } fmt.Println(boolAnsNoDefault) // Message (hello): strAnsDefault := "hello" err = interact.NewInteraction("Message").Resolve(&strAnsDefault) if err != nil { fatal(err) } fmt.Println(strAnsDefault) // Message (): var strAnsEmptyDefault string err = interact.NewInteraction("Message").Resolve(&strAnsEmptyDefault) if err != nil { fatal(err) } fmt.Println(strAnsEmptyDefault) // Message: var strAnsNoDefault string err = interact.NewInteraction("Message").Resolve(interact.Required(&strAnsNoDefault)) if err != nil { fatal(err) } fmt.Println(strAnsNoDefault) numbers := []string{"uno", "dos", "tres"} // 1: One // 2: Two // 3: Three // Choose a number: var chosenFoo string err = interact.NewInteraction( "Choose a number", interact.Choice{Display: "One", Value: numbers[0]}, interact.Choice{Display: "Two", Value: numbers[1]}, interact.Choice{Display: "Three", Value: numbers[2]}, ).Resolve(&chosenFoo) if err != nil { fatal(err) } fmt.Println(chosenFoo) // 1: One // 2: Two // 3: Three // Choose a number (2): chosenFooWithDefault := "dos" err = interact.NewInteraction( "Choose a number", interact.Choice{Display: "One", Value: numbers[0]}, interact.Choice{Display: "Two", Value: numbers[1]}, interact.Choice{Display: "Three", Value: numbers[2]}, ).Resolve(&chosenFooWithDefault) if err != nil { fatal(err) } fmt.Println(chosenFooWithDefault) // 1. One // 2. Two // 3. Three // 4. none // Choose a number (4): var chosenFooOptional *string err = interact.NewInteraction( "Choose a number", interact.Choice{Display: "One", Value: &numbers[0]}, interact.Choice{Display: "Two", Value: &numbers[1]}, interact.Choice{Display: "Three", Value: &numbers[2]}, interact.Choice{Display: "none", Value: nil}, ).Resolve(&chosenFooOptional) if err != nil { fatal(err) } fmt.Println(chosenFooOptional) // Username: var username string err = interact.NewInteraction("Username").Resolve(interact.Required(&username)) if err != nil { fatal(err) } fmt.Println(username) // Password: var password interact.Password err = interact.NewInteraction("Password").Resolve(interact.Required(&password)) if err != nil { fatal(err) } fmt.Println(password) // Interrupt: var ctrlCTest string err = interact.NewInteraction("Interrupt").Resolve(interact.Required(&ctrlCTest)) if err != nil { fmt.Println(err) } }
func (command *HijackCommand) Execute(args []string) error { target, err := rc.SelectTarget(Fly.Target) if err != nil { log.Fatalln(err) return nil } containers := getContainerIDs(command) var id string if len(containers) == 0 { fmt.Fprintln(os.Stderr, "no containers matched your search parameters! they may have expired if your build hasn't recently finished") os.Exit(1) } else if len(containers) > 1 { var choices []interact.Choice for _, container := range containers { var infos []string if container.PipelineName != "" { infos = append(infos, fmt.Sprintf("pipeline: %s", container.PipelineName)) } if container.BuildID != 0 { infos = append(infos, fmt.Sprintf("build id: %d", container.BuildID)) } infos = append(infos, fmt.Sprintf("type: %s", container.Type)) infos = append(infos, fmt.Sprintf("name: %s", container.Name)) choices = append(choices, interact.Choice{ Display: strings.Join(infos, ", "), Value: container.ID, }) } err = interact.NewInteraction("choose a container", choices...).Resolve(&id) if err == io.EOF { os.Exit(0) } if err != nil { return err } } else { id = containers[0].ID } path, args := remoteCommand(args) privileged := true reqGenerator := rata.NewRequestGenerator(target.API, atc.Routes) tlsConfig := &tls.Config{InsecureSkipVerify: target.Insecure} var ttySpec *atc.HijackTTYSpec rows, cols, err := pty.Getsize(os.Stdin) if err == nil { ttySpec = &atc.HijackTTYSpec{ WindowSize: atc.HijackWindowSize{ Columns: cols, Rows: rows, }, } } spec := atc.HijackProcessSpec{ Path: path, Args: args, Env: []string{"TERM=" + os.Getenv("TERM")}, User: "******", Privileged: privileged, TTY: ttySpec, } hijackReq := constructRequest(reqGenerator, spec, id, target.Token) hijackResult := performHijack(hijackReq, tlsConfig) os.Exit(hijackResult) return nil }
func (command *LoginCommand) loginWith(method atc.AuthMethod, connection concourse.Connection) error { var token atc.AuthToken switch method.Type { case atc.AuthTypeOAuth: fmt.Println("navigate to the following URL in your browser:") fmt.Println("") fmt.Printf(" %s\n", method.AuthURL) fmt.Println("") for { var tokenStr string err := interact.NewInteraction("enter token").Resolve(interact.Required(&tokenStr)) if err != nil { return err } segments := strings.SplitN(tokenStr, " ", 2) if len(segments) != 2 { fmt.Println("token must be of the format 'TYPE VALUE', e.g. 'Bearer ...'") continue } token.Type = segments[0] token.Value = segments[1] break } case atc.AuthTypeBasic: var username string err := interact.NewInteraction("username").Resolve(interact.Required(&username)) if err != nil { return err } var password interact.Password err = interact.NewInteraction("password").Resolve(interact.Required(&password)) if err != nil { return err } newUnauthedClient, err := rc.NewConnection(connection.URL(), command.Insecure) if err != nil { return err } basicAuthClient, err := concourse.NewConnection( newUnauthedClient.URL(), &http.Client{ Transport: basicAuthTransport{ username: username, password: string(password), base: newUnauthedClient.HTTPClient().Transport, }, }, ) if err != nil { return err } client := concourse.NewClient(basicAuthClient) token, err = client.AuthToken() if err != nil { return err } } err := rc.SaveTarget( Fly.Target, connection.URL(), command.Insecure, &rc.TargetToken{ Type: token.Type, Value: token.Value, }, ) if err != nil { return err } fmt.Println("token saved") return nil }
func (command *HijackCommand) Execute(args []string) error { target, err := rc.SelectTarget(Fly.Target) if err != nil { return err } containers, err := getContainerIDs(command) if err != nil { return err } var chosenContainer atc.Container if len(containers) == 0 { displayhelpers.Failf("no containers matched your search parameters!\n\nthey may have expired if your build hasn't recently finished.") } else if len(containers) > 1 { var choices []interact.Choice for _, container := range containers { var infos []string if container.BuildID != 0 { if container.JobName != "" { infos = append(infos, fmt.Sprintf("build #%s", container.BuildName)) } else { infos = append(infos, fmt.Sprintf("build id: %d", container.BuildID)) } } if container.StepType != "" { infos = append(infos, fmt.Sprintf("step: %s", container.StepName)) infos = append(infos, fmt.Sprintf("type: %s", container.StepType)) } else if container.ResourceName != "" { infos = append(infos, fmt.Sprintf("resource: %s", container.ResourceName)) infos = append(infos, "type: check") } else { infos = append(infos, fmt.Sprintf("step: %s", container.StepName)) infos = append(infos, "type: check") } if len(container.Attempts) != 0 { attempt := SliceItoa(container.Attempts) infos = append(infos, fmt.Sprintf("attempt: %s", attempt)) } choices = append(choices, interact.Choice{ Display: strings.Join(infos, ", "), Value: container, }) } err = interact.NewInteraction("choose a container", choices...).Resolve(&chosenContainer) if err == io.EOF { return nil } if err != nil { return err } } else { chosenContainer = containers[0] } path, args := remoteCommand(args) privileged := true reqGenerator := rata.NewRequestGenerator(target.API, atc.Routes) tlsConfig := &tls.Config{InsecureSkipVerify: target.Insecure} var ttySpec *atc.HijackTTYSpec rows, cols, err := pty.Getsize(os.Stdin) if err == nil { ttySpec = &atc.HijackTTYSpec{ WindowSize: atc.HijackWindowSize{ Columns: cols, Rows: rows, }, } } envVariables := append(chosenContainer.EnvironmentVariables, "TERM="+os.Getenv("TERM")) spec := atc.HijackProcessSpec{ Path: path, Args: args, Env: envVariables, User: chosenContainer.User, Dir: chosenContainer.WorkingDirectory, Privileged: privileged, TTY: ttySpec, } result, err := func() (int, error) { // so the term.Restore() can run before the os.Exit() var in io.Reader term, err := pty.OpenRawTerm() if err == nil { defer term.Restore() in = term } else { in = os.Stdin } io := hijacker.ProcessIO{ In: in, Out: os.Stdout, Err: os.Stderr, } h := hijacker.New(tlsConfig, reqGenerator, target.Token) return h.Hijack(chosenContainer.ID, spec, io) }() if err != nil { return err } os.Exit(result) return nil }
func (command *LoginCommand) Execute(args []string) error { if isURL(Fly.Target) { return errors.New("name for the target must be specified (--target/-t)") } var connection concourse.Connection var err error if command.ATCURL != "" { connection, err = rc.NewConnection(command.ATCURL, command.Insecure) } else { connection, err = rc.CommandTargetConnection(Fly.Target, &command.Insecure) } if err != nil { return err } client := concourse.NewClient(connection) authMethods, err := client.ListAuthMethods() if err != nil { return err } var chosenMethod atc.AuthMethod if command.Username != "" && command.Password != "" { for _, method := range authMethods { if method.Type == atc.AuthTypeBasic { chosenMethod = method break } } if chosenMethod.Type == "" { return errors.New("basic auth is not available") } } else { switch len(authMethods) { case 0: return command.saveTarget( connection.URL(), &rc.TargetToken{}, ) case 1: chosenMethod = authMethods[0] default: choices := make([]interact.Choice, len(authMethods)) for i, method := range authMethods { choices[i] = interact.Choice{ Display: method.DisplayName, Value: method, } } err = interact.NewInteraction("choose an auth method", choices...).Resolve(&chosenMethod) if err != nil { return err } } } return command.loginWith(chosenMethod, connection) }
import ( "github.com/kr/pty" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "github.com/vito/go-interact/interact" ) var _ = Describe("User IO", func() { Describe("fetching input from the user", func() { Context("when the terminal reports Ctrl-C was pressed", func() { It("returns ErrKeyboardInterrupt", func() { aPty, tty, err := pty.Open() Expect(err).NotTo(HaveOccurred()) interaction := interact.NewInteraction("What is the air-speed of a Swallow?") interaction.Input = aPty interaction.Output = aPty go func() { defer GinkgoRecover() _, err = tty.Write([]byte{03}) Expect(err).NotTo(HaveOccurred()) }() var thing string err = interaction.Resolve(&thing) Expect(err).To(Equal(interact.ErrKeyboardInterrupt)) })
func (command *LoginCommand) loginWith(method atc.AuthMethod, client concourse.Client) error { var token atc.AuthToken switch method.Type { case atc.AuthTypeOAuth: fmt.Println("navigate to the following URL in your browser:") fmt.Println("") fmt.Printf(" %s\n", method.AuthURL) fmt.Println("") for { var tokenStr string err := interact.NewInteraction("enter token").Resolve(interact.Required(&tokenStr)) if err != nil { return err } segments := strings.SplitN(tokenStr, " ", 2) if len(segments) != 2 { fmt.Println("token must be of the format 'TYPE VALUE', e.g. 'Bearer ...'") continue } token.Type = segments[0] token.Value = segments[1] break } case atc.AuthTypeBasic: var username string if command.Username != "" { username = command.Username } else { err := interact.NewInteraction("username").Resolve(interact.Required(&username)) if err != nil { return err } } var password string if command.Password != "" { password = command.Password } else { var interactivePassword interact.Password err := interact.NewInteraction("password").Resolve(interact.Required(&interactivePassword)) if err != nil { return err } password = string(interactivePassword) } newUnauthedClient := rc.NewUnauthenticatedClient(client.URL(), command.Insecure) basicAuthClient := concourse.NewClient( newUnauthedClient.URL(), &http.Client{ Transport: basicAuthTransport{ username: username, password: password, base: newUnauthedClient.HTTPClient().Transport, }, }, ) var err error token, err = basicAuthClient.AuthToken() if err != nil { return err } } return command.saveTarget( client.URL(), &rc.TargetToken{ Type: token.Type, Value: token.Value, }, ) }