1
0
mirror of https://github.com/danog/gojekyll.git synced 2024-11-27 13:24:41 +01:00
gojekyll/pipelines/pipeline.go
2017-07-14 12:12:25 -04:00

120 lines
3.2 KiB
Go

package pipelines
import (
"bytes"
"io"
"github.com/osteele/gojekyll/config"
"github.com/osteele/gojekyll/filters"
"github.com/osteele/gojekyll/tags"
"github.com/osteele/gojekyll/templates"
"github.com/osteele/gojekyll/utils"
"github.com/osteele/liquid"
)
// PipelineInterface applies transformations to a document.
type PipelineInterface interface {
ApplyLayout(string, []byte, map[string]interface{}) ([]byte, error)
OutputExt(pathname string) string
Render(io.Writer, []byte, string, int, map[string]interface{}) ([]byte, error)
}
// Pipeline applies a rendering transformation to a file.
type Pipeline struct {
PipelineOptions
config config.Config
liquidEngine *liquid.Engine
sassTempDir string
sassHash string
}
// PipelineOptions configures a pipeline.
type PipelineOptions struct {
RelativeFilenameToURL tags.LinkTagHandler
}
// NewPipeline makes a rendering pipeline.
func NewPipeline(c config.Config, options PipelineOptions) (*Pipeline, error) {
p := Pipeline{PipelineOptions: options, config: c}
p.liquidEngine = p.makeLiquidEngine()
if err := p.CopySassFileIncludes(); err != nil {
return nil, err
}
return &p, nil
}
// SourceDir returns the site source directory. Seeing how far we can bend
// the Law of Demeter.
func (p *Pipeline) SourceDir() string {
return p.config.Source
}
// TemplateEngine returns the Liquid engine.
func (p *Pipeline) TemplateEngine() *liquid.Engine {
return p.liquidEngine
}
// OutputExt returns the output extension.
func (p *Pipeline) OutputExt(pathname string) string {
return p.config.OutputExt(pathname)
}
// Render returns nil iff it wrote to the writer
func (p *Pipeline) Render(w io.Writer, b []byte, filename string, lineNo int, e map[string]interface{}) ([]byte, error) {
if p.config.IsSASSPath(filename) {
buf := new(bytes.Buffer)
if err := p.WriteSass(buf, b); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
b, err := p.renderTemplate(b, e, filename, lineNo)
if err != nil {
return nil, err
}
if p.config.IsMarkdown(filename) {
b = markdownRenderer(b)
}
return b, nil
}
func (p *Pipeline) renderTemplate(src []byte, b map[string]interface{}, filename string, lineNo int) ([]byte, error) {
tpl, err := p.liquidEngine.ParseTemplateLocation(src, filename, lineNo)
if err != nil {
return nil, utils.WrapPathError(err, filename)
}
out, err := tpl.Render(b)
if err != nil {
return nil, utils.WrapPathError(err, filename)
}
return out, err
}
// ApplyLayout applies the named layout to the data.
func (p *Pipeline) ApplyLayout(name string, data []byte, e map[string]interface{}) ([]byte, error) {
for name != "" {
var lfm map[string]interface{}
tpl, err := p.FindLayout(name, &lfm)
if err != nil {
return nil, err
}
b := utils.MergeStringMaps(e, map[string]interface{}{
"content": string(data),
"layout": lfm,
})
data, err = tpl.Render(b)
if err != nil {
return nil, utils.WrapPathError(err, name)
}
name = templates.VariableMap(lfm).String("layout", "")
}
return data, nil
}
func (p *Pipeline) makeLiquidEngine() *liquid.Engine {
engine := liquid.NewEngine()
filters.AddJekyllFilters(engine, &p.config)
tags.AddJekyllTags(engine, &p.config, p.RelativeFilenameToURL)
return engine
}