Skip to content

Commit

Permalink
Merge pull request #58 from LintaoAmons/db-backup
Browse files Browse the repository at this point in the history
feat: add database backup functionality
  • Loading branch information
LintaoAmons authored Dec 31, 2024
2 parents c848bcb + e6c0b84 commit 3323bfe
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
100 changes: 100 additions & 0 deletions lua/bookmarks/backup/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
local M = {}
local fn = vim.fn
local uv = vim.loop

---Get backup directory path from config or fallback
---@param backup_dir? string
---@return string
local function get_backup_dir(backup_dir)
if not backup_dir then
return fn.stdpath("data") .. "/bookmarks.backup"
end
return backup_dir
end
M.get_backup_dir = get_backup_dir

---Create backup directory if it doesn't exist
---@param dir string
local function ensure_backup_dir(dir)
if fn.isdirectory(dir) == 0 then
local ok = fn.mkdir(dir, "p")
if ok == 0 then
error(string.format("Failed to create backup directory: %s", dir))
end
end
end

---@param src string Source file path
---@param dst string Destination file path
local function copy_file(src, dst)
local source = uv.fs_open(src, "r", 438)
if not source then
error(string.format("Failed to open source file: %s", src))
return
end

local stat = uv.fs_fstat(source)
if not stat then
uv.fs_close(source)
error(string.format("Failed to stat source file: %s", src))
return
end

local data = uv.fs_read(source, stat.size, 0)
uv.fs_close(source)

local dest = uv.fs_open(dst, "w", 438)
if not dest then
error(string.format("Failed to open destination file: %s", dst))
return
end

uv.fs_write(dest, data)
uv.fs_close(dest)
end

---Create backup of database file
---@param db_path string Path to database file
---@param backup_dir string Path to backup directory
---@return string|nil # Backup file path or nil if backup failed
local function create_backup(db_path, backup_dir)
-- Check if source file exists
if fn.filereadable(db_path) == 0 then
return
end

local timestamp = os.date("%Y%m%d_%H%M%S")
local backup_path = string.format("%s/bookmarks_%s.sqlite.db", backup_dir, timestamp)
copy_file(db_path, backup_path)
return backup_path
end

---Setup backup with 5-minute delay
---@param config table
---@param db_path string
function M.setup(config, db_path)
if not config.backup.enabled then
return
end

local backup_dir = get_backup_dir(config.backup.dir)
ensure_backup_dir(backup_dir)

-- Create a one-shot timer for delayed backup
local timer = uv.new_timer()
timer:start(
config.backup.delay * 60 * 1000,
-- 5, -- For testing
0,
vim.schedule_wrap(function()
local backup_path = create_backup(db_path, backup_dir)
vim.notify("Bookmarks backup created: " .. backup_path, vim.log.levels.INFO, { title = "Bookmarks.nvim" })
timer:close()
end)
)

-- Store timer reference to prevent garbage collection
M._timer = timer
end

return M
10 changes: 10 additions & 0 deletions lua/bookmarks/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ local default_config = {
-- 2. Create `bookmarks.sqlite.db` inside this directory
---@type string?
db_dir = nil, -- if nil, fallback to default `stdpath("data")`
backup = {
enabled = true,
-- Directory to store backup files
-- Default: vim.fn.stdpath("data").."/bookmarks.backup"
-- You can set a custom directory
---@type string?
dir = nil,
delay = 5, -- Delay in minutes before nvim opened, no back will be created if nvim earlier than the actually backup time
},

-- Navigation configurations
navigation = {
Expand Down Expand Up @@ -127,6 +136,7 @@ local setup = function(user_config)
require("bookmarks.domain.repo").setup(get_db_path(cfg.db_dir))
require("bookmarks.sign").setup(cfg.signs)
require("bookmarks.auto-cmd").setup()
require("bookmarks.backup").setup(cfg, get_db_path(cfg.db_dir))
end

return {
Expand Down
5 changes: 4 additions & 1 deletion lua/bookmarks/info/init.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
local Repo = require("bookmarks.domain.repo")
local Window = require("bookmarks.utils.window")
local Location = require("bookmarks.domain.location")
local Backup = require("bookmarks.backup")

local M = {}

Expand Down Expand Up @@ -44,6 +45,7 @@ end

---Get info of bookmarks
function M.get_info()
local config = vim.g.bookmarks_config or {}
local sections = {
"# Bookmarks Info\n",
}
Expand All @@ -60,11 +62,12 @@ function M.get_info()
table.insert(sections, string.format("- Total Bookmarks: `%d`\n", #all_bookmarks))
table.insert(sections, string.format("- Total Lists: `%d`\n", #all_lists))
table.insert(sections, string.format("- Database Location: `%s`\n", Repo._DB.uri))
local backup_dir = Backup.get_backup_dir(config.backup.dir)
table.insert(sections, string.format("- Backup Location: `%s`\n", backup_dir))

-- Configuration section
table.insert(sections, "## Configuration\n")
table.insert(sections, "```lua")
local config = vim.g.bookmarks_config or {}
for key, value in pairs(config) do
if type(value) ~= "function" then
table.insert(sections, string.format("%s = %s", key, vim.inspect(value)))
Expand Down

0 comments on commit 3323bfe

Please sign in to comment.