From a1718a858d002bc722d147f5eeb1a32449ab139e Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Sat, 29 Oct 2022 14:29:07 -0400 Subject: Fixed plugin_manager somewhat. --- plugins/plugin_manager/init.lua | 25 ++++++++--- plugins/plugin_manager/plugin_view.lua | 9 ++-- src/lpm.lua | 76 ++++++++++++++++++++-------------- 3 files changed, 70 insertions(+), 40 deletions(-) diff --git a/plugins/plugin_manager/init.lua b/plugins/plugin_manager/init.lua index 11a6304..5472798 100644 --- a/plugins/plugin_manager/init.lua +++ b/plugins/plugin_manager/init.lua @@ -73,6 +73,8 @@ local function run(cmd) table.insert(cmd, "--mod-version=" .. MOD_VERSION) table.insert(cmd, "--quiet") table.insert(cmd, "--userdir=" .. USERDIR) + table.insert(cmd, "--datadir=" .. DATADIR) + table.insert(cmd, "--binary=" .. EXEFILE) table.insert(cmd, "--assume-yes") if config.plugins.plugin_manager.ssl_certs then table.insert(cmd, "--ssl_certs") table.insert(cmd, config.plugins.plugin_manager.ssl_certs) end if config.plugins.plugin_manager.force then table.insert(cmd, "--force") end @@ -131,12 +133,15 @@ function PluginManager:refresh() for i, plugin in ipairs(self.plugins) do if plugin.status ~= "incompatible" then table.insert(self.valid_plugins, plugin) + if plugin.name == "plugin_manager" and plugin.status == "installed" then + plugin.status = "special" + end end end self.last_refresh = os.time() prom:resolve(plugins) run({ "repo", "list" }):done(function(repositories) - self.repositories = repositories + self.repositories = json.decode(repositories)["repositories"] end) end) return prom @@ -200,6 +205,7 @@ PluginManager.view = require "plugins.plugin_manager.plugin_view" command.add(nil, { ["plugin-manager:install"] = function() + PluginManager:get_plugins() core.command_view:enter("Enter plugin name", function(name) PluginManager:get_plugin(name):done(function(plugin) @@ -215,7 +221,7 @@ command.add(nil, { local items = {} if not PluginManager.plugins then return end for i, plugin in ipairs(PluginManager.plugins) do - if not plugin.mod_version or tostring(plugin.mod_version) == tostring(MOD_VERSION) then + if not plugin.mod_version or tostring(plugin.mod_version) == tostring(MOD_VERSION) and plugin.status == "available" then table.insert(items, plugin.name .. ":" .. plugin.version) end end @@ -224,6 +230,7 @@ command.add(nil, { ) end, ["plugin-manager:uninstall"] = function() + PluginManager:get_plugins() core.command_view:enter("Enter plugin name", function(name) PluginManager:get_plugin(name):done(function(plugin) @@ -253,19 +260,25 @@ command.add(nil, { PluginManager:add(url):done(function() core.log("Successfully added repository " .. url .. ".") end) - end, - function(text) return get_suggestions(text) end + end ) end, ["plugin-manager:remove-repository"] = function() + PluginManager:get_plugins() core.command_view:enter("Enter repository url", function(url) - PluginManager:add(url):done(function() + PluginManager:remove(url):done(function() core.log("Successfully removed repository " .. url .. ".") end) end, function(text) - return get_suggestions(text) + local items = {} + if PluginManager.repositories then + for i,v in ipairs(PluginManager.repositories) do + table.insert(items, v.remote .. ":" .. (v.commit or v.branch)) + end + end + return common.fuzzy_match(items, text) end ) end, diff --git a/plugins/plugin_manager/plugin_view.lua b/plugins/plugin_manager/plugin_view.lua index 19eb9ae..3972cf4 100644 --- a/plugins/plugin_manager/plugin_view.lua +++ b/plugins/plugin_manager/plugin_view.lua @@ -157,7 +157,10 @@ function PluginView:draw() end x = x + style.padding.x for j, v in ipairs({ get_plugin_text(plugin) }) do - local color = (plugin.status == "installed" or plugin.status == "orphan") and style.good or (plugin.status == "core" and style.warn or style.text) + local color = (plugin.status == "installed" or plugin.status == "orphan") and style.good or + (plugin.status == "core" and style.warn or + (plugin.status == "special" and style.modified or style.text) + ) if self.loading then color = mul(color, style.dim) end common.draw_text(style.font, color, v, "left", x, y, self.widths[j], lh) x = x + self.widths[j] + style.padding.x @@ -234,12 +237,12 @@ end, { ["plugin-manager:reinstall-hovered"] = function() plugin_view:reinstall(plugin_view.hovered_plugin) end }) command.add(function() - return core.active_view and core.active_view:is(PluginView) and plugin_view.hovered_plugin and (plugin_view.hovered_plugin.status == "installed" or plugin_view.hovered_plugin.status == "core" or plugin_view.hovered_plugin.status == "orphan") + return core.active_view and core.active_view:is(PluginView) and plugin_view.hovered_plugin end, { ["plugin-manager:view-source-hovered"] = function() local directory = plugin_view.hovered_plugin.type == "library" and "libraries" or "plugins" local opened = false - for i, path in ipairs({ USERDIR .. PATHSEP .. directory .. PATHSEP .. plugin_view.hovered_plugin.name .. ".lua", USERDIR .. PATHSEP .. directory .. PATHSEP .. plugin_view.hovered_plugin.name .. PATHSEP .. "init.lua" }) do + for i, path in ipairs({ plugin_view.hovered_plugin.path, plugin_view.hovered_plugin.path .. PATHSEP .. "init.lua" }) do local stat = system.get_file_info(path) if stat and stat.type == "file" then core.root_view:open_doc(core.open_doc(path)) diff --git a/src/lpm.lua b/src/lpm.lua index cc8e131..e7ac06a 100644 --- a/src/lpm.lua +++ b/src/lpm.lua @@ -384,6 +384,7 @@ end function common.dirname(path) local s = path:reverse():find("[/\\]") if not s then return path end return path:sub(1, #path - s) end function common.basename(path) local s = path:reverse():find("[/\\]") if not s then return path end return path:sub(#path - s + 2) end function common.path(exec) return common.first(common.map({ common.split(":", os.getenv("PATH")) }, function(e) return e .. PATHSEP .. exec end), function(e) return system.stat(e) end) end +function common.normalize_path(path) if not path or not path:find("^~") then return path end return os.getenv("HOME") .. path:sub(2) end function common.rmrf(root) local info = root and root ~= "" and system.stat(root) if not info then return end @@ -433,7 +434,7 @@ function common.reset(path, ref, type) end end -local HOME, USERDIR, CACHEDIR, JSON, VERBOSE, MOD_VERSION, QUIET, FORCE, AUTO_PULL_REMOTES, ARCH, ASSUME_YES, NO_INSTALL_OPTIONAL, TMPDIR, repositories, lite_xls, system_bottle +local HOME, USERDIR, CACHEDIR, JSON, VERBOSE, MOD_VERSION, QUIET, FORCE, AUTO_PULL_REMOTES, ARCH, ASSUME_YES, NO_INSTALL_OPTIONAL, TMPDIR, DATADIR, BINARY, repositories, lite_xls, system_bottle local Plugin, Repository, LiteXL, Bottle = {}, {}, {}, {} @@ -516,8 +517,8 @@ function Plugin.new(repository, metadata) end function Plugin:get_install_path(bottle) - local folder = self.type == "library" and "libraries" or "plugins" - local path = (bottle.local_path and (bottle.local_path .. PATHSEP .. "user") or USERDIR) .. PATHSEP .. folder .. PATHSEP .. (self.path and common.basename(self.path):gsub("%.lua$", "") or self.name) + local folder = self.type == "library" and "libraries" or "plugins" + local path = ((self:is_core(bottle) and bottle.lite_xl.datadir_path) or (bottle.local_path and (bottle.local_path .. PATHSEP .. "user") or USERDIR)) .. PATHSEP .. folder .. PATHSEP .. (self.path and common.basename(self.path):gsub("%.lua$", "") or self.name) if self.organization == "singleton" then path = path .. ".lua" end return path end @@ -526,6 +527,10 @@ function Plugin:is_core(bottle) return self.type == "core" end function Plugin:is_installed(bottle) return self:is_core(bottle) or (bottle.lite_xl:is_compatible(self) and system.stat(self:get_install_path(bottle))) end function Plugin:is_incompatible(plugin) return self.dependencies[plugin.name] and not match_version(plugin.version, dependencies[plugin.name]) end +function Plugin:get_path(bottle) + return self:is_installed(bottle) and self:get_install_path(bottle) or self.local_path +end + function Plugin:get_compatibilities(bottle) local compatible_plugins, incompatible_plugins = {}, {} local installed_plugins = bottle:installed_plugins() @@ -850,23 +855,18 @@ end function LiteXL.__index(t, k) return LiteXL[k] end function LiteXL.new(repository, metadata) if not metadata.version then error("lite-xl entry requires a version") end - local self = setmetatable({ + local self = setmetatable(common.merge({ repository = repository, - version = metadata.version, - remote = metadata.remote, - url = metadata.url, - tags = metadata.tags or {}, - mod_version = metadata.mod_version, - path = metadata.path, - files = metadata.files or {} - }, LiteXL) + tags = {}, + files = {} + }, metadata), LiteXL) self.hash = system.hash((repository and repository:url() or "") .. "-" .. metadata.version .. common.join("", common.map(self.files, function(f) return f.checksum end))) self.local_path = self:is_local() and self.path or (CACHEDIR .. PATHSEP .. "lite_xls" .. PATHSEP .. self.version .. PATHSEP .. self.hash) + self.binary_path = self.binary_path or (self.local_path .. PATHSEP .. "lite-xl") + self.datadir_path = self.datadir_path or (self.local_path .. PATHSEP .. "data") return self end -function LiteXL:get_binary_path() return self.local_path .. PATHSEP .. "lite-xl" end -function LiteXL:get_data_directory() return self.local_path .. PATHSEP .. "data" end function LiteXL:is_system() return system_bottle and system_bottle.lite_xl == self end function LiteXL:is_local() return not self.repository and self.path end function LiteXL:is_compatible(plugin) return compare_version(self.mod_version, plugin.mod_version) == 0 end @@ -886,7 +886,7 @@ function LiteXL:install() system.chmod(self.local_path .. PATHSEP .. "lite-xl", 448) -- chmod to rwx------- common.copy(datadir, self.local_path .. PATHSEP .. "data") elseif self.path and not self.repository then -- local repository - system.symlink(self:get_binary_path(), self.path .. PATHSEP .. "lite_xl") + system.symlink(self.binary_path, self.path .. PATHSEP .. "lite_xl") else if self.remote then system.init(self.local_path, self.remote) @@ -971,17 +971,19 @@ function Bottle:all_plugins() local t, hash = get_repository_plugins() local plugin_paths = { (self.local_path and (self.local_path .. PATHSEP .. "user") or USERDIR) .. PATHSEP .. "plugins", - self.lite_xl:get_data_directory() .. PATHSEP .. "plugins" + self.lite_xl.datadir_path .. PATHSEP .. "plugins" } for i, plugin_path in ipairs(common.grep(plugin_paths, function(e) return system.stat(e) end)) do for k, v in ipairs(common.grep(system.ls(plugin_path), function(e) return i == 2 or not hash[e:gsub("%.lua$", "")] end)) do + local name = v:gsub("%.lua$", "") table.insert(t, Plugin.new(nil, { - name = v:gsub("%.lua$", ""), + name = name, type = i == 2 and "core", organization = (v:find("%.lua$") and "singleton" or "complex"), mod_version = self.lite_xl.mod_version, path = "plugins/" .. v, - version = "1.0" + version = "1.0", + description = (hash[name] and hash[name].description or nil) })) end end @@ -1127,7 +1129,7 @@ local function lpm_lite_xl_switch(version, target) if not lite_xl:is_installed() then log_action("Installing lite-xl " .. lite_xl.version) lite_xl:install() end local stat = system.stat(target) if stat and stat.symlink then os.remove(target) end - system.symlink(lite_xl:get_binary_path(), target) + system.symlink(lite_xl.binary_path, target) if not common.path('lite-xl') then os.remove(target) error(target .. " is not on your $PATH; please supply a target that can be found on your $PATH, called `lite-xl`.") @@ -1149,7 +1151,8 @@ local function lpm_lite_xl_list() mod_version = lite_xl.mod_version, tags = lite_xl.tags, is_system = lite_xl:is_system(), - status = lite_xl:is_installed() and (lite_xl:is_local() and "local" or "installed") or "available", + is_installed = lite_xl:is_installed(), + status = (lite_xl:is_installed() or lite_xl:is_system()) and (lite_xl:is_local() and "local" or "installed") or "available", local_path = lite_xl.local_path }) max_version = math.max(max_version, #lite_xl.version) @@ -1163,7 +1166,8 @@ local function lpm_lite_xl_list() repository = repo:url(), tags = lite_xl.tags, is_system = lite_xl:is_system(), - status = lite_xl:is_installed() and (lite_xl:is_local() and "local" or "installed") or "available", + is_installed = lite_xl:is_installed(), + status = (lite_xl:is_installed() or lite_xl:is_system()) and (lite_xl:is_local() and "local" or "installed") or "available", local_path = lite_xl.local_path }) max_version = math.max(max_version, #lite_xl.version) @@ -1185,7 +1189,7 @@ local function lpm_lite_xl_list() print(string.format("%" .. max_version .. "s | %10s | %s", "Version", "Status", "Location")) print(string.format("%" .. max_version .."s | %10s | %s", "-------", "---------", "---------------------------")) for i, lite_xl in ipairs(result["lite-xl"]) do - print(string.format("%" .. max_version .. "s | %10s | %s", (lite_xl.is_system and "* " or "") .. lite_xl.version, lite_xl.status, (lite_xl.status ~= "available" and lite_xl.local_path or lite_xl.repository))) + print(string.format("%" .. max_version .. "s | %10s | %s", (lite_xl.is_system and "* " or "") .. lite_xl.version, lite_xl.status, (lite_xl.is_installed and lite_xl.local_path or lite_xl.repository))) end end end @@ -1265,7 +1269,8 @@ local function lpm_plugin_list(name) tags = plugin.tags, type = plugin.type, organization = plugin.organization, - repository = repo and repo:url() + repository = repo and repo:url(), + path = plugin:get_path(system_bottle) }) end if JSON then @@ -1288,6 +1293,7 @@ local function lpm_plugin_list(name) print("Mod-Version: " .. (plugin.mod_version or "unknown")) print("Dependencies: " .. json.encode(plugin.dependencies)) print("Tags: " .. common.join(", ", plugin.tags)) + print("Path: " .. plugin.path) elseif plugin.status ~= "incompatible" then print(string.format("%" .. max_name .."s | %10s | %10s | %s", plugin.name, plugin.version, plugin.mod_version, plugin.status)) end @@ -1412,7 +1418,7 @@ xpcall(function() json = "flag", userdir = "string", cachedir = "string", version = "flag", verbose = "flag", quiet = "flag", version = "string", ["mod-version"] = "string", remotes = "flag", help = "flag", remotes = "flag", ssl_certs = "string", force = "flag", arch = "string", ["assume-yes"] = "flag", - ["install-optional"] = "flag" + ["install-optional"] = "flag", datadir = "string", binary = "string" }) if ARGS["version"] then io.stdout:write(VERSION .. "\n") @@ -1424,6 +1430,7 @@ Usage: lpm COMMAND [...ARGUMENTS] [--json] [--userdir=directory] [--cachedir=directory] [--quiet] [--version] [--help] [--remotes] [--ssl_certs=directory/file] [--force] [--arch=]] .. _G.ARCH .. [[] [--assume-yes] [--no-install-optional] [--verbose] [--mod-version=3] + [--datadir=directory] LPM is a package manager for `lite-xl`, written in C (and packed-in lua). @@ -1493,6 +1500,9 @@ Flags have the following effects: If omitted, uses the normal lite-xl logic. --cachedir=directory Sets the directory to store all repositories. --tmpdir=directory During install, sets the staging area. + --datadir=directory Sets the data directory where core plugins are located + for the system lite-xl. + --binary=path Sets the lite-xl binary path for the system lite-xl. --verbose Spits out more information, including intermediate steps to install and whatnot. --quiet Outputs nothing but explicit responses. @@ -1519,18 +1529,20 @@ Flags have the following effects: JSON = ARGS["json"] or os.getenv("LPM_JSON") QUIET = ARGS["quiet"] or os.getenv("LPM_QUIET") FORCE = ARGS["force"] + DATADIR = common.normalize_path(ARGS["datadir"]) + BINARY = common.normalize_path(ARGS["binary"]) NO_INSTALL_OPTIONAL = ARGS["no-install-optional"] ARCH = ARGS["arch"] or _G.ARCH ASSUME_YES = ARGS["assume-yes"] or FORCE MOD_VERSION = ARGS["mod-version"] or os.getenv("LPM_MODVERSION") if MOD_VERSION == "any" then MOD_VERSION = nil end HOME = (os.getenv("USERPROFILE") or os.getenv("HOME")):gsub(PATHSEP .. "$", "") - USERDIR = ARGS["userdir"] or os.getenv("LITE_USERDIR") or (os.getenv("XDG_CONFIG_HOME") and os.getenv("XDG_CONFIG_HOME") .. PATHSEP .. "lite-xl") + USERDIR = common.normalize_path(ARGS["userdir"]) or os.getenv("LITE_USERDIR") or (os.getenv("XDG_CONFIG_HOME") and os.getenv("XDG_CONFIG_HOME") .. PATHSEP .. "lite-xl") or (HOME and (HOME .. PATHSEP .. '.config' .. PATHSEP .. 'lite-xl')) AUTO_PULL_REMOTES = ARGS["remotes"] if not system.stat(USERDIR) then error("can't find user directory " .. USERDIR) end - CACHEDIR = ARGS["cachedir"] or os.getenv("LPM_CACHE") or USERDIR .. PATHSEP .. "lpm" - TMPDIR = ARGS["tmpdir"] or CACHEDIR .. "/tmp" + CACHEDIR = common.normalize_path(ARGS["cachedir"]) or os.getenv("LPM_CACHE") or USERDIR .. PATHSEP .. "lpm" + TMPDIR = common.normalize_path(ARGS["tmpdir"]) or CACHEDIR .. "/tmp" repositories = {} if ARGS[2] == "purge" then return lpm_purge() end @@ -1577,16 +1589,18 @@ Flags have the following effects: table.insert(lite_xls, LiteXL.new(nil, { version = lite_xl.version, mod_version = lite_xl.mod_version, path = lite_xl.path, tags = { "local" } })) end end - local lite_xl_binary = common.path("lite-xl") + local lite_xl_binary = BINARY or common.path("lite-xl") if lite_xl_binary then - lite_xl_binary = system.stat(lite_xl_binary).symlink or lite_xl_binary + local stat = system.stat(lite_xl_binary) + if not stat then error("can't find lite-xl binary " .. lite_xl_binary) end + lite_xl_binary = stat.symlink or lite_xl_binary local directory = common.dirname(lite_xl_binary) local hash = system.hash(lite_xl_binary, "file") local system_lite_xl = common.first(common.concat(common.flat_map(repositories, function(r) return r.lite_xls end), lite_xls), function(lite_xl) return lite_xl.local_path == directory end) if not system_lite_xl then system_lite_xl = common.first(lite_xls, function(e) return e.version == "system" end) - if system_lite_xl then error("can't find existing system lite (does " .. system_lite_xl.local_path .. " exist? was it moved?); run `lpm purge`, or resolve otherwise") end - system_lite_xl = LiteXL.new(nil, { path = directory, mod_version = MOD_VERSION or 3, version = "system", tags = { "system", "local" } }) + if system_lite_xl then error("can't find existing system lite (does " .. system_lite_xl.binary_path .. " exist? was it moved?); run `lpm purge`, or specify --binary and --datadir.") end + system_lite_xl = LiteXL.new(nil, { datadir_path = DATADIR, binary_path = BINARY, mod_version = MOD_VERSION or 3, version = "system", tags = { "system", "local" } }) table.insert(lite_xls, system_lite_xl) lpm_lite_xl_save() else -- cgit v1.2.3