go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/templates/context.go (about) 1 // Copyright 2015 The LUCI Authors. 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 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package templates 16 17 import ( 18 "context" 19 "errors" 20 "html/template" 21 "io" 22 ) 23 24 var ( 25 errNoBundle = errors.New("templates: context doesn't have templates.Bundle") 26 contextKey = "templates.Bundle" 27 ) 28 29 // boundBundle is stored in the context by Use(...). It lives for a duration of 30 // one request and stores extra information about this request. 31 type boundBundle struct { 32 *Bundle 33 *Extra 34 } 35 36 // Use replaces the template bundle in the context. There can be only one bundle 37 // installed at any time. 38 // 39 // It also takes an Extra to be passed to bundle's DefaultArgs(...) callback 40 // when using Render(...) or MustRender(...) top-level functions. 41 // 42 // DefaultArgs(...) can use the context and the given Extra to extract 43 // information about the environment. 44 func Use(c context.Context, b *Bundle, e *Extra) context.Context { 45 b.EnsureLoaded(c) 46 return context.WithValue(c, &contextKey, &boundBundle{b, e}) 47 } 48 49 // Get returns template from the currently loaded bundle or error if not found. 50 func Get(c context.Context, name string) (*template.Template, error) { 51 if b, _ := c.Value(&contextKey).(*boundBundle); b != nil { 52 return b.Get(name) 53 } 54 return nil, errNoBundle 55 } 56 57 // Render finds top level template with given name and calls its Execute or 58 // ExecuteTemplate method (depending on the value of Bundle.DefaultTemplate). 59 // 60 // It always renders output into a byte buffer, to avoid partial results in case 61 // of errors. 62 func Render(c context.Context, name string, args Args) ([]byte, error) { 63 if b, _ := c.Value(&contextKey).(*boundBundle); b != nil { 64 return b.Render(c, b.Extra, name, args) 65 } 66 return nil, errNoBundle 67 } 68 69 // MustRender renders the template into the output writer or panics. 70 // 71 // It never writes partial output. It also panics if attempt to write to 72 // the output fails. 73 func MustRender(c context.Context, out io.Writer, name string, args Args) { 74 if b, _ := c.Value(&contextKey).(*boundBundle); b != nil { 75 b.MustRender(c, b.Extra, out, name, args) 76 return 77 } 78 panic(errNoBundle) 79 }