Skip to content

Commit eb2a4cd

Browse files
authored
Merge pull request #1359 from afbjorklund/start-yq
Add builtin yq support to lima start command
2 parents 5b9df0e + 511ce35 commit eb2a4cd

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)