gitee.com/mirrors/Hugo-Go@v0.47.1/transform/chain.go (about) 1 // Copyright 2018 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 transform 15 16 import ( 17 "bytes" 18 "io" 19 20 bp "github.com/gohugoio/hugo/bufferpool" 21 ) 22 23 // Transformer is the func that needs to be implemented by a transformation step. 24 type Transformer func(ft FromTo) error 25 26 // BytesReader wraps the Bytes method, usually implemented by bytes.Buffer, and an 27 // io.Reader. 28 type BytesReader interface { 29 // The slice given by Bytes is valid for use only until the next buffer modification. 30 // That is, if you want to use this value outside of the current transformer step, 31 // you need to take a copy. 32 Bytes() []byte 33 34 io.Reader 35 } 36 37 // FromTo is sent to each transformation step in the chain. 38 type FromTo interface { 39 From() BytesReader 40 To() io.Writer 41 } 42 43 // Chain is an ordered processing chain. The next transform operation will 44 // receive the output from the previous. 45 type Chain []Transformer 46 47 // New creates a content transformer chain given the provided transform funcs. 48 func New(trs ...Transformer) Chain { 49 return trs 50 } 51 52 // NewEmpty creates a new slice of transformers with a capacity of 20. 53 func NewEmpty() Chain { 54 return make(Chain, 0, 20) 55 } 56 57 // Implements contentTransformer 58 // Content is read from the from-buffer and rewritten to to the to-buffer. 59 type fromToBuffer struct { 60 from *bytes.Buffer 61 to *bytes.Buffer 62 } 63 64 func (ft fromToBuffer) From() BytesReader { 65 return ft.from 66 } 67 68 func (ft fromToBuffer) To() io.Writer { 69 return ft.to 70 } 71 72 // Apply passes the given from io.Reader through the transformation chain. 73 // The result is written to to. 74 func (c *Chain) Apply(to io.Writer, from io.Reader) error { 75 if len(*c) == 0 { 76 _, err := io.Copy(to, from) 77 return err 78 } 79 80 b1 := bp.GetBuffer() 81 defer bp.PutBuffer(b1) 82 83 if _, err := b1.ReadFrom(from); err != nil { 84 return err 85 } 86 87 b2 := bp.GetBuffer() 88 defer bp.PutBuffer(b2) 89 90 fb := &fromToBuffer{from: b1, to: b2} 91 92 for i, tr := range *c { 93 if i > 0 { 94 if fb.from == b1 { 95 fb.from = b2 96 fb.to = b1 97 fb.to.Reset() 98 } else { 99 fb.from = b1 100 fb.to = b2 101 fb.to.Reset() 102 } 103 } 104 105 if err := tr(fb); err != nil { 106 return err 107 } 108 } 109 110 _, err := fb.to.WriteTo(to) 111 return err 112 }