This commit is contained in:
Insality
2025-11-10 22:32:11 +02:00
parent e130e39789
commit 9b8ff949bf
3 changed files with 140 additions and 57 deletions

View File

@@ -42,19 +42,115 @@ local function download_file_zip_json(url)
end
---Find widget by dependency string (format: "author:widget_id@version" or "author@widget_id" or "widget_id")
---@param dep_string string - Dependency string
---@param all_items table - List of all available widgets
---@return table|nil - Found widget item or nil
local function find_widget_by_dependency(dep_string, all_items)
if not dep_string or not all_items then
return nil
end
local author, widget_id
-- Try format: "author:widget_id@version" (e.g., "Insality:mini_graph@1")
author, widget_id = dep_string:match("^([^:]+):([^@]+)@")
if not author then
-- Try format: "author@widget_id" (e.g., "insality@mini_graph")
author, widget_id = dep_string:match("^([^@]+)@(.+)$")
if not author then
-- No author specified, search by widget_id only
widget_id = dep_string
end
end
for _, item in ipairs(all_items) do
if item.id == widget_id then
-- If author was specified, check it matches (case-insensitive)
if not author or string.lower(item.author or "") == string.lower(author) then
return item
end
end
end
return nil
end
---Install widget dependencies recursively
---@param item druid.core.item_info - Widget item
---@param all_items table - List of all available widgets
---@param install_folder string - Installation folder
---@param installing_set table - Set of widget IDs currently being installed (to prevent cycles)
---@return boolean, string|nil - Success status and message
local function install_dependencies(item, all_items, install_folder, installing_set)
if not item.depends or #item.depends == 0 then
return true, nil
end
installing_set = installing_set or {}
for _, dep_string in ipairs(item.depends) do
local dep_item = find_widget_by_dependency(dep_string, all_items)
if not dep_item then
print("Warning: Dependency not found:", dep_string)
-- Continue with other dependencies
else
-- Check if already installed
if M.is_widget_installed(dep_item, install_folder) then
print("Dependency already installed:", dep_item.id)
else
-- Check for circular dependencies
if installing_set[dep_item.id] then
print("Warning: Circular dependency detected:", dep_item.id)
-- Continue with other dependencies
else
print("Installing dependency:", dep_item.id)
local success, err = M.install_widget(dep_item, install_folder, all_items, installing_set)
if not success then
return false, "Failed to install dependency " .. dep_item.id .. ": " .. (err or "unknown error")
end
end
end
end
end
return true, nil
end
---Install a widget from a zip URL
---@param item druid.core.item_info - Widget item data containing zip_url and id
---@param install_folder string - Target folder to install to
---@param all_items table|nil - Optional list of all widgets for dependency resolution
---@param installing_set table|nil - Optional set of widget IDs currently being installed (to prevent cycles)
---@return boolean, string - Success status and message
function M.install_widget(item, install_folder)
function M.install_widget(item, install_folder, all_items, installing_set)
if not item.json_zip_url or not item.id then
return false, "Invalid widget data: missing zip_url or id"
return false, "Invalid widget data: missing json_zip_url or id"
end
-- Install dependencies first if all_items is provided
if all_items then
installing_set = installing_set or {}
if installing_set[item.id] then
return false, "Circular dependency detected: " .. item.id
end
installing_set[item.id] = true
local dep_success, dep_err = install_dependencies(item, all_items, install_folder, installing_set)
if not dep_success then
installing_set[item.id] = nil
return false, dep_err or "Failed to install dependencies"
end
end
-- Download the zip file
local zip_data, filename, content_list = download_file_zip_json(item.json_zip_url)
if not zip_data or not filename then
return false, "Failed to download widget: " .. filename
if installing_set then
installing_set[item.id] = nil
end
return false, "Failed to download widget: " .. (filename or "unknown error")
end
if content_list then
@@ -67,6 +163,9 @@ function M.install_widget(item, install_folder)
local zip_file_path = "." .. install_folder .. "/" .. filename
local zip_file = io.open(zip_file_path, "wb")
if not zip_file then
if installing_set then
installing_set[item.id] = nil
end
print("Directory does not exist: " .. install_folder)
print("Please create the directory manually and try again.")
return false, "Directory does not exist: " .. install_folder
@@ -97,6 +196,10 @@ function M.install_widget(item, install_folder)
print("Warning: No file list available, skipping path replacement")
end
if installing_set then
installing_set[item.id] = nil
end
return true, "Widget installed successfully"
end