|
|
@@ -97,7 +97,7 @@ end
|
|
|
-- Simple JSON parser for registry (basic implementation)
|
|
|
local function parse_json_simple(str)
|
|
|
-- Very basic JSON object parser for our simple registry format
|
|
|
- -- Format: { "name": { "url": "...", "description": "..." }, ... }
|
|
|
+ -- Format: { "name": { "url": "...", "path": "...", "description": "..." }, ... }
|
|
|
local result = {}
|
|
|
|
|
|
-- Remove outer braces and whitespace
|
|
|
@@ -108,6 +108,7 @@ local function parse_json_simple(str)
|
|
|
for name, content in str:gmatch('"([^"]+)"%s*:%s*({[^}]*})') do
|
|
|
local entry = {}
|
|
|
entry.url = content:match('"url"%s*:%s*"([^"]*)"')
|
|
|
+ entry.path = content:match('"path"%s*:%s*"([^"]*)"') -- Subpath in monorepo
|
|
|
entry.description = content:match('"description"%s*:%s*"([^"]*)"')
|
|
|
entry.version = content:match('"version"%s*:%s*"([^"]*)"')
|
|
|
result[name] = entry
|
|
|
@@ -288,6 +289,9 @@ end
|
|
|
-- Package Installation (Git-based)
|
|
|
-- ============================================================================
|
|
|
|
|
|
+-- Monorepo cache directory
|
|
|
+M.monorepo_cache = os.getenv("HOME") .. "/.lumacs/repos"
|
|
|
+
|
|
|
-- Install a package from git
|
|
|
function M.install(spec)
|
|
|
local normalized = normalize_spec(spec)
|
|
|
@@ -297,10 +301,12 @@ function M.install(spec)
|
|
|
|
|
|
local name = normalized.name
|
|
|
local url = normalized.url
|
|
|
+ local subpath = nil -- For monorepo packages
|
|
|
|
|
|
- -- Resolve URL from registry if needed
|
|
|
+ -- Resolve URL and path from registry if needed
|
|
|
if not url and M.registry[name] then
|
|
|
url = M.registry[name].url
|
|
|
+ subpath = M.registry[name].path
|
|
|
end
|
|
|
|
|
|
if not url then
|
|
|
@@ -318,21 +324,60 @@ function M.install(spec)
|
|
|
-- Ensure parent directory exists
|
|
|
os.execute("mkdir -p " .. M.config.install_path)
|
|
|
|
|
|
- -- Clone the repository
|
|
|
- local branch_opt = ""
|
|
|
- if normalized.branch then
|
|
|
- branch_opt = " -b " .. normalized.branch
|
|
|
- end
|
|
|
+ if subpath then
|
|
|
+ -- Monorepo installation: clone to cache, then copy subpath
|
|
|
+ local repo_name = url:match("([^/]+)$") or "repo"
|
|
|
+ local cache_dir = M.monorepo_cache .. "/" .. repo_name
|
|
|
+
|
|
|
+ -- Clone or update the monorepo cache
|
|
|
+ if not dir_exists(cache_dir) then
|
|
|
+ os.execute("mkdir -p " .. M.monorepo_cache)
|
|
|
+ local branch_opt = ""
|
|
|
+ if normalized.branch then
|
|
|
+ branch_opt = " -b " .. normalized.branch
|
|
|
+ end
|
|
|
+ local clone_cmd = string.format("git clone --depth 1%s %s %s 2>&1", branch_opt, url, cache_dir)
|
|
|
+ local handle = io.popen(clone_cmd)
|
|
|
+ local result = handle:read("*a")
|
|
|
+ local success = handle:close()
|
|
|
+ if not success then
|
|
|
+ return false, "Failed to clone monorepo: " .. result
|
|
|
+ end
|
|
|
+ end
|
|
|
|
|
|
- local cmd = string.format("git clone --depth 1%s %s %s 2>&1", branch_opt, url, install_dir)
|
|
|
- local handle = io.popen(cmd)
|
|
|
- local result = handle:read("*a")
|
|
|
- local success = handle:close()
|
|
|
+ -- Copy the specific package directory
|
|
|
+ local src_dir = cache_dir .. "/" .. subpath
|
|
|
+ if not dir_exists(src_dir) then
|
|
|
+ return false, "Package path not found in monorepo: " .. subpath
|
|
|
+ end
|
|
|
|
|
|
- if success then
|
|
|
- return true, "Installed " .. name
|
|
|
+ local copy_cmd = string.format("cp -r %s %s 2>&1", src_dir, install_dir)
|
|
|
+ local handle = io.popen(copy_cmd)
|
|
|
+ local result = handle:read("*a")
|
|
|
+ local success = handle:close()
|
|
|
+
|
|
|
+ if success then
|
|
|
+ return true, "Installed " .. name .. " (from monorepo)"
|
|
|
+ else
|
|
|
+ return false, "Failed to copy package: " .. result
|
|
|
+ end
|
|
|
else
|
|
|
- return false, "Failed to install " .. name .. ": " .. result
|
|
|
+ -- Standard single-repo installation
|
|
|
+ local branch_opt = ""
|
|
|
+ if normalized.branch then
|
|
|
+ branch_opt = " -b " .. normalized.branch
|
|
|
+ end
|
|
|
+
|
|
|
+ local cmd = string.format("git clone --depth 1%s %s %s 2>&1", branch_opt, url, install_dir)
|
|
|
+ local handle = io.popen(cmd)
|
|
|
+ local result = handle:read("*a")
|
|
|
+ local success = handle:close()
|
|
|
+
|
|
|
+ if success then
|
|
|
+ return true, "Installed " .. name
|
|
|
+ else
|
|
|
+ return false, "Failed to install " .. name .. ": " .. result
|
|
|
+ end
|
|
|
end
|
|
|
end
|
|
|
|
|
|
@@ -344,6 +389,38 @@ function M.update(name)
|
|
|
return false, "Package not installed: " .. name
|
|
|
end
|
|
|
|
|
|
+ -- Check if this is a monorepo package
|
|
|
+ if M.registry[name] and M.registry[name].path then
|
|
|
+ local subpath = M.registry[name].path
|
|
|
+ local url = M.registry[name].url
|
|
|
+ local repo_name = url:match("([^/]+)$") or "repo"
|
|
|
+ local cache_dir = M.monorepo_cache .. "/" .. repo_name
|
|
|
+
|
|
|
+ -- Update the monorepo cache
|
|
|
+ if dir_exists(cache_dir) then
|
|
|
+ local pull_cmd = string.format("cd %s && git pull 2>&1", cache_dir)
|
|
|
+ local handle = io.popen(pull_cmd)
|
|
|
+ handle:read("*a")
|
|
|
+ handle:close()
|
|
|
+ end
|
|
|
+
|
|
|
+ -- Re-copy the package
|
|
|
+ local src_dir = cache_dir .. "/" .. subpath
|
|
|
+ if dir_exists(src_dir) then
|
|
|
+ os.execute(string.format("rm -rf %s", install_dir))
|
|
|
+ local copy_cmd = string.format("cp -r %s %s 2>&1", src_dir, install_dir)
|
|
|
+ local handle = io.popen(copy_cmd)
|
|
|
+ local result = handle:read("*a")
|
|
|
+ local success = handle:close()
|
|
|
+ if success then
|
|
|
+ return true, "Updated " .. name .. " (from monorepo)"
|
|
|
+ else
|
|
|
+ return false, "Failed to update " .. name .. ": " .. result
|
|
|
+ end
|
|
|
+ end
|
|
|
+ end
|
|
|
+
|
|
|
+ -- Standard git pull for single-repo packages
|
|
|
local cmd = string.format("cd %s && git pull 2>&1", install_dir)
|
|
|
local handle = io.popen(cmd)
|
|
|
local result = handle:read("*a")
|