Skip to content

Commit

Permalink
feat: add filecontent named mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
alecthomas committed Nov 30, 2022
1 parent 9b08b89 commit 919e701
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -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})
}

Expand Down Expand Up @@ -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
}
Expand Down
18 changes: 18 additions & 0 deletions mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit 919e701

Please sign in to comment.