From 63d79fe294b5eaac78a7e68b152fdd0378a5edfa Mon Sep 17 00:00:00 2001 From: Jan De Dobbeleer Date: Wed, 6 Nov 2024 17:02:19 +0100 Subject: [PATCH] fix(upgrade): restore caching mechanism --- src/config/migrate.go | 27 +++++++++-- src/config/migrate_test.go | 6 +-- src/properties/map.go | 2 + src/segments/upgrade.go | 60 ++++++++++++++++++++---- src/segments/upgrade_test.go | 23 +++++++++ website/docs/segments/system/upgrade.mdx | 10 ++++ 6 files changed, 110 insertions(+), 18 deletions(-) diff --git a/src/config/migrate.go b/src/config/migrate.go index 2adf50b3..0c899f5f 100644 --- a/src/config/migrate.go +++ b/src/config/migrate.go @@ -30,10 +30,16 @@ func (segment *Segment) migrate(version int) { // Cache settings delete(segment.Properties, "cache_version") - segment.Cache = segment.migrateCache() segment.IncludeFolders = segment.migrateFolders(includeFolders) segment.ExcludeFolders = segment.migrateFolders(excludeFolders) + + switch segment.Type { //nolint:exhaustive + case UPGRADE: + segment.timeoutToDuration() + default: + segment.timeoutToCache() + } } func (segment *Segment) hasProperty(property properties.Property) bool { @@ -45,24 +51,35 @@ func (segment *Segment) hasProperty(property properties.Property) bool { return false } -func (segment *Segment) migrateCache() *cache.Config { +func (segment *Segment) timeoutToCache() { if !segment.hasProperty(cacheTimeout) { - return nil + return } timeout := segment.Properties.GetInt(cacheTimeout, 0) delete(segment.Properties, cacheTimeout) if timeout == 0 { - return nil + return } - return &cache.Config{ + segment.Cache = &cache.Config{ Duration: cache.ToDuration(timeout * 60), Strategy: cache.Folder, } } +func (segment *Segment) timeoutToDuration() { + timeout := segment.Properties.GetInt(cacheTimeout, 0) + delete(segment.Properties, cacheTimeout) + + if timeout == 0 { + return + } + + segment.Properties[properties.CacheDuration] = cache.ToDuration(timeout * 60) +} + func (segment *Segment) migrateFolders(property properties.Property) []string { if !segment.hasProperty(property) { return []string{} diff --git a/src/config/migrate_test.go b/src/config/migrate_test.go index 5cb1a7d8..61a648b0 100644 --- a/src/config/migrate_test.go +++ b/src/config/migrate_test.go @@ -9,7 +9,7 @@ import ( "github.com/stretchr/testify/assert" ) -func TestMigrateCache(t *testing.T) { +func TestTimeoutToCache(t *testing.T) { cases := []struct { Expected *cache.Config Case string @@ -27,8 +27,8 @@ func TestMigrateCache(t *testing.T) { }, } - got := segment.migrateCache() - assert.Equal(t, tc.Expected, got, tc.Case) + segment.timeoutToCache() + assert.Equal(t, tc.Expected, segment.Cache, tc.Case) } } diff --git a/src/properties/map.go b/src/properties/map.go index 3408c4b2..e62e899a 100644 --- a/src/properties/map.go +++ b/src/properties/map.go @@ -45,6 +45,8 @@ const ( DefaultHTTPTimeout = 20 // Files to trigger the segment on Files Property = "files" + // Duration of the cache + CacheDuration Property = "cache_duration" ) type Map map[Property]any diff --git a/src/segments/upgrade.go b/src/segments/upgrade.go index e7d65eda..53030bac 100644 --- a/src/segments/upgrade.go +++ b/src/segments/upgrade.go @@ -1,11 +1,16 @@ package segments import ( + "encoding/json" + "errors" + "github.com/jandedobbeleer/oh-my-posh/src/build" + "github.com/jandedobbeleer/oh-my-posh/src/cache" + "github.com/jandedobbeleer/oh-my-posh/src/properties" "github.com/jandedobbeleer/oh-my-posh/src/upgrade" ) -type upgradeData struct { +type UpgradeCache struct { Latest string `json:"latest"` Current string `json:"current"` } @@ -16,36 +21,71 @@ type Upgrade struct { // deprecated Version string - upgradeData + UpgradeCache } +const ( + UPGRADECACHEKEY = "upgrade_segment" +) + func (u *Upgrade) Template() string { return " \uf019 " } func (u *Upgrade) Enabled() bool { u.Current = build.Version - - latest, err := u.checkUpdate(u.Current) + latest, err := u.cachedLatest(u.Current) + if err != nil { + latest, err = u.checkUpdate(u.Current) + } if err != nil || u.Current == latest.Latest { return false } - u.upgradeData = *latest + u.UpgradeCache = *latest u.Version = u.Latest return true } -func (u *Upgrade) checkUpdate(current string) (*upgradeData, error) { +func (u *Upgrade) cachedLatest(current string) (*UpgradeCache, error) { + data, ok := u.env.Cache().Get(UPGRADECACHEKEY) + if !ok { + return nil, errors.New("no cache data") + } + + var cacheJSON UpgradeCache + err := json.Unmarshal([]byte(data), &cacheJSON) + if err != nil { + return nil, err // invalid cache data + } + + if current != cacheJSON.Current { + return nil, errors.New("version changed, run the check again") + } + + return &cacheJSON, nil +} + +func (u *Upgrade) checkUpdate(current string) (*UpgradeCache, error) { tag, err := upgrade.Latest(u.env) if err != nil { return nil, err } - return &upgradeData{ - // strip leading v - Latest: tag[1:], + latest := tag[1:] + cacheData := &UpgradeCache{ + Latest: latest, Current: current, - }, nil + } + cacheJSON, err := json.Marshal(cacheData) + if err != nil { + return nil, err + } + + // update cache + duration := u.props.GetString(properties.CacheDuration, string(cache.ONEWEEK)) + u.env.Cache().Set(UPGRADECACHEKEY, string(cacheJSON), cache.Duration(duration)) + + return cacheData, nil } diff --git a/src/segments/upgrade_test.go b/src/segments/upgrade_test.go index 5f8a663b..5dcc2f10 100644 --- a/src/segments/upgrade_test.go +++ b/src/segments/upgrade_test.go @@ -6,11 +6,13 @@ import ( "testing" "github.com/jandedobbeleer/oh-my-posh/src/build" + cache_ "github.com/jandedobbeleer/oh-my-posh/src/cache/mock" "github.com/jandedobbeleer/oh-my-posh/src/properties" "github.com/jandedobbeleer/oh-my-posh/src/runtime/mock" "github.com/jandedobbeleer/oh-my-posh/src/upgrade" "github.com/alecthomas/assert" + testify_ "github.com/stretchr/testify/mock" ) func TestUpgrade(t *testing.T) { @@ -38,21 +40,42 @@ func TestUpgrade(t *testing.T) { Case: "Error on update check", Error: errors.New("error"), }, + { + Case: "On previous, from cache", + HasCache: true, + CurrentVersion: "1.0.2", + LatestVersion: "1.0.3", + CachedVersion: "1.0.2", + ExpectedEnabled: true, + }, { Case: "On latest, version changed", + HasCache: true, CurrentVersion: "1.0.2", LatestVersion: "1.0.2", + CachedVersion: "1.0.1", }, { Case: "On previous, version changed", + HasCache: true, CurrentVersion: "1.0.2", LatestVersion: "1.0.3", + CachedVersion: "1.0.1", ExpectedEnabled: true, }, } for _, tc := range cases { env := new(mock.Environment) + cache := &cache_.Cache{} + + env.On("Cache").Return(cache) + if len(tc.CachedVersion) == 0 { + tc.CachedVersion = tc.CurrentVersion + } + cacheData := fmt.Sprintf(`{"latest":"%s", "current": "%s"}`, tc.LatestVersion, tc.CachedVersion) + cache.On("Get", UPGRADECACHEKEY).Return(cacheData, tc.HasCache) + cache.On("Set", testify_.Anything, testify_.Anything, testify_.Anything) build.Version = tc.CurrentVersion diff --git a/website/docs/segments/system/upgrade.mdx b/website/docs/segments/system/upgrade.mdx index 3fe43770..16a559c7 100644 --- a/website/docs/segments/system/upgrade.mdx +++ b/website/docs/segments/system/upgrade.mdx @@ -18,9 +18,18 @@ import Config from "@site/src/components/Config.js"; style: "plain", foreground: "#111111", background: "#FFD664", + properties: { + cache_duration: "168h", + }, }} /> +## Properties + +| Name | Type | Default | Description | +| ---------------- | :------: | :-----: | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `cache_duration` | `string` | `` | the duration for which the segment will be cached. The duration is a string in the format `1h2m3s`. The duration is parsed using the [time.ParseDuration] function from the Go standard library | + ## Template ([info][templates]) :::note default template @@ -39,3 +48,4 @@ import Config from "@site/src/components/Config.js"; | `.Latest` | `string` | the latest available version number | [templates]: /docs/configuration/templates +[time.ParseDuration]: https://golang.org/pkg/time/#ParseDuration