summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Henderson <dhenderson@gmail.com>2018-08-09 16:52:21 -0400
committerDave Henderson <dhenderson@gmail.com>2018-08-10 22:11:46 -0400
commit22ae7244297c3b63cfb8f44e3a9be52286e629df (patch)
treef3b643830254378c0c75e9bf2d0760f93b672720
parentfbb3f3f9dde228494b8d91698d7e11b749d2b88e (diff)
Adding --chmod flag to explicitly set output file modes
Signed-off-by: Dave Henderson <dhenderson@gmail.com>
-rw-r--r--cmd/gomplate/main.go13
-rw-r--r--docs/content/usage.md6
-rw-r--r--gomplate.go13
-rw-r--r--template.go68
-rw-r--r--template_test.go120
-rw-r--r--tests/integration/basic_test.go92
-rw-r--r--tests/integration/inputdir_test.go53
7 files changed, 318 insertions, 47 deletions
diff --git a/cmd/gomplate/main.go b/cmd/gomplate/main.go
index bde6eb46..c0ba8909 100644
--- a/cmd/gomplate/main.go
+++ b/cmd/gomplate/main.go
@@ -93,22 +93,27 @@ func newGomplateCmd() *cobra.Command {
}
func initFlags(command *cobra.Command) {
- command.Flags().BoolVarP(&printVer, "version", "v", false, "print the version")
+ command.Flags().SortFlags = false
+
+ command.Flags().StringArrayVarP(&opts.DataSources, "datasource", "d", nil, "`datasource` in alias=URL form. Specify multiple times to add multiple sources.")
+ command.Flags().StringArrayVarP(&opts.DataSourceHeaders, "datasource-header", "H", nil, "HTTP `header` field in 'alias=Name: value' form to be provided on HTTP-based data sources. Multiples can be set.")
command.Flags().StringArrayVarP(&opts.InputFiles, "file", "f", []string{"-"}, "Template `file` to process. Omit to use standard input, or use --in or --input-dir")
command.Flags().StringVarP(&opts.Input, "in", "i", "", "Template `string` to process (alternative to --file and --input-dir)")
command.Flags().StringVar(&opts.InputDir, "input-dir", "", "`directory` which is examined recursively for templates (alternative to --file and --in)")
+
command.Flags().StringArrayVar(&opts.ExcludeGlob, "exclude", []string{}, "glob of files to not parse")
+
command.Flags().StringArrayVarP(&opts.OutputFiles, "out", "o", []string{"-"}, "output `file` name. Omit to use standard output.")
command.Flags().StringVar(&opts.OutputDir, "output-dir", ".", "`directory` to store the processed templates. Only used for --input-dir")
-
- command.Flags().StringArrayVarP(&opts.DataSources, "datasource", "d", nil, "`datasource` in alias=URL form. Specify multiple times to add multiple sources.")
- command.Flags().StringArrayVarP(&opts.DataSourceHeaders, "datasource-header", "H", nil, "HTTP `header` field in 'alias=Name: value' form to be provided on HTTP-based data sources. Multiples can be set.")
+ command.Flags().StringVar(&opts.OutMode, "chmod", "", "set the mode for output file(s). Omit to inherit from input file(s)")
ldDefault := env.Getenv("GOMPLATE_LEFT_DELIM", "{{")
rdDefault := env.Getenv("GOMPLATE_RIGHT_DELIM", "}}")
command.Flags().StringVar(&opts.LDelim, "left-delim", ldDefault, "override the default left-`delimiter` [$GOMPLATE_LEFT_DELIM]")
command.Flags().StringVar(&opts.RDelim, "right-delim", rdDefault, "override the default right-`delimiter` [$GOMPLATE_RIGHT_DELIM]")
+
+ command.Flags().BoolVarP(&printVer, "version", "v", false, "print the version")
}
func main() {
diff --git a/docs/content/usage.md b/docs/content/usage.md
index ee203c08..4631a923 100644
--- a/docs/content/usage.md
+++ b/docs/content/usage.md
@@ -43,6 +43,12 @@ Example:
gomplate --input-dir=templates --output-dir=config --datasource config=config.yaml
```
+### `--chmod`
+
+By default, output files are created with the same file mode (permissions) as input files. If desired, the `--chmod` option can be used to override this behaviour, and set the output file mode explicitly. This can be useful for creating executable scripts or ensuring write permissions.
+
+The value must be an octal integer in the standard UNIX `chmod` format, i.e. `644` to indicate that owner gets read+write, group gets read-only, and others get read-only permissions. See the [`chmod(1)` man page](https://linux.die.net/man/1/chmod) for more details.
+
### `--exclude`
To prevent certain files from being processed, you can use `--exclude`. It takes a glob, and any files matching that glob will not be included.
diff --git a/gomplate.go b/gomplate.go
index f5d17af9..11a8ae8f 100644
--- a/gomplate.go
+++ b/gomplate.go
@@ -3,6 +3,7 @@ package gomplate
import (
"io"
"os"
+ "strconv"
"text/template"
"time"
@@ -18,6 +19,7 @@ type Config struct {
ExcludeGlob []string
OutputFiles []string
OutputDir string
+ OutMode string
DataSources []string
DataSourceHeaders []string
@@ -26,6 +28,17 @@ type Config struct {
RDelim string
}
+// parse an os.FileMode out of the string, and let us know if it's an override or not...
+func (o *Config) getMode() (os.FileMode, bool, error) {
+ modeOverride := o.OutMode != ""
+ m, err := strconv.ParseUint("0"+o.OutMode, 8, 32)
+ if err != nil {
+ return 0, false, err
+ }
+ mode := os.FileMode(m)
+ return mode, modeOverride, nil
+}
+
// gomplate -
type gomplate struct {
funcMap template.FuncMap
diff --git a/template.go b/template.go
index dcb2c8b1..496ee907 100644
--- a/template.go
+++ b/template.go
@@ -20,11 +20,12 @@ var Stdout io.WriteCloser = os.Stdout
// tplate - models a gomplate template file...
type tplate struct {
- name string
- targetPath string
- target io.Writer
- contents string
- mode os.FileMode
+ name string
+ targetPath string
+ target io.Writer
+ contents string
+ mode os.FileMode
+ modeOverride bool
}
func (t *tplate) toGoTemplate(g *gomplate) (*template.Template, error) {
@@ -48,19 +49,25 @@ func (t *tplate) addTarget() (err error) {
t.targetPath = "-"
}
if t.target == nil {
- t.target, err = openOutFile(t.targetPath, t.mode)
+ t.target, err = openOutFile(t.targetPath, t.mode, t.modeOverride)
}
return err
}
// gatherTemplates - gather and prepare input template(s) and output file(s) for rendering
func gatherTemplates(o *Config) (templates []*tplate, err error) {
+ mode, modeOverride, err := o.getMode()
+
// the arg-provided input string gets a special name
if o.Input != "" {
+ if mode == 0 {
+ mode = 0644
+ }
templates = []*tplate{{
- name: "<arg>",
- contents: o.Input,
- mode: os.FileMode(0644),
+ name: "<arg>",
+ contents: o.Input,
+ mode: mode,
+ modeOverride: modeOverride,
}}
if len(o.OutputFiles) == 1 {
@@ -70,14 +77,14 @@ func gatherTemplates(o *Config) (templates []*tplate, err error) {
// input dirs presume output dirs are set too
if o.InputDir != "" {
- templates, err = walkDir(o.InputDir, o.OutputDir, o.ExcludeGlob)
+ templates, err = walkDir(o.InputDir, o.OutputDir, o.ExcludeGlob, mode, modeOverride)
if err != nil {
return nil, err
}
} else if len(o.InputFiles) > 0 && o.Input == "" {
templates = make([]*tplate, len(o.InputFiles))
for i := range o.InputFiles {
- templates[i], err = fileToTemplates(o.InputFiles[i], o.OutputFiles[i])
+ templates[i], err = fileToTemplates(o.InputFiles[i], o.OutputFiles[i], mode, modeOverride)
if err != nil {
return nil, err
}
@@ -104,7 +111,7 @@ func processTemplates(templates []*tplate) ([]*tplate, error) {
// walkDir - given an input dir `dir` and an output dir `outDir`, and a list
// of exclude globs (if any), walk the input directory and create a list of
// tplate objects, and an error, if any.
-func walkDir(dir, outDir string, excludeGlob []string) ([]*tplate, error) {
+func walkDir(dir, outDir string, excludeGlob []string, mode os.FileMode, modeOverride bool) ([]*tplate, error) {
dir = filepath.Clean(dir)
outDir = filepath.Clean(outDir)
si, err := fs.Stat(dir)
@@ -136,35 +143,41 @@ func walkDir(dir, outDir string, excludeGlob []string) ([]*tplate, error) {
}
if entry.IsDir() {
- t, err := walkDir(nextInPath, nextOutPath, excludes)
+ t, err := walkDir(nextInPath, nextOutPath, excludes, mode, modeOverride)
if err != nil {
return nil, err
}
templates = append(templates, t...)
} else {
+ if mode == 0 {
+ mode = entry.Mode()
+ }
templates = append(templates, &tplate{
- name: nextInPath,
- targetPath: nextOutPath,
- mode: entry.Mode(),
+ name: nextInPath,
+ targetPath: nextOutPath,
+ mode: mode,
+ modeOverride: modeOverride,
})
}
}
return templates, nil
}
-func fileToTemplates(inFile, outFile string) (*tplate, error) {
- mode := os.FileMode(0644)
+func fileToTemplates(inFile, outFile string, mode os.FileMode, modeOverride bool) (*tplate, error) {
if inFile != "-" {
si, err := fs.Stat(inFile)
if err != nil {
return nil, err
}
- mode = si.Mode()
+ if mode == 0 {
+ mode = si.Mode()
+ }
}
tmpl := &tplate{
- name: inFile,
- targetPath: outFile,
- mode: mode,
+ name: inFile,
+ targetPath: outFile,
+ mode: mode,
+ modeOverride: modeOverride,
}
return tmpl, nil
@@ -180,11 +193,18 @@ func inList(list []string, entry string) bool {
return false
}
-func openOutFile(filename string, mode os.FileMode) (out io.WriteCloser, err error) {
+func openOutFile(filename string, mode os.FileMode, modeOverride bool) (out io.WriteCloser, err error) {
if filename == "-" {
return Stdout, nil
}
- return fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm())
+ out, err = fs.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_TRUNC, mode.Perm())
+ if err != nil {
+ return out, err
+ }
+ if modeOverride {
+ err = fs.Chmod(filename, mode.Perm())
+ }
+ return out, err
}
func readInput(filename string) (string, error) {
diff --git a/template_test.go b/template_test.go
index 721ba4a5..190fb35f 100644
--- a/template_test.go
+++ b/template_test.go
@@ -4,6 +4,7 @@ package gomplate
import (
"bytes"
+ "io"
"io/ioutil"
"os"
"testing"
@@ -45,7 +46,7 @@ func TestOpenOutFile(t *testing.T) {
fs = afero.NewMemMapFs()
_ = fs.Mkdir("/tmp", 0777)
- _, err := openOutFile("/tmp/foo", os.FileMode(0644))
+ _, err := openOutFile("/tmp/foo", 0644, false)
assert.NoError(t, err)
i, err := fs.Stat("/tmp/foo")
assert.NoError(t, err)
@@ -54,7 +55,7 @@ func TestOpenOutFile(t *testing.T) {
defer func() { Stdout = os.Stdout }()
Stdout = &nopWCloser{&bytes.Buffer{}}
- f, err := openOutFile("-", os.FileMode(0644))
+ f, err := openOutFile("-", 0644, false)
assert.NoError(t, err)
assert.Equal(t, Stdout, f)
}
@@ -94,7 +95,7 @@ func TestWalkDir(t *testing.T) {
defer func() { fs = origfs }()
fs = afero.NewMemMapFs()
- _, err := walkDir("/indir", "/outdir", nil)
+ _, err := walkDir("/indir", "/outdir", nil, 0, false)
assert.Error(t, err)
_ = fs.MkdirAll("/indir/one", 0777)
@@ -103,7 +104,7 @@ func TestWalkDir(t *testing.T) {
afero.WriteFile(fs, "/indir/one/bar", []byte("bar"), 0644)
afero.WriteFile(fs, "/indir/two/baz", []byte("baz"), 0644)
- templates, err := walkDir("/indir", "/outdir", []string{"/*/two"})
+ templates, err := walkDir("/indir", "/outdir", []string{"/*/two"}, 0, false)
assert.NoError(t, err)
assert.Equal(t, 2, len(templates))
@@ -141,7 +142,7 @@ func TestGatherTemplates(t *testing.T) {
origfs := fs
defer func() { fs = origfs }()
fs = afero.NewMemMapFs()
- afero.WriteFile(fs, "foo", []byte("bar"), 0644)
+ afero.WriteFile(fs, "foo", []byte("bar"), 0600)
afero.WriteFile(fs, "in/1", []byte("foo"), 0644)
afero.WriteFile(fs, "in/2", []byte("bar"), 0644)
@@ -167,6 +168,10 @@ func TestGatherTemplates(t *testing.T) {
assert.Len(t, templates, 1)
assert.Equal(t, "out", templates[0].targetPath)
assert.Equal(t, os.FileMode(0644), templates[0].mode)
+ info, err := fs.Stat("out")
+ assert.NoError(t, err)
+ assert.Equal(t, os.FileMode(0644), info.Mode())
+ fs.Remove("out")
templates, err = gatherTemplates(&Config{
InputFiles: []string{"foo"},
@@ -176,6 +181,26 @@ func TestGatherTemplates(t *testing.T) {
assert.Len(t, templates, 1)
assert.Equal(t, "bar", templates[0].contents)
assert.NotEqual(t, Stdout, templates[0].target)
+ assert.Equal(t, os.FileMode(0600), templates[0].mode)
+ info, err = fs.Stat("out")
+ assert.NoError(t, err)
+ assert.Equal(t, os.FileMode(0600), info.Mode())
+ fs.Remove("out")
+
+ templates, err = gatherTemplates(&Config{
+ InputFiles: []string{"foo"},
+ OutputFiles: []string{"out"},
+ OutMode: "755",
+ })
+ assert.NoError(t, err)
+ assert.Len(t, templates, 1)
+ assert.Equal(t, "bar", templates[0].contents)
+ assert.NotEqual(t, Stdout, templates[0].target)
+ assert.Equal(t, os.FileMode(0755), templates[0].mode)
+ info, err = fs.Stat("out")
+ assert.NoError(t, err)
+ assert.Equal(t, os.FileMode(0755), info.Mode())
+ fs.Remove("out")
templates, err = gatherTemplates(&Config{
InputDir: "in",
@@ -184,4 +209,89 @@ func TestGatherTemplates(t *testing.T) {
assert.NoError(t, err)
assert.Len(t, templates, 3)
assert.Equal(t, "foo", templates[0].contents)
+ fs.Remove("out")
+}
+
+func TestProcessTemplates(t *testing.T) {
+ origfs := fs
+ defer func() { fs = origfs }()
+ fs = afero.NewMemMapFs()
+ afero.WriteFile(fs, "foo", []byte("bar"), 0600)
+
+ afero.WriteFile(fs, "in/1", []byte("foo"), 0644)
+ afero.WriteFile(fs, "in/2", []byte("bar"), 0640)
+ afero.WriteFile(fs, "in/3", []byte("baz"), 0644)
+
+ afero.WriteFile(fs, "existing", []byte(""), 0644)
+
+ testdata := []struct {
+ templates []*tplate
+ contents []string
+ modes []os.FileMode
+ targets []io.WriteCloser
+ }{
+ {},
+ {
+ templates: []*tplate{{name: "<arg>", contents: "foo", targetPath: "-", mode: 0644}},
+ contents: []string{"foo"},
+ modes: []os.FileMode{0644},
+ targets: []io.WriteCloser{Stdout},
+ },
+ {
+ templates: []*tplate{{name: "<arg>", contents: "foo", targetPath: "out", mode: 0644}},
+ contents: []string{"foo"},
+ modes: []os.FileMode{0644},
+ },
+ {
+ templates: []*tplate{{name: "foo", targetPath: "out", mode: 0600}},
+ contents: []string{"bar"},
+ modes: []os.FileMode{0600},
+ },
+ {
+ templates: []*tplate{{name: "foo", targetPath: "out", mode: 0755}},
+ contents: []string{"bar"},
+ modes: []os.FileMode{0755},
+ },
+ {
+ templates: []*tplate{
+ {name: "in/1", targetPath: "out/1", mode: 0644},
+ {name: "in/2", targetPath: "out/2", mode: 0640},
+ {name: "in/3", targetPath: "out/3", mode: 0644},
+ },
+ contents: []string{"foo", "bar", "baz"},
+ modes: []os.FileMode{0644, 0640, 0644},
+ },
+ {
+ templates: []*tplate{
+ {name: "foo", targetPath: "existing", mode: 0755},
+ },
+ contents: []string{"bar"},
+ modes: []os.FileMode{0644},
+ },
+ {
+ templates: []*tplate{
+ {name: "foo", targetPath: "existing", mode: 0755, modeOverride: true},
+ },
+ contents: []string{"bar"},
+ modes: []os.FileMode{0755},
+ },
+ }
+ for _, in := range testdata {
+ actual, err := processTemplates(in.templates)
+ assert.NoError(t, err)
+ assert.Len(t, actual, len(in.templates))
+ for i, a := range actual {
+ assert.Equal(t, in.contents[i], a.contents)
+ assert.Equal(t, in.templates[i].mode, a.mode)
+ if len(in.targets) > 0 {
+ assert.Equal(t, in.targets[i], a.target)
+ }
+ if in.templates[i].targetPath != "-" {
+ info, err := fs.Stat(in.templates[i].targetPath)
+ assert.NoError(t, err)
+ assert.Equal(t, os.FileMode(in.modes[i]), info.Mode())
+ }
+ }
+ fs.Remove("out")
+ }
}
diff --git a/tests/integration/basic_test.go b/tests/integration/basic_test.go
index de890905..349efe04 100644
--- a/tests/integration/basic_test.go
+++ b/tests/integration/basic_test.go
@@ -1,11 +1,13 @@
-// +build integration
+//+build integration
//+build !windows
package integration
import (
"bytes"
+ "fmt"
"io/ioutil"
+ "os"
. "gopkg.in/check.v1"
@@ -21,13 +23,13 @@ type BasicSuite struct {
var _ = Suite(&BasicSuite{})
-func (s *BasicSuite) SetUpSuite(c *C) {
+func (s *BasicSuite) SetUpTest(c *C) {
s.tmpDir = fs.NewDir(c, "gomplate-inttests",
- fs.WithFile("one", "hi\n"),
+ fs.WithFile("one", "hi\n", fs.WithMode(0640)),
fs.WithFile("two", "hello\n"))
}
-func (s *BasicSuite) TearDownSuite(c *C) {
+func (s *BasicSuite) TearDownTest(c *C) {
s.tmpDir.Remove()
}
@@ -89,12 +91,82 @@ func (s *BasicSuite) TestRoutesInputsToProperOutputs(c *C) {
})
result.Assert(c, icmd.Success)
- content, err := ioutil.ReadFile(oneOut)
- assert.NilError(c, err)
- assert.Equal(c, "hi\n", string(content))
- content, err = ioutil.ReadFile(twoOut)
- assert.NilError(c, err)
- assert.Equal(c, "hello\n", string(content))
+ testdata := []struct {
+ path string
+ mode os.FileMode
+ content string
+ }{
+ {oneOut, 0640, "hi\n"},
+ {twoOut, 0644, "hello\n"},
+ }
+ for _, v := range testdata {
+ info, err := os.Stat(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.mode, info.Mode())
+ content, err := ioutil.ReadFile(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.content, string(content))
+ }
+}
+
+func (s *BasicSuite) TestRoutesInputsToProperOutputsWithChmod(c *C) {
+ oneOut := s.tmpDir.Join("one.out")
+ twoOut := s.tmpDir.Join("two.out")
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-f", s.tmpDir.Join("one"),
+ "-f", s.tmpDir.Join("two"),
+ "-o", oneOut,
+ "-o", twoOut,
+ "--chmod", "0600"), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Success)
+ fmt.Println(result.Combined())
+
+ testdata := []struct {
+ path string
+ mode os.FileMode
+ content string
+ }{
+ {oneOut, 0600, "hi\n"},
+ {twoOut, 0600, "hello\n"},
+ }
+ for _, v := range testdata {
+ info, err := os.Stat(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.mode, info.Mode())
+ content, err := ioutil.ReadFile(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.content, string(content))
+ }
+}
+
+func (s *BasicSuite) TestOverridesOutputModeWithChmod(c *C) {
+ out := s.tmpDir.Join("two")
+ result := icmd.RunCmd(icmd.Command(GomplateBin,
+ "-f", s.tmpDir.Join("one"),
+ "-o", out,
+ "--chmod", "0600"), func(cmd *icmd.Cmd) {
+ cmd.Stdin = bytes.NewBufferString("hello world")
+ })
+ result.Assert(c, icmd.Success)
+ fmt.Println(result.Combined())
+
+ testdata := []struct {
+ path string
+ mode os.FileMode
+ content string
+ }{
+ {out, 0600, "hi\n"},
+ }
+ for _, v := range testdata {
+ info, err := os.Stat(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.mode, info.Mode())
+ content, err := ioutil.ReadFile(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.content, string(content))
+ }
}
func (s *BasicSuite) TestFlagRules(c *C) {
diff --git a/tests/integration/inputdir_test.go b/tests/integration/inputdir_test.go
index 2230e5a1..d1125c53 100644
--- a/tests/integration/inputdir_test.go
+++ b/tests/integration/inputdir_test.go
@@ -5,6 +5,7 @@ package integration
import (
"io/ioutil"
+ "os"
. "gopkg.in/check.v1"
@@ -56,13 +57,57 @@ func (s *InputDirSuite) TestInputDir(c *C) {
assert.NilError(c, err)
tassert.Len(c, files, 1)
- content, err := ioutil.ReadFile(s.tmpDir.Join("out", "eins.txt"))
+ testdata := []struct {
+ path string
+ mode os.FileMode
+ content string
+ }{
+ {s.tmpDir.Join("out", "eins.txt"), 0644, "eins"},
+ {s.tmpDir.Join("out", "inner", "deux.txt"), 0644, "deux"},
+ }
+ for _, v := range testdata {
+ info, err := os.Stat(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.mode, info.Mode())
+ content, err := ioutil.ReadFile(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.content, string(content))
+ }
+}
+
+func (s *InputDirSuite) TestInputDirWithModeOverride(c *C) {
+ result := icmd.RunCommand(GomplateBin,
+ "--input-dir", s.tmpDir.Join("in"),
+ "--output-dir", s.tmpDir.Join("out"),
+ "--chmod", "0601",
+ "-d", "config="+s.tmpDir.Join("config.yml"),
+ )
+ result.Assert(c, icmd.Success)
+
+ files, err := ioutil.ReadDir(s.tmpDir.Join("out"))
assert.NilError(c, err)
- assert.Equal(c, "eins", string(content))
+ tassert.Len(c, files, 2)
- content, err = ioutil.ReadFile(s.tmpDir.Join("out", "inner", "deux.txt"))
+ files, err = ioutil.ReadDir(s.tmpDir.Join("out", "inner"))
assert.NilError(c, err)
- assert.Equal(c, "deux", string(content))
+ tassert.Len(c, files, 1)
+
+ testdata := []struct {
+ path string
+ mode os.FileMode
+ content string
+ }{
+ {s.tmpDir.Join("out", "eins.txt"), 0601, "eins"},
+ {s.tmpDir.Join("out", "inner", "deux.txt"), 0601, "deux"},
+ }
+ for _, v := range testdata {
+ info, err := os.Stat(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.mode, info.Mode())
+ content, err := ioutil.ReadFile(v.path)
+ assert.NilError(c, err)
+ assert.Equal(c, v.content, string(content))
+ }
}
func (s *InputDirSuite) TestDefaultOutputDir(c *C) {