wip - write in place

This commit is contained in:
Mike Farah 2020-11-29 20:25:47 +11:00
parent 1258fa199e
commit 8de10e550d
10 changed files with 137 additions and 729 deletions

View File

@ -2,7 +2,7 @@ package cmd
var unwrapScalar = true var unwrapScalar = true
// var writeInplace = false var writeInplace = false
var outputToJSON = false var outputToJSON = false
// var exitStatus = false // var exitStatus = false
@ -14,5 +14,3 @@ var noDocSeparators = false
var nullInput = false var nullInput = false
var verbose = false var verbose = false
var version = false var version = false
// var log = logging.MustGetLogger("yq")

View File

@ -1,6 +1,7 @@
package cmd package cmd
import ( import (
"fmt"
"os" "os"
"github.com/mikefarah/yq/v4/pkg/yqlib" "github.com/mikefarah/yq/v4/pkg/yqlib"
@ -39,7 +40,24 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) { if forceColor || (!forceNoColor && (fileInfo.Mode()&os.ModeCharDevice) != 0) {
colorsEnabled = true colorsEnabled = true
} }
if writeInplace && len(args) < 2 {
return fmt.Errorf("Write inplace flag only applicable when giving an expression and at least one file")
}
completedSuccessfully := false
if writeInplace {
writeInPlaceHandler := yqlib.NewWriteInPlaceHandler(args[1])
out, err = writeInPlaceHandler.CreateTempFile()
if err != nil {
return err
}
defer writeInPlaceHandler.FinishWriteInPlace(completedSuccessfully)
}
printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators) printer := yqlib.NewPrinter(out, outputToJSON, unwrapScalar, colorsEnabled, indent, !noDocSeparators)
allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator() allAtOnceEvaluator := yqlib.NewAllAtOnceEvaluator()
switch len(args) { switch len(args) {
case 0: case 0:
@ -59,6 +77,8 @@ func evaluateAll(cmd *cobra.Command, args []string) error {
err = allAtOnceEvaluator.EvaluateFiles(args[0], args[1:], printer) err = allAtOnceEvaluator.EvaluateFiles(args[0], args[1:], printer)
} }
completedSuccessfully = err == nil
cmd.SilenceUsage = true cmd.SilenceUsage = true
return err return err
} }

View File

@ -46,6 +46,7 @@ func New() *cobra.Command {
rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output") rootCmd.PersistentFlags().IntVarP(&indent, "indent", "I", 2, "sets indent level for output")
rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit") rootCmd.Flags().BoolVarP(&version, "version", "V", false, "Print version information and quit")
rootCmd.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace of first yaml file given.")
rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors") rootCmd.PersistentFlags().BoolVarP(&forceColor, "colors", "C", false, "force print with colors")
rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors") rootCmd.PersistentFlags().BoolVarP(&forceNoColor, "no-colors", "M", false, "force print with no colors")

View File

@ -1,61 +0,0 @@
package cmd
// import (
// "github.com/spf13/cobra"
// )
// func createWriteCmd() *cobra.Command {
// var cmdWrite = &cobra.Command{
// Use: "write [yaml_file] [path_expression] [value]",
// Aliases: []string{"w"},
// Short: "yq w [--inplace/-i] [--script/-s script_file] [--doc/-d index] sample.yaml 'b.e(name==fr*).value' newValue",
// Example: `
// yq write things.yaml 'a.b.c' true
// yq write things.yaml 'a.*.c' true
// yq write things.yaml 'a.**' true
// yq write things.yaml 'a.(child.subchild==co*).c' true
// yq write things.yaml 'a.b.c' --tag '!!str' true # force 'true' to be interpreted as a string instead of bool
// yq write things.yaml 'a.b.c' --tag '!!float' 3
// yq write --inplace -- things.yaml 'a.b.c' '--cat' # need to use '--' to stop processing arguments as flags
// yq w -i things.yaml 'a.b.c' cat
// yq w -i -s update_script.yaml things.yaml
// yq w things.yaml 'a.b.d[+]' foo # appends a new node to the 'd' array
// yq w --doc 2 things.yaml 'a.b.d[+]' foo # updates the 3rd document of the yaml file
// `,
// Long: `Updates the yaml file w.r.t the given path and value.
// Outputs to STDOUT unless the inplace flag is used, in which case the file is updated instead.
// Append value to array adds the value to the end of array.
// Update Scripts:
// Note that you can give an update script to perform more sophisticated update. Update script
// format is list of update commands (update or delete) like so:
// ---
// - command: update
// path: b.c
// value:
// #great
// things: frog # wow!
// - command: delete
// path: b.d
// `,
// RunE: writeProperty,
// }
// cmdWrite.PersistentFlags().BoolVarP(&writeInplace, "inplace", "i", false, "update the yaml file inplace")
// cmdWrite.PersistentFlags().StringVarP(&writeScript, "script", "s", "", "yaml script for updating yaml")
// cmdWrite.PersistentFlags().StringVarP(&sourceYamlFile, "from", "f", "", "yaml file for updating yaml (as-is)")
// cmdWrite.PersistentFlags().StringVarP(&customTag, "tag", "t", "", "set yaml tag (e.g. !!int)")
// cmdWrite.PersistentFlags().StringVarP(&docIndex, "doc", "d", "0", "process document index number (0 based, * for all documents)")
// cmdWrite.PersistentFlags().StringVarP(&customStyle, "style", "", "", "formatting style of the value: single, double, folded, flow, literal, tagged")
// cmdWrite.PersistentFlags().StringVarP(&anchorName, "anchorName", "", "", "anchor name")
// cmdWrite.PersistentFlags().BoolVarP(&makeAlias, "makeAlias", "", false, "create an alias using the value as the anchor name")
// return cmdWrite
// }
// func writeProperty(cmd *cobra.Command, args []string) error {
// var updateCommands, updateCommandsError = readUpdateCommands(args, 3, "Must provide <filename> <path_to_update> <value>", true)
// if updateCommandsError != nil {
// return updateCommandsError
// }
// return updateDoc(args[0], updateCommands, cmd.OutOrStdout())
// }

View File

@ -1,610 +0,0 @@
package cmd
// import (
// "fmt"
// "runtime"
// "strings"
// "testing"
// "github.com/mikefarah/yq/v3/test"
// )
// func TestWriteCmd(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 7
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteKeepCommentsCmd(t *testing.T) {
// content := `b:
// c: 3 # comment
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 7 # comment
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteWithTaggedStyleCmd(t *testing.T) {
// content := `b:
// c: dog
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --tag=!!str --style=tagged", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: !!str cat
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteWithDoubleQuotedStyleCmd(t *testing.T) {
// content := `b:
// c: dog
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=double", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: "cat"
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteUpdateStyleOnlyCmd(t *testing.T) {
// content := `b:
// c: dog
// d: things
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.* --style=single", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 'dog'
// d: 'things'
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteUpdateTagOnlyCmd(t *testing.T) {
// content := `b:
// c: true
// d: false
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.* --tag=!!str", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: "true"
// d: "false"
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteWithSingleQuotedStyleCmd(t *testing.T) {
// content := `b:
// c: dog
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=single", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 'cat'
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteWithLiteralStyleCmd(t *testing.T) {
// content := `b:
// c: dog
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=literal", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: |-
// cat
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteWithFoldedStyleCmd(t *testing.T) {
// content := `b:
// c: dog
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c cat --style=folded", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: >-
// cat
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteEmptyMultiDocCmd(t *testing.T) {
// content := `# this is empty
// ---
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s c 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `c: 7
// # this is empty
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteSurroundingEmptyMultiDocCmd(t *testing.T) {
// content := `---
// # empty
// ---
// cat: frog
// ---
// # empty
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s -d1 c 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `
// # empty
// ---
// cat: frog
// c: 7
// ---
// # empty
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteFromFileCmd(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// source := `kittens: are cute # sure are!`
// fromFilename := test.WriteTempYamlFile(source)
// defer test.RemoveTempYamlFile(fromFilename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c -f %s", filename, fromFilename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c:
// kittens: are cute # sure are!
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteEmptyCmd(t *testing.T) {
// content := ``
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 7
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteAutoCreateCmd(t *testing.T) {
// content := `applications:
// - name: app
// env:`
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s applications[0].env.hello world", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `applications:
// - name: app
// env:
// hello: world
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmdScript(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// updateScript := `- command: update
// path: b.c
// value: 7`
// scriptFilename := test.WriteTempYamlFile(updateScript)
// defer test.RemoveTempYamlFile(scriptFilename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write --script %s %s", scriptFilename, filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 7
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmdEmptyScript(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// updateScript := ``
// scriptFilename := test.WriteTempYamlFile(updateScript)
// defer test.RemoveTempYamlFile(scriptFilename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write --script %s %s", scriptFilename, filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 3
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteMultiCmd(t *testing.T) {
// content := `b:
// c: 3
// ---
// apples: great
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s -d 1 apples ok", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 3
// ---
// apples: ok
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteInvalidDocumentIndexCmd(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s -df apples ok", 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`
// test.AssertResult(t, expectedOutput, result.Error.Error())
// }
// func TestWriteBadDocumentIndexCmd(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s -d 1 apples ok", 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)`
// test.AssertResult(t, expectedOutput, result.Error.Error())
// }
// func TestWriteMultiAllCmd(t *testing.T) {
// content := `b:
// c: 3
// ---
// apples: great
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s -d * apples ok", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: 3
// apples: ok
// ---
// apples: ok`
// test.AssertResult(t, expectedOutput, strings.Trim(result.Output, "\n "))
// }
// func TestWriteCmd_EmptyArray(t *testing.T) {
// content := `b: 3`
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s a []", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b: 3
// a: []
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_Error(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "write")
// if result.Error == nil {
// t.Error("Expected command to fail due to missing arg")
// }
// expectedOutput := `Must provide <filename> <path_to_update> <value>`
// test.AssertResult(t, expectedOutput, result.Error.Error())
// }
// func TestWriteCmd_ErrorUnreadableFile(t *testing.T) {
// cmd := getRootCommand()
// result := test.RunCmd(cmd, "write fake-unknown a.b 3")
// if result.Error == nil {
// t.Error("Expected command to fail due to unknown file")
// }
// var expectedOutput string
// if runtime.GOOS == "windows" {
// expectedOutput = `open fake-unknown: The system cannot find the file specified.`
// } else {
// expectedOutput = `open fake-unknown: no such file or directory`
// }
// test.AssertResult(t, expectedOutput, result.Error.Error())
// }
// func TestWriteCmd_Inplace(t *testing.T) {
// content := `b:
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write -i %s b.c 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// gotOutput := test.ReadTempYamlFile(filename)
// expectedOutput := `b:
// c: 7`
// test.AssertResult(t, expectedOutput, strings.Trim(gotOutput, "\n "))
// }
// func TestWriteCmd_InplaceError(t *testing.T) {
// content := `b: cat
// c: 3
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write -i %s b.c 7", filename))
// if result.Error == nil {
// t.Error("Expected Error to occur!")
// }
// gotOutput := test.ReadTempYamlFile(filename)
// test.AssertResult(t, content, gotOutput)
// }
// func TestWriteCmd_Append(t *testing.T) {
// content := `b:
// - foo
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b[+] 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// - foo
// - 7
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_AppendInline(t *testing.T) {
// content := `b: [foo]`
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b[+] 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b: [foo, 7]
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_AppendInlinePretty(t *testing.T) {
// content := `b: [foo]`
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s -P b[+] 7", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// - foo
// - 7
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_AppendEmptyArray(t *testing.T) {
// content := `a: 2
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b[+] v", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `a: 2
// b:
// - v
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_SplatArray(t *testing.T) {
// content := `b:
// - c: thing
// - c: another thing
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b[*].c new", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// - c: new
// - c: new
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_SplatMap(t *testing.T) {
// content := `b:
// c: thing
// d: another thing
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.* new", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: new
// d: new
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }
// func TestWriteCmd_SplatMapEmpty(t *testing.T) {
// content := `b:
// c: thing
// d: another thing
// `
// filename := test.WriteTempYamlFile(content)
// defer test.RemoveTempYamlFile(filename)
// cmd := getRootCommand()
// result := test.RunCmd(cmd, fmt.Sprintf("write %s b.c.* new", filename))
// if result.Error != nil {
// t.Error(result.Error)
// }
// expectedOutput := `b:
// c: {}
// d: another thing
// `
// test.AssertResult(t, expectedOutput, result.Output)
// }

50
pkg/yqlib/file_utils.go Normal file
View File

@ -0,0 +1,50 @@
package yqlib
import (
"io"
"os"
)
func safelyRenameFile(from string, to string) {
if renameError := os.Rename(from, to); renameError != nil {
log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
log.Debug(renameError.Error())
// can't do this rename when running in docker to a file targeted in a mounted volume,
// so gracefully degrade to copying the entire contents.
if copyError := copyFileContents(from, to); copyError != nil {
log.Errorf("Failed copying from %v to %v", from, to)
log.Error(copyError.Error())
} else {
removeErr := os.Remove(from)
if removeErr != nil {
log.Errorf("failed removing original file: %s", from)
}
}
}
}
// thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
func copyFileContents(src, dst string) (err error) {
in, err := os.Open(src) // nolint gosec
if err != nil {
return err
}
defer safelyCloseFile(in)
out, err := os.Create(dst)
if err != nil {
return err
}
defer safelyCloseFile(out)
if _, err = io.Copy(out, in); err != nil {
return err
}
return out.Sync()
}
func safelyCloseFile(file *os.File) {
err := file.Close()
if err != nil {
log.Error("Error closing file!")
log.Error(err.Error())
}
}

View File

@ -18,6 +18,7 @@ type OperationType struct {
// operators TODO: // operators TODO:
// - cookbook doc for common things // - cookbook doc for common things
// - existStatus
// - write in place // - write in place
// - mergeEmpty (sets only if the document is empty, do I do that now?) // - mergeEmpty (sets only if the document is empty, do I do that now?)
// - compare ?? // - compare ??

View File

@ -5,7 +5,7 @@ import (
"container/list" "container/list"
"io" "io"
"gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
) )
type Printer interface { type Printer interface {
@ -53,6 +53,13 @@ func (p *resultsPrinter) writeString(writer io.Writer, txt string) error {
return errorWriting return errorWriting
} }
func (p *resultsPrinter) safelyFlush(writer *bufio.Writer) {
if err := writer.Flush(); err != nil {
log.Error("Error flushing writer!")
log.Error(err.Error())
}
}
func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error { func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error {
log.Debug("PrintResults for %v matches", matchingNodes.Len()) log.Debug("PrintResults for %v matches", matchingNodes.Len())
var err error var err error
@ -66,7 +73,7 @@ func (p *resultsPrinter) PrintResults(matchingNodes *list.List) error {
} }
bufferedWriter := bufio.NewWriter(p.writer) bufferedWriter := bufio.NewWriter(p.writer)
defer safelyFlush(bufferedWriter) defer p.safelyFlush(bufferedWriter)
if matchingNodes.Len() == 0 { if matchingNodes.Len() == 0 {
log.Debug("no matching results, nothing to print") log.Debug("no matching results, nothing to print")

View File

@ -9,8 +9,6 @@ import (
yaml "gopkg.in/yaml.v3" yaml "gopkg.in/yaml.v3"
) )
//TODO: convert to interface + struct
var treeNavigator = NewDataTreeNavigator() var treeNavigator = NewDataTreeNavigator()
var treeCreator = NewPathTreeCreator() var treeCreator = NewPathTreeCreator()
@ -52,54 +50,3 @@ func readDocuments(reader io.Reader, filename string, fileIndex int) (*list.List
currentIndex = currentIndex + 1 currentIndex = currentIndex + 1
} }
} }
// func safelyRenameFile(from string, to string) {
// if renameError := os.Rename(from, to); renameError != nil {
// log.Debugf("Error renaming from %v to %v, attempting to copy contents", from, to)
// log.Debug(renameError.Error())
// // can't do this rename when running in docker to a file targeted in a mounted volume,
// // so gracefully degrade to copying the entire contents.
// if copyError := copyFileContents(from, to); copyError != nil {
// log.Errorf("Failed copying from %v to %v", from, to)
// log.Error(copyError.Error())
// } else {
// removeErr := os.Remove(from)
// if removeErr != nil {
// log.Errorf("failed removing original file: %s", from)
// }
// }
// }
// }
// thanks https://stackoverflow.com/questions/21060945/simple-way-to-copy-a-file-in-golang
// func copyFileContents(src, dst string) (err error) {
// in, err := os.Open(src) // nolint gosec
// if err != nil {
// return err
// }
// defer safelyCloseFile(in)
// out, err := os.Create(dst)
// if err != nil {
// return err
// }
// defer safelyCloseFile(out)
// if _, err = io.Copy(out, in); err != nil {
// return err
// }
// return out.Sync()
// }
func safelyFlush(writer *bufio.Writer) {
if err := writer.Flush(); err != nil {
log.Error("Error flushing writer!")
log.Error(err.Error())
}
}
func safelyCloseFile(file *os.File) {
err := file.Close()
if err != nil {
log.Error("Error closing file!")
log.Error(err.Error())
}
}

View File

@ -0,0 +1,55 @@
package yqlib
import (
"io/ioutil"
"os"
)
type WriteInPlaceHandler interface {
CreateTempFile() (*os.File, error)
FinishWriteInPlace(evaluatedSuccessfully bool)
}
type writeInPlaceHandler struct {
inputFilename string
tempFile *os.File
}
func NewWriteInPlaceHandler(inputFile string) WriteInPlaceHandler {
return &writeInPlaceHandler{inputFile, nil}
}
func (w *writeInPlaceHandler) CreateTempFile() (*os.File, error) {
info, err := os.Stat(w.inputFilename)
if err != nil {
return nil, err
}
_, err = os.Stat(os.TempDir())
if os.IsNotExist(err) {
err = os.Mkdir(os.TempDir(), 0700)
if err != nil {
return nil, err
}
} else if err != nil {
return nil, err
}
file, err := ioutil.TempFile("", "temp")
if err != nil {
return nil, err
}
err = os.Chmod(file.Name(), info.Mode())
w.tempFile = file
return file, err
}
func (w *writeInPlaceHandler) FinishWriteInPlace(evaluatedSuccessfully bool) {
safelyCloseFile(w.tempFile)
if evaluatedSuccessfully {
safelyRenameFile(w.tempFile.Name(), w.inputFilename)
} else {
os.Remove(w.tempFile.Name())
}
}