Skip to content

Commit 511ce35

Browse files
committed
Add builtin yq support to lima start command
Allows modifying the template inplace for a single instance, if you don't want to change the default or override for all instances. There are currently some quirks with the modified yaml syntax, like removing empty lines or adding indentation on sequences... Signed-off-by: Anders F Björklund <[email protected]>
1 parent 5b9df0e commit 511ce35

File tree

7 files changed

+200
-0
lines changed

7 files changed

+200
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,11 @@ $ limactl start --name=default template://docker
176176
> NOTE: `limactl start template://TEMPLATE` requires Lima v0.9.0 or later.
177177
> Older releases require `limactl start /usr/local/share/doc/lima/examples/TEMPLATE.yaml` instead.
178178
179+
To create an instance "default" with modified parameters:
180+
```console
181+
$ limactl start --set='.cpus = 2 | .memory = "2GiB"'
182+
```
183+
179184
To see the template list:
180185
```console
181186
$ limactl start --list-templates

cmd/limactl/start.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/lima-vm/lima/pkg/store"
2222
"github.com/lima-vm/lima/pkg/store/filenames"
2323
"github.com/lima-vm/lima/pkg/templatestore"
24+
"github.com/lima-vm/lima/pkg/yqutil"
2425
"github.com/mattn/go-isatty"
2526
"github.com/sirupsen/logrus"
2627
"github.com/spf13/cobra"
@@ -36,6 +37,9 @@ $ limactl start
3637
To create an instance "default" from a template "docker":
3738
$ limactl start --name=default template://docker
3839
40+
To create an instance "default" with modified parameters:
41+
$ limactl start --set='.cpus = 2 | .memory = "2GiB"'
42+
3943
To see the template list:
4044
$ limactl start --list-templates
4145
@@ -56,6 +60,7 @@ $ cat template.yaml | limactl start --name=local -
5660
// TODO: "survey" does not support using cygwin terminal on windows yet
5761
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")
5862
startCommand.Flags().String("name", "", "override the instance name")
63+
startCommand.Flags().String("set", "", "modify the template inplace, using yq syntax")
5964
startCommand.Flags().Bool("list-templates", false, "list available templates and exit")
6065
startCommand.Flags().Duration("timeout", start.DefaultWatchHostAgentEventsTimeout, "duration to wait for the instance to be running before timing out")
6166
return startCommand
@@ -82,6 +87,10 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string) (*store.Instance, e
8287
if err != nil {
8388
return nil, err
8489
}
90+
st.yq, err = cmd.Flags().GetString("set")
91+
if err != nil {
92+
return nil, err
93+
}
8594
const yBytesLimit = 4 * 1024 * 1024 // 4MiB
8695

8796
if ok, u := guessarg.SeemsTemplateURL(arg); ok {
@@ -206,6 +215,9 @@ func loadOrCreateInstance(cmd *cobra.Command, args []string) (*store.Instance, e
206215
}
207216
} else {
208217
logrus.Info("Terminal is not available, proceeding without opening an editor")
218+
if err := modifyInPlace(st); err != nil {
219+
return nil, err
220+
}
209221
}
210222
saveBrokenEditorBuffer := tty
211223
return createInstance(st, saveBrokenEditorBuffer)
@@ -261,10 +273,27 @@ func createInstance(st *creatorState, saveBrokenEditorBuffer bool) (*store.Insta
261273
type creatorState struct {
262274
instName string // instance name
263275
yBytes []byte // yaml bytes
276+
yq string // yq expression
277+
}
278+
279+
func modifyInPlace(st *creatorState) error {
280+
if st.yq == "" {
281+
return nil
282+
}
283+
out, err := yqutil.EvaluateExpression(st.yq, st.yBytes)
284+
if err != nil {
285+
return err
286+
}
287+
st.yBytes = out
288+
return nil
264289
}
265290

266291
func chooseNextCreatorState(st *creatorState) (*creatorState, error) {
267292
for {
293+
if err := modifyInPlace(st); err != nil {
294+
logrus.WithError(err).Warn("Failed to evaluate yq expression")
295+
return st, err
296+
}
268297
var ans string
269298
prompt := &survey.Select{
270299
Message: fmt.Sprintf("Creating an instance %q", st.instName),

docs/experimental.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ The following features are experimental and subject to change:
66
- `vmType: vz` and relevant configurations (`mountType: virtiofs`, `rosetta`, `[]networks.vzNAT`)
77
- `arch: riscv64`
88
- `video.display: vnc` and relevant configuration (`video.vnc.display`)
9+
10+
The following flags are experimental and subject to change:
11+
12+
- `start --set`, yq expression

go.mod

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ require (
2626
github.com/mattn/go-isatty v0.0.17
2727
github.com/mattn/go-shellwords v1.0.12
2828
github.com/miekg/dns v1.1.50
29+
github.com/mikefarah/yq/v4 v4.30.8
2930
github.com/norouter/norouter v0.6.3
3031
github.com/nxadm/tail v1.4.8
3132
github.com/opencontainers/go-digest v1.0.0
@@ -35,6 +36,7 @@ require (
3536
github.com/xorcare/pointer v1.2.2
3637
golang.org/x/sync v0.1.0
3738
golang.org/x/sys v0.5.0
39+
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
3840
gotest.tools/v3 v3.4.0
3941
inet.af/tcpproxy v0.0.0-20220326234310-be3ee21c9fa0
4042
k8s.io/api v0.26.1
@@ -45,9 +47,13 @@ require (
4547
require (
4648
github.com/Microsoft/go-winio v0.5.2 // indirect
4749
github.com/VividCortex/ewma v1.1.1 // indirect
50+
github.com/a8m/envsubst v1.3.0 // indirect
51+
github.com/alecthomas/participle/v2 v2.0.0-beta.5 // indirect
4852
github.com/apparentlymart/go-cidr v1.1.0 // indirect
4953
github.com/davecgh/go-spew v1.1.1 // indirect
5054
github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1 // indirect
55+
github.com/dimchansky/utfbom v1.1.1 // indirect
56+
github.com/elliotchance/orderedmap v1.5.0 // indirect
5157
github.com/emicklei/go-restful/v3 v3.9.0 // indirect
5258
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
5359
github.com/fatih/color v1.13.0 // indirect
@@ -56,6 +62,7 @@ require (
5662
github.com/go-openapi/jsonpointer v0.19.5 // indirect
5763
github.com/go-openapi/jsonreference v0.20.0 // indirect
5864
github.com/go-openapi/swag v0.19.14 // indirect
65+
github.com/goccy/go-json v0.10.0 // indirect
5966
github.com/gogo/protobuf v1.3.2 // indirect
6067
github.com/golang/protobuf v1.5.2 // indirect
6168
github.com/google/btree v1.0.1 // indirect
@@ -66,10 +73,12 @@ require (
6673
github.com/imdario/mergo v0.3.12 // indirect
6774
github.com/inconshreveable/mousetrap v1.0.1 // indirect
6875
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f // indirect
76+
github.com/jinzhu/copier v0.3.5 // indirect
6977
github.com/josharian/intern v1.0.0 // indirect
7078
github.com/json-iterator/go v1.1.12 // indirect
7179
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
7280
github.com/kr/fs v0.1.0 // indirect
81+
github.com/magiconair/properties v1.8.7 // indirect
7382
github.com/mailru/easyjson v0.7.6 // indirect
7483
github.com/mattn/go-colorable v0.1.12 // indirect
7584
github.com/mattn/go-runewidth v0.0.12 // indirect

go.sum

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbt
6262
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
6363
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
6464
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
65+
github.com/a8m/envsubst v1.3.0 h1:GmXKmVssap0YtlU3E230W98RWtWCyIZzjtf1apWWyAg=
66+
github.com/a8m/envsubst v1.3.0/go.mod h1:MVUTQNGQ3tsjOOtKCNd+fl8RzhsXcDvvAEzkhGtlsbY=
67+
github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg=
68+
github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo=
69+
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
70+
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
6571
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
6672
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
6773
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
161167
github.com/digitalocean/go-libvirt v0.0.0-20201209184759-e2a69bcd5bd1/go.mod h1:QS1XzqZLcDniNYrN7EZefq3wIyb/M2WmJbql4ZKoc1Q=
162168
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001 h1:WAg57gnaAWWjMAELcwHjc2xy0PoXQ5G+vn3+XS6s1jI=
163169
github.com/digitalocean/go-qemu v0.0.0-20210326154740-ac9e0b687001/go.mod h1:IetBE52JfFxK46p2n2Rqm+p5Gx1gpu2hRHsrbnPOWZQ=
170+
github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
171+
github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
164172
github.com/diskfs/go-diskfs v1.3.0 h1:D3IVe1y7ybB5SjCO0pOmkWThL9lZEWeanp8rRa0q0sk=
165173
github.com/diskfs/go-diskfs v1.3.0/go.mod h1:3pUpCAz75Q11om5RsGpVKUgXp2Z+ATw1xV500glmCP0=
166174
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/
178186
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
179187
github.com/elazarl/goproxy v0.0.0-20210110162100-a92cc753f88e/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
180188
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
189+
github.com/elliotchance/orderedmap v1.5.0 h1:1IsExUsjv5XNBD3ZdC7jkAAqLWOOKdbPTmkHx63OsBg=
190+
github.com/elliotchance/orderedmap v1.5.0/go.mod h1:wsDwEaX5jEoyhbs7x93zk2H/qv0zwuhg4inXhDkYqys=
181191
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
182192
github.com/emicklei/go-restful/v3 v3.9.0 h1:XwGDlfxEnQZzuopoqxwSEllNcCOM9DhhFyhFIIGKwxE=
183193
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
241251
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
242252
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
243253
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
254+
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
255+
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
244256
github.com/goccy/go-yaml v1.9.8 h1:5gMyLUeU1/6zl+WFfR1hN7D2kf+1/eRGa7DFtToiBvQ=
245257
github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE=
246258
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
358370
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
359371
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
360372
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
373+
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
361374
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
362375
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
363376
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
372385
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
373386
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f h1:l1QCwn715k8nYkj4Ql50rzEog3WnMdrd4YYMMwemxEo=
374387
github.com/insomniacslk/dhcp v0.0.0-20220504074936-1ca156eafb9f/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E=
388+
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
389+
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
375390
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
376391
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
377392
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
414429
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
415430
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
416431
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
432+
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
433+
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
417434
github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
418435
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
419436
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
452469
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
453470
github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA=
454471
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
472+
github.com/mikefarah/yq/v4 v4.30.8 h1:EHovseqMJs9kvE25/2k6VnDs4CrBZN+DFbybUhpPAGM=
473+
github.com/mikefarah/yq/v4 v4.30.8/go.mod h1:8D30GDxhu3+KXll0aFV5msGcdgYRZSPOPVBTbgUQ7Dc=
455474
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
456475
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
457476
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
510529
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
511530
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
512531
github.com/pierrec/lz4 v2.3.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
532+
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e h1:aoZm08cpOy4WuID//EZDgcC4zIxODThtZNPirFr42+A=
513533
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
514534
github.com/pkg/errors v0.8.1-0.20170910134614-2b3a18b5f0fb/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
515535
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=
10671087
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
10681088
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
10691089
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
1090+
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE=
1091+
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
10701092
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
10711093
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
10721094
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=

pkg/yqutil/yqutil.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package yqutil
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"os"
7+
8+
"github.com/mikefarah/yq/v4/pkg/yqlib"
9+
"github.com/sirupsen/logrus"
10+
logging "gopkg.in/op/go-logging.v1"
11+
)
12+
13+
// EvaluateExpression evaluates the yq expression, and returns the modified yaml.
14+
func EvaluateExpression(expression string, content []byte) ([]byte, error) {
15+
tmpYAMLFile, err := os.CreateTemp("", "lima-yq-*.yaml")
16+
if err != nil {
17+
return nil, err
18+
}
19+
tmpYAMLPath := tmpYAMLFile.Name()
20+
defer os.RemoveAll(tmpYAMLPath)
21+
err = os.WriteFile(tmpYAMLPath, content, 0o600)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
memory := logging.NewMemoryBackend(0)
27+
backend := logging.AddModuleLevel(memory)
28+
logging.SetBackend(backend)
29+
yqlib.InitExpressionParser()
30+
31+
indent := 2
32+
encoder := yqlib.NewYamlEncoder(indent, false, yqlib.ConfiguredYamlPreferences)
33+
out := new(bytes.Buffer)
34+
printer := yqlib.NewPrinter(encoder, yqlib.NewSinglePrinterWriter(out))
35+
decoder := yqlib.NewYamlDecoder(yqlib.ConfiguredYamlPreferences)
36+
37+
streamEvaluator := yqlib.NewStreamEvaluator()
38+
files := []string{tmpYAMLPath}
39+
err = streamEvaluator.EvaluateFiles(expression, files, printer, decoder)
40+
if err != nil {
41+
logger := logrus.StandardLogger()
42+
for node := memory.Head(); node != nil; node = node.Next() {
43+
entry := logrus.NewEntry(logger).WithTime(node.Record.Time)
44+
prefix := fmt.Sprintf("[%s] ", node.Record.Module)
45+
message := prefix + node.Record.Message()
46+
switch node.Record.Level {
47+
case logging.CRITICAL:
48+
entry.Fatal(message)
49+
case logging.ERROR:
50+
entry.Error(message)
51+
case logging.WARNING:
52+
entry.Warn(message)
53+
case logging.NOTICE:
54+
entry.Info(message)
55+
case logging.INFO:
56+
entry.Info(message)
57+
case logging.DEBUG:
58+
entry.Debug(message)
59+
}
60+
}
61+
return nil, err
62+
}
63+
64+
return out.Bytes(), nil
65+
66+
}

pkg/yqutil/yqutil_test.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package yqutil
2+
3+
import (
4+
"testing"
5+
6+
"gotest.tools/v3/assert"
7+
)
8+
9+
func TestEvaluateExpressionSimple(t *testing.T) {
10+
expression := `.cpus = 2 | .memory = "2GiB"`
11+
content := `
12+
# CPUs
13+
cpus: null
14+
15+
# Memory size
16+
memory: null
17+
`
18+
// Note: yq currently removes empty lines, but not comments
19+
expected := `
20+
# CPUs
21+
cpus: 2
22+
# Memory size
23+
memory: 2GiB
24+
`
25+
out, err := EvaluateExpression(expression, []byte(content))
26+
assert.NilError(t, err)
27+
assert.Equal(t, expected, string(out))
28+
}
29+
30+
func TestEvaluateExpressionComplex(t *testing.T) {
31+
expression := `.mounts += {"location": "foo", "mountPoint": "bar"}`
32+
content := `
33+
# Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest
34+
# 🟢 Builtin default: null (Mount nothing)
35+
# 🔵 This file: Mount the home as read-only, /tmp/lima as writable
36+
mounts:
37+
- location: "~"
38+
# Configure the mountPoint inside the guest.
39+
# 🟢 Builtin default: value of location
40+
mountPoint: null
41+
`
42+
// Note: yq will use canonical yaml, with indented sequences
43+
// Note: yq will not explicitly quote strings, when not needed
44+
expected := `
45+
# Expose host directories to the guest, the mount point might be accessible from all UIDs in the guest
46+
# 🟢 Builtin default: null (Mount nothing)
47+
# 🔵 This file: Mount the home as read-only, /tmp/lima as writable
48+
mounts:
49+
- location: "~"
50+
# Configure the mountPoint inside the guest.
51+
# 🟢 Builtin default: value of location
52+
mountPoint: null
53+
- location: foo
54+
mountPoint: bar
55+
`
56+
out, err := EvaluateExpression(expression, []byte(content))
57+
assert.NilError(t, err)
58+
assert.Equal(t, expected, string(out))
59+
}
60+
61+
func TestEvaluateExpressionError(t *testing.T) {
62+
expression := `arch: aarch64`
63+
_, err := EvaluateExpression(expression, []byte(""))
64+
assert.ErrorContains(t, err, "invalid input text")
65+
}

0 commit comments

Comments
 (0)