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.
pull/7546/head
NiLuJe 3 years ago committed by GitHub
parent f2e90f505b
commit 22b9396696
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -12,10 +12,14 @@ local C_ = _.pgettext
local T = require("ffi/util").template local T = require("ffi/util").template
local Screen = Device.screen local Screen = Device.screen
local ReaderTypography = InputContainer:new{}
-- This is used to migrate old hyph settings, and to show the currently -- This is used to migrate old hyph settings, and to show the currently
-- used hyph dict language in the hyphenation menu. -- used hyph dict language in the hyphenation menu.
-- It will be completed with info from the LANGUAGES table below. -- 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" }, ["@none"] = { "@none", "en" },
["@softhyphens"] = { "@softhyphens", "en" }, ["@softhyphens"] = { "@softhyphens", "en" },
["@algorithm"] = { "@algorithm", "en" }, ["@algorithm"] = { "@algorithm", "en" },
@ -93,7 +97,7 @@ local LANGUAGES = {
{ "zu", {"zul"}, "H ", _("Zulu"), "Zulu.pattern" }, { "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_TAG_TO_LANG_NAME = {}
local LANG_ALIAS_TO_LANG_TAG = {} local LANG_ALIAS_TO_LANG_TAG = {}
@ -106,12 +110,10 @@ for __, v in ipairs(LANGUAGES) do
end end
end end
if hyph_filename then 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
end end
local ReaderTypography = InputContainer:new{}
function ReaderTypography:init() function ReaderTypography:init()
self.menu_table = {} self.menu_table = {}
self.language_submenu = {} self.language_submenu = {}
@ -124,44 +126,6 @@ function ReaderTypography:init()
self.hyph_force_algorithmic = false self.hyph_force_algorithmic = false
self.floating_punctuation = 0 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 = _([[ local info_text = _([[
Some languages have specific typographic rules: these include hyphenation, line breaking rules, and language specific glyph variants. 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. 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() function ReaderTypography:getCurrentDefaultHyphDictLanguage()
local hyph_dict_name = self.ui.document:getTextMainLangDefaultHyphDictionary() 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 if dict_info then
hyph_dict_name = dict_info[1] hyph_dict_name = dict_info[1]
else -- shouldn't happen else -- shouldn't happen
@ -703,7 +667,7 @@ function ReaderTypography:onReadSettings(config)
-- Migrate old readerhyphenation setting, if one was set -- Migrate old readerhyphenation setting, if one was set
if config:hasNot("text_lang") and config:has("hyph_alg") then if config:hasNot("text_lang") and config:has("hyph_alg") then
local hyph_alg = config:readSetting("hyph_alg") 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 if dict_info then
config:saveSetting("text_lang", dict_info[2]) config:saveSetting("text_lang", dict_info[2])
-- Set the other settings if the default hyph algo happens -- Set the other settings if the default hyph algo happens
@ -792,7 +756,7 @@ function ReaderTypography:onReadSettings(config)
else else
self.allow_doc_lang_tag_override = true self.allow_doc_lang_tag_override = true
-- None decided, use default (shouldn't be reached) -- 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) logger.dbg("Typography lang: no lang set, using", self.text_lang_tag)
end end
self.ui.document:setTextMainLang(self.text_lang_tag) self.ui.document:setTextMainLang(self.text_lang_tag)

@ -39,12 +39,6 @@ end
local cache_path = DataStorage:getDataDir() .. "/cache/" 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 -- return a snapshot of disk cached items for subsequent check
--]] --]]
@ -160,7 +154,7 @@ function Cache:serialize()
-- calculate disk cache size -- calculate disk cache size
local cached_size = 0 local cached_size = 0
local sorted_caches = {} 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")}) table.insert(sorted_caches, {file=file, time=lfs.attributes(file, "access")})
cached_size = cached_size + (lfs.attributes(file, "size") or 0) cached_size = cached_size + (lfs.attributes(file, "size") or 0)
end end
@ -203,4 +197,9 @@ function Cache:clear()
self.current_memsize = 0 self.current_memsize = 0
end end
-- Refresh the disk snapshot (mainly used by ui/data/onetime_migration)
function Cache:refreshSnapshot()
self.cached = getDiskCache()
end
return Cache return Cache

@ -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)

@ -24,7 +24,7 @@ function SettingsMigration:migrateSettings(config)
return return
end end
-- Fine-grained CRe margins (#4945) -- Fine-grained CRe margins (https://github.com/koreader/koreader/pull/4945)
if config:has("copt_page_margins") then if config:has("copt_page_margins") then
local old_margins = config:readSetting("copt_page_margins") 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]) 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") config:delSetting("copt_page_margins")
end 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}). -- 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% -- Be conservative and don't change space width scale: use 100%
if config:hasNot("copt_word_spacing") and config:has("copt_space_condensing") then if config:hasNot("copt_word_spacing") and config:has("copt_space_condensing") then

@ -23,29 +23,6 @@ local _ = require("gettext")
local Screen = Device.screen local Screen = Device.screen
local T = require("ffi/util").template 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 -- Default settings
if G_reader_settings:hasNot("screensaver_show_message") then if G_reader_settings:hasNot("screensaver_show_message") then
G_reader_settings:makeFalse("screensaver_show_message") G_reader_settings:makeFalse("screensaver_show_message")

@ -67,4 +67,22 @@ function Version:getShortVersion()
return self.short return self.short
end 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 return Version

@ -80,13 +80,6 @@ local OPDSBrowser = Menu:extend{
} }
function OPDSBrowser:init() 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.item_table = self:genItemTableFromRoot()
self.catalog_title = nil self.catalog_title = nil
Menu.init(self) -- call parent's init() Menu.init(self) -- call parent's init()

@ -125,6 +125,19 @@ function ReaderStatistics:isDocless()
return self.ui == nil or self.ui.document == nil return self.ui == nil or self.ui.document == nil
end 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() function ReaderStatistics:init()
if not self:isDocless() and self.ui.document.is_pic then if not self:isDocless() and self.ui.document.is_pic then
return return
@ -132,23 +145,7 @@ function ReaderStatistics:init()
self.start_current_period = os.time() self.start_current_period = os.time()
self:resetVolatileStats() self:resetVolatileStats()
local default_settings = { self.settings = G_reader_settings:readSetting("statistics", self.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.ui.menu:registerToMainMenu(self) self.ui.menu:registerToMainMenu(self)
self:checkInitDatabase() self:checkInitDatabase()

@ -172,14 +172,13 @@ if Device:hasEinkScreen() then
end end
end end
-- Handle global settings migration
local SettingsMigration = require("ui/data/settings_migration")
SettingsMigration:migrateSettings(G_reader_settings)
-- Document renderers canvas -- Document renderers canvas
local CanvasContext = require("document/canvascontext") local CanvasContext = require("document/canvascontext")
CanvasContext:init(Device) 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, -- 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 -- so have it done after CanvasContext:init() but before Bidi.setup() to not
-- have mirroring mess x/y probing). -- have mirroring mess x/y probing).

Loading…
Cancel
Save