feat: add filecontent named mapper
This commit is contained in:
@@ -485,6 +485,7 @@ function `NamedMapper(name, mapper)`.
|
||||
| `existingfile` | An existing file. ~ expansion is applied. `-` is accepted for stdin, and will be passed unaltered. |
|
||||
| `existingdir` | An existing directory. ~ expansion is applied. |
|
||||
| `counter` | Increment a numeric field. Useful for `-vvv`. Can accept `-s`, `--long` or `--long=N`. |
|
||||
| `filecontent` | Read the file at path into the field. ~ expansion is applied. `-` is accepted for stdin, and will be passed unaltered. |
|
||||
|
||||
|
||||
Slices and maps treat type tags specially. For slices, the `type:""` tag
|
||||
|
||||
@@ -283,6 +283,7 @@ func (r *Registry) RegisterDefaults() *Registry {
|
||||
RegisterName("existingfile", existingFileMapper(r)).
|
||||
RegisterName("existingdir", existingDirMapper(r)).
|
||||
RegisterName("counter", counterMapper()).
|
||||
RegisterName("filecontent", fileContentMapper(r)).
|
||||
RegisterKind(reflect.Ptr, ptrMapper{r})
|
||||
}
|
||||
|
||||
@@ -684,6 +685,39 @@ func existingDirMapper(r *Registry) MapperFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func fileContentMapper(r *Registry) MapperFunc {
|
||||
return func(ctx *DecodeContext, target reflect.Value) error {
|
||||
if target.Kind() != reflect.Slice && target.Elem().Kind() != reflect.Uint8 {
|
||||
return fmt.Errorf("\"filecontent\" must be applied to []byte not %s", target.Type())
|
||||
}
|
||||
var path string
|
||||
err := ctx.Scan.PopValueInto("file", &path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ctx.Value.Active || ctx.Value.Set {
|
||||
// early return to avoid checking extra dirs that may not exist;
|
||||
// this hack only works because the value provided on the cli is
|
||||
// checked before the default value is checked (if default is set).
|
||||
return nil
|
||||
}
|
||||
|
||||
var data []byte
|
||||
if path != "-" {
|
||||
path = ExpandPath(path)
|
||||
data, err = ioutil.ReadFile(path) //nolint:gosec
|
||||
} else {
|
||||
data, err = ioutil.ReadAll(os.Stdin)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
target.SetBytes(data)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
type ptrMapper struct {
|
||||
r *Registry
|
||||
}
|
||||
|
||||
@@ -469,6 +469,24 @@ func TestFileMapper(t *testing.T) {
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, os.Stdin, cli.File)
|
||||
}
|
||||
func TestFileContentMapper(t *testing.T) {
|
||||
type CLI struct {
|
||||
File []byte `type:"filecontent"`
|
||||
}
|
||||
var cli CLI
|
||||
p := mustNew(t, &cli)
|
||||
_, err := p.Parse([]string{"--file", "testdata/file.txt"})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, []byte(`Hello world.`), cli.File)
|
||||
p = mustNew(t, &cli)
|
||||
_, err = p.Parse([]string{"--file", "testdata/missing.txt"})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "missing.txt: no such file or directory")
|
||||
p = mustNew(t, &cli)
|
||||
_, err = p.Parse([]string{"--file", "testdata/"})
|
||||
assert.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "is a directory")
|
||||
}
|
||||
|
||||
//nolint:dupl
|
||||
func TestExistingFileMapper(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user