Hide unlink option when repo file missing

This commit is contained in:
2026-02-19 20:12:48 +00:00
parent 5affeb76ee
commit 4bfc39c2f2

115
main.go
View File

@@ -835,7 +835,18 @@ func handleStaleLinks(stales []string) error {
reader := bufio.NewReader(os.Stdin) reader := bufio.NewReader(os.Stdin)
for _, path := range stales { for _, path := range stales {
fmt.Printf("stale: %s\n", path) fmt.Printf("stale: %s\n", path)
fmt.Print("action [p=prune, u=unlink, i=ignore]: ")
canUnlink, err := staleHasRepoFile(path, repo)
if err != nil {
return err
}
prompt := "action [p=prune, u=unlink, i=ignore]: "
if !canUnlink {
prompt = "action [p=prune, i=ignore]: "
}
fmt.Print(prompt)
choice, err := reader.ReadString('\n') choice, err := reader.ReadString('\n')
if err != nil { if err != nil {
return err return err
@@ -851,7 +862,7 @@ func handleStaleLinks(stales []string) error {
fmt.Printf("removed %s\n", path) fmt.Printf("removed %s\n", path)
continue continue
} }
if choice == "u" { if choice == "u" && canUnlink {
if err := unlinkStale(path, repo); err != nil { if err := unlinkStale(path, repo); err != nil {
return err return err
} }
@@ -863,55 +874,29 @@ func handleStaleLinks(stales []string) error {
return nil return nil
} }
func unlinkStale(targetPath, repo string) error { func staleHasRepoFile(targetPath, repo string) (bool, error) {
info, err := os.Lstat(targetPath) repoPath, err := repoPathForTarget(targetPath, repo)
if err != nil { if err != nil {
return err return false, err
} }
if info.Mode()&os.ModeSymlink == 0 { if repoPath == "" {
return nil return false, nil
} }
src, err := os.Readlink(targetPath)
if err != nil {
return err
}
if !filepath.IsAbs(src) {
src = filepath.Join(filepath.Dir(targetPath), src)
}
src = filepath.Clean(src)
repoAbs, err := filepath.Abs(repo)
if err != nil {
return err
}
rel, err := filepath.Rel(repoAbs, src)
if err != nil {
return err
}
if strings.HasPrefix(rel, "..") {
return nil
}
parts := strings.Split(rel, string(os.PathSeparator))
if len(parts) < 3 {
return nil
}
if parts[1] != filesDirName {
return nil
}
repoPath := filepath.Join(repoAbs, rel)
if _, err := os.Stat(repoPath); errors.Is(err, os.ErrNotExist) { if _, err := os.Stat(repoPath); errors.Is(err, os.ErrNotExist) {
if err := os.Remove(targetPath); err != nil { return false, nil
} else if err != nil {
return false, err
}
return true, nil
}
func unlinkStale(targetPath, repo string) error {
repoPath, err := repoPathForTarget(targetPath, repo)
if err != nil {
return err return err
} }
fmt.Printf("removed %s (missing repo file)\n", targetPath) if repoPath == "" {
return nil return nil
} else if err != nil {
return err
} }
if err := os.Remove(targetPath); err != nil { if err := os.Remove(targetPath); err != nil {
@@ -930,6 +915,48 @@ func unlinkStale(targetPath, repo string) error {
return nil return nil
} }
func repoPathForTarget(targetPath, repo string) (string, error) {
info, err := os.Lstat(targetPath)
if err != nil {
return "", err
}
if info.Mode()&os.ModeSymlink == 0 {
return "", nil
}
src, err := os.Readlink(targetPath)
if err != nil {
return "", err
}
if !filepath.IsAbs(src) {
src = filepath.Join(filepath.Dir(targetPath), src)
}
src = filepath.Clean(src)
repoAbs, err := filepath.Abs(repo)
if err != nil {
return "", err
}
rel, err := filepath.Rel(repoAbs, src)
if err != nil {
return "", err
}
if strings.HasPrefix(rel, "..") {
return "", nil
}
parts := strings.Split(rel, string(os.PathSeparator))
if len(parts) < 3 {
return "", nil
}
if parts[1] != filesDirName {
return "", nil
}
return filepath.Join(repoAbs, rel), nil
}
func restorePackage(filesDir, targetRoot string, dryRun bool) error { func restorePackage(filesDir, targetRoot string, dryRun bool) error {
filesAbs, err := filepath.Abs(filesDir) filesAbs, err := filepath.Abs(filesDir)
if err != nil { if err != nil {