This commit is contained in:
Alex Yatskov 2015-12-17 12:37:11 +09:00
parent 394982f9e9
commit 37539daaf6
2 changed files with 65 additions and 70 deletions

View File

@ -29,19 +29,15 @@ import (
"sync" "sync"
) )
const (
FileFlagStatic = 1 << iota
)
type stage struct { type stage struct {
input, output chan *File input, output chan *File
err error
} }
type goldsmith struct { type goldsmith struct {
srcDir, dstDir string srcDir, dstDir string
stages []stage stages []*stage
refs map[string]bool refs map[string]bool
err error
} }
func New(srcDir, dstDir string) Goldsmith { func New(srcDir, dstDir string) Goldsmith {
@ -50,21 +46,21 @@ func New(srcDir, dstDir string) Goldsmith {
return gs return gs
} }
func NewFile(path string) *File { func (gs *goldsmith) NewFile(path string) *File {
return &File{ return &File{
Path: cleanPath(path), Path: cleanPath(path),
Meta: make(map[string]interface{}), Meta: make(map[string]interface{}),
} }
} }
func NewFileStatic(path string) *File { func (gs *goldsmith) NewFileStatic(path string) *File {
file := NewFile(path) file := gs.NewFile(path)
file.Type = FileStatic file.Type = FileStatic
return file return file
} }
func NewFileRef(path string) *File { func (gs *goldsmith) NewFileRef(path string) *File {
file := NewFile(path) file := gs.NewFile(path)
file.Type = FileReference file.Type = FileReference
return file return file
} }
@ -84,7 +80,7 @@ func (gs *goldsmith) queueFiles() {
panic(err) panic(err)
} }
file := NewFile(relPath) file := gs.NewFile(relPath)
var f *os.File var f *os.File
if f, file.Err = os.Open(path); file.Err == nil { if f, file.Err = os.Open(path); file.Err == nil {
@ -160,8 +156,8 @@ func (gs *goldsmith) exportFile(file *File) {
} }
} }
func (gs *goldsmith) makeStage() stage { func (gs *goldsmith) makeStage() *stage {
s := stage{output: make(chan *File)} s := &stage{output: make(chan *File)}
if len(gs.stages) > 0 { if len(gs.stages) > 0 {
s.input = gs.stages[len(gs.stages)-1].output s.input = gs.stages[len(gs.stages)-1].output
} }
@ -170,43 +166,36 @@ func (gs *goldsmith) makeStage() stage {
return s return s
} }
func (gs *goldsmith) chain(s stage, c Chainer) { func (gs *goldsmith) chain(s *stage, p Plugin) {
var ( defer close(s.output)
wg sync.WaitGroup
output = make(chan *File)
input = make(chan *File)
)
wg.Add(1) if init, ok := p.(Initializer); ok {
go func() { if s.err = init.Initialize(gs); s.err != nil {
for file := range output { return
s.output <- file }
} }
wg.Done() if proc, ok := p.(Processor); ok {
}() var wg sync.WaitGroup
wg.Add(1)
go func() {
a, _ := c.(Accepter)
for file := range s.input { for file := range s.input {
if file.Type == FileNormal && (a == nil || a.Accept(file)) { go func(f *File) {
input <- file defer wg.Done()
} else { if proc.Process(gs, f) {
s.output <- file s.output <- f
} }
}(file)
} }
close(input)
wg.Done()
}()
go func() {
c.Chain(gs, input, output)
wg.Wait() wg.Wait()
close(s.output) } else {
}() for file := range s.input {
s.output <- file
}
}
if fin, ok := p.(Finalizer); ok {
s.err = fin.Finalize(gs)
}
} }
func (gs *goldsmith) refFile(path string) { func (gs *goldsmith) refFile(path string) {
@ -234,42 +223,34 @@ func (gs *goldsmith) DstDir() string {
return gs.dstDir return gs.dstDir
} }
func (gs *goldsmith) Chain(c Chainer, err error) Goldsmith { func (gs *goldsmith) Chain(p Plugin) Goldsmith {
if gs.err != nil { go gs.chain(gs.makeStage(), p)
return gs return gs
} }
if gs.err = err; gs.err == nil { func (gs *goldsmith) Complete() ([]*File, []error) {
gs.chain(gs.makeStage(), c)
}
return gs
}
func (gs *goldsmith) Complete() ([]*File, error) {
s := gs.stages[len(gs.stages)-1] s := gs.stages[len(gs.stages)-1]
var files []*File var files []*File
for file := range s.output { for file := range s.output {
if gs.err == nil {
gs.exportFile(file) gs.exportFile(file)
}
file.Buff.Reset() file.Buff.Reset()
files = append(files, file) files = append(files, file)
} }
if gs.err == nil {
gs.cleanupFiles() gs.cleanupFiles()
}
err := gs.err var errs []error
for _, s := range gs.stages {
if s.err != nil {
errs = append(errs, s.err)
}
}
gs.stages = nil gs.stages = nil
gs.refs = nil gs.refs = nil
gs.err = nil
return files, err return files, errs
} }
func cleanPath(path string) string { func cleanPath(path string) string {

View File

@ -25,18 +25,28 @@ package goldsmith
import "bytes" import "bytes"
type Goldsmith interface { type Goldsmith interface {
Chain(c Chainer, err error) Goldsmith Chain(p Plugin, err error) Goldsmith
Complete() ([]*File, error) Complete() ([]*File, []error)
}
type Plugin interface{}
type Initializer interface {
Initialize(ctx Context) error
}
type Finalizer interface {
Finalize(ctx Context) error
}
type Processor interface {
Process(ctx Context, file *File) bool
} }
type Chainer interface { type Chainer interface {
Chain(ctx Context, input, output chan *File) Chain(ctx Context, input, output chan *File)
} }
type Accepter interface {
Accept(file *File) bool
}
type FileType int type FileType int
const ( const (
@ -56,4 +66,8 @@ type File struct {
type Context interface { type Context interface {
SrcDir() string SrcDir() string
DstDir() string DstDir() string
NewFile(path string) *File
NewFileStatic(path string) *File
NewFileRef(path string) *File
} }