github.com/kaydxh/golang@v0.0.131/pkg/file-cleanup/file_cleaner.go (about) 1 /* 2 *Copyright (c) 2022, kaydxh 3 * 4 *Permission is hereby granted, free of charge, to any person obtaining a copy 5 *of this software and associated documentation files (the "Software"), to deal 6 *in the Software without restriction, including without limitation the rights 7 *to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 *copies of the Software, and to permit persons to whom the Software is 9 *furnished to do so, subject to the following conditions: 10 * 11 *The above copyright notice and this permission notice shall be included in all 12 *copies or substantial portions of the Software. 13 * 14 *THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 *IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 *FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 *AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 *LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 *OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 *SOFTWARE. 21 */ 22 package filecleanup 23 24 import ( 25 "os" 26 "sort" 27 "time" 28 29 errors_ "github.com/kaydxh/golang/go/errors" 30 filepath_ "github.com/kaydxh/golang/go/path/filepath" 31 ) 32 33 type FileCleaner struct { 34 //filedir string 35 //pattern string 36 //maxAge is the maximum number of time to retain old files, 0 is unlimited 37 maxAge time.Duration 38 //maxCount is the maximum number to retain old files, 0 is unlimited 39 maxCount int64 40 } 41 42 func FileCleanup(pattern string, options ...FileCleanerOption) error { 43 var cleaner FileCleaner 44 cleaner.ApplyOptions(options...) 45 46 matches, err := filepath_.Glob(pattern) 47 if err != nil { 48 return err 49 } 50 51 now := time.Now() 52 53 removeMatches := make([]string, 0, len(matches)) 54 for _, path := range matches { 55 fi, err := os.Stat(path) 56 if err != nil { 57 continue 58 } 59 60 // maxAge 0 is unlimited 61 if cleaner.maxAge <= 0 { 62 continue 63 } 64 65 if now.Sub(fi.ModTime()) < cleaner.maxAge { 66 continue 67 } 68 69 removeMatches = append(removeMatches, path) 70 } 71 72 if cleaner.maxCount > 0 { 73 if cleaner.maxCount < int64(len(matches)) { 74 75 removeCount := len(matches) - int(cleaner.maxCount) - len(removeMatches) 76 if removeCount > 0 { 77 sort.Sort(RotatedFiles(matches)) 78 removeMatches = append( 79 removeMatches, 80 matches[len(removeMatches):len(removeMatches)+removeCount]..., 81 ) 82 } 83 } 84 85 } 86 87 //clean 88 var errs []error 89 for _, file := range removeMatches { 90 err = os.Remove(file) 91 if err != nil { 92 errs = append(errs, err) 93 } 94 } 95 96 return errors_.NewAggregate(errs) 97 } 98 99 type RotatedFiles []string 100 101 func (f RotatedFiles) Len() int { 102 return len(f) 103 } 104 105 func (f RotatedFiles) Swap(i, j int) { 106 f[i], f[j] = f[j], f[i] 107 } 108 109 func (f RotatedFiles) Less(i, j int) bool { 110 fi, err := os.Stat(f[i]) 111 if err != nil { 112 return false 113 } 114 115 fj, err := os.Stat(f[j]) 116 if err != nil { 117 return false 118 } 119 120 if fi.ModTime().Equal(fj.ModTime()) { 121 if len(f[i]) == len(f[j]) { 122 return f[i] < f[j] 123 } 124 125 return len(f[i]) < len(f[j]) // foo.9 < foo.10 126 } 127 128 return fi.ModTime().Before(fj.ModTime()) 129 130 }