// goredo -- djb's redo implementation on pure Go // Copyright (C) 2020-2024 Sergey Matveev // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, version 3 of the License. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . package main import ( "flag" "fmt" "io" "log" "os" "path" "strings" ) const ( CleanupFull = "full" CleanupLog = "log" CleanupTmp = "tmp" CleanupLock = "lock" ) var DryRun *bool func init() { if CmdName() != CmdNameRedoCleanup { return } DryRun = flag.Bool("n", false, "do no delete files during cleanup, just show them") } func redoDirClean(root, what string) error { root = mustAbs(root) dir, err := os.Open(root) if err != nil { return ErrLine(err) } defer dir.Close() for { entries, err := dir.ReadDir(1 << 10) if err != nil { if err == io.EOF { break } return ErrLine(err) } var pth string for _, entry := range entries { pth = cwdMustRel(root, entry.Name()) switch what { case CleanupLog: if strings.HasSuffix(entry.Name(), LogSuffix) || strings.HasSuffix(entry.Name(), LogRecSuffix) { fmt.Println(pth) if !*DryRun { if err = os.Remove(pth); err != nil { return ErrLine(err) } } } case CleanupLock: if strings.HasSuffix(entry.Name(), LockSuffix) { fmt.Println(pth) if !*DryRun { if err = os.Remove(pth); err != nil { return ErrLine(err) } } } case CleanupTmp: if strings.HasPrefix(entry.Name(), TmpPrefix) { fmt.Println(pth) if !*DryRun { if err = os.Remove(pth); err != nil { return ErrLine(err) } } } default: log.Fatal("unknown cleanup target") } } } return nil } func cleanupWalker(root, what string) error { root = mustAbs(root) dir, err := os.Open(root) if err != nil { return ErrLine(err) } defer dir.Close() for { entries, err := dir.ReadDir(1 << 10) if err != nil { if err == io.EOF { break } return ErrLine(err) } for _, entry := range entries { pth := path.Join(root, entry.Name()) pthRel := cwdMustRel(root, entry.Name()) if entry.IsDir() { if entry.Name() == RedoDir { if what == CleanupFull { fmt.Println(pthRel) if !*DryRun { err = ErrLine(os.RemoveAll(pth)) } } else { err = redoDirClean(pth, what) } } else if (what == CleanupTmp || what == CleanupFull) && strings.HasPrefix(entry.Name(), TmpPrefix) { fmt.Println(pthRel) if !*DryRun { err = ErrLine(os.RemoveAll(pth)) } } else { err = cleanupWalker(pth, what) } if err != nil { return err } continue } if (what == CleanupTmp || what == CleanupFull) && strings.HasPrefix(entry.Name(), TmpPrefix) { fmt.Println(pthRel) if !*DryRun { if err = os.Remove(pth); err != nil { return ErrLine(err) } } } } } return nil }