diff options
author | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-01-02 11:58:32 +0100 |
---|---|---|
committer | Bjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com> | 2019-01-02 14:25:37 +0100 |
commit | ce8a09a4c0661dece931ab1173e4f09e8e04aa38 (patch) | |
tree | 870372211e342312d0ab3034ee03285c6f698f9d /resources/resource | |
parent | 669ada436787311cc5d02dae5b88e60a09adda58 (diff) |
resources: Move resource interfaces into its own package
Diffstat (limited to 'resources/resource')
-rw-r--r-- | resources/resource/resources.go | 123 | ||||
-rw-r--r-- | resources/resource/resourcetypes.go | 106 |
2 files changed, 229 insertions, 0 deletions
diff --git a/resources/resource/resources.go b/resources/resource/resources.go new file mode 100644 index 000000000..5c661c24e --- /dev/null +++ b/resources/resource/resources.go @@ -0,0 +1,123 @@ +// Copyright 2019 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 resource + +import ( + "fmt" + "strings" + + "github.com/gohugoio/hugo/resources/internal" +) + +// Resources represents a slice of resources, which can be a mix of different types. +// I.e. both pages and images etc. +type Resources []Resource + +// ResourcesConverter converts a given slice of Resource objects to Resources. +type ResourcesConverter interface { + ToResources() Resources +} + +// ByType returns resources of a given resource type (ie. "image"). +func (r Resources) ByType(tp string) Resources { + var filtered Resources + + for _, resource := range r { + if resource.ResourceType() == tp { + filtered = append(filtered, resource) + } + } + return filtered +} + +// GetMatch finds the first Resource matching the given pattern, or nil if none found. +// See Match for a more complete explanation about the rules used. +func (r Resources) GetMatch(pattern string) Resource { + g, err := internal.GetGlob(pattern) + if err != nil { + return nil + } + + for _, resource := range r { + if g.Match(strings.ToLower(resource.Name())) { + return resource + } + } + + return nil +} + +// Match gets all resources matching the given base filename prefix, e.g +// "*.png" will match all png files. The "*" does not match path delimiters (/), +// so if you organize your resources in sub-folders, you need to be explicit about it, e.g.: +// "images/*.png". To match any PNG image anywhere in the bundle you can do "**.png", and +// to match all PNG images below the images folder, use "images/**.jpg". +// The matching is case insensitive. +// Match matches by using the value of Resource.Name, which, by default, is a filename with +// path relative to the bundle root with Unix style slashes (/) and no leading slash, e.g. "images/logo.png". +// See https://github.com/gobwas/glob for the full rules set. +func (r Resources) Match(pattern string) Resources { + g, err := internal.GetGlob(pattern) + if err != nil { + return nil + } + + var matches Resources + for _, resource := range r { + if g.Match(strings.ToLower(resource.Name())) { + matches = append(matches, resource) + } + } + return matches +} + +type translatedResource interface { + TranslationKey() string +} + +// MergeByLanguage adds missing translations in r1 from r2. +func (r Resources) MergeByLanguage(r2 Resources) Resources { + result := append(Resources(nil), r...) + m := make(map[string]bool) + for _, rr := range r { + if translated, ok := rr.(translatedResource); ok { + m[translated.TranslationKey()] = true + } + } + + for _, rr := range r2 { + if translated, ok := rr.(translatedResource); ok { + if _, found := m[translated.TranslationKey()]; !found { + result = append(result, rr) + } + } + } + return result +} + +// MergeByLanguageInterface is the generic version of MergeByLanguage. It +// is here just so it can be called from the tpl package. +func (r Resources) MergeByLanguageInterface(in interface{}) (interface{}, error) { + r2, ok := in.(Resources) + if !ok { + return nil, fmt.Errorf("%T cannot be merged by language", in) + } + return r.MergeByLanguage(r2), nil +} + +// Source is an internal template and not meant for use in the templates. It +// may change without notice. +type Source interface { + Publish() error +} diff --git a/resources/resource/resourcetypes.go b/resources/resource/resourcetypes.go new file mode 100644 index 000000000..120d753e4 --- /dev/null +++ b/resources/resource/resourcetypes.go @@ -0,0 +1,106 @@ +// Copyright 2019 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 resource + +import ( + "github.com/gohugoio/hugo/media" + + "github.com/gohugoio/hugo/common/hugio" +) + +// Cloner is an internal template and not meant for use in the templates. It +// may change without notice. +type Cloner interface { + WithNewBase(base string) Resource +} + +// Resource represents a linkable resource, i.e. a content page, image etc. +type Resource interface { + resourceBase + + // Permalink represents the absolute link to this resource. + Permalink() string + + // RelPermalink represents the host relative link to this resource. + RelPermalink() string + + // ResourceType is the resource type. For most file types, this is the main + // part of the MIME type, e.g. "image", "application", "text" etc. + // For content pages, this value is "page". + ResourceType() string + + // Name is the logical name of this resource. This can be set in the front matter + // metadata for this resource. If not set, Hugo will assign a value. + // This will in most cases be the base filename. + // So, for the image "/some/path/sunset.jpg" this will be "sunset.jpg". + // The value returned by this method will be used in the GetByPrefix and ByPrefix methods + // on Resources. + Name() string + + // Title returns the title if set in front matter. For content pages, this will be the expected value. + Title() string + + // Resource specific data set by Hugo. + // One example would be.Data.Digest for fingerprinted resources. + Data() interface{} + + // Params set in front matter for this resource. + Params() map[string]interface{} +} + +// resourceBase pulls out the minimal set of operations to define a Resource, +// to simplify testing etc. +type resourceBase interface { + // MediaType is this resource's MIME type. + MediaType() media.Type +} + +// ResourcesLanguageMerger describes an interface for merging resources from a +// different language. +type ResourcesLanguageMerger interface { + MergeByLanguage(other Resources) Resources + // Needed for integration with the tpl package. + MergeByLanguageInterface(other interface{}) (interface{}, error) +} + +// Identifier identifies a resource. +type Identifier interface { + Key() string +} + +// ContentResource represents a Resource that provides a way to get to its content. +// Most Resource types in Hugo implements this interface, including Page. +// This should be used with care, as it will read the file content into memory, but it +// should be cached as effectively as possible by the implementation. +type ContentResource interface { + resourceBase + + // Content returns this resource's content. It will be equivalent to reading the content + // that RelPermalink points to in the published folder. + // The return type will be contextual, and should be what you would expect: + // * Page: template.HTML + // * JSON: String + // * Etc. + Content() (interface{}, error) +} + +// OpenReadSeekCloser allows setting some other way (than reading from a filesystem) +// to open or create a ReadSeekCloser. +type OpenReadSeekCloser func() (hugio.ReadSeekCloser, error) + +// ReadSeekCloserResource is a Resource that supports loading its content. +type ReadSeekCloserResource interface { + resourceBase + ReadSeekCloser() (hugio.ReadSeekCloser, error) +} |