mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
* Persist: support serpent, and use by default over dump (as we assume consistency > readability in Persist). * Logger/Dbg: Use serpent instead of dump to dump tables (it's slightly more compact, honors __tostring, and will tag tables with their ref, which can come in handy when debugging). * Dbg: Don't duplicate Logger's log function, just use it directly. * Fontlist/ConfigDialog: Use serpent for the debug dump. * Call `os.setlocale(C, "numeric")` on startup instead of peppering it around dump calls. It's process-wide, so it didn't make much sense. * Trapper: Use LuaJIT's serde facilities instead of dump. They're more reliable in the face of funky input, much faster, and in this case, the data never makes it to human eyes, so a human-readable format didn't gain us anything.
192 lines
5.6 KiB
Lua
192 lines
5.6 KiB
Lua
--[[--
|
|
Subclass of LuaSettings dedicated to handling the legacy global constants.
|
|
]]
|
|
|
|
local DataStorage = require("datastorage")
|
|
local LuaSettings = require("luasettings")
|
|
local dump = require("dump")
|
|
local ffiutil = require("ffi/util")
|
|
local util = require("util")
|
|
local isAndroid, android = pcall(require, "android")
|
|
local lfs = require("libs/libkoreader-lfs")
|
|
local logger = require("logger")
|
|
|
|
local LuaDefaults = LuaSettings:extend{
|
|
ro = nil, -- will contain the defaults.lua k/v pairs (const)
|
|
rw = nil, -- will only contain non-defaults user-modified k/v pairs
|
|
}
|
|
|
|
--- Opens a settings file.
|
|
function LuaDefaults:open(path)
|
|
local file_path = path or DataStorage:getDataDir() .. "/defaults.custom.lua"
|
|
local new = LuaDefaults:extend{
|
|
file = file_path,
|
|
}
|
|
local ok, stored
|
|
|
|
-- File being absent and returning an empty table is a use case,
|
|
-- so logger.warn() only if there was an existing file
|
|
local existing = lfs.attributes(new.file, "mode") == "file"
|
|
|
|
ok, stored = pcall(dofile, new.file)
|
|
if ok and stored then
|
|
new.rw = stored
|
|
else
|
|
if existing then logger.warn("Failed reading", new.file, "(probably corrupted).") end
|
|
-- Fallback to .old if it exists
|
|
ok, stored = pcall(dofile, new.file..".old")
|
|
if ok and stored then
|
|
if existing then logger.warn("read from backup file", new.file..".old") end
|
|
new.rw = stored
|
|
else
|
|
if existing then logger.warn("no usable backup file for", new.file, "to read from") end
|
|
new.rw = {}
|
|
end
|
|
end
|
|
|
|
-- The actual defaults file, on the other hand, is set in stone.
|
|
-- We just have to deal with some platform shenanigans...
|
|
local defaults_path = DataStorage:getDataDir() .. "/defaults.lua"
|
|
if isAndroid then
|
|
defaults_path = android.dir .. "/defaults.lua"
|
|
elseif os.getenv("APPIMAGE") then
|
|
defaults_path = "defaults.lua"
|
|
end
|
|
ok, stored = pcall(dofile, defaults_path)
|
|
if ok and stored then
|
|
new.ro = stored
|
|
else
|
|
error("Failed reading " .. defaults_path)
|
|
end
|
|
|
|
return new
|
|
end
|
|
|
|
--- Reads a setting, optionally initializing it to a default.
|
|
function LuaDefaults:readSetting(key, default)
|
|
if not default then
|
|
if self:hasBeenCustomized(key) then
|
|
return self.rw[key]
|
|
else
|
|
return self.ro[key]
|
|
end
|
|
end
|
|
|
|
if not self:hasBeenCustomized(key) then
|
|
self.rw[key] = default
|
|
return self.rw[key]
|
|
end
|
|
|
|
if self:hasBeenCustomized(key) then
|
|
return self.rw[key]
|
|
else
|
|
return self.ro[key]
|
|
end
|
|
end
|
|
|
|
--- Saves a setting.
|
|
function LuaDefaults:saveSetting(key, value)
|
|
if util.tableEquals(self.ro[key], value, true) then
|
|
-- Only keep actually custom settings in the rw table ;).
|
|
return self:delSetting(key)
|
|
else
|
|
self.rw[key] = value
|
|
end
|
|
return self
|
|
end
|
|
|
|
--- Deletes a setting.
|
|
function LuaDefaults:delSetting(key)
|
|
self.rw[key] = nil
|
|
return self
|
|
end
|
|
|
|
--- Checks if setting exists.
|
|
function LuaDefaults:has(key)
|
|
return self.ro[key] ~= nil
|
|
end
|
|
|
|
--- Checks if setting does not exist.
|
|
function LuaDefaults:hasNot(key)
|
|
return self.ro[key] == nil
|
|
end
|
|
|
|
--- Checks if setting has been customized.
|
|
function LuaDefaults:hasBeenCustomized(key)
|
|
return self.rw[key] ~= nil
|
|
end
|
|
|
|
--- Checks if setting has NOT been customized.
|
|
function LuaDefaults:hasNotBeenCustomized(key)
|
|
return self.rw[key] == nil
|
|
end
|
|
|
|
--- Checks if setting is `true` (boolean).
|
|
function LuaDefaults:isTrue(key)
|
|
if self:hasBeenCustomized(key) then
|
|
return self.rw[key] == true
|
|
else
|
|
return self.ro[key] == true
|
|
end
|
|
end
|
|
|
|
--- Checks if setting is `false` (boolean).
|
|
function LuaDefaults:isFalse(key)
|
|
if self:hasBeenCustomized(key) then
|
|
return self.rw[key] == false
|
|
else
|
|
return self.ro[key] == false
|
|
end
|
|
end
|
|
|
|
--- Low-level API for filemanagersetdefaults
|
|
function LuaDefaults:getDataTables()
|
|
return self.ro, self.rw
|
|
end
|
|
|
|
function LuaDefaults:readDefaultSetting(key)
|
|
return self.ro[key]
|
|
end
|
|
|
|
-- NOP unsupported LuaSettings APIs
|
|
function LuaDefaults:wrap() end
|
|
function LuaDefaults:child() end
|
|
function LuaDefaults:initializeExtSettings() end
|
|
function LuaDefaults:getSettingForExt() end
|
|
function LuaDefaults:saveSettingForExt() end
|
|
function LuaDefaults:addTableItem() end
|
|
function LuaDefaults:removeTableItem() end
|
|
function LuaDefaults:reset() end
|
|
|
|
--- Writes settings to disk.
|
|
function LuaDefaults:flush()
|
|
if not self.file then return end
|
|
local directory_updated = false
|
|
if lfs.attributes(self.file, "mode") == "file" then
|
|
-- As an additional safety measure (to the ffiutil.fsync* calls used below),
|
|
-- we only backup the file to .old when it has not been modified in the last 60 seconds.
|
|
-- This should ensure in the case the fsync calls are not supported
|
|
-- that the OS may have itself sync'ed that file content in the meantime.
|
|
local mtime = lfs.attributes(self.file, "modification")
|
|
if mtime < os.time() - 60 then
|
|
os.rename(self.file, self.file .. ".old")
|
|
directory_updated = true -- fsync directory content too below
|
|
end
|
|
end
|
|
local f_out = io.open(self.file, "w")
|
|
if f_out ~= nil then
|
|
f_out:write("-- we can read Lua syntax here!\nreturn ")
|
|
f_out:write(dump(self.rw, nil, true))
|
|
f_out:write("\n")
|
|
ffiutil.fsyncOpenedFile(f_out) -- force flush to the storage device
|
|
f_out:close()
|
|
end
|
|
if directory_updated then
|
|
-- Ensure the file renaming is flushed to storage device
|
|
ffiutil.fsyncDirectory(self.file)
|
|
end
|
|
return self
|
|
end
|
|
|
|
return LuaDefaults
|