From a4d77f8f99ac72792d57150c361b069fb424e8ae Mon Sep 17 00:00:00 2001 From: Ettore Di Giacinto Date: Sat, 24 Apr 2021 19:21:15 +0200 Subject: [PATCH] Fixup clean path uninstall While uninstalling, we weren't checking if we left any empty dir behind. Now we walk the full path to the file in the artifact, and check each subdir if it's empty. If it is, we delete it as it is claimed by the package --- pkg/helpers/match.go | 9 +++++++ pkg/installer/installer.go | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/pkg/helpers/match.go b/pkg/helpers/match.go index ade789ac..502c447d 100644 --- a/pkg/helpers/match.go +++ b/pkg/helpers/match.go @@ -17,9 +17,18 @@ package helpers import ( + "reflect" "regexp" ) +func ReverseAny(s interface{}) { + n := reflect.ValueOf(s).Len() + swap := reflect.Swapper(s) + for i, j := 0, n-1; i < j; i, j = i+1, j-1 { + swap(i, j) + } +} + func MapMatchRegex(m *map[string]string, r *regexp.Regexp) bool { ans := false diff --git a/pkg/installer/installer.go b/pkg/installer/installer.go index b834419e..c2e62e1a 100644 --- a/pkg/installer/installer.go +++ b/pkg/installer/installer.go @@ -889,6 +889,51 @@ func (l *LuetInstaller) installerWorker(i int, wg *sync.WaitGroup, c <-chan Arti return nil } +func checkAndPrunePath(path string) { + // check if now the target path is empty + targetPath := filepath.Dir(path) + + fi, err := os.Lstat(targetPath) + if err != nil { + Warning("Dir not found (it was before?) ", err.Error()) + return + } + + switch mode := fi.Mode(); { + case mode.IsDir(): + files, err := ioutil.ReadDir(targetPath) + if err != nil { + Warning("Failed reading folder", targetPath, err.Error()) + } + if len(files) != 0 { + Debug("Preserving not-empty folder", targetPath) + return + } + } + if err = os.Remove(targetPath); err != nil { + Warning("Failed removing file (maybe not present in the system target anymore ?)", targetPath, err.Error()) + } +} + +// We will try to cleanup every path from the file, if the folders left behind are empty +func pruneEmptyFilePath(path string) { + checkAndPrunePath(path) + + // A path is for e.g. /usr/bin/bar + // we want to create an array as "/usr", "/usr/bin", "/usr/bin/bar" + paths := strings.Split(path, string(os.PathSeparator)) + currentPath := filepath.Join(string(os.PathSeparator), paths[0]) + allPaths := []string{currentPath} + for _, p := range paths[1:] { + currentPath = filepath.Join(currentPath, p) + allPaths = append(allPaths, currentPath) + } + helpers.ReverseAny(allPaths) + for _, p := range allPaths { + checkAndPrunePath(p) + } +} + func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { var cp *config.ConfigProtect annotationDir := "" @@ -950,6 +995,8 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { if err = os.Remove(target); err != nil { Warning("Failed removing file (maybe not present in the system target anymore ?)", target, err.Error()) } + + pruneEmptyFilePath(target) } for _, f := range notPresent { @@ -963,6 +1010,8 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error { if err = os.Remove(target); err != nil { Debug("Failed removing file (not present in the system target)", target, err.Error()) } + + pruneEmptyFilePath(target) } err = s.Database.RemovePackageFiles(p)