diff --git a/src/update/PatchNotes.lua b/src/update/PatchNotes.lua index 3288c4de..5fb503b0 100644 --- a/src/update/PatchNotes.lua +++ b/src/update/PatchNotes.lua @@ -16,6 +16,10 @@ PatchNotes.FILES = { "assets/PATCH_NOTES.md", } +PatchNotes.CACHE_FILES = { + "updates/notes_cache.json", +} + PatchNotes.REPO_FILES = { "mobile/ios/app-repo.json", } @@ -48,6 +52,29 @@ local function readPath(path) return nonempty(text) and text or nil end +function PatchNotes.fromCache(engine) + for _, path in ipairs(PatchNotes.CACHE_FILES) do + local text = readPath(path) + if text then + local ok, doc = pcall(Json.decode, text) + if ok and type(doc) == "table" then + if engine and engine ~= "0.0.0-dev" then + if doc[engine] and nonempty(doc[engine]) then + return doc[engine], engine + end + else + for ver, notes in pairs(doc) do + if nonempty(notes) then + return notes, ver + end + end + end + end + end + end + return nil, nil +end + function PatchNotes.fromFile() for _, path in ipairs(PatchNotes.FILES) do local text = readPath(path) @@ -88,6 +115,7 @@ function PatchNotes.fromRepo(engine) return row.notes, row.version end end + return nil, nil end return list[1].notes, list[1].version end @@ -96,17 +124,24 @@ function PatchNotes.fromRepo(engine) end function PatchNotes.body(Check) - local notes, ver = PatchNotes.fromCheck(Check) - if notes then return notes, ver end - notes = PatchNotes.fromFile() - if notes then return notes, ver end local Version = require("src.core.Version") local engine = (Version and Version.engine) or "?" + + local notes, ver = PatchNotes.fromCheck(Check) + if notes and (engine == "0.0.0-dev" or ver == engine or ver == nil) then + return notes, ver or engine + end + + notes, ver = PatchNotes.fromCache(engine) + if notes then return notes, ver end + + notes = PatchNotes.fromFile() + if notes then return notes, engine end + notes, ver = PatchNotes.fromRepo(engine) if notes then return notes, ver end - return "No patch notes loaded yet for gen1recomp v" .. engine .. ".\n\n" - .. "They appear here after the launcher checks GitHub for the latest " - .. "release.", engine + + return "Unable to fetch patch notes.", engine end return PatchNotes diff --git a/src/update/check_worker.lua b/src/update/check_worker.lua index 7d592ec6..175a5457 100644 --- a/src/update/check_worker.lua +++ b/src/update/check_worker.lua @@ -151,6 +151,28 @@ local function gatePasses(rel) return not (info.minShell and info.minShell > shell) end +local function cacheNotes(ver, notes) + if not (ver and type(notes) == "string" and notes ~= "" and Json) then return end + if not (love and love.filesystem) then return end + pcall(function() + love.filesystem.createDirectory("updates") + local cachePath = "updates/notes_cache.json" + local existing = {} + if love.filesystem.getInfo and love.filesystem.getInfo(cachePath) then + local text = love.filesystem.read(cachePath) + if text then + local ok, doc = pcall(Json.decode, text) + if ok and type(doc) == "table" then existing = doc end + end + end + existing[ver] = notes + local ok, encoded = pcall(Json.encode, existing) + if ok and encoded then + love.filesystem.write(cachePath, encoded) + end + end) +end + -- --------------------------------------------------------------------------- -- check -- --------------------------------------------------------------------------- @@ -177,6 +199,9 @@ local function doCheck() return end pending = rel + if rel.version and type(rel.notes) == "string" and rel.notes ~= "" then + cacheNotes(rel.version, rel.notes) + end -- Unstamped dev build: the working tree always looks "newer", so never -- pester the developer with an update (contract item, Check design). diff --git a/tests/engine/launcher_patch_notes.lua b/tests/engine/launcher_patch_notes.lua index 89fbc9c2..6532006f 100644 --- a/tests/engine/launcher_patch_notes.lua +++ b/tests/engine/launcher_patch_notes.lua @@ -68,6 +68,12 @@ do "stashed notes name a release version") end +do + local notes, ver = PatchNotes.fromRepo("999.999.999") + eq(notes, nil, "fromRepo returns nil when a specific engine version is missing") + eq(ver, nil, "fromRepo version is nil when missing") +end + do local f = assert(io.open("mobile/ios/app-repo.json", "rb")) local list = PatchNotes.parseRepo(f:read("*a")) @@ -78,6 +84,15 @@ do eq(notes, list[2].notes, "fromRepo returns that version's notes") end +do + local oldVersion = package.loaded["src.core.Version"] + package.loaded["src.core.Version"] = { engine = "999.999.999" } + local body, ver = PatchNotes.body(nil) + eq(body, "Unable to fetch patch notes.", "returns Unable to fetch patch notes when version is uncached and unlisted") + eq(ver, "999.999.999", "returns the requested engine version") + package.loaded["src.core.Version"] = oldVersion +end + imp._appPatchNotes = true local modal = drawAndCapture(imp) check(modal:find("Patch notes", 1, true) ~= nil, "the modal titles itself")