From: Bjørn Erik Pedersen Date: Thu, 12 Feb 2026 18:33:58 +0000 (+0100) Subject: Remove items deprecated <= v0.136.0 (note) X-Git-Url: http://git.maquefel.me/?a=commitdiff_plain;h=af5051e759f5de8b7c0520b7f2f7dbbedb798551;p=brevno-suite%2Fhugo Remove items deprecated <= v0.136.0 (note) Template functions: - data.GetCSV / getCSV (use resources.GetRemote) - data.GetJSON / getJSON (use resources.GetRemote) - crypto.FNV32a (use hash.FNV32a) - resources.Babel (use js.Babel) - resources.PostCSS (use css.PostCSS) - resources.ToCSS (use css.Sass) Page methods: - .Page.NextPage (use .Page.Next) - .Page.PrevPage (use .Page.Prev) Paginator: - .Paginator.PageSize (use .Paginator.PagerSize) Site methods: - .Site.LastChange (use .Site.Lastmod) - .Site.Author (use .Site.Params.Author) - .Site.Authors (use .Site.Params.Authors) - .Site.Social (use .Site.Params.Social) - .Site.IsMultiLingual (use hugo.IsMultilingual) - .Sites.First (use .Sites.Default) Site config: - paginate (use pagination.pagerSize) - paginatePath (use pagination.path) File caches: - getjson cache - getcsv cache --- diff --git a/cache/filecache/filecache_config.go b/cache/filecache/filecache_config.go index 96ea9611a..1cfc8b1c2 100644 --- a/cache/filecache/filecache_config.go +++ b/cache/filecache/filecache_config.go @@ -41,8 +41,6 @@ var defaultCacheConfig = FileCacheConfig{ } const ( - CacheKeyGetJSON = "getjson" - CacheKeyGetCSV = "getcsv" CacheKeyImages = "images" CacheKeyAssets = "assets" CacheKeyModules = "modules" @@ -74,8 +72,6 @@ var defaultCacheConfigs = Configs{ MaxAge: 24 * time.Hour, Dir: ":cacheDir/modules", }, - CacheKeyGetJSON: defaultCacheConfig, - CacheKeyGetCSV: defaultCacheConfig, CacheKeyImages: { MaxAge: -1, Dir: resourcesGenDir, @@ -130,16 +126,6 @@ func (c FileCacheConfig) MarshalJSON() ([]byte, error) { }) } -// GetJSONCache gets the file cache for getJSON. -func (f Caches) GetJSONCache() *Cache { - return f[CacheKeyGetJSON] -} - -// GetCSVCache gets the file cache for getCSV. -func (f Caches) GetCSVCache() *Cache { - return f[CacheKeyGetCSV] -} - // ImageCache gets the file cache for processed images. func (f Caches) ImageCache() *Cache { return f[CacheKeyImages] diff --git a/cache/filecache/filecache_config_test.go b/cache/filecache/filecache_config_test.go index ecd6f366b..e2ae63bda 100644 --- a/cache/filecache/filecache_config_test.go +++ b/cache/filecache/filecache_config_test.go @@ -44,12 +44,9 @@ assetDir = "assets" archetypeDir = "archetypes" [caches] -[caches.getJSON] +[caches.misc] maxAge = "10m" dir = "/path/to/c1" -[caches.getCSV] -maxAge = "11h" -dir = "/path/to/c2" [caches.images] dir = "/path/to/c3" [caches.getResource] @@ -60,11 +57,11 @@ dir = "/path/to/c4" c.Assert(err, qt.IsNil) fs := afero.NewMemMapFs() decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches - c.Assert(len(decoded), qt.Equals, 8) + c.Assert(len(decoded), qt.Equals, 6) - c2 := decoded["getcsv"] - c.Assert(c2.MaxAge.String(), qt.Equals, "11h0m0s") - c.Assert(c2.DirCompiled, qt.Equals, filepath.FromSlash("/path/to/c2/filecache/getcsv")) + c2 := decoded["misc"] + c.Assert(c2.MaxAge.String(), qt.Equals, "10m0s") + c.Assert(c2.DirCompiled, qt.Equals, filepath.FromSlash("/path/to/c1/filecache/misc")) c3 := decoded["images"] c.Assert(c3.MaxAge, qt.Equals, time.Duration(-1)) @@ -91,12 +88,9 @@ archeTypedir = "archetypes" ignoreCache = true [caches] -[caches.getJSON] +[caches.misc] maxAge = 1234 dir = "/path/to/c1" -[caches.getCSV] -maxAge = 3456 -dir = "/path/to/c2" [caches.images] dir = "/path/to/c3" [caches.getResource] @@ -107,7 +101,7 @@ dir = "/path/to/c4" c.Assert(err, qt.IsNil) fs := afero.NewMemMapFs() decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches - c.Assert(len(decoded), qt.Equals, 8) + c.Assert(len(decoded), qt.Equals, 6) for _, v := range decoded { c.Assert(v.MaxAge, qt.Equals, time.Duration(0)) @@ -130,20 +124,20 @@ func TestDecodeConfigDefault(t *testing.T) { fs := afero.NewMemMapFs() decoded := testconfig.GetTestConfigs(fs, cfg).Base.Caches - c.Assert(len(decoded), qt.Equals, 8) + c.Assert(len(decoded), qt.Equals, 6) imgConfig := decoded[filecache.CacheKeyImages] - jsonConfig := decoded[filecache.CacheKeyGetJSON] + miscConfig := decoded[filecache.CacheKeyMisc] if runtime.GOOS == "windows" { c.Assert(imgConfig.DirCompiled, qt.Equals, filepath.FromSlash("_gen/images")) } else { c.Assert(imgConfig.DirCompiled, qt.Equals, "_gen/images") - c.Assert(jsonConfig.DirCompiled, qt.Equals, "/cache/thecache/hugoproject/filecache/getjson") + c.Assert(miscConfig.DirCompiled, qt.Equals, "/cache/thecache/hugoproject/filecache/misc") } c.Assert(imgConfig.IsResourceDir, qt.Equals, true) - c.Assert(jsonConfig.IsResourceDir, qt.Equals, false) + c.Assert(miscConfig.IsResourceDir, qt.Equals, false) } func TestFileCacheConfigMarshalJSON(t *testing.T) { diff --git a/cache/filecache/filecache_pruner_test.go b/cache/filecache/filecache_pruner_test.go index e009ce2a9..9cb58e053 100644 --- a/cache/filecache/filecache_pruner_test.go +++ b/cache/filecache/filecache_pruner_test.go @@ -39,12 +39,9 @@ assetDir = "assets" archeTypedir = "archetypes" [caches] -[caches.getjson] +[caches.misc] maxAge = "200ms" dir = "/cache/c" -[caches.getcsv] -maxAge = "200ms" -dir = "/cache/d" [caches.assets] maxAge = "200ms" dir = ":resourceDir/_gen" @@ -53,7 +50,7 @@ maxAge = "200ms" dir = ":resourceDir/_gen" ` - for _, name := range []string{filecache.CacheKeyGetCSV, filecache.CacheKeyGetJSON, filecache.CacheKeyAssets, filecache.CacheKeyImages} { + for _, name := range []string{filecache.CacheKeyAssets, filecache.CacheKeyImages} { msg := qt.Commentf("cache: %s", name) fs := afero.NewMemMapFs() p := newPathsSpec(t, fs, configStr) diff --git a/cache/filecache/filecache_test.go b/cache/filecache/filecache_test.go index 6b435597f..35f0eee03 100644 --- a/cache/filecache/filecache_test.go +++ b/cache/filecache/filecache_test.go @@ -18,12 +18,12 @@ import ( "fmt" "io" "strings" - - "github.com/gohugoio/hugo/htesting" "sync" "testing" "time" + "github.com/gohugoio/hugo/htesting" + "github.com/gohugoio/hugo/cache/filecache" "github.com/gohugoio/hugo/common/hugio" "github.com/gohugoio/hugo/config" @@ -66,7 +66,7 @@ assetDir = "assets" archeTypedir = "archetypes" [caches] -[caches.getJSON] +[caches.misc] maxAge = "10h" dir = ":cacheDir/c" @@ -86,7 +86,7 @@ dir = ":cacheDir/c" c.Assert(err, qt.IsNil) caches.SetResourceFs(p.SourceFs) - cache := caches.Get("GetJSON") + cache := caches.Get("Misc") c.Assert(cache, qt.Not(qt.IsNil)) cache = caches.Get("Images") @@ -108,7 +108,7 @@ dir = ":cacheDir/c" return []byte("bcd"), nil } - for _, ca := range []*filecache.Cache{caches.ImageCache(), caches.AssetsCache(), caches.GetJSONCache(), caches.GetCSVCache()} { + for _, ca := range []*filecache.Cache{caches.ImageCache(), caches.AssetsCache()} { for range 2 { info, r, err := ca.GetOrCreate("a", rf("abc")) c.Assert(err, qt.IsNil) @@ -136,8 +136,6 @@ dir = ":cacheDir/c" } } - c.Assert(caches.Get("getJSON"), qt.Not(qt.IsNil)) - info, w, err := caches.ImageCache().WriteCloser("mykey") c.Assert(err, qt.IsNil) c.Assert(info.Name, qt.Equals, "mykey") @@ -177,7 +175,7 @@ assetDir = "assets" archeTypedir = "archetypes" [caches] -[caches.getjson] +[caches.misc] maxAge = "1s" dir = "/cache/c" @@ -189,7 +187,7 @@ dir = "/cache/c" c.Assert(err, qt.IsNil) caches.SetResourceFs(p.Fs.Source) - const cacheName = "getjson" + const cacheName = "misc" filenameData := func(i int) (string, string) { data := fmt.Sprintf("data: %d", i) diff --git a/common/hugo/hugo_test.go b/common/hugo/hugo_test.go index 699142212..da0d119c5 100644 --- a/common/hugo/hugo_test.go +++ b/common/hugo/hugo_test.go @@ -66,8 +66,8 @@ func TestDeprecationLogLevelFromVersion(t *testing.T) { c.Assert(deprecationLogLevelFromVersion(ver.String()), qt.Equals, logg.LevelError) // Added just to find the threshold for where we can remove deprecated items. - // Subtract 5 from the minor version of the first ERRORed version => 0.122.0. - c.Assert(deprecationLogLevelFromVersion("0.127.0"), qt.Equals, logg.LevelError) + // Subtract 5 from the minor version of the first ERRORed version => 0.136.0. + c.Assert(deprecationLogLevelFromVersion("0.141.0"), qt.Equals, logg.LevelError) } func TestMarkupScope(t *testing.T) { diff --git a/config/allconfig/allconfig.go b/config/allconfig/allconfig.go index 1efe502b1..6ed93a9ac 100644 --- a/config/allconfig/allconfig.go +++ b/config/allconfig/allconfig.go @@ -399,16 +399,6 @@ func (c *Config) CompileConfig(logger loggers.Logger) error { return err } - // Legacy paginate values. - if c.Paginate != 0 { - hugo.DeprecateWithLogger("site config key paginate", "Use pagination.pagerSize instead.", "v0.128.0", logger.Logger()) - c.Pagination.PagerSize = c.Paginate - } - if c.PaginatePath != "" { - hugo.DeprecateWithLogger("site config key paginatePath", "Use pagination.path instead.", "v0.128.0", logger.Logger()) - c.Pagination.Path = c.PaginatePath - } - // Legacy privacy values. if c.Privacy.Twitter.Disable { hugo.DeprecateWithLogger("site config key privacy.twitter.disable", "Use privacy.x.disable instead.", "v0.141.0", logger.Logger()) @@ -687,14 +677,6 @@ type RootConfig struct { // Enable if the site content has CJK language (Chinese, Japanese, or Korean). This affects how Hugo counts words. HasCJKLanguage bool - // The default number of pages per page when paginating. - // Deprecated: Use the Pagination struct. - Paginate int - - // The path to use when creating pagination URLs, e.g. "page" in /page/2/. - // Deprecated: Use the Pagination struct. - PaginatePath string - // Whether to pluralize default list titles. // Note that this currently only works for English, but you can provide your own title in the content file's front matter. PluralizeListTitles bool diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go index 2cb0b4f42..8e2430862 100644 --- a/hugolib/hugo_sites.go +++ b/hugolib/hugo_sites.go @@ -440,10 +440,6 @@ func (h *HugoSites) filterAndJoinErrors(errs []error) error { return errors.Join(errs...) } -func (h *HugoSites) isMultilingual() bool { - return len(h.Sites) > 1 -} - // TODO(bep) consolidate func (h *HugoSites) LanguageSet() map[string]int { set := make(map[string]int) diff --git a/hugolib/page__position.go b/hugolib/page__position.go index 681ad15c9..82bd208cc 100644 --- a/hugolib/page__position.go +++ b/hugolib/page__position.go @@ -17,7 +17,6 @@ import ( "context" "github.com/gohugoio/hugo/common/hsync" - "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/resources/page" ) @@ -53,22 +52,10 @@ func (p pagePosition) Next() page.Page { return p.next() } -// Deprecated: Use Next instead. -func (p pagePosition) NextPage() page.Page { - hugo.Deprecate(".Page.NextPage", "Use .Page.Next instead.", "v0.123.0") - return p.Next() -} - func (p pagePosition) Prev() page.Page { return p.prev() } -// Deprecated: Use Prev instead. -func (p pagePosition) PrevPage() page.Page { - hugo.Deprecate(".Page.PrevPage", "Use .Page.Prev instead.", "v0.123.0") - return p.Prev() -} - type pagePositionInSection struct { *nextPrev } diff --git a/hugolib/site.go b/hugolib/site.go index cf585613c..31096d0fa 100644 --- a/hugolib/site.go +++ b/hugolib/site.go @@ -663,13 +663,6 @@ func (s *Site) BaseURL() string { return s.conf.C.BaseURL.WithPath } -// Deprecated: Use .Site.Lastmod instead. -func (s *Site) LastChange() time.Time { - s.CheckReady() - hugo.Deprecate(".Site.LastChange", "Use .Site.Lastmod instead.", "v0.123.0") - return s.lastmod -} - // Returns the last modification date of the content. func (s *Site) Lastmod() time.Time { return s.lastmod @@ -680,26 +673,6 @@ func (s *Site) Params() hmaps.Params { return s.conf.Params } -// Deprecated: Use taxonomies instead. -func (s *Site) Author() map[string]any { - if len(s.conf.Author) != 0 { - hugo.Deprecate(".Site.Author", "Implement taxonomy 'author' or use .Site.Params.Author instead.", "v0.124.0") - } - return s.conf.Author -} - -// Deprecated: Use taxonomies instead. -func (s *Site) Authors() page.AuthorList { - hugo.Deprecate(".Site.Authors", "Implement taxonomy 'authors' or use .Site.Params.Author instead.", "v0.124.0") - return page.AuthorList{} -} - -// Deprecated: Use .Site.Params instead. -func (s *Site) Social() map[string]string { - hugo.Deprecate(".Site.Social", "Implement taxonomy 'social' or use .Site.Params.Social instead.", "v0.124.0") - return s.conf.Social -} - func (s *Site) Param(key any) (any, error) { return resource.Param(s, nil, key) } @@ -713,12 +686,6 @@ func (s *Site) BuildDrafts() bool { return s.conf.BuildDrafts } -// Deprecated: Use hugo.IsMultilingual instead. -func (s *Site) IsMultiLingual() bool { - hugo.Deprecate(".Site.IsMultiLingual", "Use hugo.IsMultilingual instead.", "v0.124.0") - return s.h.isMultilingual() -} - func (s *Site) LanguagePrefix() string { prefix := s.GetLanguagePrefix() if prefix == "" { diff --git a/resources/page/page.go b/resources/page/page.go index 74400d7ed..60e3cf77b 100644 --- a/resources/page/page.go +++ b/resources/page/page.go @@ -410,12 +410,6 @@ type Positioner interface { Next() Page // Prev points down to the previous regular page (sorted by Hugo’s default sort). Prev() Page - - // Deprecated: Use Prev. Will be removed in Hugo 0.57 - PrevPage() Page - - // Deprecated: Use Next. Will be removed in Hugo 0.57 - NextPage() Page } // RawContentProvider provides the raw, unprocessed content of the page. diff --git a/resources/page/page_nop.go b/resources/page/page_nop.go index d4ca5bff6..2f490aa7e 100644 --- a/resources/page/page_nop.go +++ b/resources/page/page_nop.go @@ -372,14 +372,6 @@ func (p *nopPage) NextInSection() Page { return nil } -func (p *nopPage) PrevPage() Page { - return nil -} - -func (p *nopPage) NextPage() Page { - return nil -} - func (p *nopPage) RawContent() string { return "" } diff --git a/resources/page/pagination.go b/resources/page/pagination.go index ea49d62f6..b0310f7cf 100644 --- a/resources/page/pagination.go +++ b/resources/page/pagination.go @@ -19,7 +19,6 @@ import ( "math" "reflect" - "github.com/gohugoio/hugo/common/hugo" "github.com/gohugoio/hugo/config" "github.com/spf13/cast" @@ -194,13 +193,6 @@ func (p *Paginator) Pagers() pagers { return p.pagers } -// PageSize returns the size of each paginator page. -// Deprecated: Use PagerSize instead. -func (p *Paginator) PageSize() int { - hugo.Deprecate("PageSize", "Use PagerSize instead.", "v0.128.0") - return p.size -} - // PagerSize returns the size of each paginator page. func (p *Paginator) PagerSize() int { return p.size diff --git a/resources/page/site.go b/resources/page/site.go index e6016c508..c3df5d743 100644 --- a/resources/page/site.go +++ b/resources/page/site.go @@ -92,9 +92,6 @@ type Site interface { // Returns a taxonomy map. Taxonomies() TaxonomyList - // Deprecated: Use .Lastmod instead. - LastChange() time.Time - // Returns the last modification date of the content. Lastmod() time.Time @@ -116,21 +113,9 @@ type Site interface { // Returns the site config. Config() SiteConfig - // Deprecated: Use taxonomies instead. - Author() map[string]any - - // Deprecated: Use taxonomies instead. - Authors() AuthorList - - // Deprecated: Use .Site.Params instead. - Social() map[string]string - // BuildDrafts is deprecated and will be removed in a future release. BuildDrafts() bool - // Deprecated: Use hugo.IsMultilingual instead. - IsMultiLingual() bool - // LanguagePrefix returns the language prefix for this site. LanguagePrefix() string @@ -154,12 +139,6 @@ type SiteDimension interface { // Sites represents an ordered list of sites (languages). type Sites []Site -// Deprecated: Use .Sites.Default instead. -func (s Sites) First() Site { - hugo.Deprecate(".Sites.First", "Use .Sites.Default instead.", "v0.127.0") - return s.Default() -} - // Default is a convenience method to get the site corresponding to the default // content language. func (s Sites) Default() Site { @@ -192,21 +171,6 @@ func (s *siteWrapper) Key() string { return s.s.Language().Lang } -// Deprecated: Use .Site.Params instead. -func (s *siteWrapper) Social() map[string]string { - return s.s.Social() -} - -// Deprecated: Use taxonomies instead. -func (s *siteWrapper) Author() map[string]any { - return s.s.Author() -} - -// Deprecated: Use taxonomies instead. -func (s *siteWrapper) Authors() AuthorList { - return s.s.Authors() -} - func (s *siteWrapper) GetPage(ref ...string) (Page, error) { return s.s.GetPage(ref...) } @@ -291,11 +255,6 @@ func (s *siteWrapper) Taxonomies() TaxonomyList { return s.s.Taxonomies() } -// Deprecated: Use .Site.Lastmod instead. -func (s *siteWrapper) LastChange() time.Time { - return s.s.LastChange() -} - func (s *siteWrapper) Lastmod() time.Time { return s.s.Lastmod() } @@ -324,11 +283,6 @@ func (s *siteWrapper) BuildDrafts() bool { return s.s.BuildDrafts() } -// Deprecated: Use hugo.IsMultilingual instead. -func (s *siteWrapper) IsMultiLingual() bool { - return s.s.IsMultiLingual() -} - func (s *siteWrapper) LanguagePrefix() string { return s.s.LanguagePrefix() } @@ -356,21 +310,6 @@ type testSite struct { l *langs.Language } -// Deprecated: Use taxonomies instead. -func (s testSite) Author() map[string]any { - return nil -} - -// Deprecated: Use taxonomies instead. -func (s testSite) Authors() AuthorList { - return AuthorList{} -} - -// Deprecated: Use .Site.Params instead. -func (s testSite) Social() map[string]string { - return make(map[string]string) -} - func (t testSite) Hugo() hugo.HugoInfo { return t.h } @@ -379,11 +318,6 @@ func (t testSite) ServerPort() int { return 1313 } -// Deprecated: Use .Site.Lastmod instead. -func (testSite) LastChange() (t time.Time) { - return -} - func (testSite) Lastmod() (t time.Time) { return } @@ -488,11 +422,6 @@ func (s testSite) BuildDrafts() bool { return false } -// Deprecated: Use hugo.IsMultilingual instead. -func (s testSite) IsMultiLingual() bool { - return false -} - func (s testSite) Param(key any) (any, error) { return nil, nil } diff --git a/tpl/crypto/crypto.go b/tpl/crypto/crypto.go index 677f59139..b2952e97e 100644 --- a/tpl/crypto/crypto.go +++ b/tpl/crypto/crypto.go @@ -23,9 +23,7 @@ import ( "encoding/hex" "fmt" "hash" - "hash/fnv" - "github.com/gohugoio/hugo/common/hugo" "github.com/spf13/cast" ) @@ -70,19 +68,6 @@ func (ns *Namespace) SHA256(v any) (string, error) { return hex.EncodeToString(hash[:]), nil } -// FNV32a hashes v using fnv32a algorithm. -// {"newIn": "0.98.0" } -func (ns *Namespace) FNV32a(v any) (int, error) { - hugo.Deprecate("crypto.FNV32a", "Use hash.FNV32a.", "v0.129.0") - conv, err := cast.ToStringE(v) - if err != nil { - return 0, err - } - algorithm := fnv.New32a() - algorithm.Write([]byte(conv)) - return int(algorithm.Sum32()), nil -} - // HMAC returns a cryptographic hash that uses a key to sign a message. func (ns *Namespace) HMAC(h any, k any, m any, e ...any) (string, error) { ha, err := cast.ToStringE(h) diff --git a/tpl/crypto/init.go b/tpl/crypto/init.go index 52f722a02..b31237045 100644 --- a/tpl/crypto/init.go +++ b/tpl/crypto/init.go @@ -31,12 +31,6 @@ func init() { Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil }, } - // Deprecated. Use hash.FNV32a instead. - ns.AddMethodMapping(ctx.FNV32a, - nil, - [][2]string{}, - ) - ns.AddMethodMapping(ctx.HMAC, []string{"hmac"}, [][2]string{ diff --git a/tpl/data/data.go b/tpl/data/data.go deleted file mode 100644 index 0de72ebbc..000000000 --- a/tpl/data/data.go +++ /dev/null @@ -1,209 +0,0 @@ -// Copyright 2017 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 data provides template functions for working with external data -// sources. -package data - -import ( - "bytes" - "encoding/csv" - "encoding/json" - "errors" - "fmt" - "net/http" - "slices" - "strings" - - "github.com/gohugoio/hugo/cache/filecache" - "github.com/gohugoio/hugo/common/hmaps" - "github.com/gohugoio/hugo/common/hugo" - "github.com/gohugoio/hugo/config/security" - - "github.com/gohugoio/hugo/common/types" - - "github.com/gohugoio/hugo/common/constants" - - "github.com/spf13/cast" - - "github.com/gohugoio/hugo/deps" -) - -// New returns a new instance of the data-namespaced template functions. -func New(deps *deps.Deps) *Namespace { - return &Namespace{ - deps: deps, - cacheGetCSV: deps.ResourceSpec.FileCaches.GetCSVCache(), - cacheGetJSON: deps.ResourceSpec.FileCaches.GetJSONCache(), - client: http.DefaultClient, - } -} - -// Namespace provides template functions for the "data" namespace. -type Namespace struct { - deps *deps.Deps - - cacheGetJSON *filecache.Cache - cacheGetCSV *filecache.Cache - - client *http.Client -} - -// GetCSV expects the separator sep and one or n-parts of a URL to a resource which -// can either be a local or a remote one. -// The data separator can be a comma, semi-colon, pipe, etc, but only one character. -// If you provide multiple parts for the URL they will be joined together to the final URL. -// GetCSV returns nil or a slice slice to use in a short code. -func (ns *Namespace) GetCSV(sep string, args ...any) (d [][]string, err error) { - hugo.Deprecate("data.GetCSV", "use resources.Get or resources.GetRemote with transform.Unmarshal.", "v0.123.0") - - url, headers := toURLAndHeaders(args) - cache := ns.cacheGetCSV - - unmarshal := func(b []byte) (bool, error) { - if d, err = parseCSV(b, sep); err != nil { - err = fmt.Errorf("failed to parse CSV file %s: %w", url, err) - - return true, err - } - - return false, nil - } - - var req *http.Request - req, err = http.NewRequest("GET", url, nil) - if err != nil { - return nil, fmt.Errorf("failed to create request for getCSV for resource %s: %w", url, err) - } - - // Add custom user headers. - addUserProvidedHeaders(headers, req) - addDefaultHeaders(req, "text/csv", "text/plain") - - err = ns.getResource(cache, unmarshal, req) - if err != nil { - if security.IsAccessDenied(err) { - return nil, err - } - ns.deps.Log.Erroridf(constants.ErrRemoteGetCSV, "Failed to get CSV resource %q: %s", url, err) - return nil, nil - } - - return -} - -// GetJSON expects one or n-parts of a URL in args to a resource which can either be a local or a remote one. -// If you provide multiple parts they will be joined together to the final URL. -// GetJSON returns nil or parsed JSON to use in a short code. -func (ns *Namespace) GetJSON(args ...any) (any, error) { - hugo.Deprecate("data.GetJSON", "use resources.Get or resources.GetRemote with transform.Unmarshal.", "v0.123.0") - - var v any - url, headers := toURLAndHeaders(args) - cache := ns.cacheGetJSON - - req, err := http.NewRequest("GET", url, nil) - if err != nil { - return nil, fmt.Errorf("failed to create request for getJSON resource %s: %w", url, err) - } - - unmarshal := func(b []byte) (bool, error) { - err := json.Unmarshal(b, &v) - if err != nil { - return true, err - } - return false, nil - } - - addUserProvidedHeaders(headers, req) - addDefaultHeaders(req, "application/json") - - err = ns.getResource(cache, unmarshal, req) - if err != nil { - if security.IsAccessDenied(err) { - return nil, err - } - ns.deps.Log.Erroridf(constants.ErrRemoteGetJSON, "Failed to get JSON resource %q: %s", url, err) - return nil, nil - } - - return v, nil -} - -func addDefaultHeaders(req *http.Request, accepts ...string) { - for _, accept := range accepts { - if !hasHeaderValue(req.Header, "Accept", accept) { - req.Header.Add("Accept", accept) - } - } - if !hasHeaderKey(req.Header, "User-Agent") { - req.Header.Add("User-Agent", "Hugo Static Site Generator") - } -} - -func addUserProvidedHeaders(headers map[string]any, req *http.Request) { - if headers == nil { - return - } - for key, val := range headers { - vals := types.ToStringSlicePreserveString(val) - for _, s := range vals { - req.Header.Add(key, s) - } - } -} - -func hasHeaderValue(m http.Header, key, value string) bool { - var s []string - var ok bool - - if s, ok = m[key]; !ok { - return false - } - - return slices.Contains(s, value) -} - -func hasHeaderKey(m http.Header, key string) bool { - _, ok := m[key] - return ok -} - -func toURLAndHeaders(urlParts []any) (string, map[string]any) { - if len(urlParts) == 0 { - return "", nil - } - - // The last argument may be a map. - headers, err := hmaps.ToStringMapE(urlParts[len(urlParts)-1]) - if err == nil { - urlParts = urlParts[:len(urlParts)-1] - } else { - headers = nil - } - - return strings.Join(cast.ToStringSlice(urlParts), ""), headers -} - -// parseCSV parses bytes of CSV data into a slice slice string or an error -func parseCSV(c []byte, sep string) ([][]string, error) { - if len(sep) != 1 { - return nil, errors.New("Incorrect length of CSV separator: " + sep) - } - b := bytes.NewReader(c) - r := csv.NewReader(b) - rSep := []rune(sep) - r.Comma = rSep[0] - r.FieldsPerRecord = 0 - return r.ReadAll() -} diff --git a/tpl/data/data_test.go b/tpl/data/data_test.go deleted file mode 100644 index e2bdbee36..000000000 --- a/tpl/data/data_test.go +++ /dev/null @@ -1,344 +0,0 @@ -// Copyright 2017 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 data - -import ( - "bytes" - "html/template" - "net/http" - "net/http/httptest" - "path/filepath" - "strings" - "testing" - - "github.com/bep/logg" - "github.com/gohugoio/hugo/common/hmaps" - "github.com/gohugoio/hugo/htesting" - - qt "github.com/frankban/quicktest" -) - -func TestGetCSV(t *testing.T) { - t.Parallel() - htesting.SkipSlowTestUnlessCI(t) - - c := qt.New(t) - - for i, test := range []struct { - sep string - url string - content string - expect any - }{ - // Remotes - { - ",", - `http://success/`, - "gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm\n", - [][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}}, - }, - { - ",", - `http://error.extra.field/`, - "gomeetup,city\nyes,Sydney\nyes,San Francisco\nyes,Stockholm,EXTRA\n", - false, - }, - { - ",", - `http://nofound/404`, - ``, - false, - }, - - // Locals - { - ";", - "pass/semi", - "gomeetup;city\nyes;Sydney\nyes;San Francisco\nyes;Stockholm\n", - [][]string{{"gomeetup", "city"}, {"yes", "Sydney"}, {"yes", "San Francisco"}, {"yes", "Stockholm"}}, - }, - { - ";", - "fail/no-file", - "", - false, - }, - } { - c.Run(test.url, func(c *qt.C) { - msg := qt.Commentf("Test %d", i) - - ns := newTestNs() - - // Setup HTTP test server - var srv *httptest.Server - srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) { - if !hasHeaderValue(r.Header, "Accept", "text/csv") && !hasHeaderValue(r.Header, "Accept", "text/plain") { - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - return - } - - if r.URL.Path == "/404" { - http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - return - } - - w.Header().Add("Content-type", "text/csv") - - w.Write([]byte(test.content)) - }) - defer func() { srv.Close() }() - - // Setup local test file for schema-less URLs - if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") { - f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Conf.BaseConfig().WorkingDir, test.url)) - c.Assert(err, qt.IsNil, msg) - f.WriteString(test.content) - f.Close() - } - - // Get on with it - got, err := ns.GetCSV(test.sep, test.url) - - if _, ok := test.expect.(bool); ok { - c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 1) - c.Assert(got, qt.IsNil) - return - } - - c.Assert(err, qt.IsNil, msg) - c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 0) - c.Assert(got, qt.Not(qt.IsNil), msg) - c.Assert(got, qt.DeepEquals, test.expect, msg) - }) - } -} - -func TestGetJSON(t *testing.T) { - t.Parallel() - htesting.SkipSlowTestUnlessCI(t) - c := qt.New(t) - - for i, test := range []struct { - url string - content string - expect any - }{ - { - `http://success/`, - `{"gomeetup":["Sydney","San Francisco","Stockholm"]}`, - map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}}, - }, - { - `http://malformed/`, - `{gomeetup:["Sydney","San Francisco","Stockholm"]}`, - false, - }, - { - `http://nofound/404`, - ``, - false, - }, - // Locals - { - "pass/semi", - `{"gomeetup":["Sydney","San Francisco","Stockholm"]}`, - map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}}, - }, - { - "fail/no-file", - "", - false, - }, - { - `pass/üńīçøðê-url.json`, - `{"gomeetup":["Sydney","San Francisco","Stockholm"]}`, - map[string]any{"gomeetup": []any{"Sydney", "San Francisco", "Stockholm"}}, - }, - } { - c.Run(test.url, func(c *qt.C) { - msg := qt.Commentf("Test %d", i) - ns := newTestNs() - - // Setup HTTP test server - var srv *httptest.Server - srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) { - if !hasHeaderValue(r.Header, "Accept", "application/json") { - http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest) - return - } - - if r.URL.Path == "/404" { - http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound) - return - } - - w.Header().Add("Content-type", "application/json") - - w.Write([]byte(test.content)) - }) - defer func() { srv.Close() }() - - // Setup local test file for schema-less URLs - if !strings.Contains(test.url, ":") && !strings.HasPrefix(test.url, "fail/") { - f, err := ns.deps.Fs.Source.Create(filepath.Join(ns.deps.Conf.BaseConfig().WorkingDir, test.url)) - c.Assert(err, qt.IsNil, msg) - f.WriteString(test.content) - f.Close() - } - - // Get on with it - got, _ := ns.GetJSON(test.url) - - if _, ok := test.expect.(bool); ok { - c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 1) - return - } - - c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 0, msg) - c.Assert(got, qt.Not(qt.IsNil), msg) - c.Assert(got, qt.DeepEquals, test.expect) - }) - } -} - -func TestHeaders(t *testing.T) { - t.Parallel() - c := qt.New(t) - - for _, test := range []struct { - name string - headers any - assert func(c *qt.C, headers string) - }{ - { - `Misc header variants`, - map[string]any{ - "Accept-Charset": "utf-8", - "Max-forwards": "10", - "X-Int": 32, - "X-Templ": template.HTML("a"), - "X-Multiple": []string{"a", "b"}, - "X-MultipleInt": []int{3, 4}, - }, - func(c *qt.C, headers string) { - c.Assert(headers, qt.Contains, "Accept-Charset: utf-8") - c.Assert(headers, qt.Contains, "Max-Forwards: 10") - c.Assert(headers, qt.Contains, "X-Int: 32") - c.Assert(headers, qt.Contains, "X-Templ: a") - c.Assert(headers, qt.Contains, "X-Multiple: a") - c.Assert(headers, qt.Contains, "X-Multiple: b") - c.Assert(headers, qt.Contains, "X-Multipleint: 3") - c.Assert(headers, qt.Contains, "X-Multipleint: 4") - c.Assert(headers, qt.Contains, "User-Agent: Hugo Static Site Generator") - }, - }, - { - `Params`, - hmaps.Params{ - "Accept-Charset": "utf-8", - }, - func(c *qt.C, headers string) { - c.Assert(headers, qt.Contains, "Accept-Charset: utf-8") - }, - }, - { - `Override User-Agent`, - map[string]any{ - "User-Agent": "007", - }, - func(c *qt.C, headers string) { - c.Assert(headers, qt.Contains, "User-Agent: 007") - }, - }, - } { - c.Run(test.name, func(c *qt.C) { - ns := newTestNs() - - // Setup HTTP test server - var srv *httptest.Server - var headers bytes.Buffer - srv, ns.client = getTestServer(func(w http.ResponseWriter, r *http.Request) { - c.Assert(r.URL.String(), qt.Equals, "http://gohugo.io/api?foo") - w.Write([]byte("{}")) - r.Header.Write(&headers) - }) - defer func() { srv.Close() }() - - testFunc := func(fn func(args ...any) error) { - defer headers.Reset() - err := fn("http://example.org/api", "?foo", test.headers) - - c.Assert(err, qt.IsNil) - c.Assert(int(ns.deps.Log.LoggCount(logg.LevelError)), qt.Equals, 0) - test.assert(c, headers.String()) - } - - testFunc(func(args ...any) error { - _, err := ns.GetJSON(args...) - return err - }) - testFunc(func(args ...any) error { - _, err := ns.GetCSV(",", args...) - return err - }) - }) - } -} - -func TestToURLAndHeaders(t *testing.T) { - t.Parallel() - c := qt.New(t) - url, headers := toURLAndHeaders([]any{"https://foo?id=", 32}) - c.Assert(url, qt.Equals, "https://foo?id=32") - c.Assert(headers, qt.IsNil) - - url, headers = toURLAndHeaders([]any{"https://foo?id=", 32, map[string]any{"a": "b"}}) - c.Assert(url, qt.Equals, "https://foo?id=32") - c.Assert(headers, qt.DeepEquals, map[string]any{"a": "b"}) -} - -func TestParseCSV(t *testing.T) { - t.Parallel() - c := qt.New(t) - - for i, test := range []struct { - csv []byte - sep string - exp string - err bool - }{ - {[]byte("a,b,c\nd,e,f\n"), "", "", true}, - {[]byte("a,b,c\nd,e,f\n"), "~/", "", true}, - {[]byte("a,b,c\nd,e,f"), "|", "a,b,cd,e,f", false}, - {[]byte("q,w,e\nd,e,f"), ",", "qwedef", false}, - {[]byte("a|b|c\nd|e|f|g"), "|", "abcdefg", true}, - {[]byte("z|y|c\nd|e|f"), "|", "zycdef", false}, - } { - msg := qt.Commentf("Test %d: %v", i, test) - - csv, err := parseCSV(test.csv, test.sep) - if test.err { - c.Assert(err, qt.Not(qt.IsNil), msg) - continue - } - c.Assert(err, qt.IsNil, msg) - - act := "" - for _, v := range csv { - act = act + strings.Join(v, "") - } - - c.Assert(act, qt.Equals, test.exp, msg) - } -} diff --git a/tpl/data/init.go b/tpl/data/init.go deleted file mode 100644 index 47656d398..000000000 --- a/tpl/data/init.go +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2017 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 data - -import ( - "context" - - "github.com/gohugoio/hugo/deps" - "github.com/gohugoio/hugo/tpl/internal" -) - -const name = "data" - -func init() { - f := func(d *deps.Deps) *internal.TemplateFuncsNamespace { - ctx := New(d) - - ns := &internal.TemplateFuncsNamespace{ - Name: name, - Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil }, - } - - // Deprecated. Use resources.GetRemote instead. - ns.AddMethodMapping(ctx.GetCSV, - []string{"getCSV"}, - [][2]string{}, - ) - - // Deprecated. Use resources.GetRemote instead. - ns.AddMethodMapping(ctx.GetJSON, - []string{"getJSON"}, - [][2]string{}, - ) - return ns - } - - internal.AddTemplateFuncsNamespace(f) -} diff --git a/tpl/data/resources.go b/tpl/data/resources.go deleted file mode 100644 index 9e06c0cce..000000000 --- a/tpl/data/resources.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2016 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 data - -import ( - "bytes" - "fmt" - "io" - "net/http" - "net/url" - "path/filepath" - "time" - - "github.com/gohugoio/hugo/cache/filecache" - "github.com/gohugoio/hugo/common/hashing" - "github.com/spf13/afero" -) - -var ( - resSleep = time.Second * 2 // if JSON decoding failed sleep for n seconds before retrying - resRetries = 1 // number of retries to load the JSON from URL -) - -// getRemote loads the content of a remote file. This method is thread safe. -func (ns *Namespace) getRemote(cache *filecache.Cache, unmarshal func([]byte) (bool, error), req *http.Request) error { - url := req.URL.String() - if err := ns.deps.ExecHelper.Sec().CheckAllowedHTTPURL(url); err != nil { - return err - } - if err := ns.deps.ExecHelper.Sec().CheckAllowedHTTPMethod("GET"); err != nil { - return err - } - - var headers bytes.Buffer - req.Header.Write(&headers) - id := hashing.MD5FromStringHexEncoded(url + headers.String()) - var handled bool - var retry bool - - _, b, err := cache.GetOrCreateBytes(id, func() ([]byte, error) { - var err error - handled = true - for i := 0; i <= resRetries; i++ { - ns.deps.Log.Infof("Downloading: %s ...", url) - var res *http.Response - res, err = ns.client.Do(req) - if err != nil { - return nil, err - } - - var b []byte - b, err = io.ReadAll(res.Body) - if err != nil { - return nil, err - } - res.Body.Close() - - if isHTTPError(res) { - return nil, fmt.Errorf("failed to retrieve remote file: %s, body: %q", http.StatusText(res.StatusCode), b) - } - - retry, err = unmarshal(b) - - if err == nil { - // Return it so it can be cached. - return b, nil - } - - if !retry { - return nil, err - } - - ns.deps.Log.Infof("Cannot read remote resource %s: %s", url, err) - ns.deps.Log.Infof("Retry #%d for %s and sleeping for %s", i+1, url, resSleep) - time.Sleep(resSleep) - } - - return nil, err - }) - - if !handled { - // This is cached content and should be correct. - _, err = unmarshal(b) - } - - return err -} - -// getLocal loads the content of a local file -func getLocal(workingDir, url string, fs afero.Fs) ([]byte, error) { - filename := filepath.Join(workingDir, url) - return afero.ReadFile(fs, filename) -} - -// getResource loads the content of a local or remote file and returns its content and the -// cache ID used, if relevant. -func (ns *Namespace) getResource(cache *filecache.Cache, unmarshal func(b []byte) (bool, error), req *http.Request) error { - switch req.URL.Scheme { - case "": - url, err := url.QueryUnescape(req.URL.String()) - if err != nil { - return err - } - b, err := getLocal(ns.deps.Conf.BaseConfig().WorkingDir, url, ns.deps.Fs.Source) - if err != nil { - return err - } - _, err = unmarshal(b) - return err - default: - return ns.getRemote(cache, unmarshal, req) - } -} - -func isHTTPError(res *http.Response) bool { - return res.StatusCode < 200 || res.StatusCode > 299 -} diff --git a/tpl/data/resources_test.go b/tpl/data/resources_test.go deleted file mode 100644 index d49e74d4c..000000000 --- a/tpl/data/resources_test.go +++ /dev/null @@ -1,202 +0,0 @@ -// Copyright 2016 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 data - -import ( - "bytes" - "net/http" - "net/http/httptest" - "net/url" - "path/filepath" - "sync" - "testing" - "time" - - "github.com/gohugoio/hugo/cache/filecache" - "github.com/gohugoio/hugo/common/loggers" - - "github.com/gohugoio/hugo/config/testconfig" - - "github.com/gohugoio/hugo/helpers" - - qt "github.com/frankban/quicktest" - "github.com/gohugoio/hugo/config" - "github.com/gohugoio/hugo/deps" - "github.com/gohugoio/hugo/hugofs" - "github.com/spf13/afero" -) - -func TestScpGetLocal(t *testing.T) { - t.Parallel() - v := config.New() - workingDir := "/my/working/dir" - v.Set("workingDir", workingDir) - v.Set("publishDir", "public") - fs := hugofs.NewFromOld(afero.NewMemMapFs(), v) - ps := helpers.FilePathSeparator - - tests := []struct { - path string - content []byte - }{ - {"testpath" + ps + "test.txt", []byte(`T€st Content 123 fOO,bar:foo%bAR`)}, - {"FOo" + ps + "BaR.html", []byte(`FOo/BaR.html T€st Content 123`)}, - {"трям" + ps + "трям", []byte(`T€st трям/трям Content 123`)}, - {"은행", []byte(`T€st C은행ontent 123`)}, - {"Банковский кассир", []byte(`Банковский кассир T€st Content 123`)}, - } - - for _, test := range tests { - r := bytes.NewReader(test.content) - err := helpers.WriteToDisk(filepath.Join(workingDir, test.path), r, fs.Source) - if err != nil { - t.Error(err) - } - - c, err := getLocal(workingDir, test.path, fs.Source) - if err != nil { - t.Errorf("Error getting resource content: %s", err) - } - if !bytes.Equal(c, test.content) { - t.Errorf("\nExpected: %s\nActual: %s\n", string(test.content), string(c)) - } - } -} - -func getTestServer(handler func(w http.ResponseWriter, r *http.Request)) (*httptest.Server, *http.Client) { - testServer := httptest.NewServer(http.HandlerFunc(handler)) - client := &http.Client{ - Transport: &http.Transport{Proxy: func(r *http.Request) (*url.URL, error) { - // Remove when https://github.com/golang/go/issues/13686 is fixed - r.Host = "gohugo.io" - return url.Parse(testServer.URL) - }}, - } - return testServer, client -} - -func TestScpGetRemote(t *testing.T) { - t.Parallel() - c := qt.New(t) - fs := new(afero.MemMapFs) - cache := filecache.NewCache(fs, 100, "") - - tests := []struct { - path string - content []byte - }{ - {"http://Foo.Bar/foo_Bar-Foo", []byte(`T€st Content 123`)}, - {"http://Doppel.Gänger/foo_Bar-Foo", []byte(`T€st Cont€nt 123`)}, - {"http://Doppel.Gänger/Fizz_Bazz-Foo", []byte(`T€st Банковский кассир Cont€nt 123`)}, - {"http://Doppel.Gänger/Fizz_Bazz-Bar", []byte(`T€st Банковский кассир Cont€nt 456`)}, - } - - for _, test := range tests { - msg := qt.Commentf("%v", test) - - req, err := http.NewRequest("GET", test.path, nil) - c.Assert(err, qt.IsNil, msg) - - srv, cl := getTestServer(func(w http.ResponseWriter, r *http.Request) { - w.Write(test.content) - }) - defer func() { srv.Close() }() - - ns := newTestNs() - ns.client = cl - - var cb []byte - f := func(b []byte) (bool, error) { - cb = b - return false, nil - } - - err = ns.getRemote(cache, f, req) - c.Assert(err, qt.IsNil, msg) - c.Assert(string(cb), qt.Equals, string(test.content)) - - c.Assert(string(cb), qt.Equals, string(test.content)) - - } -} - -func TestScpGetRemoteParallel(t *testing.T) { - t.Parallel() - c := qt.New(t) - - content := []byte(`T€st Content 123`) - srv, cl := getTestServer(func(w http.ResponseWriter, r *http.Request) { - w.Write(content) - }) - - defer func() { srv.Close() }() - - url := "http://Foo.Bar/foo_Bar-Foo" - req, err := http.NewRequest("GET", url, nil) - c.Assert(err, qt.IsNil) - - for _, ignoreCache := range []bool{false} { - cfg := config.New() - cfg.Set("ignoreCache", ignoreCache) - - ns := New(newDeps(cfg)) - ns.client = cl - - var wg sync.WaitGroup - - for i := range 1 { - wg.Add(1) - go func(gor int) { - defer wg.Done() - for range 10 { - var cb []byte - f := func(b []byte) (bool, error) { - cb = b - return false, nil - } - err := ns.getRemote(ns.cacheGetJSON, f, req) - - c.Assert(err, qt.IsNil) - if string(content) != string(cb) { - t.Errorf("expected\n%q\ngot\n%q", content, cb) - } - - time.Sleep(23 * time.Millisecond) - } - }(i) - } - - wg.Wait() - } -} - -func newDeps(cfg config.Provider) *deps.Deps { - conf := testconfig.GetTestConfig(nil, cfg) - logger := loggers.NewDefault() - fs := hugofs.NewFrom(afero.NewMemMapFs(), conf.BaseConfig()) - - d := &deps.Deps{ - Fs: fs, - Log: logger, - Conf: conf, - } - if err := d.Init(); err != nil { - panic(err) - } - return d -} - -func newTestNs() *Namespace { - return New(newDeps(config.New())) -} diff --git a/tpl/resources/init.go b/tpl/resources/init.go index 9048e3a46..9ce9bee20 100644 --- a/tpl/resources/init.go +++ b/tpl/resources/init.go @@ -17,9 +17,7 @@ import ( "context" "github.com/gohugoio/hugo/deps" - "github.com/gohugoio/hugo/tpl/css" "github.com/gohugoio/hugo/tpl/internal" - "github.com/gohugoio/hugo/tpl/js" ) const name = "resources" @@ -35,30 +33,8 @@ func init() { ns := &internal.TemplateFuncsNamespace{ Name: name, Context: func(cctx context.Context, args ...any) (any, error) { return ctx, nil }, - OnCreated: func(m map[string]any) { - for _, v := range m { - switch v := v.(type) { - case *css.Namespace: - ctx.cssNs = v - case *js.Namespace: - ctx.jsNs = v - } - } - if ctx.cssNs == nil { - panic("css namespace not found") - } - if ctx.jsNs == nil { - panic("js namespace not found") - } - }, } - // Deprecated. Use js.Babel instead. - ns.AddMethodMapping(ctx.Babel, - nil, - [][2]string{}, - ) - ns.AddMethodMapping(ctx.ByType, nil, [][2]string{}, @@ -114,23 +90,11 @@ func init() { [][2]string{}, ) - // Deprecated. Use css.PostCSS instead. - ns.AddMethodMapping(ctx.PostCSS, - nil, - [][2]string{}, - ) - ns.AddMethodMapping(ctx.PostProcess, nil, [][2]string{}, ) - // Deprecated. Use css.Sass instead. - ns.AddMethodMapping(ctx.ToCSS, - nil, - [][2]string{}, - ) - return ns } diff --git a/tpl/resources/resources.go b/tpl/resources/resources.go index da537ab99..62a0b6c51 100644 --- a/tpl/resources/resources.go +++ b/tpl/resources/resources.go @@ -20,10 +20,6 @@ import ( "fmt" "github.com/gohugoio/hugo/common/hmaps" - "github.com/gohugoio/hugo/common/hugo" - - "github.com/gohugoio/hugo/tpl/css" - "github.com/gohugoio/hugo/tpl/js" "github.com/gohugoio/hugo/resources/postpub" @@ -72,11 +68,6 @@ type Namespace struct { integrityClient *integrity.Client minifyClient *minifier.Client templatesClient *templates.Client - - // We moved some CSS and JS related functions to the css and js package in Hugo 0.128.0. - // Keep this here until the deprecation period is over. - cssNs *css.Namespace - jsNs *js.Namespace } // Copy copies r to the new targetPath in s. @@ -301,30 +292,7 @@ func (ns *Namespace) Minify(r resources.ResourceTransformer) (resource.Resource, return ns.minifyClient.Minify(r) } -// ToCSS converts the given Resource to CSS. You can optional provide an Options object -// as second argument. As an option, you can e.g. specify e.g. the target path (string) -// for the converted CSS resource. -// Deprecated: Moved to the css namespace in Hugo 0.128.0. -func (ns *Namespace) ToCSS(args ...any) (resource.Resource, error) { - hugo.Deprecate("resources.ToCSS", "Use css.Sass instead.", "v0.128.0") - return ns.cssNs.Sass(args...) -} - -// PostCSS processes the given Resource with PostCSS. -// Deprecated: Moved to the css namespace in Hugo 0.128.0. -func (ns *Namespace) PostCSS(args ...any) (resource.Resource, error) { - hugo.Deprecate("resources.PostCSS", "Use css.PostCSS instead.", "v0.128.0") - return ns.cssNs.PostCSS(args...) -} - // PostProcess processes r after the build. func (ns *Namespace) PostProcess(r resource.Resource) (postpub.PostPublishedResource, error) { return ns.deps.ResourceSpec.PostProcess(r) } - -// Babel processes the given Resource with Babel. -// Deprecated: Moved to the js namespace in Hugo 0.128.0. -func (ns *Namespace) Babel(args ...any) (resource.Resource, error) { - hugo.Deprecate("resources.Babel", "Use js.Babel.", "v0.128.0") - return ns.jsNs.Babel(args...) -} diff --git a/tpl/tplimplinit/tplimplinit.go b/tpl/tplimplinit/tplimplinit.go index 6316e8897..a958b0669 100644 --- a/tpl/tplimplinit/tplimplinit.go +++ b/tpl/tplimplinit/tplimplinit.go @@ -26,7 +26,6 @@ import ( _ "github.com/gohugoio/hugo/tpl/compare" _ "github.com/gohugoio/hugo/tpl/crypto" _ "github.com/gohugoio/hugo/tpl/css" - _ "github.com/gohugoio/hugo/tpl/data" _ "github.com/gohugoio/hugo/tpl/debug" _ "github.com/gohugoio/hugo/tpl/diagrams" _ "github.com/gohugoio/hugo/tpl/encoding"