github.com/linchen2chris/hugo@v0.0.0-20230307053224-cec209389705/resources/resource_factories/create/create.go (about)

     1  // Copyright 2019 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  // Package create contains functions for to create Resource objects. This will
    15  // typically non-files.
    16  package create
    17  
    18  import (
    19  	"net/http"
    20  	"path"
    21  	"path/filepath"
    22  	"strings"
    23  	"time"
    24  
    25  	"github.com/gohugoio/hugo/hugofs/glob"
    26  
    27  	"github.com/gohugoio/hugo/hugofs"
    28  
    29  	"github.com/gohugoio/hugo/cache/filecache"
    30  	"github.com/gohugoio/hugo/common/hugio"
    31  	"github.com/gohugoio/hugo/resources"
    32  	"github.com/gohugoio/hugo/resources/resource"
    33  )
    34  
    35  // Client contains methods to create Resource objects.
    36  // tasks to Resource objects.
    37  type Client struct {
    38  	rs               *resources.Spec
    39  	httpClient       *http.Client
    40  	cacheGetResource *filecache.Cache
    41  }
    42  
    43  // New creates a new Client with the given specification.
    44  func New(rs *resources.Spec) *Client {
    45  	return &Client{
    46  		rs: rs,
    47  		httpClient: &http.Client{
    48  			Timeout: time.Minute,
    49  		},
    50  		cacheGetResource: rs.FileCaches.GetResourceCache(),
    51  	}
    52  }
    53  
    54  // Copy copies r to the new targetPath.
    55  func (c *Client) Copy(r resource.Resource, targetPath string) (resource.Resource, error) {
    56  	return c.rs.ResourceCache.GetOrCreate(resources.ResourceCacheKey(targetPath), func() (resource.Resource, error) {
    57  		return resources.Copy(r, targetPath), nil
    58  	})
    59  }
    60  
    61  // Get creates a new Resource by opening the given filename in the assets filesystem.
    62  func (c *Client) Get(filename string) (resource.Resource, error) {
    63  	filename = filepath.Clean(filename)
    64  	return c.rs.ResourceCache.GetOrCreate(resources.ResourceCacheKey(filename), func() (resource.Resource, error) {
    65  		return c.rs.New(resources.ResourceSourceDescriptor{
    66  			Fs:             c.rs.BaseFs.Assets.Fs,
    67  			LazyPublish:    true,
    68  			SourceFilename: filename,
    69  		})
    70  	})
    71  }
    72  
    73  // Match gets the resources matching the given pattern from the assets filesystem.
    74  func (c *Client) Match(pattern string) (resource.Resources, error) {
    75  	return c.match("__match", pattern, nil, false)
    76  }
    77  
    78  func (c *Client) ByType(tp string) resource.Resources {
    79  	res, err := c.match(path.Join("_byType", tp), "**", func(r resource.Resource) bool { return r.ResourceType() == tp }, false)
    80  	if err != nil {
    81  		panic(err)
    82  	}
    83  	return res
    84  }
    85  
    86  // GetMatch gets first resource matching the given pattern from the assets filesystem.
    87  func (c *Client) GetMatch(pattern string) (resource.Resource, error) {
    88  	res, err := c.match("__get-match", pattern, nil, true)
    89  	if err != nil || len(res) == 0 {
    90  		return nil, err
    91  	}
    92  	return res[0], err
    93  }
    94  
    95  func (c *Client) match(name, pattern string, matchFunc func(r resource.Resource) bool, firstOnly bool) (resource.Resources, error) {
    96  	pattern = glob.NormalizePath(pattern)
    97  	partitions := glob.FilterGlobParts(strings.Split(pattern, "/"))
    98  	if len(partitions) == 0 {
    99  		partitions = []string{resources.CACHE_OTHER}
   100  	}
   101  	key := path.Join(name, path.Join(partitions...))
   102  	key = path.Join(key, pattern)
   103  
   104  	return c.rs.ResourceCache.GetOrCreateResources(key, func() (resource.Resources, error) {
   105  		var res resource.Resources
   106  
   107  		handle := func(info hugofs.FileMetaInfo) (bool, error) {
   108  			meta := info.Meta()
   109  			r, err := c.rs.New(resources.ResourceSourceDescriptor{
   110  				LazyPublish: true,
   111  				FileInfo:    info,
   112  				OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
   113  					return meta.Open()
   114  				},
   115  				RelTargetFilename: meta.Path,
   116  			})
   117  			if err != nil {
   118  				return true, err
   119  			}
   120  
   121  			if matchFunc != nil && !matchFunc(r) {
   122  				return false, nil
   123  			}
   124  
   125  			res = append(res, r)
   126  
   127  			return firstOnly, nil
   128  		}
   129  
   130  		if err := hugofs.Glob(c.rs.BaseFs.Assets.Fs, pattern, handle); err != nil {
   131  			return nil, err
   132  		}
   133  
   134  		return res, nil
   135  	})
   136  }
   137  
   138  // FromString creates a new Resource from a string with the given relative target path.
   139  func (c *Client) FromString(targetPath, content string) (resource.Resource, error) {
   140  	return c.rs.ResourceCache.GetOrCreate(path.Join(resources.CACHE_OTHER, targetPath), func() (resource.Resource, error) {
   141  		return c.rs.New(
   142  			resources.ResourceSourceDescriptor{
   143  				Fs:          c.rs.FileCaches.AssetsCache().Fs,
   144  				LazyPublish: true,
   145  				OpenReadSeekCloser: func() (hugio.ReadSeekCloser, error) {
   146  					return hugio.NewReadSeekerNoOpCloserFromString(content), nil
   147  				},
   148  				RelTargetFilename: filepath.Clean(targetPath),
   149  			})
   150  	})
   151  }