Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Implement backup system #45

Merged
merged 26 commits into from
Sep 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
2c5a6b7
impl DB.Init fn
Krealle Sep 1, 2024
6de0414
impl automatic backups on version change
Krealle Sep 1, 2024
11e54f5
new Util:GetFormattedTimeStamp fn
Krealle Sep 1, 2024
6048ff6
new Util:GetFormattedDate dn
Krealle Sep 1, 2024
09c1050
local Util
Krealle Sep 1, 2024
e9ab1e4
add some MARKs
Krealle Sep 1, 2024
4e74b2f
make NormalizeLayoutName a Util fn
Krealle Sep 1, 2024
3178fdd
add option to add color code to layout name
Krealle Sep 1, 2024
378f38c
wrap layouts in popup outside of locale string
Krealle Sep 1, 2024
dd0dce6
bump CUF.version to 2
Krealle Sep 1, 2024
65461bb
create version backup on InitDB instead of VerifyDB
Krealle Sep 1, 2024
2f8984b
improve CreateVersionBackup logic and make it give printed msg when r…
Krealle Sep 1, 2024
cc1b50d
make generic function for creating a backup
Krealle Sep 1, 2024
da6af51
manual backup fn
Krealle Sep 1, 2024
c278ea9
create wrapper frames for generalTab sections
Krealle Sep 1, 2024
77360f1
create util fns for getting layout names
Krealle Sep 1, 2024
fec3df0
use new util fns
Krealle Sep 1, 2024
8f17a83
impl option to create a backup
Krealle Sep 1, 2024
ff3d982
impl option to restore a backup
Krealle Sep 1, 2024
76aae6a
fix shortcircuit case for updating widgetList
Krealle Sep 1, 2024
b872573
rename automatic backup to automatic instead of version
Krealle Sep 1, 2024
ac16a5e
verify DB after restore
Krealle Sep 1, 2024
b5494a3
fire LoadPageDB on DB restore
Krealle Sep 1, 2024
9f147a2
add slashcommand for restoring
Krealle Sep 1, 2024
a83163c
create backup options dynamically
Krealle Sep 1, 2024
ab97d60
don't allow restoring when in combat
Krealle Sep 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Core/Init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
local CUF = select(2, ...)
_G.CUF = CUF

CUF.version = 1
CUF.version = 2

CUF.Cell = Cell

Expand Down
2 changes: 1 addition & 1 deletion Core/OnLoad.lua
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ end
local function OnAddonLoaded(owner, loadedAddonName)
if loadedAddonName == AddonName then
-- Load our DB
CUF_DB = CUF_DB or {}
CUF.DB.InitDB()

-- Load Cell and type it
CUF.Cell = Cell
Expand Down
9 changes: 8 additions & 1 deletion Core/SlashCommands.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ function SlashCmdList.CUF(msg, editbox)
CUF.SetDebugMode(not CUF.IsInDebugMode())
Debug:ToggleDebugWindow()
CUF:Print("Debug: " .. (CUF.IsInDebugMode() and "ON" or "OFF"))
elseif command == "restore" then
if rest ~= "automatic" and rest ~= "manual" then
CUF:Print("Usage: /cuf restore <automatic|manual>")
return
end
CUF.DB.RestoreFromBackup(rest)
else
CUF:Print("Available commands:" .. "\n" ..
"/cuf test - toggle test mode" .. "\n" ..
"/cuf dev - toggle debug mode"
"/cuf dev - toggle debug mode" .. "\n" ..
"/cuf restore <automatic|manual> - restore a backup"
)
end
end
147 changes: 142 additions & 5 deletions Data/DBUtil.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ local CUF = select(2, ...)
---@class CUF.database
local DB = CUF.DB

local Util = CUF.Util
local L = CUF.L

-- Props that should only be initialized once
-- eg we only want to initialize filters, not keep adding to them
-- which would potentially add spells that are unwanted by the user
Expand All @@ -13,11 +16,28 @@ DB.PropsToOnlyInit = {
whitelist = true,
}

--- Initialize the DB
function DB.InitDB()
CUF_DB = CUF_DB or {}

-- Backups
---@class CUF.database.backups
---@field automatic CUF.database.backup
---@field manual CUF.database.backup
CUF_DB.backups = CUF_DB.backups or {}

DB.CreateAutomaticBackup()
end

-----------------------------------------
-- MARK: Copy
-----------------------------------------

-- Copy ALL settings from one layout to another
---@param from string
---@param to string
function DB.CopyFullLayout(from, to)
CellDB.layouts[to].CUFUnits = CUF.Util:CopyDeep(DB.GetLayoutTable(from))
CellDB.layouts[to].CUFUnits = Util:CopyDeep(DB.GetLayoutTable(from))
end

--- Copy ALL widget settings from one unit to another
Expand All @@ -34,11 +54,128 @@ function DB.CopyWidgetSettings(from, to)

for widgetName, widgetTable in pairs(fromWidgetTables) do
if toWidgetTables[widgetName] then
toWidgetTables[widgetName] = CUF.Util:CopyDeep(widgetTable)
toWidgetTables[widgetName] = Util:CopyDeep(widgetTable)
end
end
end

-----------------------------------------
-- MARK: Backup
-----------------------------------------

---@class CUF.database.backup
---@field timestamp string
---@field CUFVersion number
---@field layouts table<string, UnitLayoutTable>
---@field layoutNames string

--- Generic function to create a backup of the current layotus
---@param backupType "manual"|"automatic" the type of backup to create
---@param msg string the message to print to the chat window
local function CreateBackup(backupType, msg)
CUF_DB.backups[backupType] = CUF_DB.backups[backupType] or {}
CUF_DB.backups[backupType].layouts = CUF_DB.backups[backupType].layouts or {}

---@type CUF.database.backup
local backup = CUF_DB.backups[backupType]

-- Clear old backups
wipe(backup.layouts)

local timestamp = string.format("%s, %s", CUF.Util:GetFormattedTimeStamp(), CUF.Util:GetFormattedDate())
backup.timestamp = timestamp
backup.CUFVersion = CUF.version

for layoutName, layoutTable in pairs(CellDB.layouts) do
backup.layouts[layoutName] = Util:CopyDeep(layoutTable.CUFUnits)
end

local layoutNames = Util:GetAllLayoutNamesAsString(true)
backup.layoutNames = layoutNames

CUF:Print(msg, layoutNames)
end

--- Create a backup of the current layotus
---
--- This is used to create to a backup for updates that either:
---
--- A) Change the way the layout is stored
--- B) Implement poentially breaking changes
--- C) Prevent data loss due to a bug
function DB.CreateAutomaticBackup()
if not CUF_DB.version -- First time addon is loaded, nothing to backup
or (CUF_DB.backups.automatic and CUF_DB.backups.automatic.CUFVersion == CUF.version) then
return
end

CreateBackup("automatic", L.CreatedAutomaticBackup)
end

--- Create a backup of the current layotus
---
--- Overrides old manual backup
function DB.CreateManulBackup()
CreateBackup("manual", L.CreatedManualBackup)
end

--- Restore layouts from a backup
---@param backupType "manual"|"automatic"
function DB.RestoreFromBackup(backupType)
if InCombatLockdown() then
CUF:Warn("Can't restore while in combat!")
return
end

---@type CUF.database.backup
local backup = CUF_DB.backups[backupType]
CUF:Log("|cff00ccffRestoreBackup:|r", backupType, backup.timestamp)

if not backup then
CUF:Warn("Failed to restore! No backup found.")
return
end

-- TODO: Later this should bounce the restore completely on version mismatch
-- For now it might be okay to just verify the DB
if backup.CUFVersion ~= CUF.version then
CUF:Log("Old version detected, verifying DB.", "Backup:", backup.CUFVersion, "New:", CUF.version)
end

for layoutName, backupLayoutTable in pairs(backup.layouts) do
if not CellDB.layouts[layoutName] then
CUF:Warn("Failed to restore Layout:", Util:FormatLayoutName(layoutName, true),
" - Layout is missing from Cell!")
else
CUF:Print("Restored:", Util:FormatLayoutName(layoutName, true))
CUF:DevAdd({ layoutTable = CellDB.layouts[layoutName].CUFUnits, backup = backupLayoutTable }, layoutName)
CellDB.layouts[layoutName].CUFUnits = Util:CopyDeep(backupLayoutTable)
end
end

DB.VerifyDB()

CUF:Fire("LoadPageDB", CUF.vars.selectedUnit, CUF.vars.selectedWidget)
CUF:Fire("UpdateUnitButtons")
CUF:Fire("UpdateWidget", DB.GetMasterLayout())
end

---@param backupType "manual"|"automatic"
function DB.GetBackupInfo(backupType)
---@type CUF.database.backup
local backup = CUF_DB.backups[backupType]
if not backup then return "" end

local name = "|cffffa500" .. L["Backup_" .. backupType] .. ":|r"
local info = string.format(L.BackupInfo, name, backup.timestamp, backup.layoutNames)

return info
end

-----------------------------------------
-- MARK: Verify
-----------------------------------------

-- Make sure that we have an active CellDB and that it has all the UnitLayouts we need
---@return false? noCellDB If CellDB is not present
function DB.VerifyDB()
Expand All @@ -51,8 +188,8 @@ function DB.VerifyDB()
if type(layoutTable.CUFUnits[unit]) ~= "table" then
layoutTable.CUFUnits[unit] = Cell.funcs:Copy(unitLayout)
else
CUF.Util:AddMissingProps(layoutTable.CUFUnits[unit], unitLayout, DB.PropsToOnlyInit)
--CUF.Util:RenameProp(layoutTable.CUFUnits[unit], "pointTo", "relativePoint")
Util:AddMissingProps(layoutTable.CUFUnits[unit], unitLayout, DB.PropsToOnlyInit)
--Util:RenameProp(layoutTable.CUFUnits[unit], "pointTo", "relativePoint")

-- Remove any widgets that shouldn't be there
for widgetName, _ in pairs(layoutTable.CUFUnits[unit].widgets) do
Expand All @@ -75,7 +212,7 @@ function DB.VerifyMasterLayout()

local masterLayoutIsValid = false

for layoutName, _ in pairs(CellDB.layouts) do
for _, layoutName in pairs(Util:GetAllLayoutNames()) do
if layoutName == masterLayout then
masterLayoutIsValid = true
end
Expand Down
25 changes: 24 additions & 1 deletion Locales/enUS.lua
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,29 @@ L.CopyLayoutFrom = "Copy Layout From"
L.CopyFromTooltip = [[|cFFFF0000This will overwrite all settings in the current layout!|r

Copy settings from another layout]]
L.CopyFromPopUp = "Copy settings from |cFFFFD700%s|r to |cFFFFD700%s|r?"
L.CopyFromPopUp = "Copy settings from %s to %s?"

L.CopyWidgetsFrom = "Copy Widgets From"
L.CopyWidgetsFromTooltip = "Copy widget settings from another unit"
L.Backups = "Backups"
L.RestoreBackup = "Restore Backup"
L.RestoreBackupTooltip = [[Restores a backup of Cell UnitFrame settings

%s

%s]]
L.BackupInfo = [[%s created: %s
Layouts: %s]]
L.CreateBackup = "Create Backup"
L.CreateBackupTooltip = [[Creates a backup of Cell UnitFrame settings for these layouts:
%s]]
L.CreateBackupPopup = [[Create a backup for these layouts?
%s]]
L.BackupOverwrite = [[This will overwrite your previous backup:
%s]]
L.RestoreBackupPopup = [[Restore this backup?
%s]]

-- Units
L.targettarget = "TargetTarget"
L.player = "Player"
Expand Down Expand Up @@ -120,6 +139,10 @@ L.RelativeTo = "Relative To"
L.Texture = "Texture"
L["left"] = "Left"
L["right"] = "Right"
L.CreatedAutomaticBackup = "New version detected. Created backups for:"
L.CreatedManualBackup = "Created manual backups for:"
L.Backup_manual = "Manual Backup"
L.Backup_automatic = "Automatic Backup"

-- Custom Formats
L.ValidTags = "Valid Tags"
Expand Down
Loading