Compare commits

..

2 Commits

Author SHA1 Message Date
e24e892773 Revert "Change File to interface"
This reverts commit 2f95fdba2d.
2024-03-03 18:09:21 -08:00
9ba1c7cfeb Revert "Make Context be an interface"
This reverts commit ab0c1c53d2.
2024-03-03 17:46:38 -08:00
31 changed files with 264 additions and 178 deletions

View File

@ -15,7 +15,7 @@ type cache struct {
baseDir string baseDir string
} }
func (self *cache) retrieveFile(context *contextImpl, outputPath string, inputFiles []File) (File, error) { func (self *cache) retrieveFile(context *Context, outputPath string, inputFiles []*File) (*File, error) {
cachePath, err := self.buildCachePath(context, outputPath, inputFiles) cachePath, err := self.buildCachePath(context, outputPath, inputFiles)
if err != nil { if err != nil {
return nil, err return nil, err
@ -33,7 +33,7 @@ func (self *cache) retrieveFile(context *contextImpl, outputPath string, inputFi
return outputFile, nil return outputFile, nil
} }
func (self *cache) storeFile(context *contextImpl, outputFile File, inputFiles []File) error { func (self *cache) storeFile(context *Context, outputFile *File, inputFiles []*File) error {
cachePath, err := self.buildCachePath(context, outputFile.Path(), inputFiles) cachePath, err := self.buildCachePath(context, outputFile.Path(), inputFiles)
if err != nil { if err != nil {
return err return err
@ -69,7 +69,7 @@ func (self *cache) storeFile(context *contextImpl, outputFile File, inputFiles [
return nil return nil
} }
func (self *cache) buildCachePath(context *contextImpl, outputPath string, inputFiles []File) (string, error) { func (self *cache) buildCachePath(context *Context, outputPath string, inputFiles []*File) (string, error) {
hasher := crc32.NewIEEE() hasher := crc32.NewIEEE()
hasher.Write([]byte(outputPath)) hasher.Write([]byte(outputPath))

View File

@ -13,34 +13,7 @@ import (
// Context corresponds to the current link in the chain and provides methods // Context corresponds to the current link in the chain and provides methods
// that enable plugins to inject new files into the chain. // that enable plugins to inject new files into the chain.
type Context interface { type Context struct {
// CreateFileFrom data creates a new file instance from the provided data buffer.
CreateFileFromReader(sourcePath string, reader io.Reader) (File, error)
// CreateFileFromAsset creates a new file instance from the provided file path.
CreateFileFromAsset(sourcePath, dataPath string) (File, error)
// DispatchFile causes the file to get passed to the next link in the chain.
DispatchFile(file File)
// DispatchAndCacheFile caches the file data (excluding the metadata), taking
// dependencies on any input files that are needed to generate it, and then
// passes it to the next link in the chain.
DispatchAndCacheFile(outputFile File, inputFiles ...File)
// RetrieveCachedFile looks up file data (excluding the metadata), given an
// output path and any input files that are needed to generate it. The function
// will return nil if the desired file is not found in the cache.
RetrieveCachedFile(outputPath string, inputFiles ...File) File
// Specify internal filter(s) that exclude files from being processed.
Filter(filters ...Filter) Context
// Specify the maximum number of threads used for processing.
Threads(threads int) Context
}
type contextImpl struct {
goldsmith *Goldsmith goldsmith *Goldsmith
plugin Plugin plugin Plugin
@ -51,33 +24,31 @@ type contextImpl struct {
threads int threads int
index int index int
filesIn chan File filesIn chan *File
filesOut chan File filesOut chan *File
} }
// CreateFileFrom data creates a new file instance from the provided data buffer. // CreateFileFrom data creates a new file instance from the provided data buffer.
func (self *contextImpl) CreateFileFromReader(sourcePath string, reader io.Reader) (File, error) { func (self *Context) CreateFileFromReader(sourcePath string, reader io.Reader) (*File, error) {
data, err := io.ReadAll(reader) data, err := io.ReadAll(reader)
if err != nil { if err != nil {
return nil, err return nil, err
} }
cf := &contextFile{ file := &File{
rawFile{
relPath: sourcePath, relPath: sourcePath,
props: make(map[string]FileProp), props: make(FileProps),
modTime: time.Now(), modTime: time.Now(),
size: int64(len(data)), size: int64(len(data)),
reader: bytes.NewReader(data), reader: bytes.NewReader(data),
}, index: self.index,
self.index,
} }
return cf, nil return file, nil
} }
// CreateFileFromAsset creates a new file instance from the provided file path. // CreateFileFromAsset creates a new file instance from the provided file path.
func (self *contextImpl) CreateFileFromAsset(sourcePath, dataPath string) (File, error) { func (self *Context) CreateFileFromAsset(sourcePath, dataPath string) (*File, error) {
if filepath.IsAbs(sourcePath) { if filepath.IsAbs(sourcePath) {
return nil, errors.New("source paths must be relative") return nil, errors.New("source paths must be relative")
} }
@ -94,29 +65,27 @@ func (self *contextImpl) CreateFileFromAsset(sourcePath, dataPath string) (File,
return nil, errors.New("assets must be files") return nil, errors.New("assets must be files")
} }
cf := &contextFile{ file := &File{
rawFile{
relPath: sourcePath, relPath: sourcePath,
props: make(map[string]FileProp), props: make(FileProps),
modTime: info.ModTime(), modTime: info.ModTime(),
size: info.Size(), size: info.Size(),
dataPath: dataPath, dataPath: dataPath,
}, index: self.index,
self.index,
} }
return cf, nil return file, nil
} }
// DispatchFile causes the file to get passed to the next link in the chain. // DispatchFile causes the file to get passed to the next link in the chain.
func (self *contextImpl) DispatchFile(file File) { func (self *Context) DispatchFile(file *File) {
self.filesOut <- file self.filesOut <- file
} }
// DispatchAndCacheFile caches the file data (excluding the metadata), taking // DispatchAndCacheFile caches the file data (excluding the metadata), taking
// dependencies on any input files that are needed to generate it, and then // dependencies on any input files that are needed to generate it, and then
// passes it to the next link in the chain. // passes it to the next link in the chain.
func (self *contextImpl) DispatchAndCacheFile(outputFile File, inputFiles ...File) { func (self *Context) DispatchAndCacheFile(outputFile *File, inputFiles ...*File) {
if self.goldsmith.state.cache != nil { if self.goldsmith.state.cache != nil {
self.goldsmith.state.cache.storeFile(self, outputFile, inputFiles) self.goldsmith.state.cache.storeFile(self, outputFile, inputFiles)
} }
@ -127,8 +96,8 @@ func (self *contextImpl) DispatchAndCacheFile(outputFile File, inputFiles ...Fil
// RetrieveCachedFile looks up file data (excluding the metadata), given an // RetrieveCachedFile looks up file data (excluding the metadata), given an
// output path and any input files that are needed to generate it. The function // output path and any input files that are needed to generate it. The function
// will return nil if the desired file is not found in the cache. // will return nil if the desired file is not found in the cache.
func (self *contextImpl) RetrieveCachedFile(outputPath string, inputFiles ...File) File { func (self *Context) RetrieveCachedFile(outputPath string, inputFiles ...*File) *File {
var outputFile File var outputFile *File
if self.goldsmith.state.cache != nil { if self.goldsmith.state.cache != nil {
outputFile, _ = self.goldsmith.state.cache.retrieveFile(self, outputPath, inputFiles) outputFile, _ = self.goldsmith.state.cache.retrieveFile(self, outputPath, inputFiles)
} }
@ -137,7 +106,7 @@ func (self *contextImpl) RetrieveCachedFile(outputPath string, inputFiles ...Fil
} }
// Specify internal filter(s) that exclude files from being processed. // Specify internal filter(s) that exclude files from being processed.
func (self *contextImpl) Filter(filters ...Filter) Context { func (self *Context) Filter(filters ...Filter) *Context {
for _, filter := range filters { for _, filter := range filters {
self.filtersInt.push(filter, self.index) self.filtersInt.push(filter, self.index)
} }
@ -146,12 +115,12 @@ func (self *contextImpl) Filter(filters ...Filter) Context {
} }
// Specify the maximum number of threads used for processing. // Specify the maximum number of threads used for processing.
func (self *contextImpl) Threads(threads int) Context { func (self *Context) Threads(threads int) *Context {
self.threads = threads self.threads = threads
return self return self
} }
func (self *contextImpl) step() { func (self *Context) step() {
defer close(self.filesOut) defer close(self.filesOut)
if initializer, ok := self.plugin.(Initializer); ok { if initializer, ok := self.plugin.(Initializer); ok {

View File

@ -9,22 +9,22 @@ type Plugin interface {
// Initializer is used to optionally initialize a plugin and to specify a // Initializer is used to optionally initialize a plugin and to specify a
// filter to be used for determining which files will be processed. // filter to be used for determining which files will be processed.
type Initializer interface { type Initializer interface {
Initialize(context Context) error Initialize(context *Context) error
} }
// Processor allows for optional processing of files passing through a plugin. // Processor allows for optional processing of files passing through a plugin.
type Processor interface { type Processor interface {
Process(context Context, file File) error Process(context *Context, file *File) error
} }
// Finalizer allows for optional finalization of a plugin after all files // Finalizer allows for optional finalization of a plugin after all files
// queued in the chain have passed through it. // queued in the chain have passed through it.
type Finalizer interface { type Finalizer interface {
Finalize(context Context) error Finalize(context *Context) error
} }
// Filter is used to determine which files should continue in the chain. // Filter is used to determine which files should continue in the chain.
type Filter interface { type Filter interface {
Name() string Name() string
Accept(file File) bool Accept(file *File) bool
} }

159
file.go
View File

@ -1,7 +1,11 @@
package goldsmith package goldsmith
import ( import (
"bytes"
"fmt"
"io" "io"
"os"
"path/filepath"
"time" "time"
) )
@ -11,26 +15,141 @@ type (
) )
// File represents in-memory or on-disk files in a chain. // File represents in-memory or on-disk files in a chain.
type File interface { type File struct {
Path() string relPath string
Dir() string props FileProps
Name() string modTime time.Time
Ext() string size int64
Rename(path string) error
Size() int64 dataPath string
ModTime() time.Time reader *bytes.Reader
Read(data []byte) (int, error) index int
WriteTo(writer io.Writer) (int64, error) }
Seek(offset int64, whence int) (int64, error)
// Rename modifies the file path relative to the source directory.
SetProp(name string, value FileProp) func (self *File) Rename(path string) error {
Prop(name string) (FileProp, bool) if filepath.IsAbs(path) {
PropOrDef(name string, valueDef FileProp) FileProp return fmt.Errorf("unexpected absolute path: %s", path)
Props() FileProps }
CopyProps(file File)
RemoveProp(name string) self.relPath = path
return nil
GoString() string }
// Path returns the file path relative to the source directory.
func (self *File) Path() string {
return filepath.ToSlash(self.relPath)
}
// Dir returns the containing directory of the file.
func (self *File) Dir() string {
return filepath.ToSlash(filepath.Dir(self.relPath))
}
// Name returns the base name of the file.
func (self *File) Name() string {
return filepath.Base(self.relPath)
}
// Ext returns the extension of the file.
func (self *File) Ext() string {
return filepath.Ext(self.relPath)
}
// Size returns the file length in bytes.
func (self *File) Size() int64 {
return self.size
}
// ModTime returns the time of the file's last modification.
func (self *File) ModTime() time.Time {
return self.modTime
}
// Read reads file data into the provided buffer.
func (self *File) Read(data []byte) (int, error) {
if err := self.load(); err != nil {
return 0, err
}
return self.reader.Read(data)
}
// Write writes file data into the provided writer.
func (self *File) WriteTo(writer io.Writer) (int64, error) {
if err := self.load(); err != nil {
return 0, err
}
return self.reader.WriteTo(writer)
}
// Seek updates the file pointer to the desired position.
func (self *File) Seek(offset int64, whence int) (int64, error) {
if self.reader == nil && offset == 0 && (whence == io.SeekStart || whence == io.SeekCurrent) {
return 0, nil
}
if err := self.load(); err != nil {
return 0, err
}
return self.reader.Seek(offset, whence)
}
// GoString returns value for string formatting.
func (self *File) GoString() string {
return self.relPath
}
// RemoveProp deletes the metadata property for the provided name.
func (self *File) RemoveProp(name string) {
delete(self.props, name)
}
// SetProp updates the metadata property for the provided name.
func (self *File) SetProp(name string, value FileProp) {
self.props[name] = value
}
// Prop returns the metadata property for the provided name.
func (self *File) Prop(name string) (FileProp, bool) {
value, ok := self.props[name]
return value, ok
}
// PropOrDef returns the metadata property for the provided name or the default.
func (self *File) PropOrDef(name string, valueDef FileProp) FileProp {
if value, ok := self.Prop(name); ok {
return value
}
return valueDef
}
// Props returns all of the metadata properties.
func (self *File) Props() FileProps {
return self.props
}
// CopyProps copies all metadata properties from the provided file.
func (self *File) CopyProps(file *File) {
for key, value := range file.props {
self.props[key] = value
}
}
func (self *File) load() error {
if self.reader != nil {
return nil
}
data, err := os.ReadFile(self.dataPath)
if err != nil {
return err
}
self.reader = bytes.NewReader(data)
return nil
} }

View File

@ -16,13 +16,13 @@ func (*fileExporter) Name() string {
return "exporter" return "exporter"
} }
func (self *fileExporter) Initialize(context Context) error { func (self *fileExporter) Initialize(context *Context) error {
self.tokens = make(map[string]bool) self.tokens = make(map[string]bool)
context.Threads(1) context.Threads(1)
return nil return nil
} }
func (self *fileExporter) Process(context Context, file File) error { func (self *fileExporter) Process(context *Context, file *File) error {
slicePath := func(path string) string { slicePath := func(path string) string {
if filepath.IsAbs(path) { if filepath.IsAbs(path) {
var err error var err error
@ -64,7 +64,7 @@ func (self *fileExporter) Process(context Context, file File) error {
return nil return nil
} }
func (self *fileExporter) Finalize(context Context) error { func (self *fileExporter) Finalize(context *Context) error {
if !self.clean { if !self.clean {
return nil return nil
} }

View File

@ -13,7 +13,7 @@ func (*fileImporter) Name() string {
return "importer" return "importer"
} }
func (self *fileImporter) Initialize(context Context) error { func (self *fileImporter) Initialize(context *Context) error {
return filepath.Walk(self.sourceDir, func(path string, info os.FileInfo, err error) error { return filepath.Walk(self.sourceDir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() { if info.IsDir() {
return nil return nil

View File

@ -7,11 +7,9 @@ type filterEntry struct {
type filterStack []filterEntry type filterStack []filterEntry
func (self *filterStack) accept(file File) bool { func (self *filterStack) accept(file *File) bool {
cf := file.(*contextFile)
for _, entry := range *self { for _, entry := range *self {
if entry.index >= cf.index && !entry.filter.Accept(file) { if entry.index >= file.index && !entry.filter.Accept(file) {
return false return false
} }
} }

View File

@ -16,6 +16,6 @@ func (*Condition) Name() string {
return "condition" return "condition"
} }
func (self *Condition) Accept(file goldsmith.File) bool { func (self *Condition) Accept(file *goldsmith.File) bool {
return self.accept return self.accept
} }

View File

@ -20,7 +20,7 @@ func (*operatorAnd) Name() string {
return "operator" return "operator"
} }
func (self *operatorAnd) Accept(file goldsmith.File) bool { func (self *operatorAnd) Accept(file *goldsmith.File) bool {
for _, filter := range self.filters { for _, filter := range self.filters {
if !filter.Accept(file) { if !filter.Accept(file) {
return false return false
@ -42,7 +42,7 @@ func (*operatorNot) Name() string {
return "operator" return "operator"
} }
func (self *operatorNot) Accept(file goldsmith.File) bool { func (self *operatorNot) Accept(file *goldsmith.File) bool {
return !self.filter.Accept(file) return !self.filter.Accept(file)
} }
@ -58,7 +58,7 @@ func (*operatorOr) Name() string {
return "operator" return "operator"
} }
func (self *operatorOr) Accept(file goldsmith.File) bool { func (self *operatorOr) Accept(file *goldsmith.File) bool {
for _, filter := range self.filters { for _, filter := range self.filters {
if filter.Accept(file) { if filter.Accept(file) {
return true return true

View File

@ -25,7 +25,7 @@ func (*Wildcard) Name() string {
return "wildcard" return "wildcard"
} }
func (self *Wildcard) Accept(file goldsmith.File) bool { func (self *Wildcard) Accept(file *goldsmith.File) bool {
filePath := self.adjustCase(file.Path()) filePath := self.adjustCase(file.Path())
for _, wildcard := range self.wildcards { for _, wildcard := range self.wildcards {

View File

@ -7,7 +7,7 @@ import (
) )
type chainState struct { type chainState struct {
contexts []*contextImpl contexts []*Context
cache *cache cache *cache
filters filterStack filters filterStack
@ -44,12 +44,12 @@ func (self *Goldsmith) Clean(clean bool) *Goldsmith {
// Chain links a plugin instance into the chain. // Chain links a plugin instance into the chain.
func (self *Goldsmith) Chain(plugin Plugin) *Goldsmith { func (self *Goldsmith) Chain(plugin Plugin) *Goldsmith {
context := &contextImpl{ context := &Context{
goldsmith: self, goldsmith: self,
plugin: plugin, plugin: plugin,
filtersExt: append(filterStack(nil), self.state.filters...), filtersExt: append(filterStack(nil), self.state.filters...),
index: self.state.index, index: self.state.index,
filesOut: make(chan File), filesOut: make(chan *File),
} }
if len(self.state.contexts) > 0 { if len(self.state.contexts) > 0 {
@ -94,7 +94,7 @@ func (self *Goldsmith) End(targetDir string) []error {
return errors return errors
} }
func (self *Goldsmith) fault(name string, file File, err error) { func (self *Goldsmith) fault(name string, file *File, err error) {
self.state.mutex.Lock() self.state.mutex.Lock()
defer self.state.mutex.Unlock() defer self.state.mutex.Unlock()

View File

@ -45,12 +45,12 @@ func (*Absolute) Name() string {
return "absolute" return "absolute"
} }
func (*Absolute) Initialize(context goldsmith.Context) error { func (*Absolute) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Absolute) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Absolute) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil { if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil {
outputFile.CopyProps(inputFile) outputFile.CopyProps(inputFile)
context.DispatchFile(outputFile) context.DispatchFile(outputFile)

View File

@ -19,7 +19,7 @@ type Crumb struct {
// Node represents information about a specific file in the site's structure. // Node represents information about a specific file in the site's structure.
type Node struct { type Node struct {
File goldsmith.File File *goldsmith.File
Parent *Node Parent *Node
Children []*Node Children []*Node
@ -70,12 +70,12 @@ func (*Breadcrumbs) Name() string {
return "breadcrumbs" return "breadcrumbs"
} }
func (*Breadcrumbs) Initialize(context goldsmith.Context) error { func (*Breadcrumbs) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Breadcrumbs) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Breadcrumbs) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
var parentNameStr string var parentNameStr string
if parentName, ok := inputFile.Prop(self.parentKey); ok { if parentName, ok := inputFile.Prop(self.parentKey); ok {
parentNameStr, _ = parentName.(string) parentNameStr, _ = parentName.(string)
@ -103,7 +103,7 @@ func (self *Breadcrumbs) Process(context goldsmith.Context, inputFile goldsmith.
return nil return nil
} }
func (self *Breadcrumbs) Finalize(context goldsmith.Context) error { func (self *Breadcrumbs) Finalize(context *goldsmith.Context) error {
for _, node := range self.allNodes { for _, node := range self.allNodes {
if len(node.parentName) == 0 { if len(node.parentName) == 0 {
continue continue

View File

@ -15,7 +15,7 @@ import (
) )
// A Comparer callback function is used to sort files within a collection group. // A Comparer callback function is used to sort files within a collection group.
type Comparer func(i, j goldsmith.File) (less bool) type Comparer func(i, j *goldsmith.File) (less bool)
// Collection chainable plugin context. // Collection chainable plugin context.
type Collection struct { type Collection struct {
@ -23,8 +23,8 @@ type Collection struct {
groupsKey string groupsKey string
comparer Comparer comparer Comparer
groups map[string][]goldsmith.File groups map[string][]*goldsmith.File
files []goldsmith.File files []*goldsmith.File
mutex sync.Mutex mutex sync.Mutex
} }
@ -33,7 +33,7 @@ func New() *Collection {
return &Collection{ return &Collection{
collectionKey: "Collection", collectionKey: "Collection",
groupsKey: "Groups", groupsKey: "Groups",
groups: make(map[string][]goldsmith.File), groups: make(map[string][]*goldsmith.File),
} }
} }
@ -61,12 +61,12 @@ func (*Collection) Name() string {
return "collection" return "collection"
} }
func (*Collection) Initialize(context goldsmith.Context) error { func (*Collection) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Collection) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Collection) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
self.mutex.Lock() self.mutex.Lock()
defer func() { defer func() {
inputFile.SetProp(self.groupsKey, self.groups) inputFile.SetProp(self.groupsKey, self.groups)
@ -96,7 +96,7 @@ func (self *Collection) Process(context goldsmith.Context, inputFile goldsmith.F
return nil return nil
} }
func (self *Collection) Finalize(context goldsmith.Context) error { func (self *Collection) Finalize(context *goldsmith.Context) error {
for _, files := range self.groups { for _, files := range self.groups {
fg := &fileSorter{files, self.comparer} fg := &fileSorter{files, self.comparer}
sort.Sort(fg) sort.Sort(fg)
@ -110,7 +110,7 @@ func (self *Collection) Finalize(context goldsmith.Context) error {
} }
type fileSorter struct { type fileSorter struct {
files []goldsmith.File files []*goldsmith.File
comparer Comparer comparer Comparer
} }

View File

@ -14,12 +14,12 @@ import (
) )
// Processor callback function to modify documents. // Processor callback function to modify documents.
type Processor func(goldsmith.File, *goquery.Document) error type Processor func(*goldsmith.File, *goquery.Document) error
// Document plugin context. // Document plugin context.
type Document struct { type Document struct {
callback Processor callback Processor
files []goldsmith.File files []*goldsmith.File
mutex sync.Mutex mutex sync.Mutex
} }
@ -32,12 +32,12 @@ func (*Document) Name() string {
return "document" return "document"
} }
func (*Document) Initialize(context goldsmith.Context) error { func (*Document) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Document) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Document) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
doc, err := goquery.NewDocumentFromReader(inputFile) doc, err := goquery.NewDocumentFromReader(inputFile)
if err != nil { if err != nil {
return err return err
@ -61,7 +61,7 @@ func (self *Document) Process(context goldsmith.Context, inputFile goldsmith.Fil
return nil return nil
} }
func (self *Document) Finalize(context goldsmith.Context) error { func (self *Document) Finalize(context *goldsmith.Context) error {
for _, file := range self.files { for _, file := range self.files {
context.DispatchFile(file) context.DispatchFile(file)
} }

View File

@ -8,7 +8,7 @@ import (
"github.com/PuerkitoBio/goquery" "github.com/PuerkitoBio/goquery"
) )
func process(file goldsmith.File, doc *goquery.Document) error { func process(file *goldsmith.File, doc *goquery.Document) error {
doc.Find("h1").SetAttr("style", "color: red;") doc.Find("h1").SetAttr("style", "color: red;")
return nil return nil
} }

View File

@ -53,7 +53,7 @@ func (*Forward) Name() string {
return "forward" return "forward"
} }
func (self *Forward) Initialize(context goldsmith.Context) error { func (self *Forward) Initialize(context *goldsmith.Context) error {
for sourcePath, targetPath := range self.pathMap { for sourcePath, targetPath := range self.pathMap {
sourceFile, err := context.CreateFileFromReader(sourcePath, bytes.NewReader(nil)) sourceFile, err := context.CreateFileFromReader(sourcePath, bytes.NewReader(nil))
if err != nil { if err != nil {

View File

@ -66,12 +66,12 @@ func (*FrontMatter) Name() string {
return "frontmatter" return "frontmatter"
} }
func (*FrontMatter) Initialize(context goldsmith.Context) error { func (*FrontMatter) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.md", "**/*.markdown", "**/*.rst", "**/*.txt", "**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.md", "**/*.markdown", "**/*.rst", "**/*.txt", "**/*.html", "**/*.htm"))
return nil return nil
} }
func (*FrontMatter) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (*FrontMatter) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
meta, body, err := parse(inputFile) meta, body, err := parse(inputFile)
if err != nil { if err != nil {
return err return err

View File

@ -18,7 +18,7 @@ type Entry struct {
Name string Name string
Path string Path string
IsDir bool IsDir bool
File goldsmith.File File *goldsmith.File
} }
// Index chainable plugin context. // Index chainable plugin context.
@ -60,7 +60,7 @@ func (*Index) Name() string {
return "index" return "index"
} }
func (self *Index) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Index) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
self.mutex.Lock() self.mutex.Lock()
defer self.mutex.Unlock() defer self.mutex.Unlock()
@ -105,7 +105,7 @@ func (self *Index) Process(context goldsmith.Context, inputFile goldsmith.File)
return nil return nil
} }
func (self *Index) Finalize(context goldsmith.Context) error { func (self *Index) Finalize(context *goldsmith.Context) error {
for name, list := range self.dirLists { for name, list := range self.dirLists {
sort.Sort(list.entries) sort.Sort(list.entries)
@ -131,7 +131,7 @@ func (self *Index) Finalize(context goldsmith.Context) error {
type directory struct { type directory struct {
entries entriesByName entries entriesByName
indexFile goldsmith.File indexFile *goldsmith.File
} }
type entriesByName []Entry type entriesByName []Entry

View File

@ -20,8 +20,8 @@ type Layout struct {
defaultLayout *string defaultLayout *string
helpers template.FuncMap helpers template.FuncMap
inputFiles []goldsmith.File inputFiles []*goldsmith.File
templateFiles []goldsmith.File templateFiles []*goldsmith.File
mutex sync.Mutex mutex sync.Mutex
template *template.Template template *template.Template
@ -64,13 +64,13 @@ func (*Layout) Name() string {
return "layout" return "layout"
} }
func (self *Layout) Initialize(context goldsmith.Context) error { func (self *Layout) Initialize(context *goldsmith.Context) error {
self.template = template.New("").Funcs(self.helpers) self.template = template.New("").Funcs(self.helpers)
context.Filter(wildcard.New("**/*.html", "**/*.htm", "**/*.tmpl", "**/*.gohtml")) context.Filter(wildcard.New("**/*.html", "**/*.htm", "**/*.tmpl", "**/*.gohtml"))
return nil return nil
} }
func (self *Layout) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Layout) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
self.mutex.Lock() self.mutex.Lock()
defer self.mutex.Unlock() defer self.mutex.Unlock()
@ -94,7 +94,7 @@ func (self *Layout) Process(context goldsmith.Context, inputFile goldsmith.File)
return nil return nil
} }
func (self *Layout) Finalize(context goldsmith.Context) error { func (self *Layout) Finalize(context *goldsmith.Context) error {
for _, templateFile := range self.templateFiles { for _, templateFile := range self.templateFiles {
var buff bytes.Buffer var buff bytes.Buffer
if _, err := templateFile.WriteTo(&buff); err != nil { if _, err := templateFile.WriteTo(&buff); err != nil {
@ -128,7 +128,7 @@ func (self *Layout) Finalize(context goldsmith.Context) error {
return nil return nil
} }
func (self *Layout) getFileLayout(file goldsmith.File) (string, bool) { func (self *Layout) getFileLayout(file *goldsmith.File) (string, bool) {
if name, ok := file.Props()[self.layoutKey].(string); ok { if name, ok := file.Props()[self.layoutKey].(string); ok {
return name, true return name, true
} }

View File

@ -31,13 +31,13 @@ func (*LiveJs) Name() string {
return "livejs" return "livejs"
} }
func (self *LiveJs) Initialize(context goldsmith.Context) error { func (self *LiveJs) Initialize(context *goldsmith.Context) error {
self.html = fmt.Sprintf("\n<!-- begin livejs code -->\n<script>\n%s\n</script>\n<!-- end livejs code -->\n", livejs) self.html = fmt.Sprintf("\n<!-- begin livejs code -->\n<script>\n%s\n</script>\n<!-- end livejs code -->\n", livejs)
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *LiveJs) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *LiveJs) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil { if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil {
outputFile.CopyProps(inputFile) outputFile.CopyProps(inputFile)
context.DispatchFile(outputFile) context.DispatchFile(outputFile)

View File

@ -42,12 +42,12 @@ func (*Markdown) Name() string {
return "markdown" return "markdown"
} }
func (self *Markdown) Initialize(context goldsmith.Context) error { func (self *Markdown) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.md", "**/*.markdown")) context.Filter(wildcard.New("**/*.md", "**/*.markdown"))
return nil return nil
} }
func (self *Markdown) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Markdown) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
outputPath := strings.TrimSuffix(inputFile.Path(), path.Ext(inputFile.Path())) + ".html" outputPath := strings.TrimSuffix(inputFile.Path(), path.Ext(inputFile.Path())) + ".html"
if outputFile := context.RetrieveCachedFile(outputPath, inputFile); outputFile != nil { if outputFile := context.RetrieveCachedFile(outputPath, inputFile); outputFile != nil {
outputFile.CopyProps(inputFile) outputFile.CopyProps(inputFile)

View File

@ -32,12 +32,12 @@ func (*Minify) Name() string {
return "minify" return "minify"
} }
func (*Minify) Initialize(context goldsmith.Context) error { func (*Minify) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.css", "**/*.html", "**/*.htm", "**/*.js", "**/*.svg", "**/*.json", "**/*.xml")) context.Filter(wildcard.New("**/*.css", "**/*.html", "**/*.htm", "**/*.js", "**/*.svg", "**/*.json", "**/*.xml"))
return nil return nil
} }
func (*Minify) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (*Minify) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil { if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil {
outputFile.CopyProps(inputFile) outputFile.CopyProps(inputFile)
context.DispatchFile(outputFile) context.DispatchFile(outputFile)

View File

@ -22,13 +22,13 @@ import (
type Namer func(path string, index int) string type Namer func(path string, index int) string
// Lister callback function is used to return a metadata slice which should be paged across several files. // Lister callback function is used to return a metadata slice which should be paged across several files.
type Lister func(file goldsmith.File) interface{} type Lister func(file *goldsmith.File) interface{}
// Page represents information about a given metadata segment. // Page represents information about a given metadata segment.
type Page struct { type Page struct {
Index int Index int
Items interface{} Items interface{}
File goldsmith.File File *goldsmith.File
Next *Page Next *Page
Prev *Page Prev *Page
@ -51,7 +51,7 @@ type Pager struct {
inheritedKeys []string inheritedKeys []string
itemsPerPage int itemsPerPage int
files []goldsmith.File files []*goldsmith.File
mutex sync.Mutex mutex sync.Mutex
} }
@ -109,12 +109,12 @@ func (*Pager) Name() string {
return "pager" return "pager"
} }
func (*Pager) Initialize(context goldsmith.Context) error { func (*Pager) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Pager) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Pager) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
self.mutex.Lock() self.mutex.Lock()
defer self.mutex.Unlock() defer self.mutex.Unlock()
@ -200,7 +200,7 @@ func (self *Pager) Process(context goldsmith.Context, inputFile goldsmith.File)
return nil return nil
} }
func (self *Pager) Finalize(ctx goldsmith.Context) error { func (self *Pager) Finalize(ctx *goldsmith.Context) error {
for _, f := range self.files { for _, f := range self.files {
ctx.DispatchFile(f) ctx.DispatchFile(f)
} }
@ -208,7 +208,7 @@ func (self *Pager) Finalize(ctx goldsmith.Context) error {
return nil return nil
} }
func (self *Pager) isEnabledForFile(file goldsmith.File) (bool, error) { func (self *Pager) isEnabledForFile(file *goldsmith.File) (bool, error) {
enableRaw, ok := file.Prop(self.enableKey) enableRaw, ok := file.Prop(self.enableKey)
if !ok { if !ok {
return false, nil return false, nil

View File

@ -11,9 +11,9 @@ import (
) )
func Test(self *testing.T) { func Test(self *testing.T) {
lister := func(file goldsmith.File) interface{} { lister := func(file *goldsmith.File) interface{} {
if groupsRaw, ok := file.Prop("Groups"); ok { if groupsRaw, ok := file.Prop("Groups"); ok {
if groups, ok := groupsRaw.(map[string][]goldsmith.File); ok { if groups, ok := groupsRaw.(map[string][]*goldsmith.File); ok {
if group, ok := groups["group"]; ok { if group, ok := groups["group"]; ok {
return group return group
} }

View File

@ -19,14 +19,14 @@ type rule struct {
type ruleApply struct { type ruleApply struct {
rule rule
Props map[string]goldsmith.FileProp Props goldsmith.FileProps
} }
type ruleDrop struct { type ruleDrop struct {
rule rule
} }
func (self *rule) accept(inputFile goldsmith.File) bool { func (self *rule) accept(inputFile *goldsmith.File) bool {
if !wildcard.New(filepath.Join(self.baseDir, "**")).Accept(inputFile) { if !wildcard.New(filepath.Join(self.baseDir, "**")).Accept(inputFile) {
return false return false
} }
@ -52,7 +52,7 @@ func (self *rule) accept(inputFile goldsmith.File) bool {
return operator.Not(wildcard.New(rejectPaths...)).Accept(inputFile) return operator.Not(wildcard.New(rejectPaths...)).Accept(inputFile)
} }
func (self *ruleApply) apply(inputFile goldsmith.File) { func (self *ruleApply) apply(inputFile *goldsmith.File) {
if self.accept(inputFile) { if self.accept(inputFile) {
for name, value := range self.Props { for name, value := range self.Props {
inputFile.SetProp(name, value) inputFile.SetProp(name, value)
@ -60,7 +60,7 @@ func (self *ruleApply) apply(inputFile goldsmith.File) {
} }
} }
func (self *ruleDrop) drop(inputFile goldsmith.File) bool { func (self *ruleDrop) drop(inputFile *goldsmith.File) bool {
return self.accept(inputFile) return self.accept(inputFile)
} }
@ -69,7 +69,7 @@ type ruleSet struct {
Drop []*ruleDrop Drop []*ruleDrop
} }
func newRuleSet(inputFile goldsmith.File) (*ruleSet, error) { func newRuleSet(inputFile *goldsmith.File) (*ruleSet, error) {
data, err := io.ReadAll(inputFile) data, err := io.ReadAll(inputFile)
if err != nil { if err != nil {
return nil, err return nil, err
@ -91,7 +91,7 @@ func newRuleSet(inputFile goldsmith.File) (*ruleSet, error) {
return &ruleSet, nil return &ruleSet, nil
} }
func (self *ruleSet) process(inputFile goldsmith.File) bool { func (self *ruleSet) process(inputFile *goldsmith.File) bool {
for _, rule := range self.Apply { for _, rule := range self.Apply {
rule.apply(inputFile) rule.apply(inputFile)
} }
@ -110,7 +110,7 @@ type Rule struct {
filename string filename string
ruleSets []*ruleSet ruleSets []*ruleSet
inputFiles []goldsmith.File inputFiles []*goldsmith.File
mutex sync.Mutex mutex sync.Mutex
} }
@ -128,7 +128,7 @@ func (*Rule) Name() string {
return "rule" return "rule"
} }
func (self *Rule) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Rule) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
if inputFile.Name() == self.filename { if inputFile.Name() == self.filename {
ruleSet, err := newRuleSet(inputFile) ruleSet, err := newRuleSet(inputFile)
if err != nil { if err != nil {
@ -147,7 +147,7 @@ func (self *Rule) Process(context goldsmith.Context, inputFile goldsmith.File) e
return nil return nil
} }
func (self *Rule) Finalize(context goldsmith.Context) error { func (self *Rule) Finalize(context *goldsmith.Context) error {
for _, inputFile := range self.inputFiles { for _, inputFile := range self.inputFiles {
var block bool var block bool
for _, ruleSet := range self.ruleSets { for _, ruleSet := range self.ruleSets {

View File

@ -57,12 +57,12 @@ func (*Summary) Name() string {
return "summary" return "summary"
} }
func (*Summary) Initialize(context goldsmith.Context) error { func (*Summary) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Summary) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Summary) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
doc, err := goquery.NewDocumentFromReader(inputFile) doc, err := goquery.NewDocumentFromReader(inputFile)
if err != nil { if err != nil {
return err return err

View File

@ -120,7 +120,7 @@ func (self *Syndicate) WithFeed(name string, config FeedConfig) *Syndicate {
return self return self
} }
func (self *Syndicate) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Syndicate) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
defer context.DispatchFile(inputFile) defer context.DispatchFile(inputFile)
getString := func(key string) string { getString := func(key string) string {
@ -214,7 +214,7 @@ func (self *Syndicate) Process(context goldsmith.Context, inputFile goldsmith.Fi
return nil return nil
} }
func (self *feed) output(context goldsmith.Context) error { func (self *feed) output(context *goldsmith.Context) error {
feed := feeds.Feed{ feed := feeds.Feed{
Title: self.config.Title, Title: self.config.Title,
Link: &feeds.Link{Href: self.config.Url}, Link: &feeds.Link{Href: self.config.Url},
@ -310,7 +310,7 @@ func (self *feed) output(context goldsmith.Context) error {
return nil return nil
} }
func (self *Syndicate) Finalize(context goldsmith.Context) error { func (self *Syndicate) Finalize(context *goldsmith.Context) error {
for _, feed := range self.feeds { for _, feed := range self.feeds {
feed.output(context) feed.output(context)
} }

View File

@ -69,12 +69,12 @@ func (*Syntax) Name() string {
return "syntax" return "syntax"
} }
func (*Syntax) Initialize(context goldsmith.Context) error { func (*Syntax) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Syntax) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Syntax) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil { if outputFile := context.RetrieveCachedFile(inputFile.Path(), inputFile); outputFile != nil {
outputFile.CopyProps(inputFile) outputFile.CopyProps(inputFile)
context.DispatchFile(outputFile) context.DispatchFile(outputFile)

View File

@ -18,7 +18,7 @@ import (
// TagInfo contains site-wide information about a particular tag. // TagInfo contains site-wide information about a particular tag.
type TagInfo struct { type TagInfo struct {
TaggedFiles filesByPath TaggedFiles filesByPath
IndexFile goldsmith.File IndexFile *goldsmith.File
SafeName string SafeName string
RawName string RawName string
} }
@ -44,7 +44,7 @@ type Tags struct {
infoByName tagInfoByName infoByName tagInfoByName
infoByCount tagInfoByCount infoByCount tagInfoByCount
files []goldsmith.File files []*goldsmith.File
mutex sync.Mutex mutex sync.Mutex
} }
@ -93,12 +93,12 @@ func (*Tags) Name() string {
return "tags" return "tags"
} }
func (*Tags) Initialize(context goldsmith.Context) error { func (*Tags) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.html", "**/*.htm")) context.Filter(wildcard.New("**/*.html", "**/*.htm"))
return nil return nil
} }
func (self *Tags) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Tags) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
tagState := &TagState{ tagState := &TagState{
TagsByName: &self.infoByName, TagsByName: &self.infoByName,
TagsByCount: &self.infoByCount, TagsByCount: &self.infoByCount,
@ -158,7 +158,7 @@ func (self *Tags) Process(context goldsmith.Context, inputFile goldsmith.File) e
return nil return nil
} }
func (self *Tags) Finalize(context goldsmith.Context) error { func (self *Tags) Finalize(context *goldsmith.Context) error {
for _, info := range self.info { for _, info := range self.info {
sort.Sort(info.TaggedFiles) sort.Sort(info.TaggedFiles)
@ -185,8 +185,8 @@ func (self *Tags) Finalize(context goldsmith.Context) error {
return nil return nil
} }
func (self *Tags) buildPages(context goldsmith.Context) ([]goldsmith.File, error) { func (self *Tags) buildPages(context *goldsmith.Context) ([]*goldsmith.File, error) {
var files []goldsmith.File var files []*goldsmith.File
for tag, info := range self.info { for tag, info := range self.info {
var err error var err error
info.IndexFile, err = context.CreateFileFromReader(self.tagPagePath(tag), bytes.NewReader(nil)) info.IndexFile, err = context.CreateFileFromReader(self.tagPagePath(tag), bytes.NewReader(nil))
@ -273,7 +273,7 @@ func (self tagInfoByName) Less(i, j int) bool {
return false return false
} }
type filesByPath []goldsmith.File type filesByPath []*goldsmith.File
func (self filesByPath) Len() int { func (self filesByPath) Len() int {
return len(self) return len(self)

View File

@ -76,12 +76,12 @@ func (*Thumbnail) Name() string {
return "thumbnail" return "thumbnail"
} }
func (*Thumbnail) Initialize(context goldsmith.Context) error { func (*Thumbnail) Initialize(context *goldsmith.Context) error {
context.Filter(wildcard.New("**/*.jpg", "**/*.jpeg", "**/*.gif", "**/*.png")) context.Filter(wildcard.New("**/*.jpg", "**/*.jpeg", "**/*.gif", "**/*.png"))
return nil return nil
} }
func (self *Thumbnail) Process(context goldsmith.Context, inputFile goldsmith.File) error { func (self *Thumbnail) Process(context *goldsmith.Context, inputFile *goldsmith.File) error {
defer context.DispatchFile(inputFile) defer context.DispatchFile(inputFile)
thumbPath := self.namer(inputFile.Path(), self.size) thumbPath := self.namer(inputFile.Path(), self.size)
@ -104,7 +104,7 @@ func (self *Thumbnail) Process(context goldsmith.Context, inputFile goldsmith.Fi
return nil return nil
} }
func (self *Thumbnail) thumbnail(context goldsmith.Context, inputFile goldsmith.File, thumbPath string) (goldsmith.File, error) { func (self *Thumbnail) thumbnail(context *goldsmith.Context, inputFile *goldsmith.File, thumbPath string) (*goldsmith.File, error) {
var thumbFormat imaging.Format var thumbFormat imaging.Format
switch strings.ToLower(filepath.Ext(thumbPath)) { switch strings.ToLower(filepath.Ext(thumbPath)) {
case ".jpg", ".jpeg": case ".jpg", ".jpeg":