// Copyright 2016 The Hugo Authors. All rights reserved. // // Portions Copyright The Go Authors. // 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 tplimpl import ( "fmt" "html/template" "sync" "github.com/spf13/cast" "github.com/spf13/hugo/tpl/internal" // Init the namespaces _ "github.com/spf13/hugo/tpl/collections" _ "github.com/spf13/hugo/tpl/compare" _ "github.com/spf13/hugo/tpl/crypto" _ "github.com/spf13/hugo/tpl/data" _ "github.com/spf13/hugo/tpl/encoding" _ "github.com/spf13/hugo/tpl/images" _ "github.com/spf13/hugo/tpl/inflect" _ "github.com/spf13/hugo/tpl/lang" _ "github.com/spf13/hugo/tpl/math" _ "github.com/spf13/hugo/tpl/os" _ "github.com/spf13/hugo/tpl/safe" _ "github.com/spf13/hugo/tpl/strings" _ "github.com/spf13/hugo/tpl/time" _ "github.com/spf13/hugo/tpl/transform" ) // Get retrieves partial output from the cache based upon the partial name. // If the partial is not found in the cache, the partial is rendered and added // to the cache. func (t *templateFuncster) Get(key, name string, context interface{}) (p interface{}, err error) { var ok bool t.cachedPartials.RLock() p, ok = t.cachedPartials.p[key] t.cachedPartials.RUnlock() if ok { return } t.cachedPartials.Lock() if p, ok = t.cachedPartials.p[key]; !ok { t.cachedPartials.Unlock() p, err = t.partial(name, context) t.cachedPartials.Lock() t.cachedPartials.p[key] = p } t.cachedPartials.Unlock() return } // partialCache represents a cache of partials protected by a mutex. type partialCache struct { sync.RWMutex p map[string]interface{} } // partialCached executes and caches partial templates. An optional variant // string parameter (a string slice actually, but be only use a variadic // argument to make it optional) can be passed so that a given partial can have // multiple uses. The cache is created with name+variant as the key. func (t *templateFuncster) partialCached(name string, context interface{}, variant ...string) (interface{}, error) { key := name if len(variant) > 0 { for i := 0; i < len(variant); i++ { key += variant[i] } } return t.Get(key, name, context) } func (t *templateFuncster) initFuncMap() { funcMap := template.FuncMap{ // Namespaces //"time": t.time.Namespace, "urls": t.urls.Namespace, "absURL": t.urls.AbsURL, "absLangURL": t.urls.AbsLangURL, "int": func(v interface{}) (int, error) { return cast.ToIntE(v) }, "partial": t.partial, "partialCached": t.partialCached, "print": fmt.Sprint, "printf": fmt.Sprintf, "println": fmt.Sprintln, "ref": t.urls.Ref, "relURL": t.urls.RelURL, "relLangURL": t.urls.RelLangURL, "relref": t.urls.RelRef, "string": func(v interface{}) (string, error) { return cast.ToStringE(v) }, "urlize": t.PathSpec.URLize, } // Merge the namespace funcs for _, nsf := range internal.TemplateFuncsNamespaceRegistry { ns := nsf(t.Deps) // TODO(bep) namespace ns.Context is a dummy func just to make this work. // Consider if we can add this context to the rendering context in an easy // way to make this cleaner. Maybe. funcMap[ns.Name] = ns.Context for k, v := range ns.Aliases { funcMap[k] = v } } t.funcMap = funcMap t.Tmpl.(*templateHandler).setFuncs(funcMap) }