2013-09-05 01:28:59 -04:00
|
|
|
package source
|
|
|
|
|
|
|
|
import (
|
2013-12-15 09:49:23 -05:00
|
|
|
"bytes"
|
2013-09-20 20:03:43 -04:00
|
|
|
"errors"
|
2013-09-05 01:28:59 -04:00
|
|
|
"io"
|
2013-12-15 09:49:23 -05:00
|
|
|
"io/ioutil"
|
2013-09-05 01:28:59 -04:00
|
|
|
"os"
|
2013-09-20 20:03:43 -04:00
|
|
|
"path"
|
2013-09-05 01:28:59 -04:00
|
|
|
"path/filepath"
|
2013-11-28 09:27:09 -05:00
|
|
|
"strings"
|
2013-09-05 01:28:59 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
type Input interface {
|
|
|
|
Files() []*File
|
|
|
|
}
|
|
|
|
|
|
|
|
type File struct {
|
2013-09-20 20:03:43 -04:00
|
|
|
name string
|
|
|
|
LogicalName string
|
|
|
|
Contents io.Reader
|
|
|
|
Section string
|
|
|
|
Dir string
|
2013-09-05 01:28:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type Filesystem struct {
|
|
|
|
files []*File
|
|
|
|
Base string
|
|
|
|
AvoidPaths []string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Filesystem) Files() []*File {
|
2013-10-01 17:27:09 -04:00
|
|
|
if len(f.files) < 1 {
|
|
|
|
f.captureFiles()
|
|
|
|
}
|
2013-09-05 01:28:59 -04:00
|
|
|
return f.files
|
|
|
|
}
|
|
|
|
|
2013-09-20 20:03:43 -04:00
|
|
|
var errMissingBaseDir = errors.New("source: missing base directory")
|
|
|
|
|
|
|
|
func (f *Filesystem) add(name string, reader io.Reader) (err error) {
|
|
|
|
|
|
|
|
if name, err = f.getRelativePath(name); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-11-28 09:27:09 -05:00
|
|
|
// section should be the first part of the path
|
2013-09-20 20:03:43 -04:00
|
|
|
dir, logical := path.Split(name)
|
2013-11-28 09:27:09 -05:00
|
|
|
parts := strings.Split(dir, "/")
|
|
|
|
section := parts[0]
|
|
|
|
|
2013-09-20 20:03:43 -04:00
|
|
|
if section == "." {
|
|
|
|
section = ""
|
|
|
|
}
|
|
|
|
|
|
|
|
f.files = append(f.files, &File{
|
|
|
|
name: name,
|
|
|
|
LogicalName: logical,
|
|
|
|
Contents: reader,
|
|
|
|
Section: section,
|
|
|
|
Dir: dir,
|
|
|
|
})
|
2013-11-28 09:27:09 -05:00
|
|
|
|
2013-09-20 20:03:43 -04:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Filesystem) getRelativePath(name string) (final string, err error) {
|
|
|
|
if filepath.IsAbs(name) && f.Base == "" {
|
|
|
|
return "", errMissingBaseDir
|
|
|
|
}
|
|
|
|
name = filepath.Clean(name)
|
|
|
|
base := filepath.Clean(f.Base)
|
|
|
|
|
|
|
|
name, err = filepath.Rel(base, name)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2013-09-12 13:48:59 -04:00
|
|
|
name = filepath.ToSlash(name)
|
2013-09-20 20:03:43 -04:00
|
|
|
return name, nil
|
2013-09-05 01:28:59 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func (f *Filesystem) captureFiles() {
|
|
|
|
|
2013-09-20 20:03:43 -04:00
|
|
|
walker := func(filePath string, fi os.FileInfo, err error) error {
|
2013-09-05 01:28:59 -04:00
|
|
|
if err != nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if fi.IsDir() {
|
2013-09-20 20:03:43 -04:00
|
|
|
if f.avoid(filePath) {
|
2013-09-05 01:28:59 -04:00
|
|
|
return filepath.SkipDir
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
} else {
|
2013-09-20 20:03:43 -04:00
|
|
|
if ignoreDotFile(filePath) {
|
2013-09-05 01:28:59 -04:00
|
|
|
return nil
|
|
|
|
}
|
2013-12-15 09:49:23 -05:00
|
|
|
data, err := ioutil.ReadFile(filePath)
|
2013-09-05 01:28:59 -04:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2013-12-15 09:49:23 -05:00
|
|
|
f.add(filePath, bytes.NewBuffer(data))
|
2013-09-05 01:28:59 -04:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
filepath.Walk(f.Base, walker)
|
|
|
|
}
|
|
|
|
|
2013-09-20 20:03:43 -04:00
|
|
|
func (f *Filesystem) avoid(filePath string) bool {
|
2013-09-05 01:28:59 -04:00
|
|
|
for _, avoid := range f.AvoidPaths {
|
2013-09-20 20:03:43 -04:00
|
|
|
if avoid == filePath {
|
2013-09-05 01:28:59 -04:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2013-09-20 20:03:43 -04:00
|
|
|
func ignoreDotFile(filePath string) bool {
|
|
|
|
return filepath.Base(filePath)[0] == '.'
|
2013-09-05 01:28:59 -04:00
|
|
|
}
|