From 0386e2619eb5c11367980741af062d3865ea4e8c Mon Sep 17 00:00:00 2001 From: hius07 <62179190+hius07@users.noreply.github.com> Date: Sun, 8 Dec 2024 09:33:46 +0200 Subject: [PATCH] Patch management: plugin -> core (#12862) --- frontend/apps/filemanager/filemanagermenu.lua | 15 +- frontend/apps/reader/modules/readermenu.lua | 7 +- frontend/ui/data/onetime_migration.lua | 14 +- frontend/ui/elements/patch_management.lua | 158 ++++++++++++++ plugins/patchmanagement.koplugin/_meta.lua | 6 - plugins/patchmanagement.koplugin/main.lua | 192 ------------------ 6 files changed, 182 insertions(+), 210 deletions(-) create mode 100644 frontend/ui/elements/patch_management.lua delete mode 100644 plugins/patchmanagement.koplugin/_meta.lua delete mode 100644 plugins/patchmanagement.koplugin/main.lua diff --git a/frontend/apps/filemanager/filemanagermenu.lua b/frontend/apps/filemanager/filemanagermenu.lua index a404f643f..468904c3a 100644 --- a/frontend/apps/filemanager/filemanagermenu.lua +++ b/frontend/apps/filemanager/filemanagermenu.lua @@ -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 diff --git a/frontend/apps/reader/modules/readermenu.lua b/frontend/apps/reader/modules/readermenu.lua index ec74a9774..6272f0148 100644 --- a/frontend/apps/reader/modules/readermenu.lua +++ b/frontend/apps/reader/modules/readermenu.lua @@ -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 diff --git a/frontend/ui/data/onetime_migration.lua b/frontend/ui/data/onetime_migration.lua index e92f63f23..f7722c802 100644 --- a/frontend/ui/data/onetime_migration.lua +++ b/frontend/ui/data/onetime_migration.lua @@ -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) diff --git a/frontend/ui/elements/patch_management.lua b/frontend/ui/elements/patch_management.lua new file mode 100644 index 000000000..05a221582 --- /dev/null +++ b/frontend/ui/elements/patch_management.lua @@ -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, +} diff --git a/plugins/patchmanagement.koplugin/_meta.lua b/plugins/patchmanagement.koplugin/_meta.lua deleted file mode 100644 index d5be8016b..000000000 --- a/plugins/patchmanagement.koplugin/_meta.lua +++ /dev/null @@ -1,6 +0,0 @@ -local _ = require("gettext") -return { - name = "patchmanagement", - fullname = _("Patch management"), - description = _("This plugin allows enabling, disabling or editing user patches."), -} diff --git a/plugins/patchmanagement.koplugin/main.lua b/plugins/patchmanagement.koplugin/main.lua deleted file mode 100644 index 688d1b75f..000000000 --- a/plugins/patchmanagement.koplugin/main.lua +++ /dev/null @@ -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