mirror of
https://github.com/koreader/koreader.git
synced 2025-08-10 00:52:38 +00:00
Patch management: plugin -> core (#12862)
This commit is contained in:
@@ -2,7 +2,6 @@ local BD = require("ui/bidi")
|
||||
local CenterContainer = require("ui/widget/container/centercontainer")
|
||||
local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local Device = require("device")
|
||||
local FFIUtil = require("ffi/util")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local KeyValuePage = require("ui/widget/keyvaluepage")
|
||||
local PluginLoader = require("pluginloader")
|
||||
@@ -11,13 +10,14 @@ local Size = require("ui/size")
|
||||
local SpinWidget = require("ui/widget/spinwidget")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local Screen = Device.screen
|
||||
local ffiUtil = require("ffi/util")
|
||||
local filemanagerutil = require("apps/filemanager/filemanagerutil")
|
||||
local dbg = require("dbg")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
local _ = require("gettext")
|
||||
local T = FFIUtil.template
|
||||
local T = ffiUtil.template
|
||||
|
||||
local FileManagerMenu = InputContainer:extend{
|
||||
tab_item_table = nil,
|
||||
@@ -482,16 +482,17 @@ To:
|
||||
}
|
||||
|
||||
-- tools tab
|
||||
self.menu_items.plugin_management = {
|
||||
text = _("Plugin management"),
|
||||
sub_item_table = PluginLoader:genPluginManagerSubItem(),
|
||||
}
|
||||
self.menu_items.patch_management = dofile("frontend/ui/elements/patch_management.lua")
|
||||
self.menu_items.advanced_settings = {
|
||||
text = _("Advanced settings"),
|
||||
callback = function()
|
||||
SetDefaults:ConfirmEdit()
|
||||
end,
|
||||
}
|
||||
self.menu_items.plugin_management = {
|
||||
text = _("Plugin management"),
|
||||
sub_item_table = PluginLoader:genPluginManagerSubItem()
|
||||
}
|
||||
|
||||
self.menu_items.developer_options = {
|
||||
text = _("Developer options"),
|
||||
@@ -505,7 +506,7 @@ To:
|
||||
local DataStorage = require("datastorage")
|
||||
local cachedir = DataStorage:getDataDir() .. "/cache"
|
||||
if lfs.attributes(cachedir, "mode") == "directory" then
|
||||
FFIUtil.purgeDir(cachedir)
|
||||
ffiUtil.purgeDir(cachedir)
|
||||
end
|
||||
lfs.mkdir(cachedir)
|
||||
-- Also remove from the Cache object references to the cache files we've just deleted
|
||||
|
||||
@@ -4,6 +4,7 @@ local ConfirmBox = require("ui/widget/confirmbox")
|
||||
local Device = require("device")
|
||||
local Event = require("ui/event")
|
||||
local InputContainer = require("ui/widget/container/inputcontainer")
|
||||
local PluginLoader = require("pluginloader")
|
||||
local Screensaver = require("ui/screensaver")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local logger = require("logger")
|
||||
@@ -284,11 +285,13 @@ function ReaderMenu:setUpdateItemTable()
|
||||
}
|
||||
end
|
||||
|
||||
local PluginLoader = require("pluginloader")
|
||||
-- tools tab
|
||||
self.menu_items.plugin_management = {
|
||||
text = _("Plugin management"),
|
||||
sub_item_table = PluginLoader:genPluginManagerSubItem()
|
||||
sub_item_table = PluginLoader:genPluginManagerSubItem(),
|
||||
}
|
||||
self.menu_items.patch_management = dofile("frontend/ui/elements/patch_management.lua")
|
||||
|
||||
-- main menu tab
|
||||
-- insert common info
|
||||
for id, common_setting in pairs(dofile("frontend/ui/elements/common_info_menu_table.lua")) do
|
||||
|
||||
@@ -3,6 +3,7 @@ Centralizes any and all one time migration concerns.
|
||||
--]]
|
||||
|
||||
local DataStorage = require("datastorage")
|
||||
local ffiUtil = require("ffi/util")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local SQ3 = require("lua-ljsqlite3/init")
|
||||
@@ -10,7 +11,7 @@ local util = require("util")
|
||||
local _ = require("gettext")
|
||||
|
||||
-- Date at which the last migration snippet was added
|
||||
local CURRENT_MIGRATION_DATE = 20241123
|
||||
local CURRENT_MIGRATION_DATE = 20241207
|
||||
|
||||
-- Retrieve the date of the previous migration, if any
|
||||
local last_migration_date = G_reader_settings:readSetting("last_migration_date", 0)
|
||||
@@ -339,11 +340,10 @@ end
|
||||
-- 20210831, Clean VirtualKeyboard settings of disabled layouts, https://github.com/koreader/koreader/pull/8159
|
||||
if last_migration_date < 20210831 then
|
||||
logger.info("Performing one-time migration for 20210831")
|
||||
local FFIUtil = require("ffi/util")
|
||||
local keyboard_layouts = G_reader_settings:readSetting("keyboard_layouts") or {}
|
||||
local keyboard_layouts_new = {}
|
||||
local selected_layouts_count = 0
|
||||
for k, v in FFIUtil.orderedPairs(keyboard_layouts) do
|
||||
for k, v in ffiUtil.orderedPairs(keyboard_layouts) do
|
||||
if v == true and selected_layouts_count < 4 then
|
||||
selected_layouts_count = selected_layouts_count + 1
|
||||
keyboard_layouts_new[selected_layouts_count] = k
|
||||
@@ -760,5 +760,13 @@ if last_migration_date < 20241123 then
|
||||
end
|
||||
end
|
||||
|
||||
-- 20241207, We moved patch management to core. Remove the original plugin.
|
||||
-- https://github.com/koreader/koreader/pull/12862
|
||||
if last_migration_date < 20241207 then
|
||||
logger.info("Performing one-time migration for 20241207")
|
||||
|
||||
ffiUtil.purgeDir(DataStorage:getDataDir() .. "/plugins/patchmanagement.koplugin")
|
||||
end
|
||||
|
||||
-- We're done, store the current migration date
|
||||
G_reader_settings:saveSetting("last_migration_date", CURRENT_MIGRATION_DATE)
|
||||
|
||||
158
frontend/ui/elements/patch_management.lua
Normal file
158
frontend/ui/elements/patch_management.lua
Normal file
@@ -0,0 +1,158 @@
|
||||
local DataStorage = require("datastorage")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
|
||||
local patch_dir = DataStorage:getDataDir() .. "/patches"
|
||||
if lfs.attributes(patch_dir, "mode") ~= "directory" then return end
|
||||
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local sort = require("sort")
|
||||
local userPatch = require("userpatch")
|
||||
local _ = require("gettext")
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local priority_first = tonumber(userPatch.early_once)
|
||||
local priority_last = tonumber(userPatch.on_exit)
|
||||
local priorities = {
|
||||
[priority_first] = _("On startup, only after update"),
|
||||
[tonumber(userPatch.early)] = _("On startup"),
|
||||
[tonumber(userPatch.late)] = _("After setup"),
|
||||
[tonumber(userPatch.before_exit)] = _("Before exit"),
|
||||
[priority_last] = _("On exit"),
|
||||
}
|
||||
|
||||
local patches = {}
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] then
|
||||
patches[priority] = {}
|
||||
end
|
||||
end
|
||||
for entry in lfs.dir(patch_dir) do
|
||||
local mode = lfs.attributes(patch_dir .. "/" .. entry, "mode")
|
||||
if mode == "file" and entry:find(".lua", 1, true) then
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] and entry:match("^" .. priority .. "%d*%-") then
|
||||
-- only lua files, starting with "%d+%-"
|
||||
table.insert(patches[priority], entry)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] and #patches[priority] > 1 then
|
||||
table.sort(patches[priority], sort.natsort_cmp())
|
||||
end
|
||||
end
|
||||
|
||||
local function done_callback()
|
||||
UIManager:askForRestart(_("Patches might have changed. Current set of patches will be applied on next restart."))
|
||||
end
|
||||
|
||||
local function genSubMenu(priority)
|
||||
local sub_menu = {}
|
||||
for i, patch in ipairs(patches[priority]) do
|
||||
local ext = ".lua"
|
||||
-- strip anything after ".lua" in patch_name
|
||||
local patch_name = patch:sub(1, patch:find(ext, 1, true) + ext:len() - 1)
|
||||
sub_menu[i] = {
|
||||
text = patch_name:sub(1, -5) .. (userPatch.execution_status[patch_name] == false and " ⚠" or ""),
|
||||
checked_func = function()
|
||||
return patch:find("%.lua$") ~= nil
|
||||
end,
|
||||
callback = function()
|
||||
local extension_pos = patch:find(ext, 1, true)
|
||||
if extension_pos then
|
||||
local new_name
|
||||
local is_patch_enabled = extension_pos == patch:len() - (ext:len() - 1)
|
||||
if is_patch_enabled then -- patch name ends with ".lua"
|
||||
new_name = patch .. ".disabled"
|
||||
else -- patch contains ".lua"
|
||||
new_name = patch:sub(1, extension_pos + ext:len() - 1)
|
||||
end
|
||||
os.rename(patch_dir .. "/" .. patch, patch_dir .. "/" .. new_name)
|
||||
patch = new_name
|
||||
end
|
||||
done_callback()
|
||||
end,
|
||||
hold_callback = function()
|
||||
local patch_fullpath = patch_dir .. "/" .. patch
|
||||
local ui = require("apps/filemanager/filemanager").instance or require("apps/reader/readerui").instance
|
||||
if ui.texteditor then
|
||||
ui.texteditor:quickEditFile(patch_fullpath, done_callback, false)
|
||||
else
|
||||
local TextViewer = require("ui/widget/textviewer")
|
||||
TextViewer.openFile(patch_fullpath)
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
return sub_menu
|
||||
end
|
||||
|
||||
local about_text = _([[Patch management allows enabling, disabling or editing user provided patches.
|
||||
|
||||
The runlevel and priority of a patch can not be modified here. This has to be done manually by renaming the patch prefix.
|
||||
|
||||
For more information about user patches, see
|
||||
https://github.com/koreader/koreader/wiki/User-patches
|
||||
|
||||
Patches are an advanced feature, so be careful what you do!]])
|
||||
|
||||
return {
|
||||
text = _("Patch management"),
|
||||
sub_item_table_func = function()
|
||||
local sub_item_table = {
|
||||
{
|
||||
text = _("About patch management"),
|
||||
keep_menu_open = true,
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{ text = about_text })
|
||||
end,
|
||||
separator = true,
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
local count = 0
|
||||
for _, status in pairs(userPatch.execution_status) do
|
||||
if status then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
return T(_("Patches executed: %1"), count)
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function()
|
||||
local txt = {}
|
||||
for patch, status in pairs(userPatch.execution_status) do
|
||||
if status then
|
||||
table.insert(txt, patch:sub(1, -5))
|
||||
end
|
||||
end
|
||||
if #txt > 0 then
|
||||
table.sort(txt, sort.natsort_cmp())
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = table.concat(txt, "\n"),
|
||||
monospace_font = true,
|
||||
})
|
||||
end
|
||||
end,
|
||||
separator = true,
|
||||
},
|
||||
}
|
||||
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] then
|
||||
table.insert(sub_item_table, {
|
||||
text = priorities[priority],
|
||||
enabled_func = function()
|
||||
return #patches[priority] > 0
|
||||
end,
|
||||
sub_item_table = genSubMenu(priority),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return sub_item_table
|
||||
end,
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
local _ = require("gettext")
|
||||
return {
|
||||
name = "patchmanagement",
|
||||
fullname = _("Patch management"),
|
||||
description = _("This plugin allows enabling, disabling or editing user patches."),
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
--[[--
|
||||
Plugin for managing user patches
|
||||
|
||||
@module koplugin.patchmanagement
|
||||
--]]--
|
||||
|
||||
local DataStorage = require("datastorage")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
|
||||
local patch_dir = DataStorage:getDataDir() .. "/patches"
|
||||
if lfs.attributes(patch_dir, "mode") ~= "directory" then
|
||||
return { disabled = true }
|
||||
end
|
||||
|
||||
local Device = require("device")
|
||||
local InfoMessage = require("ui/widget/infomessage")
|
||||
local TextViewer = require("ui/widget/textviewer")
|
||||
local UIManager = require("ui/uimanager")
|
||||
local WidgetContainer = require("ui/widget/container/widgetcontainer")
|
||||
local sort = require("sort")
|
||||
local userPatch = require("userpatch")
|
||||
local _ = require("gettext")
|
||||
local Screen = Device.screen
|
||||
local T = require("ffi/util").template
|
||||
|
||||
local PatchManagement = WidgetContainer:extend{
|
||||
name = "patch_management",
|
||||
disable_ext = ".disabled",
|
||||
patches = nil,
|
||||
}
|
||||
|
||||
local priority_first = tonumber(userPatch.early_once)
|
||||
local priority_last = tonumber(userPatch.on_exit)
|
||||
local priorities = {
|
||||
[priority_first] = _("On startup, only after update"),
|
||||
[tonumber(userPatch.early)] = _("On startup"),
|
||||
[tonumber(userPatch.late)] = _("After setup"),
|
||||
[tonumber(userPatch.before_exit)] = _("Before exit"),
|
||||
[priority_last] = _("On exit"),
|
||||
}
|
||||
|
||||
function PatchManagement:init()
|
||||
self.ui.menu:registerToMainMenu(self)
|
||||
end
|
||||
|
||||
function PatchManagement:getAvailablePatches()
|
||||
self.patches = {}
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] then
|
||||
self.patches[priority] = {}
|
||||
end
|
||||
end
|
||||
|
||||
for entry in lfs.dir(patch_dir) do
|
||||
local mode = lfs.attributes(patch_dir .. "/" .. entry, "mode")
|
||||
if mode == "file" and entry:find(".lua", 1, true) then
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] and entry:match("^" .. priority .. "%d*%-") then
|
||||
-- only lua files, starting with "%d+%-"
|
||||
table.insert(self.patches[priority], entry)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] and #self.patches[priority] > 1 then
|
||||
table.sort(self.patches[priority], sort.natsort_cmp())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PatchManagement:getSubMenu(priority)
|
||||
local sub_menu = {}
|
||||
for i, patch in ipairs(self.patches[priority]) do
|
||||
local ext = ".lua"
|
||||
-- strip anything after ".lua" in patch_name
|
||||
local patch_name = patch:sub(1, patch:find(ext, 1, true) + ext:len() - 1)
|
||||
table.insert(sub_menu, {
|
||||
text = patch_name:sub(1,-5) .. (userPatch.execution_status[patch_name] == false and " ⚠" or ""),
|
||||
checked_func = function()
|
||||
return patch:find("%.lua$") ~= nil
|
||||
end,
|
||||
callback = function()
|
||||
local extension_pos = patch:find(ext, 1, true)
|
||||
if extension_pos then
|
||||
local is_patch_enabled = extension_pos == patch:len() - (ext:len() - 1)
|
||||
if is_patch_enabled then -- patch name ends with ".lua"
|
||||
local disabled_name = patch .. self.disable_ext
|
||||
os.rename(patch_dir .. "/" .. patch, patch_dir .. "/" .. disabled_name)
|
||||
patch = disabled_name
|
||||
else -- patch contains ".lua"
|
||||
local enabled_name = patch:sub(1, extension_pos + ext:len() - 1)
|
||||
os.rename(patch_dir .. "/" .. patch, patch_dir .. "/" .. enabled_name)
|
||||
patch = enabled_name
|
||||
end
|
||||
end
|
||||
UIManager:askForRestart(
|
||||
_("Patches changed. Current set of patches will be applied on next restart."))
|
||||
end,
|
||||
hold_callback = function()
|
||||
local patch_fullpath = patch_dir .. "/" .. patch
|
||||
if self.ui.texteditor then
|
||||
local function done_callback()
|
||||
UIManager:askForRestart(
|
||||
_("Patches might have changed. Current set of patches will be applied on next restart."))
|
||||
end
|
||||
self.ui.texteditor:quickEditFile(patch_fullpath, done_callback, false)
|
||||
else
|
||||
TextViewer.openFile(patch_fullpath)
|
||||
end
|
||||
end,
|
||||
})
|
||||
end
|
||||
return sub_menu
|
||||
end
|
||||
|
||||
local about_text = _([[Patch management allows enabling, disabling or editing user provided patches.
|
||||
|
||||
The runlevel and priority of a patch can not be modified here. This has to be done manually by renaming the patch prefix.
|
||||
|
||||
For more information about user patches, see
|
||||
https://github.com/koreader/koreader/wiki/User-patches
|
||||
|
||||
Patches are an advanced feature, so be careful what you do!]])
|
||||
|
||||
function PatchManagement:addToMainMenu(menu_items)
|
||||
menu_items.patch_management = {
|
||||
text = _("Patch management"),
|
||||
sub_item_table_func = function()
|
||||
local sub_item_table = {
|
||||
{
|
||||
text = _("About patch management"),
|
||||
keep_menu_open = true,
|
||||
callback = function()
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = about_text,
|
||||
width = math.floor(Screen:getWidth() * 0.9),
|
||||
})
|
||||
end,
|
||||
separator = true,
|
||||
},
|
||||
{
|
||||
text_func = function()
|
||||
local count = 0
|
||||
for _, status in pairs(userPatch.execution_status) do
|
||||
if status then
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
return T(_("Patches executed: %1"), count)
|
||||
end,
|
||||
keep_menu_open = true,
|
||||
callback = function()
|
||||
local txt = {}
|
||||
for patch, status in pairs(userPatch.execution_status) do
|
||||
if status then
|
||||
table.insert(txt, patch:sub(1,-5))
|
||||
end
|
||||
end
|
||||
if #txt > 0 then
|
||||
table.sort(txt, sort.natsort_cmp())
|
||||
UIManager:show(InfoMessage:new{
|
||||
text = table.concat(txt, "\n"),
|
||||
monospace_font = true,
|
||||
})
|
||||
end
|
||||
end,
|
||||
separator = true,
|
||||
},
|
||||
}
|
||||
|
||||
self:getAvailablePatches()
|
||||
for priority = priority_first, priority_last do
|
||||
if priorities[priority] then
|
||||
table.insert(sub_item_table, {
|
||||
text = priorities[priority],
|
||||
enabled_func = function()
|
||||
return #self.patches[priority] > 0
|
||||
end,
|
||||
sub_item_table = self:getSubMenu(priority),
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
return sub_item_table
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
return PatchManagement
|
||||
Reference in New Issue
Block a user