From 10cbcd1034a8d382b30d5068b44229f56688d79a Mon Sep 17 00:00:00 2001 From: Jan Dubois Date: Tue, 2 Jan 2024 23:00:51 -0800 Subject: [PATCH] Store Lima version in the instance directory That way future Lima releases can make decisions about default settings based on the Lima version that created the instance instead of the current instance, and settings for existing instances will not change just because the user updated Lima. Signed-off-by: Jan Dubois --- cmd/limactl/start.go | 4 ++ pkg/store/filenames/filenames.go | 1 + pkg/store/instance.go | 46 +++++++++++++++++++ pkg/store/instance_test.go | 9 ++++ .../content/en/docs/dev/Internals/_index.md | 1 + 5 files changed, 61 insertions(+) diff --git a/cmd/limactl/start.go b/cmd/limactl/start.go index 19d26f98322..13a8ae1a2fa 100644 --- a/cmd/limactl/start.go +++ b/cmd/limactl/start.go @@ -23,6 +23,7 @@ import ( "github.com/lima-vm/lima/pkg/store/filenames" "github.com/lima-vm/lima/pkg/templatestore" "github.com/lima-vm/lima/pkg/uiutil" + "github.com/lima-vm/lima/pkg/version" "github.com/lima-vm/lima/pkg/yqutil" "github.com/sirupsen/logrus" "github.com/spf13/cobra" @@ -332,6 +333,9 @@ func createInstance(ctx context.Context, st *creatorState, saveBrokenEditorBuffe if err := os.WriteFile(filePath, st.yBytes, 0o644); err != nil { return nil, err } + if err := os.WriteFile(filepath.Join(instDir, filenames.LimaVersion), []byte(version.Version), 0o444); err != nil { + return nil, err + } inst, err := store.Inspect(st.instName) if err != nil { diff --git a/pkg/store/filenames/filenames.go b/pkg/store/filenames/filenames.go index 466d552d0e1..6615b410feb 100644 --- a/pkg/store/filenames/filenames.go +++ b/pkg/store/filenames/filenames.go @@ -27,6 +27,7 @@ const ( const ( LimaYAML = "lima.yaml" + LimaVersion = "lima-version" // Lima version used to create instance CIDataISO = "cidata.iso" CIDataISODir = "cidata" BaseDisk = "basedisk" diff --git a/pkg/store/instance.go b/pkg/store/instance.go index 27e09d6e2c1..e01610320c8 100644 --- a/pkg/store/instance.go +++ b/pkg/store/instance.go @@ -16,12 +16,14 @@ import ( "text/template" "time" + "github.com/coreos/go-semver/semver" "github.com/docker/go-units" hostagentclient "github.com/lima-vm/lima/pkg/hostagent/api/client" "github.com/lima-vm/lima/pkg/limayaml" "github.com/lima-vm/lima/pkg/store/dirnames" "github.com/lima-vm/lima/pkg/store/filenames" "github.com/lima-vm/lima/pkg/textutil" + "github.com/sirupsen/logrus" ) type Status = string @@ -56,6 +58,7 @@ type Instance struct { Config *limayaml.LimaYAML `json:"config,omitempty"` SSHAddress string `json:"sshAddress,omitempty"` Protected bool `json:"protected"` + LimaVersion string `json:"limaVersion"` } func (inst *Instance) LoadYAML() (*limayaml.LimaYAML, error) { @@ -167,6 +170,16 @@ func Inspect(instName string) (*Instance, error) { } } } + + limaVersionFile := filepath.Join(instDir, filenames.LimaVersion) + if version, err := os.ReadFile(limaVersionFile); err == nil { + inst.LimaVersion = strings.TrimSpace(string(version)) + if _, err = parseLimaVersion(inst.LimaVersion); err != nil { + logrus.Warnf("treating lima version %q from %q as very latest release", inst.LimaVersion, limaVersionFile) + } + } else if !errors.Is(err, os.ErrNotExist) { + inst.Errors = append(inst.Errors, err) + } return inst, nil } @@ -423,3 +436,36 @@ func (inst *Instance) Unprotect() error { inst.Protected = false return nil } + +// parseLimaVersion parses a Lima version string by removing the leading "v" character and +// stripping everything from the first "-" forward (which are `git describe` artifacts and +// not semver pre-release markers). So "v0.19.1-16-gf3dc6ed.m" will be parsed as "0.19.1". +func parseLimaVersion(version string) (*semver.Version, error) { + version = strings.TrimPrefix(version, "v") + version, _, _ = strings.Cut(version, "-") + return semver.NewVersion(version) +} + +// LimaVersionGreaterThan returns true if the Lima version used to create an instance is greater +// than a specific older version. Always returns false if the Lima version is the empty string. +// Unparsable lima versions (like SHA1 commit ids) are treated as the latest version and return true. +// limaVersion is a `github describe` string, not a semantic version. So "0.19.1-16-gf3dc6ed.m" +// will be considered greater than "0.19.1". +func LimaVersionGreaterThan(limaVersion, oldVersion string) bool { + if limaVersion == "" { + return false + } + version, err := parseLimaVersion(limaVersion) + if err != nil { + return true + } + switch version.Compare(*semver.New(oldVersion)) { + case -1: + return false + case +1: + return true + case 0: + return strings.Contains(limaVersion, "-") + } + panic("unreachable") +} diff --git a/pkg/store/instance_test.go b/pkg/store/instance_test.go index bdbbba7d943..0d532673362 100644 --- a/pkg/store/instance_test.go +++ b/pkg/store/instance_test.go @@ -155,3 +155,12 @@ func TestPrintInstanceTableTwo(t *testing.T) { assert.NilError(t, err) assert.Equal(t, tableTwo, buf.String()) } + +func TestLimaVersionGreaterThan(t *testing.T) { + assert.Equal(t, LimaVersionGreaterThan("", "0.1.0"), false) + assert.Equal(t, LimaVersionGreaterThan("0.0.1", "0.1.0"), false) + assert.Equal(t, LimaVersionGreaterThan("0.1.0", "0.1.0"), false) + assert.Equal(t, LimaVersionGreaterThan("0.1.0-2", "0.1.0"), true) + assert.Equal(t, LimaVersionGreaterThan("0.2.0", "0.1.0"), true) + assert.Equal(t, LimaVersionGreaterThan("abacab", "0.1.0"), true) +} diff --git a/website/content/en/docs/dev/Internals/_index.md b/website/content/en/docs/dev/Internals/_index.md index 1089a83c66d..c1cd06ac7c8 100644 --- a/website/content/en/docs/dev/Internals/_index.md +++ b/website/content/en/docs/dev/Internals/_index.md @@ -30,6 +30,7 @@ having to specify an identity explicitly. An instance directory contains the following files: Metadata: +- `lima-version`: the Lima version used to create this instance - `lima.yaml`: the YAML - `protected`: empty file, used by `limactl protect`