Skip to content

Commit

Permalink
Add more emojis for various jobs and tasks statuses in alfred watch.
Browse files Browse the repository at this point in the history
  • Loading branch information
gnutix committed Nov 14, 2023
1 parent 363004e commit 61512b8
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 58 deletions.
73 changes: 52 additions & 21 deletions client/watch.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"math"
"strings"
"time"
"unicode/utf8"

"github.com/gammadia/alfred/client/ui"
"github.com/gammadia/alfred/proto"
"github.com/rivo/uniseg"
"github.com/samber/lo"
"github.com/spf13/cobra"
)
Expand All @@ -26,18 +28,22 @@ var watchCmd = &cobra.Command{

spinner := ui.NewSpinner("Waiting for job data")

emoji := func(emoji string) string {
return emoji + strings.Repeat(" ", utf8.RuneCountInString(emoji))
}
itemsPrinter := func(items []string, last bool) string {
nbItems := len(items)
if nbItems < 1 {
return ""
}

// Try to display the first or last 20 items, as long as displaying them doesn't exceed 180 characters...
// ... except in verbose mode, where we go a bit crazier.
// ... except in verbose mode, where we display everything (it might be ugly while it's running, but it's
// very useful once it's finished).
displayItems := 20
lineLength := 180
if verbose {
displayItems = 250
displayItems = math.MaxInt32
lineLength = math.MaxInt32
}
partial := nbItems > displayItems
Expand All @@ -48,27 +54,31 @@ var watchCmd = &cobra.Command{
} else {
nItems = items[:min(nbItems, displayItems)]
}
if len(strings.Join(nItems, " ")) <= lineLength {
if uniseg.GraphemeClusterCount(strings.Join(nItems, " ")) <= lineLength {
break
}
displayItems -= 1
partial = true
}

if last {
return fmt.Sprintf("%s%s (📝 %d)", lo.Ternary(partial, "… ", ""), strings.Join(nItems, " "), nbItems)
return fmt.Sprintf("%s%s (%s%d)", lo.Ternary(partial, "… ", ""), strings.Join(nItems, " "), emoji("📝"), nbItems)
}
return fmt.Sprintf("%s%s (📝 %d)", strings.Join(nItems, " "), lo.Ternary(partial, " …", ""), nbItems)
return fmt.Sprintf("%s%s (%s%d)", strings.Join(nItems, " "), lo.Ternary(partial, " …", ""), emoji("📝"), nbItems)
}

var stats, timestamp string
var tasks []string

someTime := lo.Must(time.ParseDuration("30m"))
aLongTime := lo.Must(time.ParseDuration("2h"))
aVeryLongTime := lo.Must(time.ParseDuration("4h"))

for {
msg, err := c.Recv()
if err != nil {
if err == io.EOF {
spinner.Success(fmt.Sprintf("Job '%s' completed (📝 %d, %s)\n%s", args[0], len(tasks), timestamp, stats))
spinner.Success(fmt.Sprintf("Job '%s' completed (%s%d, %s)\n%s", args[0], emoji("📝"), len(tasks), timestamp, stats))
return nil
}
spinner.Fail()
Expand All @@ -84,53 +94,74 @@ var watchCmd = &cobra.Command{

tasks = lo.Map(msg.Tasks, func(t *proto.TaskStatus, _ int) string { return t.Name })
for _, t := range msg.Tasks {
label := t.Name

if t.StartedAt != nil {
var taskRunningFor time.Duration
if t.CompletedAt != nil {
taskRunningFor = t.CompletedAt.AsTime().Sub(t.StartedAt.AsTime()).Truncate(time.Second)
} else {
taskRunningFor = time.Since(t.StartedAt.AsTime()).Truncate(time.Second)
}
if taskRunningFor >= someTime {
label += fmt.Sprintf(" (%s%s)", emoji(lo.Ternary(taskRunningFor >= aLongTime, "🧟", "🐢")), taskRunningFor)
}
} else {
taskQueuedFor := time.Since(msg.ScheduledAt.AsTime()).Truncate(time.Second)
if taskQueuedFor >= aVeryLongTime {
label += fmt.Sprintf(" (%s%s)", emoji("😴"), taskQueuedFor)
}
}

switch t.Status {
case proto.TaskStatus_QUEUED:
queued = append(queued, t.Name)
queued = append(queued, label)
case proto.TaskStatus_RUNNING:
running = append(running, t.Name)
running = append(running, label)
case proto.TaskStatus_ABORTED:
aborted = append(aborted, t.Name)
aborted = append(aborted, label)
case proto.TaskStatus_FAILED:
if *t.ExitCode == 42 {
failures = append(failures, t.Name)
failures = append(failures, label)
} else {
crashed = append(crashed, t.Name)
crashed = append(crashed, label)
}
case proto.TaskStatus_COMPLETED:
completed = append(completed, t.Name)
completed = append(completed, label)
}
}

statItems := []string{}
if len(queued) > 0 {
statItems = append(statItems, fmt.Sprintf("⏳ %s", itemsPrinter(queued, false)))
statItems = append(statItems, emoji("⏳")+itemsPrinter(queued, false))
}
if len(running) > 0 {
statItems = append(statItems, fmt.Sprintf("⚙️ %s", itemsPrinter(running, false)))
statItems = append(statItems, emoji("⚙️")+itemsPrinter(running, false))
}
if len(aborted) > 0 {
statItems = append(statItems, fmt.Sprintf("🛑 %s", itemsPrinter(aborted, true)))
statItems = append(statItems, emoji("🛑")+itemsPrinter(aborted, true))
}
if len(crashed) > 0 {
statItems = append(statItems, fmt.Sprintf("💥 %s", itemsPrinter(crashed, true)))
statItems = append(statItems, emoji("💥")+itemsPrinter(crashed, true))
}
if len(failures) > 0 {
statItems = append(statItems, fmt.Sprintf("⚠️ %s", itemsPrinter(failures, true)))
statItems = append(statItems, emoji("⚠️")+itemsPrinter(failures, true))
}
if len(completed) > 0 {
statItems = append(statItems, fmt.Sprintf("✅ %s", itemsPrinter(completed, true)))
statItems = append(statItems, emoji("✅")+itemsPrinter(completed, true))
}

stats = strings.Join(statItems, "\n")

if msg.CompletedAt != nil {
timestamp = fmt.Sprintf("🏁 %s", msg.CompletedAt.AsTime().Sub(msg.ScheduledAt.AsTime()).Truncate(time.Second))
timestamp = emoji("🏁") + fmt.Sprintf("%s", msg.CompletedAt.AsTime().Sub(msg.ScheduledAt.AsTime()).Truncate(time.Second))
} else {
timestamp = fmt.Sprintf("⏱️ %s", time.Since(msg.ScheduledAt.AsTime()).Truncate(time.Second))
jobRunningFor := time.Since(msg.ScheduledAt.AsTime()).Truncate(time.Second)
jobRunningForEmoji := lo.Ternary(jobRunningFor >= aLongTime, lo.Ternary(jobRunningFor >= aVeryLongTime, "🧟", "🐢"), "⏱️")
timestamp = emoji(jobRunningForEmoji) + fmt.Sprintf("%s", jobRunningFor)
}

spinner.UpdateMessage(fmt.Sprintf("Job '%s' running (📝 %d, %s)\n%s", args[0], len(tasks), timestamp, stats))
spinner.UpdateMessage(fmt.Sprintf("Job '%s' running (%s%d, %s)\n%s", args[0], emoji("📝"), len(tasks), timestamp, stats))
}
},
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/fatih/color v1.15.0
github.com/gophercloud/gophercloud v1.7.0
github.com/rivo/tview v0.0.0-20231102183219-1b91b8131c43
github.com/rivo/uniseg v0.4.4
github.com/samber/lo v1.38.1
github.com/spf13/cobra v1.7.0
github.com/spf13/pflag v1.0.5
Expand Down Expand Up @@ -48,7 +49,6 @@ require (
github.com/pelletier/go-toml/v2 v2.1.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
Expand Down
99 changes: 63 additions & 36 deletions proto/alfred.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions proto/alfred.proto
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ message TaskStatus {
string name = 1;
Status status = 2;
optional int32 exit_code = 3;
google.protobuf.Timestamp started_at = 4;
optional google.protobuf.Timestamp completed_at = 5;

enum Status {
UNKNOWN = 0;
Expand Down
5 changes: 5 additions & 0 deletions server/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ func listenEvents(c <-chan schedulerpkg.Event) {
for _, task := range job.Tasks {
if task.Name == event.Task {
task.Status = proto.TaskStatus_RUNNING
task.StartedAt = timestamppb.Now()
break
}
}
Expand All @@ -127,6 +128,9 @@ func listenEvents(c <-chan schedulerpkg.Event) {
if task.Name == event.Task {
task.Status = proto.TaskStatus_FAILED
task.ExitCode = lo.ToPtr(int32(event.ExitCode))
if event.ExitCode == 42 {
task.CompletedAt = timestamppb.Now()
}
break
}
}
Expand All @@ -140,6 +144,7 @@ func listenEvents(c <-chan schedulerpkg.Event) {
if task.Name == event.Task {
task.Status = proto.TaskStatus_COMPLETED
task.ExitCode = lo.ToPtr(int32(0))
task.CompletedAt = timestamppb.Now()
break
}
}
Expand Down

0 comments on commit 61512b8

Please sign in to comment.