resources: Replace error handling in GetRemote with try (note)

Closes #13216
This commit is contained in:
Bjørn Erik Pedersen
2025-01-05 15:43:18 +01:00
parent 4ea94c451d
commit 0918e087ec
16 changed files with 108 additions and 223 deletions

View File

@@ -19,6 +19,7 @@ import (
"io"
"reflect"
"github.com/gohugoio/hugo/common/herrors"
"github.com/gohugoio/hugo/common/hreflect"
"github.com/gohugoio/hugo/tpl/internal/go_templates/texttemplate/parse"
@@ -256,14 +257,34 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
panic("not reached")
}
// newErrorWithCause creates a new error with the given cause.
func newErrorWithCause(err error) *TryError {
return &TryError{Err: err, Cause: herrors.Cause(err)}
}
// TryError wraps an error with a cause.
type TryError struct {
Err error
Cause error
}
func (e *TryError) Error() string {
return e.Err.Error()
}
func (e *TryError) Unwrap() error {
return e.Err
}
// TryValue is what gets returned when using the "try" keyword.
type TryValue struct {
// Value is the value returned by the function or method wrapped with "try".
// This will always be nil if Err is set.
Value any
// Err is the error returned by the function or method wrapped with "try".
// This will always be nil if Value is set.
Err error
Err *TryError
}
// evalCall executes a function or method call. If it's a method, fun already has the receiver bound, so
@@ -274,10 +295,11 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
if name == "try" {
defer func() {
if r := recover(); r != nil {
// Cause: herrors.Cause(err)
if err, ok := r.(error); ok {
val = reflect.ValueOf(TryValue{nil, err})
val = reflect.ValueOf(TryValue{Value: nil, Err: newErrorWithCause(err)})
} else {
val = reflect.ValueOf(TryValue{nil, fmt.Errorf("%v", r)})
val = reflect.ValueOf(TryValue{Value: nil, Err: newErrorWithCause(fmt.Errorf("%v", r))})
}
}
}()
@@ -396,7 +418,7 @@ func (s *state) evalCall(dot, fun reflect.Value, isBuiltin bool, node parse.Node
// Added for Hugo.
if name == "try" {
return reflect.ValueOf(TryValue{vv.Interface(), nil})
return reflect.ValueOf(TryValue{Value: vv.Interface()})
}
return vv

View File

@@ -115,14 +115,10 @@ func (ns *Namespace) Get(filename any) resource.Resource {
//
// Note: This method does not return any error as a second return value,
// for any error situations the error can be checked in .Err.
func (ns *Namespace) GetRemote(args ...any) resource.Resource {
func (ns *Namespace) GetRemote(args ...any) (resource.Resource, error) {
get := func(args ...any) (resource.Resource, error) {
if len(args) < 1 {
return nil, errors.New("must provide an URL")
}
if len(args) > 2 {
return nil, errors.New("must not provide more arguments than URL and options")
if len(args) < 1 || len(args) > 2 {
return nil, errors.New("must provide an URL and optionally an options map")
}
urlstr, err := cast.ToStringE(args[0])
@@ -146,12 +142,12 @@ func (ns *Namespace) GetRemote(args ...any) resource.Resource {
if err != nil {
switch v := err.(type) {
case *create.HTTPError:
return resources.NewErrorResource(resource.NewResourceError(v, v.Data))
return nil, resource.NewResourceError(v, v.Data)
default:
return resources.NewErrorResource(resource.NewResourceError(fmt.Errorf("error calling resources.GetRemote: %w", err), make(map[string]any)))
return nil, resource.NewResourceError(err, nil)
}
}
return r
return r, nil
}
// GetMatch finds the first Resource matching the given pattern, or nil if none found.

View File

@@ -17,13 +17,13 @@
{{- $url := printf "https://twitter.com/%v/status/%v" .user .id -}}
{{- $query := querify "url" $url "dnt" .dnt -}}
{{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}}
{{- with resources.GetRemote $request -}}
{{- with try (resources.GetRemote $request) -}}
{{- with .Err -}}
{{- errorf "%s" . -}}
{{- else -}}
{{- else with .Value -}}
{{- (. | transform.Unmarshal).html | safeHTML -}}
{{- end -}}
{{- else -}}
{{- else -}}
{{- warnidf "shortcode-twitter-getremote" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
{{- end -}}
{{- end -}}
{{- end -}}

View File

@@ -14,14 +14,14 @@
{{- $url := printf "https://twitter.com/%v/status/%v" .user .id -}}
{{- $query := querify "url" $url "dnt" .dnt "omit_script" true -}}
{{- $request := printf "https://publish.twitter.com/oembed?%s" $query -}}
{{- with resources.GetRemote $request -}}
{{- with try (resources.GetRemote $request) -}}
{{- with .Err -}}
{{- errorf "%s" . -}}
{{- else -}}
{{- else with .Value -}}
{{- (. | transform.Unmarshal).html | safeHTML -}}
{{- else -}}
{{- warnidf "shortcode-twitter-simple-getremote" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
{{- end -}}
{{- else -}}
{{- warnidf "shortcode-twitter-simple-getremote" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
{{- end -}}
{{- end -}}
@@ -31,7 +31,16 @@
{{- .Page.Scratch.Set "__h_simple_twitter_css" true -}}
<style type="text/css">
.twitter-tweet {
font: 14px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
font:
14px/1.45 -apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Oxygen-Sans,
Ubuntu,
Cantarell,
"Helvetica Neue",
sans-serif;
border-left: 4px solid #2b7bb9;
padding-left: 1.5em;
color: #555;

View File

@@ -23,10 +23,10 @@
{{- $url := urls.JoinPath "https://vimeo.com" .id -}}
{{- $query := querify "url" $url "dnt" $dnt -}}
{{- $request := printf "https://vimeo.com/api/oembed.json?%s" $query -}}
{{- with resources.GetRemote $request -}}
{{- with try (resources.GetRemote $request) -}}
{{- with .Err -}}
{{- errorf "%s" . -}}
{{- else -}}
{{- else with .Value -}}
{{- with . | transform.Unmarshal -}}
{{- $class := printf "%s %s" "s_video_simple" "__h_video" -}}
{{- with $.class -}}
@@ -45,8 +45,8 @@
</a>
</div>
{{- end -}}
{{- else -}}
{{- warnidf "shortcode-vimeo-simple" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
{{- end -}}
{{- else -}}
{{- warnidf "shortcode-vimeo-simple" "The %q shortcode was unable to retrieve the remote data. See %s" .name .position -}}
{{- end -}}
{{- end -}}