mirror of
https://github.com/lukaszraczylo/harness-sync.git
synced 2026-10-15 01:07:27 +00:00
feat(cli): add apply subcommand
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/lukaszraczylo/harness-sync/internal/adapter"
|
||||
"github.com/lukaszraczylo/harness-sync/internal/canonical"
|
||||
)
|
||||
|
||||
// NewShow returns the `show` subcommand which prints the files each adapter
|
||||
// would manage if `apply` were run now. Useful for auditing what harness-sync
|
||||
// will write to your system before committing to it.
|
||||
func NewShow(reg *adapter.Registry) *cobra.Command {
|
||||
var (
|
||||
root string
|
||||
all bool
|
||||
)
|
||||
cmd := &cobra.Command{
|
||||
Use: "show [harness...]",
|
||||
Short: "List files harness-sync manages for each harness",
|
||||
Long: `Renders the canonical bundle through each adapter and prints
|
||||
the resulting targets without writing anything. By default, shows only detected
|
||||
harnesses; pass --all to include adapters whose harness is not installed, or
|
||||
positional args to select specific harnesses.`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
r, err := resolveRoot(root)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b, err := canonical.Load(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var selected []adapter.Adapter
|
||||
switch {
|
||||
case len(args) > 0:
|
||||
for _, name := range args {
|
||||
a, ok := reg.Get(name)
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown adapter %q", name)
|
||||
}
|
||||
selected = append(selected, a)
|
||||
}
|
||||
case all:
|
||||
selected = reg.All()
|
||||
default:
|
||||
for _, a := range reg.All() {
|
||||
if a.Detect() {
|
||||
selected = append(selected, a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
w := cmd.OutOrStdout()
|
||||
for _, a := range selected {
|
||||
fs, err := a.Render(b)
|
||||
if err != nil {
|
||||
if _, werr := fmt.Fprintf(w, "%s: render error: %v\n", a.Name(), err); werr != nil {
|
||||
return werr
|
||||
}
|
||||
continue
|
||||
}
|
||||
if _, werr := fmt.Fprintf(w, "%s (%s)\n", a.Name(), detectLabel(a)); werr != nil {
|
||||
return werr
|
||||
}
|
||||
var iterErr error
|
||||
fs.ForEach(func(f adapter.File) {
|
||||
if iterErr != nil {
|
||||
return
|
||||
}
|
||||
switch f.Kind {
|
||||
case adapter.SymlinkDir, adapter.SymlinkFile:
|
||||
_, iterErr = fmt.Fprintf(w, " %-12s %s -> %s\n",
|
||||
f.Kind.String(), short(f.Dest), short(f.SymlinkTarget))
|
||||
case adapter.RenderedFile:
|
||||
_, iterErr = fmt.Fprintf(w, " %-12s %s (%d bytes)\n",
|
||||
f.Kind.String(), short(f.Dest), len(f.Content))
|
||||
}
|
||||
})
|
||||
if iterErr != nil {
|
||||
return iterErr
|
||||
}
|
||||
if _, werr := fmt.Fprintln(w); werr != nil {
|
||||
return werr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringVar(&root, "root", "", "canonical root (default ~/.config/harness-sync)")
|
||||
cmd.Flags().BoolVar(&all, "all", false, "include adapters whose harness is not detected")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func detectLabel(a adapter.Adapter) string {
|
||||
if a.Detect() {
|
||||
return "detected"
|
||||
}
|
||||
return "not detected"
|
||||
}
|
||||
|
||||
// short collapses the user's home dir to "~" for cleaner output.
|
||||
func short(p string) string {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil || home == "" {
|
||||
return p
|
||||
}
|
||||
if p == home {
|
||||
return "~"
|
||||
}
|
||||
if len(p) > len(home) && p[:len(home)+1] == home+string(filepath.Separator) {
|
||||
return "~" + p[len(home):]
|
||||
}
|
||||
return p
|
||||
}
|
||||
Reference in New Issue
Block a user