Skip to content

codespace: use progress indicator#4556

Merged
josebalius merged 11 commits intojg/universe-prepfrom
jg/use-progress
Oct 18, 2021
Merged

codespace: use progress indicator#4556
josebalius merged 11 commits intojg/universe-prepfrom
jg/use-progress

Conversation

@josebalius
Copy link
Contributor

@josebalius josebalius commented Oct 18, 2021

This PR builds on top of #4555 and it changes the code to use IOStreams' progress indicator.

  • Most of the logged states turn into progress indicators
  • There are a few TODOs that need to be resolved (working on this but happy to get feedback)
  • The spinner color is hardcoded to black at the moment. I use a light terminal and the default spinner is very light and barely visible. We need to resolve how to set the spinner color?
  • If we are non-interactive, loading states are instead logged. If DEBUG=1 has been set, then they are logged out to the io.Out
  • There are functions like getOrChooseCodespace that should probably also take a progressIndicator or an *App. I really wanted to move everything out of pkg/cmd/codespace and internal/codespaces/app.go and other files. It feels like we need to this at some point. I actually did in another branch but the diff is huge 😬

@josebalius josebalius self-assigned this Oct 18, 2021
@josebalius josebalius requested review from a team as code owners October 18, 2021 17:12
@josebalius josebalius requested review from vilmibm and removed request for a team October 18, 2021 17:12
if nameFilter == "" {
a.StartProgressIndicatorWithSuffix("Fetching codespaces")
codespaces, err = a.apiClient.ListCodespaces(ctx, -1)
a.StopProgressIndicator()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if there is a helper function one could write that would allow you to write this sequence each time you need a progress indicator:

progress.start()
defer progress.stop()
slowOperation()

Ideally it should work correctly even when the call sequence is start1 start2 stop2 stop1 so that you can use the above sequence of statements twice within a function that has two slow operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would need to test how two spinners would interact with each other. I did initially have something like this:

	var repository *api.Repository
	if err := a.perform("Fetching repository", func() error {
		repository, err = a.apiClient.GetRepository(ctx, repo)
		return err
	}); err != nil {
		return fmt.Errorf("error getting repository: %w", err)
	}

But I didn't want to spread a.perform all over the place with vars everywhere. There's a tradeoff for sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, we definitely don't want to go that route. Control flow abstraction is not one of Go's strengths.

I was imagining the helper would maintain an underlying spinner and a stack of unstopped starts, and would take care of calling underlying.stop in between two nested calls to outer.start; similarly, after a call to outer.stop, it would use underlying.start to restart the last unstopped task.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see... that sounds nice, having to manage the stop across possible error returns is tedious. Perhaps it's something we can consider for gh as a whole since the pattern I'm using here it's used heavily everywhere else. Likely not going to happen in this PR though 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants