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:
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)