-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from albertrdixon/feature/chan
Refactor to use buffered channel and new File interface
- Loading branch information
Showing
17 changed files
with
667 additions
and
339 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
package config | ||
|
||
const ( | ||
CodeVersion = "v0.1.1" | ||
CodeVersion = "v1.0.0" | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package file | ||
|
||
import ( | ||
"bytes" | ||
"os" | ||
"text/template" | ||
) | ||
|
||
// Testing is set to true for running file tests | ||
var Testing bool | ||
|
||
// File describes a tmplnator template file | ||
type File interface { | ||
Write(*bytes.Buffer, interface{}) error | ||
Read() ([]byte, error) | ||
Template(*template.Template) | ||
Destination() string | ||
Info() Info | ||
Output() string | ||
DeleteTemplate() error | ||
setDir(string, ...interface{}) string | ||
setName(string, ...interface{}) string | ||
setUser(int) string | ||
setGroup(int) string | ||
setMode(os.FileMode) string | ||
setDirMode(os.FileMode) string | ||
setSkip() string | ||
} | ||
|
||
// Info objects have all the info for objects that implement File. | ||
type Info struct { | ||
Src string | ||
Name string | ||
Dir string | ||
User int | ||
Group int | ||
Mode os.FileMode | ||
Dirmode os.FileMode | ||
} | ||
|
||
// NewFile returns a File object. If Testing is true underlying struct is | ||
// a mockFile, otherwise it is a templateFile | ||
func NewFile(path string, defaultDir string) File { | ||
if Testing { | ||
return newMockFile(path, defaultDir) | ||
} | ||
return newTemplateFile(path, defaultDir) | ||
} | ||
|
||
func init() { | ||
Testing = false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package file | ||
|
||
import ( | ||
// "io/ioutil" | ||
"bytes" | ||
"os" | ||
"testing" | ||
) | ||
|
||
var filetest = []struct { | ||
name string | ||
template string | ||
expectedOutput string | ||
expectedInfo Info | ||
expectError bool | ||
stackSize int | ||
}{ | ||
{ | ||
name: "bad", | ||
template: `{{ dir "/some/other/path" }{{ mode 0755 "one too many" }}Body Text {{ env "BAD" Something }}`, | ||
expectedOutput: "", | ||
expectedInfo: Info{}, | ||
expectError: true, | ||
stackSize: 0, | ||
}, | ||
{ | ||
name: "change_everything", | ||
template: `{{ dir "/some/path" }}{{ name "name_changed" }}{{ mode 0777 }}{{ user 10000 }}Body Text`, | ||
expectedOutput: "Body Text", | ||
expectedInfo: Info{ | ||
Name: "name_changed", | ||
Dir: "/some/path", | ||
Mode: os.FileMode(0777), | ||
User: 10000, | ||
}, | ||
expectError: false, | ||
stackSize: 1, | ||
}, | ||
} | ||
|
||
func TestParseFile(t *testing.T) { | ||
Testing = true | ||
for _, ft := range filetest { | ||
fq := NewFileQueue() | ||
mf := NewFile(ft.template, ft.name) | ||
err := ParseFile(mf, fq) | ||
fq.PopulateQueue() | ||
|
||
if !ft.expectError && err != nil { | ||
t.Errorf("ParseFile(%q): Expected no error while parsing, got: %v", ft.name, err) | ||
} | ||
if ft.expectError && err == nil { | ||
t.Errorf("ParseFile(%q): Expected an error while parsing", ft.name) | ||
} | ||
if fq.Len() != ft.stackSize { | ||
t.Errorf("ParseFile(%q): Expected stack size to be %d, got %d", ft.name, ft.stackSize, fq.Len()) | ||
} | ||
} | ||
} | ||
|
||
func TestWriteFile(t *testing.T) { | ||
Testing = true | ||
for _, ft := range filetest { | ||
fq := NewFileQueue() | ||
mf := NewFile(ft.template, ft.name) | ||
err := ParseFile(mf, fq) | ||
if err != nil { | ||
if !ft.expectError { | ||
t.Errorf("WriteFile(%q): Parsing failed, please fix it.", ft.name) | ||
} | ||
} else { | ||
err = mf.Write(new(bytes.Buffer), nil) | ||
if err != nil { | ||
t.Errorf("WriteFile(%q): Did not expect error in write: %v", ft.name, err) | ||
} | ||
|
||
out, info := mf.Output(), mf.Info() | ||
if out != ft.expectedOutput { | ||
t.Errorf("WriteFile(%q): Expected output=%q, got output=%q", ft.name, ft.expectedOutput, out) | ||
} | ||
|
||
if info.Name != ft.expectedInfo.Name { | ||
t.Errorf("WriteFile(%q): Expected filename=%q, got filename=%q", ft.name, ft.expectedInfo.Name, info.Name) | ||
} | ||
if info.Dir != ft.expectedInfo.Dir { | ||
t.Errorf("WriteFile(%q): Expected dir=%q, got dir=%q", ft.name, ft.expectedInfo.Dir, info.Dir) | ||
} | ||
if info.Mode != ft.expectedInfo.Mode { | ||
t.Errorf("WriteFile(%q): Expected mode=%q, got mode=%q", ft.name, ft.expectedInfo.Mode, info.Mode) | ||
} | ||
if info.User != ft.expectedInfo.User { | ||
t.Errorf("WriteFile(%q): Expected user=%d, got user=%d", ft.name, ft.expectedInfo.User, info.User) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
package file | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"os" | ||
"path/filepath" | ||
tmpl "text/template" | ||
) | ||
|
||
type mockFile struct { | ||
dir string | ||
dirmode os.FileMode | ||
example string | ||
group int | ||
mode os.FileMode | ||
name string | ||
output string | ||
template *tmpl.Template | ||
user int | ||
} | ||
|
||
func (mf *mockFile) Write(b *bytes.Buffer, data interface{}) (err error) { | ||
err = mf.template.Execute(b, data) | ||
mf.output = b.String() | ||
return | ||
} | ||
|
||
func (mf *mockFile) Read() ([]byte, error) { | ||
return []byte(mf.example), nil | ||
} | ||
|
||
func (mf *mockFile) Template(t *tmpl.Template) { | ||
mf.template = t | ||
} | ||
|
||
func (mf *mockFile) Destination() string { | ||
return filepath.Join(mf.dir, mf.name) | ||
} | ||
|
||
func (mf *mockFile) Info() Info { | ||
return Info{ | ||
Name: mf.name, | ||
Dir: mf.dir, | ||
User: mf.user, | ||
Group: mf.group, | ||
Mode: mf.mode, | ||
Dirmode: mf.dirmode, | ||
} | ||
} | ||
|
||
func (mf *mockFile) Output() string { | ||
return mf.output | ||
} | ||
|
||
func (mf *mockFile) DeleteTemplate() error { | ||
return nil | ||
} | ||
|
||
func (mf *mockFile) setDir(d string, args ...interface{}) string { | ||
for i, a := range args { | ||
if a == nil { | ||
args[i] = "" | ||
} | ||
} | ||
mf.dir = fmt.Sprintf(d, args...) | ||
return "" | ||
} | ||
|
||
func (mf *mockFile) setName(n string, args ...interface{}) string { | ||
for i, a := range args { | ||
if a == nil { | ||
args[i] = "" | ||
} | ||
} | ||
mf.name = fmt.Sprintf(n, args...) | ||
return "" | ||
} | ||
|
||
func (mf *mockFile) setUser(uid int) string { | ||
mf.user = uid | ||
return "" | ||
} | ||
|
||
func (mf *mockFile) setGroup(gid int) string { | ||
mf.group = gid | ||
return "" | ||
} | ||
|
||
func (mf *mockFile) setMode(fm os.FileMode) string { | ||
mf.mode = fm | ||
return "" | ||
} | ||
|
||
func (mf *mockFile) setDirMode(dm os.FileMode) string { | ||
mf.dirmode = dm | ||
return "" | ||
} | ||
|
||
func (mf *mockFile) setSkip() string { | ||
return "" | ||
} | ||
|
||
func newMockFile(e string, n string) File { | ||
return &mockFile{ | ||
example: e, | ||
name: n, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package file | ||
|
||
import ( | ||
l "github.com/Sirupsen/logrus" | ||
"os" | ||
"path/filepath" | ||
"text/template" | ||
) | ||
|
||
// ParseFiles will recursively parse all the files under dir, returning | ||
// a Queue object with all the files loaded in. | ||
func ParseFiles(dir string, def string) (fq *Queue, err error) { | ||
l.WithField("directory", dir).Info("Parsing files") | ||
fq = NewFileQueue() | ||
err = filepath.Walk(dir, walkfunc(def, fq)) | ||
fq.PopulateQueue() | ||
return | ||
} | ||
|
||
func walkfunc(def string, fq *Queue) filepath.WalkFunc { | ||
return func(path string, info os.FileInfo, err error) error { | ||
ext := filepath.Ext(path) | ||
if info.Mode().IsRegular() && ext != ".skip" && ext != ".ignore" { | ||
f := NewFile(path, def) | ||
return ParseFile(f, fq) | ||
} | ||
l.WithField("path", path).Debug("Skipping") | ||
return nil | ||
} | ||
} | ||
|
||
// ParseFile will parse an individual file and put it in the | ||
// Queue | ||
func ParseFile(f File, fq *Queue) (err error) { | ||
l.WithField("path", f.Info().Src).Debug("Parsing file") | ||
|
||
contents, err := f.Read() | ||
if err != nil { | ||
return | ||
} | ||
|
||
t, err := newTemplate(f).Parse(string(contents)) | ||
if err != nil { | ||
return | ||
} | ||
f.Template(t) | ||
fq.add(f) | ||
return | ||
} | ||
|
||
func newTemplate(f File) *template.Template { | ||
return template.New(f.Info().Src).Funcs(newFuncMap(f)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package file | ||
|
||
import l "github.com/Sirupsen/logrus" | ||
|
||
// Queue describes a queue of files ofr the generator workers | ||
type Queue struct { | ||
files []File | ||
queue chan File | ||
} | ||
|
||
// NewFileQueue returns an initialized file.Queue | ||
func NewFileQueue() *Queue { | ||
return &Queue{files: []File{}} | ||
} | ||
|
||
func (fq *Queue) add(f File) { | ||
l.WithField("file", f).Debug("Adding file to queue") | ||
fq.files = append(fq.files, f) | ||
l.WithField("file", f).Debug("File added") | ||
} | ||
|
||
// PopulateQueue feeds parsed files into the underlying channel | ||
func (fq *Queue) PopulateQueue() { | ||
fq.queue = make(chan File, len(fq.files)) | ||
for _, f := range fq.files { | ||
fq.queue <- f | ||
} | ||
close(fq.queue) | ||
} | ||
|
||
// Queue returns the File channel | ||
func (fq *Queue) Queue() chan File { | ||
return fq.queue | ||
} | ||
|
||
// Len returns the length of the queue | ||
func (fq *Queue) Len() int { | ||
return len(fq.queue) | ||
} | ||
|
||
// Files returns the file slice | ||
func (f *Queue) Files() []File { | ||
return f.files | ||
} |
Oops, something went wrong.