diff options
-rw-r--r-- | hugolib/page.go | 4 | ||||
-rw-r--r-- | hugolib/resource_chain_test.go | 5 | ||||
-rw-r--r-- | resources/errorResource.go | 129 | ||||
-rw-r--r-- | resources/page/page_nop.go | 4 | ||||
-rw-r--r-- | resources/page/testhelpers_test.go | 5 | ||||
-rw-r--r-- | resources/resource.go | 4 | ||||
-rw-r--r-- | resources/resource/resourcetypes.go | 1 | ||||
-rw-r--r-- | resources/resource_factories/create/create.go | 2 | ||||
-rw-r--r-- | resources/transform.go | 4 | ||||
-rw-r--r-- | tpl/resources/resources.go | 44 |
10 files changed, 182 insertions, 20 deletions
diff --git a/hugolib/page.go b/hugolib/page.go index ab2a4d74c..f35865cf0 100644 --- a/hugolib/page.go +++ b/hugolib/page.go @@ -129,6 +129,10 @@ type pageState struct { *pageCommon } +func (p *pageState) Err() error { + return nil +} + // Eq returns whether the current page equals the given page. // This is what's invoked when doing `{{ if eq $page $otherPage }}` func (p *pageState) Eq(other interface{}) bool { diff --git a/hugolib/resource_chain_test.go b/hugolib/resource_chain_test.go index efd28a95d..214dda216 100644 --- a/hugolib/resource_chain_test.go +++ b/hugolib/resource_chain_test.go @@ -415,6 +415,7 @@ CSS integrity Data last: {{ $cssFingerprinted2.RelPermalink }} {{ $cssFingerpri {{ $rimg := resources.Get "%[1]s/sunset.jpg" }} {{ $remotenotfound := resources.Get "%[1]s/notfound.jpg" }} {{ $localnotfound := resources.Get "images/notfound.jpg" }} +{{ $gopherprotocol := resources.Get "gopher://example.org" }} {{ $rfit := $rimg.Fit "200x200" }} {{ $rfit2 := $rfit.Fit "100x200" }} {{ $rimg = $rimg | fingerprint }} @@ -422,6 +423,8 @@ SUNSET REMOTE: {{ $rimg.Name }}|{{ $rimg.RelPermalink }}|{{ $rimg.Width }}|{{ le FIT REMOTE: {{ $rfit.Name }}|{{ $rfit.RelPermalink }}|{{ $rfit.Width }} REMOTE NOT FOUND: {{ if $remotenotfound }}FAILED{{ else}}OK{{ end }} LOCAL NOT FOUND: {{ if $localnotfound }}FAILED{{ else}}OK{{ end }} +PRINT PROTOCOL ERROR1: {{ with $gopherprotocol }}{{ . | safeHTML }}{{ end }} +PRINT PROTOCOL ERROR2: {{ with $gopherprotocol }}{{ .Err | safeHTML }}{{ end }} `, ts.URL)) @@ -454,6 +457,8 @@ SUNSET REMOTE: sunset_%[1]s.jpg|/sunset_%[1]s.a9bf1d944e19c0f382e0d8f51de690f7d0 FIT REMOTE: sunset_%[1]s.jpg|/sunset_%[1]s_hu59e56ffff1bc1d8d122b1403d34e039f_0_200x200_fit_q75_box.jpg|200 REMOTE NOT FOUND: OK LOCAL NOT FOUND: OK +PRINT PROTOCOL ERROR1: error calling resources.Get: Get "gopher://example.org": unsupported protocol scheme "gopher" +PRINT PROTOCOL ERROR2: error calling resources.Get: Get "gopher://example.org": unsupported protocol scheme "gopher" `, helpers.HashString(ts.URL+"/sunset.jpg", map[string]interface{}{}))) diff --git a/resources/errorResource.go b/resources/errorResource.go new file mode 100644 index 000000000..705547d4c --- /dev/null +++ b/resources/errorResource.go @@ -0,0 +1,129 @@ +// Copyright 2021 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 resources + +import ( + "image" + + "github.com/gohugoio/hugo/common/hugio" + "github.com/gohugoio/hugo/common/maps" + "github.com/gohugoio/hugo/media" + + "github.com/gohugoio/hugo/resources/images/exif" + + "github.com/gohugoio/hugo/resources/resource" +) + +var ( + _ error = (*errorResource)(nil) + // Imnage covers all current Resource implementations. + _ resource.Image = (*errorResource)(nil) + // The list of user facing and exported interfaces in resource.go + // Note that if we're missing some interface here, the user will still + // get an error, but not as pretty. + _ resource.ContentResource = (*errorResource)(nil) + _ resource.ReadSeekCloserResource = (*errorResource)(nil) + _ resource.ResourcesLanguageMerger = (*resource.Resources)(nil) + // Make sure it also fails when passed to a pipe function. + _ ResourceTransformer = (*errorResource)(nil) +) + +// NewErrorResource wraps err in a Resource where all but the Err method will panic. +func NewErrorResource(err error) resource.Resource { + return &errorResource{error: err} +} + +type errorResource struct { + error +} + +func (e *errorResource) Err() error { + return e.error +} + +func (e *errorResource) ReadSeekCloser() (hugio.ReadSeekCloser, error) { + panic(e.error) +} + +func (e *errorResource) Content() (interface{}, error) { + panic(e.error) +} + +func (e *errorResource) ResourceType() string { + panic(e.error) +} + +func (e *errorResource) MediaType() media.Type { + panic(e.error) +} + +func (e *errorResource) Permalink() string { + panic(e.error) +} + +func (e *errorResource) RelPermalink() string { + panic(e.error) +} + +func (e *errorResource) Name() string { + panic(e.error) +} + +func (e *errorResource) Title() string { + panic(e.error) +} + +func (e *errorResource) Params() maps.Params { + panic(e.error) +} + +func (e *errorResource) Data() interface{} { + panic(e.error) +} + +func (e *errorResource) Height() int { + panic(e.error) +} + +func (e *errorResource) Width() int { + panic(e.error) +} + +func (e *errorResource) Fill(spec string) (resource.Image, error) { + panic(e.error) +} + +func (e *errorResource) Fit(spec string) (resource.Image, error) { + panic(e.error) +} + +func (e *errorResource) Resize(spec string) (resource.Image, error) { + panic(e.error) +} + +func (e *errorResource) Filter(filters ...interface{}) (resource.Image, error) { + panic(e.error) +} + +func (e *errorResource) Exif() *exif.Exif { + panic(e.error) +} + +func (e *errorResource) DecodeImage() (image.Image, error) { + panic(e.error) +} + +func (e *errorResource) Transform(...ResourceTransformation) (ResourceTransformer, error) { + panic(e.error) +} diff --git a/resources/page/page_nop.go b/resources/page/page_nop.go index 94515d27d..4f91883a0 100644 --- a/resources/page/page_nop.go +++ b/resources/page/page_nop.go @@ -48,6 +48,10 @@ var ( // PageNop implements Page, but does nothing. type nopPage int +func (p *nopPage) Err() error { + return nil +} + func (p *nopPage) Aliases() []string { return nil } diff --git a/resources/page/testhelpers_test.go b/resources/page/testhelpers_test.go index 1a0a6586a..a21ab2ff3 100644 --- a/resources/page/testhelpers_test.go +++ b/resources/page/testhelpers_test.go @@ -29,7 +29,6 @@ import ( "github.com/bep/gitmap" "github.com/gohugoio/hugo/helpers" "github.com/gohugoio/hugo/resources/resource" - "github.com/gohugoio/hugo/navigation" @@ -121,6 +120,10 @@ type testPage struct { sectionEntries []string } +func (p *testPage) Err() error { + return nil +} + func (p *testPage) Aliases() []string { panic("not implemented") } diff --git a/resources/resource.go b/resources/resource.go index 28b9a8879..1f6246859 100644 --- a/resources/resource.go +++ b/resources/resource.go @@ -230,6 +230,10 @@ func (l *genericResource) Content() (interface{}, error) { return l.content, nil } +func (r *genericResource) Err() error { + return nil +} + func (l *genericResource) Data() interface{} { return l.data } diff --git a/resources/resource/resourcetypes.go b/resources/resource/resourcetypes.go index 8ab77e436..788cdb86a 100644 --- a/resources/resource/resourcetypes.go +++ b/resources/resource/resourcetypes.go @@ -45,6 +45,7 @@ type Resource interface { ResourceMetaProvider ResourceParamsProvider ResourceDataProvider + Err() error } // Image represents an image resource. diff --git a/resources/resource_factories/create/create.go b/resources/resource_factories/create/create.go index dc03568ac..f7bde9ee6 100644 --- a/resources/resource_factories/create/create.go +++ b/resources/resource_factories/create/create.go @@ -35,7 +35,6 @@ import ( "github.com/gohugoio/hugo/hugofs" "github.com/gohugoio/hugo/cache/filecache" - "github.com/gohugoio/hugo/common/herrors" "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/common/maps" "github.com/gohugoio/hugo/common/types" @@ -155,7 +154,6 @@ func (c *Client) FromString(targetPath, content string) (resource.Resource, erro // FromRemote expects one or n-parts of a URL to a resource // If you provide multiple parts they will be joined together to the final URL. func (c *Client) FromRemote(uri string, options map[string]interface{}) (resource.Resource, error) { - defer herrors.Recover() rURL, err := url.Parse(uri) if err != nil { return nil, errors.Wrapf(err, "failed to parse URL for resource %s", uri) diff --git a/resources/transform.go b/resources/transform.go index 0d555b2b5..0569fb35e 100644 --- a/resources/transform.go +++ b/resources/transform.go @@ -167,6 +167,10 @@ func (r *resourceAdapter) Content() (interface{}, error) { return r.target.Content() } +func (r *resourceAdapter) Err() error { + return nil +} + func (r *resourceAdapter) Data() interface{} { r.init(false, false) return r.target.Data() diff --git a/tpl/resources/resources.go b/tpl/resources/resources.go index a3f3aaa3e..0be52ad05 100644 --- a/tpl/resources/resources.go +++ b/tpl/resources/resources.go @@ -113,30 +113,40 @@ func (ns *Namespace) getscssClientDartSass() (*dartsass.Client, error) { // further transformations. // // For URLs an additional argument with options can be provided. -func (ns *Namespace) Get(args ...interface{}) (resource.Resource, error) { - if len(args) != 1 && len(args) != 2 { - return nil, errors.New("must provide a filename or URL") - } +func (ns *Namespace) Get(args ...interface{}) resource.Resource { + get := func(args ...interface{}) (resource.Resource, error) { + if len(args) != 1 && len(args) != 2 { + return nil, errors.New("must provide a filename or URL") + } - filenamestr, err := cast.ToStringE(args[0]) - if err != nil { - return nil, err - } + filenamestr, err := cast.ToStringE(args[0]) + if err != nil { + return nil, err + } - if u, err := url.Parse(filenamestr); err == nil && u.Scheme != "" { - if len(args) == 2 { - options, err := maps.ToStringMapE(args[1]) - if err != nil { - return nil, err + if u, err := url.Parse(filenamestr); err == nil && u.Scheme != "" { + if len(args) == 2 { + options, err := maps.ToStringMapE(args[1]) + if err != nil { + return nil, err + } + return ns.createClient.FromRemote(filenamestr, options) } - return ns.createClient.FromRemote(filenamestr, options) + return ns.createClient.FromRemote(filenamestr, nil) } - return ns.createClient.FromRemote(filenamestr, nil) + + filenamestr = filepath.Clean(filenamestr) + + return ns.createClient.Get(filenamestr) } - filenamestr = filepath.Clean(filenamestr) + r, err := get(args...) + if err != nil { + // This allows the client to reason about the .Err in the template. + return resources.NewErrorResource(errors.Wrap(err, "error calling resources.Get")) + } + return r - return ns.createClient.Get(filenamestr) } // GetMatch finds the first Resource matching the given pattern, or nil if none found. |