diff --git a/cli/cli.go b/cli/cli.go index 59551ae..3c3cc6d 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -1,4 +1,4 @@ -// Copyright © 2019-Present Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/cli/graph.go b/cli/graph.go index adacc48..d7ff48c 100644 --- a/cli/graph.go +++ b/cli/graph.go @@ -1,4 +1,4 @@ -// Copyright © 2019-Present Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. diff --git a/cli/list.go b/cli/list.go index e1feb9c..fc81632 100644 --- a/cli/list.go +++ b/cli/list.go @@ -1,4 +1,4 @@ -// Copyright © 2019-Present Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,8 +16,8 @@ package cli import ( "fmt" + "log/slog" - log "github.com/DataDrake/waterlog" "github.com/getsolus/usysconf/config" ) @@ -28,7 +28,7 @@ func (l list) Run(flags GlobalFlags) error { if err != nil { return fmt.Errorf("failed to load triggers: %w", err) } - log.Info("Available triggers:\n\n") + slog.Info("Available triggers:") tm.Print(flags.Chroot, flags.Live) return nil } diff --git a/cli/run.go b/cli/run.go index 5527454..4efe3ce 100644 --- a/cli/run.go +++ b/cli/run.go @@ -1,4 +1,4 @@ -// Copyright © 2019-Present Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ import ( "fmt" "os" - log "github.com/DataDrake/waterlog" "github.com/getsolus/usysconf/config" "github.com/getsolus/usysconf/triggers" "github.com/getsolus/usysconf/util" @@ -33,9 +32,6 @@ type run struct { } func (r run) Run(flags GlobalFlags) error { - log.Debugln("Started usysconf") - defer log.Debugln("Exiting usysconf") - if os.Geteuid() != 0 { return errors.New("you must have root privileges to run triggers") } diff --git a/config/load.go b/config/load.go index 891b1ab..1c5d48b 100644 --- a/config/load.go +++ b/config/load.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,32 +16,29 @@ package config import ( "fmt" - log "github.com/DataDrake/waterlog" - "github.com/getsolus/usysconf/triggers" - "io/ioutil" + "log/slog" "os" "os/user" "path/filepath" "strings" + + "github.com/getsolus/usysconf/triggers" ) -// Load reads in all of the trigger files in a directory -func Load(path string) (tm triggers.Map, err error) { - tm = make(triggers.Map) - entries, err := ioutil.ReadDir(path) +// Load reads in all of the trigger files in a directory. +func Load(path string) (triggers.Map, error) { + logger := slog.With("path", path) + + entries, err := os.ReadDir(path) if err != nil { - log.Debugf("Skipped directory '%s':\n", path) if os.IsNotExist(err) { - log.Debugf(" Not found.\n") - err = nil - return + logger.Debug("Directory not found") + return nil, nil } - log.Debugf(" Failed to read triggers, reason: %s\n", err) - err = nil - return + return nil, fmt.Errorf("failed to read triggers: %w", err) } - log.Debugf("Scanning directory '%s':\n", path) - found := false + tm := make(triggers.Map, len(entries)) + logger.Debug("Scanning directory") for _, entry := range entries { if entry.IsDir() { continue @@ -54,73 +51,51 @@ func Load(path string) (tm triggers.Map, err error) { Name: strings.TrimSuffix(name, ".toml"), Path: filepath.Clean(filepath.Join(path, name)), } - // found trigger - log.Debugf(" Found '%s'\n", t.Name) - found = true - if err = t.Load(t.Path); err == nil { - // Check the config for problems - err = t.Validate() + logger.Debug("Trigger found", "name", t.Name) + err = t.Load(t.Path) + if err != nil { + return nil, err } + err = t.Validate() if err != nil { - err = fmt.Errorf("failed to read '%s' from '%s' reason: %s", name, path, err.Error()) - return + return nil, fmt.Errorf("failed to read %s from %s: %w", name, path, err) } - // save trigger tm[t.Name] = t } - if !found { - log.Debugln(" No triggers found.") + if len(tm) == 0 { + logger.Debug("No triggers found") } - return + return tm, nil } // LoadAll will check the system, user, and home directories, in that order, for a // configuration file that has the passed name parameter, without the extension // and will create a config with the specified valus. -func LoadAll() (tm triggers.Map, err error) { - // Read from System directory - tm, err = Load(SysDir) - if err != nil { - return - } - // Read from User Directory - tm2, err := Load(UsrDir) - if err != nil { - return +func LoadAll() (triggers.Map, error) { + paths := []string{SysDir, UsrDir} + if p, err := os.UserHomeDir(); err != nil { + paths = append(paths, p) } - tm.Merge(tm2) - // Read from Home directory - home, err := os.UserHomeDir() - if err != nil { - return - } - // replace the root directory with the user home directory executing usysconf if os.Getuid() == 0 { - username := os.Getenv("SUDO_USER") - if username == "" || username == "root" { - // if user is not found or it is actually being run by root without sudo return - log.Warnln("Home Triggers not loaded") - goto CHECK + uname := os.Getenv("SUDO_USER") + if uname != "" && uname != "root" { + u, err := user.Lookup(uname) + if err != nil { + slog.Warn("Failed to lookup underlying user", "name", uname, "reason", err) + } else { + paths = append(paths, filepath.Join(u.HomeDir, ".config", "usysconf.d")) + } } - // Lookup sudo user's home directory - u, err := user.Lookup(username) + } + + tm := make(triggers.Map) + for _, path := range paths { + trig, err := Load(path) if err != nil { - log.Warnf("Failed to lookup user '%s', reason: %s\n", username, err) - } else { - home = u.HomeDir + return nil, err } + tm.Merge(trig) } - // Load configs from the user's Home directory - tm2, err = Load(filepath.Join(home, ".config", "usysconf.d")) - if err != nil { - return - } - tm.Merge(tm2) -CHECK: - // check for lack of triggers - if len(tm) == 0 { - log.Fatalln("No triggers available") - } - log.Goodf("Found '%d' triggers\n", len(tm)) - return + slog.Info("Total triggers", "count", len(tm)) + return tm, nil } diff --git a/deps/graph.go b/deps/graph.go index e1d7f63..50737f9 100644 --- a/deps/graph.go +++ b/deps/graph.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,8 @@ package deps import ( - log "github.com/DataDrake/waterlog" + "fmt" + "log/slog" "sort" "strings" ) @@ -46,7 +47,7 @@ func (g Graph) CheckMissing(triggers []string) { } } if !found { - log.Warnf("Dependency '%s' of trigger '%s' does not exist\n", dep, name) + slog.Warn("Dependency does not exist", "parent", name, "child", dep) } } } @@ -64,7 +65,9 @@ func (g Graph) CheckCircular() { } found = found[1:] } - log.Fatalf("Circular dependency: %s\n", strings.Join(found, " -> ")) + // TODO: Return an error instead of panicking. + slog.Error("Circular dependency", "chain", strings.Join(found, " -> ")) + panic("Circular dependency") } } } @@ -168,13 +171,13 @@ func (g Graph) Print() { names = append(names, name) } sort.Strings(names) - log.Println("digraph {") + fmt.Println("digraph {") for _, name := range names { deps := g[name] sort.Strings(deps) for _, dep := range deps { - log.Printf("\t\"%s\" -> \"%s\";\n", name, dep) + fmt.Printf("\t\"%s\" -> \"%s\";\n", name, dep) } } - log.Println("}") + fmt.Println("}") } diff --git a/go.mod b/go.mod index ce0cb65..4535442 100644 --- a/go.mod +++ b/go.mod @@ -1,15 +1,11 @@ module github.com/getsolus/usysconf -go 1.20 +go 1.21 require ( github.com/BurntSushi/toml v1.3.2 - github.com/DataDrake/waterlog v1.2.0 github.com/alecthomas/kong v0.8.0 github.com/fxamacker/cbor/v2 v2.5.0 ) -require ( - github.com/DataDrake/flair v0.5.1 // indirect - github.com/x448/float16 v0.8.4 // indirect -) +require github.com/x448/float16 v0.8.4 // indirect diff --git a/go.sum b/go.sum index edb0eb5..2c3cd2b 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,5 @@ github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= -github.com/DataDrake/flair v0.5.1 h1:JHWOoBRiQGWg+k2bV2Mje2YmDtRjhMj51yDxQkzidWI= -github.com/DataDrake/flair v0.5.1/go.mod h1:3KgdmkL8eJDbg/HdMwlHkeYH/mpSy/hsQvxYQFp9A/Y= -github.com/DataDrake/waterlog v1.2.0 h1:T3Hs0D6YOQfz6GtViw+fYSIGpGimU41FubcxQQzaeHM= -github.com/DataDrake/waterlog v1.2.0/go.mod h1:xSKEWChL8698jwSJSyjKPIpFpj/K5n+Eif2ztYXDjJI= github.com/alecthomas/assert/v2 v2.1.0 h1:tbredtNcQnoSd3QBhQWI7QZ3XHOVkw1Moklp2ojoH/0= github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= diff --git a/main.go b/main.go index 554d082..f33fbae 100644 --- a/main.go +++ b/main.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,25 +15,24 @@ package main import ( - log2 "log" + "log/slog" + "os" - log "github.com/DataDrake/waterlog" - "github.com/DataDrake/waterlog/format" - "github.com/DataDrake/waterlog/level" "github.com/getsolus/usysconf/cli" ) func main() { ctx, flags := cli.Parse() + logOpt := &slog.HandlerOptions{} if flags.Debug { - log.SetLevel(level.Debug) + logOpt.Level = slog.LevelDebug } - log.SetFormat(format.Min) - log.SetFlags(log2.Ltime | log2.Ldate | log2.LUTC) + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, logOpt))) err := ctx.Run(flags) if err != nil { - log.Fatal(err) + slog.Error(err.Error()) + os.Exit(1) } } diff --git a/state/map.go b/state/map.go index fe06f71..8122205 100644 --- a/state/map.go +++ b/state/map.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ package state import ( "fmt" + "log/slog" "os" "path/filepath" "regexp" "strings" "time" - log "github.com/DataDrake/waterlog" - cbor "github.com/fxamacker/cbor/v2" + "github.com/fxamacker/cbor/v2" ) // Path is the location of the serialized system state directory @@ -110,7 +110,7 @@ func (m Map) Search(paths []string) Map { search = "^" + strings.ReplaceAll(search, string(filepath.Separator), "\\"+string(filepath.Separator)) regex, err := regexp.Compile(search) if err != nil { - log.Warnf("Could not convert path to regex: %s\n", path) + slog.Warn("Could not convert to regex", "path", path) continue } for k, v := range m { @@ -133,7 +133,7 @@ func (m Map) Exclude(patterns []string) Map { exclude := strings.ReplaceAll(pattern, "*", ".*") regex, err := regexp.Compile(exclude) if err != nil { - log.Warnf("Could not convert pattern to regex: %s\n", pattern) + slog.Warn("Could not convert to regex", "pattern", pattern) continue } regexes = append(regexes, regex) diff --git a/triggers/bin.go b/triggers/bin.go index 4ffb741..f7432ee 100644 --- a/triggers/bin.go +++ b/triggers/bin.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -17,9 +17,10 @@ package triggers import ( "bytes" "fmt" - log "github.com/DataDrake/waterlog" - "github.com/getsolus/usysconf/util" + "log/slog" "os/exec" + + "github.com/getsolus/usysconf/util" ) // Bin contains the details of the binary to be executed. @@ -92,10 +93,10 @@ func (b Bin) FanOut() (nbins []Bin, outputs []Output) { return } if b.Replace == nil { - log.Errorln(" Placeholder found, but [bins.replaces] is missing.") + slog.Error("Placeholder found, but [bins.replaces] is missing") return } - log.Debugf(" Replace string exists at arg: %d\n", phIndex) + slog.Debug("Replace string exists", "argument", phIndex) paths := util.FilterPaths(b.Replace.Paths, b.Replace.Exclude) for _, path := range paths { out := Output{ diff --git a/triggers/check.go b/triggers/check.go index a0f6b22..6289efd 100644 --- a/triggers/check.go +++ b/triggers/check.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,7 +16,8 @@ package triggers import ( "fmt" - log "github.com/DataDrake/waterlog" + "log/slog" + "github.com/getsolus/usysconf/state" ) @@ -30,7 +31,7 @@ type Check struct { func (t *Trigger) CheckMatch() (m state.Map, ok bool) { ok = true if t.Check == nil { - log.Debugf("No check paths for trigger '%s'\n", t.Name) + slog.Debug("No check paths for trigger", "name", t.Name) return } m, err := state.Scan(t.Check.Paths) diff --git a/triggers/map.go b/triggers/map.go index 47bbb8b..3802fc5 100644 --- a/triggers/map.go +++ b/triggers/map.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,9 +16,9 @@ package triggers import ( "fmt" + "log/slog" "sort" - log "github.com/DataDrake/waterlog" "github.com/getsolus/usysconf/deps" "github.com/getsolus/usysconf/state" ) @@ -53,9 +53,9 @@ func (tm Map) Print(chroot, live bool) { continue } } - log.Printf(f, t.Name, t.Description) + fmt.Printf(f, t.Name, t.Description) } - log.Println() + fmt.Println() } // Graph generates a dependency graph @@ -82,7 +82,7 @@ func (tm Map) Run(s Scope, names []string) { prev, err := state.Load() if err != nil { - log.Errorf("Failed to read state file: %s\n", err) + slog.Error("Failed to read state file", "reason", err) return } @@ -95,7 +95,7 @@ func (tm Map) Run(s Scope, names []string) { // Get Trigger if available t, ok := tm[name] if !ok { - log.Warnf("Could not find trigger %s\n", name) + slog.Warn("Could not find trigger", "name", name) continue } // Run Trigger @@ -104,7 +104,7 @@ func (tm Map) Run(s Scope, names []string) { if !s.DryRun { // Save new State for next run if err := next.Save(); err != nil { - log.Errorf("Failed to save next state file, reason: %s\n", err) + slog.Error("Failed to save next state file", "reason", err) } } } diff --git a/triggers/remove.go b/triggers/remove.go index 6da0177..7ca65f6 100644 --- a/triggers/remove.go +++ b/triggers/remove.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -16,9 +16,10 @@ package triggers import ( "fmt" - log "github.com/DataDrake/waterlog" - "github.com/getsolus/usysconf/state" + "log/slog" "os" + + "github.com/getsolus/usysconf/state" ) // Remove contains paths to be removed from the system. This supports globbing. @@ -30,10 +31,10 @@ type Remove struct { // Remove glob the paths and if it exists it will remove it from the system func (t *Trigger) Remove(s Scope) bool { if s.DryRun { - log.Debugln(" No Paths will be removed during a dry-run\n") + slog.Debug("No Paths will be removed during a dry-run") } if len(t.Removals) == 0 { - log.Debugln(" No Paths to remove\n") + slog.Debug("No Paths to remove") return true } for _, remove := range t.Removals { @@ -57,7 +58,7 @@ func (t *Trigger) removeOne(s Scope, remove Remove) bool { } matches = matches.Exclude(remove.Exclude) for path := range matches { - log.Debugf(" Removing path '%s'\n", path) + slog.Debug("Removing", "path", path) if s.DryRun { continue } diff --git a/triggers/trigger.go b/triggers/trigger.go index 447d605..2193334 100644 --- a/triggers/trigger.go +++ b/triggers/trigger.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,8 @@ package triggers import ( - log "github.com/DataDrake/waterlog" + "log/slog" + "github.com/getsolus/usysconf/state" ) @@ -72,30 +73,30 @@ func (t *Trigger) Finish(s Scope) { // Indicate the worst status for the whole group switch status { case Skipped: - log.Debugln(t.Name) + slog.Debug(t.Name) case Failure: - log.Errorln(t.Name) + slog.Error(t.Name) case Success: - log.Goodln(t.Name) + slog.Info(t.Name) } // Indicate status for sub-tasks for _, out := range t.Output { switch out.Status { case Skipped: if len(out.SubTask) > 0 { - log.Debugf(" Skipped for %s due to %s\n", out.SubTask, out.Message) + slog.Debug("Skipped", "subtask", out.SubTask, "reason", out.Message) } else if len(out.Message) > 0 { - log.Debugf(" Skipped due to %s\n", out.Message) + slog.Debug("Skipped", "reason", out.Message) } case Failure: if len(out.SubTask) > 0 { - log.Errorf(" Failure for %s due to %s\n", out.SubTask, out.Message) + slog.Error("Failed", "subtask", out.SubTask, "reason", out.Message) } else if len(out.Message) > 0 { - log.Errorf(" Failure due to %s\n", out.Message) + slog.Error("Failed", "reason", out.Message) } case Success: if s.DryRun && len(out.SubTask) > 0 { - log.Infof(" %s\n", out.SubTask) + slog.Info(out.SubTask) } } } diff --git a/util/chroot.go b/util/chroot.go index c83926d..5703236 100644 --- a/util/chroot.go +++ b/util/chroot.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,8 +15,8 @@ package util import ( - log "github.com/DataDrake/waterlog" - "io/ioutil" + "io" + "log/slog" "os" "path/filepath" "strconv" @@ -32,35 +32,39 @@ func IsChroot() bool { var pid int // Try to check for access to the root partition of PID1 (shell?) if _, err := os.Stat("/proc/1/root"); err != nil { - log.Warnln("Failed to access '/proc/1/root', assuming chroot and continuing.") + slog.Warn("Failed to access, assuming chroot and continuing", "path", "/proc/1/root") return true } // Check /proc/mounts for overlayfs on "/" mounts, err := os.Open("/proc/mounts") if err != nil { - log.Warnf("Failed to access '/proc/mounts', reason: %s\n", err) + slog.Warn("Failed to access", "path", "/proc/mounts", "reason", err) goto FALLBACK } - raw, err = ioutil.ReadAll(mounts) + raw, err = io.ReadAll(mounts) if err != nil { - log.Warnf("Failed to read '/proc/mounts', reason: %s\n", err) + slog.Warn("Failed to read", "path", "/proc/mounts", "reason", err) goto FALLBACK } _ = mounts.Close() if strings.Contains(string(raw), "overlay / overlay") { - log.Debugln("Overlayfs for '/' found, assuming chroot.\n") + slog.Debug("Overlayfs for '/' found, assuming chroot") return true } FALLBACK: - log.Debugln("Falling back to rigorous check for chroot") + slog.Debug("Falling back to rigorous check for chroot") rootDir, err = os.Stat("/") if err != nil { - log.Fatalf("Failed to access '/', reason: %s\n", err) + slog.Error("Failed to access", "path", "/", "reason", err) + // TODO: Return error instead of panicking. + panic("Failed to access") } pid = os.Getpid() chrootDir, err = os.Stat(filepath.Join("/", "proc", strconv.Itoa(pid), "root")) if err != nil { - log.Fatalf("Failed to access '/', reason: %s\n", err) + slog.Error("Failed to access", "path", "/", "reason", err) + // TODO: Return error instead of panicking. + panic("Failed to access") } root = rootDir.Sys().(*syscall.Stat_t) chroot = chrootDir.Sys().(*syscall.Stat_t) diff --git a/util/live.go b/util/live.go index 849d139..6674b03 100644 --- a/util/live.go +++ b/util/live.go @@ -1,4 +1,4 @@ -// Copyright © 2019-2020 Solus Project +// Copyright © Solus Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,7 +15,7 @@ package util import ( - log "github.com/DataDrake/waterlog" + "log/slog" "os" ) @@ -23,12 +23,14 @@ import ( func IsLive() bool { var err error if _, err = os.Stat("/run/initramfs/livedev"); err == nil { - log.Debugln("Live session detected.") + slog.Debug("Live session detected") return true } if os.IsNotExist(err) { return false } - log.Fatalf("Could not check for live session, reason: %s\n", err) - return false + slog.Error("Could not check for live session", "reason", err) + // TODO: Return error instead of panicking. + panic("Could not check for live session") + //return false }