Add prune option to apply
This commit is contained in:
111
main.go
111
main.go
@@ -33,7 +33,7 @@ func main() {
|
||||
var err error
|
||||
switch args[0] {
|
||||
case "apply":
|
||||
err = applyCmd()
|
||||
err = applyCmd(args[1:])
|
||||
case "add":
|
||||
err = addCmd(args[1:])
|
||||
case "help", "-h", "--help":
|
||||
@@ -52,11 +52,20 @@ func main() {
|
||||
func usage() {
|
||||
fmt.Println("sigil: minimal dotfile symlink manager")
|
||||
fmt.Println("usage:")
|
||||
fmt.Println(" sigil apply")
|
||||
fmt.Println(" sigil apply [--prune]")
|
||||
fmt.Println(" sigil add <path>")
|
||||
}
|
||||
|
||||
func applyCmd() error {
|
||||
func applyCmd(args []string) error {
|
||||
prune := false
|
||||
for _, arg := range args {
|
||||
if arg == "--prune" {
|
||||
prune = true
|
||||
continue
|
||||
}
|
||||
return fmt.Errorf("unknown flag %q", arg)
|
||||
}
|
||||
|
||||
repo, err := repoPath()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -67,6 +76,8 @@ func applyCmd() error {
|
||||
return err
|
||||
}
|
||||
|
||||
var stales []string
|
||||
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() || strings.HasPrefix(entry.Name(), ".") {
|
||||
continue
|
||||
@@ -102,6 +113,28 @@ func applyCmd() error {
|
||||
if err := applyPackage(filesDir, targetRoot); err != nil {
|
||||
return fmt.Errorf("%s: %w", entry.Name(), err)
|
||||
}
|
||||
|
||||
stale, err := findStaleLinks(filesDir, targetRoot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %w", entry.Name(), err)
|
||||
}
|
||||
stales = append(stales, stale...)
|
||||
}
|
||||
|
||||
if len(stales) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
if prune {
|
||||
return removeLinks(stales)
|
||||
}
|
||||
|
||||
ok, err := promptYesNo("Found stale links. Prune them?", false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ok {
|
||||
return removeLinks(stales)
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -395,6 +428,24 @@ func promptWithDefault(reader *bufio.Reader, label, def string) string {
|
||||
return text
|
||||
}
|
||||
|
||||
func promptYesNo(message string, def bool) (bool, error) {
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
defLabel := "y/N"
|
||||
if def {
|
||||
defLabel = "Y/n"
|
||||
}
|
||||
fmt.Printf("%s [%s]: ", message, defLabel)
|
||||
text, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
text = strings.TrimSpace(strings.ToLower(text))
|
||||
if text == "" {
|
||||
return def, nil
|
||||
}
|
||||
return text == "y" || text == "yes", nil
|
||||
}
|
||||
|
||||
func moveDirContents(srcDir, destDir string) error {
|
||||
entries, err := os.ReadDir(srcDir)
|
||||
if err != nil {
|
||||
@@ -418,3 +469,57 @@ func moveDirContents(srcDir, destDir string) error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func findStaleLinks(filesDir, targetRoot string) ([]string, error) {
|
||||
known := make(map[string]struct{})
|
||||
|
||||
err := filepath.WalkDir(filesDir, func(path string, entry fs.DirEntry, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if path == filesDir || entry.IsDir() {
|
||||
return nil
|
||||
}
|
||||
rel, err := filepath.Rel(filesDir, path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
known[filepath.Join(targetRoot, rel)] = struct{}{}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var stale []string
|
||||
for targetPath := range known {
|
||||
info, err := os.Lstat(targetPath)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if info.Mode()&os.ModeSymlink == 0 {
|
||||
continue
|
||||
}
|
||||
src, err := os.Readlink(targetPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := os.Stat(src); errors.Is(err, os.ErrNotExist) {
|
||||
stale = append(stale, targetPath)
|
||||
}
|
||||
}
|
||||
|
||||
return stale, nil
|
||||
}
|
||||
|
||||
func removeLinks(paths []string) error {
|
||||
for _, path := range paths {
|
||||
if err := os.Remove(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user