mirror of
https://github.com/mikefarah/yq.git
synced 2024-11-13 22:38:04 +00:00
feat: add prefix command
This commit is contained in:
parent
d7040e3933
commit
48dcc15281
174
commands_test.go
174
commands_test.go
@ -341,6 +341,180 @@ func TestReadCmd_ToJsonLong(t *testing.T) {
|
|||||||
assertResult(t, "2\n", result.Output)
|
assertResult(t, "2\n", result.Output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix %s d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `d:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
assertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_MultiLayer(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix %s d.e.f", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `d:
|
||||||
|
e:
|
||||||
|
f:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
assertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixMultiCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix %s -d 1 d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
d:
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
assertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
func TestPrefixInvalidDocumentIndexCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix %s -df d", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to invalid path")
|
||||||
|
}
|
||||||
|
expectedOutput := `Document index f is not a integer or *: strconv.ParseInt: parsing "f": invalid syntax`
|
||||||
|
assertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixBadDocumentIndexCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix %s -d 1 d", filename))
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to invalid path")
|
||||||
|
}
|
||||||
|
expectedOutput := `Asked to process document index 1 but there are only 1 document(s)`
|
||||||
|
assertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
func TestPrefixMultiAllCmd(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
apples: great
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix %s -d * d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `d:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
---
|
||||||
|
d:
|
||||||
|
apples: great`
|
||||||
|
assertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_Error(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, "prefix")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to missing arg")
|
||||||
|
}
|
||||||
|
expectedOutput := `Must provide <filename> <prefixed_path>`
|
||||||
|
assertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_ErrorUnreadableFile(t *testing.T) {
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, "prefix fake-unknown a.b")
|
||||||
|
if result.Error == nil {
|
||||||
|
t.Error("Expected command to fail due to unknown file")
|
||||||
|
}
|
||||||
|
expectedOutput := `open fake-unknown: no such file or directory`
|
||||||
|
assertResult(t, expectedOutput, result.Error.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_Verbose(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("-v prefix %s x", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
expectedOutput := `x:
|
||||||
|
b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
assertResult(t, expectedOutput, result.Output)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPrefixCmd_Inplace(t *testing.T) {
|
||||||
|
content := `b:
|
||||||
|
c: 3
|
||||||
|
`
|
||||||
|
filename := writeTempYamlFile(content)
|
||||||
|
defer removeTempYamlFile(filename)
|
||||||
|
|
||||||
|
cmd := getRootCommand()
|
||||||
|
result := runCmd(cmd, fmt.Sprintf("prefix -i %s d", filename))
|
||||||
|
if result.Error != nil {
|
||||||
|
t.Error(result.Error)
|
||||||
|
}
|
||||||
|
gotOutput := readTempYamlFile(filename)
|
||||||
|
expectedOutput := `d:
|
||||||
|
b:
|
||||||
|
c: 3`
|
||||||
|
assertResult(t, expectedOutput, strings.Trim(gotOutput, "\n "))
|
||||||
|
}
|
||||||
|
|
||||||
func TestNewCmd(t *testing.T) {
|
func TestNewCmd(t *testing.T) {
|
||||||
cmd := getRootCommand()
|
cmd := getRootCommand()
|
||||||
result := runCmd(cmd, "new b.c 3")
|
result := runCmd(cmd, "new b.c 3")
|
||||||
|
96
mkdocs/prefix.md
Normal file
96
mkdocs/prefix.md
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
Paths can be prefixed using the 'prefix' command.
|
||||||
|
The complete yaml content will be nested inside the new prefix path.
|
||||||
|
|
||||||
|
```
|
||||||
|
yq p <yaml_file> <path>
|
||||||
|
```
|
||||||
|
|
||||||
|
### To Stdout
|
||||||
|
Given a data1.yaml file of:
|
||||||
|
```yaml
|
||||||
|
a: simple
|
||||||
|
b: [1, 2]
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq p data1.yaml c
|
||||||
|
```
|
||||||
|
will output:
|
||||||
|
```yaml
|
||||||
|
c:
|
||||||
|
a: simple
|
||||||
|
b: [1, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Arbitrary depth
|
||||||
|
Given a data1.yaml file of:
|
||||||
|
```yaml
|
||||||
|
a:
|
||||||
|
b: [1, 2]
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq p data1.yaml c.d
|
||||||
|
```
|
||||||
|
will output:
|
||||||
|
```yaml
|
||||||
|
c:
|
||||||
|
d:
|
||||||
|
a:
|
||||||
|
b: [1, 2]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating files in-place
|
||||||
|
Given a data1.yaml file of:
|
||||||
|
```yaml
|
||||||
|
a: simple
|
||||||
|
b: [1, 2]
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq p -i data1.yaml c
|
||||||
|
```
|
||||||
|
will update the data1.yaml file so that the path 'c' is prefixed to all other paths.
|
||||||
|
|
||||||
|
### Multiple Documents - update a single document
|
||||||
|
Given a data1.yaml file of:
|
||||||
|
```yaml
|
||||||
|
something: else
|
||||||
|
---
|
||||||
|
a: simple
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq p -d1 data1.yaml c
|
||||||
|
```
|
||||||
|
will output:
|
||||||
|
```yaml
|
||||||
|
something: else
|
||||||
|
---
|
||||||
|
c:
|
||||||
|
a: simple
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
|
||||||
|
### Multiple Documents - update a single document
|
||||||
|
Given a data1.yaml file of:
|
||||||
|
```yaml
|
||||||
|
something: else
|
||||||
|
---
|
||||||
|
a: simple
|
||||||
|
b: cat
|
||||||
|
```
|
||||||
|
then
|
||||||
|
```bash
|
||||||
|
yq p -d'*' data1.yaml c
|
||||||
|
```
|
||||||
|
will output:
|
||||||
|
```yaml
|
||||||
|
c:
|
||||||
|
something: else
|
||||||
|
---
|
||||||
|
c:
|
||||||
|
a: simple
|
||||||
|
b: cat
|
||||||
|
```
|
57
yq.go
57
yq.go
@ -73,6 +73,7 @@ func newCommandCLI() *cobra.Command {
|
|||||||
rootCmd.AddCommand(
|
rootCmd.AddCommand(
|
||||||
createReadCmd(),
|
createReadCmd(),
|
||||||
createWriteCmd(),
|
createWriteCmd(),
|
||||||
|
createPrefixCmd(),
|
||||||
createDeleteCmd(),
|
createDeleteCmd(),
|
||||||
createNewCmd(),
|
createNewCmd(),
|
||||||
createMergeCmd(),
|
createMergeCmd(),
|
||||||
@ -137,6 +138,28 @@ a.b.e:
|
|||||||
return cmdWrite
|
return cmdWrite
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func createPrefixCmd() *cobra.Command {
|
||||||
|
var cmdWrite = &cobra.Command{
|
||||||
|
Use: "prefix [yaml_file] [path]",
|
||||||
|
Aliases: []string{"p"},
|
||||||
|
Short: "yq p [--inplace/-i] [--doc/-d index] sample.yaml a.b.c",
|
||||||
|
Example: `
|
||||||
|
yq prefix things.yaml a.b.c
|
||||||
|
yq prefix --inplace things.yaml a.b.c
|
||||||
|
yq p -i things.yaml a.b.c
|
||||||
|
yq p --doc 2 things.yaml a.b.d
|
||||||
|
yq p -d2 things.yaml a.b.d
|
||||||
|
`,
|
||||||
|
Long: `Prefixes w.r.t to the yaml file at the given path.
|
||||||
|
Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
|
||||||
|
`,
|
||||||
|
RunE: prefixProperty,
|
||||||
|
}
|
||||||
|
cmdWrite.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
|
||||||
|
cmdWrite.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
|
||||||
|
return cmdWrite
|
||||||
|
}
|
||||||
|
|
||||||
func createDeleteCmd() *cobra.Command {
|
func createDeleteCmd() *cobra.Command {
|
||||||
var cmdDelete = &cobra.Command{
|
var cmdDelete = &cobra.Command{
|
||||||
Use: "delete [yaml_file] [path]",
|
Use: "delete [yaml_file] [path]",
|
||||||
@ -394,6 +417,40 @@ func writeProperty(cmd *cobra.Command, args []string) error {
|
|||||||
return readAndUpdate(cmd.OutOrStdout(), args[0], updateData)
|
return readAndUpdate(cmd.OutOrStdout(), args[0], updateData)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func prefixProperty(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) != 2 {
|
||||||
|
return errors.New("Must provide <filename> <prefixed_path>")
|
||||||
|
}
|
||||||
|
var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex()
|
||||||
|
if errorParsingDocIndex != nil {
|
||||||
|
return errorParsingDocIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
var paths = parsePath(args[1])
|
||||||
|
|
||||||
|
// Inverse order
|
||||||
|
for i := len(paths)/2 - 1; i >= 0; i-- {
|
||||||
|
opp := len(paths) - 1 - i
|
||||||
|
paths[i], paths[opp] = paths[opp], paths[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) {
|
||||||
|
|
||||||
|
if updateAll || currentIndex == docIndexInt {
|
||||||
|
log.Debugf("Prefixing %v to doc %v", paths, currentIndex)
|
||||||
|
var mapDataBucket = dataBucket
|
||||||
|
for _, key := range paths {
|
||||||
|
nestedBucket := make(map[string]interface{})
|
||||||
|
nestedBucket[key] = mapDataBucket
|
||||||
|
mapDataBucket = nestedBucket
|
||||||
|
}
|
||||||
|
return mapDataBucket, nil
|
||||||
|
}
|
||||||
|
return dataBucket, nil
|
||||||
|
}
|
||||||
|
return readAndUpdate(cmd.OutOrStdout(), args[0], updateData)
|
||||||
|
}
|
||||||
|
|
||||||
func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) error {
|
func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) error {
|
||||||
var destination io.Writer
|
var destination io.Writer
|
||||||
var destinationName string
|
var destinationName string
|
||||||
|
Loading…
Reference in New Issue
Block a user