From 22b939669650e24a16d044eef658c22d70089e17 Mon Sep 17 00:00:00 2001 From: NiLuJe Date: Tue, 13 Apr 2021 17:54:11 +0200 Subject: [PATCH] Centralize one time migration code after updates (#7531) There have been a couple of these this month, and keeping stuff that should only ever run once piling up in their respective module was getting ugly, especially when it's usually simple stuff (settings, files). So, move everything to a dedicated module, run by reader.lua on startup, and that will actually only do things once, when necessary. --- .../apps/reader/modules/readertypography.lua | 56 +---- frontend/cache.lua | 13 +- frontend/ui/data/onetime_migration.lua | 202 ++++++++++++++++++ frontend/ui/data/settings_migration.lua | 4 +- frontend/ui/screensaver.lua | 23 -- frontend/version.lua | 18 ++ plugins/opds.koplugin/opdsbrowser.lua | 7 - plugins/statistics.koplugin/main.lua | 31 ++- reader.lua | 7 +- 9 files changed, 255 insertions(+), 106 deletions(-) create mode 100644 frontend/ui/data/onetime_migration.lua diff --git a/frontend/apps/reader/modules/readertypography.lua b/frontend/apps/reader/modules/readertypography.lua index 7e263a9f6..5ad82e922 100644 --- a/frontend/apps/reader/modules/readertypography.lua +++ b/frontend/apps/reader/modules/readertypography.lua @@ -12,10 +12,14 @@ local C_ = _.pgettext local T = require("ffi/util").template local Screen = Device.screen +local ReaderTypography = InputContainer:new{} + -- This is used to migrate old hyph settings, and to show the currently -- used hyph dict language in the hyphenation menu. -- It will be completed with info from the LANGUAGES table below. -local HYPH_DICT_NAME_TO_LANG_NAME_TAG = { +-- NOTE: Actual migration is handled in ui/data/onetime_migration, +-- which is why this hash is public. +ReaderTypography.HYPH_DICT_NAME_TO_LANG_NAME_TAG = { ["@none"] = { "@none", "en" }, ["@softhyphens"] = { "@softhyphens", "en" }, ["@algorithm"] = { "@algorithm", "en" }, @@ -93,7 +97,7 @@ local LANGUAGES = { { "zu", {"zul"}, "H ", _("Zulu"), "Zulu.pattern" }, } -local DEFAULT_LANG_TAG = "en-US" -- English_US.pattern is loaded by default in crengine +ReaderTypography.DEFAULT_LANG_TAG = "en-US" -- English_US.pattern is loaded by default in crengine local LANG_TAG_TO_LANG_NAME = {} local LANG_ALIAS_TO_LANG_TAG = {} @@ -106,12 +110,10 @@ for __, v in ipairs(LANGUAGES) do end end if hyph_filename then - HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_filename] = { lang_name, lang_tag } + ReaderTypography.HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_filename] = { lang_name, lang_tag } end end -local ReaderTypography = InputContainer:new{} - function ReaderTypography:init() self.menu_table = {} self.language_submenu = {} @@ -124,44 +126,6 @@ function ReaderTypography:init() self.hyph_force_algorithmic = false self.floating_punctuation = 0 - -- Migrate old readerhyphenation settings (but keep them in case one - -- go back to a previous version) - if G_reader_settings:hasNot("text_lang_default") and G_reader_settings:hasNot("text_lang_fallback") then - local g_text_lang_set = false - local hyph_alg_default = G_reader_settings:readSetting("hyph_alg_default") - if hyph_alg_default then - local dict_info = HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_alg_default] - if dict_info then - G_reader_settings:saveSetting("text_lang_default", dict_info[2]) - g_text_lang_set = true - -- Tweak the other settings if the default hyph algo happens - -- to be one of these: - if hyph_alg_default == "@none" then - G_reader_settings:makeFalse("hyphenation") - elseif hyph_alg_default == "@softhyphens" then - G_reader_settings:makeTrue("hyph_soft_hyphens_only") - elseif hyph_alg_default == "@algorithm" then - G_reader_settings:makeTrue("hyph_force_algorithmic") - end - end - end - local hyph_alg_fallback = G_reader_settings:readSetting("hyph_alg_fallback") - if not g_text_lang_set and hyph_alg_fallback then - local dict_info = HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_alg_fallback] - if dict_info then - G_reader_settings:saveSetting("text_lang_fallback", dict_info[2]) - g_text_lang_set = true - -- We can't really tweak other settings if the hyph algo fallback - -- happens to be @none, @softhyphens, @algortihm... - end - end - if not g_text_lang_set then - -- If nothing migrated, set the fallback to DEFAULT_LANG_TAG, - -- as we'll always have one of text_lang_default/_fallback set. - G_reader_settings:saveSetting("text_lang_fallback", DEFAULT_LANG_TAG) - end - end - local info_text = _([[ Some languages have specific typographic rules: these include hyphenation, line breaking rules, and language specific glyph variants. KOReader will choose one according to the language tag from the book's metadata, but you can select another one. @@ -639,7 +603,7 @@ end function ReaderTypography:getCurrentDefaultHyphDictLanguage() local hyph_dict_name = self.ui.document:getTextMainLangDefaultHyphDictionary() - local dict_info = HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_dict_name] + local dict_info = self.HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_dict_name] if dict_info then hyph_dict_name = dict_info[1] else -- shouldn't happen @@ -703,7 +667,7 @@ function ReaderTypography:onReadSettings(config) -- Migrate old readerhyphenation setting, if one was set if config:hasNot("text_lang") and config:has("hyph_alg") then local hyph_alg = config:readSetting("hyph_alg") - local dict_info = HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_alg] + local dict_info = self.HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_alg] if dict_info then config:saveSetting("text_lang", dict_info[2]) -- Set the other settings if the default hyph algo happens @@ -792,7 +756,7 @@ function ReaderTypography:onReadSettings(config) else self.allow_doc_lang_tag_override = true -- None decided, use default (shouldn't be reached) - self.text_lang_tag = DEFAULT_LANG_TAG + self.text_lang_tag = self.DEFAULT_LANG_TAG logger.dbg("Typography lang: no lang set, using", self.text_lang_tag) end self.ui.document:setTextMainLang(self.text_lang_tag) diff --git a/frontend/cache.lua b/frontend/cache.lua index e7add0d23..5f075cf72 100644 --- a/frontend/cache.lua +++ b/frontend/cache.lua @@ -39,12 +39,6 @@ end local cache_path = DataStorage:getDataDir() .. "/cache/" --- NOTE: Before 2021.04, fontlist used to squat our folder, needlessly polluting our state tracking. -os.remove(cache_path .. "/fontinfo.dat") --- Ditto for Calibre -os.remove(cache_path .. "/calibre-libraries.lua") -os.remove(cache_path .. "/calibre-books.dat") - --[[ -- return a snapshot of disk cached items for subsequent check --]] @@ -160,7 +154,7 @@ function Cache:serialize() -- calculate disk cache size local cached_size = 0 local sorted_caches = {} - for _,file in pairs(self.cached) do + for _, file in pairs(self.cached) do table.insert(sorted_caches, {file=file, time=lfs.attributes(file, "access")}) cached_size = cached_size + (lfs.attributes(file, "size") or 0) end @@ -203,4 +197,9 @@ function Cache:clear() self.current_memsize = 0 end +-- Refresh the disk snapshot (mainly used by ui/data/onetime_migration) +function Cache:refreshSnapshot() + self.cached = getDiskCache() +end + return Cache diff --git a/frontend/ui/data/onetime_migration.lua b/frontend/ui/data/onetime_migration.lua new file mode 100644 index 000000000..a7b61c9bb --- /dev/null +++ b/frontend/ui/data/onetime_migration.lua @@ -0,0 +1,202 @@ +--[[ +Centralizes any and all one time migration concerns. +--]] + +local DataStorage = require("datastorage") +local lfs = require("libs/libkoreader-lfs") +local logger = require("logger") + +-- Date at which the last migration snippet was added +local CURRENT_MIGRATION_DATE = 20210413 + +-- Retrieve the date of the previous migration, if any +local last_migration_date = G_reader_settings:readSetting("last_migration_date", 0) + +-- If there's nothing new to migrate since the last time, we're done. +if last_migration_date == CURRENT_MIGRATION_DATE then + return +end + +-- Keep this in rough chronological order, with a reference to the PR that implemented the change. + +-- Global settings, https://github.com/koreader/koreader/pull/4945 & https://github.com/koreader/koreader/pull/5655 +-- Limit the check to the most recent update. ReaderUI calls this one unconditionally to update docsettings, too. +if last_migration_date < 20191129 then + logger.info("Performing one-time migration for 20191129") + + local SettingsMigration = require("ui/data/settings_migration") + SettingsMigration:migrateSettings(G_reader_settings) +end + +-- ReaderTypography, https://github.com/koreader/koreader/pull/6072 +if last_migration_date < 20200421 then + logger.info("Performing one-time migration for 20200421") + + local ReaderTypography = require("apps/reader/modules/readertypography") + -- Migrate old readerhyphenation settings + -- (but keep them in case one goes back to a previous version) + if G_reader_settings:hasNot("text_lang_default") and G_reader_settings:hasNot("text_lang_fallback") then + local g_text_lang_set = false + local hyph_alg_default = G_reader_settings:readSetting("hyph_alg_default") + if hyph_alg_default then + local dict_info = ReaderTypography.HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_alg_default] + if dict_info then + G_reader_settings:saveSetting("text_lang_default", dict_info[2]) + g_text_lang_set = true + -- Tweak the other settings if the default hyph algo happens to be one of these: + if hyph_alg_default == "@none" then + G_reader_settings:makeFalse("hyphenation") + elseif hyph_alg_default == "@softhyphens" then + G_reader_settings:makeTrue("hyph_soft_hyphens_only") + elseif hyph_alg_default == "@algorithm" then + G_reader_settings:makeTrue("hyph_force_algorithmic") + end + end + end + local hyph_alg_fallback = G_reader_settings:readSetting("hyph_alg_fallback") + if not g_text_lang_set and hyph_alg_fallback then + local dict_info = ReaderTypography.HYPH_DICT_NAME_TO_LANG_NAME_TAG[hyph_alg_fallback] + if dict_info then + G_reader_settings:saveSetting("text_lang_fallback", dict_info[2]) + g_text_lang_set = true + -- We can't really tweak other settings if the hyph algo fallback happens to be + -- @none, @softhyphens, @algortihm... + end + end + if not g_text_lang_set then + -- If nothing migrated, set the fallback to DEFAULT_LANG_TAG, + -- as we'll always have one of text_lang_default/_fallback set. + G_reader_settings:saveSetting("text_lang_fallback", ReaderTypography.DEFAULT_LANG_TAG) + end + end +end + +-- NOTE: ReaderRolling, on the other hand, does some lower-level things @ onReadSettings tied to CRe that would be much harder to factor out. +-- https://github.com/koreader/koreader/pull/1930 +-- NOTE: The Gestures plugin also handles its settings migration on its own, but deals with it sanely. + +-- ScreenSaver, https://github.com/koreader/koreader/pull/7371 +if last_migration_date < 20210306 then + logger.info("Performing one-time migration for 20210306 (1/2)") + + -- Migrate settings from 2021.02 or older. + if G_reader_settings:readSetting("screensaver_type") == "message" then + G_reader_settings:saveSetting("screensaver_type", "disable") + G_reader_settings:makeTrue("screensaver_show_message") + end + if G_reader_settings:has("screensaver_no_background") then + if G_reader_settings:isTrue("screensaver_no_background") then + G_reader_settings:saveSetting("screensaver_background", "none") + end + G_reader_settings:delSetting("screensaver_no_background") + end + if G_reader_settings:has("screensaver_white_background") then + if G_reader_settings:isTrue("screensaver_white_background") then + G_reader_settings:saveSetting("screensaver_background", "white") + end + G_reader_settings:delSetting("screensaver_white_background") + end +end + +-- OPDS, same as above +if last_migration_date < 20210306 then + logger.info("Performing one-time migration for 20210306 (2/2)") + + local opds_servers = G_reader_settings:readSetting("opds_servers") + if opds_servers then + -- Update deprecated URLs & remove deprecated entries + for i = #opds_servers, 1, -1 do + local server = opds_servers[i] + + if server.url == "http://bookserver.archive.org/catalog/" then + server.url = "https://bookserver.archive.org" + elseif server.url == "http://m.gutenberg.org/ebooks.opds/?format=opds" then + server.url = "https://m.gutenberg.org/ebooks.opds/?format=opds" + elseif server.url == "http://www.feedbooks.com/publicdomain/catalog.atom" then + server.url = "https://catalog.feedbooks.com/catalog/public_domain.atom" + end + + if server.title == "Gallica [Fr] [Searchable]" or server.title == "Project Gutenberg [Searchable]" then + table.remove(opds_servers, i) + end + end + G_reader_settings:saveSetting("opds_servers", opds_servers) + end +end + +-- Statistics, https://github.com/koreader/koreader/pull/7471 +if last_migration_date < 20210330 then + logger.info("Performing one-time migration for 20210330") + + -- c.f., PluginLoader + local package_path = package.path + package.path = string.format("%s/?.lua;%s", "plugins/statistics.koplugin", package_path) + local ok, ReaderStatistics = pcall(dofile, "plugins/statistics.koplugin/main.lua") + package.path = package_path + if not ok or not ReaderStatistics then + logger.warn("Error when loading plugins/statistics.koplugin/main.lua:", ReaderStatistics) + else + local settings = G_reader_settings:readSetting("statistics", ReaderStatistics.default_settings) + -- Handle a snafu in 2021.03 that could lead to an empty settings table on fresh installs. + for k, v in pairs(ReaderStatistics.default_settings) do + if settings[k] == nil then + settings[k] = v + end + end + G_reader_settings:saveSetting("statistics", settings) + end +end + +-- ScreenSaver, https://github.com/koreader/koreader/pull/7496 +if last_migration_date < 20210404 then + logger.info("Performing one-time migration for 20210404") + + -- Migrate settings from 2021.03 or older. + if G_reader_settings:has("screensaver_background") then + G_reader_settings:saveSetting("screensaver_img_background", G_reader_settings:readSetting("screensaver_background")) + G_reader_settings:delSetting("screensaver_background") + end +end + +-- Fontlist, cache migration, https://github.com/koreader/koreader/pull/7524 +if last_migration_date < 20210409 then + logger.info("Performing one-time migration for 20210409") + + -- NOTE: Before 2021.04, fontlist used to squat our folder, needlessly polluting our state tracking. + local cache_path = DataStorage:getDataDir() .. "/cache" + local new_path = cache_path .. "/fontlist" + lfs.mkdir(new_path) + local ok, err = os.rename(cache_path .. "/fontinfo.dat", new_path .. "/fontinfo.dat") + if not ok then + logger.warn("os.rename:", err) + end + + -- Make sure Cache gets the memo + local Cache = require("cache") + Cache:refreshSnapshot() +end + +-- Calibre, cache migration, https://github.com/koreader/koreader/pull/7528 +if last_migration_date < 20210412 then + logger.info("Performing one-time migration for 20210412") + + -- Ditto for Calibre + local cache_path = DataStorage:getDataDir() .. "/cache" + local new_path = cache_path .. "/calibre" + lfs.mkdir(new_path) + local ok, err = os.rename(cache_path .. "/calibre-libraries.lua", new_path .. "/libraries.lua") + if not ok then + logger.warn("os.rename:", err) + end + ok, err = os.rename(cache_path .. "/calibre-books.dat", new_path .. "/books.dat") + if not ok then + logger.warn("os.rename:", err) + end + + -- Make sure Cache gets the memo + local Cache = require("cache") + Cache:refreshSnapshot() +end + +-- We're done, store the current migration date +G_reader_settings:saveSetting("last_migration_date", CURRENT_MIGRATION_DATE) diff --git a/frontend/ui/data/settings_migration.lua b/frontend/ui/data/settings_migration.lua index b4bbf9827..d36444259 100644 --- a/frontend/ui/data/settings_migration.lua +++ b/frontend/ui/data/settings_migration.lua @@ -24,7 +24,7 @@ function SettingsMigration:migrateSettings(config) return end - -- Fine-grained CRe margins (#4945) + -- Fine-grained CRe margins (https://github.com/koreader/koreader/pull/4945) if config:has("copt_page_margins") then local old_margins = config:readSetting("copt_page_margins") logger.info("Migrating old", cfg_class, "CRe margin settings: L", old_margins[1], "T", old_margins[2], "R", old_margins[3], "B", old_margins[4]) @@ -36,7 +36,7 @@ function SettingsMigration:migrateSettings(config) config:delSetting("copt_page_margins") end - -- Space condensing to Word spacing + -- Space condensing to Word spacing (https://github.com/koreader/koreader/pull/5655) -- From a single number (space condensing) to a table of 2 numbers ({space width scale, space condensing}). -- Be conservative and don't change space width scale: use 100% if config:hasNot("copt_word_spacing") and config:has("copt_space_condensing") then diff --git a/frontend/ui/screensaver.lua b/frontend/ui/screensaver.lua index a6d9c0bcf..6177916ea 100644 --- a/frontend/ui/screensaver.lua +++ b/frontend/ui/screensaver.lua @@ -23,29 +23,6 @@ local _ = require("gettext") local Screen = Device.screen local T = require("ffi/util").template --- Migrate settings from 2021.02 or older. -if G_reader_settings:readSetting("screensaver_type") == "message" then - G_reader_settings:saveSetting("screensaver_type", "disable") - G_reader_settings:makeTrue("screensaver_show_message") -end -if G_reader_settings:has("screensaver_no_background") then - if G_reader_settings:isTrue("screensaver_no_background") then - G_reader_settings:saveSetting("screensaver_background", "none") - end - G_reader_settings:delSetting("screensaver_no_background") -end -if G_reader_settings:has("screensaver_white_background") then - if G_reader_settings:isTrue("screensaver_white_background") then - G_reader_settings:saveSetting("screensaver_background", "white") - end - G_reader_settings:delSetting("screensaver_white_background") -end --- Migrate settings from 2021.03 or older. -if G_reader_settings:has("screensaver_background") then - G_reader_settings:saveSetting("screensaver_img_background", G_reader_settings:readSetting("screensaver_background")) - G_reader_settings:delSetting("screensaver_background") -end - -- Default settings if G_reader_settings:hasNot("screensaver_show_message") then G_reader_settings:makeFalse("screensaver_show_message") diff --git a/frontend/version.lua b/frontend/version.lua index f07597d62..702949c2f 100644 --- a/frontend/version.lua +++ b/frontend/version.lua @@ -67,4 +67,22 @@ function Version:getShortVersion() return self.short end +--- Returns the release date of the current version of KOReader, YYYYmmdd, in UTC. +--- Technically closer to the build date, but close enough where official builds are concerned ;). +-- @treturn int date +function Version:getBuildDate() + if not self.date then + local lfs = require("libs/libkoreader-lfs") + local mtime = lfs.attributes("git-rev", "modification") + if mtime then + local ts = os.date("!%Y%m%d", mtime) + self.date = tonumber(ts) or 0 + else + -- No git-rev file? + self.date = 0 + end + end + return self.date +end + return Version diff --git a/plugins/opds.koplugin/opdsbrowser.lua b/plugins/opds.koplugin/opdsbrowser.lua index 3e737f9c0..c36b97905 100644 --- a/plugins/opds.koplugin/opdsbrowser.lua +++ b/plugins/opds.koplugin/opdsbrowser.lua @@ -80,13 +80,6 @@ local OPDSBrowser = Menu:extend{ } function OPDSBrowser:init() - -- Update deprecated URLs - for _, server in ipairs(self.opds_servers) do - if server.url == "http://bookserver.archive.org/catalog/" then - server.url = "https://bookserver.archive.org" - end - end - self.item_table = self:genItemTableFromRoot() self.catalog_title = nil Menu.init(self) -- call parent's init() diff --git a/plugins/statistics.koplugin/main.lua b/plugins/statistics.koplugin/main.lua index 9dfdfdd0b..d2f9d208a 100644 --- a/plugins/statistics.koplugin/main.lua +++ b/plugins/statistics.koplugin/main.lua @@ -125,6 +125,19 @@ function ReaderStatistics:isDocless() return self.ui == nil or self.ui.document == nil end +-- NOTE: This is used in a migration script by ui/data/onetime_migration, +-- which is why it's public. +ReaderStatistics.default_settings = { + min_sec = DEFAULT_MIN_READ_SEC, + max_sec = DEFAULT_MAX_READ_SEC, + is_enabled = true, + convert_to_db = nil, + calendar_start_day_of_week = DEFAULT_CALENDAR_START_DAY_OF_WEEK, + calendar_nb_book_spans = DEFAULT_CALENDAR_NB_BOOK_SPANS, + calendar_show_histogram = true, + calendar_browse_future_months = false, +} + function ReaderStatistics:init() if not self:isDocless() and self.ui.document.is_pic then return @@ -132,23 +145,7 @@ function ReaderStatistics:init() self.start_current_period = os.time() self:resetVolatileStats() - local default_settings = { - min_sec = DEFAULT_MIN_READ_SEC, - max_sec = DEFAULT_MAX_READ_SEC, - is_enabled = true, - convert_to_db = nil, - calendar_start_day_of_week = DEFAULT_CALENDAR_START_DAY_OF_WEEK, - calendar_nb_book_spans = DEFAULT_CALENDAR_NB_BOOK_SPANS, - calendar_show_histogram = true, - calendar_browse_future_months = false, - } - self.settings = G_reader_settings:readSetting("statistics", default_settings) - -- Handle a snafu in 2021.03 that could lead to an empty settings table on fresh installs. - for k, v in pairs(default_settings) do - if self.settings[k] == nil then - self.settings[k] = v - end - end + self.settings = G_reader_settings:readSetting("statistics", self.default_settings) self.ui.menu:registerToMainMenu(self) self:checkInitDatabase() diff --git a/reader.lua b/reader.lua index 0f97da2bb..88b2fe225 100755 --- a/reader.lua +++ b/reader.lua @@ -172,14 +172,13 @@ if Device:hasEinkScreen() then end end --- Handle global settings migration -local SettingsMigration = require("ui/data/settings_migration") -SettingsMigration:migrateSettings(G_reader_settings) - -- Document renderers canvas local CanvasContext = require("document/canvascontext") CanvasContext:init(Device) +-- Handle one time migration stuff (settings, deprecation, ...) in case of an upgrade... +require("ui/data/onetime_migration") + -- Touch screen (this may display some widget, on first install on Kobo Touch, -- so have it done after CanvasContext:init() but before Bidi.setup() to not -- have mirroring mess x/y probing).