Skip to content
New issue

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

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

Already on GitHub? # to your account

Improve limactl edit #2593

Merged
merged 1 commit into from
Sep 16, 2024
Merged

Conversation

norio-nomura
Copy link
Contributor

  • yqutil: use yamlfmt to fix indentation of sequence
  • limactl edit: support editing lima.yaml file
    This allows limactl edit --set "..." <limayaml> to be used instead of yq -i eval "..." <limayaml> in scripts like hack/inject-cmdline-to-template.sh.

The changes made to examples/ubuntu.yaml using limactl edit --set in hack/inject-cmdline-to-template.sh are as follows:

diff --git forkSrcPrefix/examples/ubuntu.yaml forkDstPrefix/examples/ubuntu.yaml
index a7fb0b3246e71bd9f98df2e8849185ed1339c76b..9f19540104091b13e08cf255bd074831560af654 100644
--- forkSrcPrefix/examples/ubuntu.yaml
+++ forkDstPrefix/examples/ubuntu.yaml
@@ -7,13 +7,19 @@ images:
 - location: "https://cloud-images.ubuntu.com/releases/24.04/release-20240821/ubuntu-24.04-server-cloudimg-arm64.img"
   arch: "aarch64"
   digest: "sha256:5ecac6447be66a164626744a87a27fd4e6c6606dc683e0a233870af63df4276a"
+  kernel:
+    location: https://cloud-images.ubuntu.com/releases/24.04/release-20240821/unpacked/ubuntu-24.04-server-cloudimg-arm64-vmlinuz-generic
+    digest: sha256:69e66230d6acc503082f098fd072a672a804774007209110b353d25bb7007669
+    cmdline: root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyAMA0 console=hvc0
+  initrd:
+    location: https://cloud-images.ubuntu.com/releases/24.04/release-20240821/unpacked/ubuntu-24.04-server-cloudimg-arm64-initrd-generic
+    digest: sha256:92acf9f2976b7a8b3b5e9e3f22211d17a6fdb3f2aed981467f91cd6dbfa16ae5
 # Fallback to the latest release image.
 # Hint: run `limactl prune` to invalidate the cache
 - location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
   arch: "x86_64"
 - location: "https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-arm64.img"
   arch: "aarch64"
-
 mounts:
 - location: "~"
 - location: "/tmp/lima"

The issue with line breaks disappearing cannot be fixed with yamlfmt, so it still remains. However, the sequence is no longer indented, and I personally think it has become usable.

I'm considering making a separate PR to change hack/inject-cmdline-to-template.sh from yq -i eval to limactl edit --set after #2562, which is likely to have overlapping changes, is resolved.

@@ -58,6 +59,8 @@ require (
github.com/VividCortex/ewma v1.2.0 // indirect
github.com/a8m/envsubst v1.4.2 // indirect
github.com/alecthomas/participle/v2 v2.1.1 // indirect
github.com/bmatcuk/doublestar/v4 v4.6.0 // indirect
github.com/braydonk/yaml v0.7.0 // indirect
Copy link
Member

Choose a reason for hiding this comment

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

Not a huge fan of importing multiple YAML libraries

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is this the fifth YAML library?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, is this the first time a YAML library forked from https://github.com/go-yaml/yaml is being added?

This comment was marked as off-topic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I want to express my gratitude to Go for allowing the use of both a forked library and the original library simultaneously without causing issues. 👏🏻

Copy link
Member

Choose a reason for hiding this comment

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

I think both of yqlib and yamlfmt brings enough value, to be allowed to bring-their-own-yaml to the party

@jandubois
Copy link
Member

Tests are failing on Windows because it is adding \r\n line endings to the YAML file instead of sticking to plain newlines.

@afbjorklund
Copy link
Member

afbjorklund commented Sep 9, 2024

I like this new library, with some configuration it can actually keep the examples/default.yaml more or less as-is:

.yamlfmt

line_ending: lf
formatter:
    indentless_arrays: true
    retain_line_breaks: true

The only change is some alignment on the comments, and I don't think that is too bad (and yamllint is OK too)

yamlfmt examples/default.yaml

--- a/examples/default.yaml
+++ b/examples/default.yaml
@@ -264,10 +264,10 @@ containerd:
 # Setting of instructions is supported like this: "qemu64,+ssse3".
 # 🟢 Builtin default: hard-coded arch map with type (see the output of `limactl info | jq .defaultTemplate.cpuType`)
 cpuType:
-  # aarch64: "cortex-a72" # (or "host" when running on aarch64 host)
-  # armv7l: "cortex-a7" # (or "host" when running on armv7l host)
-  # riscv64: "rv64" # (or "host" when running on riscv64 host)
-  # x86_64: "qemu64" # (or "host,-pdpe1gb" when running on x86_64 host)
+# aarch64: "cortex-a72" # (or "host" when running on aarch64 host)
+# armv7l: "cortex-a7" # (or "host" when running on armv7l host)
+# riscv64: "rv64" # (or "host" when running on riscv64 host)
+# x86_64: "qemu64" # (or "host,-pdpe1gb" when running on x86_64 host)
 
 rosetta:
   # Enable Rosetta for Linux (EXPERIMENTAL; will graduate from experimental in Lima v1.0).
@@ -456,8 +456,8 @@ hostResolver:
   # predefined to specify the gateway address to the host.
   # 🟢 Builtin default: null
   hosts:
-    # guest.name: 127.1.1.1
-    # host.name: host.lima.internal
+  # guest.name: 127.1.1.1
+  # host.name: host.lima.internal
 
 # If hostResolver.enabled is false, then the following rules apply for configuring dns:
 # Explicitly set DNS addresses for qemu user-mode networking. By default qemu picks *one*

Copy link
Member

@jandubois jandubois left a comment

Choose a reason for hiding this comment

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

I agree with @afbjorklund that the new libraries provide sufficient value to justify adding one more YAML library to the project.

I think the fact that limactl edit can now edit templates in addition to instances should be noted in the command descriptions:

-		Use:               "edit INSTANCE",
-		Short:             "Edit an instance of Lima",
+		Use:               "edit INSTANCE|FILE.yaml",
+		Short:             "Edit an instance of Lima or a template",

@jandubois
Copy link
Member

Please squash commits!

Signed-off-by: Norio Nomura <norio.nomura@gmail.com>

`limactl edit`: support editing lima.yaml file

This allows `limactl edit --set "..." <limayaml>` to be used instead of `yq -i eval "..." <limayaml>` in scripts like `hack/inject-cmdline-to-template.sh`.

Signed-off-by: Norio Nomura <norio.nomura@gmail.com>

yqutil: Use `LF` for line endings regardless of the platform.

Signed-off-by: Norio Nomura <norio.nomura@gmail.com>

`limactl edit`: update command description

Signed-off-by: Norio Nomura <norio.nomura@gmail.com>

yqutil_test: fix typo

Signed-off-by: Norio Nomura <norio.nomura@gmail.com>
Copy link
Member

@jandubois jandubois left a comment

Choose a reason for hiding this comment

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

Thanks, LGTM

@jandubois
Copy link
Member

@AkihiroSuda Do you have any objections to merging this?

@jandubois
Copy link
Member

The issue with line breaks disappearing cannot be fixed with yamlfmt, so it still remains.

Super-hacky idea: Replace all empty lines with ### this is an empty line ### before editing the file, and then replace them back with empty lines after yamlfmt is done.

@AkihiroSuda AkihiroSuda added this to the v1.0 milestone Sep 15, 2024
@AkihiroSuda AkihiroSuda added the area/cli limactl CLI user experience label Sep 15, 2024
@norio-nomura
Copy link
Contributor Author

Super-hacky idea: Replace all empty lines with ### this is an empty line ### before editing the file, and then replace them back with empty lines after yamlfmt is done.

That's exactly the idea that yamlfmt adopts.
https://github.com/google/yamlfmt/blob/main/internal/hotfix/retain_line_break.go

@norio-nomura
Copy link
Contributor Author

norio-nomura commented Sep 15, 2024

That's exactly the idea that yamlfmt adopts

Oh, it seems that the following hack works well:

diff --git forkSrcPrefix/pkg/yqutil/yqutil.go forkDstPrefix/pkg/yqutil/yqutil.go
index 139d9fcbce3ff6c7ca3df38a04a1fb3ef36ccc1b..8787797f40b6e0a8fcaec1f06b203b25e8ba3c06 100644
--- forkSrcPrefix/pkg/yqutil/yqutil.go
+++ forkDstPrefix/pkg/yqutil/yqutil.go
@@ -1,6 +1,7 @@
 package yqutil
 
 import (
+	"bufio"
 	"bytes"
 	"fmt"
 	"os"
@@ -15,13 +16,17 @@ import (
 // EvaluateExpression evaluates the yq expression, and returns the modified yaml.
 func EvaluateExpression(expression string, content []byte) ([]byte, error) {
 	logrus.Debugf("Evaluating yq expression: %q", expression)
+	contentModified, err := replaceLineBreaksWithMagicString(content)
+	if err != nil {
+		return nil, err
+	}
 	tmpYAMLFile, err := os.CreateTemp("", "lima-yq-*.yaml")
 	if err != nil {
 		return nil, err
 	}
 	tmpYAMLPath := tmpYAMLFile.Name()
 	defer os.RemoveAll(tmpYAMLPath)
-	_, err = tmpYAMLFile.Write(content)
+	_, err = tmpYAMLFile.Write(contentModified)
 	if err != nil {
 		tmpYAMLFile.Close()
 		return nil, err
@@ -94,3 +99,41 @@ func yamlfmt(content []byte) ([]byte, error) {
 	}
 	return formatter.Format(content)
 }
+
+const yamlfmtLineBreakPlaceholder = "#magic___^_^___line"
+
+type paddinger struct {
+	strings.Builder
+}
+
+func (p *paddinger) adjust(txt string) {
+	var indentSize int
+	for i := 0; i < len(txt) && txt[i] == ' '; i++ { // yaml only allows space to indent.
+		indentSize++
+	}
+	// Grows if the given size is larger than us and always return the max padding.
+	for diff := indentSize - p.Len(); diff > 0; diff-- {
+		p.WriteByte(' ')
+	}
+}
+
+func replaceLineBreaksWithMagicString(content []byte) ([]byte, error) {
+	// hotfix: yq does not support line breaks in the middle of a string.
+	var buf bytes.Buffer
+	reader := bytes.NewReader(content)
+	scanner := bufio.NewScanner(reader)
+	var padding paddinger
+	for scanner.Scan() {
+		txt := scanner.Text()
+		padding.adjust(txt)
+		if strings.TrimSpace(txt) == "" { // line break or empty space line.
+			buf.WriteString(padding.String()) // prepend some padding incase literal multiline strings.
+			buf.WriteString(yamlfmtLineBreakPlaceholder)
+			buf.WriteString("\n")
+		} else {
+			buf.WriteString(txt)
+			buf.WriteString("\n")
+		}
+	}
+	return buf.Bytes(), scanner.Err()
+}
diff --git forkSrcPrefix/pkg/yqutil/yqutil_test.go forkDstPrefix/pkg/yqutil/yqutil_test.go
index fcf1260ec24519a847a9305d978144f0bbdbe7cc..287c51c6be2d13bd75a7984712f0d4aad492fb0b 100644
--- forkSrcPrefix/pkg/yqutil/yqutil_test.go
+++ forkDstPrefix/pkg/yqutil/yqutil_test.go
@@ -19,6 +19,7 @@ memory: null
 	expected := `
 # CPUs
 cpus: 2
+
 # Memory size
 memory: 2GiB
 `

🤔

(edited: add yqutil_test.go to patch)

@norio-nomura
Copy link
Contributor Author

The changes after running limactl edit templates/default.yaml --memory 8 using the above patch are as follows:

diff --git forkSrcPrefix/examples/default.yaml forkDstPrefix/examples/default.yaml
index 5b269ff7e25530c16ce7a9c4fd00251a35850b0d..c46886072da9ff064754da989698e618daa787e8 100644
--- forkSrcPrefix/examples/default.yaml
+++ forkDstPrefix/examples/default.yaml
@@ -43,7 +43,7 @@ cpus: null
 
 # Memory size
 # 🟢 Builtin default: min("4GiB", half of host memory)
-memory: null
+memory: 8GiB
 
 # Disk size
 # 🟢 Builtin default: "100GiB"
@@ -264,10 +264,10 @@ containerd:
 # Setting of instructions is supported like this: "qemu64,+ssse3".
 # 🟢 Builtin default: hard-coded arch map with type (see the output of `limactl info | jq .defaultTemplate.cpuType`)
 cpuType:
-  # aarch64: "cortex-a72" # (or "host" when running on aarch64 host)
-  # armv7l: "cortex-a7" # (or "host" when running on armv7l host)
-  # riscv64: "rv64" # (or "host" when running on riscv64 host)
-  # x86_64: "qemu64" # (or "host,-pdpe1gb" when running on x86_64 host)
+# aarch64: "cortex-a72" # (or "host" when running on aarch64 host)
+# armv7l: "cortex-a7" # (or "host" when running on armv7l host)
+# riscv64: "rv64" # (or "host" when running on riscv64 host)
+# x86_64: "qemu64" # (or "host,-pdpe1gb" when running on x86_64 host)
 
 rosetta:
   # Enable Rosetta for Linux (EXPERIMENTAL; will graduate from experimental in Lima v1.0).
@@ -456,8 +456,8 @@ hostResolver:
   # predefined to specify the gateway address to the host.
   # 🟢 Builtin default: null
   hosts:
-    # guest.name: 127.1.1.1
-    # host.name: host.lima.internal
+  # guest.name: 127.1.1.1
+  # host.name: host.lima.internal
 
 # If hostResolver.enabled is false, then the following rules apply for configuring dns:
 # Explicitly set DNS addresses for qemu user-mode networking. By default qemu picks *one*

@jandubois
Copy link
Member

jandubois commented Sep 16, 2024

Oh, it seems that the following hack works well:

If you create a PR with that hack (which I would like to see once the current PR is merged), then I would suggest that we should also fix up the templates so that the comments round-trip correctly (all comments should be in front of the setting they apply to, and not after it).

Then we can add a check to CI to make sure they remain round-trippable. Something like

find examples -name '*.yaml' -exec limactl edit --set 'del(.nothing)' {} \;
git diff-index --exit-code HEAD

@jandubois
Copy link
Member

@AkihiroSuda I'll take the fact that you assigned this PR to the 1.0 milestone as agreement to merge. I was waiting for your feedback because you originally commented:

Not a huge fan of importing multiple YAML libraries

So I wasn't sure if you still had objections to merging it or not. But I guess you are ok with it now.

@jandubois jandubois merged commit 133979a into lima-vm:master Sep 16, 2024
27 checks passed
@norio-nomura norio-nomura deleted the improve-limactl-edit branch September 16, 2024 00:23
@norio-nomura
Copy link
Contributor Author

Thanks! 🙏🏻

Then we can add a check to CI to make sure they remain round-trippable.

Before doing that, I want to finalize #2532.

@AkihiroSuda
Copy link
Member

@AkihiroSuda I'll take the fact that you assigned this PR to the 1.0 milestone as agreement to merge. I was waiting for your feedback because you originally commented:

Not a huge fan of importing multiple YAML libraries

So I wasn't sure if you still had objections to merging it or not. But I guess you are ok with it now.

Yes, ok to merge, sorry for delay
🙇‍♂️

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
area/cli limactl CLI user experience
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants