mirror of
https://github.com/Insality/druid.git
synced 2025-11-26 19:00:50 +01:00
up
This commit is contained in:
@@ -42,12 +42,13 @@ end
|
||||
---Handle widget installation
|
||||
---@param item table - Widget item to install
|
||||
---@param install_folder string - Installation folder
|
||||
---@param all_items table - List of all widgets for dependency resolution
|
||||
---@param on_success function - Success callback
|
||||
---@param on_error function - Error callback
|
||||
local function handle_install(item, install_folder, on_success, on_error)
|
||||
local function handle_install(item, install_folder, all_items, on_success, on_error)
|
||||
print("Installing widget:", item.id)
|
||||
|
||||
local success, message = installer.install_widget(item, install_folder)
|
||||
local success, message = installer.install_widget(item, install_folder, all_items)
|
||||
|
||||
if success then
|
||||
print("Installation successful:", message)
|
||||
@@ -115,7 +116,7 @@ function M.open_asset_store(store_url)
|
||||
|
||||
-- Installation handlers
|
||||
local function on_install(item)
|
||||
handle_install(item, install_folder,
|
||||
handle_install(item, install_folder, all_items,
|
||||
function(message)
|
||||
set_install_status("Success: " .. message)
|
||||
end,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -6,29 +6,15 @@ local system = require("druid.editor_scripts.defold_parser.system.parser_interna
|
||||
local M = {}
|
||||
|
||||
|
||||
---Detect the original path structure from item data
|
||||
---Builds widget/author/widget_id path
|
||||
---@param author string|nil - Author name
|
||||
---@param widget_id string - Widget ID
|
||||
---@return string|nil - Original path prefix (e.g., "widget/Insality/fps_panel") or nil
|
||||
local function detect_original_path_from_item(author, widget_id)
|
||||
if not author or not widget_id then
|
||||
return nil
|
||||
end
|
||||
|
||||
local original_path = "widget/" .. author .. "/" .. widget_id
|
||||
print("Detected original path from item:", original_path)
|
||||
return original_path
|
||||
end
|
||||
|
||||
|
||||
---Replace paths in file content
|
||||
---@param content string - File content
|
||||
---@param original_path string - Original path to replace (e.g., "widget/Insality/fps_panel")
|
||||
---@param target_path string - Target path (e.g., "widget/fps_panel")
|
||||
---@param author string - Author name (e.g., "Insality")
|
||||
---@param install_folder string - Installation folder (e.g., "widget")
|
||||
---@return string - Modified content
|
||||
local function replace_paths_in_content(content, original_path, target_path)
|
||||
if not content or not original_path or not target_path then
|
||||
local function replace_paths_in_content(content, author, install_folder)
|
||||
if not content or not author then
|
||||
return content
|
||||
end
|
||||
|
||||
@@ -37,15 +23,28 @@ local function replace_paths_in_content(content, original_path, target_path)
|
||||
return str:gsub("[%^%$%(%)%%%.%[%]%*%+%-%?]", "%%%0")
|
||||
end
|
||||
|
||||
-- Replace paths with forward slashes: widget/Insality/fps_panel -> widget/fps_panel
|
||||
local escaped_original = escape_pattern(original_path)
|
||||
content = content:gsub(escaped_original, target_path)
|
||||
-- Remove leading / from install_folder if present
|
||||
local clean_install_folder = install_folder
|
||||
if clean_install_folder:sub(1, 1) == "/" then
|
||||
clean_install_folder = clean_install_folder:sub(2)
|
||||
end
|
||||
|
||||
-- Replace require statements with dots: widget.Insality.fps_panel -> widget.fps_panel
|
||||
local original_dots = original_path:gsub("/", ".")
|
||||
local target_dots = target_path:gsub("/", ".")
|
||||
local escaped_original_dots = escape_pattern(original_dots)
|
||||
content = content:gsub(escaped_original_dots, target_dots)
|
||||
-- Replace all paths with author: widget/Insality/* -> widget/*
|
||||
local author_path_pattern = escape_pattern(clean_install_folder .. "/" .. author .. "/")
|
||||
local target_path_prefix = clean_install_folder .. "/"
|
||||
content = content:gsub(author_path_pattern, target_path_prefix)
|
||||
|
||||
-- Replace all require statements with dots: widget.Insality.* -> widget.*
|
||||
local author_dots_pattern = escape_pattern(clean_install_folder .. "." .. author .. ".")
|
||||
local target_dots_prefix = clean_install_folder .. "."
|
||||
content = content:gsub(author_dots_pattern, target_dots_prefix)
|
||||
|
||||
-- Also replace paths that start with author directly: Insality/widget -> widget
|
||||
-- But only if they're in require statements or paths
|
||||
local author_start_pattern = escape_pattern(author .. "/")
|
||||
content = content:gsub(author_start_pattern, "")
|
||||
local author_start_dots_pattern = escape_pattern(author .. ".")
|
||||
content = content:gsub(author_start_dots_pattern, "")
|
||||
|
||||
return content
|
||||
end
|
||||
@@ -61,31 +60,12 @@ end
|
||||
function M.process_widget_paths(folder_path, install_folder, widget_id, author, file_list)
|
||||
print("Processing widget paths in:", folder_path)
|
||||
|
||||
-- Detect original path structure from item data
|
||||
local original_path = detect_original_path_from_item(author, widget_id)
|
||||
|
||||
if not original_path then
|
||||
print("Warning: Could not detect original path structure (missing author or widget_id), skipping path replacement")
|
||||
if not author then
|
||||
print("Warning: Missing author, skipping path replacement")
|
||||
return true, nil
|
||||
end
|
||||
|
||||
-- Construct target path
|
||||
-- Remove leading / from install_folder if present
|
||||
local clean_install_folder = install_folder
|
||||
if clean_install_folder:sub(1, 1) == "/" then
|
||||
clean_install_folder = clean_install_folder:sub(2)
|
||||
end
|
||||
|
||||
local target_path = clean_install_folder
|
||||
if widget_id then
|
||||
if target_path ~= "" then
|
||||
target_path = target_path .. "/" .. widget_id
|
||||
else
|
||||
target_path = widget_id
|
||||
end
|
||||
end
|
||||
|
||||
print("Replacing paths from:", original_path, "to:", target_path)
|
||||
print("Replacing all paths with author:", author, "in install folder:", install_folder)
|
||||
|
||||
-- Get absolute project path
|
||||
local absolute_project_path = editor.external_file_attributes(".").path
|
||||
@@ -120,8 +100,8 @@ function M.process_widget_paths(folder_path, install_folder, widget_id, author,
|
||||
if not content then
|
||||
print("Warning: Could not read file:", file_path, err)
|
||||
else
|
||||
-- Replace paths
|
||||
local modified_content = replace_paths_in_content(content, original_path, target_path)
|
||||
-- Replace all paths with author
|
||||
local modified_content = replace_paths_in_content(content, author, install_folder)
|
||||
if modified_content ~= content then
|
||||
-- Write modified content back
|
||||
local success, write_err = system.write_file(absolute_file_path, modified_content)
|
||||
@@ -141,4 +121,3 @@ end
|
||||
|
||||
|
||||
return M
|
||||
|
||||
|
||||
Reference in New Issue
Block a user