diff options
| author | Dave Henderson <dhenderson@gmail.com> | 2018-02-10 10:13:58 -0500 |
|---|---|---|
| committer | Dave Henderson <dhenderson@gmail.com> | 2018-03-03 10:58:05 -0500 |
| commit | 96ab610f904c48fa4e85bb42e212f49eb3a4ff1c (patch) | |
| tree | 81caae2b83298694798eea978a2e28380e29ef62 | |
| parent | 5f47dac2c1273e189f4b70b74a6dfea68cf788ff (diff) | |
Adding file namespace
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
| -rw-r--r-- | docs/content/functions/file.md | 116 | ||||
| -rw-r--r-- | file/file.go | 45 | ||||
| -rw-r--r-- | file/file_test.go | 43 | ||||
| -rw-r--r-- | funcs.go | 1 | ||||
| -rw-r--r-- | funcs/file.go | 57 | ||||
| -rw-r--r-- | funcs/file_test.go | 32 | ||||
| -rw-r--r-- | test/integration/file_test.go | 30 |
7 files changed, 324 insertions, 0 deletions
diff --git a/docs/content/functions/file.md b/docs/content/functions/file.md new file mode 100644 index 00000000..cff6af2c --- /dev/null +++ b/docs/content/functions/file.md @@ -0,0 +1,116 @@ +--- +title: file functions +menu: + main: + parent: functions +--- + +## `file.Exists` + +Reports whether a file or directory exists at the given path. + +### Usage +```go +file.Exists path +``` + +### Example + +_`input.tmpl`:_ +``` +{{ if (file.Exists "/tmp/foo") }}yes{{else}}no{{end}} +``` + +```console +$ gomplate -f input.tmpl +no +$ touch /tmp/foo +$ gomplate -f input.tmpl +yes +``` + +## `file.IsDir` + +Reports whether a given path is a directory. + +### Usage +```go +file.IsDir path +``` + +### Example + +_`input.tmpl`:_ +``` +{{ if (file.IsDir "/tmp/foo") }}yes{{else}}no{{end}} +``` + +```console +$ gomplate -f input.tmpl +no +$ touch /tmp/foo +$ gomplate -f input.tmpl +no +$ rm /tmp/foo && mkdir /tmp/foo +$ gomplate -f input.tmpl +yes +``` + +## `file.Read` + +Reads a given file _as text_. Note that this will succeed if the given file +is binary, but + +### Usage +```go +file.Read path +``` + +### Examples + +```console +$ echo "hello world" > /tmp/hi +$ gomplate -i '{{file.Read "/tmp/hi"}}' +hello world +``` + +## `file.ReadDir` + +Reads a directory and lists the files and directories contained within. + +### Usage +```go +file.ReadDir path +``` + +### Examples + +```console +$ mkdir /tmp/foo +$ touch /tmp/foo/a; touch /tmp/foo/b; touch /tmp/foo/c +$ mkdir /tmp/foo/d +$ gomplate -i '{{ range (file.ReadDir "/tmp/foo") }}{{.}}{{"\n"}}{{end}}' +a +b +c +d +``` + +## `file.Stat` + +Returns a [`os.FileInfo`](https://golang.org/pkg/os/#FileInfo) describing +the named path. +Essentially a wrapper for Go's [`os.Stat`](https://golang.org/pkg/os/#Stat) function. + +### Usage +```go +file.Stat path +``` + +### Examples + +```console +$ echo "hello world" > /tmp/foo +$ gomplate -i '{{ $s := file.Stat "/tmp/foo" }}{{ $s.Mode }} {{ $s.Size }} {{ $s.Name }}' +-rw-r--r-- 12 foo +``` diff --git a/file/file.go b/file/file.go new file mode 100644 index 00000000..10f58a41 --- /dev/null +++ b/file/file.go @@ -0,0 +1,45 @@ +package file + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + + "github.com/spf13/afero" +) + +// for overriding in tests +var fs = afero.NewOsFs() + +// Read - +func Read(filename string) (string, error) { + inFile, err := fs.OpenFile(filename, os.O_RDONLY, 0) + if err != nil { + return "", fmt.Errorf("failed to open %s\n%v", filename, err) + } + // nolint: errcheck + defer inFile.Close() + bytes, err := ioutil.ReadAll(inFile) + if err != nil { + err = fmt.Errorf("read failed for %s\n%v", filename, err) + return "", err + } + return string(bytes), nil +} + +// ReadDir - +func ReadDir(path string) ([]string, error) { + f, err := fs.Open(path) + if err != nil { + return nil, err + } + i, err := f.Stat() + if err != nil { + return nil, err + } + if i.IsDir() { + return f.Readdirnames(0) + } + return nil, errors.New("file is not a directory") +} diff --git a/file/file_test.go b/file/file_test.go new file mode 100644 index 00000000..97cfa0fb --- /dev/null +++ b/file/file_test.go @@ -0,0 +1,43 @@ +package file + +import ( + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" +) + +func TestRead(t *testing.T) { + origfs := fs + defer func() { fs = origfs }() + fs = afero.NewMemMapFs() + _ = fs.Mkdir("/tmp", 0777) + f, _ := fs.Create("/tmp/foo") + _, _ = f.Write([]byte("foo")) + + actual, err := Read("/tmp/foo") + assert.NoError(t, err) + assert.Equal(t, "foo", actual) + + actual, err = Read("/tmp/bar") + assert.Error(t, err) +} + +func TestReadDir(t *testing.T) { + origfs := fs + defer func() { fs = origfs }() + fs = afero.NewMemMapFs() + fs.Mkdir("/tmp", 0777) + fs.Create("/tmp/foo") + fs.Create("/tmp/bar") + fs.Create("/tmp/baz") + fs.Mkdir("/tmp/qux", 0777) + fs.Create("/tmp/qux/quux") + + actual, err := ReadDir("/tmp") + assert.NoError(t, err) + assert.Equal(t, []string{"bar", "baz", "foo", "qux"}, actual) + + _, err = ReadDir("/tmp/foo") + assert.Error(t, err) +} @@ -21,5 +21,6 @@ func initFuncs(d *data.Data) template.FuncMap { funcs.AddTimeFuncs(f) funcs.AddMathFuncs(f) funcs.AddCryptoFuncs(f) + funcs.AddFileFuncs(f) return f } diff --git a/funcs/file.go b/funcs/file.go new file mode 100644 index 00000000..1f1a30bd --- /dev/null +++ b/funcs/file.go @@ -0,0 +1,57 @@ +package funcs + +import ( + "os" + "sync" + + "github.com/hairyhenderson/gomplate/file" + "github.com/spf13/afero" +) + +var ( + ff *FileFuncs + ffInit sync.Once +) + +// FileNS - the File namespace +func FileNS() *FileFuncs { + ffInit.Do(func() { ff = &FileFuncs{afero.NewOsFs()} }) + return ff +} + +// AddFileFuncs - +func AddFileFuncs(f map[string]interface{}) { + f["file"] = FileNS +} + +// FileFuncs - +type FileFuncs struct { + fs afero.Fs +} + +// Read - +func (f *FileFuncs) Read(path string) (string, error) { + return file.Read(path) +} + +// Stat - +func (f *FileFuncs) Stat(path string) (os.FileInfo, error) { + return f.fs.Stat(path) +} + +// Exists - +func (f *FileFuncs) Exists(path string) bool { + _, err := f.Stat(path) + return err == nil +} + +// IsDir - +func (f *FileFuncs) IsDir(path string) bool { + i, err := f.Stat(path) + return err == nil && i.IsDir() +} + +// ReadDir - +func (f *FileFuncs) ReadDir(path string) ([]string, error) { + return file.ReadDir(path) +} diff --git a/funcs/file_test.go b/funcs/file_test.go new file mode 100644 index 00000000..2a3ce9a9 --- /dev/null +++ b/funcs/file_test.go @@ -0,0 +1,32 @@ +package funcs + +import ( + "testing" + + "github.com/spf13/afero" + "github.com/stretchr/testify/assert" +) + +func TestFileExists(t *testing.T) { + fs := afero.NewMemMapFs() + ff := &FileFuncs{fs} + + _ = fs.Mkdir("/tmp", 0777) + f, _ := fs.Create("/tmp/foo") + _, _ = f.Write([]byte("foo")) + + assert.True(t, ff.Exists("/tmp/foo")) + assert.False(t, ff.Exists("/tmp/bar")) +} + +func TestFileIsDir(t *testing.T) { + fs := afero.NewMemMapFs() + ff := &FileFuncs{fs} + + _ = fs.Mkdir("/tmp", 0777) + f, _ := fs.Create("/tmp/foo") + _, _ = f.Write([]byte("foo")) + + assert.True(t, ff.IsDir("/tmp")) + assert.False(t, ff.IsDir("/tmp/foo")) +} diff --git a/test/integration/file_test.go b/test/integration/file_test.go new file mode 100644 index 00000000..4d3fed22 --- /dev/null +++ b/test/integration/file_test.go @@ -0,0 +1,30 @@ +//+build !xxintegration +//+build !windows + +package integration + +import ( + . "gopkg.in/check.v1" + + "github.com/gotestyourself/gotestyourself/fs" +) + +type FileSuite struct { + tmpDir *fs.Dir +} + +var _ = Suite(&FileSuite{}) + +func (s *FileSuite) SetUpSuite(c *C) { + s.tmpDir = fs.NewDir(c, "gomplate-inttests", + fs.WithFile("one", "hi\n"), + fs.WithFile("two", "hello\n")) +} + +func (s *FileSuite) TearDownSuite(c *C) { + s.tmpDir.Remove() +} + +func (s *FileSuite) TestReadsFile(c *C) { + inOutTest(c, `{{ file.Read "`+s.tmpDir.Join("one")+`"}}`, "hi") +} |
