diff --git a/cache.go b/cache.go index b824664..45a29e8 100644 --- a/cache.go +++ b/cache.go @@ -8,6 +8,7 @@ import ( "os" "path/filepath" "sort" + "strings" ) type cache struct { @@ -72,7 +73,9 @@ func (self *cache) buildCachePath(context *Context, outputPath string, inputFile hasher := crc32.NewIEEE() hasher.Write([]byte(outputPath)) - sort.Sort(filesByPath(inputFiles)) + sort.Slice(inputFiles, func(i, j int) bool { + return strings.Compare(inputFiles[i].Path(), inputFiles[j].Path()) < 0 + }) for _, inputFile := range inputFiles { modTimeBuff := make([]byte, 8) diff --git a/file_exporter.go b/file_exporter.go new file mode 100644 index 0000000..e321f7c --- /dev/null +++ b/file_exporter.go @@ -0,0 +1,69 @@ +package goldsmith + +import ( + "os" + "path/filepath" +) + +type fileExporter struct { + targetDir string + clean bool + tokens map[string]bool +} + +func (*fileExporter) Name() string { + return "exporter" +} + +func (self *fileExporter) Initialize(context *Context) error { + self.tokens = make(map[string]bool) + context.Threads(1) + return nil +} + +func (self *fileExporter) Process(context *Context, file *File) error { + slicePath := func(path string) string { + if filepath.IsAbs(path) { + var err error + if path, err = filepath.Rel("/", path); err != nil { + panic(err) + } + } + + return filepath.Clean(path) + } + + for token := slicePath(file.relPath); token != "."; token = filepath.Dir(token) { + self.tokens[token] = true + } + + return file.export(self.targetDir) +} + +func (self *fileExporter) Finalize(context *Context) error { + if !self.clean { + return nil + } + + infoChan := make(chan fileInfo) + go scanDir(self.targetDir, infoChan) + + for info := range infoChan { + if info.path == self.targetDir { + continue + } + + relPath, err := filepath.Rel(self.targetDir, info.path) + if err != nil { + panic(err) + } + + if tokenized, _ := self.tokens[relPath]; !tokenized { + if err := os.RemoveAll(info.path); err != nil { + return err + } + } + } + + return nil +} diff --git a/file_importer.go b/file_importer.go new file mode 100644 index 0000000..a110a97 --- /dev/null +++ b/file_importer.go @@ -0,0 +1,38 @@ +package goldsmith + +import ( + "path/filepath" +) + +type fileImporter struct { + sourceDir string +} + +func (*fileImporter) Name() string { + return "importer" +} + +func (self *fileImporter) Initialize(context *Context) error { + infoChan := make(chan fileInfo) + go scanDir(self.sourceDir, infoChan) + + for info := range infoChan { + if info.IsDir() { + continue + } + + relPath, err := filepath.Rel(self.sourceDir, info.path) + if err != nil { + panic(err) + } + + file, err := context.CreateFileFromAsset(relPath, info.path) + if err != nil { + return err + } + + context.DispatchFile(file) + } + + return nil +} diff --git a/file_util.go b/file_util.go index a384d29..7ffb578 100644 --- a/file_util.go +++ b/file_util.go @@ -3,45 +3,19 @@ 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) - } - } +func scanDir(dir string, infoChan chan fileInfo) { + defer close(infoChan) - 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 { + filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { if err == nil { - infos <- fileInfo{FileInfo: info, path: path} + infoChan <- fileInfo{FileInfo: info, path: path} } return err diff --git a/goldsmith.go b/goldsmith.go index c70af31..63c7608 100644 --- a/goldsmith.go +++ b/goldsmith.go @@ -8,9 +8,6 @@ import ( // Goldsmith chainable context. type Goldsmith struct { - sourceDir string - targetDir string - contexts []*Context cache *cache @@ -24,8 +21,8 @@ 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} - goldsmith.Chain(&loader{}) + goldsmith := new(Goldsmith) + goldsmith.Chain(&fileImporter{sourceDir: sourceDir}) return goldsmith } @@ -77,9 +74,7 @@ func (self *Goldsmith) FilterPop() *Goldsmith { // End stops a chain, writing all recieved files to targetDir as output. func (self *Goldsmith) End(targetDir string) []error { - self.targetDir = targetDir - - self.Chain(&saver{clean: self.clean}) + self.Chain(&fileExporter{targetDir: targetDir, clean: self.clean}) for _, context := range self.contexts { go context.step() } diff --git a/loader.go b/loader.go deleted file mode 100644 index 58b26a1..0000000 --- a/loader.go +++ /dev/null @@ -1,30 +0,0 @@ -package goldsmith - -import "path/filepath" - -type loader struct{} - -func (*loader) Name() string { - return "loader" -} - -func (*loader) Initialize(context *Context) error { - scannedInfo := make(chan fileInfo) - go scanDir(context.goldsmith.sourceDir, scannedInfo) - - for info := range scannedInfo { - if info.IsDir() { - continue - } - - relPath, _ := filepath.Rel(context.goldsmith.sourceDir, info.path) - file, err := context.CreateFileFromAsset(relPath, info.path) - if err != nil { - return err - } - - context.DispatchFile(file) - } - - return nil -} diff --git a/saver.go b/saver.go deleted file mode 100644 index 5b880b9..0000000 --- a/saver.go +++ /dev/null @@ -1,49 +0,0 @@ -package goldsmith - -import ( - "os" - "path/filepath" -) - -type saver struct { - clean bool - tokens map[string]bool -} - -func (*saver) Name() string { - return "saver" -} - -func (self *saver) Initialize(context *Context) error { - self.tokens = make(map[string]bool) - context.Threads(1) - return nil -} - -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 (self *saver) Finalize(context *Context) error { - if !self.clean { - return nil - } - - scannedInfo := make(chan fileInfo) - go scanDir(context.goldsmith.targetDir, scannedInfo) - - for info := range scannedInfo { - if info.path != context.goldsmith.targetDir { - relPath, _ := filepath.Rel(context.goldsmith.targetDir, info.path) - if contained, _ := self.tokens[relPath]; !contained { - os.RemoveAll(info.path) - } - } - } - - return nil -}