diff --git a/examples/sample.yaml b/examples/sample.yaml index b26830e..a08d1d1 100644 --- a/examples/sample.yaml +++ b/examples/sample.yaml @@ -1,7 +1,7 @@ a: Easy! as one two three b: c: 2 - d: [3, 4] + d: [3, 4, 5] e: - name: fred value: 3 diff --git a/pkg/yqlib/data_navigator.go b/pkg/yqlib/data_navigator.go index 3a2d184..234405b 100644 --- a/pkg/yqlib/data_navigator.go +++ b/pkg/yqlib/data_navigator.go @@ -10,8 +10,9 @@ import ( type DataNavigator interface { DebugNode(node *yaml.Node) - Get(rootNode *yaml.Node, remainingPath []string) (*yaml.Node, error) - Update(rootNode *yaml.Node, remainingPath []string, changesToApply yaml.Node) error + Get(rootNode *yaml.Node, path []string) (*yaml.Node, error) + Update(rootNode *yaml.Node, path []string, changesToApply yaml.Node) error + Delete(rootNode *yaml.Node, path []string) error } type navigator struct { @@ -34,8 +35,8 @@ func (n *navigator) Get(value *yaml.Node, path []string) (*yaml.Node, error) { return n.Visit(value, path, identityVisitor) } -func (n *navigator) Update(value *yaml.Node, path []string, changesToApply yaml.Node) error { - _, errorVisiting := n.Visit(value, path, func(nodeToUpdate *yaml.Node) (*yaml.Node, error) { +func (n *navigator) Update(rootNode *yaml.Node, path []string, changesToApply yaml.Node) error { + _, errorVisiting := n.Visit(rootNode, path, func(nodeToUpdate *yaml.Node) (*yaml.Node, error) { n.log.Debug("going to update") n.DebugNode(nodeToUpdate) n.log.Debug("with") @@ -53,6 +54,36 @@ func (n *navigator) Update(value *yaml.Node, path []string, changesToApply yaml. return errorVisiting } +func (n *navigator) Delete(rootNode *yaml.Node, path []string) error { + + lastBit, newTail := path[len(path)-1], path[:len(path)-1] + n.log.Debug("splitting path, %v", lastBit) + n.log.Debug("new tail, %v", newTail) + _, errorVisiting := n.Visit(rootNode, newTail, func(nodeToUpdate *yaml.Node) (*yaml.Node, error) { + n.log.Debug("need to find %v in here", lastBit) + n.DebugNode(nodeToUpdate) + + if nodeToUpdate.Kind == yaml.SequenceNode { + var index, err = strconv.ParseInt(lastBit, 10, 64) // nolint + if err != nil { + return nil, err + } + if index >= int64(len(nodeToUpdate.Content)) { + n.log.Debug("index %v is greater than content lenth %v", index, len(nodeToUpdate.Content)) + return nodeToUpdate, nil + } + original := nodeToUpdate.Content + nodeToUpdate.Content = append(original[:index], original[index+1:]...) + + } else if nodeToUpdate.Kind == yaml.MappingNode { + + } + + return nodeToUpdate, nil + }) + return errorVisiting +} + func (n *navigator) Visit(value *yaml.Node, path []string, visitor VisitorFn) (*yaml.Node, error) { realValue := value if realValue.Kind == yaml.DocumentNode { diff --git a/pkg/yqlib/lib.go b/pkg/yqlib/lib.go index 10d30ee..344aa24 100644 --- a/pkg/yqlib/lib.go +++ b/pkg/yqlib/lib.go @@ -50,8 +50,8 @@ func (l *lib) Update(rootNode *yaml.Node, updateCommand UpdateCommand) error { var paths = l.parser.ParsePath(updateCommand.Path) return l.navigator.Update(rootNode, paths, updateCommand.Value) case "delete": - l.log.Debugf("need to implement delete") - return nil + var paths = l.parser.ParsePath(updateCommand.Path) + return l.navigator.Delete(rootNode, paths) default: return fmt.Errorf("Unknown command %v", updateCommand.Command) } diff --git a/yq.go b/yq.go index 7fec3c1..6801d03 100644 --- a/yq.go +++ b/yq.go @@ -77,7 +77,7 @@ func newCommandCLI() *cobra.Command { createReadCmd(), createWriteCmd(), // createPrefixCmd(), - // createDeleteCmd(), + createDeleteCmd(), // createNewCmd(), // createMergeCmd(), ) @@ -166,27 +166,27 @@ a.b.e: // return cmdWrite // } -// func createDeleteCmd() *cobra.Command { -// var cmdDelete = &cobra.Command{ -// Use: "delete [yaml_file] [path]", -// Aliases: []string{"d"}, -// Short: "yq d [--inplace/-i] [--doc/-d index] sample.yaml a.b.c", -// Example: ` -// yq delete things.yaml a.b.c -// yq delete --inplace things.yaml a.b.c -// yq delete --inplace -- things.yaml --key-starting-with-dash -// yq d -i things.yaml a.b.c -// yq d things.yaml a.b.c -// `, -// Long: `Deletes the given path from the YAML file. -// Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead. -// `, -// RunE: deleteProperty, -// } -// cmdDelete.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace") -// cmdDelete.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") -// return cmdDelete -// } +func createDeleteCmd() *cobra.Command { + var cmdDelete = &cobra.Command{ + Use: "delete [yaml_file] [path]", + Aliases: []string{"d"}, + Short: "yq d [--inplace/-i] [--doc/-d index] sample.yaml a.b.c", + Example: ` +yq delete things.yaml a.b.c +yq delete --inplace things.yaml a.b.c +yq delete --inplace -- things.yaml --key-starting-with-dash +yq d -i things.yaml a.b.c +yq d things.yaml a.b.c + `, + Long: `Deletes the given path from the YAML file. +Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead. +`, + RunE: deleteProperty, + } + cmdDelete.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace") + cmdDelete.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)") + return cmdDelete +} // func createNewCmd() *cobra.Command { // var cmdNew = &cobra.Command{ @@ -407,6 +407,20 @@ func writeProperty(cmd *cobra.Command, args []string) error { if updateCommandsError != nil { return updateCommandsError } + return updateDoc(args[0], updateCommands, cmd.OutOrStdout()) +} + +func deleteProperty(cmd *cobra.Command, args []string) error { + if len(args) < 2 { + return errors.New("Must provide ") + } + var updateCommands []yqlib.UpdateCommand = make([]yqlib.UpdateCommand, 1) + updateCommands[0] = yqlib.UpdateCommand{Command: "delete", Path: args[1]} + + return updateDoc(args[0], updateCommands, cmd.OutOrStdout()) +} + +func updateDoc(inputFile string, updateCommands []yqlib.UpdateCommand, writer io.Writer) error { var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex() if errorParsingDocIndex != nil { return errorParsingDocIndex @@ -424,7 +438,7 @@ func writeProperty(cmd *cobra.Command, args []string) error { } return nil } - return readAndUpdate(cmd.OutOrStdout(), args[0], updateData) + return readAndUpdate(writer, inputFile, updateData) } // func prefixProperty(cmd *cobra.Command, args []string) error { @@ -484,27 +498,6 @@ func readAndUpdate(stdOut io.Writer, inputFile string, updateData updateDataFn) return readStream(inputFile, mapYamlDecoder(updateData, encoder)) } -// func deleteProperty(cmd *cobra.Command, args []string) error { -// if len(args) < 2 { -// return errors.New("Must provide ") -// } -// var deletePath = args[1] -// var updateAll, docIndexInt, errorParsingDocIndex = parseDocumentIndex() -// if errorParsingDocIndex != nil { -// return errorParsingDocIndex -// } - -// var updateData = func(dataBucket interface{}, currentIndex int) (interface{}, error) { -// if updateAll || currentIndex == docIndexInt { -// log.Debugf("Deleting path in doc %v", currentIndex) -// return lib.DeletePath(dataBucket, deletePath) -// } -// return dataBucket, nil -// } - -// return readAndUpdate(cmd.OutOrStdout(), args[0], updateData) -// } - // func mergeProperties(cmd *cobra.Command, args []string) error { // if len(args) < 2 { // return errors.New("Must provide at least 2 yaml files")