src

Go monorepo.
Log | Files | Refs

commit 87783226a7ea14f6e1a228621210abef4fc36873
parent 05de12b4b86cfcb2f855cfbdef432324b7e8ab01
Author: dwrz <dwrz@dwrz.net>
Date:   Mon, 19 Dec 2022 18:08:27 +0000

Refactor statusbar to use context

Should prevent hanging commands from halting output.

Diffstat:
Mcmd/statusbar/main.go | 10+++++++---
Mpkg/statusbar/cpu/cpu.go | 3++-
Mpkg/statusbar/datetime/datetime.go | 5+++--
Mpkg/statusbar/disk/disk.go | 5+++--
Mpkg/statusbar/eth/eth.go | 3++-
Mpkg/statusbar/light/light.go | 5+++--
Mpkg/statusbar/memory/memory.go | 5+++--
Mpkg/statusbar/mic/mic.go | 7++++---
Mpkg/statusbar/power/power.go | 3++-
Mpkg/statusbar/statusbar.go | 14+++++++++-----
Mpkg/statusbar/temp/temp.go | 5+++--
Mpkg/statusbar/volume/volume.go | 7++++---
Mpkg/statusbar/wlan/wlan.go | 7+++++--
Mpkg/statusbar/wwan/wwan.go | 9+++++----
14 files changed, 55 insertions(+), 33 deletions(-)

diff --git a/cmd/statusbar/main.go b/cmd/statusbar/main.go @@ -1,6 +1,7 @@ package main import ( + "context" "flag" "fmt" "os" @@ -29,7 +30,10 @@ var once = flag.Bool("once", false, "print output once") func main() { flag.Parse() - var l = log.New(os.Stderr) + var ( + ctx = context.Background() + l = log.New(os.Stderr) + ) // Setup workspace and log file. cdir, err := os.UserCacheDir() @@ -99,7 +103,7 @@ func main() { }) // Initial print. - fmt.Println(bar.Render()) + fmt.Println(bar.Render(ctx)) if *once { os.Exit(0) } @@ -110,7 +114,7 @@ func main() { select { case <-ticker.C: // now := time.Now() - fmt.Println(bar.Render()) + fmt.Println(bar.Render(ctx)) // fmt.Println(time.Since(now)) } } diff --git a/pkg/statusbar/cpu/cpu.go b/pkg/statusbar/cpu/cpu.go @@ -1,6 +1,7 @@ package cpu import ( + "context" "fmt" "os" "runtime" @@ -19,7 +20,7 @@ func (b *Block) Name() string { return "cpu" } -func (b *Block) Render() (string, error) { +func (b *Block) Render(ctx context.Context) (string, error) { out, err := os.ReadFile(path) if err != nil { return "", fmt.Errorf("failed to read %s: %v", path, err) diff --git a/pkg/statusbar/datetime/datetime.go b/pkg/statusbar/datetime/datetime.go @@ -1,6 +1,7 @@ package datetime import ( + "context" "fmt" "os/exec" "strings" @@ -34,8 +35,8 @@ func (b *Block) Name() string { return "datetime" } -func (b *Block) Render() (string, error) { - cmd := exec.Command("date", b.format) +func (b *Block) Render(ctx context.Context) (string, error) { + cmd := exec.CommandContext(ctx, "date", b.format) cmd.Env = append(cmd.Env, fmt.Sprintf("TZ=%s", b.timezone)) out, err := cmd.Output() diff --git a/pkg/statusbar/disk/disk.go b/pkg/statusbar/disk/disk.go @@ -1,6 +1,7 @@ package disk import ( + "context" "fmt" "os/exec" "strings" @@ -18,8 +19,8 @@ func (b *Block) Name() string { return "disk" } -func (b *Block) Render() (string, error) { - out, err := exec.Command("df", "-h").Output() +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext(ctx, "df", "-h").Output() if err != nil { return "", fmt.Errorf("exec df failed: %v", err) } diff --git a/pkg/statusbar/eth/eth.go b/pkg/statusbar/eth/eth.go @@ -1,6 +1,7 @@ package eth import ( + "context" "fmt" "net" ) @@ -17,7 +18,7 @@ func (b *Block) Name() string { return "eth" } -func (b *Block) Render() (string, error) { +func (b *Block) Render(ctx context.Context) (string, error) { iface, err := net.InterfaceByName(b.iface) if err != nil { if err.Error() == "route ip+net: no such network interface" { diff --git a/pkg/statusbar/light/light.go b/pkg/statusbar/light/light.go @@ -1,6 +1,7 @@ package light import ( + "context" "fmt" "os/exec" "strings" @@ -16,8 +17,8 @@ func (b *Block) Name() string { return "light" } -func (b *Block) Render() (string, error) { - out, err := exec.Command("brightnessctl", "-m").Output() +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext(ctx, "brightnessctl", "-m").Output() if err != nil { return "", fmt.Errorf("failed to exec: %v", err) } diff --git a/pkg/statusbar/memory/memory.go b/pkg/statusbar/memory/memory.go @@ -1,6 +1,7 @@ package memory import ( + "context" "fmt" "os/exec" "strconv" @@ -17,10 +18,10 @@ func (b *Block) Name() string { return "memory" } -func (b *Block) Render() (string, error) { +func (b *Block) Render(ctx context.Context) (string, error) { var output strings.Builder - out, err := exec.Command("free", "-m").Output() + out, err := exec.CommandContext(ctx, "free", "-m").Output() if err != nil { return "", fmt.Errorf("failed to exec: %v", err) } diff --git a/pkg/statusbar/mic/mic.go b/pkg/statusbar/mic/mic.go @@ -1,6 +1,7 @@ package mic import ( + "context" "fmt" "os/exec" "strings" @@ -16,9 +17,9 @@ func (b *Block) Name() string { return "mic" } -func (b *Block) Render() (string, error) { - out, err := exec.Command( - "pactl", "get-source-mute", "@DEFAULT_SOURCE@", +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext( + ctx, "pactl", "get-source-mute", "@DEFAULT_SOURCE@", ).Output() if err != nil { return "", fmt.Errorf("exec pactl failed: %v", err) diff --git a/pkg/statusbar/power/power.go b/pkg/statusbar/power/power.go @@ -2,6 +2,7 @@ package power import ( "bufio" + "context" "fmt" "math" "os" @@ -25,7 +26,7 @@ func (b *Block) Name() string { return "power" } -func (b *Block) Render() (string, error) { +func (b *Block) Render(ctx context.Context) (string, error) { // Get the power supplies. var supplies []string diff --git a/pkg/statusbar/statusbar.go b/pkg/statusbar/statusbar.go @@ -1,16 +1,18 @@ package statusbar import ( + "context" "fmt" "strings" "sync" + "time" "code.dwrz.net/src/pkg/log" ) type Block interface { Name() string - Render() (string, error) + Render(ctx context.Context) (string, error) } type Parameters struct { @@ -26,15 +28,17 @@ type StatusBar struct { sep string } -func (s *StatusBar) Render() string { +func (s *StatusBar) Render(ctx context.Context) string { defer s.b.Reset() fmt.Fprintf(s.b, "%s ", s.sep) var ( - outputs = make([]string, len(s.blocks)) - wg sync.WaitGroup + timeout, cancel = context.WithTimeout(ctx, 100*time.Millisecond) + outputs = make([]string, len(s.blocks)) + wg sync.WaitGroup ) + defer cancel() wg.Add(len(s.blocks)) @@ -42,7 +46,7 @@ func (s *StatusBar) Render() string { go func(i int, b Block) { defer wg.Done() - text, err := b.Render() + text, err := b.Render(timeout) if err != nil { s.l.Error.Printf( "failed to render %s: %v", diff --git a/pkg/statusbar/temp/temp.go b/pkg/statusbar/temp/temp.go @@ -1,6 +1,7 @@ package temp import ( + "context" "encoding/json" "fmt" "os/exec" @@ -16,8 +17,8 @@ func (b *Block) Name() string { return "temp" } -func (b *Block) Render() (string, error) { - out, err := exec.Command("sensors", "-j").Output() +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext(ctx, "sensors", "-j").Output() if err != nil { return "", fmt.Errorf("exec sensors failed: %v", err) } diff --git a/pkg/statusbar/volume/volume.go b/pkg/statusbar/volume/volume.go @@ -1,6 +1,7 @@ package volume import ( + "context" "fmt" "os/exec" "strings" @@ -16,9 +17,9 @@ func (b *Block) Name() string { return "volume" } -func (b *Block) Render() (string, error) { - out, err := exec.Command( - "pactl", "get-sink-mute", "@DEFAULT_SINK@", +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext( + ctx, "pactl", "get-sink-mute", "@DEFAULT_SINK@", ).Output() if err != nil { return "", fmt.Errorf("exec pactl failed: %v", err) diff --git a/pkg/statusbar/wlan/wlan.go b/pkg/statusbar/wlan/wlan.go @@ -3,6 +3,7 @@ package wlan import ( "bufio" "bytes" + "context" "fmt" "os/exec" "strings" @@ -19,8 +20,10 @@ func (b *Block) Name() string { } // TODO: signal strength icon. -func (b *Block) Render() (string, error) { - out, err := exec.Command("iwctl", "station", "wlan0", "show").Output() +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext( + ctx, "iwctl", "station", "wlan0", "show", + ).Output() if err != nil { return "", fmt.Errorf("exec iwctl failed: %v", err) } diff --git a/pkg/statusbar/wwan/wwan.go b/pkg/statusbar/wwan/wwan.go @@ -3,6 +3,7 @@ package wwan import ( "bufio" "bytes" + "context" "fmt" "net" "os/exec" @@ -24,8 +25,8 @@ func (b *Block) Name() string { // TODO: signal strength icon. // TODO: get IP address (net.Interfaces). -func (b *Block) Render() (string, error) { - out, err := exec.Command("mmcli", "--list-modems").Output() +func (b *Block) Render(ctx context.Context) (string, error) { + out, err := exec.CommandContext(ctx, "mmcli", "--list-modems").Output() if err != nil { return "", fmt.Errorf("exec mmcli failed: %v", err) } @@ -36,8 +37,8 @@ func (b *Block) Render() (string, error) { } modem := path.Base(fields[0]) - out, err = exec.Command( - "mmcli", "-m", modem, "--output-keyvalue", + out, err = exec.CommandContext( + ctx, "mmcli", "-m", modem, "--output-keyvalue", ).Output() if err != nil { return "", fmt.Errorf("exec mmcli failed: %v", err)