goldsmith/context.go

147 lines
3.8 KiB
Go
Raw Normal View History

2015-12-18 08:03:30 +00:00
package goldsmith
import (
2018-12-08 19:18:51 +00:00
"bytes"
"errors"
2015-12-20 14:18:58 +00:00
"os"
2015-12-20 08:38:53 +00:00
"runtime"
2015-12-18 08:03:30 +00:00
"sync"
2018-12-08 19:18:51 +00:00
"time"
2015-12-18 08:03:30 +00:00
)
2019-04-08 01:02:57 +00:00
// Context corresponds to the current link in the chain and provides methods
// that enable plugins to inject new files into the chain.
2018-12-08 19:18:51 +00:00
type Context struct {
goldsmith *Goldsmith
2021-05-01 22:12:50 +00:00
plugin Plugin
chainHash uint32
2018-12-08 19:18:51 +00:00
2021-05-01 22:12:50 +00:00
filtersExt filterStack
filtersInt filterStack
2021-04-12 02:13:59 +00:00
2021-05-01 22:12:50 +00:00
threads int
filesIn chan *File
filesOut chan *File
2018-12-08 19:18:51 +00:00
}
2019-04-08 01:02:57 +00:00
// CreateFileFrom data creates a new file instance from the provided data buffer.
2018-12-08 19:18:51 +00:00
func (*Context) CreateFileFromData(sourcePath string, data []byte) *File {
return &File{
sourcePath: sourcePath,
Meta: make(map[string]interface{}),
reader: bytes.NewReader(data),
size: int64(len(data)),
modTime: time.Now(),
}
}
2019-04-08 01:02:57 +00:00
// CreateFileFromAsset creates a new file instance from the provided file path.
2018-12-08 19:18:51 +00:00
func (*Context) CreateFileFromAsset(sourcePath, dataPath string) (*File, error) {
info, err := os.Stat(dataPath)
if err != nil {
return nil, err
}
if info.IsDir() {
return nil, errors.New("assets must be files")
}
file := &File{
sourcePath: sourcePath,
dataPath: dataPath,
Meta: make(map[string]interface{}),
size: info.Size(),
modTime: info.ModTime(),
}
return file, nil
}
2019-04-08 01:02:57 +00:00
// DispatchFile causes the file to get passed to the next link in the chain.
2018-12-10 01:00:46 +00:00
func (context *Context) DispatchFile(file *File) {
2021-05-01 22:12:50 +00:00
context.filesOut <- file
2018-12-08 19:18:51 +00:00
}
2019-04-08 01:02:57 +00:00
// 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.
2018-12-10 01:00:46 +00:00
func (context *Context) DispatchAndCacheFile(outputFile *File, inputFiles ...*File) {
2021-05-01 22:12:50 +00:00
if context.goldsmith.cache != nil {
context.goldsmith.cache.storeFile(context, outputFile, inputFiles)
}
context.filesOut <- outputFile
2015-12-18 08:03:30 +00:00
}
2019-04-08 01:02:57 +00:00
// 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.
2018-12-10 01:00:46 +00:00
func (context *Context) RetrieveCachedFile(outputPath string, inputFiles ...*File) *File {
2021-05-01 22:12:50 +00:00
var outputFile *File
if context.goldsmith.cache != nil {
outputFile, _ = context.goldsmith.cache.retrieveFile(context, outputPath, inputFiles)
}
return outputFile
2018-12-08 19:18:51 +00:00
}
2021-04-12 02:13:59 +00:00
// Specify internal filter(s) that exclude files from being processed.
func (context *Context) Filter(filters ...Filter) *Context {
2021-05-01 22:12:50 +00:00
context.filtersInt = filters
return context
}
// Specify the maximum number of threads used for processing.
func (context *Context) Threads(threads int) *Context {
context.threads = threads
2021-04-12 02:13:59 +00:00
return context
}
2018-12-10 01:00:46 +00:00
func (context *Context) step() {
2021-05-01 22:12:50 +00:00
defer close(context.filesOut)
2015-12-18 08:03:30 +00:00
2018-12-10 01:00:46 +00:00
if initializer, ok := context.plugin.(Initializer); ok {
2021-04-12 02:13:59 +00:00
if err := initializer.Initialize(context); err != nil {
2018-12-10 01:00:46 +00:00
context.goldsmith.fault(context.plugin.Name(), nil, err)
2015-12-20 08:38:53 +00:00
return
2015-12-18 08:03:30 +00:00
}
}
2021-05-01 22:12:50 +00:00
if context.filesIn != nil {
2018-12-10 01:00:46 +00:00
processor, _ := context.plugin.(Processor)
2016-07-10 20:05:23 +00:00
2021-05-01 22:12:50 +00:00
threads := context.threads
if threads < 1 {
threads = runtime.NumCPU()
}
2016-01-10 11:17:35 +00:00
var wg sync.WaitGroup
2021-05-01 22:12:50 +00:00
for i := 0; i < threads; i++ {
2016-01-10 11:17:35 +00:00
wg.Add(1)
go func() {
defer wg.Done()
2021-05-01 22:12:50 +00:00
for inputFile := range context.filesIn {
if processor != nil && context.filtersInt.accept(inputFile) && context.filtersExt.accept(inputFile) {
2018-12-08 19:18:51 +00:00
if _, err := inputFile.Seek(0, os.SEEK_SET); err != nil {
2018-12-10 01:00:46 +00:00
context.goldsmith.fault("core", inputFile, err)
2016-01-10 11:17:35 +00:00
}
2018-12-10 01:00:46 +00:00
if err := processor.Process(context, inputFile); err != nil {
context.goldsmith.fault(context.plugin.Name(), inputFile, err)
2016-01-10 11:17:35 +00:00
}
} else {
2021-05-01 22:12:50 +00:00
context.filesOut <- inputFile
2015-12-20 08:38:53 +00:00
}
2015-12-18 08:03:30 +00:00
}
2016-01-10 11:17:35 +00:00
}()
}
wg.Wait()
2015-12-18 08:03:30 +00:00
}
2018-12-10 01:00:46 +00:00
if finalizer, ok := context.plugin.(Finalizer); ok {
if err := finalizer.Finalize(context); err != nil {
context.goldsmith.fault(context.plugin.Name(), nil, err)
2015-12-18 08:03:30 +00:00
}
2015-12-19 11:51:23 +00:00
}
2015-12-18 08:03:30 +00:00
}