mirror of
https://github.com/coder/coder.git
synced 2026-11-10 04:02:54 +08:00
* chore: Move httpmw to /coderd directory httpmw is specific to coderd and should be scoped under coderd * chore: Move httpapi to /coderd directory httpapi is specific to coderd and should be scoped under coderd * chore: Move database to /coderd directory database is specific to coderd and should be scoped under coderd * chore: Update codecov & gitattributes for generated files * chore: Update Makefile
158 lines
3.7 KiB
Go
158 lines
3.7 KiB
Go
package cliui
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
|
|
"github.com/briandowns/spinner"
|
|
"github.com/charmbracelet/lipgloss"
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/coder/coder/coderd/database"
|
|
"github.com/coder/coder/codersdk"
|
|
)
|
|
|
|
type JobOptions struct {
|
|
Title string
|
|
Output bool
|
|
Fetch func() (codersdk.ProvisionerJob, error)
|
|
Cancel func() error
|
|
Logs func() (<-chan codersdk.ProvisionerJobLog, error)
|
|
}
|
|
|
|
// Job renders a provisioner job.
|
|
func Job(cmd *cobra.Command, opts JobOptions) (codersdk.ProvisionerJob, error) {
|
|
var (
|
|
spin = spinner.New(spinner.CharSets[5], 100*time.Millisecond, spinner.WithColor("fgGreen"))
|
|
|
|
started = false
|
|
completed = false
|
|
job codersdk.ProvisionerJob
|
|
)
|
|
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s%s %s\n", Styles.FocusedPrompt, opts.Title, Styles.Placeholder.Render("(ctrl+c to cancel)"))
|
|
|
|
spin.Writer = cmd.OutOrStdout()
|
|
defer spin.Stop()
|
|
|
|
// Refreshes the job state!
|
|
refresh := func() {
|
|
var err error
|
|
job, err = opts.Fetch()
|
|
if err != nil {
|
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), defaultStyles.Error.Render(err.Error()))
|
|
return
|
|
}
|
|
|
|
if !started && job.StartedAt != nil {
|
|
spin.Stop()
|
|
_, _ = fmt.Fprintf(cmd.OutOrStdout(), Styles.Prompt.String()+"Started "+Styles.Placeholder.Render("[%dms]")+"\n", job.StartedAt.Sub(job.CreatedAt).Milliseconds())
|
|
spin.Start()
|
|
started = true
|
|
}
|
|
if !completed && job.CompletedAt != nil {
|
|
spin.Stop()
|
|
msg := ""
|
|
switch job.Status {
|
|
case codersdk.ProvisionerJobCanceled:
|
|
msg = "Canceled"
|
|
case codersdk.ProvisionerJobFailed:
|
|
msg = "Completed"
|
|
case codersdk.ProvisionerJobSucceeded:
|
|
msg = "Built"
|
|
}
|
|
started := job.CreatedAt
|
|
if job.StartedAt != nil {
|
|
started = *job.StartedAt
|
|
}
|
|
_, _ = fmt.Fprintf(cmd.OutOrStderr(), Styles.Prompt.String()+msg+" "+Styles.Placeholder.Render("[%dms]")+"\n", job.CompletedAt.Sub(started).Milliseconds())
|
|
spin.Start()
|
|
completed = true
|
|
}
|
|
|
|
switch job.Status {
|
|
case codersdk.ProvisionerJobPending:
|
|
spin.Suffix = " Queued"
|
|
case codersdk.ProvisionerJobRunning:
|
|
spin.Suffix = " Running"
|
|
case codersdk.ProvisionerJobCanceling:
|
|
spin.Suffix = " Canceling"
|
|
}
|
|
}
|
|
refresh()
|
|
spin.Start()
|
|
|
|
stopChan := make(chan os.Signal, 1)
|
|
defer signal.Stop(stopChan)
|
|
go func() {
|
|
signal.Notify(stopChan, os.Interrupt)
|
|
select {
|
|
case <-cmd.Context().Done():
|
|
return
|
|
case _, ok := <-stopChan:
|
|
if !ok {
|
|
return
|
|
}
|
|
}
|
|
signal.Stop(stopChan)
|
|
spin.Stop()
|
|
_, _ = fmt.Fprintf(cmd.OutOrStdout(), Styles.FocusedPrompt.String()+"Gracefully canceling... wait for exit or data loss may occur!\n")
|
|
spin.Start()
|
|
err := opts.Cancel()
|
|
if err != nil {
|
|
spin.Stop()
|
|
_, _ = fmt.Fprintln(cmd.OutOrStdout(), defaultStyles.Error.Render(err.Error()))
|
|
return
|
|
}
|
|
refresh()
|
|
}()
|
|
|
|
logs, err := opts.Logs()
|
|
if err != nil {
|
|
return job, err
|
|
}
|
|
|
|
firstLog := false
|
|
ticker := time.NewTicker(time.Second)
|
|
for {
|
|
select {
|
|
case <-cmd.Context().Done():
|
|
return job, cmd.Context().Err()
|
|
case <-ticker.C:
|
|
refresh()
|
|
if job.CompletedAt != nil {
|
|
return job, nil
|
|
}
|
|
case log, ok := <-logs:
|
|
if !ok {
|
|
refresh()
|
|
return job, nil
|
|
}
|
|
if !firstLog {
|
|
refresh()
|
|
firstLog = true
|
|
}
|
|
if !opts.Output {
|
|
continue
|
|
}
|
|
spin.Stop()
|
|
var style lipgloss.Style
|
|
switch log.Level {
|
|
case database.LogLevelTrace:
|
|
style = defaultStyles.Error
|
|
case database.LogLevelDebug:
|
|
style = defaultStyles.Error
|
|
case database.LogLevelError:
|
|
style = defaultStyles.Error
|
|
case database.LogLevelWarn:
|
|
style = Styles.Warn
|
|
case database.LogLevelInfo:
|
|
style = defaultStyles.Note
|
|
}
|
|
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s %s %s\n", Styles.Placeholder.Render("|"), style.Render(string(log.Level)), log.Output)
|
|
spin.Start()
|
|
}
|
|
}
|
|
}
|