47 lines
1011 B
Go
47 lines
1011 B
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
)
|
|
|
|
func readJSON(path string, v any) error {
|
|
body, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return json.Unmarshal(body, v)
|
|
}
|
|
|
|
// writeJSON replaces the file atomically: a half-written state file would look
|
|
// like a corrupt install on the next run.
|
|
func writeJSON(path string, v any) error {
|
|
body, err := json.MarshalIndent(v, "", " ")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
tmp := fmt.Sprintf("%s.%d", path, os.Getpid())
|
|
addTemp(tmp)
|
|
defer dropTemp(tmp)
|
|
|
|
if err := os.WriteFile(tmp, append(body, '\n'), 0o644); err != nil {
|
|
return fmt.Errorf("cannot write %s: %w", tmp, err)
|
|
}
|
|
if err := os.Rename(tmp, path); err != nil {
|
|
os.Remove(tmp)
|
|
return fmt.Errorf("cannot update %s: %w", path, err)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func humanSize(n int64) string {
|
|
switch {
|
|
case n >= 1024*1024:
|
|
return fmt.Sprintf("%.1f MB", float64(n)/1024/1024)
|
|
case n >= 1024:
|
|
return fmt.Sprintf("%.1f kB", float64(n)/1024)
|
|
}
|
|
return fmt.Sprintf("%d B", n)
|
|
}
|