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  }