github.com/anakojm/hugo-katex@v0.0.0-20231023141351-42d6f5de9c0b/cache/filecache/filecache_pruner.go (about)

     1  // Copyright 2018 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package filecache
    15  
    16  import (
    17  	"fmt"
    18  	"io"
    19  	"os"
    20  
    21  	"github.com/gohugoio/hugo/common/herrors"
    22  	"github.com/gohugoio/hugo/hugofs"
    23  
    24  	"github.com/spf13/afero"
    25  )
    26  
    27  // Prune removes expired and unused items from this cache.
    28  // The last one requires a full build so the cache usage can be tracked.
    29  // Note that we operate directly on the filesystem here, so this is not
    30  // thread safe.
    31  func (c Caches) Prune() (int, error) {
    32  	counter := 0
    33  	for k, cache := range c {
    34  		count, err := cache.Prune(false)
    35  
    36  		counter += count
    37  
    38  		if err != nil {
    39  			if herrors.IsNotExist(err) {
    40  				continue
    41  			}
    42  			return counter, fmt.Errorf("failed to prune cache %q: %w", k, err)
    43  		}
    44  
    45  	}
    46  
    47  	return counter, nil
    48  }
    49  
    50  // Prune removes expired and unused items from this cache.
    51  // If force is set, everything will be removed not considering expiry time.
    52  func (c *Cache) Prune(force bool) (int, error) {
    53  	if c.pruneAllRootDir != "" {
    54  		return c.pruneRootDir(force)
    55  	}
    56  	if err := c.init(); err != nil {
    57  		return 0, err
    58  	}
    59  
    60  	counter := 0
    61  
    62  	err := afero.Walk(c.Fs, "", func(name string, info os.FileInfo, err error) error {
    63  
    64  		if info == nil {
    65  			return nil
    66  		}
    67  
    68  		name = cleanID(name)
    69  
    70  		if info.IsDir() {
    71  			f, err := c.Fs.Open(name)
    72  
    73  			if err != nil {
    74  				// This cache dir may not exist.
    75  				return nil
    76  			}
    77  			_, err = f.Readdirnames(1)
    78  			f.Close()
    79  			if err == io.EOF {
    80  				// Empty dir.
    81  				if name == "." {
    82  					// e.g. /_gen/images -- keep it even if empty.
    83  					err = nil
    84  				} else {
    85  					err = c.Fs.Remove(name)
    86  				}
    87  			}
    88  
    89  			if err != nil && !herrors.IsNotExist(err) {
    90  				return err
    91  			}
    92  
    93  			return nil
    94  		}
    95  
    96  		shouldRemove := force || c.isExpired(info.ModTime())
    97  
    98  		if !shouldRemove && len(c.nlocker.seen) > 0 {
    99  			// Remove it if it's not been touched/used in the last build.
   100  			_, seen := c.nlocker.seen[name]
   101  			shouldRemove = !seen
   102  		}
   103  
   104  		if shouldRemove {
   105  			err := c.Fs.Remove(name)
   106  			if err == nil {
   107  				counter++
   108  			}
   109  
   110  			if err != nil && !herrors.IsNotExist(err) {
   111  				return err
   112  			}
   113  
   114  		}
   115  
   116  		return nil
   117  	})
   118  
   119  	return counter, err
   120  }
   121  
   122  func (c *Cache) pruneRootDir(force bool) (int, error) {
   123  	if err := c.init(); err != nil {
   124  		return 0, err
   125  	}
   126  	info, err := c.Fs.Stat(c.pruneAllRootDir)
   127  	if err != nil {
   128  		if herrors.IsNotExist(err) {
   129  			return 0, nil
   130  		}
   131  		return 0, err
   132  	}
   133  
   134  	if !force && !c.isExpired(info.ModTime()) {
   135  		return 0, nil
   136  	}
   137  
   138  	return hugofs.MakeReadableAndRemoveAllModulePkgDir(c.Fs, c.pruneAllRootDir)
   139  }