(ctx context.Context, opts sshOptions)
| 550 | } |
| 551 | |
| 552 | func (a *App) printOpenSSHConfig(ctx context.Context, opts sshOptions) (err error) { |
| 553 | ctx, cancel := context.WithCancel(ctx) |
| 554 | defer cancel() |
| 555 | |
| 556 | var csList []*api.Codespace |
| 557 | if opts.selector.codespaceName == "" { |
| 558 | err = a.RunWithProgress("Fetching codespaces", func() (err error) { |
| 559 | csList, err = a.apiClient.ListCodespaces(ctx, api.ListCodespacesOptions{}) |
| 560 | return |
| 561 | }) |
| 562 | } else { |
| 563 | var codespace *api.Codespace |
| 564 | codespace, err = opts.selector.Select(ctx) |
| 565 | csList = []*api.Codespace{codespace} |
| 566 | } |
| 567 | if err != nil { |
| 568 | return fmt.Errorf("error getting codespace info: %w", err) |
| 569 | } |
| 570 | |
| 571 | type sshResult struct { |
| 572 | codespace *api.Codespace |
| 573 | user string // on success, the remote ssh username; else nil |
| 574 | err error |
| 575 | } |
| 576 | |
| 577 | sshUsers := make(chan sshResult, len(csList)) |
| 578 | var wg sync.WaitGroup |
| 579 | var status error |
| 580 | for _, cs := range csList { |
| 581 | if cs.State != "Available" && opts.selector.codespaceName == "" { |
| 582 | fmt.Fprintf(os.Stderr, "skipping unavailable codespace %s: %s\n", cs.Name, cs.State) |
| 583 | status = cmdutil.SilentError |
| 584 | continue |
| 585 | } |
| 586 | |
| 587 | wg.Add(1) |
| 588 | go func(cs *api.Codespace) { |
| 589 | result := sshResult{} |
| 590 | defer wg.Done() |
| 591 | |
| 592 | codespaceConnection, err := codespaces.GetCodespaceConnection(ctx, a, a.apiClient, cs) |
| 593 | if err != nil { |
| 594 | result.err = fmt.Errorf("error connecting to codespace: %w", err) |
| 595 | sshUsers <- result |
| 596 | return |
| 597 | } |
| 598 | |
| 599 | fwd, err := portforwarder.NewPortForwarder(ctx, codespaceConnection) |
| 600 | if err != nil { |
| 601 | result.err = fmt.Errorf("failed to create port forwarder: %w", err) |
| 602 | sshUsers <- result |
| 603 | return |
| 604 | } |
| 605 | defer safeClose(fwd, &err) |
| 606 | |
| 607 | invoker, err := rpc.CreateInvoker(ctx, fwd) |
| 608 | if err != nil { |
| 609 | result.err = fmt.Errorf("error connecting to codespace: %w", err) |
no test coverage detected