summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-12-14 12:20:13 +0100
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2022-12-14 13:51:06 +0100
commitad2059878a8d6ace9669ccc5ff0a8d4e5811ad37 (patch)
tree34d88705ab22e5b54949a6ce48e028b1fc2ab7e6
parent87e898a17a52b5338bc9d554dd12b99a54aa2431 (diff)
Also consider wrapped errors when checking for file IsNotExist errors
Fixes #10534
-rw-r--r--cache/filecache/filecache_pruner.go9
-rw-r--r--commands/hugo.go4
-rw-r--r--commands/static_syncer.go4
-rw-r--r--common/herrors/errors.go21
-rw-r--r--common/herrors/errors_test.go36
-rw-r--r--helpers/path.go3
-rw-r--r--hugofs/decorators.go3
-rw-r--r--hugofs/rootmapping_fs.go3
-rw-r--r--hugofs/slice_fs.go5
-rw-r--r--hugofs/walk.go5
-rw-r--r--hugolib/codeowners.go4
-rw-r--r--hugolib/filesystems/basefs.go7
-rw-r--r--hugolib/page.go3
-rw-r--r--hugolib/pages_capture.go4
-rw-r--r--hugolib/site.go20
-rw-r--r--magefile.go2
-rw-r--r--modules/client.go8
-rw-r--r--modules/collect.go3
-rw-r--r--resources/resource_spec.go2
-rw-r--r--tpl/tplimpl/template.go3
-rw-r--r--watcher/filenotify/poller.go9
21 files changed, 110 insertions, 48 deletions
diff --git a/cache/filecache/filecache_pruner.go b/cache/filecache/filecache_pruner.go
index e5e571972..5734af199 100644
--- a/cache/filecache/filecache_pruner.go
+++ b/cache/filecache/filecache_pruner.go
@@ -18,6 +18,7 @@ import (
"io"
"os"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/hugofs"
"github.com/spf13/afero"
@@ -36,7 +37,7 @@ func (c Caches) Prune() (int, error) {
counter += count
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
continue
}
return counter, fmt.Errorf("failed to prune cache %q: %w", k, err)
@@ -76,7 +77,7 @@ func (c *Cache) Prune(force bool) (int, error) {
err = c.Fs.Remove(name)
}
- if err != nil && !os.IsNotExist(err) {
+ if err != nil && !herrors.IsNotExist(err) {
return err
}
@@ -97,7 +98,7 @@ func (c *Cache) Prune(force bool) (int, error) {
counter++
}
- if err != nil && !os.IsNotExist(err) {
+ if err != nil && !herrors.IsNotExist(err) {
return err
}
@@ -112,7 +113,7 @@ func (c *Cache) Prune(force bool) (int, error) {
func (c *Cache) pruneRootDir(force bool) (int, error) {
info, err := c.Fs.Stat(c.pruneAllRootDir)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
return 0, nil
}
return 0, err
diff --git a/commands/hugo.go b/commands/hugo.go
index e26f052d4..e247fca27 100644
--- a/commands/hugo.go
+++ b/commands/hugo.go
@@ -579,7 +579,7 @@ func (c *commandeer) serverBuild() error {
func (c *commandeer) copyStatic() (map[string]uint64, error) {
m, err := c.doWithPublishDirs(c.copyStaticTo)
- if err == nil || os.IsNotExist(err) {
+ if err == nil || herrors.IsNotExist(err) {
return m, nil
}
return m, err
@@ -899,7 +899,7 @@ func (c *commandeer) newWatcher(pollIntervalStr string, dirList ...string) (*wat
}
unlock()
case err := <-watcher.Errors():
- if err != nil && !os.IsNotExist(err) {
+ if err != nil && !herrors.IsNotExist(err) {
c.logger.Errorln("Error while watching:", err)
}
}
diff --git a/commands/static_syncer.go b/commands/static_syncer.go
index b97c4df7a..c248ca152 100644
--- a/commands/static_syncer.go
+++ b/commands/static_syncer.go
@@ -14,9 +14,9 @@
package commands
import (
- "os"
"path/filepath"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/hugolib/filesystems"
"github.com/fsnotify/fsnotify"
@@ -95,7 +95,7 @@ func (s *staticSyncer) syncsStaticEvents(staticEvents []fsnotify.Event) error {
// the source of that static file. In this case Hugo will incorrectly remove that file
// from the published directory.
if ev.Op&fsnotify.Rename == fsnotify.Rename || ev.Op&fsnotify.Remove == fsnotify.Remove {
- if _, err := sourceFs.Fs.Stat(relPath); os.IsNotExist(err) {
+ if _, err := sourceFs.Fs.Stat(relPath); herrors.IsNotExist(err) {
// If file doesn't exist in any static dir, remove it
logger.Println("File no longer exists in static dir, removing", relPath)
_ = c.Fs.PublishDirStatic.RemoveAll(relPath)
diff --git a/common/herrors/errors.go b/common/herrors/errors.go
index 6ce908853..822271ef2 100644
--- a/common/herrors/errors.go
+++ b/common/herrors/errors.go
@@ -1,4 +1,4 @@
-// Copyright 2018 The Hugo Authors. All rights reserved.
+// Copyright 2022 The Hugo Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"io"
+ "os"
"runtime"
"runtime/debug"
"strconv"
@@ -38,7 +39,8 @@ type ErrorSender interface {
// Recover is a helper function that can be used to capture panics.
// Put this at the top of a method/function that crashes in a template:
-// defer herrors.Recover()
+//
+// defer herrors.Recover()
func Recover(args ...any) {
if r := recover(); r != nil {
fmt.Println("ERR:", r)
@@ -69,3 +71,18 @@ func Must(err error) {
panic(err)
}
}
+
+// IsNotExist returns true if the error is a file not found error.
+// Unlike os.IsNotExist, this also considers wrapped errors.
+func IsNotExist(err error) bool {
+ if os.IsNotExist(err) {
+ return true
+ }
+
+ // os.IsNotExist does not consider wrapped errors.
+ if os.IsNotExist(errors.Unwrap(err)) {
+ return true
+ }
+
+ return false
+}
diff --git a/common/herrors/errors_test.go b/common/herrors/errors_test.go
new file mode 100644
index 000000000..1e0730028
--- /dev/null
+++ b/common/herrors/errors_test.go
@@ -0,0 +1,36 @@
+// Copyright 2022 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package herrors
+
+import (
+ "fmt"
+ "testing"
+
+ qt "github.com/frankban/quicktest"
+ "github.com/spf13/afero"
+)
+
+func TestIsNotExist(t *testing.T) {
+ c := qt.New(t)
+
+ c.Assert(IsNotExist(afero.ErrFileNotFound), qt.Equals, true)
+ c.Assert(IsNotExist(afero.ErrFileExists), qt.Equals, false)
+ c.Assert(IsNotExist(afero.ErrDestinationExists), qt.Equals, false)
+ c.Assert(IsNotExist(nil), qt.Equals, false)
+
+ c.Assert(IsNotExist(fmt.Errorf("foo")), qt.Equals, false)
+
+ // os.IsNotExist returns false for wrapped errors.
+ c.Assert(IsNotExist(fmt.Errorf("foo: %w", afero.ErrFileNotFound)), qt.Equals, true)
+}
diff --git a/helpers/path.go b/helpers/path.go
index 0fb365f43..ad2ff7658 100644
--- a/helpers/path.go
+++ b/helpers/path.go
@@ -24,6 +24,7 @@ import (
"strings"
"unicode"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/text"
"github.com/gohugoio/hugo/config"
@@ -378,7 +379,7 @@ func OpenFileForWriting(fs afero.Fs, filename string) (afero.File, error) {
// os.Create will create any new files with mode 0666 (before umask).
f, err := fs.Create(filename)
if err != nil {
- if !os.IsNotExist(err) {
+ if !herrors.IsNotExist(err) {
return nil, err
}
if err = fs.MkdirAll(filepath.Dir(filename), 0777); err != nil { // before umask
diff --git a/hugofs/decorators.go b/hugofs/decorators.go
index 3762d753b..47b4266df 100644
--- a/hugofs/decorators.go
+++ b/hugofs/decorators.go
@@ -19,6 +19,7 @@ import (
"path/filepath"
"strings"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/spf13/afero"
)
@@ -224,7 +225,7 @@ func (l *baseFileDecoratorFile) Readdir(c int) (ofi []os.FileInfo, err error) {
// We need to resolve any symlink info.
fi, _, err := lstatIfPossible(l.fs.Fs, filename)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
continue
}
return nil, err
diff --git a/hugofs/rootmapping_fs.go b/hugofs/rootmapping_fs.go
index 90df48f8c..a37e21a8b 100644
--- a/hugofs/rootmapping_fs.go
+++ b/hugofs/rootmapping_fs.go
@@ -19,6 +19,7 @@ import (
"path/filepath"
"strings"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/hugofs/files"
radix "github.com/armon/go-radix"
@@ -45,7 +46,7 @@ func NewRootMappingFs(fs afero.Fs, rms ...RootMapping) (*RootMappingFs, error) {
fi, err := fs.Stat(rm.To)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
continue
}
return nil, err
diff --git a/hugofs/slice_fs.go b/hugofs/slice_fs.go
index 7edaf7513..574a5cb5f 100644
--- a/hugofs/slice_fs.go
+++ b/hugofs/slice_fs.go
@@ -21,6 +21,7 @@ import (
"errors"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/spf13/afero"
)
@@ -161,7 +162,7 @@ func (fs *SliceFs) pickFirst(name string) (os.FileInfo, int, error) {
return fi, i, nil
}
- if !os.IsNotExist(err) {
+ if !herrors.IsNotExist(err) {
// Real error
return nil, -1, err
}
@@ -175,7 +176,7 @@ func (fs *SliceFs) readDirs(name string, startIdx, count int) ([]os.FileInfo, er
collect := func(lfs *FileMeta) ([]os.FileInfo, error) {
d, err := lfs.Fs.Open(name)
if err != nil {
- if !os.IsNotExist(err) {
+ if !herrors.IsNotExist(err) {
return nil, err
}
return nil, nil
diff --git a/hugofs/walk.go b/hugofs/walk.go
index 22a99402f..e847174c6 100644
--- a/hugofs/walk.go
+++ b/hugofs/walk.go
@@ -20,6 +20,7 @@ import (
"sort"
"strings"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/loggers"
"errors"
@@ -118,7 +119,7 @@ func (w *Walkway) Walk() error {
} else {
info, _, err := lstatIfPossible(w.fs, w.root)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
return nil
}
@@ -154,7 +155,7 @@ func (w *Walkway) checkErr(filename string, err error) bool {
return true
}
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
// The file may be removed in process.
// This may be a ERROR situation, but it is not possible
// to determine as a general case.
diff --git a/hugolib/codeowners.go b/hugolib/codeowners.go
index 17e956981..162ee16ae 100644
--- a/hugolib/codeowners.go
+++ b/hugolib/codeowners.go
@@ -15,9 +15,9 @@ package hugolib
import (
"io"
- "os"
"path"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/config"
"github.com/gohugoio/hugo/resources/page"
"github.com/hairyhenderson/go-codeowners"
@@ -32,7 +32,7 @@ func findCodeOwnersFile(dir string) (io.Reader, error) {
_, err := afs.Stat(f)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
continue
}
return nil, err
diff --git a/hugolib/filesystems/basefs.go b/hugolib/filesystems/basefs.go
index e0fed6f3e..5a98be47e 100644
--- a/hugolib/filesystems/basefs.go
+++ b/hugolib/filesystems/basefs.go
@@ -28,6 +28,7 @@ import (
"github.com/gohugoio/hugo/htesting"
"github.com/gohugoio/hugo/hugofs/glob"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/types"
"github.com/gohugoio/hugo/common/loggers"
@@ -295,15 +296,15 @@ func (s SourceFilesystems) StaticFs(lang string) afero.Fs {
// StatResource looks for a resource in these filesystems in order: static, assets and finally content.
// If found in any of them, it returns FileInfo and the relevant filesystem.
-// Any non os.IsNotExist error will be returned.
-// An os.IsNotExist error wil be returned only if all filesystems return such an error.
+// Any non herrors.IsNotExist error will be returned.
+// An herrors.IsNotExist error wil be returned only if all filesystems return such an error.
// Note that if we only wanted to find the file, we could create a composite Afero fs,
// but we also need to know which filesystem root it lives in.
func (s SourceFilesystems) StatResource(lang, filename string) (fi os.FileInfo, fs afero.Fs, err error) {
for _, fsToCheck := range []afero.Fs{s.StaticFs(lang), s.Assets.Fs, s.Content.Fs} {
fs = fsToCheck
fi, err = fs.Stat(filename)
- if err == nil || !os.IsNotExist(err) {
+ if err == nil || !herrors.IsNotExist(err) {
return
}
}
diff --git a/hugolib/page.go b/hugolib/page.go
index ec7b82277..5acfbc677 100644
--- a/hugolib/page.go
+++ b/hugolib/page.go
@@ -16,7 +16,6 @@ package hugolib
import (
"bytes"
"fmt"
- "os"
"path"
"path/filepath"
"sort"
@@ -489,7 +488,7 @@ func (p *pageState) renderResources() (err error) {
}
if err := src.Publish(); err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
// The resource has been deleted from the file system.
// This should be extremely rare, but can happen on live reload in server
// mode when the same resource is member of different page bundles.
diff --git a/hugolib/pages_capture.go b/hugolib/pages_capture.go
index da7515fc2..b72ae7e85 100644
--- a/hugolib/pages_capture.go
+++ b/hugolib/pages_capture.go
@@ -16,11 +16,11 @@ package hugolib
import (
"context"
"fmt"
- "os"
pth "path"
"path/filepath"
"reflect"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/maps"
"github.com/gohugoio/hugo/parser/pageparser"
@@ -318,7 +318,7 @@ func (c *pagesCollector) cloneFileInfo(fi hugofs.FileMetaInfo) hugofs.FileMetaIn
func (c *pagesCollector) collectDir(dirname string, partial bool, inFilter func(fim hugofs.FileMetaInfo) bool) error {
fi, err := c.fs.Stat(dirname)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
// May have been deleted.
return nil
}
diff --git a/hugolib/site.go b/hugolib/site.go
index cbfc4d836..8fb39a1ea 100644
--- a/hugolib/site.go
+++ b/hugolib/site.go
@@ -20,7 +20,6 @@ import (
"log"
"mime"
"net/url"
- "os"
"path"
"path/filepath"
"regexp"
@@ -30,6 +29,7 @@ import (
"strings"
"time"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/htime"
"github.com/gohugoio/hugo/common/hugio"
"github.com/gohugoio/hugo/common/types"
@@ -90,16 +90,16 @@ import (
//
// 1. A list of Files is parsed and then converted into Pages.
//
-// 2. Pages contain sections (based on the file they were generated from),
-// aliases and slugs (included in a pages frontmatter) which are the
-// various targets that will get generated. There will be canonical
-// listing. The canonical path can be overruled based on a pattern.
+// 2. Pages contain sections (based on the file they were generated from),
+// aliases and slugs (included in a pages frontmatter) which are the
+// various targets that will get generated. There will be canonical
+// listing. The canonical path can be overruled based on a pattern.
//
-// 3. Taxonomies are created via configuration and will present some aspect of
-// the final page and typically a perm url.
+// 3. Taxonomies are created via configuration and will present some aspect of
+// the final page and typically a perm url.
//
-// 4. All Pages are passed through a template based on their desired
-// layout based on numerous different elements.
+// 4. All Pages are passed through a template based on their desired
+// layout based on numerous different elements.
//
// 5. The entire collection of files is written to disk.
type Site struct {
@@ -954,7 +954,7 @@ func (s *Site) filterFileEvents(events []fsnotify.Event) []fsnotify.Event {
// Throw away any directories
isRegular, err := s.SourceSpec.IsRegularSourceFile(ev.Name)
- if err != nil && os.IsNotExist(err) && (ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Rename == fsnotify.Rename) {
+ if err != nil && herrors.IsNotExist(err) && (ev.Op&fsnotify.Remove == fsnotify.Remove || ev.Op&fsnotify.Rename == fsnotify.Rename) {
// Force keep of event
isRegular = true
}
diff --git a/magefile.go b/magefile.go
index b2dc54777..c8f2a048e 100644
--- a/magefile.go
+++ b/magefile.go
@@ -268,7 +268,7 @@ func Lint() error {
return nil
}
-// Run go vet linter
+// Run go vet linter
func Vet() error {
if err := sh.Run(goexe, "vet", "./..."); err != nil {
return fmt.Errorf("error running go vet: %v", err)
diff --git a/modules/client.go b/modules/client.go
index 78ba9f5ae..953391e59 100644
--- a/modules/client.go
+++ b/modules/client.go
@@ -29,6 +29,7 @@ import (
"time"
"github.com/gohugoio/hugo/common/collections"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hexec"
hglob "github.com/gohugoio/hugo/hugofs/glob"
@@ -193,7 +194,8 @@ func (c *Client) Tidy() error {
//
// We, by default, use the /_vendor folder first, if found. To disable,
// run with
-// hugo --ignoreVendorPaths=".*"
+//
+// hugo --ignoreVendorPaths=".*"
//
// Given a module tree, Hugo will pick the first module for a given path,
// meaning that if the top-level module is vendored, that will be the full
@@ -297,7 +299,7 @@ func (c *Client) Vendor() error {
configFiles = append(configFiles, filepath.Join(dir, "theme.toml"))
for _, configFile := range configFiles {
if err := hugio.CopyFile(c.fs, configFile, filepath.Join(vendorDir, t.Path(), filepath.Base(configFile))); err != nil {
- if !os.IsNotExist(err) {
+ if !herrors.IsNotExist(err) {
return err
}
}
@@ -560,7 +562,7 @@ func (c *Client) rewriteGoModRewrite(name string, isGoMod map[string]bool) ([]by
b := &bytes.Buffer{}
f, err := c.fs.Open(filepath.Join(c.ccfg.WorkingDir, name))
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
// It's been deleted.
return nil, nil
}
diff --git a/modules/collect.go b/modules/collect.go
index ff83f9ecc..7d92e3045 100644
--- a/modules/collect.go
+++ b/modules/collect.go
@@ -23,6 +23,7 @@ import (
"time"
"github.com/bep/debounce"
+ "github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/loggers"
"github.com/spf13/cast"
@@ -539,7 +540,7 @@ func (c *collector) collectModulesTXT(owner Module) error {
f, err := c.fs.Open(filename)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
return nil
}
diff --git a/resources/resource_spec.go b/resources/resource_spec.go
index fd9653012..13920be7e 100644
--- a/resources/resource_spec.go
+++ b/resources/resource_spec.go
@@ -258,7 +258,7 @@ func (r *Spec) newResource(sourceFs afero.Fs, fd ResourceSourceDescriptor) (reso
var err error
fi, err = sourceFs.Stat(fd.SourceFilename)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
return nil, nil
}
return nil, err
diff --git a/tpl/tplimpl/template.go b/tpl/tplimpl/template.go
index 9a9e82a80..c01863ebb 100644
--- a/tpl/tplimpl/template.go
+++ b/tpl/tplimpl/template.go
@@ -20,7 +20,6 @@ import (
"fmt"
"io"
"io/fs"
- "os"
"path/filepath"
"reflect"
"regexp"
@@ -824,7 +823,7 @@ func (t *templateHandler) loadTemplates() error {
}
if err := helpers.SymbolicWalk(t.Layouts.Fs, "", walker); err != nil {
- if !os.IsNotExist(err) {
+ if !herrors.IsNotExist(err) {
return err
}
return nil
diff --git a/watcher/filenotify/poller.go b/watcher/filenotify/poller.go
index 71d806209..7479dcbdd 100644
--- a/watcher/filenotify/poller.go
+++ b/watcher/filenotify/poller.go
@@ -11,6 +11,7 @@ import (
"time"
"github.com/fsnotify/fsnotify"
+ "github.com/gohugoio/hugo/common/herrors"
)
var (
@@ -191,7 +192,7 @@ func (r *recording) record(filename string) error {
r.clear()
fi, err := os.Stat(filename)
- if err != nil && !os.IsNotExist(err) {
+ if err != nil && !herrors.IsNotExist(err) {
return err
}
@@ -206,7 +207,7 @@ func (r *recording) record(filename string) error {
if fi.IsDir() {
f, err := os.Open(filename)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
return nil
}
return err
@@ -215,7 +216,7 @@ func (r *recording) record(filename string) error {
fis, err := f.Readdir(-1)
if err != nil {
- if os.IsNotExist(err) {
+ if herrors.IsNotExist(err) {
return nil
}
return err
@@ -260,7 +261,7 @@ func (item *itemToWatch) checkForChanges() ([]fsnotify.Event, error) {
}
err := item.right.record(item.filename)
- if err != nil && !os.IsNotExist(err) {
+ if err != nil && !herrors.IsNotExist(err) {
return nil, err
}