feat: add filecontent named mapper

This commit is contained in:
Alec Thomas
2022-11-30 22:27:36 +11:00
parent 9b08b89396
commit 919e70103f
3 changed files with 53 additions and 0 deletions
+1
View File
@@ -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
+34
View File
@@ -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
}
+18
View File
@@ -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) {