Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add builtin yq support to lima start command #1359

Merged
merged 1 commit into from
Feb 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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"'
```

Comment on lines +179 to +183
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we need to include a reference to the yq documentation, so people can learn to construct more powerful expressions for e.g. scripting:

$ limactl start --set '.env.HOSTPATH=strenv(PATH)' template://alpine

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expected the same syntax to be available for the limactl edit command as well.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I should have specified: I would expect limactl edit --set ... to just edit the config, but not to invoke an editor.

It would just be a mechanism to modify the config programmatically without starting the instance.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use something like --eval, since that is the name of the yq command being invoked ?

Available Commands:
  completion       Generate the autocompletion script for the specified shell
  eval             (default) Apply the expression to each document in each yaml file in sequence
  eval-all         Loads _all_ yaml documents of _all_ yaml files and runs expression once
  help             Help about any command
  shell-completion Generate completion script

I agree that --set is somewhat misleading, and that --yq might be a bit cryptic for lima users...

Adding it to edit should be straight-forward.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect limactl edit --set ... to just edit the config, but not to invoke an editor.

👍

--eval sounds much more misleading

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

limactl edit --set can be another PR if complicated

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error handling can be a bit tricky to do, so I'd like that.

To see the template list:
```console
$ limactl start --list-templates
Expand Down
29 changes: 29 additions & 0 deletions cmd/limactl/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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

Expand All @@ -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
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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),
Expand Down
4 changes: 4 additions & 0 deletions docs/experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
9 changes: 9 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
22 changes: 22 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand All @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand All @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
66 changes: 66 additions & 0 deletions pkg/yqutil/yqutil.go
Original file line number Diff line number Diff line change
@@ -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:
afbjorklund marked this conversation as resolved.
Show resolved Hide resolved
entry.Info(message)
case logging.INFO:
entry.Info(message)
case logging.DEBUG:
entry.Debug(message)
}
}
return nil, err
}

return out.Bytes(), nil

}
65 changes: 65 additions & 0 deletions pkg/yqutil/yqutil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package yqutil

import (
"testing"

"gotest.tools/v3/assert"
)

func TestEvaluateExpressionSimple(t *testing.T) {
expression := `.cpus = 2 | .memory = "2GiB"`
afbjorklund marked this conversation as resolved.
Show resolved Hide resolved
content := `
# CPUs
cpus: null

# Memory size
memory: null
`
// Note: yq currently removes empty lines, but not comments
afbjorklund marked this conversation as resolved.
Show resolved Hide resolved
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
afbjorklund marked this conversation as resolved.
Show resolved Hide resolved
// 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")
}