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
|
|
|
|
|
|
|
|
plugin Plugin
|
|
|
|
hash uint32
|
|
|
|
|
|
|
|
fileFilters []Filter
|
|
|
|
inputFiles chan *File
|
|
|
|
outputFiles chan *File
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
context.outputFiles <- 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) {
|
|
|
|
context.goldsmith.storeFile(context, outputFile, inputFiles)
|
|
|
|
context.outputFiles <- 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 {
|
|
|
|
return context.goldsmith.retrieveFile(context, outputPath, inputFiles)
|
2018-12-08 19:18:51 +00:00
|
|
|
}
|
|
|
|
|
2018-12-10 01:00:46 +00:00
|
|
|
func (context *Context) step() {
|
|
|
|
defer close(context.outputFiles)
|
2015-12-18 08:03:30 +00:00
|
|
|
|
2018-01-07 23:42:32 +00:00
|
|
|
var err error
|
2018-12-09 20:45:06 +00:00
|
|
|
var filter Filter
|
2018-12-10 01:00:46 +00:00
|
|
|
if initializer, ok := context.plugin.(Initializer); ok {
|
|
|
|
filter, err = initializer.Initialize(context)
|
2016-07-10 20:05:23 +00:00
|
|
|
if 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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-10 01:00:46 +00:00
|
|
|
if context.inputFiles != nil {
|
|
|
|
processor, _ := context.plugin.(Processor)
|
2016-07-10 20:05:23 +00:00
|
|
|
|
2016-01-10 11:17:35 +00:00
|
|
|
var wg sync.WaitGroup
|
|
|
|
for i := 0; i < runtime.NumCPU(); i++ {
|
|
|
|
wg.Add(1)
|
|
|
|
go func() {
|
|
|
|
defer wg.Done()
|
2018-12-10 01:00:46 +00:00
|
|
|
for inputFile := range context.inputFiles {
|
2016-07-10 20:05:23 +00:00
|
|
|
accept := processor != nil
|
2018-12-09 20:45:06 +00:00
|
|
|
|
|
|
|
var fileFilters []Filter
|
2018-12-10 01:00:46 +00:00
|
|
|
fileFilters = append(fileFilters, context.fileFilters...)
|
2018-12-09 20:45:06 +00:00
|
|
|
if filter != nil {
|
|
|
|
fileFilters = append(fileFilters, filter)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, fileFilter := range fileFilters {
|
2019-04-03 02:01:36 +00:00
|
|
|
if accept, err = fileFilter.Accept(inputFile); err != nil {
|
2018-12-10 01:00:46 +00:00
|
|
|
context.goldsmith.fault(fileFilter.Name(), inputFile, err)
|
2018-01-07 23:42:32 +00:00
|
|
|
return
|
2016-07-04 03:08:31 +00:00
|
|
|
}
|
2018-01-07 23:42:32 +00:00
|
|
|
if !accept {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2016-07-10 20:05:23 +00:00
|
|
|
|
2016-07-04 03:08:31 +00:00
|
|
|
if accept {
|
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
|
|
|
}
|
2016-07-04 03:08:31 +00:00
|
|
|
} else {
|
2018-12-10 01:00:46 +00:00
|
|
|
context.outputFiles <- 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
|
|
|
}
|