]> ruderich.org/simon Gitweb - safcm/safcm.git/commitdiff
safcm: move sync_changes.go and term.go to frontend package
authorSimon Ruderich <simon@ruderich.org>
Tue, 18 May 2021 16:15:23 +0000 (18:15 +0200)
committerSimon Ruderich <simon@ruderich.org>
Wed, 19 May 2021 05:54:00 +0000 (07:54 +0200)
cmd/safcm/sync.go
cmd/safcm/sync_sync.go
frontend/changes.go [moved from cmd/safcm/sync_changes.go with 76% similarity]
frontend/changes_test.go [moved from cmd/safcm/sync_changes_test.go with 96% similarity]
frontend/term.go [moved from cmd/safcm/term.go with 97% similarity]
frontend/term_test.go [moved from cmd/safcm/term_test.go with 99% similarity]

index 10edc68755e98c81e2c890745d3e3f706d3a3691..f1877cffde6b9b42b18955587192a19fda43127d 100644 (file)
@@ -214,11 +214,11 @@ are only available after the hosts were contacted.
 func logEvent(x frontend.Event, level safcm.LogLevel, isTTY bool, failed *bool) {
        // We have multiple event sources so this is somewhat ugly.
        var prefix, data string
-       var color Color
+       var color frontend.Color
        if x.Error != nil {
                prefix = "[error]"
                data = x.Error.Error()
-               color = ColorRed
+               color = frontend.ColorRed
                // We logged an error, tell the caller
                *failed = true
        } else if x.Log.Level != 0 {
@@ -237,7 +237,7 @@ func logEvent(x frontend.Event, level safcm.LogLevel, isTTY bool, failed *bool)
                        prefix = "[debug2]"
                default:
                        prefix = fmt.Sprintf("[INVALID=%d]", x.Log.Level)
-                       color = ColorRed
+                       color = frontend.ColorRed
                }
                data = x.Log.Text
        } else {
@@ -254,19 +254,19 @@ func logEvent(x frontend.Event, level safcm.LogLevel, isTTY bool, failed *bool)
                        x.ConnEvent.Data = "remote helper upload in progress"
                default:
                        prefix = fmt.Sprintf("[INVALID=%d]", x.ConnEvent.Type)
-                       color = ColorRed
+                       color = frontend.ColorRed
                }
                data = x.ConnEvent.Data
        }
 
        host := x.Host.Name()
        if color != 0 {
-               host = ColorString(isTTY, color, host)
+               host = frontend.ColorString(isTTY, color, host)
        }
        // Make sure to escape control characters to prevent terminal
        // injection attacks
        if !x.Escaped {
-               data = EscapeControlCharacters(isTTY, data)
+               data = frontend.EscapeControlCharacters(isTTY, data)
        }
        log.Printf("%-9s [%s] %s", prefix, host, data)
 }
index 3f0c30b0e88e88baa2044212ce0c84646b692ea9..7e4d225705eb46dae48c851d033d7364d4eff8cf 100644 (file)
@@ -26,6 +26,7 @@ import (
 
        "ruderich.org/simon/safcm"
        "ruderich.org/simon/safcm/cmd/safcm/config"
+       "ruderich.org/simon/safcm/frontend"
        "ruderich.org/simon/safcm/rpc"
 )
 
@@ -44,7 +45,12 @@ func (s *Sync) hostSync(conn *rpc.Conn, detectedGroups []string) error {
        }
 
        // Display changes
-       changes := s.formatChanges(resp)
+       c := frontend.Changes{
+               DryRun: s.config.DryRun,
+               Quiet:  s.config.Quiet,
+               IsTTY:  s.isTTY,
+       }
+       changes := c.FormatChanges(resp)
        if changes != "" {
                s.log(safcm.LogInfo, true, changes)
        }
similarity index 76%
rename from cmd/safcm/sync_changes.go
rename to frontend/changes.go
index 2650bb46062b33ab0f86e75d9b0f0cb1643bf556..351cdfac181a7a054350584453d5133e3606b371 100644 (file)
@@ -1,4 +1,4 @@
-// "sync" sub-command: format changes
+// Frontend: Format changes
 
 // Copyright (C) 2021  Simon Ruderich
 //
@@ -15,7 +15,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package main
+package frontend
 
 import (
        "fmt"
@@ -30,23 +30,29 @@ import (
 // the remote helper is untrusted and must be either escaped with %q or by
 // calling EscapeControlCharacters().
 
-func (s *Sync) formatChanges(resp safcm.MsgSyncResp) string {
+type Changes struct {
+       DryRun bool
+       Quiet  bool
+       IsTTY  bool
+}
+
+func (c *Changes) FormatChanges(resp safcm.MsgSyncResp) string {
        var changes []string
        if len(resp.FileChanges) > 0 {
                changes = append(changes,
-                       s.formatFileChanges(resp.FileChanges))
+                       c.FormatFileChanges(resp.FileChanges))
        }
        if len(resp.PackageChanges) > 0 {
                changes = append(changes,
-                       s.formatPackageChanges(resp.PackageChanges))
+                       c.FormatPackageChanges(resp.PackageChanges))
        }
        if len(resp.ServiceChanges) > 0 {
                changes = append(changes,
-                       s.formatServiceChanges(resp.ServiceChanges))
+                       c.FormatServiceChanges(resp.ServiceChanges))
        }
        if len(resp.CommandChanges) > 0 {
                changes = append(changes,
-                       s.formatCommandChanges(resp.CommandChanges))
+                       c.FormatCommandChanges(resp.CommandChanges))
        }
        if len(changes) == 0 {
                // Notify user that the host was synced successfully
@@ -64,30 +70,30 @@ func (s *Sync) formatChanges(resp safcm.MsgSyncResp) string {
        return "\n" + x
 }
 
-func (s *Sync) formatFileChanges(changes []safcm.FileChange) string {
+func (c *Changes) FormatFileChanges(changes []safcm.FileChange) string {
        var buf strings.Builder
-       if s.config.DryRun {
+       if c.DryRun {
                fmt.Fprintf(&buf, "will change %d file(s): (dry-run)\n",
                        len(changes))
        } else {
                fmt.Fprintf(&buf, "changed %d file(s):\n", len(changes))
        }
        for _, x := range changes {
-               fmt.Fprintf(&buf, "%s:", s.formatTarget(x.Path))
+               fmt.Fprintf(&buf, "%s:", c.FormatTarget(x.Path))
 
                var info []string
                if x.Created {
                        info = append(info,
-                               ColorString(s.isTTY, ColorGreen, "created"),
-                               formatFileType(x.New),
-                               formatFileUserGroup(x.New),
-                               formatFilePerm(x.New),
+                               ColorString(c.IsTTY, ColorGreen, "created"),
+                               FormatFileType(x.New),
+                               FormatFileUserGroup(x.New),
+                               FormatFilePerm(x.New),
                        )
                } else {
                        if x.Old.Mode.Type() != x.New.Mode.Type() {
                                info = append(info, fmt.Sprintf("%s -> %s",
-                                       formatFileType(x.Old),
-                                       formatFileType(x.New),
+                                       FormatFileType(x.Old),
+                                       FormatFileType(x.New),
                                ))
                        }
                        if x.Old.User != x.New.User ||
@@ -95,15 +101,15 @@ func (s *Sync) formatFileChanges(changes []safcm.FileChange) string {
                                x.Old.Group != x.New.Group ||
                                x.Old.Gid != x.New.Gid {
                                info = append(info, fmt.Sprintf("%s -> %s",
-                                       formatFileUserGroup(x.Old),
-                                       formatFileUserGroup(x.New),
+                                       FormatFileUserGroup(x.Old),
+                                       FormatFileUserGroup(x.New),
                                ))
                        }
                        if config.FileModeToFullPerm(x.Old.Mode) !=
                                config.FileModeToFullPerm(x.New.Mode) {
                                info = append(info, fmt.Sprintf("%s -> %s",
-                                       formatFilePerm(x.Old),
-                                       formatFilePerm(x.New),
+                                       FormatFilePerm(x.Old),
+                                       FormatFilePerm(x.New),
                                ))
                        }
                }
@@ -113,13 +119,14 @@ func (s *Sync) formatFileChanges(changes []safcm.FileChange) string {
                }
 
                if x.DataDiff != "" {
-                       fmt.Fprintf(&buf, "\n%s", s.formatDiff(x.DataDiff))
+                       fmt.Fprintf(&buf, "\n%s", c.FormatDiff(x.DataDiff))
                }
                fmt.Fprintf(&buf, "\n")
        }
        return buf.String()
 }
-func formatFileType(info safcm.FileChangeInfo) string {
+
+func FormatFileType(info safcm.FileChangeInfo) string {
        switch info.Mode.Type() {
        case 0: // regular file
                return "file"
@@ -131,18 +138,18 @@ func formatFileType(info safcm.FileChangeInfo) string {
                return fmt.Sprintf("invalid type %v", info.Mode.Type())
        }
 }
-func formatFileUserGroup(info safcm.FileChangeInfo) string {
+func FormatFileUserGroup(info safcm.FileChangeInfo) string {
        return fmt.Sprintf("%s(%d) %s(%d)",
                EscapeControlCharacters(false, info.User), info.Uid,
                EscapeControlCharacters(false, info.Group), info.Gid)
 }
-func formatFilePerm(info safcm.FileChangeInfo) string {
+func FormatFilePerm(info safcm.FileChangeInfo) string {
        return fmt.Sprintf("%#o", config.FileModeToFullPerm(info.Mode))
 }
 
-func (s *Sync) formatPackageChanges(changes []safcm.PackageChange) string {
+func (c *Changes) FormatPackageChanges(changes []safcm.PackageChange) string {
        var buf strings.Builder
-       if s.config.DryRun {
+       if c.DryRun {
                fmt.Fprintf(&buf, "will install %d package(s): (dry-run)\n",
                        len(changes))
        } else {
@@ -150,14 +157,14 @@ func (s *Sync) formatPackageChanges(changes []safcm.PackageChange) string {
        }
        for _, x := range changes {
                // TODO: indicate if installation failed
-               fmt.Fprintf(&buf, "%s\n", s.formatTarget(x.Name))
+               fmt.Fprintf(&buf, "%s\n", c.FormatTarget(x.Name))
        }
        return buf.String()
 }
 
-func (s *Sync) formatServiceChanges(changes []safcm.ServiceChange) string {
+func (c *Changes) FormatServiceChanges(changes []safcm.ServiceChange) string {
        var buf strings.Builder
-       if s.config.DryRun {
+       if c.DryRun {
                fmt.Fprintf(&buf, "will modify %d service(s): (dry-run)\n",
                        len(changes))
        } else {
@@ -172,13 +179,13 @@ func (s *Sync) formatServiceChanges(changes []safcm.ServiceChange) string {
                        info = append(info, "enabled")
                }
                fmt.Fprintf(&buf, "%s: %s\n",
-                       s.formatTarget(x.Name),
+                       c.FormatTarget(x.Name),
                        strings.Join(info, ", "))
        }
        return buf.String()
 }
 
-func (s *Sync) formatCommandChanges(changes []safcm.CommandChange) string {
+func (c *Changes) FormatCommandChanges(changes []safcm.CommandChange) string {
        const indent = "   > "
 
        // Quiet hides all successful, non-trigger commands which produce no
@@ -188,7 +195,7 @@ func (s *Sync) formatCommandChanges(changes []safcm.CommandChange) string {
        // Instead, quiet shows them only when they produce output (e.g.
        // `ainsl`, `rm -v`) and thus modify the host's state.
        var noOutput int
-       if s.config.Quiet {
+       if c.Quiet {
                for _, x := range changes {
                        if x.Trigger == "" &&
                                x.Error == "" &&
@@ -199,18 +206,18 @@ func (s *Sync) formatCommandChanges(changes []safcm.CommandChange) string {
        }
 
        var buf strings.Builder
-       if s.config.DryRun {
+       if c.DryRun {
                fmt.Fprintf(&buf, "will execute %d command(s)", len(changes))
        } else {
                fmt.Fprintf(&buf, "executed %d command(s)", len(changes))
        }
-       if noOutput > 0 && !s.config.DryRun {
+       if noOutput > 0 && !c.DryRun {
                fmt.Fprintf(&buf, ", %d with no output (hidden)", noOutput)
        }
        if noOutput != len(changes) {
                fmt.Fprintf(&buf, ":")
        }
-       if s.config.DryRun {
+       if c.DryRun {
                fmt.Fprintf(&buf, " (dry-run)")
        }
        fmt.Fprintf(&buf, "\n")
@@ -220,7 +227,7 @@ func (s *Sync) formatCommandChanges(changes []safcm.CommandChange) string {
                        continue
                }
 
-               fmt.Fprintf(&buf, "%s", s.formatTarget(x.Command))
+               fmt.Fprintf(&buf, "%s", c.FormatTarget(x.Command))
                if x.Trigger != "" {
                        fmt.Fprintf(&buf, ", trigger for %q", x.Trigger)
                }
@@ -231,34 +238,34 @@ func (s *Sync) formatCommandChanges(changes []safcm.CommandChange) string {
                        // TODO: truncate very large outputs?
                        x := indentBlock(x.Output, indent)
                        fmt.Fprintf(&buf, ":\n%s",
-                               EscapeControlCharacters(s.isTTY, x))
+                               EscapeControlCharacters(c.IsTTY, x))
                }
                fmt.Fprintf(&buf, "\n")
        }
        return buf.String()
 }
 
-func (s *Sync) formatTarget(x string) string {
+func (c *Changes) FormatTarget(x string) string {
        x = fmt.Sprintf("%q", x) // escape!
-       return ColorString(s.isTTY, ColorCyan, x)
+       return ColorString(c.IsTTY, ColorCyan, x)
 }
 
-func (s *Sync) formatDiff(diff string) string {
+func (c *Changes) FormatDiff(diff string) string {
        const indent = "   "
 
        diff = indentBlock(diff, indent)
        // Never color diff content as we want to color the whole diff
        diff = EscapeControlCharacters(false, diff)
-       if !s.isTTY {
+       if !c.IsTTY {
                return diff
        }
 
        var res []string
        for _, x := range strings.Split(diff, "\n") {
                if strings.HasPrefix(x, indent+"+") {
-                       x = ColorString(s.isTTY, ColorGreen, x)
+                       x = ColorString(c.IsTTY, ColorGreen, x)
                } else if strings.HasPrefix(x, indent+"-") {
-                       x = ColorString(s.isTTY, ColorRed, x)
+                       x = ColorString(c.IsTTY, ColorRed, x)
                }
                res = append(res, x)
        }
similarity index 96%
rename from cmd/safcm/sync_changes_test.go
rename to frontend/changes_test.go
index 219373c9522e4edfba458d3dd410b306c7ccdb06..02a95c40c24101d1250b9edb031fc98ea6399428 100644 (file)
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package main
+package frontend
 
 import (
        "io/fs"
        "testing"
 
        "ruderich.org/simon/safcm"
-       "ruderich.org/simon/safcm/cmd/safcm/config"
        "ruderich.org/simon/safcm/testutil"
 )
 
@@ -157,15 +156,13 @@ func TestFormatChanges(t *testing.T) {
 
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
-                       s := &Sync{
-                               config: &config.Config{
-                                       DryRun: tc.dryRun,
-                                       Quiet:  tc.quiet,
-                               },
-                               isTTY: tc.isTTY,
+                       c := Changes{
+                               DryRun: tc.dryRun,
+                               Quiet:  tc.quiet,
+                               IsTTY:  tc.isTTY,
                        }
 
-                       res := s.formatChanges(tc.resp)
+                       res := c.FormatChanges(tc.resp)
                        testutil.AssertEqual(t, "res", res, tc.exp)
                })
        }
@@ -656,14 +653,12 @@ func TestFormatFileChanges(t *testing.T) {
 
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
-                       s := &Sync{
-                               config: &config.Config{
-                                       DryRun: tc.dryRun,
-                               },
-                               isTTY: tc.isTTY,
+                       c := Changes{
+                               DryRun: tc.dryRun,
+                               IsTTY:  tc.isTTY,
                        }
 
-                       res := s.formatFileChanges(tc.changes)
+                       res := c.FormatFileChanges(tc.changes)
                        testutil.AssertEqual(t, "res", res, tc.exp)
                })
        }
@@ -773,14 +768,12 @@ func TestFormatPackageChanges(t *testing.T) {
 
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
-                       s := &Sync{
-                               config: &config.Config{
-                                       DryRun: tc.dryRun,
-                               },
-                               isTTY: tc.isTTY,
+                       c := Changes{
+                               DryRun: tc.dryRun,
+                               IsTTY:  tc.isTTY,
                        }
 
-                       res := s.formatPackageChanges(tc.changes)
+                       res := c.FormatPackageChanges(tc.changes)
                        testutil.AssertEqual(t, "res", res, tc.exp)
                })
        }
@@ -931,14 +924,12 @@ func TestFormatServiceChanges(t *testing.T) {
 
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
-                       s := &Sync{
-                               config: &config.Config{
-                                       DryRun: tc.dryRun,
-                               },
-                               isTTY: tc.isTTY,
+                       c := Changes{
+                               DryRun: tc.dryRun,
+                               IsTTY:  tc.isTTY,
                        }
 
-                       res := s.formatServiceChanges(tc.changes)
+                       res := c.FormatServiceChanges(tc.changes)
                        testutil.AssertEqual(t, "res", res, tc.exp)
                })
        }
@@ -1230,15 +1221,13 @@ func TestFormatCommandChanges(t *testing.T) {
 
        for _, tc := range tests {
                t.Run(tc.name, func(t *testing.T) {
-                       s := &Sync{
-                               config: &config.Config{
-                                       DryRun: tc.dryRun,
-                                       Quiet:  tc.quiet,
-                               },
-                               isTTY: tc.isTTY,
+                       c := Changes{
+                               DryRun: tc.dryRun,
+                               Quiet:  tc.quiet,
+                               IsTTY:  tc.isTTY,
                        }
 
-                       res := s.formatCommandChanges(tc.changes)
+                       res := c.FormatCommandChanges(tc.changes)
                        testutil.AssertEqual(t, "res", res, tc.exp)
                })
        }
similarity index 97%
rename from cmd/safcm/term.go
rename to frontend/term.go
index 47f7d62cc1b14fe0ddbe3239d597e1d9f4b68ecc..f50f16264cdcae8590278e67e1f8208772b97fd1 100644 (file)
@@ -1,4 +1,4 @@
-// Functions for terminal output
+// Frontend: Functions for terminal output
 
 // Copyright (C) 2021  Simon Ruderich
 //
@@ -15,7 +15,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package main
+package frontend
 
 import (
        "fmt"
similarity index 99%
rename from cmd/safcm/term_test.go
rename to frontend/term_test.go
index 479d7e8e197f7ab951331adec562c6e8671e21e2..7569a9934cc1a60a10ba99619e4eee669e7b86a1 100644 (file)
@@ -13,7 +13,7 @@
 // You should have received a copy of the GNU General Public License
 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
-package main
+package frontend
 
 import (
        "testing"