From 410e3e057d41e08f497c770ce0576072e6b83fe7 Mon Sep 17 00:00:00 2001 From: Thijs Schreijer Date: Wed, 4 Jul 2018 23:15:07 +0200 Subject: cmd: dynamically load additional external commands Instead of a fixed list of commands, a dynamic list of modules residing within the `luarocks.cmd.external.` in the Lua path will be dynamically added. This allows extending LuaRocks with additional commands. Same for `luarocks.admin.cmd.external.`. --- src/bin/luarocks | 5 +---- src/bin/luarocks-admin | 2 +- src/luarocks/cmd.lua | 14 +++++++++----- src/luarocks/fs/lua.lua | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/bin/luarocks b/src/bin/luarocks index d0df0532..18a6179b 100755 --- a/src/bin/luarocks +++ b/src/bin/luarocks @@ -1,8 +1,5 @@ #!/usr/bin/env lua --- this should be loaded first. -local cfg = require("luarocks.core.cfg") - local loader = require("luarocks.loader") local cmd = require("luarocks.cmd") @@ -33,4 +30,4 @@ local commands = { test = "luarocks.cmd.test", } -cmd.run_command(description, commands, ...) +cmd.run_command(description, commands, "luarocks.cmd.external", ...) diff --git a/src/bin/luarocks-admin b/src/bin/luarocks-admin index e27b8c01..77a51872 100755 --- a/src/bin/luarocks-admin +++ b/src/bin/luarocks-admin @@ -13,4 +13,4 @@ local commands = { refresh_cache = "luarocks.admin.cmd.refresh_cache", } -cmd.run_command(description, commands, ...) +cmd.run_command(description, commands, "luarocks.admin.cmd.external", ...) diff --git a/src/luarocks/cmd.lua b/src/luarocks/cmd.lua index 4200959c..7a7f9654 100644 --- a/src/luarocks/cmd.lua +++ b/src/luarocks/cmd.lua @@ -254,12 +254,11 @@ end -- Parses input arguments and calls the appropriate driver function -- to execute the action requested on the command-line, forwarding -- to it any additional arguments passed by the user. --- Uses the global table "commands", which contains --- the loaded modules representing commands. --- @param program_version string: The program version number as a string. -- @param description string: Short summary description of the program. +-- @param commands table: contains the loaded modules representing commands. +-- @param external_namespace string: where to look for external commands. -- @param ... string: Arguments given on the command-line. -function cmd.run_command(description, commands, ...) +function cmd.run_command(description, commands, external_namespace, ...) check_popen() @@ -377,6 +376,12 @@ function cmd.run_command(description, commands, ...) os.exit(cmd.errorcodes.OK) end + for _, module_name in ipairs(fs.modules(external_namespace)) do + if not commands[module_name] then + commands[module_name] = external_namespace.."."..module_name + end + end + if flags["verbose"] then cfg.verbose = true fs.verbose() @@ -386,7 +391,6 @@ function cmd.run_command(description, commands, ...) die("Current directory does not exist. Please run LuaRocks from an existing directory.") end - local ok, err ok, err = process_tree_flags(flags) if not ok then die(err) diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 200a1b0c..373dcbdd 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua @@ -166,6 +166,52 @@ function fs_lua.dir(at) return coroutine.wrap(function() fs.dir_iterator(at) end) end +--- List the Lua modules at a specific require path. +-- eg. `modules("luarocks.cmd")` would return a list of all LuaRocks command +-- modules, in the current Lua path. +function fs_lua.modules(at) + at = at or "" + if #at > 0 then + -- turn require path into file path + at = at:gsub("%.", package.config:sub(1,1)) .. package.config:sub(1,1) + end + + local path = package.path:sub(-1, -1) == ";" and package.path or package.path .. ";" + local paths = {} + for location in path:gmatch("(.-);") do + if location:lower() == "?.lua" then + location = "./?.lua" + end + local _, q_count = location:gsub("%?", "") -- only use the ones with a single '?' + if location:match("%?%.[lL][uU][aA]$") and q_count == 1 then -- only use when ending with "?.lua" + location = location:gsub("%?%.[lL][uU][aA]$", at) + table.insert(paths, location) + end + end + + if #paths == 0 then + return {} + end + + local modules = {} + local is_duplicate = {} + for _, path in ipairs(paths) do + local files = fs.list_dir(path) + for _, filename in ipairs(files or {}) do + if filename:match("%.[lL][uU][aA]$") then + filename = filename:sub(1,-5) -- drop the extension + if not is_duplicate[filename] then + is_duplicate[filename] = true + table.insert(modules, filename) + end + end + end + end + + return modules +end + + --------------------------------------------------------------------- -- LuaFileSystem functions --------------------------------------------------------------------- -- cgit v1.2.3-55-g6feb