mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-07 20:30:36 -05:00
parent
4b286b9d27
commit
180195aa34
2 changed files with 61 additions and 1 deletions
12
cache/filecache/filecache.go
vendored
12
cache/filecache/filecache.go
vendored
|
@ -15,6 +15,7 @@ package filecache
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
@ -31,6 +32,9 @@ import (
|
|||
"github.com/spf13/afero"
|
||||
)
|
||||
|
||||
// ErrFatal can be used to signal an unrecoverable error.
|
||||
var ErrFatal = errors.New("fatal filecache error")
|
||||
|
||||
const (
|
||||
filecacheRootDirname = "filecache"
|
||||
)
|
||||
|
@ -137,7 +141,13 @@ func (c *Cache) ReadOrCreate(id string,
|
|||
if r := c.getOrRemove(id); r != nil {
|
||||
err = read(info, r)
|
||||
defer r.Close()
|
||||
return
|
||||
if err == nil || err == ErrFatal {
|
||||
// See https://github.com/gohugoio/hugo/issues/6401
|
||||
// To recover from file corruption we handle read errors
|
||||
// as the cache item was not found.
|
||||
// Any file permission issue will also fail in the next step.
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
f, err := helpers.OpenFileForWriting(c.Fs, id)
|
||||
|
|
50
cache/filecache/filecache_test.go
vendored
50
cache/filecache/filecache_test.go
vendored
|
@ -14,6 +14,7 @@
|
|||
package filecache
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
@ -243,6 +244,55 @@ dir = "/cache/c"
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
func TestFileCacheReadOrCreateErrorInRead(t *testing.T) {
|
||||
t.Parallel()
|
||||
c := qt.New(t)
|
||||
|
||||
var result string
|
||||
|
||||
rf := func(failLevel int) func(info ItemInfo, r io.Reader) error {
|
||||
|
||||
return func(info ItemInfo, r io.Reader) error {
|
||||
if failLevel > 0 {
|
||||
if failLevel > 1 {
|
||||
return ErrFatal
|
||||
}
|
||||
return errors.New("fail")
|
||||
}
|
||||
|
||||
b, _ := ioutil.ReadAll(r)
|
||||
result = string(b)
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
bf := func(s string) func(info ItemInfo, w io.WriteCloser) error {
|
||||
return func(info ItemInfo, w io.WriteCloser) error {
|
||||
defer w.Close()
|
||||
result = s
|
||||
_, err := w.Write([]byte(s))
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
cache := NewCache(afero.NewMemMapFs(), 100*time.Hour, "")
|
||||
|
||||
const id = "a32"
|
||||
|
||||
_, err := cache.ReadOrCreate(id, rf(0), bf("v1"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(result, qt.Equals, "v1")
|
||||
_, err = cache.ReadOrCreate(id, rf(0), bf("v2"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(result, qt.Equals, "v1")
|
||||
_, err = cache.ReadOrCreate(id, rf(1), bf("v3"))
|
||||
c.Assert(err, qt.IsNil)
|
||||
c.Assert(result, qt.Equals, "v3")
|
||||
_, err = cache.ReadOrCreate(id, rf(2), bf("v3"))
|
||||
c.Assert(err, qt.Equals, ErrFatal)
|
||||
}
|
||||
|
||||
func TestCleanID(t *testing.T) {
|
||||
c := qt.New(t)
|
||||
c.Assert(cleanID(filepath.FromSlash("/a/b//c.txt")), qt.Equals, filepath.FromSlash("a/b/c.txt"))
|
||||
|
|
Loading…
Reference in a new issue