diff --git a/datastorage.lua b/datastorage.lua index 8f20a6b68..14966c5e2 100644 --- a/datastorage.lua +++ b/datastorage.lua @@ -42,6 +42,9 @@ function DataStorage:getSettingsDir() return self:getDataDir() .. "/settings" end +function DataStorage:getDocSettingsDir() + return self:getDataDir() .. "/docsettings" +end function DataStorage:getFullDataDir() if full_data_dir then return full_data_dir end @@ -58,8 +61,8 @@ end local function initDataDir() local sub_data_dirs = { "cache", "clipboard", - "data", "data/dict", "data/tessdata", - "history", "ota", "plugins", + "data", "data/dict", "data/tessdata", "docsettings", + "history", "ota", "patches", "plugins", "screenshots", "settings", "styletweaks", } for _, dir in ipairs(sub_data_dirs) do diff --git a/frontend/docsettings.lua b/frontend/docsettings.lua index ca49711a5..14cfd4c5d 100644 --- a/frontend/docsettings.lua +++ b/frontend/docsettings.lua @@ -15,6 +15,7 @@ local util = require("util") local DocSettings = LuaSettings:extend{} local HISTORY_DIR = DataStorage:getHistoryDir() +local DOCSETTINGS_DIR = DataStorage:getDocSettingsDir() local function buildCandidates(list) local candidates = {} @@ -64,120 +65,125 @@ local function buildCandidates(list) end --- Returns path to sidecar directory (`filename.sdr`). --- -- Sidecar directory is the file without _last_ suffix. -- @string doc_path path to the document (e.g., `/foo/bar.pdf`) -- @treturn string path to the sidecar directory (e.g., `/foo/bar.sdr`) -function DocSettings:getSidecarDir(doc_path) - if doc_path == nil or doc_path == '' then return '' end - local file_without_suffix = doc_path:match("(.*)%.") - if file_without_suffix then - return file_without_suffix..".sdr" +function DocSettings:getSidecarDir(doc_path, force_location) + if doc_path == nil or doc_path == "" then return "" end + local path = doc_path:match("(.*)%.") or doc_path -- file path without the last suffix + local location = force_location or G_reader_settings:readSetting("document_metadata_folder", "doc") + if location == "dir" then + path = DOCSETTINGS_DIR..path end - return doc_path..".sdr" + return path..".sdr" end --- Returns path to `metadata.lua` file. -- @string doc_path path to the document (e.g., `/foo/bar.pdf`) -- @treturn string path to `/foo/bar.sdr/metadata.lua` file -function DocSettings:getSidecarFile(doc_path) - if doc_path == nil or doc_path == '' then return '' end +function DocSettings:getSidecarFile(doc_path, force_location) + if doc_path == nil or doc_path == "" then return "" end -- If the file does not have a suffix or we are working on a directory, we -- should ignore the suffix part in metadata file path. - local suffix = doc_path:match(".*%.(.+)") - if suffix == nil then - suffix = '' - end - return self:getSidecarDir(doc_path) .. "/metadata." .. suffix .. ".lua" + local suffix = doc_path:match(".*%.(.+)") or "" + return self:getSidecarDir(doc_path, force_location) .. "/metadata." .. suffix .. ".lua" end --- Returns `true` if there is a `metadata.lua` file. -- @string doc_path path to the document (e.g., `/foo/bar.pdf`) -- @treturn bool function DocSettings:hasSidecarFile(doc_path) - return lfs.attributes(self:getSidecarFile(doc_path), "mode") == "file" + return lfs.attributes(self:getSidecarFile(doc_path, "doc"), "mode") == "file" + or lfs.attributes(self:getSidecarFile(doc_path, "dir"), "mode") == "file" + or lfs.attributes(self:getHistoryPath(doc_path), "mode") == "file" +end + +function DocSettings:getLastSaveTime(doc_path) -- for readhistory + return lfs.attributes(self:getSidecarFile(doc_path, "doc"), "modification") + or lfs.attributes(self:getSidecarFile(doc_path, "dir"), "modification") end -function DocSettings:getHistoryPath(fullpath) - return HISTORY_DIR .. "/[" .. fullpath:gsub("(.*/)([^/]+)", "%1] %2"):gsub("/", "#") .. ".lua" +function DocSettings:getHistoryPath(doc_path) + if doc_path == nil or doc_path == "" then return "" end + return HISTORY_DIR .. "/[" .. doc_path:gsub("(.*/)([^/]+)", "%1] %2"):gsub("/", "#") .. ".lua" end function DocSettings:getPathFromHistory(hist_name) - if hist_name == nil or hist_name == '' then return '' end - if hist_name:sub(-4) ~= ".lua" then return '' end -- ignore .lua.old backups + if hist_name == nil or hist_name == "" then return "" end + if hist_name:sub(-4) ~= ".lua" then return "" end -- ignore .lua.old backups -- 1. select everything included in brackets local s = string.match(hist_name,"%b[]") - if s == nil or s == '' then return '' end + if s == nil or s == "" then return "" end -- 2. crop the bracket-sign from both sides -- 3. and finally replace decorative signs '#' to dir-char '/' return string.gsub(string.sub(s, 2, -3), "#", "/") end function DocSettings:getNameFromHistory(hist_name) - if hist_name == nil or hist_name == '' then return '' end - if hist_name:sub(-4) ~= ".lua" then return '' end -- ignore .lua.old backups + if hist_name == nil or hist_name == "" then return "" end + if hist_name:sub(-4) ~= ".lua" then return "" end -- ignore .lua.old backups local s = string.match(hist_name, "%b[]") - if s == nil or s == '' then return '' end + if s == nil or s == "" then return "" end -- at first, search for path length -- and return the rest of string without 4 last characters (".lua") return string.sub(hist_name, string.len(s)+2, -5) end -function DocSettings:getLastSaveTime(doc_path) - local attr = lfs.attributes(self:getSidecarFile(doc_path)) - if attr and attr.mode == "file" then - return attr.modification - end -end - -function DocSettings:ensureSidecar(sidecar) - if lfs.attributes(sidecar, "mode") ~= "directory" then - lfs.mkdir(sidecar) +function DocSettings:getFileFromHistory(hist_name) + local path = self:getPathFromHistory(hist_name) + if path ~= "" then + local name = self:getNameFromHistory(hist_name) + if name ~= "" then + return ffiutil.joinPath(path, name) + end end end --- Opens a document's individual settings (font, margin, dictionary, etc.) --- @string docfile path to the document (e.g., `/foo/bar.pdf`) +-- @string doc_path path to the document (e.g., `/foo/bar.pdf`) -- @treturn DocSettings object -function DocSettings:open(docfile) - --- @todo (zijiehe): Remove history_path, use only sidecar. - +function DocSettings:open(doc_path) -- NOTE: Beware, our new instance is new, but self is still DocSettings! local new = DocSettings:extend{} - new.history_file = new:getHistoryPath(docfile) - local sidecar = new:getSidecarDir(docfile) - new.sidecar = sidecar - DocSettings:ensureSidecar(sidecar) - -- If there is a file which has a same name as the sidecar directory, - -- or the file system is read-only, we should not waste time to read it. - if lfs.attributes(sidecar, "mode") == "directory" then - -- New sidecar file name is metadata.{file last suffix}.lua. - -- So we can handle two files with only different suffixes. - new.sidecar_file = new:getSidecarFile(docfile) - new.legacy_sidecar_file = sidecar.."/".. - ffiutil.basename(docfile)..".lua" + new.doc_sidecar_dir = new:getSidecarDir(doc_path, "doc") + new.doc_sidecar_file = new:getSidecarFile(doc_path, "doc") + local doc_sidecar_file, legacy_sidecar_file + if lfs.attributes(new.doc_sidecar_dir, "mode") == "directory" then + doc_sidecar_file = new.doc_sidecar_file + legacy_sidecar_file = new.doc_sidecar_dir.."/"..ffiutil.basename(doc_path)..".lua" + end + new.dir_sidecar_dir = new:getSidecarDir(doc_path, "dir") + new.dir_sidecar_file = new:getSidecarFile(doc_path, "dir") + local dir_sidecar_file + if lfs.attributes(new.dir_sidecar_dir, "mode") == "directory" then + dir_sidecar_file = new.dir_sidecar_file end + local history_file = new:getHistoryPath(doc_path) -- Candidates list, in order of priority: local candidates_list = { - -- New sidecar file - new.sidecar_file or "", - -- Backup file of new sidecar file - new.sidecar_file and (new.sidecar_file .. ".old") or "", + -- New sidecar file in doc folder + doc_sidecar_file or "", + -- Backup file of new sidecar file in doc folder + doc_sidecar_file and (doc_sidecar_file..".old") or "", -- Legacy sidecar file - new.legacy_sidecar_file or "", + legacy_sidecar_file or "", + -- New sidecar file in docsettings folder + dir_sidecar_file or "", + -- Backup file of new sidecar file in docsettings folder + dir_sidecar_file and (dir_sidecar_file..".old") or "", -- Legacy history folder - new.history_file, + history_file, -- Backup file in legacy history folder - new.history_file .. ".old", + history_file..".old", -- Legacy kpdfview setting - docfile..".kpdfview.lua", + doc_path..".kpdfview.lua", } -- We get back an array of tables for *existing* candidates, sorted MRU first (insertion order breaks ties). local candidates = buildCandidates(candidates_list) - local ok, stored, filepath + local ok, stored for _, t in ipairs(candidates) do local candidate_path = t.path -- Ignore empty files @@ -186,7 +192,6 @@ function DocSettings:open(docfile) -- Ignore empty tables if ok and next(stored) ~= nil then logger.dbg("DocSettings: data is read from", candidate_path) - filepath = candidate_path break end end @@ -196,7 +201,6 @@ function DocSettings:open(docfile) if ok and stored then new.data = stored new.candidates = candidates - new.filepath = filepath else new.data = {} end @@ -205,40 +209,33 @@ function DocSettings:open(docfile) end --- Serializes settings and writes them to `metadata.lua`. -function DocSettings:flush() - -- write serialized version of the data table into one of - -- i) sidecar directory in the same directory of the document or - -- ii) history directory in root directory of KOReader - if not self.history_file and not self.sidecar_file then - return - end +function DocSettings:flush(data) + -- Depending on the settings, doc_settings are saved to the book folder or + -- to koreader/docsettings folder. The latter is also a fallback for read-only book storage. + local serials = G_reader_settings:readSetting("document_metadata_folder", "doc") == "doc" + and { {self.doc_sidecar_dir, self.doc_sidecar_file}, + {self.dir_sidecar_dir, self.dir_sidecar_file}, } + or { {self.dir_sidecar_dir, self.dir_sidecar_file}, } - -- If we can write to sidecar_file, we do not need to write to history_file anymore. - local serials = {} - if self.sidecar_file then - table.insert(serials, self.sidecar_file) - end - if self.history_file then - table.insert(serials, self.history_file) - end - self:ensureSidecar(self.sidecar) - local s_out = dump(self.data) - for _, f in ipairs(serials) do + local s_out = dump(data or self.data, nil, true) + for _, s in ipairs(serials) do + util.makePath(s[1]) + local sidecar_file = s[2] local directory_updated = false - if lfs.attributes(f, "mode") == "file" then + if lfs.attributes(sidecar_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(f, "modification") + local mtime = lfs.attributes(sidecar_file, "modification") if mtime < os.time() - 60 then - logger.dbg("DocSettings: Renamed", f, "to", f .. ".old") - os.rename(f, f .. ".old") + logger.dbg("DocSettings: Renamed", sidecar_file, "to", sidecar_file .. ".old") + os.rename(sidecar_file, sidecar_file .. ".old") directory_updated = true -- fsync directory content too below end end - logger.dbg("DocSettings: Writing to", f) - local f_out = io.open(f, "w") + logger.dbg("DocSettings: Writing to", sidecar_file) + local f_out = io.open(sidecar_file, "w") if f_out ~= nil then f_out:write("-- we can read Lua syntax here!\nreturn ") f_out:write(s_out) @@ -246,77 +243,67 @@ function DocSettings:flush() ffiutil.fsyncOpenedFile(f_out) -- force flush to the storage device f_out:close() - if self.candidates ~= nil - and G_reader_settings:nilOrFalse("preserve_legacy_docsetting") then - for _, t in ipairs(self.candidates) do - local candidate_path = t.path - if candidate_path ~= f and candidate_path ~= f .. ".old" then - logger.dbg("DocSettings: Removed legacy file", candidate_path) - os.remove(candidate_path) - -- We should not remove sidecar folder, as it may - -- contain Kindle history files. - end - end - end - if directory_updated then -- Ensure the file renaming is flushed to storage device - ffiutil.fsyncDirectory(f) + ffiutil.fsyncDirectory(sidecar_file) end + + self:purge(false, sidecar_file) -- remove old candidates and empty sidecar folders + break end end end -function DocSettings:getFilePath() - return self.filepath -end - --- Purges (removes) sidecar directory. -function DocSettings:purge(full) +function DocSettings:purge(full, sidecar_to_keep) -- Remove any of the old ones we may consider as candidates in DocSettings:open() - if self.history_file then - os.remove(self.history_file) - os.remove(self.history_file .. ".old") + if self.candidates then + for _, t in ipairs(self.candidates) do + local candidate_path = t.path + if lfs.attributes(candidate_path, "mode") == "file" then + if (not sidecar_to_keep) + or (candidate_path ~= sidecar_to_keep and candidate_path ~= sidecar_to_keep..".old") then + os.remove(candidate_path) + logger.dbg("DocSettings: purged:", candidate_path) + end + end + end end - if self.legacy_sidecar_file then - os.remove(self.legacy_sidecar_file) + + local function purgeDir(dir, full_purge) + if lfs.attributes(dir, "mode") == "directory" then + if full_purge then + -- Asked to remove all the content of this .sdr directory, whether it's ours or not + ffiutil.purgeDir(dir) + else + -- If the sidecar folder ends up empty, os.remove() can delete it. + -- Otherwise, the following statement has no effect. + os.remove(dir) + end + end end - if lfs.attributes(self.sidecar, "mode") == "directory" then - if full then - -- Asked to remove all the content of this .sdr directory, whether it's ours or not - ffiutil.purgeDir(self.sidecar) + purgeDir(self.doc_sidecar_dir, full) + purgeDir(self.dir_sidecar_dir, full) +end + +--- Updates sidecar info for file rename/copy/move/delete operations. +function DocSettings:update(doc_path, new_doc_path, copy) + if self:hasSidecarFile(doc_path) then + local doc_settings = DocSettings:open(doc_path) + if new_doc_path then + local new_doc_settings = DocSettings:open(new_doc_path) + new_doc_settings:flush(doc_settings.data) -- with current "Book metadata folder" setting else - -- Only remove the files we know we may have created with our usual names. - for f in lfs.dir(self.sidecar) do - local fullpath = self.sidecar.."/"..f - local to_remove = false - if lfs.attributes(fullpath, "mode") == "file" then - -- Currently, we only create a single file in there, - -- named metadata.suffix.lua (ie. metadata.epub.lua), - -- with possibly backups named metadata.epub.lua.old and - -- metadata.epub.lua.old_dom20180528, - -- so all sharing the same base: self.sidecar_file - if util.stringStartsWith(fullpath, self.sidecar_file) then - to_remove = true - end - end - if to_remove then - os.remove(fullpath) - logger.dbg("DocSettings: purged:", fullpath) - end + local cache_file_path = doc_settings:readSetting("cache_file_path") + if cache_file_path then + os.remove(cache_file_path) end - -- If the sidecar folder ends up empty, os.remove() can delete it. - -- Otherwise, the following statement has no effect. - os.remove(self.sidecar) + end + if not copy then + doc_settings:purge() end end - -- We should have meet the candidate we used and remove it above. - -- But in case we didn't, remove it. - if self.filepath and lfs.attributes(self.filepath, "mode") == "file" then - os.remove(self.filepath) - end - self.data = {} end return DocSettings diff --git a/frontend/readhistory.lua b/frontend/readhistory.lua index 2b96f65ae..277e3eda3 100644 --- a/frontend/readhistory.lua +++ b/frontend/readhistory.lua @@ -146,17 +146,13 @@ function ReadHistory:_readLegacyHistory() local history_updated local history_dir = DataStorage:getHistoryDir() for f in lfs.dir(history_dir) do - local path = joinPath(history_dir, f) - if lfs.attributes(path, "mode") == "file" then - path = DocSettings:getPathFromHistory(f) - if path ~= nil and path ~= "" then - local file = DocSettings:getNameFromHistory(f) - if file ~= nil and file ~= "" then - local item_path = joinPath(path, file) - local item_time = lfs.attributes(joinPath(history_dir, f), "modification") - if self:addItem(item_path, item_time, true) then - history_updated = true - end + local legacy_history_file = joinPath(history_dir, f) + if lfs.attributes(legacy_history_file, "mode") == "file" then + local item_path = DocSettings:getFileFromHistory(f) + if item_path then + local item_time = lfs.attributes(legacy_history_file, "modification") + if self:addItem(item_path, item_time, true) then + history_updated = true end end end diff --git a/frontend/ui/elements/common_settings_menu_table.lua b/frontend/ui/elements/common_settings_menu_table.lua index 94cc25481..3c3d83b5f 100644 --- a/frontend/ui/elements/common_settings_menu_table.lua +++ b/frontend/ui/elements/common_settings_menu_table.lua @@ -526,6 +526,34 @@ common_settings.document = { -- submenus are filled by menu_order } +local metadata_folder_str = { + ["doc"] = _("book folder"), + ["dir"] = "koreader/docsettings", +} + +local function genMetadataFolderMenuItem(value) + return { + text = metadata_folder_str[value], + checked_func = function() + return G_reader_settings:readSetting("document_metadata_folder") == value + end, + callback = function() + G_reader_settings:saveSetting("document_metadata_folder", value) + end, + } +end + +common_settings.document_metadata_folder = { + text_func = function() + local value = G_reader_settings:readSetting("document_metadata_folder", "doc") + return T(_("Book metadata folder: %1"), metadata_folder_str[value]) + end, + sub_item_table = { + genMetadataFolderMenuItem("doc"), + genMetadataFolderMenuItem("dir"), + }, +} + common_settings.document_auto_save = { text_func = function() local interval = G_reader_settings:readSetting("auto_save_settings_interval_minutes") @@ -552,6 +580,7 @@ common_settings.document_auto_save = { end, } or nil, }, + separator = true, } common_settings.document_save = { diff --git a/frontend/ui/elements/filemanager_menu_order.lua b/frontend/ui/elements/filemanager_menu_order.lua index bb83e1fa1..e01b38d24 100644 --- a/frontend/ui/elements/filemanager_menu_order.lua +++ b/frontend/ui/elements/filemanager_menu_order.lua @@ -36,6 +36,7 @@ local order = { -- end common settings }, document = { + "document_metadata_folder", "document_auto_save", "document_save", "document_end_action", diff --git a/frontend/ui/elements/reader_menu_order.lua b/frontend/ui/elements/reader_menu_order.lua index 3e1d56712..00054a113 100644 --- a/frontend/ui/elements/reader_menu_order.lua +++ b/frontend/ui/elements/reader_menu_order.lua @@ -79,6 +79,7 @@ local order = { "status_bar", }, document = { + "document_metadata_folder", "document_auto_save", "document_save", "document_end_action", diff --git a/plugins/exporter.koplugin/clip.lua b/plugins/exporter.koplugin/clip.lua index 56ee62835..462d95834 100644 --- a/plugins/exporter.koplugin/clip.lua +++ b/plugins/exporter.koplugin/clip.lua @@ -1,16 +1,16 @@ +local DataStorage = require("datastorage") local DocumentRegistry = require("document/documentregistry") local DocSettings = require("docsettings") -local ReadHistory = require("readhistory") +local ffiutil = require("ffi/util") local lfs = require("libs/libkoreader-lfs") local logger = require("logger") local md5 = require("ffi/sha2").md5 local util = require("util") local _ = require("gettext") -local T = require("ffi/util").template +local T = ffiutil.template local MyClipping = { my_clippings = "/mnt/us/documents/My Clippings.txt", - history_dir = "./history", } function MyClipping:new(o) @@ -333,18 +333,22 @@ end function MyClipping:parseHistory() local clippings = {} - for f in lfs.dir(self.history_dir) do - self:parseHistoryFile(clippings, - self.history_dir .. "/" .. f, - DocSettings:getPathFromHistory(f) .. "/" .. - DocSettings:getNameFromHistory(f)) + local history_dir = DataStorage:getHistoryDir() + for f in lfs.dir(history_dir) do + local legacy_history_file = ffiutil.joinPath(history_dir, f) + if lfs.attributes(legacy_history_file, "mode") == "file" then + local doc_file = DocSettings:getFileFromHistory(f) + if doc_file then + self:parseHistoryFile(clippings, legacy_history_file, doc_file) + end + end end - for _, item in ipairs(ReadHistory.hist) do - self:parseHistoryFile(clippings, - DocSettings:getSidecarFile(item.file), - item.file) + for _, item in ipairs(require("readhistory").hist) do + if not item.dim then + self:parseHistoryFile(clippings, DocSettings:getSidecarFile(item.file, "doc"), item.file) + self:parseHistoryFile(clippings, DocSettings:getSidecarFile(item.file, "dir"), item.file) + end end - return clippings end diff --git a/spec/unit/docsettings_spec.lua b/spec/unit/docsettings_spec.lua index 58df901e5..e76070ff9 100644 --- a/spec/unit/docsettings_spec.lua +++ b/spec/unit/docsettings_spec.lua @@ -1,20 +1,38 @@ describe("docsettings module", function() - local docsettings, lfs, util + local DataStorage, docsettings, docsettings_dir, ffiutil, lfs setup(function() require("commonrequire") + DataStorage = require("datastorage") docsettings = require("docsettings") + ffiutil = require("ffi/util") lfs = require("libs/libkoreader-lfs") - util = require("ffi/util") + + docsettings_dir = DataStorage:getDocSettingsDir() + end) + + it("should generate sidecar folder path in book folder (by default)", function() + G_reader_settings:delSetting("document_metadata_folder") + assert.Equals("../../foo.sdr", docsettings:getSidecarDir("../../foo.pdf")) + assert.Equals("/foo/bar.sdr", docsettings:getSidecarDir("/foo/bar.pdf")) + assert.Equals("baz.sdr", docsettings:getSidecarDir("baz.pdf")) end) - it("should generate sidecar directory path", function() + it("should generate sidecar folder path in book folder", function() + G_reader_settings:saveSetting("document_metadata_folder", "doc") assert.Equals("../../foo.sdr", docsettings:getSidecarDir("../../foo.pdf")) assert.Equals("/foo/bar.sdr", docsettings:getSidecarDir("/foo/bar.pdf")) assert.Equals("baz.sdr", docsettings:getSidecarDir("baz.pdf")) end) - it("should generate sidecar metadata file", function() + it("should generate sidecar folder path in docsettings folder", function() + G_reader_settings:saveSetting("document_metadata_folder", "dir") + assert.Equals(docsettings_dir.."/foo/bar.sdr", docsettings:getSidecarDir("/foo/bar.pdf")) + assert.Equals(docsettings_dir.."baz.sdr", docsettings:getSidecarDir("baz.pdf")) + end) + + it("should generate sidecar metadata file (book folder)", function() + G_reader_settings:saveSetting("document_metadata_folder", "doc") assert.Equals("../../foo.sdr/metadata.pdf.lua", docsettings:getSidecarFile("../../foo.pdf")) assert.Equals("/foo/bar.sdr/metadata.pdf.lua", @@ -23,7 +41,16 @@ describe("docsettings module", function() docsettings:getSidecarFile("baz.epub")) end) + it("should generate sidecar metadata file (docsettings folder)", function() + G_reader_settings:saveSetting("document_metadata_folder", "dir") + assert.Equals(docsettings_dir.."/foo/bar.sdr/metadata.pdf.lua", + docsettings:getSidecarFile("/foo/bar.pdf")) + assert.Equals(docsettings_dir.."baz.sdr/metadata.epub.lua", + docsettings:getSidecarFile("baz.epub")) + end) + it("should read legacy history file", function() + G_reader_settings:delSetting("document_metadata_folder") local file = "file.pdf" local d = docsettings:open(file) d:saveSetting("a", "b") @@ -32,15 +59,15 @@ describe("docsettings module", function() -- Now the sidecar file should be written. local legacy_files = { - d.history_file, - d.sidecar .. "/file.pdf.lua", + docsettings:getHistoryPath(file), + d.doc_sidecar_dir .. "/file.pdf.lua", "file.pdf.kpdfview.lua", } - for _, f in pairs(legacy_files) do - assert.False(os.rename(d.sidecar_file, f) == nil) + for _, f in ipairs(legacy_files) do + assert.False(os.rename(d.doc_sidecar_file, f) == nil) d = docsettings:open(file) - assert.True(os.remove(d.sidecar_file) == nil) + assert.True(os.remove(d.doc_sidecar_file) == nil) -- Legacy history files should not be removed before flush has been -- called. assert.Equals(lfs.attributes(f, "mode"), "file") @@ -53,7 +80,7 @@ describe("docsettings module", function() assert.True(os.remove(f) == nil) end - assert.False(os.remove(d.sidecar_file) == nil) + assert.False(os.remove(d.doc_sidecar_file) == nil) d:purge() end) @@ -62,20 +89,20 @@ describe("docsettings module", function() local d = docsettings:open(file) local legacy_files = { - d.history_file, - d.sidecar .. "/file.pdf.lua", + docsettings:getHistoryPath(file), + d.doc_sidecar_dir .. "/file.pdf.lua", "file.pdf.kpdfview.lua", } -- docsettings:flush will remove legacy files. - for i, v in pairs(legacy_files) do + for i, v in ipairs(legacy_files) do d:saveSetting("a", i) d:flush() - assert.False(os.rename(d.sidecar_file, v.."1") == nil) + assert.False(os.rename(d.doc_sidecar_file, v.."1") == nil) end d:close() - for _, v in pairs(legacy_files) do + for _, v in ipairs(legacy_files) do assert.False(os.rename(v.."1", v) == nil) end @@ -87,45 +114,46 @@ describe("docsettings module", function() it("should build correct legacy history path", function() local file = "/a/b/c--d/c.txt" - local history_path = util.basename(docsettings:getHistoryPath(file)) + local history_path = ffiutil.basename(docsettings:getHistoryPath(file)) local path_from_history = docsettings:getPathFromHistory(history_path) local name_from_history = docsettings:getNameFromHistory(history_path) assert.is.same(file, path_from_history .. "/" .. name_from_history) end) it("should reserve last good file", function() + G_reader_settings:delSetting("document_metadata_folder") local file = "file.pdf" local d = docsettings:open(file) d:saveSetting("a", "a") d:flush() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) d:flush() -- metadata.pdf.lua.old should not yet be generated. - assert.are.not_equal("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.are.not_equal("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- make metadata.pdf.lua older to bypass 60s age needed for .old rotation local minutes_ago = os.time() - 120 - lfs.touch(d.sidecar_file, minutes_ago) + lfs.touch(d.doc_sidecar_file, minutes_ago) d:close() -- metadata.pdf.lua and metadata.pdf.lua.old should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- write some garbage to sidecar-file. - local f_out = io.open(d.sidecar_file, "w") + local f_out = io.open(d.doc_sidecar_file, "w") f_out:write("bla bla bla") f_out:close() d = docsettings:open(file) -- metadata.pdf.lua should be removed. - assert.are.not_equal("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.are.not_equal("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) assert.Equals("a", d:readSetting("a")) d:saveSetting("a", "b") d:close() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- The contents in sidecar_file and sidecar_file.old are different. -- a:b v.s. a:a @@ -133,87 +161,89 @@ describe("docsettings module", function() -- The content should come from sidecar_file. assert.Equals("b", d:readSetting("a")) -- write some garbage to sidecar-file. - f_out = io.open(d.sidecar_file, "w") + f_out = io.open(d.doc_sidecar_file, "w") f_out:write("bla bla bla") f_out:close() -- do not flush the result, open docsettings again. d = docsettings:open(file) -- metadata.pdf.lua should be removed. - assert.are.not_equal("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.are.not_equal("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- The content should come from sidecar_file.old. assert.Equals("a", d:readSetting("a")) d:close() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) end) describe("ignore empty sidecar file", function() it("should ignore empty file", function() + G_reader_settings:delSetting("document_metadata_folder") local file = "file.pdf" local d = docsettings:open(file) d:saveSetting("a", "a") d:flush() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) -- make metadata.pdf.lua older to bypass 60s age needed for .old rotation local minutes_ago = os.time() - 120 - lfs.touch(d.sidecar_file, minutes_ago) + lfs.touch(d.doc_sidecar_file, minutes_ago) d:close() -- metadata.pdf.lua and metadata.pdf.lua.old should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- reset the sidecar_file to an empty file. - local f_out = io.open(d.sidecar_file, "w") + local f_out = io.open(d.doc_sidecar_file, "w") f_out:close() d = docsettings:open(file) -- metadata.pdf.lua should be removed. - assert.are.not_equal("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.are.not_equal("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) assert.Equals("a", d:readSetting("a")) d:saveSetting("a", "b") d:close() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- The contents in sidecar_file and sidecar_file.old are different. -- a:b v.s. a:a end) it("should ignore empty table", function() + G_reader_settings:delSetting("document_metadata_folder") local file = "file.pdf" local d = docsettings:open(file) d:saveSetting("a", "a") d:flush() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) -- make metadata.pdf.lua older to bypass 60s age needed for .old rotation local minutes_ago = os.time() - 120 - lfs.touch(d.sidecar_file, minutes_ago) + lfs.touch(d.doc_sidecar_file, minutes_ago) d:close() -- metadata.pdf.lua and metadata.pdf.lua.old should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- reset the sidecar_file to an empty file. - local f_out = io.open(d.sidecar_file, "w") + local f_out = io.open(d.doc_sidecar_file, "w") f_out:write("{ } ") f_out:close() d = docsettings:open(file) -- metadata.pdf.lua should be removed. - assert.are.not_equal("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.are.not_equal("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) assert.Equals("a", d:readSetting("a")) d:saveSetting("a", "b") d:close() -- metadata.pdf.lua should be generated. - assert.Equals("file", lfs.attributes(d.sidecar_file, "mode")) - assert.Equals("file", lfs.attributes(d.sidecar_file .. ".old", "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file, "mode")) + assert.Equals("file", lfs.attributes(d.doc_sidecar_file .. ".old", "mode")) -- The contents in sidecar_file and sidecar_file.old are different. -- a:b v.s. a:a end)