diff --git a/README.md b/README.md index 916968a3cb3..463e829cc12 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,11 @@ $ limactl start --name=default template://docker > NOTE: `limactl start template://TEMPLATE` requires Lima v0.9.0 or later. > Older releases require `limactl start /usr/local/share/doc/lima/examples/TEMPLATE.yaml` instead. +To create an instance "default" with modified parameters: +```console +$ limactl start --set='.cpus = 2 | .memory = "2GiB"' +``` + To see the template list: ```console $ limactl start --list-templates diff --git a/cmd/limactl/start.go b/cmd/limactl/start.go index 8cd4d8be3fb..307f2a0b1c8 100644 --- a/cmd/limactl/start.go +++ b/cmd/limactl/start.go @@ -21,6 +21,7 @@ import ( "github.com/lima-vm/lima/pkg/store" "github.com/lima-vm/lima/pkg/store/filenames" "github.com/lima-vm/lima/pkg/templatestore" + "github.com/lima-vm/lima/pkg/yqutil" "github.com/mattn/go-isatty" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -36,6 +37,9 @@ $ limactl start To create an instance "default" from a template "docker": $ limactl start --name=default template://docker +To create an instance "default" with modified parameters: +$ limactl start --set='.cpus = 2 | .memory = "2GiB"' + To see the template list: $ limactl start --list-templates @@ -56,6 +60,7 @@ $ cat template.yaml | limactl start --name=local - // TODO: "survey" does not support using cygwin terminal on windows yet startCommand.Flags().Bool("tty", isatty.IsTerminal(os.Stdout.Fd()), "enable TUI interactions such as opening an editor, defaults to true when stdout is a terminal") startCommand.Flags().String("name", "", "override the instance name") + startCommand.Flags().String("set", "", "modify the template inplace, using yq syntax") startCommand.Flags().Bool("list-templates", false, "list available templates and exit") startCommand.Flags().Duration("timeout", start.DefaultWatchHostAgentEventsTimeout, "duration to wait for the instance to be running before timing out") return startCommand @@ -82,6 +87,10 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string) (*store.Instance, e if err != nil { return nil, err } + st.yq, err = cmd.Flags().GetString("set") + if err != nil { + return nil, err + } const yBytesLimit = 4 * 1024 * 1024 // 4MiB if ok, u := guessarg.SeemsTemplateURL(arg); ok { @@ -206,6 +215,9 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string) (*store.Instance, e } } else { logrus.Info("Terminal is not available, proceeding without opening an editor") + if err := modifyInPlace(st); err != nil { + return nil, err + } } saveBrokenEditorBuffer := tty return createInstance(st, saveBrokenEditorBuffer) @@ -261,10 +273,27 @@ func createInstance(st *creatorState, saveBrokenEditorBuffer bool) (*store.Insta type creatorState struct { instName string // instance name yBytes []byte // yaml bytes + yq string // yq expression +} + +func modifyInPlace(st *creatorState) error { + if st.yq == "" { + return nil + } + out, err := yqutil.EvaluateExpression(st.yq, st.yBytes) + if err != nil { + return err + } + st.yBytes = out + return nil } func chooseNextCreatorState(st *creatorState) (*creatorState, error) { for { + if err := modifyInPlace(st); err != nil { + logrus.WithError(err).Warn("Failed to evaluate yq expression") + return st, err + } var ans string prompt := &survey.Select{ Message: fmt.Sprintf("Creating an instance %q", st.instName), diff --git a/docs/experimental.md b/docs/experimental.md index 76787efb206..ca26a8234dc 100644 --- a/docs/experimental.md +++ b/docs/experimental.md @@ -6,3 +6,7 @@ The following features are experimental and subject to change: - `vmType: vz` and relevant configurations (`mountType: virtiofs`, `rosetta`, `[]networks.vzNAT`) - `arch: riscv64` - `video.display: vnc` and relevant configuration (`video.vnc.display`) + +The following flags are experimental and subject to change: + +- `start --set`, yq expression diff --git a/go.mod b/go.mod index 704c41b3607..5acc7db3d55 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/mattn/go-isatty v0.0.17 github.com/mattn/go-shellwords v1.0.12 github.com/miekg/dns v1.1.50 + github.com/mikefarah/yq/v4 v4.30.8 github.com/norouter/norouter v0.6.3 github.com/nxadm/tail v1.4.8 github.com/opencontainers/go-digest v1.0.0 @@ -35,6 +36,7 @@ require ( github.com/xorcare/pointer v1.2.2 golang.org/x/sync v0.1.0 golang.org/x/sys v0.5.0 + gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 gotest.tools/v3 v3.4.0 inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0 k8s.io/api v0.26.1 @@ -45,9 +47,13 @@ require ( require ( github.com/Microsoft/go-winio v0.5.2 // indirect github.com/VividCortex/ewma v1.1.1 // indirect + github.com/a8m/envsubst v1.3.0 // indirect + github.com/alecthomas/participle/v2 v2.0.0-beta.5 // indirect github.com/apparentlymart/go-cidr v1.1.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1 // indirect + github.com/dimchansky/utfbom v1.1.1 // indirect + github.com/elliotchance/orderedmap v1.5.0 // indirect github.com/emicklei/go-restful/v3 v3.9.0 // indirect github.com/evanphx/json-patch v4.12.0+incompatible // indirect github.com/fatih/color v1.13.0 // indirect @@ -56,6 +62,7 @@ require ( github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonreference v0.20.0 // indirect github.com/go-openapi/swag v0.19.14 // indirect + github.com/goccy/go-json v0.10.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/google/btree v1.0.1 // indirect @@ -66,10 +73,12 @@ require ( github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.1 // indirect github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f // indirect + github.com/jinzhu/copier v0.3.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kr/fs v0.1.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect github.com/mailru/easyjson v0.7.6 // indirect github.com/mattn/go-colorable v0.1.12 // indirect github.com/mattn/go-runewidth v0.0.12 // indirect diff --git a/go.sum b/go.sum index ea75927a5d6..f3bc1d316b3 100644 --- a/go.sum +++ b/go.sum @@ -62,6 +62,12 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE= github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM= github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= +github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg= +github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY= +github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg= +github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo= +github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM= +github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= @@ -161,6 +167,8 @@ github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1 h1:j6vGfla github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1/go.mod h1:QS1XzqZLcDniNYrN7EZefq3wIyb/M2WmJbql4ZKoc1Q= github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001 h1:WAg57gnaAWWjMAELcwHjc2xy0PoXQ5G+vn3+XS6s1jI= github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001/go.mod h1:IetBE52JfFxK46p2n2Rqm+p5Gx1gpu2hRHsrbnPOWZQ= +github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U= +github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE= github.com/diskfs/go-diskfs v1.3.0 h1:D3IVe1y7ybB5SjCO0pOmkWThL9lZEWeanp8rRa0q0sk= github.com/diskfs/go-diskfs v1.3.0/go.mod h1:3pUpCAz75Q11om5RsGpVKUgXp2Z+ATw1xV500glmCP0= github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= @@ -178,6 +186,8 @@ github.com/elastic/go-libaudit/v2 v2.3.2/go.mod h1:+ZE0czqmbqtnRkl0fNgpI+HvVVRo/ github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc= github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= +github.com/elliotchance/orderedmap v1.5.0 h1:1IsExUsjv5XNBD3ZdC7jkAAqLWOOKdbPTmkHx63OsBg= +github.com/elliotchance/orderedmap v1.5.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys= github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs= github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE= github.com/emicklei/go-restful/v3 v3.9.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= @@ -241,6 +251,8 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM= github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE= +github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= +github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-yaml v1.9.8 h1:5gMyLUeU1/6zl+WFfR1hN7D2kf+1/eRGa7DFtToiBvQ= github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -358,6 +370,7 @@ github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -372,6 +385,8 @@ github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7P github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo= github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= +github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg= +github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -414,6 +429,8 @@ github.com/linuxkit/virtsock v0.0.0-20220523201153-1a23e78aa7a2/go.mod h1:SWzULI github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY= github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= @@ -452,6 +469,8 @@ github.com/miekg/dns v1.1.25/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKju github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/mikefarah/yq/v4 v4.30.8 h1:EHovseqMJs9kvE25/2k6VnDs4CrBZN+DFbybUhpPAGM= +github.com/mikefarah/yq/v4 v4.30.8/go.mod h1:8D30GDxhu3+KXll0aFV5msGcdgYRZSPOPVBTbgUQ7Dc= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -510,6 +529,7 @@ github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtP github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20170910134614-2b3a18b5f0fb/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -1067,6 +1087,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE= +gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= diff --git a/pkg/yqutil/yqutil.go b/pkg/yqutil/yqutil.go new file mode 100644 index 00000000000..5184b4c65e2 --- /dev/null +++ b/pkg/yqutil/yqutil.go @@ -0,0 +1,66 @@ +package yqutil + +import ( + "bytes" + "fmt" + "os" + + "github.com/mikefarah/yq/v4/pkg/yqlib" + "github.com/sirupsen/logrus" + logging "gopkg.in/op/go-logging.v1" +) + +// EvaluateExpression evaluates the yq expression, and returns the modified yaml. +func EvaluateExpression(expression string, content []byte) ([]byte, error) { + tmpYAMLFile, err := os.CreateTemp("", "lima-yq-*.yaml") + if err != nil { + return nil, err + } + tmpYAMLPath := tmpYAMLFile.Name() + defer os.RemoveAll(tmpYAMLPath) + err = os.WriteFile(tmpYAMLPath, content, 0o600) + if err != nil { + return nil, err + } + + memory := logging.NewMemoryBackend(0) + backend := logging.AddModuleLevel(memory) + logging.SetBackend(backend) + yqlib.InitExpressionParser() + + indent := 2 + encoder := yqlib.NewYamlEncoder(indent, false, yqlib.ConfiguredYamlPreferences) + out := new(bytes.Buffer) + printer := yqlib.NewPrinter(encoder, yqlib.NewSinglePrinterWriter(out)) + decoder := yqlib.NewYamlDecoder(yqlib.ConfiguredYamlPreferences) + + streamEvaluator := yqlib.NewStreamEvaluator() + files := []string{tmpYAMLPath} + err = streamEvaluator.EvaluateFiles(expression, files, printer, decoder) + if err != nil { + logger := logrus.StandardLogger() + for node := memory.Head(); node != nil; node = node.Next() { + entry := logrus.NewEntry(logger).WithTime(node.Record.Time) + prefix := fmt.Sprintf("[%s] ", node.Record.Module) + message := prefix + node.Record.Message() + switch node.Record.Level { + case logging.CRITICAL: + entry.Fatal(message) + case logging.ERROR: + entry.Error(message) + case logging.WARNING: + entry.Warn(message) + case logging.NOTICE: + entry.Info(message) + case logging.INFO: + entry.Info(message) + case logging.DEBUG: + entry.Debug(message) + } + } + return nil, err + } + + return out.Bytes(), nil + +} diff --git a/pkg/yqutil/yqutil_test.go b/pkg/yqutil/yqutil_test.go new file mode 100644 index 00000000000..297a2e2c6b6 --- /dev/null +++ b/pkg/yqutil/yqutil_test.go @@ -0,0 +1,65 @@ +package yqutil + +import ( + "testing" + + "gotest.tools/v3/assert" +) + +func TestEvaluateExpressionSimple(t *testing.T) { + expression := `.cpus = 2 | .memory = "2GiB"` + content := ` +# CPUs +cpus: null + +# Memory size +memory: null +` + // Note: yq currently removes empty lines, but not comments + expected := ` +# CPUs +cpus: 2 +# Memory size +memory: 2GiB +` + out, err := EvaluateExpression(expression, []byte(content)) + assert.NilError(t, err) + assert.Equal(t, expected, string(out)) +} + +func TestEvaluateExpressionComplex(t *testing.T) { + expression := `.mounts += {"location": "foo", "mountPoint": "bar"}` + content := ` +# Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest +# 🟢 Builtin default: null (Mount nothing) +# 🔵 This file: Mount the home as read-only, /tmp/lima as writable +mounts: +- location: "~" + # Configure the mountPoint inside the guest. + # 🟢 Builtin default: value of location + mountPoint: null +` + // Note: yq will use canonical yaml, with indented sequences + // Note: yq will not explicitly quote strings, when not needed + expected := ` +# Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest +# 🟢 Builtin default: null (Mount nothing) +# 🔵 This file: Mount the home as read-only, /tmp/lima as writable +mounts: + - location: "~" + # Configure the mountPoint inside the guest. + # 🟢 Builtin default: value of location + mountPoint: null + - location: foo + mountPoint: bar +` + out, err := EvaluateExpression(expression, []byte(content)) + assert.NilError(t, err) + assert.Equal(t, expected, string(out)) +} + +func TestEvaluateExpressionError(t *testing.T) { + expression := `arch: aarch64` + _, err := EvaluateExpression(expression, []byte("")) + assert.ErrorContains(t, err, "invalid input text") +}