From e408fa9335de3a073a80e212d492c8235c970d21 Mon Sep 17 00:00:00 2001 From: Alex Yatskov Date: Sat, 8 Jan 2022 18:08:36 -0800 Subject: [PATCH] Squashed commit of the following: commit 106991bfd59bb95977045399f7b4e5f4e7addc56 Author: Alex Yatskov Date: Sat Jan 8 11:19:21 2022 -0800 Rename property functions commit 07f6033d4e86df257806af16de002ce8fad3d67f Author: Alex Yatskov Date: Sat Jan 8 11:16:46 2022 -0800 Update rewrite commit ea2dc0b4d223d54832752f0efd3eb46d81d17b50 Author: Alex Yatskov Date: Fri Jan 7 22:47:17 2022 -0800 Add more property methods commit e2f7f8dc7ebc5b668539e8233e323a7c256eced2 Author: Alex Yatskov Date: Fri Jan 7 22:39:23 2022 -0800 Add step indexing commit a7ed2a0b1c95ed9fbb0bbd87c779cf51a92f0b5f Author: Alex Yatskov Date: Fri Jan 7 20:50:19 2022 -0800 Use self commit 7ecc01e508c06680dcb6b6ecd4265a7f72e2c933 Author: Alex Yatskov Date: Sun Aug 22 12:33:09 2021 -0700 Cleanup commit 87dd28a4c14b88bea061ca913f68e272cca787f9 Author: Alex Yatskov Date: Sun Aug 22 12:09:41 2021 -0700 Cleanup commit 129130128d2a50f119c46f70e7cb70ef421892ff Merge: 629fce0 e751d70 Author: Alex Yatskov Date: Sat Aug 21 12:18:09 2021 -0700 Merge branch 'master' into dev commit 629fce06a8fca6810ec772f558d9ffabda016d01 Author: Alex Yatskov Date: Sun Jun 27 19:34:53 2021 -0700 Abstract metadata --- cache.go | 30 +++---- context.go | 109 +++++++++++++---------- file.go | 235 ++++++++++++++++++------------------------------- file_util.go | 49 +++++++++++ filter_util.go | 31 +++++++ goldsmith.go | 83 ++++++++--------- loader.go | 16 ++-- saver.go | 22 ++--- 8 files changed, 296 insertions(+), 279 deletions(-) create mode 100644 file_util.go create mode 100644 filter_util.go diff --git a/cache.go b/cache.go index 71b7acc..3d61038 100644 --- a/cache.go +++ b/cache.go @@ -13,8 +13,8 @@ type cache struct { baseDir string } -func (cache *cache) retrieveFile(context *Context, outputPath string, inputFiles []*File) (*File, error) { - cachePath, err := cache.buildCachePath(context, outputPath, inputFiles) +func (self *cache) retrieveFile(context *Context, outputPath string, inputFiles []*File) (*File, error) { + cachePath, err := self.buildCachePath(context, outputPath, inputFiles) if err != nil { return nil, err } @@ -31,13 +31,13 @@ func (cache *cache) retrieveFile(context *Context, outputPath string, inputFiles return outputFile, nil } -func (cache *cache) storeFile(context *Context, outputFile *File, inputFiles []*File) error { - cachePath, err := cache.buildCachePath(context, outputFile.Path(), inputFiles) +func (self *cache) storeFile(context *Context, outputFile *File, inputFiles []*File) error { + cachePath, err := self.buildCachePath(context, outputFile.Path(), inputFiles) if err != nil { return err } - if err := os.MkdirAll(cache.baseDir, 0755); err != nil { + if err := os.MkdirAll(self.baseDir, 0755); err != nil { return err } @@ -67,28 +67,20 @@ func (cache *cache) storeFile(context *Context, outputFile *File, inputFiles []* return nil } -func (cache *cache) buildCachePath(context *Context, outputPath string, inputFiles []*File) (string, error) { - uintBuff := make([]byte, 4) - binary.LittleEndian.PutUint32(uintBuff, context.chainHash) - +func (self *cache) buildCachePath(context *Context, outputPath string, inputFiles []*File) (string, error) { hasher := crc32.NewIEEE() - hasher.Write(uintBuff) hasher.Write([]byte(outputPath)) sort.Sort(filesByPath(inputFiles)) + for _, inputFile := range inputFiles { - fileHash, err := inputFile.hash() - if err != nil { - return "", err - } - - binary.LittleEndian.PutUint32(uintBuff, fileHash) - - hasher.Write(uintBuff) + modTimeBuff := make([]byte, 8) + binary.LittleEndian.PutUint64(modTimeBuff, uint64(inputFile.ModTime().UnixNano())) hasher.Write([]byte(inputFile.Path())) + hasher.Write(modTimeBuff) } - cachePath := filepath.Join(cache.baseDir, fmt.Sprintf( + cachePath := filepath.Join(self.baseDir, fmt.Sprintf( "gs_%.8x%s", hasher.Sum32(), filepath.Ext(outputPath), diff --git a/context.go b/context.go index ba7ceb5..ba477ad 100644 --- a/context.go +++ b/context.go @@ -3,6 +3,8 @@ package goldsmith import ( "bytes" "errors" + "io" + "io/ioutil" "os" "runtime" "sync" @@ -14,31 +16,39 @@ import ( type Context struct { goldsmith *Goldsmith - plugin Plugin - chainHash uint32 + plugin Plugin filtersExt filterStack filtersInt filterStack threads int + index int filesIn chan *File filesOut chan *File } // CreateFileFrom data creates a new file instance from the provided data buffer. -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(), +func (self *Context) CreateFileFromReader(sourcePath string, reader io.Reader) (*File, error) { + data, err := ioutil.ReadAll(reader) + if err != nil { + return nil, err } + + file := &File{ + relPath: sourcePath, + props: make(map[string]Prop), + modTime: time.Now(), + size: int64(len(data)), + reader: bytes.NewReader(data), + index: self.index, + } + + return file, nil } // CreateFileFromAsset creates a new file instance from the provided file path. -func (*Context) CreateFileFromAsset(sourcePath, dataPath string) (*File, error) { +func (self *Context) CreateFileFromAsset(sourcePath, dataPath string) (*File, error) { info, err := os.Stat(dataPath) if err != nil { return nil, err @@ -48,70 +58,74 @@ func (*Context) CreateFileFromAsset(sourcePath, dataPath string) (*File, error) } file := &File{ - sourcePath: sourcePath, - dataPath: dataPath, - Meta: make(map[string]interface{}), - size: info.Size(), - modTime: info.ModTime(), + relPath: sourcePath, + props: make(map[string]Prop), + modTime: info.ModTime(), + size: info.Size(), + dataPath: dataPath, + index: self.index, } return file, nil } // DispatchFile causes the file to get passed to the next link in the chain. -func (context *Context) DispatchFile(file *File) { - context.filesOut <- file +func (self *Context) DispatchFile(file *File) { + self.filesOut <- 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. -func (context *Context) DispatchAndCacheFile(outputFile *File, inputFiles ...*File) { - if context.goldsmith.cache != nil { - context.goldsmith.cache.storeFile(context, outputFile, inputFiles) +func (self *Context) DispatchAndCacheFile(outputFile *File, inputFiles ...*File) { + if self.goldsmith.cache != nil { + self.goldsmith.cache.storeFile(self, outputFile, inputFiles) } - context.filesOut <- outputFile + self.filesOut <- outputFile } // 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. -func (context *Context) RetrieveCachedFile(outputPath string, inputFiles ...*File) *File { +func (self *Context) RetrieveCachedFile(outputPath string, inputFiles ...*File) *File { var outputFile *File - if context.goldsmith.cache != nil { - outputFile, _ = context.goldsmith.cache.retrieveFile(context, outputPath, inputFiles) + if self.goldsmith.cache != nil { + outputFile, _ = self.goldsmith.cache.retrieveFile(self, outputPath, inputFiles) } return outputFile } // Specify internal filter(s) that exclude files from being processed. -func (context *Context) Filter(filters ...Filter) *Context { - context.filtersInt = filters - return context +func (self *Context) Filter(filters ...Filter) *Context { + for _, filter := range filters { + self.filtersInt.push(filter, self.index) + } + + return self } // Specify the maximum number of threads used for processing. -func (context *Context) Threads(threads int) *Context { - context.threads = threads - return context +func (self *Context) Threads(threads int) *Context { + self.threads = threads + return self } -func (context *Context) step() { - defer close(context.filesOut) +func (self *Context) step() { + defer close(self.filesOut) - if initializer, ok := context.plugin.(Initializer); ok { - if err := initializer.Initialize(context); err != nil { - context.goldsmith.fault(context.plugin.Name(), nil, err) + if initializer, ok := self.plugin.(Initializer); ok { + if err := initializer.Initialize(self); err != nil { + self.goldsmith.fault(self.plugin.Name(), nil, err) return } } - if context.filesIn != nil { - processor, _ := context.plugin.(Processor) + if self.filesIn != nil { + processor, _ := self.plugin.(Processor) - threads := context.threads + threads := self.threads if threads < 1 { threads = runtime.NumCPU() } @@ -121,26 +135,27 @@ func (context *Context) step() { wg.Add(1) go func() { defer wg.Done() - for inputFile := range context.filesIn { - if processor != nil && context.filtersInt.accept(inputFile) && context.filtersExt.accept(inputFile) { + for inputFile := range self.filesIn { + if processor != nil && self.filtersInt.accept(inputFile) && self.filtersExt.accept(inputFile) { if _, err := inputFile.Seek(0, os.SEEK_SET); err != nil { - context.goldsmith.fault("core", inputFile, err) + self.goldsmith.fault("core", inputFile, err) } - if err := processor.Process(context, inputFile); err != nil { - context.goldsmith.fault(context.plugin.Name(), inputFile, err) + if err := processor.Process(self, inputFile); err != nil { + self.goldsmith.fault(self.plugin.Name(), inputFile, err) } } else { - context.filesOut <- inputFile + self.filesOut <- inputFile } } }() } + wg.Wait() } - if finalizer, ok := context.plugin.(Finalizer); ok { - if err := finalizer.Finalize(context); err != nil { - context.goldsmith.fault(context.plugin.Name(), nil, err) + if finalizer, ok := self.plugin.(Finalizer); ok { + if err := finalizer.Finalize(self); err != nil { + self.goldsmith.fault(self.plugin.Name(), nil, err) } } } diff --git a/file.go b/file.go index f5cbbaf..ad52950 100644 --- a/file.go +++ b/file.go @@ -2,106 +2,144 @@ package goldsmith import ( "bytes" - "hash/crc32" "io" "io/ioutil" "os" "path" "path/filepath" - "strings" "time" ) +type Prop interface{} +type PropMap map[string]Prop + // File represents in-memory or on-disk files in a chain. type File struct { - sourcePath string - dataPath string - - Meta map[string]interface{} - - hashValue uint32 - hashValid bool - - reader *bytes.Reader - size int64 + relPath string + props map[string]Prop modTime time.Time + size int64 + + dataPath string + reader *bytes.Reader + + index int } // Rename modifies the file path relative to the source directory. -func (file *File) Rename(path string) { - file.sourcePath = path +func (self *File) Rename(path string) { + self.relPath = path +} + +func (self *File) Rewrite(reader io.Reader) error { + data, err := ioutil.ReadAll(reader) + if err != nil { + return err + } + + self.reader = bytes.NewReader(data) + self.modTime = time.Now() + self.size = int64(len(data)) + return nil } // Path returns the file path relative to the source directory. -func (file *File) Path() string { - return file.sourcePath +func (self *File) Path() string { + return self.relPath } // Name returns the base name of the file. -func (file *File) Name() string { - return path.Base(file.sourcePath) +func (self *File) Name() string { + return path.Base(self.relPath) } // Dir returns the containing directory of the file. -func (file *File) Dir() string { - return path.Dir(file.sourcePath) +func (self *File) Dir() string { + return path.Dir(self.relPath) } // Ext returns the extension of the file. -func (file *File) Ext() string { - return path.Ext(file.sourcePath) +func (self *File) Ext() string { + return path.Ext(self.relPath) } // Size returns the file length in bytes. -func (file *File) Size() int64 { - return file.size +func (self *File) Size() int64 { + return self.size } // ModTime returns the time of the file's last modification. -func (file *File) ModTime() time.Time { - return file.modTime +func (self *File) ModTime() time.Time { + return self.modTime } // Read reads file data into the provided buffer. -func (file *File) Read(data []byte) (int, error) { - if err := file.load(); err != nil { +func (self *File) Read(data []byte) (int, error) { + if err := self.load(); err != nil { return 0, err } - return file.reader.Read(data) + return self.reader.Read(data) } // Write writes file data into the provided writer. -func (file *File) WriteTo(writer io.Writer) (int64, error) { - if err := file.load(); err != nil { +func (self *File) WriteTo(writer io.Writer) (int64, error) { + if err := self.load(); err != nil { return 0, err } - return file.reader.WriteTo(writer) + return self.reader.WriteTo(writer) } // Seek updates the file pointer to the desired position. -func (file *File) Seek(offset int64, whence int) (int64, error) { - if file.reader == nil && offset == 0 && (whence == os.SEEK_SET || whence == os.SEEK_CUR) { +func (self *File) Seek(offset int64, whence int) (int64, error) { + if self.reader == nil && offset == 0 && (whence == os.SEEK_SET || whence == os.SEEK_CUR) { return 0, nil } - if err := file.load(); err != nil { + if err := self.load(); err != nil { return 0, err } - return file.reader.Seek(offset, whence) + return self.reader.Seek(offset, whence) } // Returns value for string formatting. -func (file *File) GoString() string { - return file.sourcePath +func (self *File) GoString() string { + return self.relPath } -func (file *File) export(targetDir string) error { - targetPath := filepath.Join(targetDir, file.sourcePath) +func (self *File) SetProp(name string, value Prop) { + self.props[name] = value +} - if targetInfo, err := os.Stat(targetPath); err == nil && !targetInfo.ModTime().Before(file.ModTime()) { +func (self *File) CopyProps(file *File) { + for key, value := range file.props { + self.props[key] = value + } +} + +func (self *File) Prop(name string) (Prop, bool) { + value, ok := self.props[name] + return value, ok +} + +func (self *File) Props() PropMap { + return self.props +} + +func (self *File) PropOrDefault(name string, valueDef Prop) Prop { + if value, ok := self.Prop(name); ok { + return value + } + + return valueDef +} + +func (self *File) export(targetDir string) error { + targetPath := filepath.Join(targetDir, self.relPath) + + if targetInfo, err := os.Stat(targetPath); err == nil && !targetInfo.ModTime().Before(self.ModTime()) { return nil } @@ -115,8 +153,8 @@ func (file *File) export(targetDir string) error { } defer fw.Close() - if file.reader == nil { - fr, err := os.Open(file.dataPath) + if self.reader == nil { + fr, err := os.Open(self.dataPath) if err != nil { return err } @@ -126,11 +164,11 @@ func (file *File) export(targetDir string) error { return err } } else { - if _, err := file.Seek(0, os.SEEK_SET); err != nil { + if _, err := self.Seek(0, os.SEEK_SET); err != nil { return err } - if _, err := file.WriteTo(fw); err != nil { + if _, err := self.WriteTo(fw); err != nil { return err } } @@ -138,115 +176,16 @@ func (file *File) export(targetDir string) error { return nil } -func (file *File) load() error { - if file.reader != nil { +func (self *File) load() error { + if self.reader != nil { return nil } - data, err := ioutil.ReadFile(file.dataPath) + data, err := ioutil.ReadFile(self.dataPath) if err != nil { return err } - file.reader = bytes.NewReader(data) + self.reader = bytes.NewReader(data) return nil } - -func (file *File) hash() (uint32, error) { - if file.hashValid { - return file.hashValue, nil - } - - if err := file.load(); err != nil { - return 0, err - } - - offset, err := file.Seek(0, os.SEEK_CUR) - if err != nil { - return 0, err - } - - if _, err := file.Seek(0, os.SEEK_SET); err != nil { - return 0, err - } - - hasher := crc32.NewIEEE() - if _, err := io.Copy(hasher, file.reader); err != nil { - return 0, err - } - - if _, err := file.Seek(offset, os.SEEK_SET); err != nil { - return 0, err - } - - file.hashValue = hasher.Sum32() - file.hashValid = true - return file.hashValue, nil -} - -type filesByPath []*File - -func (file filesByPath) Len() int { - return len(file) -} - -func (file filesByPath) Swap(i, j int) { - file[i], file[j] = file[j], file[i] -} - -func (file filesByPath) Less(i, j int) bool { - return strings.Compare(file[i].Path(), file[j].Path()) < 0 -} - -type fileInfo struct { - os.FileInfo - path string -} - -func cleanPath(path string) string { - if filepath.IsAbs(path) { - var err error - if path, err = filepath.Rel("/", path); err != nil { - panic(err) - } - } - - return filepath.Clean(path) -} - -func scanDir(rootDir string, infos chan fileInfo) { - defer close(infos) - - filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { - if err == nil { - infos <- fileInfo{FileInfo: info, path: path} - } - - return err - }) -} - -type filterStack []Filter - -func (filters *filterStack) accept(file *File) bool { - for _, filter := range *filters { - if !filter.Accept(file) { - return false - } - } - - return true -} - -func (filters *filterStack) push(filter Filter) { - *filters = append(*filters, filter) -} - -func (filters *filterStack) pop() { - count := len(*filters) - if count == 0 { - panic("attempted to pop empty filter stack") - } - - *filters = (*filters)[:count-1] -} diff --git a/file_util.go b/file_util.go new file mode 100644 index 0000000..a384d29 --- /dev/null +++ b/file_util.go @@ -0,0 +1,49 @@ +package goldsmith + +import ( + "os" + "path/filepath" + "strings" +) + +type filesByPath []*File + +func (self filesByPath) Len() int { + return len(self) +} + +func (self filesByPath) Swap(i, j int) { + self[i], self[j] = self[j], self[i] +} + +func (self filesByPath) Less(i, j int) bool { + return strings.Compare(self[i].Path(), self[j].Path()) < 0 +} + +type fileInfo struct { + os.FileInfo + path string +} + +func cleanPath(path string) string { + if filepath.IsAbs(path) { + var err error + if path, err = filepath.Rel("/", path); err != nil { + panic(err) + } + } + + return filepath.Clean(path) +} + +func scanDir(rootDir string, infos chan fileInfo) { + defer close(infos) + + filepath.Walk(rootDir, func(path string, info os.FileInfo, err error) error { + if err == nil { + infos <- fileInfo{FileInfo: info, path: path} + } + + return err + }) +} diff --git a/filter_util.go b/filter_util.go new file mode 100644 index 0000000..d3744d1 --- /dev/null +++ b/filter_util.go @@ -0,0 +1,31 @@ +package goldsmith + +type filterEntry struct { + filter Filter + index int +} + +type filterStack []filterEntry + +func (self *filterStack) accept(file *File) bool { + for _, entry := range *self { + if entry.index >= file.index && !entry.filter.Accept(file) { + return false + } + } + + return true +} + +func (self *filterStack) push(filter Filter, index int) { + *self = append(*self, filterEntry{filter, index}) +} + +func (self *filterStack) pop() { + count := len(*self) + if count == 0 { + panic("attempted to pop empty filter stack") + } + + *self = (*self)[:count-1] +} diff --git a/goldsmith.go b/goldsmith.go index f6c8f51..c70af31 100644 --- a/goldsmith.go +++ b/goldsmith.go @@ -3,8 +3,6 @@ package goldsmith import ( "fmt" - "hash" - "hash/crc32" "sync" ) @@ -13,12 +11,12 @@ type Goldsmith struct { sourceDir string targetDir string - contexts []*Context - contextHasher hash.Hash32 + contexts []*Context cache *cache filters filterStack clean bool + index int errors []error mutex sync.Mutex @@ -26,80 +24,77 @@ type Goldsmith struct { // Begin starts a chain, reading the files located in the source directory as input. func Begin(sourceDir string) *Goldsmith { - goldsmith := &Goldsmith{ - sourceDir: sourceDir, - contextHasher: crc32.NewIEEE(), - } - + goldsmith := &Goldsmith{sourceDir: sourceDir} goldsmith.Chain(&loader{}) return goldsmith } // Cache enables caching in cacheDir for the remainder of the chain. -func (goldsmith *Goldsmith) Cache(cacheDir string) *Goldsmith { - goldsmith.cache = &cache{cacheDir} - return goldsmith +func (self *Goldsmith) Cache(cacheDir string) *Goldsmith { + self.cache = &cache{cacheDir} + return self } // Clean enables or disables removal of leftover files in the target directory. -func (goldsmith *Goldsmith) Clean(clean bool) *Goldsmith { - goldsmith.clean = clean - return goldsmith +func (self *Goldsmith) Clean(clean bool) *Goldsmith { + self.clean = clean + return self } // Chain links a plugin instance into the chain. -func (goldsmith *Goldsmith) Chain(plugin Plugin) *Goldsmith { - goldsmith.contextHasher.Write([]byte(plugin.Name())) - +func (self *Goldsmith) Chain(plugin Plugin) *Goldsmith { context := &Context{ - goldsmith: goldsmith, - plugin: plugin, - chainHash: goldsmith.contextHasher.Sum32(), - filesOut: make(chan *File), + goldsmith: self, + plugin: plugin, + filtersExt: append(filterStack(nil), self.filters...), + index: self.index, + filesOut: make(chan *File), } - context.filtersExt = append(context.filtersExt, goldsmith.filters...) - - if len(goldsmith.contexts) > 0 { - context.filesIn = goldsmith.contexts[len(goldsmith.contexts)-1].filesOut + if len(self.contexts) > 0 { + context.filesIn = self.contexts[len(self.contexts)-1].filesOut } - goldsmith.contexts = append(goldsmith.contexts, context) - return goldsmith + self.contexts = append(self.contexts, context) + self.index++ + + return self } // FilterPush pushes a filter instance on the chain's filter stack. -func (goldsmith *Goldsmith) FilterPush(filter Filter) *Goldsmith { - goldsmith.filters.push(filter) - return goldsmith +func (self *Goldsmith) FilterPush(filter Filter) *Goldsmith { + self.filters.push(filter, self.index) + self.index++ + return self } // FilterPop pops a filter instance from the chain's filter stack. -func (goldsmith *Goldsmith) FilterPop() *Goldsmith { - goldsmith.filters.pop() - return goldsmith +func (self *Goldsmith) FilterPop() *Goldsmith { + self.filters.pop() + self.index++ + return self } // End stops a chain, writing all recieved files to targetDir as output. -func (goldsmith *Goldsmith) End(targetDir string) []error { - goldsmith.targetDir = targetDir +func (self *Goldsmith) End(targetDir string) []error { + self.targetDir = targetDir - goldsmith.Chain(&saver{clean: goldsmith.clean}) - for _, context := range goldsmith.contexts { + self.Chain(&saver{clean: self.clean}) + for _, context := range self.contexts { go context.step() } - context := goldsmith.contexts[len(goldsmith.contexts)-1] + context := self.contexts[len(self.contexts)-1] for range context.filesOut { } - return goldsmith.errors + return self.errors } -func (goldsmith *Goldsmith) fault(name string, file *File, err error) { - goldsmith.mutex.Lock() - defer goldsmith.mutex.Unlock() +func (self *Goldsmith) fault(name string, file *File, err error) { + self.mutex.Lock() + defer self.mutex.Unlock() var faultError error if file == nil { @@ -108,5 +103,5 @@ func (goldsmith *Goldsmith) fault(name string, file *File, err error) { faultError = fmt.Errorf("[%s@%v]: %w", name, file, err) } - goldsmith.errors = append(goldsmith.errors, faultError) + self.errors = append(self.errors, faultError) } diff --git a/loader.go b/loader.go index fba2cd9..58b26a1 100644 --- a/loader.go +++ b/loader.go @@ -9,22 +9,18 @@ func (*loader) Name() string { } func (*loader) Initialize(context *Context) error { - infos := make(chan fileInfo) - go scanDir(context.goldsmith.sourceDir, infos) + scannedInfo := make(chan fileInfo) + go scanDir(context.goldsmith.sourceDir, scannedInfo) - for info := range infos { + for info := range scannedInfo { if info.IsDir() { continue } relPath, _ := filepath.Rel(context.goldsmith.sourceDir, info.path) - - file := &File{ - sourcePath: relPath, - Meta: make(map[string]interface{}), - modTime: info.ModTime(), - size: info.Size(), - dataPath: info.path, + file, err := context.CreateFileFromAsset(relPath, info.path) + if err != nil { + return err } context.DispatchFile(file) diff --git a/saver.go b/saver.go index 0545f49..5b880b9 100644 --- a/saver.go +++ b/saver.go @@ -14,32 +14,32 @@ func (*saver) Name() string { return "saver" } -func (saver *saver) Initialize(context *Context) error { - saver.tokens = make(map[string]bool) +func (self *saver) Initialize(context *Context) error { + self.tokens = make(map[string]bool) context.Threads(1) return nil } -func (saver *saver) Process(context *Context, file *File) error { - for token := cleanPath(file.sourcePath); token != "."; token = filepath.Dir(token) { - saver.tokens[token] = true +func (self *saver) Process(context *Context, file *File) error { + for token := cleanPath(file.relPath); token != "."; token = filepath.Dir(token) { + self.tokens[token] = true } return file.export(context.goldsmith.targetDir) } -func (saver *saver) Finalize(context *Context) error { - if !saver.clean { +func (self *saver) Finalize(context *Context) error { + if !self.clean { return nil } - infos := make(chan fileInfo) - go scanDir(context.goldsmith.targetDir, infos) + scannedInfo := make(chan fileInfo) + go scanDir(context.goldsmith.targetDir, scannedInfo) - for info := range infos { + for info := range scannedInfo { if info.path != context.goldsmith.targetDir { relPath, _ := filepath.Rel(context.goldsmith.targetDir, info.path) - if contained, _ := saver.tokens[relPath]; !contained { + if contained, _ := self.tokens[relPath]; !contained { os.RemoveAll(info.path) } }