diff options
| author | daurnimator <quae@daurnimator.com> | 2019-08-24 12:15:34 +1000 |
|---|---|---|
| committer | daurnimator <quae@daurnimator.com> | 2019-08-24 12:15:34 +1000 |
| commit | cffcc251be58914c49a1acbdaf5c38e42f93976c (patch) | |
| tree | dffd799f90d06016e1b43cbd6f96c385e1ef0a64 /src | |
| parent | 8a957d68133a8af6650c4f8349646fa9420258f3 (diff) | |
| parent | 8e602d751e79c97eb664682b5b2441495d9ad974 (diff) | |
| download | luarocks-cffcc251be58914c49a1acbdaf5c38e42f93976c.tar.gz luarocks-cffcc251be58914c49a1acbdaf5c38e42f93976c.tar.bz2 luarocks-cffcc251be58914c49a1acbdaf5c38e42f93976c.zip | |
Merge PR #1035
Diffstat (limited to 'src')
35 files changed, 3089 insertions, 1225 deletions
diff --git a/src/bin/luarocks b/src/bin/luarocks index d982530c..56caaa60 100755 --- a/src/bin/luarocks +++ b/src/bin/luarocks | |||
| @@ -9,7 +9,6 @@ local cmd = require("luarocks.cmd") | |||
| 9 | local description = "LuaRocks main command-line interface" | 9 | local description = "LuaRocks main command-line interface" |
| 10 | 10 | ||
| 11 | local commands = { | 11 | local commands = { |
| 12 | help = "luarocks.cmd.help", | ||
| 13 | init = "luarocks.cmd.init", | 12 | init = "luarocks.cmd.init", |
| 14 | pack = "luarocks.cmd.pack", | 13 | pack = "luarocks.cmd.pack", |
| 15 | unpack = "luarocks.cmd.unpack", | 14 | unpack = "luarocks.cmd.unpack", |
diff --git a/src/bin/luarocks-admin b/src/bin/luarocks-admin index 71e17b55..4a85e45b 100755 --- a/src/bin/luarocks-admin +++ b/src/bin/luarocks-admin | |||
| @@ -9,7 +9,6 @@ local cmd = require("luarocks.cmd") | |||
| 9 | local description = "LuaRocks repository administration interface" | 9 | local description = "LuaRocks repository administration interface" |
| 10 | 10 | ||
| 11 | local commands = { | 11 | local commands = { |
| 12 | help = "luarocks.cmd.help", | ||
| 13 | make_manifest = "luarocks.admin.cmd.make_manifest", | 12 | make_manifest = "luarocks.admin.cmd.make_manifest", |
| 14 | add = "luarocks.admin.cmd.add", | 13 | add = "luarocks.admin.cmd.add", |
| 15 | remove = "luarocks.admin.cmd.remove", | 14 | remove = "luarocks.admin.cmd.remove", |
diff --git a/src/luarocks/admin/cmd/add.lua b/src/luarocks/admin/cmd/add.lua index 19990b3c..5011c680 100644 --- a/src/luarocks/admin/cmd/add.lua +++ b/src/luarocks/admin/cmd/add.lua | |||
| @@ -11,20 +11,20 @@ local fs = require("luarocks.fs") | |||
| 11 | local cache = require("luarocks.admin.cache") | 11 | local cache = require("luarocks.admin.cache") |
| 12 | local index = require("luarocks.admin.index") | 12 | local index = require("luarocks.admin.index") |
| 13 | 13 | ||
| 14 | add.help_summary = "Add a rock or rockspec to a rocks server." | 14 | function add.add_to_parser(parser) |
| 15 | add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" | 15 | local cmd = parser:command("add", "Add a rock or rockspec to a rocks server.", util.see_also()) |
| 16 | add.help = [[ | 16 | |
| 17 | Arguments are local files, which may be rockspecs or rocks. | 17 | cmd:argument("rock", "A local rockspec or rock file.") |
| 18 | The flag --server indicates which server to use. | 18 | :args("+") |
| 19 | If not given, the default server set in the upload_server variable | 19 | |
| 20 | from the configuration file is used instead. | 20 | cmd:option("--server", "The server to use. If not given, the default server ".. |
| 21 | 21 | "set in the upload_server variable from the configuration file is used instead.") | |
| 22 | --no-refresh The local cache should not be refreshed | 22 | :target("add_server") |
| 23 | prior to generation of the updated manifest. | 23 | cmd:flag("--no-refresh", "Do not refresh the local cache prior to ".. |
| 24 | --index Produce an index.html file for the manifest. | 24 | "generation of the updated manifest.") |
| 25 | This flag is automatically set if an index.html | 25 | cmd:flag("--index", "Produce an index.html file for the manifest. This ".. |
| 26 | file already exists. | 26 | "flag is automatically set if an index.html file already exists.") |
| 27 | ]] | 27 | end |
| 28 | 28 | ||
| 29 | local function zip_manifests() | 29 | local function zip_manifests() |
| 30 | for ver in util.lua_versions() do | 30 | for ver in util.lua_versions() do |
| @@ -124,14 +124,10 @@ local function add_files_to_server(refresh, rockfiles, server, upload_server, do | |||
| 124 | return fs.execute(cmd) | 124 | return fs.execute(cmd) |
| 125 | end | 125 | end |
| 126 | 126 | ||
| 127 | function add.command(flags, ...) | 127 | function add.command(args) |
| 128 | local files = {...} | 128 | local server, server_table = cache.get_upload_server(args.add_server or args.server) |
| 129 | if #files < 1 then | ||
| 130 | return nil, "Argument missing. "..util.see_help("add", "luarocks-admin") | ||
| 131 | end | ||
| 132 | local server, server_table = cache.get_upload_server(flags["server"]) | ||
| 133 | if not server then return nil, server_table end | 129 | if not server then return nil, server_table end |
| 134 | return add_files_to_server(not flags["no-refresh"], files, server, server_table, flags["index"]) | 130 | return add_files_to_server(not args.no_refresh, args.rock, server, server_table, args.index) |
| 135 | end | 131 | end |
| 136 | 132 | ||
| 137 | 133 | ||
diff --git a/src/luarocks/admin/cmd/make_manifest.lua b/src/luarocks/admin/cmd/make_manifest.lua index f0b64135..ab940f9e 100644 --- a/src/luarocks/admin/cmd/make_manifest.lua +++ b/src/luarocks/admin/cmd/make_manifest.lua | |||
| @@ -11,36 +11,36 @@ local deps = require("luarocks.deps") | |||
| 11 | local fs = require("luarocks.fs") | 11 | local fs = require("luarocks.fs") |
| 12 | local dir = require("luarocks.dir") | 12 | local dir = require("luarocks.dir") |
| 13 | 13 | ||
| 14 | make_manifest.help_summary = "Compile a manifest file for a repository." | 14 | function make_manifest.add_to_parser(parser) |
| 15 | local cmd = parser:command("make_manifest", "Compile a manifest file for a repository.", util.see_also()) | ||
| 16 | parser:command("make-manifest"):hidden(true):action(function(args) args.command = "make_manifest" end) | ||
| 15 | 17 | ||
| 16 | make_manifest.help = [[ | 18 | cmd:argument("repository", "Local repository pathname.") |
| 17 | <argument>, if given, is a local repository pathname. | 19 | :args("?") |
| 18 | 20 | ||
| 19 | --local-tree If given, do not write versioned versions of the manifest file. | 21 | cmd:flag("--local-tree", "If given, do not write versioned versions of the manifest file.\n".. |
| 20 | Use this when rebuilding the manifest of a local rocks tree. | 22 | "Use this when rebuilding the manifest of a local rocks tree.") |
| 21 | ]] | 23 | util.deps_mode_option(cmd) |
| 24 | end | ||
| 22 | 25 | ||
| 23 | --- Driver function for "make_manifest" command. | 26 | --- Driver function for "make_manifest" command. |
| 24 | -- @param repo string or nil: Pathname of a local repository. If not given, | ||
| 25 | -- the default local repository configured as cfg.rocks_dir is used. | ||
| 26 | -- @return boolean or (nil, string): True if manifest was generated, | 27 | -- @return boolean or (nil, string): True if manifest was generated, |
| 27 | -- or nil and an error message. | 28 | -- or nil and an error message. |
| 28 | function make_manifest.command(flags, repo) | 29 | function make_manifest.command(args) |
| 29 | assert(type(repo) == "string" or not repo) | 30 | local repo = args.repository or cfg.rocks_dir |
| 30 | repo = repo or cfg.rocks_dir | ||
| 31 | 31 | ||
| 32 | util.printout("Making manifest for "..repo) | 32 | util.printout("Making manifest for "..repo) |
| 33 | 33 | ||
| 34 | if repo:match("/lib/luarocks") and not flags["local-tree"] then | 34 | if repo:match("/lib/luarocks") and not args.local_tree then |
| 35 | util.warning("This looks like a local rocks tree, but you did not pass --local-tree.") | 35 | util.warning("This looks like a local rocks tree, but you did not pass --local-tree.") |
| 36 | end | 36 | end |
| 37 | 37 | ||
| 38 | local ok, err = writer.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"]) | 38 | local ok, err = writer.make_manifest(repo, deps.get_deps_mode(args), not args.local_tree) |
| 39 | if ok and not flags["local-tree"] then | 39 | if ok and not args.local_tree then |
| 40 | util.printout("Generating index.html for "..repo) | 40 | util.printout("Generating index.html for "..repo) |
| 41 | index.make_index(repo) | 41 | index.make_index(repo) |
| 42 | end | 42 | end |
| 43 | if flags["local-tree"] then | 43 | if args.local_tree then |
| 44 | for luaver in util.lua_versions() do | 44 | for luaver in util.lua_versions() do |
| 45 | fs.delete(dir.path(repo, "manifest-"..luaver)) | 45 | fs.delete(dir.path(repo, "manifest-"..luaver)) |
| 46 | end | 46 | end |
diff --git a/src/luarocks/admin/cmd/refresh_cache.lua b/src/luarocks/admin/cmd/refresh_cache.lua index 3ffe56d9..40c9ff09 100644 --- a/src/luarocks/admin/cmd/refresh_cache.lua +++ b/src/luarocks/admin/cmd/refresh_cache.lua | |||
| @@ -3,18 +3,20 @@ | |||
| 3 | local refresh_cache = {} | 3 | local refresh_cache = {} |
| 4 | 4 | ||
| 5 | local cfg = require("luarocks.core.cfg") | 5 | local cfg = require("luarocks.core.cfg") |
| 6 | local util = require("luarocks.util") | ||
| 6 | local cache = require("luarocks.admin.cache") | 7 | local cache = require("luarocks.admin.cache") |
| 7 | 8 | ||
| 8 | refresh_cache.help_summary = "Refresh local cache of a remote rocks server." | 9 | function refresh_cache.add_to_parser(parser) |
| 9 | refresh_cache.help_arguments = "[--from=<server>]" | 10 | local cmd = parser:command("refresh_cache", "Refresh local cache of a remote rocks server.", util.see_also()) |
| 10 | refresh_cache.help = [[ | 11 | parser:command("refresh-cache"):hidden(true):action(function(args) args.command = "refresh_cache" end) |
| 11 | The flag --from indicates which server to use. | ||
| 12 | If not given, the default server set in the upload_server variable | ||
| 13 | from the configuration file is used instead. | ||
| 14 | ]] | ||
| 15 | 12 | ||
| 16 | function refresh_cache.command(flags) | 13 | cmd:option("--from", "The server to use. If not given, the default server ".. |
| 17 | local server, upload_server = cache.get_upload_server(flags["server"]) | 14 | "set in the upload_server variable from the configuration file is used instead.") |
| 15 | :argname("<server>") | ||
| 16 | end | ||
| 17 | |||
| 18 | function refresh_cache.command(args) | ||
| 19 | local server, upload_server = cache.get_upload_server(args.server) | ||
| 18 | if not server then return nil, upload_server end | 20 | if not server then return nil, upload_server end |
| 19 | local download_url = cache.get_server_urls(server, upload_server) | 21 | local download_url = cache.get_server_urls(server, upload_server) |
| 20 | 22 | ||
diff --git a/src/luarocks/admin/cmd/remove.lua b/src/luarocks/admin/cmd/remove.lua index f005c83c..de58f7a3 100644 --- a/src/luarocks/admin/cmd/remove.lua +++ b/src/luarocks/admin/cmd/remove.lua | |||
| @@ -11,16 +11,17 @@ local fs = require("luarocks.fs") | |||
| 11 | local cache = require("luarocks.admin.cache") | 11 | local cache = require("luarocks.admin.cache") |
| 12 | local index = require("luarocks.admin.index") | 12 | local index = require("luarocks.admin.index") |
| 13 | 13 | ||
| 14 | admin_remove.help_summary = "Remove a rock or rockspec from a rocks server." | 14 | function admin_remove.add_to_parser(parser) |
| 15 | admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" | 15 | local cmd = parser:command("remove", "Remove a rock or rockspec from a rocks server.", util.see_also()) |
| 16 | admin_remove.help = [[ | 16 | |
| 17 | Arguments are local files, which may be rockspecs or rocks. | 17 | cmd:argument("rock", "A local rockspec or rock file.") |
| 18 | The flag --server indicates which server to use. | 18 | :args("+") |
| 19 | If not given, the default server set in the upload_server variable | 19 | |
| 20 | from the configuration file is used instead. | 20 | cmd:option("--server", "The server to use. If not given, the default server ".. |
| 21 | The flag --no-refresh indicates the local cache should not be refreshed | 21 | "set in the upload_server variable from the configuration file is used instead.") |
| 22 | prior to generation of the updated manifest. | 22 | cmd:flag("--no-refresh", "Do not refresh the local cache prior to ".. |
| 23 | ]] | 23 | "generation of the updated manifest.") |
| 24 | end | ||
| 24 | 25 | ||
| 25 | local function remove_files_from_server(refresh, rockfiles, server, upload_server) | 26 | local function remove_files_from_server(refresh, rockfiles, server, upload_server) |
| 26 | assert(type(refresh) == "boolean" or not refresh) | 27 | assert(type(refresh) == "boolean" or not refresh) |
| @@ -76,14 +77,10 @@ local function remove_files_from_server(refresh, rockfiles, server, upload_serve | |||
| 76 | return true | 77 | return true |
| 77 | end | 78 | end |
| 78 | 79 | ||
| 79 | function admin_remove.command(flags, ...) | 80 | function admin_remove.command(args) |
| 80 | local files = {...} | 81 | local server, server_table = cache.get_upload_server(args.server) |
| 81 | if #files < 1 then | ||
| 82 | return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin") | ||
| 83 | end | ||
| 84 | local server, server_table = cache.get_upload_server(flags["server"]) | ||
| 85 | if not server then return nil, server_table end | 82 | if not server then return nil, server_table end |
| 86 | return remove_files_from_server(not flags["no-refresh"], files, server, server_table) | 83 | return remove_files_from_server(not args.no_refresh, args.rock, server, server_table) |
| 87 | end | 84 | end |
| 88 | 85 | ||
| 89 | 86 | ||
diff --git a/src/luarocks/argparse.lua b/src/luarocks/argparse.lua new file mode 100644 index 00000000..dc6cdb0d --- /dev/null +++ b/src/luarocks/argparse.lua | |||
| @@ -0,0 +1,2078 @@ | |||
| 1 | -- The MIT License (MIT) | ||
| 2 | |||
| 3 | -- Copyright (c) 2013 - 2018 Peter Melnichenko | ||
| 4 | -- 2019 Paul Ouellette | ||
| 5 | |||
| 6 | -- Permission is hereby granted, free of charge, to any person obtaining a copy of | ||
| 7 | -- this software and associated documentation files (the "Software"), to deal in | ||
| 8 | -- the Software without restriction, including without limitation the rights to | ||
| 9 | -- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of | ||
| 10 | -- the Software, and to permit persons to whom the Software is furnished to do so, | ||
| 11 | -- subject to the following conditions: | ||
| 12 | |||
| 13 | -- The above copyright notice and this permission notice shall be included in all | ||
| 14 | -- copies or substantial portions of the Software. | ||
| 15 | |||
| 16 | -- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| 17 | -- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS | ||
| 18 | -- FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
| 19 | -- COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | ||
| 20 | -- IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
| 21 | -- CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
| 22 | |||
| 23 | local function deep_update(t1, t2) | ||
| 24 | for k, v in pairs(t2) do | ||
| 25 | if type(v) == "table" then | ||
| 26 | v = deep_update({}, v) | ||
| 27 | end | ||
| 28 | |||
| 29 | t1[k] = v | ||
| 30 | end | ||
| 31 | |||
| 32 | return t1 | ||
| 33 | end | ||
| 34 | |||
| 35 | -- A property is a tuple {name, callback}. | ||
| 36 | -- properties.args is number of properties that can be set as arguments | ||
| 37 | -- when calling an object. | ||
| 38 | local function class(prototype, properties, parent) | ||
| 39 | -- Class is the metatable of its instances. | ||
| 40 | local cl = {} | ||
| 41 | cl.__index = cl | ||
| 42 | |||
| 43 | if parent then | ||
| 44 | cl.__prototype = deep_update(deep_update({}, parent.__prototype), prototype) | ||
| 45 | else | ||
| 46 | cl.__prototype = prototype | ||
| 47 | end | ||
| 48 | |||
| 49 | if properties then | ||
| 50 | local names = {} | ||
| 51 | |||
| 52 | -- Create setter methods and fill set of property names. | ||
| 53 | for _, property in ipairs(properties) do | ||
| 54 | local name, callback = property[1], property[2] | ||
| 55 | |||
| 56 | cl[name] = function(self, value) | ||
| 57 | if not callback(self, value) then | ||
| 58 | self["_" .. name] = value | ||
| 59 | end | ||
| 60 | |||
| 61 | return self | ||
| 62 | end | ||
| 63 | |||
| 64 | names[name] = true | ||
| 65 | end | ||
| 66 | |||
| 67 | function cl.__call(self, ...) | ||
| 68 | -- When calling an object, if the first argument is a table, | ||
| 69 | -- interpret keys as property names, else delegate arguments | ||
| 70 | -- to corresponding setters in order. | ||
| 71 | if type((...)) == "table" then | ||
| 72 | for name, value in pairs((...)) do | ||
| 73 | if names[name] then | ||
| 74 | self[name](self, value) | ||
| 75 | end | ||
| 76 | end | ||
| 77 | else | ||
| 78 | local nargs = select("#", ...) | ||
| 79 | |||
| 80 | for i, property in ipairs(properties) do | ||
| 81 | if i > nargs or i > properties.args then | ||
| 82 | break | ||
| 83 | end | ||
| 84 | |||
| 85 | local arg = select(i, ...) | ||
| 86 | |||
| 87 | if arg ~= nil then | ||
| 88 | self[property[1]](self, arg) | ||
| 89 | end | ||
| 90 | end | ||
| 91 | end | ||
| 92 | |||
| 93 | return self | ||
| 94 | end | ||
| 95 | end | ||
| 96 | |||
| 97 | -- If indexing class fails, fallback to its parent. | ||
| 98 | local class_metatable = {} | ||
| 99 | class_metatable.__index = parent | ||
| 100 | |||
| 101 | function class_metatable.__call(self, ...) | ||
| 102 | -- Calling a class returns its instance. | ||
| 103 | -- Arguments are delegated to the instance. | ||
| 104 | local object = deep_update({}, self.__prototype) | ||
| 105 | setmetatable(object, self) | ||
| 106 | return object(...) | ||
| 107 | end | ||
| 108 | |||
| 109 | return setmetatable(cl, class_metatable) | ||
| 110 | end | ||
| 111 | |||
| 112 | local function typecheck(name, types, value) | ||
| 113 | for _, type_ in ipairs(types) do | ||
| 114 | if type(value) == type_ then | ||
| 115 | return true | ||
| 116 | end | ||
| 117 | end | ||
| 118 | |||
| 119 | error(("bad property '%s' (%s expected, got %s)"):format(name, table.concat(types, " or "), type(value))) | ||
| 120 | end | ||
| 121 | |||
| 122 | local function typechecked(name, ...) | ||
| 123 | local types = {...} | ||
| 124 | return {name, function(_, value) typecheck(name, types, value) end} | ||
| 125 | end | ||
| 126 | |||
| 127 | local multiname = {"name", function(self, value) | ||
| 128 | typecheck("name", {"string"}, value) | ||
| 129 | |||
| 130 | for alias in value:gmatch("%S+") do | ||
| 131 | self._name = self._name or alias | ||
| 132 | table.insert(self._aliases, alias) | ||
| 133 | end | ||
| 134 | |||
| 135 | -- Do not set _name as with other properties. | ||
| 136 | return true | ||
| 137 | end} | ||
| 138 | |||
| 139 | local function parse_boundaries(str) | ||
| 140 | if tonumber(str) then | ||
| 141 | return tonumber(str), tonumber(str) | ||
| 142 | end | ||
| 143 | |||
| 144 | if str == "*" then | ||
| 145 | return 0, math.huge | ||
| 146 | end | ||
| 147 | |||
| 148 | if str == "+" then | ||
| 149 | return 1, math.huge | ||
| 150 | end | ||
| 151 | |||
| 152 | if str == "?" then | ||
| 153 | return 0, 1 | ||
| 154 | end | ||
| 155 | |||
| 156 | if str:match "^%d+%-%d+$" then | ||
| 157 | local min, max = str:match "^(%d+)%-(%d+)$" | ||
| 158 | return tonumber(min), tonumber(max) | ||
| 159 | end | ||
| 160 | |||
| 161 | if str:match "^%d+%+$" then | ||
| 162 | local min = str:match "^(%d+)%+$" | ||
| 163 | return tonumber(min), math.huge | ||
| 164 | end | ||
| 165 | end | ||
| 166 | |||
| 167 | local function boundaries(name) | ||
| 168 | return {name, function(self, value) | ||
| 169 | typecheck(name, {"number", "string"}, value) | ||
| 170 | |||
| 171 | local min, max = parse_boundaries(value) | ||
| 172 | |||
| 173 | if not min then | ||
| 174 | error(("bad property '%s'"):format(name)) | ||
| 175 | end | ||
| 176 | |||
| 177 | self["_min" .. name], self["_max" .. name] = min, max | ||
| 178 | end} | ||
| 179 | end | ||
| 180 | |||
| 181 | local actions = {} | ||
| 182 | |||
| 183 | local option_action = {"action", function(_, value) | ||
| 184 | typecheck("action", {"function", "string"}, value) | ||
| 185 | |||
| 186 | if type(value) == "string" and not actions[value] then | ||
| 187 | error(("unknown action '%s'"):format(value)) | ||
| 188 | end | ||
| 189 | end} | ||
| 190 | |||
| 191 | local option_init = {"init", function(self) | ||
| 192 | self._has_init = true | ||
| 193 | end} | ||
| 194 | |||
| 195 | local option_default = {"default", function(self, value) | ||
| 196 | if type(value) ~= "string" then | ||
| 197 | self._init = value | ||
| 198 | self._has_init = true | ||
| 199 | return true | ||
| 200 | end | ||
| 201 | end} | ||
| 202 | |||
| 203 | local add_help = {"add_help", function(self, value) | ||
| 204 | typecheck("add_help", {"boolean", "string", "table"}, value) | ||
| 205 | |||
| 206 | if self._help_option_idx then | ||
| 207 | table.remove(self._options, self._help_option_idx) | ||
| 208 | self._help_option_idx = nil | ||
| 209 | end | ||
| 210 | |||
| 211 | if value then | ||
| 212 | local help = self:flag() | ||
| 213 | :description "Show this help message and exit." | ||
| 214 | :action(function() | ||
| 215 | print(self:get_help()) | ||
| 216 | os.exit(0) | ||
| 217 | end) | ||
| 218 | |||
| 219 | if value ~= true then | ||
| 220 | help = help(value) | ||
| 221 | end | ||
| 222 | |||
| 223 | if not help._name then | ||
| 224 | help "-h" "--help" | ||
| 225 | end | ||
| 226 | |||
| 227 | self._help_option_idx = #self._options | ||
| 228 | end | ||
| 229 | end} | ||
| 230 | |||
| 231 | local Parser = class({ | ||
| 232 | _arguments = {}, | ||
| 233 | _options = {}, | ||
| 234 | _commands = {}, | ||
| 235 | _mutexes = {}, | ||
| 236 | _groups = {}, | ||
| 237 | _require_command = true, | ||
| 238 | _handle_options = true | ||
| 239 | }, { | ||
| 240 | args = 3, | ||
| 241 | typechecked("name", "string"), | ||
| 242 | typechecked("description", "string"), | ||
| 243 | typechecked("epilog", "string"), | ||
| 244 | typechecked("usage", "string"), | ||
| 245 | typechecked("help", "string"), | ||
| 246 | typechecked("require_command", "boolean"), | ||
| 247 | typechecked("handle_options", "boolean"), | ||
| 248 | typechecked("action", "function"), | ||
| 249 | typechecked("command_target", "string"), | ||
| 250 | typechecked("help_vertical_space", "number"), | ||
| 251 | typechecked("usage_margin", "number"), | ||
| 252 | typechecked("usage_max_width", "number"), | ||
| 253 | typechecked("help_usage_margin", "number"), | ||
| 254 | typechecked("help_description_margin", "number"), | ||
| 255 | typechecked("help_max_width", "number"), | ||
| 256 | add_help | ||
| 257 | }) | ||
| 258 | |||
| 259 | local Command = class({ | ||
| 260 | _aliases = {} | ||
| 261 | }, { | ||
| 262 | args = 3, | ||
| 263 | multiname, | ||
| 264 | typechecked("description", "string"), | ||
| 265 | typechecked("epilog", "string"), | ||
| 266 | typechecked("summary", "string"), | ||
| 267 | typechecked("target", "string"), | ||
| 268 | typechecked("usage", "string"), | ||
| 269 | typechecked("help", "string"), | ||
| 270 | typechecked("require_command", "boolean"), | ||
| 271 | typechecked("handle_options", "boolean"), | ||
| 272 | typechecked("action", "function"), | ||
| 273 | typechecked("command_target", "string"), | ||
| 274 | typechecked("help_vertical_space", "number"), | ||
| 275 | typechecked("usage_margin", "number"), | ||
| 276 | typechecked("usage_max_width", "number"), | ||
| 277 | typechecked("help_usage_margin", "number"), | ||
| 278 | typechecked("help_description_margin", "number"), | ||
| 279 | typechecked("help_max_width", "number"), | ||
| 280 | typechecked("hidden", "boolean"), | ||
| 281 | add_help | ||
| 282 | }, Parser) | ||
| 283 | |||
| 284 | local Argument = class({ | ||
| 285 | _minargs = 1, | ||
| 286 | _maxargs = 1, | ||
| 287 | _mincount = 1, | ||
| 288 | _maxcount = 1, | ||
| 289 | _defmode = "unused", | ||
| 290 | _show_default = true | ||
| 291 | }, { | ||
| 292 | args = 5, | ||
| 293 | typechecked("name", "string"), | ||
| 294 | typechecked("description", "string"), | ||
| 295 | option_default, | ||
| 296 | typechecked("convert", "function", "table"), | ||
| 297 | boundaries("args"), | ||
| 298 | typechecked("target", "string"), | ||
| 299 | typechecked("defmode", "string"), | ||
| 300 | typechecked("show_default", "boolean"), | ||
| 301 | typechecked("argname", "string", "table"), | ||
| 302 | typechecked("choices", "table"), | ||
| 303 | typechecked("hidden", "boolean"), | ||
| 304 | option_action, | ||
| 305 | option_init | ||
| 306 | }) | ||
| 307 | |||
| 308 | local Option = class({ | ||
| 309 | _aliases = {}, | ||
| 310 | _mincount = 0, | ||
| 311 | _overwrite = true | ||
| 312 | }, { | ||
| 313 | args = 6, | ||
| 314 | multiname, | ||
| 315 | typechecked("description", "string"), | ||
| 316 | option_default, | ||
| 317 | typechecked("convert", "function", "table"), | ||
| 318 | boundaries("args"), | ||
| 319 | boundaries("count"), | ||
| 320 | typechecked("target", "string"), | ||
| 321 | typechecked("defmode", "string"), | ||
| 322 | typechecked("show_default", "boolean"), | ||
| 323 | typechecked("overwrite", "boolean"), | ||
| 324 | typechecked("argname", "string", "table"), | ||
| 325 | typechecked("choices", "table"), | ||
| 326 | typechecked("hidden", "boolean"), | ||
| 327 | option_action, | ||
| 328 | option_init | ||
| 329 | }, Argument) | ||
| 330 | |||
| 331 | function Parser:_inherit_property(name, default) | ||
| 332 | local element = self | ||
| 333 | |||
| 334 | while true do | ||
| 335 | local value = element["_" .. name] | ||
| 336 | |||
| 337 | if value ~= nil then | ||
| 338 | return value | ||
| 339 | end | ||
| 340 | |||
| 341 | if not element._parent then | ||
| 342 | return default | ||
| 343 | end | ||
| 344 | |||
| 345 | element = element._parent | ||
| 346 | end | ||
| 347 | end | ||
| 348 | |||
| 349 | function Argument:_get_argument_list() | ||
| 350 | local buf = {} | ||
| 351 | local i = 1 | ||
| 352 | |||
| 353 | while i <= math.min(self._minargs, 3) do | ||
| 354 | local argname = self:_get_argname(i) | ||
| 355 | |||
| 356 | if self._default and self._defmode:find "a" then | ||
| 357 | argname = "[" .. argname .. "]" | ||
| 358 | end | ||
| 359 | |||
| 360 | table.insert(buf, argname) | ||
| 361 | i = i+1 | ||
| 362 | end | ||
| 363 | |||
| 364 | while i <= math.min(self._maxargs, 3) do | ||
| 365 | table.insert(buf, "[" .. self:_get_argname(i) .. "]") | ||
| 366 | i = i+1 | ||
| 367 | |||
| 368 | if self._maxargs == math.huge then | ||
| 369 | break | ||
| 370 | end | ||
| 371 | end | ||
| 372 | |||
| 373 | if i < self._maxargs then | ||
| 374 | table.insert(buf, "...") | ||
| 375 | end | ||
| 376 | |||
| 377 | return buf | ||
| 378 | end | ||
| 379 | |||
| 380 | function Argument:_get_usage() | ||
| 381 | local usage = table.concat(self:_get_argument_list(), " ") | ||
| 382 | |||
| 383 | if self._default and self._defmode:find "u" then | ||
| 384 | if self._maxargs > 1 or (self._minargs == 1 and not self._defmode:find "a") then | ||
| 385 | usage = "[" .. usage .. "]" | ||
| 386 | end | ||
| 387 | end | ||
| 388 | |||
| 389 | return usage | ||
| 390 | end | ||
| 391 | |||
| 392 | function actions.store_true(result, target) | ||
| 393 | result[target] = true | ||
| 394 | end | ||
| 395 | |||
| 396 | function actions.store_false(result, target) | ||
| 397 | result[target] = false | ||
| 398 | end | ||
| 399 | |||
| 400 | function actions.store(result, target, argument) | ||
| 401 | result[target] = argument | ||
| 402 | end | ||
| 403 | |||
| 404 | function actions.count(result, target, _, overwrite) | ||
| 405 | if not overwrite then | ||
| 406 | result[target] = result[target] + 1 | ||
| 407 | end | ||
| 408 | end | ||
| 409 | |||
| 410 | function actions.append(result, target, argument, overwrite) | ||
| 411 | result[target] = result[target] or {} | ||
| 412 | table.insert(result[target], argument) | ||
| 413 | |||
| 414 | if overwrite then | ||
| 415 | table.remove(result[target], 1) | ||
| 416 | end | ||
| 417 | end | ||
| 418 | |||
| 419 | function actions.concat(result, target, arguments, overwrite) | ||
| 420 | if overwrite then | ||
| 421 | error("'concat' action can't handle too many invocations") | ||
| 422 | end | ||
| 423 | |||
| 424 | result[target] = result[target] or {} | ||
| 425 | |||
| 426 | for _, argument in ipairs(arguments) do | ||
| 427 | table.insert(result[target], argument) | ||
| 428 | end | ||
| 429 | end | ||
| 430 | |||
| 431 | function Argument:_get_action() | ||
| 432 | local action, init | ||
| 433 | |||
| 434 | if self._maxcount == 1 then | ||
| 435 | if self._maxargs == 0 then | ||
| 436 | action, init = "store_true", nil | ||
| 437 | else | ||
| 438 | action, init = "store", nil | ||
| 439 | end | ||
| 440 | else | ||
| 441 | if self._maxargs == 0 then | ||
| 442 | action, init = "count", 0 | ||
| 443 | else | ||
| 444 | action, init = "append", {} | ||
| 445 | end | ||
| 446 | end | ||
| 447 | |||
| 448 | if self._action then | ||
| 449 | action = self._action | ||
| 450 | end | ||
| 451 | |||
| 452 | if self._has_init then | ||
| 453 | init = self._init | ||
| 454 | end | ||
| 455 | |||
| 456 | if type(action) == "string" then | ||
| 457 | action = actions[action] | ||
| 458 | end | ||
| 459 | |||
| 460 | return action, init | ||
| 461 | end | ||
| 462 | |||
| 463 | -- Returns placeholder for `narg`-th argument. | ||
| 464 | function Argument:_get_argname(narg) | ||
| 465 | local argname = self._argname or self:_get_default_argname() | ||
| 466 | |||
| 467 | if type(argname) == "table" then | ||
| 468 | return argname[narg] | ||
| 469 | else | ||
| 470 | return argname | ||
| 471 | end | ||
| 472 | end | ||
| 473 | |||
| 474 | function Argument:_get_choices_list() | ||
| 475 | return "{" .. table.concat(self._choices, ",") .. "}" | ||
| 476 | end | ||
| 477 | |||
| 478 | function Argument:_get_default_argname() | ||
| 479 | if self._choices then | ||
| 480 | return self:_get_choices_list() | ||
| 481 | else | ||
| 482 | return "<" .. self._name .. ">" | ||
| 483 | end | ||
| 484 | end | ||
| 485 | |||
| 486 | function Option:_get_default_argname() | ||
| 487 | if self._choices then | ||
| 488 | return self:_get_choices_list() | ||
| 489 | else | ||
| 490 | return "<" .. self:_get_default_target() .. ">" | ||
| 491 | end | ||
| 492 | end | ||
| 493 | |||
| 494 | -- Returns labels to be shown in the help message. | ||
| 495 | function Argument:_get_label_lines() | ||
| 496 | if self._choices then | ||
| 497 | return {self:_get_choices_list()} | ||
| 498 | else | ||
| 499 | return {self._name} | ||
| 500 | end | ||
| 501 | end | ||
| 502 | |||
| 503 | function Option:_get_label_lines() | ||
| 504 | local argument_list = self:_get_argument_list() | ||
| 505 | |||
| 506 | if #argument_list == 0 then | ||
| 507 | -- Don't put aliases for simple flags like `-h` on different lines. | ||
| 508 | return {table.concat(self._aliases, ", ")} | ||
| 509 | end | ||
| 510 | |||
| 511 | local longest_alias_length = -1 | ||
| 512 | |||
| 513 | for _, alias in ipairs(self._aliases) do | ||
| 514 | longest_alias_length = math.max(longest_alias_length, #alias) | ||
| 515 | end | ||
| 516 | |||
| 517 | local argument_list_repr = table.concat(argument_list, " ") | ||
| 518 | local lines = {} | ||
| 519 | |||
| 520 | for i, alias in ipairs(self._aliases) do | ||
| 521 | local line = (" "):rep(longest_alias_length - #alias) .. alias .. " " .. argument_list_repr | ||
| 522 | |||
| 523 | if i ~= #self._aliases then | ||
| 524 | line = line .. "," | ||
| 525 | end | ||
| 526 | |||
| 527 | table.insert(lines, line) | ||
| 528 | end | ||
| 529 | |||
| 530 | return lines | ||
| 531 | end | ||
| 532 | |||
| 533 | function Command:_get_label_lines() | ||
| 534 | return {table.concat(self._aliases, ", ")} | ||
| 535 | end | ||
| 536 | |||
| 537 | function Argument:_get_description() | ||
| 538 | if self._default and self._show_default then | ||
| 539 | if self._description then | ||
| 540 | return ("%s (default: %s)"):format(self._description, self._default) | ||
| 541 | else | ||
| 542 | return ("default: %s"):format(self._default) | ||
| 543 | end | ||
| 544 | else | ||
| 545 | return self._description or "" | ||
| 546 | end | ||
| 547 | end | ||
| 548 | |||
| 549 | function Command:_get_description() | ||
| 550 | return self._summary or self._description or "" | ||
| 551 | end | ||
| 552 | |||
| 553 | function Option:_get_usage() | ||
| 554 | local usage = self:_get_argument_list() | ||
| 555 | table.insert(usage, 1, self._name) | ||
| 556 | usage = table.concat(usage, " ") | ||
| 557 | |||
| 558 | if self._mincount == 0 or self._default then | ||
| 559 | usage = "[" .. usage .. "]" | ||
| 560 | end | ||
| 561 | |||
| 562 | return usage | ||
| 563 | end | ||
| 564 | |||
| 565 | function Argument:_get_default_target() | ||
| 566 | return self._name | ||
| 567 | end | ||
| 568 | |||
| 569 | function Option:_get_default_target() | ||
| 570 | local res | ||
| 571 | |||
| 572 | for _, alias in ipairs(self._aliases) do | ||
| 573 | if alias:sub(1, 1) == alias:sub(2, 2) then | ||
| 574 | res = alias:sub(3) | ||
| 575 | break | ||
| 576 | end | ||
| 577 | end | ||
| 578 | |||
| 579 | res = res or self._name:sub(2) | ||
| 580 | return (res:gsub("-", "_")) | ||
| 581 | end | ||
| 582 | |||
| 583 | function Option:_is_vararg() | ||
| 584 | return self._maxargs ~= self._minargs | ||
| 585 | end | ||
| 586 | |||
| 587 | function Parser:_get_fullname(exclude_root) | ||
| 588 | local parent = self._parent | ||
| 589 | if exclude_root and not parent then | ||
| 590 | return "" | ||
| 591 | end | ||
| 592 | local buf = {self._name} | ||
| 593 | |||
| 594 | while parent do | ||
| 595 | if not exclude_root or parent._parent then | ||
| 596 | table.insert(buf, 1, parent._name) | ||
| 597 | end | ||
| 598 | parent = parent._parent | ||
| 599 | end | ||
| 600 | |||
| 601 | return table.concat(buf, " ") | ||
| 602 | end | ||
| 603 | |||
| 604 | function Parser:_update_charset(charset) | ||
| 605 | charset = charset or {} | ||
| 606 | |||
| 607 | for _, command in ipairs(self._commands) do | ||
| 608 | command:_update_charset(charset) | ||
| 609 | end | ||
| 610 | |||
| 611 | for _, option in ipairs(self._options) do | ||
| 612 | for _, alias in ipairs(option._aliases) do | ||
| 613 | charset[alias:sub(1, 1)] = true | ||
| 614 | end | ||
| 615 | end | ||
| 616 | |||
| 617 | return charset | ||
| 618 | end | ||
| 619 | |||
| 620 | function Parser:argument(...) | ||
| 621 | local argument = Argument(...) | ||
| 622 | table.insert(self._arguments, argument) | ||
| 623 | return argument | ||
| 624 | end | ||
| 625 | |||
| 626 | function Parser:option(...) | ||
| 627 | local option = Option(...) | ||
| 628 | table.insert(self._options, option) | ||
| 629 | return option | ||
| 630 | end | ||
| 631 | |||
| 632 | function Parser:flag(...) | ||
| 633 | return self:option():args(0)(...) | ||
| 634 | end | ||
| 635 | |||
| 636 | function Parser:command(...) | ||
| 637 | local command = Command():add_help(true)(...) | ||
| 638 | command._parent = self | ||
| 639 | table.insert(self._commands, command) | ||
| 640 | return command | ||
| 641 | end | ||
| 642 | |||
| 643 | function Parser:mutex(...) | ||
| 644 | local elements = {...} | ||
| 645 | |||
| 646 | for i, element in ipairs(elements) do | ||
| 647 | local mt = getmetatable(element) | ||
| 648 | assert(mt == Option or mt == Argument, ("bad argument #%d to 'mutex' (Option or Argument expected)"):format(i)) | ||
| 649 | end | ||
| 650 | |||
| 651 | table.insert(self._mutexes, elements) | ||
| 652 | return self | ||
| 653 | end | ||
| 654 | |||
| 655 | function Parser:group(name, ...) | ||
| 656 | assert(type(name) == "string", ("bad argument #1 to 'group' (string expected, got %s)"):format(type(name))) | ||
| 657 | |||
| 658 | local group = {name = name, ...} | ||
| 659 | |||
| 660 | for i, element in ipairs(group) do | ||
| 661 | local mt = getmetatable(element) | ||
| 662 | assert(mt == Option or mt == Argument or mt == Command, | ||
| 663 | ("bad argument #%d to 'group' (Option or Argument or Command expected)"):format(i + 1)) | ||
| 664 | end | ||
| 665 | |||
| 666 | table.insert(self._groups, group) | ||
| 667 | return self | ||
| 668 | end | ||
| 669 | |||
| 670 | local usage_welcome = "Usage: " | ||
| 671 | |||
| 672 | function Parser:get_usage() | ||
| 673 | if self._usage then | ||
| 674 | return self._usage | ||
| 675 | end | ||
| 676 | |||
| 677 | local usage_margin = self:_inherit_property("usage_margin", #usage_welcome) | ||
| 678 | local max_usage_width = self:_inherit_property("usage_max_width", 70) | ||
| 679 | local lines = {usage_welcome .. self:_get_fullname()} | ||
| 680 | |||
| 681 | local function add(s) | ||
| 682 | if #lines[#lines]+1+#s <= max_usage_width then | ||
| 683 | lines[#lines] = lines[#lines] .. " " .. s | ||
| 684 | else | ||
| 685 | lines[#lines+1] = (" "):rep(usage_margin) .. s | ||
| 686 | end | ||
| 687 | end | ||
| 688 | |||
| 689 | -- Normally options are before positional arguments in usage messages. | ||
| 690 | -- However, vararg options should be after, because they can't be reliable used | ||
| 691 | -- before a positional argument. | ||
| 692 | -- Mutexes come into play, too, and are shown as soon as possible. | ||
| 693 | -- Overall, output usages in the following order: | ||
| 694 | -- 1. Mutexes that don't have positional arguments or vararg options. | ||
| 695 | -- 2. Options that are not in any mutexes and are not vararg. | ||
| 696 | -- 3. Positional arguments - on their own or as a part of a mutex. | ||
| 697 | -- 4. Remaining mutexes. | ||
| 698 | -- 5. Remaining options. | ||
| 699 | |||
| 700 | local elements_in_mutexes = {} | ||
| 701 | local added_elements = {} | ||
| 702 | local added_mutexes = {} | ||
| 703 | local argument_to_mutexes = {} | ||
| 704 | |||
| 705 | local function add_mutex(mutex, main_argument) | ||
| 706 | if added_mutexes[mutex] then | ||
| 707 | return | ||
| 708 | end | ||
| 709 | |||
| 710 | added_mutexes[mutex] = true | ||
| 711 | local buf = {} | ||
| 712 | |||
| 713 | for _, element in ipairs(mutex) do | ||
| 714 | if not element._hidden and not added_elements[element] then | ||
| 715 | if getmetatable(element) == Option or element == main_argument then | ||
| 716 | table.insert(buf, element:_get_usage()) | ||
| 717 | added_elements[element] = true | ||
| 718 | end | ||
| 719 | end | ||
| 720 | end | ||
| 721 | |||
| 722 | if #buf == 1 then | ||
| 723 | add(buf[1]) | ||
| 724 | elseif #buf > 1 then | ||
| 725 | add("(" .. table.concat(buf, " | ") .. ")") | ||
| 726 | end | ||
| 727 | end | ||
| 728 | |||
| 729 | local function add_element(element) | ||
| 730 | if not element._hidden and not added_elements[element] then | ||
| 731 | add(element:_get_usage()) | ||
| 732 | added_elements[element] = true | ||
| 733 | end | ||
| 734 | end | ||
| 735 | |||
| 736 | for _, mutex in ipairs(self._mutexes) do | ||
| 737 | local is_vararg = false | ||
| 738 | local has_argument = false | ||
| 739 | |||
| 740 | for _, element in ipairs(mutex) do | ||
| 741 | if getmetatable(element) == Option then | ||
| 742 | if element:_is_vararg() then | ||
| 743 | is_vararg = true | ||
| 744 | end | ||
| 745 | else | ||
| 746 | has_argument = true | ||
| 747 | argument_to_mutexes[element] = argument_to_mutexes[element] or {} | ||
| 748 | table.insert(argument_to_mutexes[element], mutex) | ||
| 749 | end | ||
| 750 | |||
| 751 | elements_in_mutexes[element] = true | ||
| 752 | end | ||
| 753 | |||
| 754 | if not is_vararg and not has_argument then | ||
| 755 | add_mutex(mutex) | ||
| 756 | end | ||
| 757 | end | ||
| 758 | |||
| 759 | for _, option in ipairs(self._options) do | ||
| 760 | if not elements_in_mutexes[option] and not option:_is_vararg() then | ||
| 761 | add_element(option) | ||
| 762 | end | ||
| 763 | end | ||
| 764 | |||
| 765 | -- Add usages for positional arguments, together with one mutex containing them, if they are in a mutex. | ||
| 766 | for _, argument in ipairs(self._arguments) do | ||
| 767 | -- Pick a mutex as a part of which to show this argument, take the first one that's still available. | ||
| 768 | local mutex | ||
| 769 | |||
| 770 | if elements_in_mutexes[argument] then | ||
| 771 | for _, argument_mutex in ipairs(argument_to_mutexes[argument]) do | ||
| 772 | if not added_mutexes[argument_mutex] then | ||
| 773 | mutex = argument_mutex | ||
| 774 | end | ||
| 775 | end | ||
| 776 | end | ||
| 777 | |||
| 778 | if mutex then | ||
| 779 | add_mutex(mutex, argument) | ||
| 780 | else | ||
| 781 | add_element(argument) | ||
| 782 | end | ||
| 783 | end | ||
| 784 | |||
| 785 | for _, mutex in ipairs(self._mutexes) do | ||
| 786 | add_mutex(mutex) | ||
| 787 | end | ||
| 788 | |||
| 789 | for _, option in ipairs(self._options) do | ||
| 790 | add_element(option) | ||
| 791 | end | ||
| 792 | |||
| 793 | if #self._commands > 0 then | ||
| 794 | if self._require_command then | ||
| 795 | add("<command>") | ||
| 796 | else | ||
| 797 | add("[<command>]") | ||
| 798 | end | ||
| 799 | |||
| 800 | add("...") | ||
| 801 | end | ||
| 802 | |||
| 803 | return table.concat(lines, "\n") | ||
| 804 | end | ||
| 805 | |||
| 806 | local function split_lines(s) | ||
| 807 | if s == "" then | ||
| 808 | return {} | ||
| 809 | end | ||
| 810 | |||
| 811 | local lines = {} | ||
| 812 | |||
| 813 | if s:sub(-1) ~= "\n" then | ||
| 814 | s = s .. "\n" | ||
| 815 | end | ||
| 816 | |||
| 817 | for line in s:gmatch("([^\n]*)\n") do | ||
| 818 | table.insert(lines, line) | ||
| 819 | end | ||
| 820 | |||
| 821 | return lines | ||
| 822 | end | ||
| 823 | |||
| 824 | local function autowrap_line(line, max_length) | ||
| 825 | -- Algorithm for splitting lines is simple and greedy. | ||
| 826 | local result_lines = {} | ||
| 827 | |||
| 828 | -- Preserve original indentation of the line, put this at the beginning of each result line. | ||
| 829 | -- If the first word looks like a list marker ('*', '+', or '-'), add spaces so that starts | ||
| 830 | -- of the second and the following lines vertically align with the start of the second word. | ||
| 831 | local indentation = line:match("^ *") | ||
| 832 | |||
| 833 | if line:find("^ *[%*%+%-]") then | ||
| 834 | indentation = indentation .. " " .. line:match("^ *[%*%+%-]( *)") | ||
| 835 | end | ||
| 836 | |||
| 837 | -- Parts of the last line being assembled. | ||
| 838 | local line_parts = {} | ||
| 839 | |||
| 840 | -- Length of the current line. | ||
| 841 | local line_length = 0 | ||
| 842 | |||
| 843 | -- Index of the next character to consider. | ||
| 844 | local index = 1 | ||
| 845 | |||
| 846 | while true do | ||
| 847 | local word_start, word_finish, word = line:find("([^ ]+)", index) | ||
| 848 | |||
| 849 | if not word_start then | ||
| 850 | -- Ignore trailing spaces, if any. | ||
| 851 | break | ||
| 852 | end | ||
| 853 | |||
| 854 | local preceding_spaces = line:sub(index, word_start - 1) | ||
| 855 | index = word_finish + 1 | ||
| 856 | |||
| 857 | if (#line_parts == 0) or (line_length + #preceding_spaces + #word <= max_length) then | ||
| 858 | -- Either this is the very first word or it fits as an addition to the current line, add it. | ||
| 859 | table.insert(line_parts, preceding_spaces) -- For the very first word this adds the indentation. | ||
| 860 | table.insert(line_parts, word) | ||
| 861 | line_length = line_length + #preceding_spaces + #word | ||
| 862 | else | ||
| 863 | -- Does not fit, finish current line and put the word into a new one. | ||
| 864 | table.insert(result_lines, table.concat(line_parts)) | ||
| 865 | line_parts = {indentation, word} | ||
| 866 | line_length = #indentation + #word | ||
| 867 | end | ||
| 868 | end | ||
| 869 | |||
| 870 | if #line_parts > 0 then | ||
| 871 | table.insert(result_lines, table.concat(line_parts)) | ||
| 872 | end | ||
| 873 | |||
| 874 | if #result_lines == 0 then | ||
| 875 | -- Preserve empty lines. | ||
| 876 | result_lines[1] = "" | ||
| 877 | end | ||
| 878 | |||
| 879 | return result_lines | ||
| 880 | end | ||
| 881 | |||
| 882 | -- Automatically wraps lines within given array, | ||
| 883 | -- attempting to limit line length to `max_length`. | ||
| 884 | -- Existing line splits are preserved. | ||
| 885 | local function autowrap(lines, max_length) | ||
| 886 | local result_lines = {} | ||
| 887 | |||
| 888 | for _, line in ipairs(lines) do | ||
| 889 | local autowrapped_lines = autowrap_line(line, max_length) | ||
| 890 | |||
| 891 | for _, autowrapped_line in ipairs(autowrapped_lines) do | ||
| 892 | table.insert(result_lines, autowrapped_line) | ||
| 893 | end | ||
| 894 | end | ||
| 895 | |||
| 896 | return result_lines | ||
| 897 | end | ||
| 898 | |||
| 899 | function Parser:_get_element_help(element) | ||
| 900 | local label_lines = element:_get_label_lines() | ||
| 901 | local description_lines = split_lines(element:_get_description()) | ||
| 902 | |||
| 903 | local result_lines = {} | ||
| 904 | |||
| 905 | -- All label lines should have the same length (except the last one, it has no comma). | ||
| 906 | -- If too long, start description after all the label lines. | ||
| 907 | -- Otherwise, combine label and description lines. | ||
| 908 | |||
| 909 | local usage_margin_len = self:_inherit_property("help_usage_margin", 3) | ||
| 910 | local usage_margin = (" "):rep(usage_margin_len) | ||
| 911 | local description_margin_len = self:_inherit_property("help_description_margin", 25) | ||
| 912 | local description_margin = (" "):rep(description_margin_len) | ||
| 913 | |||
| 914 | local help_max_width = self:_inherit_property("help_max_width") | ||
| 915 | |||
| 916 | if help_max_width then | ||
| 917 | local description_max_width = math.max(help_max_width - description_margin_len, 10) | ||
| 918 | description_lines = autowrap(description_lines, description_max_width) | ||
| 919 | end | ||
| 920 | |||
| 921 | if #label_lines[1] >= (description_margin_len - usage_margin_len) then | ||
| 922 | for _, label_line in ipairs(label_lines) do | ||
| 923 | table.insert(result_lines, usage_margin .. label_line) | ||
| 924 | end | ||
| 925 | |||
| 926 | for _, description_line in ipairs(description_lines) do | ||
| 927 | table.insert(result_lines, description_margin .. description_line) | ||
| 928 | end | ||
| 929 | else | ||
| 930 | for i = 1, math.max(#label_lines, #description_lines) do | ||
| 931 | local label_line = label_lines[i] | ||
| 932 | local description_line = description_lines[i] | ||
| 933 | |||
| 934 | local line = "" | ||
| 935 | |||
| 936 | if label_line then | ||
| 937 | line = usage_margin .. label_line | ||
| 938 | end | ||
| 939 | |||
| 940 | if description_line and description_line ~= "" then | ||
| 941 | line = line .. (" "):rep(description_margin_len - #line) .. description_line | ||
| 942 | end | ||
| 943 | |||
| 944 | table.insert(result_lines, line) | ||
| 945 | end | ||
| 946 | end | ||
| 947 | |||
| 948 | return table.concat(result_lines, "\n") | ||
| 949 | end | ||
| 950 | |||
| 951 | local function get_group_types(group) | ||
| 952 | local types = {} | ||
| 953 | |||
| 954 | for _, element in ipairs(group) do | ||
| 955 | types[getmetatable(element)] = true | ||
| 956 | end | ||
| 957 | |||
| 958 | return types | ||
| 959 | end | ||
| 960 | |||
| 961 | function Parser:_add_group_help(blocks, added_elements, label, elements) | ||
| 962 | local buf = {label} | ||
| 963 | |||
| 964 | for _, element in ipairs(elements) do | ||
| 965 | if not element._hidden and not added_elements[element] then | ||
| 966 | added_elements[element] = true | ||
| 967 | table.insert(buf, self:_get_element_help(element)) | ||
| 968 | end | ||
| 969 | end | ||
| 970 | |||
| 971 | if #buf > 1 then | ||
| 972 | table.insert(blocks, table.concat(buf, ("\n"):rep(self:_inherit_property("help_vertical_space", 0) + 1))) | ||
| 973 | end | ||
| 974 | end | ||
| 975 | |||
| 976 | function Parser:get_help() | ||
| 977 | if self._help then | ||
| 978 | return self._help | ||
| 979 | end | ||
| 980 | |||
| 981 | local blocks = {self:get_usage()} | ||
| 982 | |||
| 983 | local help_max_width = self:_inherit_property("help_max_width") | ||
| 984 | |||
| 985 | if self._description then | ||
| 986 | local description = self._description | ||
| 987 | |||
| 988 | if help_max_width then | ||
| 989 | description = table.concat(autowrap(split_lines(description), help_max_width), "\n") | ||
| 990 | end | ||
| 991 | |||
| 992 | table.insert(blocks, description) | ||
| 993 | end | ||
| 994 | |||
| 995 | -- 1. Put groups containing arguments first, then other arguments. | ||
| 996 | -- 2. Put remaining groups containing options, then other options. | ||
| 997 | -- 3. Put remaining groups containing commands, then other commands. | ||
| 998 | -- Assume that an element can't be in several groups. | ||
| 999 | local groups_by_type = { | ||
| 1000 | [Argument] = {}, | ||
| 1001 | [Option] = {}, | ||
| 1002 | [Command] = {} | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | for _, group in ipairs(self._groups) do | ||
| 1006 | local group_types = get_group_types(group) | ||
| 1007 | |||
| 1008 | for _, mt in ipairs({Argument, Option, Command}) do | ||
| 1009 | if group_types[mt] then | ||
| 1010 | table.insert(groups_by_type[mt], group) | ||
| 1011 | break | ||
| 1012 | end | ||
| 1013 | end | ||
| 1014 | end | ||
| 1015 | |||
| 1016 | local default_groups = { | ||
| 1017 | {name = "Arguments", type = Argument, elements = self._arguments}, | ||
| 1018 | {name = "Options", type = Option, elements = self._options}, | ||
| 1019 | {name = "Commands", type = Command, elements = self._commands} | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | local added_elements = {} | ||
| 1023 | |||
| 1024 | for _, default_group in ipairs(default_groups) do | ||
| 1025 | local type_groups = groups_by_type[default_group.type] | ||
| 1026 | |||
| 1027 | for _, group in ipairs(type_groups) do | ||
| 1028 | self:_add_group_help(blocks, added_elements, group.name .. ":", group) | ||
| 1029 | end | ||
| 1030 | |||
| 1031 | local default_label = default_group.name .. ":" | ||
| 1032 | |||
| 1033 | if #type_groups > 0 then | ||
| 1034 | default_label = "Other " .. default_label:gsub("^.", string.lower) | ||
| 1035 | end | ||
| 1036 | |||
| 1037 | self:_add_group_help(blocks, added_elements, default_label, default_group.elements) | ||
| 1038 | end | ||
| 1039 | |||
| 1040 | if self._epilog then | ||
| 1041 | local epilog = self._epilog | ||
| 1042 | |||
| 1043 | if help_max_width then | ||
| 1044 | epilog = table.concat(autowrap(split_lines(epilog), help_max_width), "\n") | ||
| 1045 | end | ||
| 1046 | |||
| 1047 | table.insert(blocks, epilog) | ||
| 1048 | end | ||
| 1049 | |||
| 1050 | return table.concat(blocks, "\n\n") | ||
| 1051 | end | ||
| 1052 | |||
| 1053 | function Parser:add_help_command(value) | ||
| 1054 | if value then | ||
| 1055 | assert(type(value) == "string" or type(value) == "table", | ||
| 1056 | ("bad argument #1 to 'add_help_command' (string or table expected, got %s)"):format(type(value))) | ||
| 1057 | end | ||
| 1058 | |||
| 1059 | local help = self:command() | ||
| 1060 | :description "Show help for commands." | ||
| 1061 | help:argument "command" | ||
| 1062 | :description "The command to show help for." | ||
| 1063 | :args "?" | ||
| 1064 | :action(function(_, _, cmd) | ||
| 1065 | if not cmd then | ||
| 1066 | print(self:get_help()) | ||
| 1067 | os.exit(0) | ||
| 1068 | else | ||
| 1069 | for _, command in ipairs(self._commands) do | ||
| 1070 | for _, alias in ipairs(command._aliases) do | ||
| 1071 | if alias == cmd then | ||
| 1072 | print(command:get_help()) | ||
| 1073 | os.exit(0) | ||
| 1074 | end | ||
| 1075 | end | ||
| 1076 | end | ||
| 1077 | end | ||
| 1078 | help:error(("unknown command '%s'"):format(cmd)) | ||
| 1079 | end) | ||
| 1080 | |||
| 1081 | if value then | ||
| 1082 | help = help(value) | ||
| 1083 | end | ||
| 1084 | |||
| 1085 | if not help._name then | ||
| 1086 | help "help" | ||
| 1087 | end | ||
| 1088 | |||
| 1089 | help._is_help_command = true | ||
| 1090 | return self | ||
| 1091 | end | ||
| 1092 | |||
| 1093 | function Parser:_is_shell_safe() | ||
| 1094 | if self._basename then | ||
| 1095 | if self._basename:find("[^%w_%-%+%.]") then | ||
| 1096 | return false | ||
| 1097 | end | ||
| 1098 | else | ||
| 1099 | for _, alias in ipairs(self._aliases) do | ||
| 1100 | if alias:find("[^%w_%-%+%.]") then | ||
| 1101 | return false | ||
| 1102 | end | ||
| 1103 | end | ||
| 1104 | end | ||
| 1105 | for _, option in ipairs(self._options) do | ||
| 1106 | for _, alias in ipairs(option._aliases) do | ||
| 1107 | if alias:find("[^%w_%-%+%.]") then | ||
| 1108 | return false | ||
| 1109 | end | ||
| 1110 | end | ||
| 1111 | if option._choices then | ||
| 1112 | for _, choice in ipairs(option._choices) do | ||
| 1113 | if choice:find("[%s'\"]") then | ||
| 1114 | return false | ||
| 1115 | end | ||
| 1116 | end | ||
| 1117 | end | ||
| 1118 | end | ||
| 1119 | for _, argument in ipairs(self._arguments) do | ||
| 1120 | if argument._choices then | ||
| 1121 | for _, choice in ipairs(argument._choices) do | ||
| 1122 | if choice:find("[%s'\"]") then | ||
| 1123 | return false | ||
| 1124 | end | ||
| 1125 | end | ||
| 1126 | end | ||
| 1127 | end | ||
| 1128 | for _, command in ipairs(self._commands) do | ||
| 1129 | if not command:_is_shell_safe() then | ||
| 1130 | return false | ||
| 1131 | end | ||
| 1132 | end | ||
| 1133 | return true | ||
| 1134 | end | ||
| 1135 | |||
| 1136 | function Parser:add_complete(value) | ||
| 1137 | if value then | ||
| 1138 | assert(type(value) == "string" or type(value) == "table", | ||
| 1139 | ("bad argument #1 to 'add_complete' (string or table expected, got %s)"):format(type(value))) | ||
| 1140 | end | ||
| 1141 | |||
| 1142 | local complete = self:option() | ||
| 1143 | :description "Output a shell completion script for the specified shell." | ||
| 1144 | :args(1) | ||
| 1145 | :choices {"bash", "zsh", "fish"} | ||
| 1146 | :action(function(_, _, shell) | ||
| 1147 | io.write(self["get_" .. shell .. "_complete"](self)) | ||
| 1148 | os.exit(0) | ||
| 1149 | end) | ||
| 1150 | |||
| 1151 | if value then | ||
| 1152 | complete = complete(value) | ||
| 1153 | end | ||
| 1154 | |||
| 1155 | if not complete._name then | ||
| 1156 | complete "--completion" | ||
| 1157 | end | ||
| 1158 | |||
| 1159 | return self | ||
| 1160 | end | ||
| 1161 | |||
| 1162 | function Parser:add_complete_command(value) | ||
| 1163 | if value then | ||
| 1164 | assert(type(value) == "string" or type(value) == "table", | ||
| 1165 | ("bad argument #1 to 'add_complete_command' (string or table expected, got %s)"):format(type(value))) | ||
| 1166 | end | ||
| 1167 | |||
| 1168 | local complete = self:command() | ||
| 1169 | :description "Output a shell completion script." | ||
| 1170 | complete:argument "shell" | ||
| 1171 | :description "The shell to output a completion script for." | ||
| 1172 | :choices {"bash", "zsh", "fish"} | ||
| 1173 | :action(function(_, _, shell) | ||
| 1174 | io.write(self["get_" .. shell .. "_complete"](self)) | ||
| 1175 | os.exit(0) | ||
| 1176 | end) | ||
| 1177 | |||
| 1178 | if value then | ||
| 1179 | complete = complete(value) | ||
| 1180 | end | ||
| 1181 | |||
| 1182 | if not complete._name then | ||
| 1183 | complete "completion" | ||
| 1184 | end | ||
| 1185 | |||
| 1186 | return self | ||
| 1187 | end | ||
| 1188 | |||
| 1189 | local function base_name(pathname) | ||
| 1190 | return pathname:gsub("[/\\]*$", ""):match(".*[/\\]([^/\\]*)") or pathname | ||
| 1191 | end | ||
| 1192 | |||
| 1193 | local function get_short_description(element) | ||
| 1194 | local short = element:_get_description():match("^(.-)%.%s") | ||
| 1195 | return short or element:_get_description():match("^(.-)%.?$") | ||
| 1196 | end | ||
| 1197 | |||
| 1198 | function Parser:_get_options() | ||
| 1199 | local options = {} | ||
| 1200 | for _, option in ipairs(self._options) do | ||
| 1201 | for _, alias in ipairs(option._aliases) do | ||
| 1202 | table.insert(options, alias) | ||
| 1203 | end | ||
| 1204 | end | ||
| 1205 | return table.concat(options, " ") | ||
| 1206 | end | ||
| 1207 | |||
| 1208 | function Parser:_get_commands() | ||
| 1209 | local commands = {} | ||
| 1210 | for _, command in ipairs(self._commands) do | ||
| 1211 | for _, alias in ipairs(command._aliases) do | ||
| 1212 | table.insert(commands, alias) | ||
| 1213 | end | ||
| 1214 | end | ||
| 1215 | return table.concat(commands, " ") | ||
| 1216 | end | ||
| 1217 | |||
| 1218 | function Parser:_bash_option_args(buf, indent) | ||
| 1219 | local opts = {} | ||
| 1220 | for _, option in ipairs(self._options) do | ||
| 1221 | if option._choices or option._minargs > 0 then | ||
| 1222 | local compreply | ||
| 1223 | if option._choices then | ||
| 1224 | compreply = 'COMPREPLY=($(compgen -W "' .. table.concat(option._choices, " ") .. '" -- "$cur"))' | ||
| 1225 | else | ||
| 1226 | compreply = 'COMPREPLY=($(compgen -f -- "$cur"))' | ||
| 1227 | end | ||
| 1228 | table.insert(opts, (" "):rep(indent + 4) .. table.concat(option._aliases, "|") .. ")") | ||
| 1229 | table.insert(opts, (" "):rep(indent + 8) .. compreply) | ||
| 1230 | table.insert(opts, (" "):rep(indent + 8) .. "return 0") | ||
| 1231 | table.insert(opts, (" "):rep(indent + 8) .. ";;") | ||
| 1232 | end | ||
| 1233 | end | ||
| 1234 | |||
| 1235 | if #opts > 0 then | ||
| 1236 | table.insert(buf, (" "):rep(indent) .. 'case "$prev" in') | ||
| 1237 | table.insert(buf, table.concat(opts, "\n")) | ||
| 1238 | table.insert(buf, (" "):rep(indent) .. "esac\n") | ||
| 1239 | end | ||
| 1240 | end | ||
| 1241 | |||
| 1242 | function Parser:_bash_get_cmd(buf, indent) | ||
| 1243 | if #self._commands == 0 then | ||
| 1244 | return | ||
| 1245 | end | ||
| 1246 | |||
| 1247 | table.insert(buf, (" "):rep(indent) .. 'args=("${args[@]:1}")') | ||
| 1248 | table.insert(buf, (" "):rep(indent) .. 'for arg in "${args[@]}"; do') | ||
| 1249 | table.insert(buf, (" "):rep(indent + 4) .. 'case "$arg" in') | ||
| 1250 | |||
| 1251 | for _, command in ipairs(self._commands) do | ||
| 1252 | table.insert(buf, (" "):rep(indent + 8) .. table.concat(command._aliases, "|") .. ")") | ||
| 1253 | if self._parent then | ||
| 1254 | table.insert(buf, (" "):rep(indent + 12) .. 'cmd="$cmd ' .. command._name .. '"') | ||
| 1255 | else | ||
| 1256 | table.insert(buf, (" "):rep(indent + 12) .. 'cmd="' .. command._name .. '"') | ||
| 1257 | end | ||
| 1258 | table.insert(buf, (" "):rep(indent + 12) .. 'opts="$opts ' .. command:_get_options() .. '"') | ||
| 1259 | command:_bash_get_cmd(buf, indent + 12) | ||
| 1260 | table.insert(buf, (" "):rep(indent + 12) .. "break") | ||
| 1261 | table.insert(buf, (" "):rep(indent + 12) .. ";;") | ||
| 1262 | end | ||
| 1263 | |||
| 1264 | table.insert(buf, (" "):rep(indent + 4) .. "esac") | ||
| 1265 | table.insert(buf, (" "):rep(indent) .. "done") | ||
| 1266 | end | ||
| 1267 | |||
| 1268 | function Parser:_bash_cmd_completions(buf) | ||
| 1269 | local cmd_buf = {} | ||
| 1270 | if self._parent then | ||
| 1271 | self:_bash_option_args(cmd_buf, 12) | ||
| 1272 | end | ||
| 1273 | if #self._commands > 0 then | ||
| 1274 | table.insert(cmd_buf, (" "):rep(12) .. 'COMPREPLY=($(compgen -W "' .. self:_get_commands() .. '" -- "$cur"))') | ||
| 1275 | elseif self._is_help_command then | ||
| 1276 | table.insert(cmd_buf, (" "):rep(12) | ||
| 1277 | .. 'COMPREPLY=($(compgen -W "' | ||
| 1278 | .. self._parent:_get_commands() | ||
| 1279 | .. '" -- "$cur"))') | ||
| 1280 | end | ||
| 1281 | if #cmd_buf > 0 then | ||
| 1282 | table.insert(buf, (" "):rep(8) .. "'" .. self:_get_fullname(true) .. "')") | ||
| 1283 | table.insert(buf, table.concat(cmd_buf, "\n")) | ||
| 1284 | table.insert(buf, (" "):rep(12) .. ";;") | ||
| 1285 | end | ||
| 1286 | |||
| 1287 | for _, command in ipairs(self._commands) do | ||
| 1288 | command:_bash_cmd_completions(buf) | ||
| 1289 | end | ||
| 1290 | end | ||
| 1291 | |||
| 1292 | function Parser:get_bash_complete() | ||
| 1293 | self._basename = base_name(self._name) | ||
| 1294 | assert(self:_is_shell_safe()) | ||
| 1295 | local buf = {([[ | ||
| 1296 | _%s() { | ||
| 1297 | local IFS=$' \t\n' | ||
| 1298 | local args cur prev cmd opts arg | ||
| 1299 | args=("${COMP_WORDS[@]}") | ||
| 1300 | cur="${COMP_WORDS[COMP_CWORD]}" | ||
| 1301 | prev="${COMP_WORDS[COMP_CWORD-1]}" | ||
| 1302 | opts="%s" | ||
| 1303 | ]]):format(self._basename, self:_get_options())} | ||
| 1304 | |||
| 1305 | self:_bash_option_args(buf, 4) | ||
| 1306 | self:_bash_get_cmd(buf, 4) | ||
| 1307 | if #self._commands > 0 then | ||
| 1308 | table.insert(buf, "") | ||
| 1309 | table.insert(buf, (" "):rep(4) .. 'case "$cmd" in') | ||
| 1310 | self:_bash_cmd_completions(buf) | ||
| 1311 | table.insert(buf, (" "):rep(4) .. "esac\n") | ||
| 1312 | end | ||
| 1313 | |||
| 1314 | table.insert(buf, ([=[ | ||
| 1315 | if [[ "$cur" = -* ]]; then | ||
| 1316 | COMPREPLY=($(compgen -W "$opts" -- "$cur")) | ||
| 1317 | fi | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | complete -F _%s -o bashdefault -o default %s | ||
| 1321 | ]=]):format(self._basename, self._basename)) | ||
| 1322 | |||
| 1323 | return table.concat(buf, "\n") | ||
| 1324 | end | ||
| 1325 | |||
| 1326 | function Parser:_zsh_arguments(buf, cmd_name, indent) | ||
| 1327 | if self._parent then | ||
| 1328 | table.insert(buf, (" "):rep(indent) .. "options=(") | ||
| 1329 | table.insert(buf, (" "):rep(indent + 2) .. "$options") | ||
| 1330 | else | ||
| 1331 | table.insert(buf, (" "):rep(indent) .. "local -a options=(") | ||
| 1332 | end | ||
| 1333 | |||
| 1334 | for _, option in ipairs(self._options) do | ||
| 1335 | local line = {} | ||
| 1336 | if #option._aliases > 1 then | ||
| 1337 | if option._maxcount > 1 then | ||
| 1338 | table.insert(line, '"*"') | ||
| 1339 | end | ||
| 1340 | table.insert(line, "{" .. table.concat(option._aliases, ",") .. '}"') | ||
| 1341 | else | ||
| 1342 | table.insert(line, '"') | ||
| 1343 | if option._maxcount > 1 then | ||
| 1344 | table.insert(line, "*") | ||
| 1345 | end | ||
| 1346 | table.insert(line, option._name) | ||
| 1347 | end | ||
| 1348 | if option._description then | ||
| 1349 | local description = get_short_description(option):gsub('["%]:`$]', "\\%0") | ||
| 1350 | table.insert(line, "[" .. description .. "]") | ||
| 1351 | end | ||
| 1352 | if option._maxargs == math.huge then | ||
| 1353 | table.insert(line, ":*") | ||
| 1354 | end | ||
| 1355 | if option._choices then | ||
| 1356 | table.insert(line, ": :(" .. table.concat(option._choices, " ") .. ")") | ||
| 1357 | elseif option._maxargs > 0 then | ||
| 1358 | table.insert(line, ": :_files") | ||
| 1359 | end | ||
| 1360 | table.insert(line, '"') | ||
| 1361 | table.insert(buf, (" "):rep(indent + 2) .. table.concat(line)) | ||
| 1362 | end | ||
| 1363 | |||
| 1364 | table.insert(buf, (" "):rep(indent) .. ")") | ||
| 1365 | table.insert(buf, (" "):rep(indent) .. "_arguments -s -S \\") | ||
| 1366 | table.insert(buf, (" "):rep(indent + 2) .. "$options \\") | ||
| 1367 | |||
| 1368 | if self._is_help_command then | ||
| 1369 | table.insert(buf, (" "):rep(indent + 2) .. '": :(' .. self._parent:_get_commands() .. ')" \\') | ||
| 1370 | else | ||
| 1371 | for _, argument in ipairs(self._arguments) do | ||
| 1372 | local spec | ||
| 1373 | if argument._choices then | ||
| 1374 | spec = ": :(" .. table.concat(argument._choices, " ") .. ")" | ||
| 1375 | else | ||
| 1376 | spec = ": :_files" | ||
| 1377 | end | ||
| 1378 | if argument._maxargs == math.huge then | ||
| 1379 | table.insert(buf, (" "):rep(indent + 2) .. '"*' .. spec .. '" \\') | ||
| 1380 | break | ||
| 1381 | end | ||
| 1382 | for _ = 1, argument._maxargs do | ||
| 1383 | table.insert(buf, (" "):rep(indent + 2) .. '"' .. spec .. '" \\') | ||
| 1384 | end | ||
| 1385 | end | ||
| 1386 | |||
| 1387 | if #self._commands > 0 then | ||
| 1388 | table.insert(buf, (" "):rep(indent + 2) .. '": :_' .. cmd_name .. '_cmds" \\') | ||
| 1389 | table.insert(buf, (" "):rep(indent + 2) .. '"*:: :->args" \\') | ||
| 1390 | end | ||
| 1391 | end | ||
| 1392 | |||
| 1393 | table.insert(buf, (" "):rep(indent + 2) .. "&& return 0") | ||
| 1394 | end | ||
| 1395 | |||
| 1396 | function Parser:_zsh_cmds(buf, cmd_name) | ||
| 1397 | table.insert(buf, "\n_" .. cmd_name .. "_cmds() {") | ||
| 1398 | table.insert(buf, " local -a commands=(") | ||
| 1399 | |||
| 1400 | for _, command in ipairs(self._commands) do | ||
| 1401 | local line = {} | ||
| 1402 | if #command._aliases > 1 then | ||
| 1403 | table.insert(line, "{" .. table.concat(command._aliases, ",") .. '}"') | ||
| 1404 | else | ||
| 1405 | table.insert(line, '"' .. command._name) | ||
| 1406 | end | ||
| 1407 | if command._description then | ||
| 1408 | table.insert(line, ":" .. get_short_description(command):gsub('["`$]', "\\%0")) | ||
| 1409 | end | ||
| 1410 | table.insert(buf, " " .. table.concat(line) .. '"') | ||
| 1411 | end | ||
| 1412 | |||
| 1413 | table.insert(buf, ' )\n _describe "command" commands\n}') | ||
| 1414 | end | ||
| 1415 | |||
| 1416 | function Parser:_zsh_complete_help(buf, cmds_buf, cmd_name, indent) | ||
| 1417 | if #self._commands == 0 then | ||
| 1418 | return | ||
| 1419 | end | ||
| 1420 | |||
| 1421 | self:_zsh_cmds(cmds_buf, cmd_name) | ||
| 1422 | table.insert(buf, "\n" .. (" "):rep(indent) .. "case $words[1] in") | ||
| 1423 | |||
| 1424 | for _, command in ipairs(self._commands) do | ||
| 1425 | local name = cmd_name .. "_" .. command._name | ||
| 1426 | table.insert(buf, (" "):rep(indent + 2) .. table.concat(command._aliases, "|") .. ")") | ||
| 1427 | command:_zsh_arguments(buf, name, indent + 4) | ||
| 1428 | command:_zsh_complete_help(buf, cmds_buf, name, indent + 4) | ||
| 1429 | table.insert(buf, (" "):rep(indent + 4) .. ";;\n") | ||
| 1430 | end | ||
| 1431 | |||
| 1432 | table.insert(buf, (" "):rep(indent) .. "esac") | ||
| 1433 | end | ||
| 1434 | |||
| 1435 | function Parser:get_zsh_complete() | ||
| 1436 | self._basename = base_name(self._name) | ||
| 1437 | assert(self:_is_shell_safe()) | ||
| 1438 | local buf = {("#compdef %s\n"):format(self._basename)} | ||
| 1439 | local cmds_buf = {} | ||
| 1440 | table.insert(buf, "_" .. self._basename .. "() {") | ||
| 1441 | if #self._commands > 0 then | ||
| 1442 | table.insert(buf, " local context state state_descr line") | ||
| 1443 | table.insert(buf, " typeset -A opt_args\n") | ||
| 1444 | end | ||
| 1445 | self:_zsh_arguments(buf, self._basename, 2) | ||
| 1446 | self:_zsh_complete_help(buf, cmds_buf, self._basename, 2) | ||
| 1447 | table.insert(buf, "\n return 1") | ||
| 1448 | table.insert(buf, "}") | ||
| 1449 | |||
| 1450 | local result = table.concat(buf, "\n") | ||
| 1451 | if #cmds_buf > 0 then | ||
| 1452 | result = result .. "\n" .. table.concat(cmds_buf, "\n") | ||
| 1453 | end | ||
| 1454 | return result .. "\n\n_" .. self._basename .. "\n" | ||
| 1455 | end | ||
| 1456 | |||
| 1457 | local function fish_escape(string) | ||
| 1458 | return string:gsub("[\\']", "\\%0") | ||
| 1459 | end | ||
| 1460 | |||
| 1461 | function Parser:_fish_get_cmd(buf, indent) | ||
| 1462 | if #self._commands == 0 then | ||
| 1463 | return | ||
| 1464 | end | ||
| 1465 | |||
| 1466 | table.insert(buf, (" "):rep(indent) .. "set -e cmdline[1]") | ||
| 1467 | table.insert(buf, (" "):rep(indent) .. "for arg in $cmdline") | ||
| 1468 | table.insert(buf, (" "):rep(indent + 4) .. "switch $arg") | ||
| 1469 | |||
| 1470 | for _, command in ipairs(self._commands) do | ||
| 1471 | table.insert(buf, (" "):rep(indent + 8) .. "case " .. table.concat(command._aliases, " ")) | ||
| 1472 | table.insert(buf, (" "):rep(indent + 12) .. "set cmd $cmd " .. command._name) | ||
| 1473 | command:_fish_get_cmd(buf, indent + 12) | ||
| 1474 | table.insert(buf, (" "):rep(indent + 12) .. "break") | ||
| 1475 | end | ||
| 1476 | |||
| 1477 | table.insert(buf, (" "):rep(indent + 4) .. "end") | ||
| 1478 | table.insert(buf, (" "):rep(indent) .. "end") | ||
| 1479 | end | ||
| 1480 | |||
| 1481 | function Parser:_fish_complete_help(buf, basename) | ||
| 1482 | local prefix = "complete -c " .. basename | ||
| 1483 | table.insert(buf, "") | ||
| 1484 | |||
| 1485 | for _, command in ipairs(self._commands) do | ||
| 1486 | local aliases = table.concat(command._aliases, " ") | ||
| 1487 | local line | ||
| 1488 | if self._parent then | ||
| 1489 | line = ("%s -n '__fish_%s_using_command %s' -xa '%s'") | ||
| 1490 | :format(prefix, basename, self:_get_fullname(true), aliases) | ||
| 1491 | else | ||
| 1492 | line = ("%s -n '__fish_%s_using_command' -xa '%s'"):format(prefix, basename, aliases) | ||
| 1493 | end | ||
| 1494 | if command._description then | ||
| 1495 | line = ("%s -d '%s'"):format(line, fish_escape(get_short_description(command))) | ||
| 1496 | end | ||
| 1497 | table.insert(buf, line) | ||
| 1498 | end | ||
| 1499 | |||
| 1500 | if self._is_help_command then | ||
| 1501 | local line = ("%s -n '__fish_%s_using_command %s' -xa '%s'") | ||
| 1502 | :format(prefix, basename, self:_get_fullname(true), self._parent:_get_commands()) | ||
| 1503 | table.insert(buf, line) | ||
| 1504 | end | ||
| 1505 | |||
| 1506 | for _, option in ipairs(self._options) do | ||
| 1507 | local parts = {prefix} | ||
| 1508 | |||
| 1509 | if self._parent then | ||
| 1510 | table.insert(parts, "-n '__fish_" .. basename .. "_seen_command " .. self:_get_fullname(true) .. "'") | ||
| 1511 | end | ||
| 1512 | |||
| 1513 | for _, alias in ipairs(option._aliases) do | ||
| 1514 | if alias:match("^%-.$") then | ||
| 1515 | table.insert(parts, "-s " .. alias:sub(2)) | ||
| 1516 | elseif alias:match("^%-%-.+") then | ||
| 1517 | table.insert(parts, "-l " .. alias:sub(3)) | ||
| 1518 | end | ||
| 1519 | end | ||
| 1520 | |||
| 1521 | if option._choices then | ||
| 1522 | table.insert(parts, "-xa '" .. table.concat(option._choices, " ") .. "'") | ||
| 1523 | elseif option._minargs > 0 then | ||
| 1524 | table.insert(parts, "-r") | ||
| 1525 | end | ||
| 1526 | |||
| 1527 | if option._description then | ||
| 1528 | table.insert(parts, "-d '" .. fish_escape(get_short_description(option)) .. "'") | ||
| 1529 | end | ||
| 1530 | |||
| 1531 | table.insert(buf, table.concat(parts, " ")) | ||
| 1532 | end | ||
| 1533 | |||
| 1534 | for _, command in ipairs(self._commands) do | ||
| 1535 | command:_fish_complete_help(buf, basename) | ||
| 1536 | end | ||
| 1537 | end | ||
| 1538 | |||
| 1539 | function Parser:get_fish_complete() | ||
| 1540 | self._basename = base_name(self._name) | ||
| 1541 | assert(self:_is_shell_safe()) | ||
| 1542 | local buf = {} | ||
| 1543 | |||
| 1544 | if #self._commands > 0 then | ||
| 1545 | table.insert(buf, ([[ | ||
| 1546 | function __fish_%s_print_command | ||
| 1547 | set -l cmdline (commandline -poc) | ||
| 1548 | set -l cmd]]):format(self._basename)) | ||
| 1549 | self:_fish_get_cmd(buf, 4) | ||
| 1550 | table.insert(buf, ([[ | ||
| 1551 | echo "$cmd" | ||
| 1552 | end | ||
| 1553 | |||
| 1554 | function __fish_%s_using_command | ||
| 1555 | test (__fish_%s_print_command) = "$argv" | ||
| 1556 | and return 0 | ||
| 1557 | or return 1 | ||
| 1558 | end | ||
| 1559 | |||
| 1560 | function __fish_%s_seen_command | ||
| 1561 | string match -q "$argv*" (__fish_%s_print_command) | ||
| 1562 | and return 0 | ||
| 1563 | or return 1 | ||
| 1564 | end]]):format(self._basename, self._basename, self._basename, self._basename)) | ||
| 1565 | end | ||
| 1566 | |||
| 1567 | self:_fish_complete_help(buf, self._basename) | ||
| 1568 | return table.concat(buf, "\n") .. "\n" | ||
| 1569 | end | ||
| 1570 | |||
| 1571 | local function get_tip(context, wrong_name) | ||
| 1572 | local context_pool = {} | ||
| 1573 | local possible_name | ||
| 1574 | local possible_names = {} | ||
| 1575 | |||
| 1576 | for name in pairs(context) do | ||
| 1577 | if type(name) == "string" then | ||
| 1578 | for i = 1, #name do | ||
| 1579 | possible_name = name:sub(1, i - 1) .. name:sub(i + 1) | ||
| 1580 | |||
| 1581 | if not context_pool[possible_name] then | ||
| 1582 | context_pool[possible_name] = {} | ||
| 1583 | end | ||
| 1584 | |||
| 1585 | table.insert(context_pool[possible_name], name) | ||
| 1586 | end | ||
| 1587 | end | ||
| 1588 | end | ||
| 1589 | |||
| 1590 | for i = 1, #wrong_name + 1 do | ||
| 1591 | possible_name = wrong_name:sub(1, i - 1) .. wrong_name:sub(i + 1) | ||
| 1592 | |||
| 1593 | if context[possible_name] then | ||
| 1594 | possible_names[possible_name] = true | ||
| 1595 | elseif context_pool[possible_name] then | ||
| 1596 | for _, name in ipairs(context_pool[possible_name]) do | ||
| 1597 | possible_names[name] = true | ||
| 1598 | end | ||
| 1599 | end | ||
| 1600 | end | ||
| 1601 | |||
| 1602 | local first = next(possible_names) | ||
| 1603 | |||
| 1604 | if first then | ||
| 1605 | if next(possible_names, first) then | ||
| 1606 | local possible_names_arr = {} | ||
| 1607 | |||
| 1608 | for name in pairs(possible_names) do | ||
| 1609 | table.insert(possible_names_arr, "'" .. name .. "'") | ||
| 1610 | end | ||
| 1611 | |||
| 1612 | table.sort(possible_names_arr) | ||
| 1613 | return "\nDid you mean one of these: " .. table.concat(possible_names_arr, " ") .. "?" | ||
| 1614 | else | ||
| 1615 | return "\nDid you mean '" .. first .. "'?" | ||
| 1616 | end | ||
| 1617 | else | ||
| 1618 | return "" | ||
| 1619 | end | ||
| 1620 | end | ||
| 1621 | |||
| 1622 | local ElementState = class({ | ||
| 1623 | invocations = 0 | ||
| 1624 | }) | ||
| 1625 | |||
| 1626 | function ElementState:__call(state, element) | ||
| 1627 | self.state = state | ||
| 1628 | self.result = state.result | ||
| 1629 | self.element = element | ||
| 1630 | self.target = element._target or element:_get_default_target() | ||
| 1631 | self.action, self.result[self.target] = element:_get_action() | ||
| 1632 | return self | ||
| 1633 | end | ||
| 1634 | |||
| 1635 | function ElementState:error(fmt, ...) | ||
| 1636 | self.state:error(fmt, ...) | ||
| 1637 | end | ||
| 1638 | |||
| 1639 | function ElementState:convert(argument, index) | ||
| 1640 | local converter = self.element._convert | ||
| 1641 | |||
| 1642 | if converter then | ||
| 1643 | local ok, err | ||
| 1644 | |||
| 1645 | if type(converter) == "function" then | ||
| 1646 | ok, err = converter(argument) | ||
| 1647 | elseif type(converter[index]) == "function" then | ||
| 1648 | ok, err = converter[index](argument) | ||
| 1649 | else | ||
| 1650 | ok = converter[argument] | ||
| 1651 | end | ||
| 1652 | |||
| 1653 | if ok == nil then | ||
| 1654 | self:error(err and "%s" or "malformed argument '%s'", err or argument) | ||
| 1655 | end | ||
| 1656 | |||
| 1657 | argument = ok | ||
| 1658 | end | ||
| 1659 | |||
| 1660 | return argument | ||
| 1661 | end | ||
| 1662 | |||
| 1663 | function ElementState:default(mode) | ||
| 1664 | return self.element._defmode:find(mode) and self.element._default | ||
| 1665 | end | ||
| 1666 | |||
| 1667 | local function bound(noun, min, max, is_max) | ||
| 1668 | local res = "" | ||
| 1669 | |||
| 1670 | if min ~= max then | ||
| 1671 | res = "at " .. (is_max and "most" or "least") .. " " | ||
| 1672 | end | ||
| 1673 | |||
| 1674 | local number = is_max and max or min | ||
| 1675 | return res .. tostring(number) .. " " .. noun .. (number == 1 and "" or "s") | ||
| 1676 | end | ||
| 1677 | |||
| 1678 | function ElementState:set_name(alias) | ||
| 1679 | self.name = ("%s '%s'"):format(alias and "option" or "argument", alias or self.element._name) | ||
| 1680 | end | ||
| 1681 | |||
| 1682 | function ElementState:invoke() | ||
| 1683 | self.open = true | ||
| 1684 | self.overwrite = false | ||
| 1685 | |||
| 1686 | if self.invocations >= self.element._maxcount then | ||
| 1687 | if self.element._overwrite then | ||
| 1688 | self.overwrite = true | ||
| 1689 | else | ||
| 1690 | local num_times_repr = bound("time", self.element._mincount, self.element._maxcount, true) | ||
| 1691 | self:error("%s must be used %s", self.name, num_times_repr) | ||
| 1692 | end | ||
| 1693 | else | ||
| 1694 | self.invocations = self.invocations + 1 | ||
| 1695 | end | ||
| 1696 | |||
| 1697 | self.args = {} | ||
| 1698 | |||
| 1699 | if self.element._maxargs <= 0 then | ||
| 1700 | self:close() | ||
| 1701 | end | ||
| 1702 | |||
| 1703 | return self.open | ||
| 1704 | end | ||
| 1705 | |||
| 1706 | function ElementState:check_choices(argument) | ||
| 1707 | if self.element._choices then | ||
| 1708 | for _, choice in ipairs(self.element._choices) do | ||
| 1709 | if argument == choice then | ||
| 1710 | return | ||
| 1711 | end | ||
| 1712 | end | ||
| 1713 | local choices_list = "'" .. table.concat(self.element._choices, "', '") .. "'" | ||
| 1714 | local is_option = getmetatable(self.element) == Option | ||
| 1715 | self:error("%s%s must be one of %s", is_option and "argument for " or "", self.name, choices_list) | ||
| 1716 | end | ||
| 1717 | end | ||
| 1718 | |||
| 1719 | function ElementState:pass(argument) | ||
| 1720 | self:check_choices(argument) | ||
| 1721 | argument = self:convert(argument, #self.args + 1) | ||
| 1722 | table.insert(self.args, argument) | ||
| 1723 | |||
| 1724 | if #self.args >= self.element._maxargs then | ||
| 1725 | self:close() | ||
| 1726 | end | ||
| 1727 | |||
| 1728 | return self.open | ||
| 1729 | end | ||
| 1730 | |||
| 1731 | function ElementState:complete_invocation() | ||
| 1732 | while #self.args < self.element._minargs do | ||
| 1733 | self:pass(self.element._default) | ||
| 1734 | end | ||
| 1735 | end | ||
| 1736 | |||
| 1737 | function ElementState:close() | ||
| 1738 | if self.open then | ||
| 1739 | self.open = false | ||
| 1740 | |||
| 1741 | if #self.args < self.element._minargs then | ||
| 1742 | if self:default("a") then | ||
| 1743 | self:complete_invocation() | ||
| 1744 | else | ||
| 1745 | if #self.args == 0 then | ||
| 1746 | if getmetatable(self.element) == Argument then | ||
| 1747 | self:error("missing %s", self.name) | ||
| 1748 | elseif self.element._maxargs == 1 then | ||
| 1749 | self:error("%s requires an argument", self.name) | ||
| 1750 | end | ||
| 1751 | end | ||
| 1752 | |||
| 1753 | self:error("%s requires %s", self.name, bound("argument", self.element._minargs, self.element._maxargs)) | ||
| 1754 | end | ||
| 1755 | end | ||
| 1756 | |||
| 1757 | local args | ||
| 1758 | |||
| 1759 | if self.element._maxargs == 0 then | ||
| 1760 | args = self.args[1] | ||
| 1761 | elseif self.element._maxargs == 1 then | ||
| 1762 | if self.element._minargs == 0 and self.element._mincount ~= self.element._maxcount then | ||
| 1763 | args = self.args | ||
| 1764 | else | ||
| 1765 | args = self.args[1] | ||
| 1766 | end | ||
| 1767 | else | ||
| 1768 | args = self.args | ||
| 1769 | end | ||
| 1770 | |||
| 1771 | self.action(self.result, self.target, args, self.overwrite) | ||
| 1772 | end | ||
| 1773 | end | ||
| 1774 | |||
| 1775 | local ParseState = class({ | ||
| 1776 | result = {}, | ||
| 1777 | options = {}, | ||
| 1778 | arguments = {}, | ||
| 1779 | argument_i = 1, | ||
| 1780 | element_to_mutexes = {}, | ||
| 1781 | mutex_to_element_state = {}, | ||
| 1782 | command_actions = {} | ||
| 1783 | }) | ||
| 1784 | |||
| 1785 | function ParseState:__call(parser, error_handler) | ||
| 1786 | self.parser = parser | ||
| 1787 | self.error_handler = error_handler | ||
| 1788 | self.charset = parser:_update_charset() | ||
| 1789 | self:switch(parser) | ||
| 1790 | return self | ||
| 1791 | end | ||
| 1792 | |||
| 1793 | function ParseState:error(fmt, ...) | ||
| 1794 | self.error_handler(self.parser, fmt:format(...)) | ||
| 1795 | end | ||
| 1796 | |||
| 1797 | function ParseState:switch(parser) | ||
| 1798 | self.parser = parser | ||
| 1799 | |||
| 1800 | if parser._action then | ||
| 1801 | table.insert(self.command_actions, {action = parser._action, name = parser._name}) | ||
| 1802 | end | ||
| 1803 | |||
| 1804 | for _, option in ipairs(parser._options) do | ||
| 1805 | option = ElementState(self, option) | ||
| 1806 | table.insert(self.options, option) | ||
| 1807 | |||
| 1808 | for _, alias in ipairs(option.element._aliases) do | ||
| 1809 | self.options[alias] = option | ||
| 1810 | end | ||
| 1811 | end | ||
| 1812 | |||
| 1813 | for _, mutex in ipairs(parser._mutexes) do | ||
| 1814 | for _, element in ipairs(mutex) do | ||
| 1815 | if not self.element_to_mutexes[element] then | ||
| 1816 | self.element_to_mutexes[element] = {} | ||
| 1817 | end | ||
| 1818 | |||
| 1819 | table.insert(self.element_to_mutexes[element], mutex) | ||
| 1820 | end | ||
| 1821 | end | ||
| 1822 | |||
| 1823 | for _, argument in ipairs(parser._arguments) do | ||
| 1824 | argument = ElementState(self, argument) | ||
| 1825 | table.insert(self.arguments, argument) | ||
| 1826 | argument:set_name() | ||
| 1827 | argument:invoke() | ||
| 1828 | end | ||
| 1829 | |||
| 1830 | self.handle_options = parser._handle_options | ||
| 1831 | self.argument = self.arguments[self.argument_i] | ||
| 1832 | self.commands = parser._commands | ||
| 1833 | |||
| 1834 | for _, command in ipairs(self.commands) do | ||
| 1835 | for _, alias in ipairs(command._aliases) do | ||
| 1836 | self.commands[alias] = command | ||
| 1837 | end | ||
| 1838 | end | ||
| 1839 | end | ||
| 1840 | |||
| 1841 | function ParseState:get_option(name) | ||
| 1842 | local option = self.options[name] | ||
| 1843 | |||
| 1844 | if not option then | ||
| 1845 | self:error("unknown option '%s'%s", name, get_tip(self.options, name)) | ||
| 1846 | else | ||
| 1847 | return option | ||
| 1848 | end | ||
| 1849 | end | ||
| 1850 | |||
| 1851 | function ParseState:get_command(name) | ||
| 1852 | local command = self.commands[name] | ||
| 1853 | |||
| 1854 | if not command then | ||
| 1855 | if #self.commands > 0 then | ||
| 1856 | self:error("unknown command '%s'%s", name, get_tip(self.commands, name)) | ||
| 1857 | else | ||
| 1858 | self:error("too many arguments") | ||
| 1859 | end | ||
| 1860 | else | ||
| 1861 | return command | ||
| 1862 | end | ||
| 1863 | end | ||
| 1864 | |||
| 1865 | function ParseState:check_mutexes(element_state) | ||
| 1866 | if self.element_to_mutexes[element_state.element] then | ||
| 1867 | for _, mutex in ipairs(self.element_to_mutexes[element_state.element]) do | ||
| 1868 | local used_element_state = self.mutex_to_element_state[mutex] | ||
| 1869 | |||
| 1870 | if used_element_state and used_element_state ~= element_state then | ||
| 1871 | self:error("%s can not be used together with %s", element_state.name, used_element_state.name) | ||
| 1872 | else | ||
| 1873 | self.mutex_to_element_state[mutex] = element_state | ||
| 1874 | end | ||
| 1875 | end | ||
| 1876 | end | ||
| 1877 | end | ||
| 1878 | |||
| 1879 | function ParseState:invoke(option, name) | ||
| 1880 | self:close() | ||
| 1881 | option:set_name(name) | ||
| 1882 | self:check_mutexes(option, name) | ||
| 1883 | |||
| 1884 | if option:invoke() then | ||
| 1885 | self.option = option | ||
| 1886 | end | ||
| 1887 | end | ||
| 1888 | |||
| 1889 | function ParseState:pass(arg) | ||
| 1890 | if self.option then | ||
| 1891 | if not self.option:pass(arg) then | ||
| 1892 | self.option = nil | ||
| 1893 | end | ||
| 1894 | elseif self.argument then | ||
| 1895 | self:check_mutexes(self.argument) | ||
| 1896 | |||
| 1897 | if not self.argument:pass(arg) then | ||
| 1898 | self.argument_i = self.argument_i + 1 | ||
| 1899 | self.argument = self.arguments[self.argument_i] | ||
| 1900 | end | ||
| 1901 | else | ||
| 1902 | local command = self:get_command(arg) | ||
| 1903 | self.result[command._target or command._name] = true | ||
| 1904 | |||
| 1905 | if self.parser._command_target then | ||
| 1906 | self.result[self.parser._command_target] = command._name | ||
| 1907 | end | ||
| 1908 | |||
| 1909 | self:switch(command) | ||
| 1910 | end | ||
| 1911 | end | ||
| 1912 | |||
| 1913 | function ParseState:close() | ||
| 1914 | if self.option then | ||
| 1915 | self.option:close() | ||
| 1916 | self.option = nil | ||
| 1917 | end | ||
| 1918 | end | ||
| 1919 | |||
| 1920 | function ParseState:finalize() | ||
| 1921 | self:close() | ||
| 1922 | |||
| 1923 | for i = self.argument_i, #self.arguments do | ||
| 1924 | local argument = self.arguments[i] | ||
| 1925 | if #argument.args == 0 and argument:default("u") then | ||
| 1926 | argument:complete_invocation() | ||
| 1927 | else | ||
| 1928 | argument:close() | ||
| 1929 | end | ||
| 1930 | end | ||
| 1931 | |||
| 1932 | if self.parser._require_command and #self.commands > 0 then | ||
| 1933 | self:error("a command is required") | ||
| 1934 | end | ||
| 1935 | |||
| 1936 | for _, option in ipairs(self.options) do | ||
| 1937 | option.name = option.name or ("option '%s'"):format(option.element._name) | ||
| 1938 | |||
| 1939 | if option.invocations == 0 then | ||
| 1940 | if option:default("u") then | ||
| 1941 | option:invoke() | ||
| 1942 | option:complete_invocation() | ||
| 1943 | option:close() | ||
| 1944 | end | ||
| 1945 | end | ||
| 1946 | |||
| 1947 | local mincount = option.element._mincount | ||
| 1948 | |||
| 1949 | if option.invocations < mincount then | ||
| 1950 | if option:default("a") then | ||
| 1951 | while option.invocations < mincount do | ||
| 1952 | option:invoke() | ||
| 1953 | option:close() | ||
| 1954 | end | ||
| 1955 | elseif option.invocations == 0 then | ||
| 1956 | self:error("missing %s", option.name) | ||
| 1957 | else | ||
| 1958 | self:error("%s must be used %s", option.name, bound("time", mincount, option.element._maxcount)) | ||
| 1959 | end | ||
| 1960 | end | ||
| 1961 | end | ||
| 1962 | |||
| 1963 | for i = #self.command_actions, 1, -1 do | ||
| 1964 | self.command_actions[i].action(self.result, self.command_actions[i].name) | ||
| 1965 | end | ||
| 1966 | end | ||
| 1967 | |||
| 1968 | function ParseState:parse(args) | ||
| 1969 | for _, arg in ipairs(args) do | ||
| 1970 | local plain = true | ||
| 1971 | |||
| 1972 | if self.handle_options then | ||
| 1973 | local first = arg:sub(1, 1) | ||
| 1974 | |||
| 1975 | if self.charset[first] then | ||
| 1976 | if #arg > 1 then | ||
| 1977 | plain = false | ||
| 1978 | |||
| 1979 | if arg:sub(2, 2) == first then | ||
| 1980 | if #arg == 2 then | ||
| 1981 | if self.options[arg] then | ||
| 1982 | local option = self:get_option(arg) | ||
| 1983 | self:invoke(option, arg) | ||
| 1984 | else | ||
| 1985 | self:close() | ||
| 1986 | end | ||
| 1987 | |||
| 1988 | self.handle_options = false | ||
| 1989 | else | ||
| 1990 | local equals = arg:find "=" | ||
| 1991 | if equals then | ||
| 1992 | local name = arg:sub(1, equals - 1) | ||
| 1993 | local option = self:get_option(name) | ||
| 1994 | |||
| 1995 | if option.element._maxargs <= 0 then | ||
| 1996 | self:error("option '%s' does not take arguments", name) | ||
| 1997 | end | ||
| 1998 | |||
| 1999 | self:invoke(option, name) | ||
| 2000 | self:pass(arg:sub(equals + 1)) | ||
| 2001 | else | ||
| 2002 | local option = self:get_option(arg) | ||
| 2003 | self:invoke(option, arg) | ||
| 2004 | end | ||
| 2005 | end | ||
| 2006 | else | ||
| 2007 | for i = 2, #arg do | ||
| 2008 | local name = first .. arg:sub(i, i) | ||
| 2009 | local option = self:get_option(name) | ||
| 2010 | self:invoke(option, name) | ||
| 2011 | |||
| 2012 | if i ~= #arg and option.element._maxargs > 0 then | ||
| 2013 | self:pass(arg:sub(i + 1)) | ||
| 2014 | break | ||
| 2015 | end | ||
| 2016 | end | ||
| 2017 | end | ||
| 2018 | end | ||
| 2019 | end | ||
| 2020 | end | ||
| 2021 | |||
| 2022 | if plain then | ||
| 2023 | self:pass(arg) | ||
| 2024 | end | ||
| 2025 | end | ||
| 2026 | |||
| 2027 | self:finalize() | ||
| 2028 | return self.result | ||
| 2029 | end | ||
| 2030 | |||
| 2031 | function Parser:error(msg) | ||
| 2032 | io.stderr:write(("%s\n\nError: %s\n"):format(self:get_usage(), msg)) | ||
| 2033 | os.exit(1) | ||
| 2034 | end | ||
| 2035 | |||
| 2036 | -- Compatibility with strict.lua and other checkers: | ||
| 2037 | local default_cmdline = rawget(_G, "arg") or {} | ||
| 2038 | |||
| 2039 | function Parser:_parse(args, error_handler) | ||
| 2040 | return ParseState(self, error_handler):parse(args or default_cmdline) | ||
| 2041 | end | ||
| 2042 | |||
| 2043 | function Parser:parse(args) | ||
| 2044 | return self:_parse(args, self.error) | ||
| 2045 | end | ||
| 2046 | |||
| 2047 | local function xpcall_error_handler(err) | ||
| 2048 | return tostring(err) .. "\noriginal " .. debug.traceback("", 2):sub(2) | ||
| 2049 | end | ||
| 2050 | |||
| 2051 | function Parser:pparse(args) | ||
| 2052 | local parse_error | ||
| 2053 | |||
| 2054 | local ok, result = xpcall(function() | ||
| 2055 | return self:_parse(args, function(_, err) | ||
| 2056 | parse_error = err | ||
| 2057 | error(err, 0) | ||
| 2058 | end) | ||
| 2059 | end, xpcall_error_handler) | ||
| 2060 | |||
| 2061 | if ok then | ||
| 2062 | return true, result | ||
| 2063 | elseif not parse_error then | ||
| 2064 | error(result, 0) | ||
| 2065 | else | ||
| 2066 | return false, parse_error | ||
| 2067 | end | ||
| 2068 | end | ||
| 2069 | |||
| 2070 | local argparse = {} | ||
| 2071 | |||
| 2072 | argparse.version = "0.7.0" | ||
| 2073 | |||
| 2074 | setmetatable(argparse, {__call = function(_, ...) | ||
| 2075 | return Parser(default_cmdline[0]):add_help(true)(...) | ||
| 2076 | end}) | ||
| 2077 | |||
| 2078 | return argparse | ||
diff --git a/src/luarocks/cmd.lua b/src/luarocks/cmd.lua index 1ead6c4b..f424f488 100644 --- a/src/luarocks/cmd.lua +++ b/src/luarocks/cmd.lua | |||
| @@ -2,16 +2,14 @@ | |||
| 2 | --- Functions for command-line scripts. | 2 | --- Functions for command-line scripts. |
| 3 | local cmd = {} | 3 | local cmd = {} |
| 4 | 4 | ||
| 5 | local unpack = unpack or table.unpack | ||
| 6 | |||
| 7 | local loader = require("luarocks.loader") | 5 | local loader = require("luarocks.loader") |
| 8 | local util = require("luarocks.util") | 6 | local util = require("luarocks.util") |
| 9 | local path = require("luarocks.path") | 7 | local path = require("luarocks.path") |
| 10 | local deps = require("luarocks.deps") | ||
| 11 | local cfg = require("luarocks.core.cfg") | 8 | local cfg = require("luarocks.core.cfg") |
| 12 | local dir = require("luarocks.dir") | 9 | local dir = require("luarocks.dir") |
| 13 | local fun = require("luarocks.fun") | 10 | local fun = require("luarocks.fun") |
| 14 | local fs = require("luarocks.fs") | 11 | local fs = require("luarocks.fs") |
| 12 | local argparse = require("luarocks.argparse") | ||
| 15 | 13 | ||
| 16 | local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded") | 14 | local hc_ok, hardcoded = pcall(require, "luarocks.core.hardcoded") |
| 17 | if not hc_ok then | 15 | if not hc_ok then |
| @@ -41,11 +39,11 @@ local function check_popen() | |||
| 41 | end | 39 | end |
| 42 | end | 40 | end |
| 43 | 41 | ||
| 44 | local process_tree_flags | 42 | local process_tree_args |
| 45 | do | 43 | do |
| 46 | local function replace_tree(flags, root, tree) | 44 | local function replace_tree(args, root, tree) |
| 47 | root = dir.normalize(root) | 45 | root = dir.normalize(root) |
| 48 | flags["tree"] = root | 46 | args.tree = root |
| 49 | path.use_tree(tree or root) | 47 | path.use_tree(tree or root) |
| 50 | end | 48 | end |
| 51 | 49 | ||
| @@ -61,44 +59,44 @@ do | |||
| 61 | cfg.deploy_lib_dir = cfg.deploy_lib_dir:gsub("/+$", "") | 59 | cfg.deploy_lib_dir = cfg.deploy_lib_dir:gsub("/+$", "") |
| 62 | end | 60 | end |
| 63 | 61 | ||
| 64 | process_tree_flags = function(flags, project_dir) | 62 | process_tree_args = function(args, project_dir) |
| 65 | 63 | ||
| 66 | if flags["global"] then | 64 | if args.global then |
| 67 | cfg.local_by_default = false | 65 | cfg.local_by_default = false |
| 68 | end | 66 | end |
| 69 | 67 | ||
| 70 | if flags["tree"] then | 68 | if args.tree then |
| 71 | local named = false | 69 | local named = false |
| 72 | for _, tree in ipairs(cfg.rocks_trees) do | 70 | for _, tree in ipairs(cfg.rocks_trees) do |
| 73 | if type(tree) == "table" and flags["tree"] == tree.name then | 71 | if type(tree) == "table" and args.tree == tree.name then |
| 74 | if not tree.root then | 72 | if not tree.root then |
| 75 | return nil, "Configuration error: tree '"..tree.name.."' has no 'root' field." | 73 | return nil, "Configuration error: tree '"..tree.name.."' has no 'root' field." |
| 76 | end | 74 | end |
| 77 | replace_tree(flags, tree.root, tree) | 75 | replace_tree(args, tree.root, tree) |
| 78 | named = true | 76 | named = true |
| 79 | break | 77 | break |
| 80 | end | 78 | end |
| 81 | end | 79 | end |
| 82 | if not named then | 80 | if not named then |
| 83 | local root_dir = fs.absolute_name(flags["tree"]) | 81 | local root_dir = fs.absolute_name(args.tree) |
| 84 | replace_tree(flags, root_dir) | 82 | replace_tree(args, root_dir) |
| 85 | end | 83 | end |
| 86 | elseif flags["local"] then | 84 | elseif args["local"] then |
| 87 | if not cfg.home_tree then | 85 | if not cfg.home_tree then |
| 88 | return nil, "The --local flag is meant for operating in a user's home directory.\n".. | 86 | return nil, "The --local flag is meant for operating in a user's home directory.\n".. |
| 89 | "You are running as a superuser, which is intended for system-wide operation.\n".. | 87 | "You are running as a superuser, which is intended for system-wide operation.\n".. |
| 90 | "To force using the superuser's home, use --tree explicitly." | 88 | "To force using the superuser's home, use --tree explicitly." |
| 91 | else | 89 | else |
| 92 | replace_tree(flags, cfg.home_tree) | 90 | replace_tree(args, cfg.home_tree) |
| 93 | end | 91 | end |
| 94 | elseif flags["project-tree"] then | 92 | elseif args.project_tree then |
| 95 | local tree = flags["project-tree"] | 93 | local tree = args.project_tree |
| 96 | table.insert(cfg.rocks_trees, 1, { name = "project", root = tree } ) | 94 | table.insert(cfg.rocks_trees, 1, { name = "project", root = tree } ) |
| 97 | loader.load_rocks_trees() | 95 | loader.load_rocks_trees() |
| 98 | path.use_tree(tree) | 96 | path.use_tree(tree) |
| 99 | elseif cfg.local_by_default then | 97 | elseif cfg.local_by_default then |
| 100 | if cfg.home_tree then | 98 | if cfg.home_tree then |
| 101 | replace_tree(flags, cfg.home_tree) | 99 | replace_tree(args, cfg.home_tree) |
| 102 | end | 100 | end |
| 103 | elseif project_dir then | 101 | elseif project_dir then |
| 104 | local project_tree = project_dir .. "/lua_modules" | 102 | local project_tree = project_dir .. "/lua_modules" |
| @@ -119,26 +117,26 @@ do | |||
| 119 | end | 117 | end |
| 120 | end | 118 | end |
| 121 | 119 | ||
| 122 | local function process_server_flags(flags) | 120 | local function process_server_args(args) |
| 123 | if flags["server"] then | 121 | if args.server then |
| 124 | local protocol, pathname = dir.split_url(flags["server"]) | 122 | local protocol, pathname = dir.split_url(args.server) |
| 125 | table.insert(cfg.rocks_servers, 1, protocol.."://"..pathname) | 123 | table.insert(cfg.rocks_servers, 1, protocol.."://"..pathname) |
| 126 | end | 124 | end |
| 127 | 125 | ||
| 128 | if flags["dev"] then | 126 | if args.dev then |
| 129 | local append_dev = function(s) return dir.path(s, "dev") end | 127 | local append_dev = function(s) return dir.path(s, "dev") end |
| 130 | local dev_servers = fun.traverse(cfg.rocks_servers, append_dev) | 128 | local dev_servers = fun.traverse(cfg.rocks_servers, append_dev) |
| 131 | cfg.rocks_servers = fun.concat(dev_servers, cfg.rocks_servers) | 129 | cfg.rocks_servers = fun.concat(dev_servers, cfg.rocks_servers) |
| 132 | end | 130 | end |
| 133 | 131 | ||
| 134 | if flags["only-server"] then | 132 | if args.only_server then |
| 135 | if flags["dev"] then | 133 | if args.dev then |
| 136 | return nil, "--only-server cannot be used with --dev" | 134 | return nil, "--only-server cannot be used with --dev" |
| 137 | end | 135 | end |
| 138 | if flags["server"] then | 136 | if args.server then |
| 139 | return nil, "--only-server cannot be used with --server" | 137 | return nil, "--only-server cannot be used with --server" |
| 140 | end | 138 | end |
| 141 | cfg.rocks_servers = { flags["only-server"] } | 139 | cfg.rocks_servers = { args.only_server } |
| 142 | end | 140 | end |
| 143 | 141 | ||
| 144 | return true | 142 | return true |
| @@ -174,7 +172,7 @@ end | |||
| 174 | 172 | ||
| 175 | local init_config | 173 | local init_config |
| 176 | do | 174 | do |
| 177 | local detect_config_via_flags | 175 | local detect_config_via_args |
| 178 | do | 176 | do |
| 179 | local function find_project_dir(project_tree) | 177 | local function find_project_dir(project_tree) |
| 180 | if project_tree then | 178 | if project_tree then |
| @@ -193,7 +191,7 @@ do | |||
| 193 | return nil | 191 | return nil |
| 194 | end | 192 | end |
| 195 | 193 | ||
| 196 | local function find_default_lua_version(flags, project_dir) | 194 | local function find_default_lua_version(args, project_dir) |
| 197 | if hardcoded.FORCE_CONFIG then | 195 | if hardcoded.FORCE_CONFIG then |
| 198 | return nil | 196 | return nil |
| 199 | end | 197 | end |
| @@ -212,7 +210,7 @@ do | |||
| 212 | if mod then | 210 | if mod then |
| 213 | local pok, ver = pcall(mod) | 211 | local pok, ver = pcall(mod) |
| 214 | if pok and type(ver) == "string" and ver:match("%d+.%d+") then | 212 | if pok and type(ver) == "string" and ver:match("%d+.%d+") then |
| 215 | if flags["verbose"] then | 213 | if args.verbose then |
| 216 | util.printout("Defaulting to Lua " .. ver .. " based on " .. f .. " ...") | 214 | util.printout("Defaulting to Lua " .. ver .. " based on " .. f .. " ...") |
| 217 | end | 215 | end |
| 218 | return ver | 216 | return ver |
| @@ -230,13 +228,13 @@ do | |||
| 230 | end) | 228 | end) |
| 231 | end | 229 | end |
| 232 | 230 | ||
| 233 | local function detect_lua_via_flags(flags, project_dir) | 231 | local function detect_lua_via_args(args, project_dir) |
| 234 | local lua_version = flags["lua-version"] | 232 | local lua_version = args.lua_version |
| 235 | or find_default_lua_version(flags, project_dir) | 233 | or find_default_lua_version(args, project_dir) |
| 236 | or (project_dir and find_version_from_config(project_dir)) | 234 | or (project_dir and find_version_from_config(project_dir)) |
| 237 | 235 | ||
| 238 | if flags["lua-dir"] then | 236 | if args.lua_dir then |
| 239 | local detected, err = util.find_lua(flags["lua-dir"], lua_version) | 237 | local detected, err = util.find_lua(args.lua_dir, lua_version) |
| 240 | if not detected then | 238 | if not detected then |
| 241 | die(err) | 239 | die(err) |
| 242 | end | 240 | end |
| @@ -264,14 +262,14 @@ do | |||
| 264 | return {} | 262 | return {} |
| 265 | end | 263 | end |
| 266 | 264 | ||
| 267 | detect_config_via_flags = function(flags) | 265 | detect_config_via_args = function(args) |
| 268 | local project_dir, given = find_project_dir(flags["project-tree"]) | 266 | local project_dir, given = find_project_dir(args.project_tree) |
| 269 | local detected = detect_lua_via_flags(flags, project_dir) | 267 | local detected = detect_lua_via_args(args, project_dir) |
| 270 | if flags["lua-version"] then | 268 | if args.lua_version then |
| 271 | detected.given_lua_version = flags["lua-version"] | 269 | detected.given_lua_version = args.lua_version |
| 272 | end | 270 | end |
| 273 | if flags["lua-dir"] then | 271 | if args.lua_dir then |
| 274 | detected.given_lua_dir = flags["lua-dir"] | 272 | detected.given_lua_dir = args.lua_dir |
| 275 | end | 273 | end |
| 276 | if given then | 274 | if given then |
| 277 | detected.given_project_dir = project_dir | 275 | detected.given_project_dir = project_dir |
| @@ -281,8 +279,8 @@ do | |||
| 281 | end | 279 | end |
| 282 | end | 280 | end |
| 283 | 281 | ||
| 284 | init_config = function(flags) | 282 | init_config = function(args) |
| 285 | local detected = detect_config_via_flags(flags) | 283 | local detected = detect_config_via_args(args) |
| 286 | 284 | ||
| 287 | -- FIXME A quick hack for the experimental Windows build | 285 | -- FIXME A quick hack for the experimental Windows build |
| 288 | if os.getenv("LUAROCKS_CROSS_COMPILING") then | 286 | if os.getenv("LUAROCKS_CROSS_COMPILING") then |
| @@ -306,6 +304,135 @@ do | |||
| 306 | end | 304 | end |
| 307 | end | 305 | end |
| 308 | 306 | ||
| 307 | local variables_help = [[ | ||
| 308 | Variables: | ||
| 309 | Variables from the "variables" table of the configuration file can be | ||
| 310 | overridden with VAR=VALUE assignments. | ||
| 311 | |||
| 312 | ]] | ||
| 313 | |||
| 314 | local function get_status(status) | ||
| 315 | return status and "ok" or "not found" | ||
| 316 | end | ||
| 317 | |||
| 318 | local function get_config_text(cfg) | ||
| 319 | local buf = "Configuration:\n Lua version: "..cfg.lua_version.."\n" | ||
| 320 | if cfg.luajit_version then | ||
| 321 | buf = buf.." LuaJIT version: "..cfg.luajit_version.."\n" | ||
| 322 | end | ||
| 323 | buf = buf.."\n Configuration files:\n" | ||
| 324 | local conf = cfg.config_files | ||
| 325 | buf = buf.." System : "..fs.absolute_name(conf.system.file).." ("..get_status(conf.system.found)..")\n" | ||
| 326 | if conf.user.file then | ||
| 327 | buf = buf.." User : "..fs.absolute_name(conf.user.file).." ("..get_status(conf.user.found)..")\n" | ||
| 328 | else | ||
| 329 | buf = buf.." User : disabled in this LuaRocks installation.\n" | ||
| 330 | end | ||
| 331 | if conf.project then | ||
| 332 | buf = buf.." Project : "..fs.absolute_name(conf.project.file).." ("..get_status(conf.project.found)..")\n" | ||
| 333 | end | ||
| 334 | buf = buf.."\n Rocks trees in use: \n" | ||
| 335 | for _, tree in ipairs(cfg.rocks_trees) do | ||
| 336 | if type(tree) == "string" then | ||
| 337 | buf = buf.." "..fs.absolute_name(tree) | ||
| 338 | else | ||
| 339 | local name = tree.name and " (\""..tree.name.."\")" or "" | ||
| 340 | buf = buf.." "..fs.absolute_name(tree.root)..name | ||
| 341 | end | ||
| 342 | end | ||
| 343 | |||
| 344 | return buf.."\n" | ||
| 345 | end | ||
| 346 | |||
| 347 | local function get_parser(description, cmd_modules) | ||
| 348 | local basename = dir.base_name(program) | ||
| 349 | local parser = argparse( | ||
| 350 | basename, "LuaRocks "..cfg.program_version..", the Lua package manager\n\n".. | ||
| 351 | program.." - "..description, variables_help.."Run '"..basename.. | ||
| 352 | "' without any arguments to see the configuration.") | ||
| 353 | :help_max_width(80) | ||
| 354 | :add_help_command() | ||
| 355 | :add_complete_command({ | ||
| 356 | help_max_width = 100, | ||
| 357 | summary = "Output a shell completion script.", | ||
| 358 | description = [[ | ||
| 359 | Output a shell completion script. | ||
| 360 | |||
| 361 | Enabling completions for Bash: | ||
| 362 | |||
| 363 | Add the following line to your ~/.bashrc: | ||
| 364 | source <(]]..basename..[[ completion bash) | ||
| 365 | or save the completion script to the local completion directory: | ||
| 366 | ]]..basename..[[ completion bash > ~/.local/share/bash-completion/completions/]]..basename..[[ | ||
| 367 | |||
| 368 | |||
| 369 | Enabling completions for Zsh: | ||
| 370 | |||
| 371 | Save the completion script to a file in your $fpath. | ||
| 372 | You can add a new directory to your $fpath by adding e.g. | ||
| 373 | fpath=(~/.zfunc $fpath) | ||
| 374 | to your ~/.zshrc. | ||
| 375 | Then run: | ||
| 376 | ]]..basename..[[ completion zsh > ~/.zfunc/_]]..basename..[[ | ||
| 377 | |||
| 378 | |||
| 379 | Enabling completion for Fish: | ||
| 380 | |||
| 381 | Add the following line to your ~/.config/fish/config.fish: | ||
| 382 | ]]..basename..[[ completion fish | source | ||
| 383 | or save the completion script to the local completion directory: | ||
| 384 | ]]..basename..[[ completion fish > ~/.config/fish/completions/]]..basename..[[.fish | ||
| 385 | ]]}) | ||
| 386 | :command_target("command") | ||
| 387 | :require_command(false) | ||
| 388 | |||
| 389 | parser:flag("--version", "Show version info and exit.") | ||
| 390 | :action(function() | ||
| 391 | util.printout(program.." "..cfg.program_version) | ||
| 392 | util.printout(description) | ||
| 393 | util.printout() | ||
| 394 | os.exit(cmd.errorcodes.OK) | ||
| 395 | end) | ||
| 396 | parser:flag("--dev", "Enable the sub-repositories in rocks servers for ".. | ||
| 397 | "rockspecs of in-development versions.") | ||
| 398 | parser:option("--server", "Fetch rocks/rockspecs from this server ".. | ||
| 399 | "(takes priority over config file).") | ||
| 400 | parser:option("--only-server", "Fetch rocks/rockspecs from this server only ".. | ||
| 401 | "(overrides any entries in the config file).") | ||
| 402 | :argname("<server>") | ||
| 403 | parser:option("--only-sources", "Restrict downloads to paths matching the given URL.") | ||
| 404 | :argname("<url>") | ||
| 405 | parser:option("--namespace", "Specify the rocks server namespace to use.") | ||
| 406 | parser:option("--lua-dir", "Which Lua installation to use.") | ||
| 407 | :argname("<prefix>") | ||
| 408 | parser:option("--lua-version", "Which Lua version to use.") | ||
| 409 | :argname("<ver>") | ||
| 410 | parser:option("--tree", "Which tree to operate on.") | ||
| 411 | parser:flag("--local", "Use the tree in the user's home directory.\n".. | ||
| 412 | "To enable it, see '"..program.." help path'.") | ||
| 413 | parser:flag("--global", "Use the system tree when `local_by_default` is `true`.") | ||
| 414 | parser:flag("--verbose", "Display verbose output of commands executed.") | ||
| 415 | parser:option("--timeout", "Timeout on network operations, in seconds.\n".. | ||
| 416 | "0 means no timeout (wait forever). Default is ".. | ||
| 417 | tostring(cfg.connection_timeout)..".") | ||
| 418 | :argname("<seconds>") | ||
| 419 | :convert(tonumber) | ||
| 420 | |||
| 421 | -- Used internally to force the use of a particular project tree | ||
| 422 | parser:option("--project-tree"):hidden(true) | ||
| 423 | -- Compatibility for old names of some options | ||
| 424 | parser:option("--to"):target("tree"):hidden(true) | ||
| 425 | parser:option("--from"):target("server"):hidden(true) | ||
| 426 | parser:option("--only-from"):target("only_server"):hidden(true) | ||
| 427 | parser:option("--only-sources-from"):target("only_sources"):hidden(true) | ||
| 428 | |||
| 429 | for _, module in util.sortedpairs(cmd_modules) do | ||
| 430 | module.add_to_parser(parser) | ||
| 431 | end | ||
| 432 | |||
| 433 | return parser | ||
| 434 | end | ||
| 435 | |||
| 309 | --- Main command-line processor. | 436 | --- Main command-line processor. |
| 310 | -- Parses input arguments and calls the appropriate driver function | 437 | -- Parses input arguments and calls the appropriate driver function |
| 311 | -- to execute the action requested on the command-line, forwarding | 438 | -- to execute the action requested on the command-line, forwarding |
| @@ -318,7 +445,20 @@ function cmd.run_command(description, commands, external_namespace, ...) | |||
| 318 | 445 | ||
| 319 | check_popen() | 446 | check_popen() |
| 320 | 447 | ||
| 321 | local function process_arguments(...) | 448 | fs.init() |
| 449 | |||
| 450 | for _, module_name in ipairs(fs.modules(external_namespace)) do | ||
| 451 | if not commands[module_name] then | ||
| 452 | commands[module_name] = external_namespace.."."..module_name | ||
| 453 | end | ||
| 454 | end | ||
| 455 | |||
| 456 | local cmd_modules = {} | ||
| 457 | for name, module in pairs(commands) do | ||
| 458 | cmd_modules[name] = require(module) | ||
| 459 | end | ||
| 460 | |||
| 461 | local function process_cmdline_vars(...) | ||
| 322 | local args = {...} | 462 | local args = {...} |
| 323 | local cmdline_vars = {} | 463 | local cmdline_vars = {} |
| 324 | local last = #args | 464 | local last = #args |
| @@ -340,69 +480,38 @@ function cmd.run_command(description, commands, external_namespace, ...) | |||
| 340 | end | 480 | end |
| 341 | end | 481 | end |
| 342 | end | 482 | end |
| 343 | local nonflags = { util.parse_flags(unpack(args)) } | ||
| 344 | local flags = table.remove(nonflags, 1) | ||
| 345 | if flags.ERROR then | ||
| 346 | die(flags.ERROR.." See --help.") | ||
| 347 | end | ||
| 348 | 483 | ||
| 349 | -- Compatibility for old names of some flags | 484 | return args, cmdline_vars |
| 350 | if flags["to"] then flags["tree"] = flags["to"] end | ||
| 351 | if flags["from"] then flags["server"] = flags["from"] end | ||
| 352 | if flags["nodeps"] then flags["deps-mode"] = "none" end | ||
| 353 | if flags["only-from"] then flags["only-server"] = flags["only-from"] end | ||
| 354 | if flags["only-sources-from"] then flags["only-sources"] = flags["only-sources-from"] end | ||
| 355 | |||
| 356 | return flags, nonflags, cmdline_vars | ||
| 357 | end | 485 | end |
| 358 | 486 | ||
| 359 | local flags, nonflags, cmdline_vars = process_arguments(...) | 487 | local args, cmdline_vars = process_cmdline_vars(...) |
| 488 | local parser = get_parser(description, cmd_modules) | ||
| 489 | args = parser:parse(args) | ||
| 360 | 490 | ||
| 361 | if flags["timeout"] then -- setting it in the config file will kick-in earlier in the process | 491 | -- Compatibility for old flag |
| 362 | local timeout = tonumber(flags["timeout"]) | 492 | if args.nodeps then |
| 363 | if timeout then | 493 | args.deps_mode = "none" |
| 364 | cfg.connection_timeout = timeout | ||
| 365 | else | ||
| 366 | die "Argument error: --timeout expects a numeric argument." | ||
| 367 | end | ||
| 368 | end | 494 | end |
| 369 | 495 | ||
| 370 | local command | 496 | if args.timeout then -- setting it in the config file will kick-in earlier in the process |
| 371 | if flags["help"] or #nonflags == 0 then | 497 | cfg.connection_timeout = args.timeout |
| 372 | command = "help" | ||
| 373 | else | ||
| 374 | command = table.remove(nonflags, 1) | ||
| 375 | end | 498 | end |
| 376 | command = command:gsub("-", "_") | ||
| 377 | 499 | ||
| 378 | if command == "config" then | 500 | if args.command == "config" then |
| 379 | if nonflags[1] == "lua_version" and nonflags[2] then | 501 | if args.key == "lua_version" and args.value then |
| 380 | flags["lua-version"] = nonflags[2] | 502 | args.lua_version = args.value |
| 381 | elseif nonflags[1] == "lua_dir" and nonflags[2] then | 503 | elseif args.key == "lua_dir" and args.value then |
| 382 | flags["lua-dir"] = nonflags[2] | 504 | args.lua_dir = args.value |
| 383 | end | 505 | end |
| 384 | end | 506 | end |
| 385 | 507 | ||
| 386 | if flags["deps-mode"] and not deps.check_deps_mode_flag(flags["deps-mode"]) then | ||
| 387 | die("Invalid entry for --deps-mode.") | ||
| 388 | end | ||
| 389 | |||
| 390 | ----------------------------------------------------------------------------- | 508 | ----------------------------------------------------------------------------- |
| 391 | local lua_found, err = init_config(flags) | 509 | local lua_found, err = init_config(args) |
| 392 | if err then | 510 | if err then |
| 393 | die(err) | 511 | die(err) |
| 394 | end | 512 | end |
| 395 | ----------------------------------------------------------------------------- | 513 | ----------------------------------------------------------------------------- |
| 396 | 514 | ||
| 397 | if flags["version"] then | ||
| 398 | util.printout(program.." "..cfg.program_version) | ||
| 399 | util.printout(description) | ||
| 400 | util.printout() | ||
| 401 | os.exit(cmd.errorcodes.OK) | ||
| 402 | end | ||
| 403 | |||
| 404 | fs.init() | ||
| 405 | |||
| 406 | -- if the Lua interpreter wasn't explicitly found before cfg.init, | 515 | -- if the Lua interpreter wasn't explicitly found before cfg.init, |
| 407 | -- try again now. | 516 | -- try again now. |
| 408 | if not lua_found then | 517 | if not lua_found then |
| @@ -414,7 +523,7 @@ function cmd.run_command(description, commands, external_namespace, ...) | |||
| 414 | if not lua_found then | 523 | if not lua_found then |
| 415 | util.warning("Could not find a Lua " .. cfg.lua_version .. " interpreter in your PATH. " .. | 524 | util.warning("Could not find a Lua " .. cfg.lua_version .. " interpreter in your PATH. " .. |
| 416 | "Modules may not install with the correct configurations. " .. | 525 | "Modules may not install with the correct configurations. " .. |
| 417 | "You may want to specify to the path prefix to your build " .. | 526 | "You may want to specify the path prefix to your build " .. |
| 418 | "of Lua " .. cfg.lua_version .. " using --lua-dir") | 527 | "of Lua " .. cfg.lua_version .. " using --lua-dir") |
| 419 | end | 528 | end |
| 420 | cfg.lua_found = lua_found | 529 | cfg.lua_found = lua_found |
| @@ -423,13 +532,7 @@ function cmd.run_command(description, commands, external_namespace, ...) | |||
| 423 | cfg.project_dir = fs.absolute_name(cfg.project_dir) | 532 | cfg.project_dir = fs.absolute_name(cfg.project_dir) |
| 424 | end | 533 | end |
| 425 | 534 | ||
| 426 | for _, module_name in ipairs(fs.modules(external_namespace)) do | 535 | if args.verbose then |
| 427 | if not commands[module_name] then | ||
| 428 | commands[module_name] = external_namespace.."."..module_name | ||
| 429 | end | ||
| 430 | end | ||
| 431 | |||
| 432 | if flags["verbose"] then | ||
| 433 | cfg.verbose = true | 536 | cfg.verbose = true |
| 434 | fs.verbose() | 537 | fs.verbose() |
| 435 | end | 538 | end |
| @@ -438,24 +541,22 @@ function cmd.run_command(description, commands, external_namespace, ...) | |||
| 438 | die("Current directory does not exist. Please run LuaRocks from an existing directory.") | 541 | die("Current directory does not exist. Please run LuaRocks from an existing directory.") |
| 439 | end | 542 | end |
| 440 | 543 | ||
| 441 | ok, err = process_tree_flags(flags, cfg.project_dir) | 544 | local ok, err = process_tree_args(args, cfg.project_dir) |
| 442 | if not ok then | 545 | if not ok then |
| 443 | die(err) | 546 | die(err) |
| 444 | end | 547 | end |
| 445 | 548 | ||
| 446 | ok, err = process_server_flags(flags) | 549 | ok, err = process_server_args(args) |
| 447 | if not ok then | 550 | if not ok then |
| 448 | die(err) | 551 | die(err) |
| 449 | end | 552 | end |
| 450 | 553 | ||
| 451 | if flags["only-sources"] then | 554 | if args.only_sources then |
| 452 | cfg.only_sources_from = flags["only-sources"] | 555 | cfg.only_sources_from = args.only_sources |
| 453 | end | 556 | end |
| 454 | 557 | ||
| 455 | if command ~= "help" then | 558 | for k, v in pairs(cmdline_vars) do |
| 456 | for k, v in pairs(cmdline_vars) do | 559 | cfg.variables[k] = v |
| 457 | cfg.variables[k] = v | ||
| 458 | end | ||
| 459 | end | 560 | end |
| 460 | 561 | ||
| 461 | -- if running as superuser, use system cache dir | 562 | -- if running as superuser, use system cache dir |
| @@ -463,22 +564,23 @@ function cmd.run_command(description, commands, external_namespace, ...) | |||
| 463 | cfg.local_cache = dir.path(fs.system_cache_dir(), "luarocks") | 564 | cfg.local_cache = dir.path(fs.system_cache_dir(), "luarocks") |
| 464 | end | 565 | end |
| 465 | 566 | ||
| 466 | if commands[command] then | 567 | if not args.command then |
| 467 | local cmd_mod = require(commands[command]) | 568 | parser:epilog(variables_help..get_config_text(cfg)) |
| 468 | local call_ok, ok, err, exitcode = xpcall(function() | 569 | util.printout() |
| 469 | if command == "help" then | 570 | util.printout(parser:get_help()) |
| 470 | return cmd_mod.command(description, commands, unpack(nonflags)) | 571 | util.printout() |
| 471 | else | 572 | os.exit(cmd.errorcodes.OK) |
| 472 | return cmd_mod.command(flags, unpack(nonflags)) | 573 | end |
| 473 | end | 574 | |
| 474 | end, error_handler) | 575 | local cmd_mod = cmd_modules[args.command] |
| 475 | if not call_ok then | 576 | local call_ok, ok, err, exitcode = xpcall(function() |
| 476 | die(ok, cmd.errorcodes.CRASH) | 577 | return cmd_mod.command(args) |
| 477 | elseif not ok then | 578 | end, error_handler) |
| 478 | die(err, exitcode) | 579 | |
| 479 | end | 580 | if not call_ok then |
| 480 | else | 581 | die(ok, cmd.errorcodes.CRASH) |
| 481 | die("Unknown command: "..command) | 582 | elseif not ok then |
| 583 | die(err, exitcode) | ||
| 482 | end | 584 | end |
| 483 | util.run_scheduled_functions() | 585 | util.run_scheduled_functions() |
| 484 | end | 586 | end |
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua index 23a94fa7..0654b4eb 100644 --- a/src/luarocks/cmd/build.lua +++ b/src/luarocks/cmd/build.lua | |||
| @@ -18,40 +18,20 @@ local search = require("luarocks.search") | |||
| 18 | local make = require("luarocks.cmd.make") | 18 | local make = require("luarocks.cmd.make") |
| 19 | local cmd = require("luarocks.cmd") | 19 | local cmd = require("luarocks.cmd") |
| 20 | 20 | ||
| 21 | cmd_build.help_summary = "build/compile a rock." | 21 | function cmd_build.add_to_parser(parser) |
| 22 | cmd_build.help_arguments = "[<flags...>] {<rockspec>|<rock>|<name> [<version>]}" | 22 | local cmd = parser:command("build", "Build and install a rock, compiling its C parts if any.\n".. |
| 23 | cmd_build.help = [[ | 23 | "If no arguments are given, behaves as luarocks make.", util.see_also()) |
| 24 | Build and install a rock, compiling its C parts if any. | 24 | :summary("Build/compile a rock.") |
| 25 | Argument may be a rockspec file, a source rock file | 25 | |
| 26 | or the name of a rock to be fetched from a repository. | 26 | cmd:argument("rock", "A rockspec file, a source rock file, or the name of ".. |
| 27 | 27 | "a rock to be fetched from a repository.") | |
| 28 | --pack-binary-rock Do not install rock. Instead, produce a .rock file | 28 | :args("?") |
| 29 | with the contents of compilation in the current | 29 | cmd:argument("version", "Rock version.") |
| 30 | directory. | 30 | :args("?") |
| 31 | 31 | ||
| 32 | --keep Do not remove previously installed versions of the | 32 | cmd:flag("--only-deps", "Installs only the dependencies of the rock.") |
| 33 | rock after building a new one. This behavior can | 33 | make.cmd_options(cmd) |
| 34 | be made permanent by setting keep_other_versions=true | 34 | end |
| 35 | in the configuration file. | ||
| 36 | |||
| 37 | --branch=<name> Override the `source.branch` field in the loaded | ||
| 38 | rockspec. Allows to specify a different branch to | ||
| 39 | fetch. Particularly for "dev" rocks. | ||
| 40 | |||
| 41 | --only-deps Installs only the dependencies of the rock. | ||
| 42 | |||
| 43 | --verify Verify signature of the rockspec or src.rock being | ||
| 44 | built. If the rockspec or src.rock is being downloaded, | ||
| 45 | LuaRocks will attempt to download the signature as well. | ||
| 46 | Otherwise, the signature file should be already | ||
| 47 | available locally in the same directory. | ||
| 48 | You need the signer’s public key in your local | ||
| 49 | keyring for this option to work properly. | ||
| 50 | |||
| 51 | --sign To be used with --pack-binary-rock. Also produce | ||
| 52 | a signature file for the generated .rock file. | ||
| 53 | |||
| 54 | ]]..util.deps_mode_help() | ||
| 55 | 35 | ||
| 56 | --- Build and install a rock. | 36 | --- Build and install a rock. |
| 57 | -- @param rock_filename string: local or remote filename of a rock. | 37 | -- @param rock_filename string: local or remote filename of a rock. |
| @@ -132,58 +112,54 @@ local function remove_doc_dir(name, version) | |||
| 132 | end | 112 | end |
| 133 | 113 | ||
| 134 | --- Driver function for "build" command. | 114 | --- Driver function for "build" command. |
| 135 | -- @param name string: A local or remote rockspec or rock file. | ||
| 136 | -- If a package name is given, forwards the request to "search" and, | 115 | -- If a package name is given, forwards the request to "search" and, |
| 137 | -- if returned a result, installs the matching rock. | 116 | -- if returned a result, installs the matching rock. |
| 138 | -- @param version string: When passing a package name, a version number may | 117 | -- When passing a package name, a version number may also be given. |
| 139 | -- also be given. | ||
| 140 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an | 118 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an |
| 141 | -- error message otherwise. exitcode is optionally returned. | 119 | -- error message otherwise. exitcode is optionally returned. |
| 142 | function cmd_build.command(flags, name, version) | 120 | function cmd_build.command(args) |
| 143 | assert(type(name) == "string" or not name) | 121 | if not args.rock then |
| 144 | assert(type(version) == "string" or not version) | 122 | return make.command(args) |
| 145 | |||
| 146 | if not name then | ||
| 147 | return make.command(flags) | ||
| 148 | end | 123 | end |
| 149 | 124 | ||
| 150 | name = util.adjust_name_and_namespace(name, flags) | 125 | local name = util.adjust_name_and_namespace(args.rock, args) |
| 151 | 126 | ||
| 152 | local opts = build.opts({ | 127 | local opts = build.opts({ |
| 153 | need_to_fetch = true, | 128 | need_to_fetch = true, |
| 154 | minimal_mode = false, | 129 | minimal_mode = false, |
| 155 | deps_mode = deps.get_deps_mode(flags), | 130 | deps_mode = deps.get_deps_mode(args), |
| 156 | build_only_deps = not not flags["only-deps"], | 131 | build_only_deps = not not args.only_deps, |
| 157 | namespace = flags["namespace"], | 132 | namespace = args.namespace, |
| 158 | branch = not not flags["branch"], | 133 | branch = not not args.branch, |
| 159 | verify = not not flags["verify"], | 134 | verify = not not args.verify, |
| 160 | }) | 135 | }) |
| 161 | 136 | ||
| 162 | if flags["sign"] and not flags["pack-binary-rock"] then | 137 | if args.sign and not args.pack_binary_rock then |
| 163 | return nil, "In the build command, --sign is meant to be used only with --pack-binary-rock" | 138 | return nil, "In the build command, --sign is meant to be used only with --pack-binary-rock" |
| 164 | end | 139 | end |
| 165 | 140 | ||
| 166 | if flags["pack-binary-rock"] then | 141 | if args.pack_binary_rock then |
| 167 | return pack.pack_binary_rock(name, version, flags["sign"], function() | 142 | return pack.pack_binary_rock(name, args.version, args.sign, function() |
| 168 | opts.build_only_deps = false | 143 | opts.build_only_deps = false |
| 169 | local status, err, errcode = do_build(name, version, opts) | 144 | local status, err, errcode = do_build(name, args.version, opts) |
| 170 | if status and flags["no-doc"] then | 145 | if status and args.no_doc then |
| 171 | remove_doc_dir(name, version) | 146 | remove_doc_dir(name, args.version) |
| 172 | end | 147 | end |
| 173 | return status, err, errcode | 148 | return status, err, errcode |
| 174 | end) | 149 | end) |
| 175 | end | 150 | end |
| 176 | 151 | ||
| 177 | local ok, err = fs.check_command_permissions(flags) | 152 | local ok, err = fs.check_command_permissions(args) |
| 178 | if not ok then | 153 | if not ok then |
| 179 | return nil, err, cmd.errorcodes.PERMISSIONDENIED | 154 | return nil, err, cmd.errorcodes.PERMISSIONDENIED |
| 180 | end | 155 | end |
| 181 | 156 | ||
| 182 | ok, err = do_build(name, version, opts) | 157 | ok, err = do_build(name, args.version, opts) |
| 183 | if not ok then return nil, err end | 158 | if not ok then return nil, err end |
| 159 | local version | ||
| 184 | name, version = ok, err | 160 | name, version = ok, err |
| 185 | 161 | ||
| 186 | if flags["no-doc"] then | 162 | if args.no_doc then |
| 187 | remove_doc_dir(name, version) | 163 | remove_doc_dir(name, version) |
| 188 | end | 164 | end |
| 189 | 165 | ||
| @@ -191,15 +167,15 @@ function cmd_build.command(flags, name, version) | |||
| 191 | util.printout("Stopping after installing dependencies for " ..name.." "..version) | 167 | util.printout("Stopping after installing dependencies for " ..name.." "..version) |
| 192 | util.printout() | 168 | util.printout() |
| 193 | else | 169 | else |
| 194 | if (not flags["keep"]) and not cfg.keep_other_versions then | 170 | if (not args.keep) and not cfg.keep_other_versions then |
| 195 | local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) | 171 | local ok, err = remove.remove_other_versions(name, version, args.force, args.force_fast) |
| 196 | if not ok then | 172 | if not ok then |
| 197 | util.printerr(err) | 173 | util.printerr(err) |
| 198 | end | 174 | end |
| 199 | end | 175 | end |
| 200 | end | 176 | end |
| 201 | 177 | ||
| 202 | writer.check_dependencies(nil, deps.get_deps_mode(flags)) | 178 | writer.check_dependencies(nil, deps.get_deps_mode(args)) |
| 203 | return name, version | 179 | return name, version |
| 204 | end | 180 | end |
| 205 | 181 | ||
diff --git a/src/luarocks/cmd/config.lua b/src/luarocks/cmd/config.lua index b3cb5e07..59dafdb5 100644 --- a/src/luarocks/cmd/config.lua +++ b/src/luarocks/cmd/config.lua | |||
| @@ -9,21 +9,22 @@ local deps = require("luarocks.deps") | |||
| 9 | local dir = require("luarocks.dir") | 9 | local dir = require("luarocks.dir") |
| 10 | local fs = require("luarocks.fs") | 10 | local fs = require("luarocks.fs") |
| 11 | 11 | ||
| 12 | config_cmd.help_summary = "Query information about the LuaRocks configuration." | 12 | function config_cmd.add_to_parser(parser) |
| 13 | config_cmd.help_arguments = "(<key> | <key> <value> --scope=<scope> | <key> --unset --scope=<scope> | )" | 13 | local cmd = parser:command("config", [[ |
| 14 | config_cmd.help = [[ | 14 | Query information about the LuaRocks configuration. |
| 15 | * When given a configuration key, it prints the value of that key | 15 | |
| 16 | according to the currently active configuration (taking into account | 16 | * When given a configuration key, it prints the value of that key according to |
| 17 | all config files and any command-line flags passed) | 17 | the currently active configuration (taking into account all config files and |
| 18 | any command-line flags passed) | ||
| 18 | 19 | ||
| 19 | Examples: | 20 | Examples: |
| 20 | luarocks config lua_interpreter | 21 | luarocks config lua_interpreter |
| 21 | luarocks config variables.LUA_INCDIR | 22 | luarocks config variables.LUA_INCDIR |
| 22 | luarocks config lua_version | 23 | luarocks config lua_version |
| 23 | 24 | ||
| 24 | * When given a configuration key and a value, | 25 | * When given a configuration key and a value, it overwrites the config file (see |
| 25 | it overwrites the config file (see the --scope option below to determine which) | 26 | the --scope option below to determine which) and replaces the value of the |
| 26 | and replaces the value of the given key with the given value. | 27 | given key with the given value. |
| 27 | 28 | ||
| 28 | * `lua_dir` is a special key as it checks for a valid Lua installation | 29 | * `lua_dir` is a special key as it checks for a valid Lua installation |
| 29 | (equivalent to --lua-dir) and sets several keys at once. | 30 | (equivalent to --lua-dir) and sets several keys at once. |
| @@ -35,33 +36,42 @@ config_cmd.help = [[ | |||
| 35 | luarocks config lua_dir /usr/local | 36 | luarocks config lua_dir /usr/local |
| 36 | luarocks config lua_version 5.3 | 37 | luarocks config lua_version 5.3 |
| 37 | 38 | ||
| 38 | * When given a configuration key and --unset, | 39 | * When given a configuration key and --unset, it overwrites the config file (see |
| 39 | it overwrites the config file (see the --scope option below to determine which) | 40 | the --scope option below to determine which) and deletes that key from the |
| 40 | and deletes that key from the file. | 41 | file. |
| 41 | 42 | ||
| 42 | Example: luarocks config variables.OPENSSL_DIR --unset | 43 | Example: luarocks config variables.OPENSSL_DIR --unset |
| 43 | 44 | ||
| 44 | * When given no arguments, it prints the entire currently active | 45 | * When given no arguments, it prints the entire currently active configuration, |
| 45 | configuration, resulting from reading the config files from | 46 | resulting from reading the config files from all scopes. |
| 46 | all scopes. | 47 | |
| 47 | 48 | Example: luarocks config]], util.see_also([[ | |
| 48 | Example: luarocks config | 49 | https://github.com/luarocks/luarocks/wiki/Config-file-format |
| 49 | 50 | for detailed information on the LuaRocks config file format. | |
| 50 | OPTIONS | 51 | ]])) |
| 51 | --scope=<scope> The scope indicates which config file should be rewritten. | 52 | :summary("Query information about the LuaRocks configuration.") |
| 52 | Accepted values are "system", "user" or "project". | 53 | |
| 53 | * Using a wrapper created with `luarocks init`, | 54 | cmd:argument("key", "The configuration key.") |
| 54 | the default is "project". | 55 | :args("?") |
| 55 | * Using --local (or when `local_by_default` is `true`), | 56 | cmd:argument("value", "The configuration value.") |
| 56 | the default is "user". | 57 | :args("?") |
| 57 | * Otherwise, the default is "system". | 58 | |
| 58 | 59 | cmd:option("--scope", "The scope indicates which config file should be rewritten.\n".. | |
| 59 | --json Output as JSON | 60 | '* Using a wrapper created with `luarocks init`, the default is "project".\n'.. |
| 60 | ]] | 61 | '* Using --local (or when `local_by_default` is `true`), the default is "user".\n'.. |
| 61 | config_cmd.help_see_also = [[ | 62 | '* Otherwise, the default is "system".') |
| 62 | https://github.com/luarocks/luarocks/wiki/Config-file-format | 63 | :choices({"system", "user", "project"}) |
| 63 | for detailed information on the LuaRocks config file format. | 64 | cmd:flag("--unset", "Delete the key from the configuration file.") |
| 64 | ]] | 65 | cmd:flag("--json", "Output as JSON.") |
| 66 | |||
| 67 | -- Deprecated flags | ||
| 68 | cmd:flag("--lua-incdir"):hidden(true) | ||
| 69 | cmd:flag("--lua-libdir"):hidden(true) | ||
| 70 | cmd:flag("--lua-ver"):hidden(true) | ||
| 71 | cmd:flag("--system-config"):hidden(true) | ||
| 72 | cmd:flag("--user-config"):hidden(true) | ||
| 73 | cmd:flag("--rock-trees"):hidden(true) | ||
| 74 | end | ||
| 65 | 75 | ||
| 66 | local function config_file(conf) | 76 | local function config_file(conf) |
| 67 | print(dir.normalize(conf.file)) | 77 | print(dir.normalize(conf.file)) |
| @@ -218,45 +228,40 @@ local function write_entries(keys, scope, do_unset) | |||
| 218 | end | 228 | end |
| 219 | end | 229 | end |
| 220 | 230 | ||
| 221 | local function check_scope(flags) | 231 | local function get_scope(args) |
| 222 | local scope = flags["scope"] | 232 | return args.scope |
| 223 | or (flags["local"] and "user") | 233 | or (args["local"] and "user") |
| 224 | or (flags["project-tree"] and "project") | 234 | or (args.project_tree and "project") |
| 225 | or (cfg.local_by_default and "user") | 235 | or (cfg.local_by_default and "user") |
| 226 | or "system" | 236 | or "system" |
| 227 | if scope ~= "system" and scope ~= "user" and scope ~= "project" then | ||
| 228 | return nil, "Valid values for scope are: system, user, project" | ||
| 229 | end | ||
| 230 | |||
| 231 | return scope | ||
| 232 | end | 237 | end |
| 233 | 238 | ||
| 234 | --- Driver function for "config" command. | 239 | --- Driver function for "config" command. |
| 235 | -- @return boolean: True if succeeded, nil on errors. | 240 | -- @return boolean: True if succeeded, nil on errors. |
| 236 | function config_cmd.command(flags, var, val) | 241 | function config_cmd.command(args) |
| 237 | deps.check_lua_incdir(cfg.variables) | 242 | deps.check_lua_incdir(cfg.variables) |
| 238 | deps.check_lua_libdir(cfg.variables) | 243 | deps.check_lua_libdir(cfg.variables) |
| 239 | 244 | ||
| 240 | -- deprecated flags | 245 | -- deprecated flags |
| 241 | if flags["lua-incdir"] then | 246 | if args.lua_incdir then |
| 242 | print(cfg.variables.LUA_INCDIR) | 247 | print(cfg.variables.LUA_INCDIR) |
| 243 | return true | 248 | return true |
| 244 | end | 249 | end |
| 245 | if flags["lua-libdir"] then | 250 | if args.lua_libdir then |
| 246 | print(cfg.variables.LUA_LIBDIR) | 251 | print(cfg.variables.LUA_LIBDIR) |
| 247 | return true | 252 | return true |
| 248 | end | 253 | end |
| 249 | if flags["lua-ver"] then | 254 | if args.lua_ver then |
| 250 | print(cfg.lua_version) | 255 | print(cfg.lua_version) |
| 251 | return true | 256 | return true |
| 252 | end | 257 | end |
| 253 | if flags["system-config"] then | 258 | if args.system_config then |
| 254 | return config_file(cfg.config_files.system) | 259 | return config_file(cfg.config_files.system) |
| 255 | end | 260 | end |
| 256 | if flags["user-config"] then | 261 | if args.user_config then |
| 257 | return config_file(cfg.config_files.user) | 262 | return config_file(cfg.config_files.user) |
| 258 | end | 263 | end |
| 259 | if flags["rock-trees"] then | 264 | if args.rock_trees then |
| 260 | for _, tree in ipairs(cfg.rocks_trees) do | 265 | for _, tree in ipairs(cfg.rocks_trees) do |
| 261 | if type(tree) == "string" then | 266 | if type(tree) == "string" then |
| 262 | util.printout(dir.normalize(tree)) | 267 | util.printout(dir.normalize(tree)) |
| @@ -268,29 +273,22 @@ function config_cmd.command(flags, var, val) | |||
| 268 | return true | 273 | return true |
| 269 | end | 274 | end |
| 270 | 275 | ||
| 271 | if var == "lua_version" and val then | 276 | if args.key == "lua_version" and args.value then |
| 272 | local scope, err = check_scope(flags) | 277 | local scope = get_scope(args) |
| 273 | if not scope then | ||
| 274 | return nil, err | ||
| 275 | end | ||
| 276 | |||
| 277 | if scope == "project" and not cfg.config_files.project then | 278 | if scope == "project" and not cfg.config_files.project then |
| 278 | return nil, "Current directory is not part of a project. You may want to run `luarocks init`." | 279 | return nil, "Current directory is not part of a project. You may want to run `luarocks init`." |
| 279 | end | 280 | end |
| 280 | 281 | ||
| 281 | local prefix = dir.dir_name(cfg.config_files[scope].file) | 282 | local prefix = dir.dir_name(cfg.config_files[scope].file) |
| 282 | local ok, err = persist.save_default_lua_version(prefix, val) | 283 | local ok, err = persist.save_default_lua_version(prefix, args.value) |
| 283 | if not ok then | 284 | if not ok then |
| 284 | return nil, "could not set default Lua version: " .. err | 285 | return nil, "could not set default Lua version: " .. err |
| 285 | end | 286 | end |
| 286 | print("Lua version will default to " .. val .. " in " .. prefix) | 287 | print("Lua version will default to " .. args.value .. " in " .. prefix) |
| 287 | end | 288 | end |
| 288 | 289 | ||
| 289 | if var == "lua_dir" and val then | 290 | if args.key == "lua_dir" and args.value then |
| 290 | local scope, err = check_scope(flags) | 291 | local scope = get_scope(args) |
| 291 | if not scope then | ||
| 292 | return nil, err | ||
| 293 | end | ||
| 294 | local keys = { | 292 | local keys = { |
| 295 | ["variables.LUA_DIR"] = cfg.variables.LUA_DIR, | 293 | ["variables.LUA_DIR"] = cfg.variables.LUA_DIR, |
| 296 | ["variables.LUA_BINDIR"] = cfg.variables.LUA_BINDIR, | 294 | ["variables.LUA_BINDIR"] = cfg.variables.LUA_BINDIR, |
| @@ -298,25 +296,21 @@ function config_cmd.command(flags, var, val) | |||
| 298 | ["variables.LUA_LIBDIR"] = cfg.variables.LUA_LIBDIR, | 296 | ["variables.LUA_LIBDIR"] = cfg.variables.LUA_LIBDIR, |
| 299 | ["lua_interpreter"] = cfg.lua_interpreter, | 297 | ["lua_interpreter"] = cfg.lua_interpreter, |
| 300 | } | 298 | } |
| 301 | return write_entries(keys, scope, flags["unset"]) | 299 | return write_entries(keys, scope, args.unset) |
| 302 | end | 300 | end |
| 303 | 301 | ||
| 304 | if var then | 302 | if args.key then |
| 305 | if val or flags["unset"] then | 303 | if args.value or args.unset then |
| 306 | local scope, err = check_scope(flags) | 304 | local scope = get_scope(args) |
| 307 | if not scope then | 305 | return write_entries({ [args.key] = args.value }, scope, args.unset) |
| 308 | return nil, err | ||
| 309 | end | ||
| 310 | |||
| 311 | return write_entries({ [var] = val }, scope, flags["unset"]) | ||
| 312 | else | 306 | else |
| 313 | return print_entry(var, cfg, flags["json"]) | 307 | return print_entry(args.key, cfg, args.json) |
| 314 | end | 308 | end |
| 315 | end | 309 | end |
| 316 | 310 | ||
| 317 | local cleancfg = cleanup(cfg) | 311 | local cleancfg = cleanup(cfg) |
| 318 | 312 | ||
| 319 | if flags["json"] then | 313 | if args.json then |
| 320 | return print_json(cleancfg) | 314 | return print_json(cleancfg) |
| 321 | else | 315 | else |
| 322 | print(persist.save_from_table_to_string(cleancfg)) | 316 | print(persist.save_from_table_to_string(cleancfg)) |
diff --git a/src/luarocks/cmd/doc.lua b/src/luarocks/cmd/doc.lua index a2472be4..4b3335d8 100644 --- a/src/luarocks/cmd/doc.lua +++ b/src/luarocks/cmd/doc.lua | |||
| @@ -12,19 +12,22 @@ local fetch = require("luarocks.fetch") | |||
| 12 | local fs = require("luarocks.fs") | 12 | local fs = require("luarocks.fs") |
| 13 | local download = require("luarocks.download") | 13 | local download = require("luarocks.download") |
| 14 | 14 | ||
| 15 | doc.help_summary = "Show documentation for an installed rock." | 15 | function doc.add_to_parser(parser) |
| 16 | 16 | local cmd = parser:command("doc", "Show documentation for an installed rock.\n\n".. | |
| 17 | doc.help = [[ | 17 | "Without any flags, tries to load the documentation using a series of heuristics.\n".. |
| 18 | <argument> is an existing package name. | 18 | "With flags, return only the desired information.", util.see_also([[ |
| 19 | Without any flags, tries to load the documentation | 19 | For more information about a rock, see the 'show' command. |
| 20 | using a series of heuristics. | 20 | ]])) |
| 21 | With these flags, return only the desired information: | 21 | :summary("Show documentation for an installed rock.") |
| 22 | 22 | ||
| 23 | --home Open the home page of project. | 23 | cmd:argument("rock", "Name of the rock.") |
| 24 | --list List documentation files only. | 24 | cmd:argument("version", "Version of the rock.") |
| 25 | 25 | :args("?") | |
| 26 | For more information about a rock, see the 'show' command. | 26 | |
| 27 | ]] | 27 | cmd:flag("--home", "Open the home page of project.") |
| 28 | cmd:flag("--list", "List documentation files only.") | ||
| 29 | cmd:flag("--porcelain", "Produce machine-friendly output.") | ||
| 30 | end | ||
| 28 | 31 | ||
| 29 | local function show_homepage(homepage, name, version) | 32 | local function show_homepage(homepage, name, version) |
| 30 | if not homepage then | 33 | if not homepage then |
| @@ -54,17 +57,12 @@ local function try_to_open_homepage(name, version) | |||
| 54 | end | 57 | end |
| 55 | 58 | ||
| 56 | --- Driver function for "doc" command. | 59 | --- Driver function for "doc" command. |
| 57 | -- @param name or nil: an existing package name. | ||
| 58 | -- @param version string or nil: a version may also be passed. | ||
| 59 | -- @return boolean: True if succeeded, nil on errors. | 60 | -- @return boolean: True if succeeded, nil on errors. |
| 60 | function doc.command(flags, name, version) | 61 | function doc.command(args) |
| 61 | if not name then | 62 | local name = util.adjust_name_and_namespace(args.rock, args) |
| 62 | return nil, "Argument missing. "..util.see_help("doc") | 63 | local version = args.version |
| 63 | end | ||
| 64 | |||
| 65 | name = util.adjust_name_and_namespace(name, flags) | ||
| 66 | local query = queries.new(name, version) | 64 | local query = queries.new(name, version) |
| 67 | local iname, iversion, repo = search.pick_installed_rock(query, flags["tree"]) | 65 | local iname, iversion, repo = search.pick_installed_rock(query, args.tree) |
| 68 | if not iname then | 66 | if not iname then |
| 69 | util.printout(name..(version and " "..version or "").." is not installed. Looking for it in the rocks servers...") | 67 | util.printout(name..(version and " "..version or "").." is not installed. Looking for it in the rocks servers...") |
| 70 | return try_to_open_homepage(name, version) | 68 | return try_to_open_homepage(name, version) |
| @@ -75,7 +73,7 @@ function doc.command(flags, name, version) | |||
| 75 | if not rockspec then return nil,err end | 73 | if not rockspec then return nil,err end |
| 76 | local descript = rockspec.description or {} | 74 | local descript = rockspec.description or {} |
| 77 | 75 | ||
| 78 | if flags["home"] then | 76 | if args.home then |
| 79 | return show_homepage(descript.homepage, name, version) | 77 | return show_homepage(descript.homepage, name, version) |
| 80 | end | 78 | end |
| 81 | 79 | ||
| @@ -91,7 +89,7 @@ function doc.command(flags, name, version) | |||
| 91 | end | 89 | end |
| 92 | end | 90 | end |
| 93 | if not docdir then | 91 | if not docdir then |
| 94 | if descript.homepage and not flags["list"] then | 92 | if descript.homepage and not args.list then |
| 95 | util.printout("Local documentation directory not found -- opening "..descript.homepage.." ...") | 93 | util.printout("Local documentation directory not found -- opening "..descript.homepage.." ...") |
| 96 | fs.browser(descript.homepage) | 94 | fs.browser(descript.homepage) |
| 97 | return true | 95 | return true |
| @@ -105,7 +103,7 @@ function doc.command(flags, name, version) | |||
| 105 | local extensions = { htmlpatt, "%.md$", "%.txt$", "%.textile$", "" } | 103 | local extensions = { htmlpatt, "%.md$", "%.txt$", "%.textile$", "" } |
| 106 | local basenames = { "index", "readme", "manual" } | 104 | local basenames = { "index", "readme", "manual" } |
| 107 | 105 | ||
| 108 | local porcelain = flags["porcelain"] | 106 | local porcelain = args.porcelain |
| 109 | if #files > 0 then | 107 | if #files > 0 then |
| 110 | util.title("Documentation files for "..name.." "..version, porcelain) | 108 | util.title("Documentation files for "..name.." "..version, porcelain) |
| 111 | if porcelain then | 109 | if porcelain then |
| @@ -120,7 +118,7 @@ function doc.command(flags, name, version) | |||
| 120 | end | 118 | end |
| 121 | end | 119 | end |
| 122 | 120 | ||
| 123 | if flags["list"] then | 121 | if args.list then |
| 124 | return true | 122 | return true |
| 125 | end | 123 | end |
| 126 | 124 | ||
diff --git a/src/luarocks/cmd/download.lua b/src/luarocks/cmd/download.lua index 50c10c0c..5032d580 100644 --- a/src/luarocks/cmd/download.lua +++ b/src/luarocks/cmd/download.lua | |||
| @@ -6,42 +6,44 @@ local cmd_download = {} | |||
| 6 | local util = require("luarocks.util") | 6 | local util = require("luarocks.util") |
| 7 | local download = require("luarocks.download") | 7 | local download = require("luarocks.download") |
| 8 | 8 | ||
| 9 | cmd_download.help_summary = "Download a specific rock file from a rocks server." | 9 | function cmd_download.add_to_parser(parser) |
| 10 | cmd_download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" | 10 | local cmd = parser:command("download", "Download a specific rock file from a rocks server.", util.see_also()) |
| 11 | cmd_download.help = [[ | 11 | |
| 12 | --all Download all files if there are multiple matches. | 12 | cmd:argument("name", "Name of the rock.") |
| 13 | --source Download .src.rock if available. | 13 | :args("?") |
| 14 | --rockspec Download .rockspec if available. | 14 | cmd:argument("version", "Version of the rock.") |
| 15 | --arch=<arch> Download rock for a specific architecture. | 15 | :args("?") |
| 16 | ]] | 16 | |
| 17 | cmd:flag("--all", "Download all files if there are multiple matches.") | ||
| 18 | cmd:mutex( | ||
| 19 | cmd:flag("--source", "Download .src.rock if available."), | ||
| 20 | cmd:flag("--rockspec", "Download .rockspec if available."), | ||
| 21 | cmd:option("--arch", "Download rock for a specific architecture.")) | ||
| 22 | end | ||
| 17 | 23 | ||
| 18 | --- Driver function for the "download" command. | 24 | --- Driver function for the "download" command. |
| 19 | -- @param name string: a rock name. | ||
| 20 | -- @param version string or nil: if the name of a package is given, a | ||
| 21 | -- version may also be passed. | ||
| 22 | -- @return boolean or (nil, string): true if successful or nil followed | 25 | -- @return boolean or (nil, string): true if successful or nil followed |
| 23 | -- by an error message. | 26 | -- by an error message. |
| 24 | function cmd_download.command(flags, name, version) | 27 | function cmd_download.command(args) |
| 25 | assert(type(version) == "string" or not version) | 28 | if not args.name and not args.all then |
| 26 | if type(name) ~= "string" and not flags["all"] then | ||
| 27 | return nil, "Argument missing. "..util.see_help("download") | 29 | return nil, "Argument missing. "..util.see_help("download") |
| 28 | end | 30 | end |
| 29 | 31 | ||
| 30 | name = util.adjust_name_and_namespace(name, flags) | 32 | local name = util.adjust_name_and_namespace(args.name, args) |
| 31 | 33 | ||
| 32 | if not name then name, version = "", "" end | 34 | if not name then name, args.version = "", "" end |
| 33 | 35 | ||
| 34 | local arch | 36 | local arch |
| 35 | 37 | ||
| 36 | if flags["source"] then | 38 | if args.source then |
| 37 | arch = "src" | 39 | arch = "src" |
| 38 | elseif flags["rockspec"] then | 40 | elseif args.rockspec then |
| 39 | arch = "rockspec" | 41 | arch = "rockspec" |
| 40 | elseif flags["arch"] then | 42 | elseif args.arch then |
| 41 | arch = flags["arch"] | 43 | arch = args.arch |
| 42 | end | 44 | end |
| 43 | 45 | ||
| 44 | local dl, err = download.download(arch, name:lower(), version, flags["all"]) | 46 | local dl, err = download.download(arch, name:lower(), args.version, args.all) |
| 45 | return dl and true, err | 47 | return dl and true, err |
| 46 | end | 48 | end |
| 47 | 49 | ||
diff --git a/src/luarocks/cmd/help.lua b/src/luarocks/cmd/help.lua deleted file mode 100644 index b3d937e1..00000000 --- a/src/luarocks/cmd/help.lua +++ /dev/null | |||
| @@ -1,139 +0,0 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "help" command. | ||
| 3 | -- This is a generic help display module, which | ||
| 4 | -- uses a global table called "commands" to find commands | ||
| 5 | -- to show help for; each command should be represented by a | ||
| 6 | -- table containing "help" and "help_summary" fields. | ||
| 7 | local help = {} | ||
| 8 | |||
| 9 | local util = require("luarocks.util") | ||
| 10 | local cfg = require("luarocks.core.cfg") | ||
| 11 | local dir = require("luarocks.dir") | ||
| 12 | local fs = require("luarocks.fs") | ||
| 13 | |||
| 14 | local program = util.this_program("luarocks") | ||
| 15 | |||
| 16 | help.help_summary = "Help on commands. Type '"..program.." help <command>' for more." | ||
| 17 | |||
| 18 | help.help_arguments = "[<command>]" | ||
| 19 | help.help = [[ | ||
| 20 | <command> is the command to show help for. | ||
| 21 | ]] | ||
| 22 | |||
| 23 | local function print_banner() | ||
| 24 | util.printout("\nLuaRocks "..cfg.program_version..", the Lua package manager") | ||
| 25 | end | ||
| 26 | |||
| 27 | local function print_section(section) | ||
| 28 | util.printout("\n"..section) | ||
| 29 | end | ||
| 30 | |||
| 31 | local function get_status(status) | ||
| 32 | if status then | ||
| 33 | return "ok" | ||
| 34 | else | ||
| 35 | return "not found" | ||
| 36 | end | ||
| 37 | end | ||
| 38 | |||
| 39 | --- Driver function for the "help" command. | ||
| 40 | -- @param command string or nil: command to show help for; if not | ||
| 41 | -- given, help summaries for all commands are shown. | ||
| 42 | -- @return boolean or (nil, string): true if there were no errors | ||
| 43 | -- or nil and an error message if an invalid command was requested. | ||
| 44 | function help.command(description, commands, command) | ||
| 45 | assert(type(description) == "string") | ||
| 46 | assert(type(commands) == "table") | ||
| 47 | |||
| 48 | if not command then | ||
| 49 | print_banner() | ||
| 50 | print_section("NAME") | ||
| 51 | util.printout("\t"..program..[[ - ]]..description) | ||
| 52 | print_section("SYNOPSIS") | ||
| 53 | util.printout("\t"..program..[[ [<flags...>] [VAR=VALUE]... <command> [<argument>] ]]) | ||
| 54 | print_section("GENERAL OPTIONS") | ||
| 55 | util.printout([[ | ||
| 56 | These apply to all commands, as appropriate: | ||
| 57 | |||
| 58 | --dev Enable the sub-repositories in rocks servers | ||
| 59 | for rockspecs of in-development versions | ||
| 60 | --server=<server> Fetch rocks/rockspecs from this server | ||
| 61 | (takes priority over config file) | ||
| 62 | --only-server=<server> Fetch rocks/rockspecs from this server only | ||
| 63 | (overrides any entries in the config file) | ||
| 64 | --only-sources=<url> Restrict downloads to paths matching the | ||
| 65 | given URL. | ||
| 66 | --lua-dir=<prefix> Which Lua installation to use. | ||
| 67 | --lua-version=<ver> Which Lua version to use. | ||
| 68 | --tree=<tree> Which tree to operate on. | ||
| 69 | --local Use the tree in the user's home directory. | ||
| 70 | To enable it, see ']]..program..[[ help path'. | ||
| 71 | --global Use the system tree when `local_by_default` is `true`. | ||
| 72 | --verbose Display verbose output of commands executed. | ||
| 73 | --timeout=<seconds> Timeout on network operations, in seconds. | ||
| 74 | 0 means no timeout (wait forever). | ||
| 75 | Default is ]]..tostring(cfg.connection_timeout)..[[.]]) | ||
| 76 | print_section("VARIABLES") | ||
| 77 | util.printout([[ | ||
| 78 | Variables from the "variables" table of the configuration file | ||
| 79 | can be overridden with VAR=VALUE assignments.]]) | ||
| 80 | print_section("COMMANDS") | ||
| 81 | for name, modname in util.sortedpairs(commands) do | ||
| 82 | local cmd = require(modname) | ||
| 83 | util.printout("", name) | ||
| 84 | util.printout("\t", cmd.help_summary) | ||
| 85 | end | ||
| 86 | print_section("CONFIGURATION") | ||
| 87 | util.printout("\tLua version: " .. cfg.lua_version) | ||
| 88 | local ljv = util.get_luajit_version() | ||
| 89 | if ljv then | ||
| 90 | util.printout("\tLuaJIT version: " .. ljv) | ||
| 91 | end | ||
| 92 | util.printout() | ||
| 93 | util.printout("\tConfiguration files:") | ||
| 94 | local conf = cfg.config_files | ||
| 95 | util.printout("\t\tSystem : ".. fs.absolute_name(conf.system.file) .. " (" .. get_status(conf.system.found) ..")") | ||
| 96 | if conf.user.file then | ||
| 97 | util.printout("\t\tUser : ".. fs.absolute_name(conf.user.file) .. " (" .. get_status(conf.user.found) ..")") | ||
| 98 | else | ||
| 99 | util.printout("\t\tUser : disabled in this LuaRocks installation.") | ||
| 100 | end | ||
| 101 | if conf.project then | ||
| 102 | util.printout("\t\tProject : ".. fs.absolute_name(conf.project.file) .. " (" .. get_status(conf.project.found) ..")") | ||
| 103 | end | ||
| 104 | util.printout() | ||
| 105 | util.printout("\tRocks trees in use: ") | ||
| 106 | for _, tree in ipairs(cfg.rocks_trees) do | ||
| 107 | if type(tree) == "string" then | ||
| 108 | util.printout("\t\t"..fs.absolute_name(tree)) | ||
| 109 | else | ||
| 110 | local name = tree.name and " (\""..tree.name.."\")" or "" | ||
| 111 | util.printout("\t\t"..fs.absolute_name(tree.root)..name) | ||
| 112 | end | ||
| 113 | end | ||
| 114 | util.printout() | ||
| 115 | else | ||
| 116 | command = command:gsub("-", "_") | ||
| 117 | local cmd = commands[command] and require(commands[command]) | ||
| 118 | if cmd then | ||
| 119 | local arguments = cmd.help_arguments or "<argument>" | ||
| 120 | print_banner() | ||
| 121 | print_section("NAME") | ||
| 122 | util.printout("\t"..program.." "..command.." - "..cmd.help_summary) | ||
| 123 | print_section("SYNOPSIS") | ||
| 124 | util.printout("\t"..program.." "..command.." "..arguments) | ||
| 125 | print_section("DESCRIPTION") | ||
| 126 | util.printout("",(cmd.help:gsub("\n","\n\t"):gsub("\n\t$",""))) | ||
| 127 | print_section("SEE ALSO") | ||
| 128 | if cmd.help_see_also then | ||
| 129 | util.printout(cmd.help_see_also) | ||
| 130 | end | ||
| 131 | util.printout("","'"..program.." help' for general options and configuration.\n") | ||
| 132 | else | ||
| 133 | return nil, "Unknown command: "..command | ||
| 134 | end | ||
| 135 | end | ||
| 136 | return true | ||
| 137 | end | ||
| 138 | |||
| 139 | return help | ||
diff --git a/src/luarocks/cmd/init.lua b/src/luarocks/cmd/init.lua index 60aa4f82..5f269e22 100644 --- a/src/luarocks/cmd/init.lua +++ b/src/luarocks/cmd/init.lua | |||
| @@ -10,27 +10,17 @@ local util = require("luarocks.util") | |||
| 10 | local persist = require("luarocks.persist") | 10 | local persist = require("luarocks.persist") |
| 11 | local write_rockspec = require("luarocks.cmd.write_rockspec") | 11 | local write_rockspec = require("luarocks.cmd.write_rockspec") |
| 12 | 12 | ||
| 13 | init.help_summary = "Initialize a directory for a Lua project using LuaRocks." | 13 | function init.add_to_parser(parser) |
| 14 | init.help_arguments = "[<name> [<version>]]" | 14 | local cmd = parser:command("init", "Initialize a directory for a Lua project using LuaRocks.", util.see_also()) |
| 15 | init.help = [[ | 15 | |
| 16 | <name> is the project name. | 16 | cmd:argument("name", "The project name.") |
| 17 | <version> is an optional project version. | 17 | :args("?") |
| 18 | 18 | cmd:argument("version", "An optional project version.") | |
| 19 | --reset Delete .luarocks/config-5.x.lua and ./lua | 19 | :args("?") |
| 20 | and generate new ones. | 20 | cmd:flag("--reset", "Delete .luarocks/config-5.x.lua and ./lua and generate new ones.") |
| 21 | 21 | ||
| 22 | Options for specifying rockspec data: | 22 | cmd:group("Options for specifying rockspec data", write_rockspec.cmd_options(cmd)) |
| 23 | 23 | end | |
| 24 | --license="<string>" A license string, such as "MIT/X11" or "GNU GPL v3". | ||
| 25 | --summary="<txt>" A short one-line description summary. | ||
| 26 | --detailed="<txt>" A longer description string. | ||
| 27 | --homepage=<url> Project homepage. | ||
| 28 | --lua-versions=<ver> Supported Lua versions. Accepted values are "5.1", "5.2", | ||
| 29 | "5.3", "5.1,5.2", "5.2,5.3", or "5.1,5.2,5.3". | ||
| 30 | --rockspec-format=<ver> Rockspec format version, such as "1.0" or "1.1". | ||
| 31 | --lib=<lib>[,<lib>] A comma-separated list of libraries that C files need to | ||
| 32 | link to. | ||
| 33 | ]] | ||
| 34 | 24 | ||
| 35 | local function write_gitignore(entries) | 25 | local function write_gitignore(entries) |
| 36 | local gitignore = "" | 26 | local gitignore = "" |
| @@ -53,18 +43,18 @@ end | |||
| 53 | 43 | ||
| 54 | --- Driver function for "init" command. | 44 | --- Driver function for "init" command. |
| 55 | -- @return boolean: True if succeeded, nil on errors. | 45 | -- @return boolean: True if succeeded, nil on errors. |
| 56 | function init.command(flags, name, version) | 46 | function init.command(args) |
| 57 | 47 | ||
| 58 | local pwd = fs.current_dir() | 48 | local pwd = fs.current_dir() |
| 59 | 49 | ||
| 60 | if not name then | 50 | if not args.name then |
| 61 | name = dir.base_name(pwd) | 51 | args.name = dir.base_name(pwd) |
| 62 | if name == "/" then | 52 | if args.name == "/" then |
| 63 | return nil, "When running from the root directory, please specify the <name> argument" | 53 | return nil, "When running from the root directory, please specify the <name> argument" |
| 64 | end | 54 | end |
| 65 | end | 55 | end |
| 66 | 56 | ||
| 67 | util.title("Initializing project '" .. name .. "' for Lua " .. cfg.lua_version .. " ...") | 57 | util.title("Initializing project '" .. args.name .. "' for Lua " .. cfg.lua_version .. " ...") |
| 68 | 58 | ||
| 69 | util.printout("Checking your Lua installation ...") | 59 | util.printout("Checking your Lua installation ...") |
| 70 | if not cfg.lua_found then | 60 | if not cfg.lua_found then |
| @@ -84,7 +74,9 @@ function init.command(flags, name, version) | |||
| 84 | end | 74 | end |
| 85 | 75 | ||
| 86 | if not has_rockspec then | 76 | if not has_rockspec then |
| 87 | local ok, err = write_rockspec.command(flags, name, version or "dev", pwd) | 77 | args.version = args.version or "dev" |
| 78 | args.location = pwd | ||
| 79 | local ok, err = write_rockspec.command(args) | ||
| 88 | if not ok then | 80 | if not ok then |
| 89 | util.printerr(err) | 81 | util.printerr(err) |
| 90 | end | 82 | end |
| @@ -101,7 +93,7 @@ function init.command(flags, name, version) | |||
| 101 | fs.make_dir(".luarocks") | 93 | fs.make_dir(".luarocks") |
| 102 | local config_file = ".luarocks/config-" .. cfg.lua_version .. ".lua" | 94 | local config_file = ".luarocks/config-" .. cfg.lua_version .. ".lua" |
| 103 | 95 | ||
| 104 | if flags["reset"] then | 96 | if args.reset then |
| 105 | fs.delete(lua_wrapper) | 97 | fs.delete(lua_wrapper) |
| 106 | fs.delete(config_file) | 98 | fs.delete(config_file) |
| 107 | end | 99 | end |
diff --git a/src/luarocks/cmd/install.lua b/src/luarocks/cmd/install.lua index d1d7bf6c..4020918e 100644 --- a/src/luarocks/cmd/install.lua +++ b/src/luarocks/cmd/install.lua | |||
| @@ -16,32 +16,35 @@ local cfg = require("luarocks.core.cfg") | |||
| 16 | local cmd = require("luarocks.cmd") | 16 | local cmd = require("luarocks.cmd") |
| 17 | local dir = require("luarocks.dir") | 17 | local dir = require("luarocks.dir") |
| 18 | 18 | ||
| 19 | install.help_summary = "Install a rock." | 19 | function install.add_to_parser(parser) |
| 20 | 20 | local cmd = parser:command("install", "Install a rock.", util.see_also()) | |
| 21 | install.help_arguments = "{<rock>|<name> [<version>]}" | 21 | |
| 22 | 22 | cmd:argument("rock", "The name of a rock to be fetched from a repository ".. | |
| 23 | install.help = [[ | 23 | "or a filename of a locally available rock.") |
| 24 | Argument may be the name of a rock to be fetched from a repository | 24 | cmd:argument("version", "Version of the rock.") |
| 25 | or a filename of a locally available rock. | 25 | :args("?") |
| 26 | 26 | ||
| 27 | --keep Do not remove previously installed versions of the | 27 | cmd:flag("--keep", "Do not remove previously installed versions of the ".. |
| 28 | rock after installing a new one. This behavior can | 28 | "rock after building a new one. This behavior can be made permanent by ".. |
| 29 | be made permanent by setting keep_other_versions=true | 29 | "setting keep_other_versions=true in the configuration file.") |
| 30 | in the configuration file. | 30 | cmd:flag("--force", "If --keep is not specified, force removal of ".. |
| 31 | 31 | "previously installed versions if it would break dependencies.") | |
| 32 | --only-deps Installs only the dependencies of the rock. | 32 | cmd:flag("--force-fast", "Like --force, but performs a forced removal ".. |
| 33 | 33 | "without reporting dependency issues.") | |
| 34 | --no-doc Installs the rock without its documentation. | 34 | cmd:flag("--only-deps", "Installs only the dependencies of the rock.") |
| 35 | 35 | cmd:flag("--no-doc", "Installs the rock without its documentation.") | |
| 36 | --verify Verify signature of the rock being installed. | 36 | cmd:flag("--verify", "Verify signature of the rockspec or src.rock being ".. |
| 37 | If rock is being downloaded, LuaRocks will attempt | 37 | "built. If the rockspec or src.rock is being downloaded, LuaRocks will ".. |
| 38 | to download the signature as well. If the rock is | 38 | "attempt to download the signature as well. Otherwise, the signature ".. |
| 39 | local, the signature file should be in the same | 39 | "file should be already available locally in the same directory.\n".. |
| 40 | directory. | 40 | "You need the signer’s public key in your local keyring for this ".. |
| 41 | You need the signer’s public key in your local | 41 | "option to work properly.") |
| 42 | keyring for this option to work properly. | 42 | util.deps_mode_option(cmd) |
| 43 | 43 | -- luarocks build options | |
| 44 | ]]..util.deps_mode_help() | 44 | parser:flag("--pack-binary-rock"):hidden(true) |
| 45 | parser:flag("--branch"):hidden(true) | ||
| 46 | parser:flag("--sign"):hidden(true) | ||
| 47 | end | ||
| 45 | 48 | ||
| 46 | install.opts = util.opts_table("install.opts", { | 49 | install.opts = util.opts_table("install.opts", { |
| 47 | namespace = "string?", | 50 | namespace = "string?", |
| @@ -208,51 +211,46 @@ local function install_rock_file(filename, opts) | |||
| 208 | end | 211 | end |
| 209 | 212 | ||
| 210 | --- Driver function for the "install" command. | 213 | --- Driver function for the "install" command. |
| 211 | -- @param name string: name of a binary rock. If an URL or pathname | 214 | -- If an URL or pathname to a binary rock is given, fetches and installs it. |
| 212 | -- to a binary rock is given, fetches and installs it. If a rockspec or a | 215 | -- If a rockspec or a source rock is given, forwards the request to the "build" |
| 213 | -- source rock is given, forwards the request to the "build" command. | 216 | -- command. |
| 214 | -- If a package name is given, forwards the request to "search" and, | 217 | -- If a package name is given, forwards the request to "search" and, |
| 215 | -- if returned a result, installs the matching rock. | 218 | -- if returned a result, installs the matching rock. |
| 216 | -- @param version string: When passing a package name, a version number | ||
| 217 | -- may also be given. | ||
| 218 | -- @return boolean or (nil, string, exitcode): True if installation was | 219 | -- @return boolean or (nil, string, exitcode): True if installation was |
| 219 | -- successful, nil and an error message otherwise. exitcode is optionally returned. | 220 | -- successful, nil and an error message otherwise. exitcode is optionally returned. |
| 220 | function install.command(flags, name, version) | 221 | function install.command(args) |
| 221 | if type(name) ~= "string" then | 222 | args.rock = util.adjust_name_and_namespace(args.rock, args) |
| 222 | return nil, "Argument missing. "..util.see_help("install") | ||
| 223 | end | ||
| 224 | |||
| 225 | name = util.adjust_name_and_namespace(name, flags) | ||
| 226 | 223 | ||
| 227 | local ok, err = fs.check_command_permissions(flags) | 224 | local ok, err = fs.check_command_permissions(args) |
| 228 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end | 225 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end |
| 229 | 226 | ||
| 230 | if name:match("%.rockspec$") or name:match("%.src%.rock$") then | 227 | if args.rock:match("%.rockspec$") or args.rock:match("%.src%.rock$") then |
| 231 | local build = require("luarocks.cmd.build") | 228 | local build = require("luarocks.cmd.build") |
| 232 | return build.command(flags, name) | 229 | return build.command(args) |
| 233 | elseif name:match("%.rock$") then | 230 | elseif args.rock:match("%.rock$") then |
| 234 | local deps_mode = deps.get_deps_mode(flags) | 231 | local deps_mode = deps.get_deps_mode(args) |
| 235 | local opts = install.opts({ | 232 | local opts = install.opts({ |
| 236 | namespace = flags["namespace"], | 233 | namespace = args.namespace, |
| 237 | keep = not not flags["keep"], | 234 | keep = not not args.keep, |
| 238 | force = not not flags["force"], | 235 | force = not not args.force, |
| 239 | force_fast = not not flags["force-fast"], | 236 | force_fast = not not args.force_fast, |
| 240 | no_doc = not not flags["no-doc"], | 237 | no_doc = not not args.no_doc, |
| 241 | deps_mode = deps_mode, | 238 | deps_mode = deps_mode, |
| 242 | verify = not not flags["verify"], | 239 | verify = not not args.verify, |
| 243 | }) | 240 | }) |
| 244 | if flags["only-deps"] then | 241 | if args.only_deps then |
| 245 | return install_rock_file_deps(name, opts) | 242 | return install_rock_file_deps(args.rock, opts) |
| 246 | else | 243 | else |
| 247 | return install_rock_file(name, opts) | 244 | return install_rock_file(args.rock, opts) |
| 248 | end | 245 | end |
| 249 | else | 246 | else |
| 250 | local url, err = search.find_suitable_rock(queries.new(name:lower(), version), true) | 247 | local url, err = search.find_suitable_rock(queries.new(args.rock:lower(), args.version), true) |
| 251 | if not url then | 248 | if not url then |
| 252 | return nil, err | 249 | return nil, err |
| 253 | end | 250 | end |
| 254 | util.printout("Installing "..url) | 251 | util.printout("Installing "..url) |
| 255 | return install.command(flags, url) | 252 | args.rock = url |
| 253 | return install.command(args) | ||
| 256 | end | 254 | end |
| 257 | end | 255 | end |
| 258 | 256 | ||
diff --git a/src/luarocks/cmd/lint.lua b/src/luarocks/cmd/lint.lua index c9ea45ea..20c842ff 100644 --- a/src/luarocks/cmd/lint.lua +++ b/src/luarocks/cmd/lint.lua | |||
| @@ -7,24 +7,21 @@ local util = require("luarocks.util") | |||
| 7 | local download = require("luarocks.download") | 7 | local download = require("luarocks.download") |
| 8 | local fetch = require("luarocks.fetch") | 8 | local fetch = require("luarocks.fetch") |
| 9 | 9 | ||
| 10 | lint.help_summary = "Check syntax of a rockspec." | 10 | function lint.add_to_parser(parser) |
| 11 | lint.help_arguments = "<rockspec>" | 11 | local cmd = parser:command("lint", "Check syntax of a rockspec.\n\n".. |
| 12 | lint.help = [[ | 12 | "Returns success if the text of the rockspec is syntactically correct, else failure.", |
| 13 | This is a utility function that checks the syntax of a rockspec. | 13 | util.see_also()) |
| 14 | 14 | :summary("Check syntax of a rockspec.") | |
| 15 | It returns success or failure if the text of a rockspec is | 15 | |
| 16 | syntactically correct. | 16 | cmd:argument("rockspec", "The rockspec to check.") |
| 17 | ]] | 17 | end |
| 18 | 18 | ||
| 19 | function lint.command(flags, input) | 19 | function lint.command(args) |
| 20 | if not input then | 20 | |
| 21 | return nil, "Argument missing. "..util.see_help("lint") | 21 | local filename = args.rockspec |
| 22 | end | 22 | if not filename:match(".rockspec$") then |
| 23 | |||
| 24 | local filename = input | ||
| 25 | if not input:match(".rockspec$") then | ||
| 26 | local err | 23 | local err |
| 27 | filename, err = download.download("rockspec", input:lower()) | 24 | filename, err = download.download("rockspec", filename:lower()) |
| 28 | if not filename then | 25 | if not filename then |
| 29 | return nil, err | 26 | return nil, err |
| 30 | end | 27 | end |
diff --git a/src/luarocks/cmd/list.lua b/src/luarocks/cmd/list.lua index 5e5cfac8..cac5cd8a 100644 --- a/src/luarocks/cmd/list.lua +++ b/src/luarocks/cmd/list.lua | |||
| @@ -10,16 +10,18 @@ local cfg = require("luarocks.core.cfg") | |||
| 10 | local util = require("luarocks.util") | 10 | local util = require("luarocks.util") |
| 11 | local path = require("luarocks.path") | 11 | local path = require("luarocks.path") |
| 12 | 12 | ||
| 13 | list.help_summary = "List currently installed rocks." | 13 | function list.add_to_parser(parser) |
| 14 | list.help_arguments = "[--porcelain] <filter>" | 14 | local cmd = parser:command("list", "List currently installed rocks.", util.see_also()) |
| 15 | list.help = [[ | ||
| 16 | <filter> is a substring of a rock name to filter by. | ||
| 17 | 15 | ||
| 18 | --outdated List only rocks for which there is a | 16 | cmd:argument("filter", "A substring of a rock name to filter by.") |
| 19 | higher version available in the rocks server. | 17 | :args("?") |
| 18 | cmd:argument("version", "Rock version to filter by.") | ||
| 19 | :args("?") | ||
| 20 | 20 | ||
| 21 | --porcelain Produce machine-friendly output. | 21 | cmd:flag("--outdated", "List only rocks for which there is a higher ".. |
| 22 | ]] | 22 | "version available in the rocks server.") |
| 23 | cmd:flag("--porcelain", "Produce machine-friendly output.") | ||
| 24 | end | ||
| 23 | 25 | ||
| 24 | local function check_outdated(trees, query) | 26 | local function check_outdated(trees, query) |
| 25 | local results_installed = {} | 27 | local results_installed = {} |
| @@ -65,20 +67,18 @@ local function list_outdated(trees, query, porcelain) | |||
| 65 | end | 67 | end |
| 66 | 68 | ||
| 67 | --- Driver function for "list" command. | 69 | --- Driver function for "list" command. |
| 68 | -- @param filter string or nil: A substring of a rock name to filter by. | ||
| 69 | -- @param version string or nil: a version may also be passed. | ||
| 70 | -- @return boolean: True if succeeded, nil on errors. | 70 | -- @return boolean: True if succeeded, nil on errors. |
| 71 | function list.command(flags, filter, version) | 71 | function list.command(args) |
| 72 | local query = queries.new(filter and filter:lower() or "", version, true) | 72 | local query = queries.new(args.filter and args.filter:lower() or "", args.version, true) |
| 73 | local trees = cfg.rocks_trees | 73 | local trees = cfg.rocks_trees |
| 74 | local title = "Rocks installed for Lua "..cfg.lua_version | 74 | local title = "Rocks installed for Lua "..cfg.lua_version |
| 75 | if flags["tree"] then | 75 | if args.tree then |
| 76 | trees = { flags["tree"] } | 76 | trees = { args.tree } |
| 77 | title = title .. " in " .. flags["tree"] | 77 | title = title .. " in " .. args.tree |
| 78 | end | 78 | end |
| 79 | 79 | ||
| 80 | if flags["outdated"] then | 80 | if args.outdated then |
| 81 | return list_outdated(trees, query, flags["porcelain"]) | 81 | return list_outdated(trees, query, args.porcelain) |
| 82 | end | 82 | end |
| 83 | 83 | ||
| 84 | local results = {} | 84 | local results = {} |
| @@ -88,8 +88,8 @@ function list.command(flags, filter, version) | |||
| 88 | util.warning(err) | 88 | util.warning(err) |
| 89 | end | 89 | end |
| 90 | end | 90 | end |
| 91 | util.title(title, flags["porcelain"]) | 91 | util.title(title, args.porcelain) |
| 92 | search.print_result_tree(results, flags["porcelain"]) | 92 | search.print_result_tree(results, args.porcelain) |
| 93 | return true | 93 | return true |
| 94 | end | 94 | end |
| 95 | 95 | ||
diff --git a/src/luarocks/cmd/make.lua b/src/luarocks/cmd/make.lua index 4d813864..480ec48d 100644 --- a/src/luarocks/cmd/make.lua +++ b/src/luarocks/cmd/make.lua | |||
| @@ -16,58 +16,61 @@ local deps = require("luarocks.deps") | |||
| 16 | local writer = require("luarocks.manif.writer") | 16 | local writer = require("luarocks.manif.writer") |
| 17 | local cmd = require("luarocks.cmd") | 17 | local cmd = require("luarocks.cmd") |
| 18 | 18 | ||
| 19 | make.help_summary = "Compile package in current directory using a rockspec." | 19 | function make.cmd_options(parser) |
| 20 | make.help_arguments = "[--pack-binary-rock] [<rockspec>]" | 20 | parser:flag("--pack-binary-rock", "Do not install rock. Instead, produce a ".. |
| 21 | make.help = [[ | 21 | ".rock file with the contents of compilation in the current directory.") |
| 22 | Builds sources in the current directory, but unlike "build", | 22 | parser:flag("--keep", "Do not remove previously installed versions of the ".. |
| 23 | it does not fetch sources, etc., assuming everything is | 23 | "rock after building a new one. This behavior can be made permanent by ".. |
| 24 | available in the current directory. If no argument is given, | 24 | "setting keep_other_versions=true in the configuration file.") |
| 25 | it looks for a rockspec in the current directory and in "rockspec/" | 25 | parser:flag("--force", "If --keep is not specified, force removal of ".. |
| 26 | and "rockspecs/" subdirectories, picking the rockspec with newest version | 26 | "previously installed versions if it would break dependencies.") |
| 27 | or without version name. If rockspecs for different rocks are found | 27 | parser:flag("--force-fast", "Like --force, but performs a forced removal ".. |
| 28 | or there are several rockspecs without version, you must specify which to use, | 28 | "without reporting dependency issues.") |
| 29 | parser:option("--branch", "Override the `source.branch` field in the loaded ".. | ||
| 30 | "rockspec. Allows to specify a different branch to fetch. Particularly ".. | ||
| 31 | 'for "dev" rocks.') | ||
| 32 | :argname("<name>") | ||
| 33 | parser:flag("--verify", "Verify signature of the rockspec or src.rock being ".. | ||
| 34 | "built. If the rockspec or src.rock is being downloaded, LuaRocks will ".. | ||
| 35 | "attempt to download the signature as well. Otherwise, the signature ".. | ||
| 36 | "file should be already available locally in the same directory.\n".. | ||
| 37 | "You need the signer’s public key in your local keyring for this ".. | ||
| 38 | "option to work properly.") | ||
| 39 | parser:flag("--sign", "To be used with --pack-binary-rock. Also produce a ".. | ||
| 40 | "signature file for the generated .rock file.") | ||
| 41 | util.deps_mode_option(parser) | ||
| 42 | end | ||
| 43 | |||
| 44 | function make.add_to_parser(parser) | ||
| 45 | local cmd = parser:command("make", [[ | ||
| 46 | Builds sources in the current directory, but unlike "build", it does not fetch | ||
| 47 | sources, etc., assuming everything is available in the current directory. If no | ||
| 48 | argument is given, it looks for a rockspec in the current directory and in | ||
| 49 | "rockspec/" and "rockspecs/" subdirectories, picking the rockspec with newest | ||
| 50 | version or without version name. If rockspecs for different rocks are found or | ||
| 51 | there are several rockspecs without version, you must specify which to use, | ||
| 29 | through the command-line. | 52 | through the command-line. |
| 30 | 53 | ||
| 31 | This command is useful as a tool for debugging rockspecs. | 54 | This command is useful as a tool for debugging rockspecs. |
| 32 | To install rocks, you'll normally want to use the "install" and | 55 | To install rocks, you'll normally want to use the "install" and "build" |
| 33 | "build" commands. See the help on those for details. | 56 | commands. See the help on those for details. |
| 34 | 57 | ||
| 35 | NB: Use `luarocks install` with the `--only-deps` flag if you want to install | 58 | NB: Use `luarocks install` with the `--only-deps` flag if you want to install |
| 36 | only dependencies of the rockspec (see `luarocks help install`). | 59 | only dependencies of the rockspec (see `luarocks help install`). |
| 60 | ]], util.see_also()) | ||
| 61 | :summary("Compile package in current directory using a rockspec.") | ||
| 37 | 62 | ||
| 38 | --pack-binary-rock Do not install rock. Instead, produce a .rock file | 63 | cmd:argument("rockspec", "Rockspec for the rock to build.") |
| 39 | with the contents of compilation in the current | 64 | :args("?") |
| 40 | directory. | ||
| 41 | |||
| 42 | --keep Do not remove previously installed versions of the | ||
| 43 | rock after installing a new one. This behavior can | ||
| 44 | be made permanent by setting keep_other_versions=true | ||
| 45 | in the configuration file. | ||
| 46 | |||
| 47 | --branch=<name> Override the `source.branch` field in the loaded | ||
| 48 | rockspec. Allows to specify a different branch to | ||
| 49 | fetch. Particularly for "dev" rocks. | ||
| 50 | 65 | ||
| 51 | --verify Verify signature of the rockspec or src.rock being | 66 | make.cmd_options(cmd) |
| 52 | built. If the rockspec or src.rock is being downloaded, | 67 | end |
| 53 | LuaRocks will attempt to download the signature as well. | ||
| 54 | Otherwise, the signature file should be already | ||
| 55 | available locally in the same directory. | ||
| 56 | You need the signer’s public key in your local | ||
| 57 | keyring for this option to work properly. | ||
| 58 | |||
| 59 | --sign To be used with --pack-binary-rock. Also produce | ||
| 60 | a signature file for the generated .rock file. | ||
| 61 | |||
| 62 | ]] | ||
| 63 | 68 | ||
| 64 | --- Driver function for "make" command. | 69 | --- Driver function for "make" command. |
| 65 | -- @param name string: A local rockspec. | ||
| 66 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an | 70 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an |
| 67 | -- error message otherwise. exitcode is optionally returned. | 71 | -- error message otherwise. exitcode is optionally returned. |
| 68 | function make.command(flags, rockspec_filename) | 72 | function make.command(args) |
| 69 | assert(type(rockspec_filename) == "string" or not rockspec_filename) | 73 | local rockspec_filename = args.rockspec |
| 70 | |||
| 71 | if not rockspec_filename then | 74 | if not rockspec_filename then |
| 72 | local err | 75 | local err |
| 73 | rockspec_filename, err = util.get_default_rockspec() | 76 | rockspec_filename, err = util.get_default_rockspec() |
| @@ -84,39 +87,39 @@ function make.command(flags, rockspec_filename) | |||
| 84 | return nil, err | 87 | return nil, err |
| 85 | end | 88 | end |
| 86 | 89 | ||
| 87 | local name = util.adjust_name_and_namespace(rockspec.name, flags) | 90 | local name = util.adjust_name_and_namespace(rockspec.name, args) |
| 88 | 91 | ||
| 89 | local opts = build.opts({ | 92 | local opts = build.opts({ |
| 90 | need_to_fetch = false, | 93 | need_to_fetch = false, |
| 91 | minimal_mode = true, | 94 | minimal_mode = true, |
| 92 | deps_mode = deps.get_deps_mode(flags), | 95 | deps_mode = deps.get_deps_mode(args), |
| 93 | build_only_deps = false, | 96 | build_only_deps = false, |
| 94 | namespace = flags["namespace"], | 97 | namespace = args.namespace, |
| 95 | branch = not not flags["branch"], | 98 | branch = not not args.branch, |
| 96 | verify = not not flags["verify"], | 99 | verify = not not args.verify, |
| 97 | }) | 100 | }) |
| 98 | 101 | ||
| 99 | if flags["sign"] and not flags["pack-binary-rock"] then | 102 | if args.sign and not args.pack_binary_rock then |
| 100 | return nil, "In the make command, --sign is meant to be used only with --pack-binary-rock" | 103 | return nil, "In the make command, --sign is meant to be used only with --pack-binary-rock" |
| 101 | end | 104 | end |
| 102 | 105 | ||
| 103 | if flags["pack-binary-rock"] then | 106 | if args.pack_binary_rock then |
| 104 | return pack.pack_binary_rock(name, rockspec.version, flags["sign"], function() | 107 | return pack.pack_binary_rock(name, rockspec.version, args.sign, function() |
| 105 | return build.build_rockspec(rockspec, opts) | 108 | return build.build_rockspec(rockspec, opts) |
| 106 | end) | 109 | end) |
| 107 | else | 110 | else |
| 108 | local ok, err = fs.check_command_permissions(flags) | 111 | local ok, err = fs.check_command_permissions(args) |
| 109 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end | 112 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end |
| 110 | ok, err = build.build_rockspec(rockspec, opts) | 113 | ok, err = build.build_rockspec(rockspec, opts) |
| 111 | if not ok then return nil, err end | 114 | if not ok then return nil, err end |
| 112 | local name, version = ok, err | 115 | local name, version = ok, err |
| 113 | 116 | ||
| 114 | if (not flags["keep"]) and not cfg.keep_other_versions then | 117 | if (not args.keep) and not cfg.keep_other_versions then |
| 115 | local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) | 118 | local ok, err = remove.remove_other_versions(name, version, args.force, args.force_fast) |
| 116 | if not ok then util.printerr(err) end | 119 | if not ok then util.printerr(err) end |
| 117 | end | 120 | end |
| 118 | 121 | ||
| 119 | writer.check_dependencies(nil, deps.get_deps_mode(flags)) | 122 | writer.check_dependencies(nil, deps.get_deps_mode(args)) |
| 120 | return name, version | 123 | return name, version |
| 121 | end | 124 | end |
| 122 | end | 125 | end |
diff --git a/src/luarocks/cmd/new_version.lua b/src/luarocks/cmd/new_version.lua index 19b5fa1e..62fb08f6 100644 --- a/src/luarocks/cmd/new_version.lua +++ b/src/luarocks/cmd/new_version.lua | |||
| @@ -11,35 +11,46 @@ local fs = require("luarocks.fs") | |||
| 11 | local dir = require("luarocks.dir") | 11 | local dir = require("luarocks.dir") |
| 12 | local type_rockspec = require("luarocks.type.rockspec") | 12 | local type_rockspec = require("luarocks.type.rockspec") |
| 13 | 13 | ||
| 14 | new_version.help_summary = "Auto-write a rockspec for a new version of a rock." | 14 | function new_version.add_to_parser(parser) |
| 15 | new_version.help_arguments = "[--tag=<tag>] [--dir=<path>] [<package>|<rockspec>] [<new_version>] [<new_url>]" | 15 | local cmd = parser:command("new_version", [[ |
| 16 | new_version.help = [[ | 16 | This is a utility function that writes a new rockspec, updating data from a |
| 17 | This is a utility function that writes a new rockspec, updating data | 17 | previous one. |
| 18 | from a previous one. | 18 | |
| 19 | 19 | If a package name is given, it downloads the latest rockspec from the default | |
| 20 | If a package name is given, it downloads the latest rockspec from the | 20 | server. If a rockspec is given, it uses it instead. If no argument is given, it |
| 21 | default server. If a rockspec is given, it uses it instead. If no argument | 21 | looks for a rockspec same way 'luarocks make' does. |
| 22 | is given, it looks for a rockspec same way 'luarocks make' does. | 22 | |
| 23 | 23 | If the version number is not given and tag is passed using --tag, it is used as | |
| 24 | If the version number is not given and tag is passed using --tag, | 24 | the version, with 'v' removed from beginning. Otherwise, it only increments the |
| 25 | it is used as the version, with 'v' removed from beginning. | 25 | revision number of the given (or downloaded) rockspec. |
| 26 | Otherwise, it only increments the revision number of the given | 26 | |
| 27 | (or downloaded) rockspec. | 27 | If a URL is given, it replaces the one from the old rockspec with the given URL. |
| 28 | 28 | If a URL is not given and a new version is given, it tries to guess the new URL | |
| 29 | If a URL is given, it replaces the one from the old rockspec with the | 29 | by replacing occurrences of the version number in the URL or tag. It also tries |
| 30 | given URL. If a URL is not given and a new version is given, it tries | 30 | to download the new URL to determine the new MD5 checksum. |
| 31 | to guess the new URL by replacing occurrences of the version number | 31 | |
| 32 | in the URL or tag. It also tries to download the new URL to determine | 32 | If a tag is given, it replaces the one from the old rockspec. If there is an old |
| 33 | the new MD5 checksum. | 33 | tag but no new one passed, it is guessed in the same way URL is. |
| 34 | |||
| 35 | If a tag is given, it replaces the one from the old rockspec. If there is | ||
| 36 | an old tag but no new one passed, it is guessed in the same way URL is. | ||
| 37 | 34 | ||
| 38 | If a directory is not given, it defaults to the current directory. | 35 | If a directory is not given, it defaults to the current directory. |
| 39 | 36 | ||
| 40 | WARNING: it writes the new rockspec to the given directory, | 37 | WARNING: it writes the new rockspec to the given directory, overwriting the file |
| 41 | overwriting the file if it already exists. | 38 | if it already exists.]], util.see_also()) |
| 42 | ]] | 39 | :summary("Auto-write a rockspec for a new version of a rock.") |
| 40 | |||
| 41 | parser:command("new-version"):hidden(true):action(function(args) args.command = "new_version" end) | ||
| 42 | |||
| 43 | cmd:argument("rock", "Package name or rockspec.") | ||
| 44 | :args("?") | ||
| 45 | cmd:argument("new_version", "New version of the rock.") | ||
| 46 | :args("?") | ||
| 47 | cmd:argument("new_url", "New URL of the rock.") | ||
| 48 | :args("?") | ||
| 49 | |||
| 50 | cmd:option("--dir", "Output directory for the new rockspec.") | ||
| 51 | cmd:option("--tag", "New SCM tag.") | ||
| 52 | end | ||
| 53 | |||
| 43 | 54 | ||
| 44 | local function try_replace(tbl, field, old, new) | 55 | local function try_replace(tbl, field, old, new) |
| 45 | if not tbl[field] then | 56 | if not tbl[field] then |
| @@ -126,24 +137,23 @@ local function update_source_section(out_rs, url, tag, old_ver, new_ver) | |||
| 126 | return true | 137 | return true |
| 127 | end | 138 | end |
| 128 | 139 | ||
| 129 | function new_version.command(flags, input, version, url) | 140 | function new_version.command(args) |
| 130 | if not input then | 141 | if not args.rock then |
| 131 | local err | 142 | local err |
| 132 | input, err = util.get_default_rockspec() | 143 | args.rock, err = util.get_default_rockspec() |
| 133 | if not input then | 144 | if not args.rock then |
| 134 | return nil, err | 145 | return nil, err |
| 135 | end | 146 | end |
| 136 | end | 147 | end |
| 137 | assert(type(input) == "string") | ||
| 138 | 148 | ||
| 139 | local filename, err | 149 | local filename, err |
| 140 | if input:match("rockspec$") then | 150 | if args.rock:match("rockspec$") then |
| 141 | filename, err = fetch.fetch_url(input) | 151 | filename, err = fetch.fetch_url(args.rock) |
| 142 | if not filename then | 152 | if not filename then |
| 143 | return nil, err | 153 | return nil, err |
| 144 | end | 154 | end |
| 145 | else | 155 | else |
| 146 | filename, err = download.download("rockspec", input:lower()) | 156 | filename, err = download.download("rockspec", args.rock:lower()) |
| 147 | if not filename then | 157 | if not filename then |
| 148 | return nil, err | 158 | return nil, err |
| 149 | end | 159 | end |
| @@ -157,20 +167,20 @@ function new_version.command(flags, input, version, url) | |||
| 157 | local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$") | 167 | local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$") |
| 158 | local new_ver, new_rev | 168 | local new_ver, new_rev |
| 159 | 169 | ||
| 160 | if flags.tag and not version then | 170 | if args.tag and not args.new_version then |
| 161 | version = flags.tag:gsub("^v", "") | 171 | args.new_version = args.tag:gsub("^v", "") |
| 162 | end | 172 | end |
| 163 | 173 | ||
| 164 | local out_dir | 174 | local out_dir |
| 165 | if flags.dir then | 175 | if args.dir then |
| 166 | out_dir = dir.normalize(flags.dir) | 176 | out_dir = dir.normalize(args.dir) |
| 167 | end | 177 | end |
| 168 | 178 | ||
| 169 | if version then | 179 | if args.new_version then |
| 170 | new_ver, new_rev = version:match("(.*)%-(%d+)$") | 180 | new_ver, new_rev = args.new_version:match("(.*)%-(%d+)$") |
| 171 | new_rev = tonumber(new_rev) | 181 | new_rev = tonumber(new_rev) |
| 172 | if not new_rev then | 182 | if not new_rev then |
| 173 | new_ver = version | 183 | new_ver = args.new_version |
| 174 | new_rev = 1 | 184 | new_rev = 1 |
| 175 | end | 185 | end |
| 176 | else | 186 | else |
| @@ -183,7 +193,7 @@ function new_version.command(flags, input, version, url) | |||
| 183 | local out_name = out_rs.package:lower() | 193 | local out_name = out_rs.package:lower() |
| 184 | out_rs.version = new_rockver.."-"..new_rev | 194 | out_rs.version = new_rockver.."-"..new_rev |
| 185 | 195 | ||
| 186 | local ok, err = update_source_section(out_rs, url, flags.tag, old_ver, new_ver) | 196 | local ok, err = update_source_section(out_rs, args.new_url, args.tag, old_ver, new_ver) |
| 187 | if not ok then return nil, err end | 197 | if not ok then return nil, err end |
| 188 | 198 | ||
| 189 | if out_rs.build and out_rs.build.type == "module" then | 199 | if out_rs.build and out_rs.build.type == "module" then |
diff --git a/src/luarocks/cmd/pack.lua b/src/luarocks/cmd/pack.lua index 7781a3bd..fde8f875 100644 --- a/src/luarocks/cmd/pack.lua +++ b/src/luarocks/cmd/pack.lua | |||
| @@ -8,39 +8,30 @@ local pack = require("luarocks.pack") | |||
| 8 | local signing = require("luarocks.signing") | 8 | local signing = require("luarocks.signing") |
| 9 | local queries = require("luarocks.queries") | 9 | local queries = require("luarocks.queries") |
| 10 | 10 | ||
| 11 | cmd_pack.help_summary = "Create a rock, packing sources or binaries." | 11 | function cmd_pack.add_to_parser(parser) |
| 12 | cmd_pack.help_arguments = "{<rockspec>|<name> [<version>]}" | 12 | local cmd = parser:command("pack", "Create a rock, packing sources or binaries.", util.see_also()) |
| 13 | cmd_pack.help = [[ | ||
| 14 | --sign Produce a signature file as well. | ||
| 15 | 13 | ||
| 16 | Argument may be a rockspec file, for creating a source rock, | 14 | cmd:argument("rock", "A rockspec file, for creating a source rock, or the ".. |
| 17 | or the name of an installed package, for creating a binary rock. | 15 | "name of an installed package, for creating a binary rock.") |
| 18 | In the latter case, the app version may be given as a second | 16 | cmd:argument("version", "A version may be given if the first argument is a rock name.") |
| 19 | argument. | 17 | :args("?") |
| 20 | ]] | 18 | |
| 19 | cmd:flag("--sign", "Produce a signature file as well.") | ||
| 20 | end | ||
| 21 | 21 | ||
| 22 | --- Driver function for the "pack" command. | 22 | --- Driver function for the "pack" command. |
| 23 | -- @param arg string: may be a rockspec file, for creating a source rock, | ||
| 24 | -- or the name of an installed package, for creating a binary rock. | ||
| 25 | -- @param version string or nil: if the name of a package is given, a | ||
| 26 | -- version may also be passed. | ||
| 27 | -- @return boolean or (nil, string): true if successful or nil followed | 23 | -- @return boolean or (nil, string): true if successful or nil followed |
| 28 | -- by an error message. | 24 | -- by an error message. |
| 29 | function cmd_pack.command(flags, arg, version) | 25 | function cmd_pack.command(args) |
| 30 | assert(type(version) == "string" or not version) | ||
| 31 | if type(arg) ~= "string" then | ||
| 32 | return nil, "Argument missing. "..util.see_help("pack") | ||
| 33 | end | ||
| 34 | |||
| 35 | local file, err | 26 | local file, err |
| 36 | if arg:match(".*%.rockspec") then | 27 | if args.rock:match(".*%.rockspec") then |
| 37 | file, err = pack.pack_source_rock(arg) | 28 | file, err = pack.pack_source_rock(args.rock) |
| 38 | else | 29 | else |
| 39 | local name = util.adjust_name_and_namespace(arg, flags) | 30 | local name = util.adjust_name_and_namespace(args.rock, args) |
| 40 | local query = queries.new(name, version) | 31 | local query = queries.new(name, args.version) |
| 41 | file, err = pack.pack_installed_rock(query, flags["tree"]) | 32 | file, err = pack.pack_installed_rock(query, args.tree) |
| 42 | end | 33 | end |
| 43 | return pack.report_and_sign_local_file(file, err, flags["sign"]) | 34 | return pack.report_and_sign_local_file(file, err, args.sign) |
| 44 | end | 35 | end |
| 45 | 36 | ||
| 46 | return cmd_pack | 37 | return cmd_pack |
diff --git a/src/luarocks/cmd/path.lua b/src/luarocks/cmd/path.lua index bb383ad9..b1da4c0b 100644 --- a/src/luarocks/cmd/path.lua +++ b/src/luarocks/cmd/path.lua | |||
| @@ -7,48 +7,45 @@ local util = require("luarocks.util") | |||
| 7 | local cfg = require("luarocks.core.cfg") | 7 | local cfg = require("luarocks.core.cfg") |
| 8 | local fs = require("luarocks.fs") | 8 | local fs = require("luarocks.fs") |
| 9 | 9 | ||
| 10 | path_cmd.help_summary = "Return the currently configured package path." | 10 | function path_cmd.add_to_parser(parser) |
| 11 | path_cmd.help_arguments = "" | 11 | local cmd = parser:command("path", [[ |
| 12 | path_cmd.help = [[ | ||
| 13 | Returns the package path currently configured for this installation | 12 | Returns the package path currently configured for this installation |
| 14 | of LuaRocks, formatted as shell commands to update LUA_PATH and LUA_CPATH. | 13 | of LuaRocks, formatted as shell commands to update LUA_PATH and LUA_CPATH. |
| 15 | 14 | ||
| 16 | --no-bin Do not export the PATH variable | ||
| 17 | |||
| 18 | --append Appends the paths to the existing paths. Default is to prefix | ||
| 19 | the LR paths to the existing paths. | ||
| 20 | |||
| 21 | --lr-path Exports the Lua path (not formatted as shell command) | ||
| 22 | |||
| 23 | --lr-cpath Exports the Lua cpath (not formatted as shell command) | ||
| 24 | |||
| 25 | --lr-bin Exports the system path (not formatted as shell command) | ||
| 26 | |||
| 27 | |||
| 28 | On Unix systems, you may run: | 15 | On Unix systems, you may run: |
| 29 | eval `luarocks path` | 16 | eval `luarocks path` |
| 30 | And on Windows: | 17 | And on Windows: |
| 31 | luarocks path > "%temp%\_lrp.bat" && call "%temp%\_lrp.bat" && del "%temp%\_lrp.bat" | 18 | luarocks path > "%temp%\_lrp.bat" && call "%temp%\_lrp.bat" && del "%temp%\_lrp.bat"]], |
| 32 | ]] | 19 | util.see_also()) |
| 20 | :summary("Return the currently configured package path.") | ||
| 21 | |||
| 22 | cmd:flag("--no-bin", "Do not export the PATH variable.") | ||
| 23 | cmd:flag("--append", "Appends the paths to the existing paths. Default is ".. | ||
| 24 | "to prefix the LR paths to the existing paths.") | ||
| 25 | cmd:flag("--lr-path", "Exports the Lua path (not formatted as shell command).") | ||
| 26 | cmd:flag("--lr-cpath", "Exports the Lua cpath (not formatted as shell command).") | ||
| 27 | cmd:flag("--lr-bin", "Exports the system path (not formatted as shell command).") | ||
| 28 | cmd:flag("--bin"):hidden(true) | ||
| 29 | end | ||
| 33 | 30 | ||
| 34 | --- Driver function for "path" command. | 31 | --- Driver function for "path" command. |
| 35 | -- @return boolean This function always succeeds. | 32 | -- @return boolean This function always succeeds. |
| 36 | function path_cmd.command(flags) | 33 | function path_cmd.command(args) |
| 37 | local lr_path, lr_cpath, lr_bin = cfg.package_paths(flags["tree"]) | 34 | local lr_path, lr_cpath, lr_bin = cfg.package_paths(args.tree) |
| 38 | local path_sep = cfg.export_path_separator | 35 | local path_sep = cfg.export_path_separator |
| 39 | 36 | ||
| 40 | if flags["lr-path"] then | 37 | if args.lr_path then |
| 41 | util.printout(util.cleanup_path(lr_path, ';', cfg.lua_version)) | 38 | util.printout(util.cleanup_path(lr_path, ';', cfg.lua_version)) |
| 42 | return true | 39 | return true |
| 43 | elseif flags["lr-cpath"] then | 40 | elseif args.lr_cpath then |
| 44 | util.printout(util.cleanup_path(lr_cpath, ';', cfg.lua_version)) | 41 | util.printout(util.cleanup_path(lr_cpath, ';', cfg.lua_version)) |
| 45 | return true | 42 | return true |
| 46 | elseif flags["lr-bin"] then | 43 | elseif args.lr_bin then |
| 47 | util.printout(util.cleanup_path(lr_bin, path_sep)) | 44 | util.printout(util.cleanup_path(lr_bin, path_sep)) |
| 48 | return true | 45 | return true |
| 49 | end | 46 | end |
| 50 | 47 | ||
| 51 | if flags["append"] then | 48 | if args.append then |
| 52 | lr_path = package.path .. ";" .. lr_path | 49 | lr_path = package.path .. ";" .. lr_path |
| 53 | lr_cpath = package.cpath .. ";" .. lr_cpath | 50 | lr_cpath = package.cpath .. ";" .. lr_cpath |
| 54 | lr_bin = os.getenv("PATH") .. path_sep .. lr_bin | 51 | lr_bin = os.getenv("PATH") .. path_sep .. lr_bin |
| @@ -60,10 +57,10 @@ function path_cmd.command(flags) | |||
| 60 | 57 | ||
| 61 | local lpath_var, lcpath_var = util.lua_path_variables() | 58 | local lpath_var, lcpath_var = util.lua_path_variables() |
| 62 | 59 | ||
| 63 | util.printout(fs.export_cmd(lpath_var, util.cleanup_path(lr_path, ';', cfg.lua_version, flags["append"]))) | 60 | util.printout(fs.export_cmd(lpath_var, util.cleanup_path(lr_path, ';', cfg.lua_version))) |
| 64 | util.printout(fs.export_cmd(lcpath_var, util.cleanup_path(lr_cpath, ';', cfg.lua_version, flags["append"]))) | 61 | util.printout(fs.export_cmd(lcpath_var, util.cleanup_path(lr_cpath, ';', cfg.lua_version))) |
| 65 | if not flags["no-bin"] then | 62 | if not args.no_bin then |
| 66 | util.printout(fs.export_cmd("PATH", util.cleanup_path(lr_bin, path_sep, nil, flags["append"]))) | 63 | util.printout(fs.export_cmd("PATH", util.cleanup_path(lr_bin, path_sep))) |
| 67 | end | 64 | end |
| 68 | return true | 65 | return true |
| 69 | end | 66 | end |
diff --git a/src/luarocks/cmd/purge.lua b/src/luarocks/cmd/purge.lua index 98b76a0f..b71baa7c 100644 --- a/src/luarocks/cmd/purge.lua +++ b/src/luarocks/cmd/purge.lua | |||
| @@ -15,24 +15,27 @@ local remove = require("luarocks.remove") | |||
| 15 | local queries = require("luarocks.queries") | 15 | local queries = require("luarocks.queries") |
| 16 | local cmd = require("luarocks.cmd") | 16 | local cmd = require("luarocks.cmd") |
| 17 | 17 | ||
| 18 | purge.help_summary = "Remove all installed rocks from a tree." | 18 | function purge.add_to_parser(parser) |
| 19 | purge.help_arguments = "--tree=<tree> [--old-versions]" | 19 | local cmd = parser:command("purge", [[ |
| 20 | purge.help = [[ | ||
| 21 | This command removes rocks en masse from a given tree. | 20 | This command removes rocks en masse from a given tree. |
| 22 | By default, it removes all rocks from a tree. | 21 | By default, it removes all rocks from a tree. |
| 23 | 22 | ||
| 24 | The --tree argument is mandatory: luarocks purge does not | 23 | The --tree option is mandatory: luarocks purge does not assume a default tree.]], |
| 25 | assume a default tree. | 24 | util.see_also()) |
| 25 | :summary("Remove all installed rocks from a tree.") | ||
| 26 | 26 | ||
| 27 | --old-versions Keep the highest-numbered version of each | 27 | cmd:flag("--old-versions", "Keep the highest-numbered version of each ".. |
| 28 | rock and remove the other ones. By default | 28 | "rock and remove the other ones. By default it only removes old ".. |
| 29 | it only removes old versions if they are | 29 | "versions if they are not needed as dependencies. This can be ".. |
| 30 | not needed as dependencies. This can be | 30 | "overridden with the flag --force.") |
| 31 | overridden with the flag --force. | 31 | cmd:flag("--force", "If --old-versions is specified, force removal of ".. |
| 32 | ]] | 32 | "previously installed versions if it would break dependencies.") |
| 33 | cmd:flag("--force-fast", "Like --force, but performs a forced removal ".. | ||
| 34 | "without reporting dependency issues.") | ||
| 35 | end | ||
| 33 | 36 | ||
| 34 | function purge.command(flags) | 37 | function purge.command(args) |
| 35 | local tree = flags["tree"] | 38 | local tree = args.tree |
| 36 | 39 | ||
| 37 | if type(tree) ~= "string" then | 40 | if type(tree) ~= "string" then |
| 38 | return nil, "The --tree argument is mandatory. "..util.see_help("purge") | 41 | return nil, "The --tree argument is mandatory. "..util.see_help("purge") |
| @@ -43,21 +46,21 @@ function purge.command(flags) | |||
| 43 | return nil, "Directory not found: "..tree | 46 | return nil, "Directory not found: "..tree |
| 44 | end | 47 | end |
| 45 | 48 | ||
| 46 | local ok, err = fs.check_command_permissions(flags) | 49 | local ok, err = fs.check_command_permissions(args) |
| 47 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end | 50 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end |
| 48 | 51 | ||
| 49 | search.local_manifest_search(results, path.rocks_dir(tree), queries.all()) | 52 | search.local_manifest_search(results, path.rocks_dir(tree), queries.all()) |
| 50 | 53 | ||
| 51 | local sort = function(a,b) return vers.compare_versions(b,a) end | 54 | local sort = function(a,b) return vers.compare_versions(b,a) end |
| 52 | if flags["old-versions"] then | 55 | if args.old_versions then |
| 53 | sort = vers.compare_versions | 56 | sort = vers.compare_versions |
| 54 | end | 57 | end |
| 55 | 58 | ||
| 56 | for package, versions in util.sortedpairs(results) do | 59 | for package, versions in util.sortedpairs(results) do |
| 57 | for version, _ in util.sortedpairs(versions, sort) do | 60 | for version, _ in util.sortedpairs(versions, sort) do |
| 58 | if flags["old-versions"] then | 61 | if args.old_versions then |
| 59 | util.printout("Keeping "..package.." "..version.."...") | 62 | util.printout("Keeping "..package.." "..version.."...") |
| 60 | local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"]) | 63 | local ok, err = remove.remove_other_versions(package, version, args.force, args.force_fast) |
| 61 | if not ok then | 64 | if not ok then |
| 62 | util.printerr(err) | 65 | util.printerr(err) |
| 63 | end | 66 | end |
diff --git a/src/luarocks/cmd/remove.lua b/src/luarocks/cmd/remove.lua index 5ddf7477..f29b0b7d 100644 --- a/src/luarocks/cmd/remove.lua +++ b/src/luarocks/cmd/remove.lua | |||
| @@ -14,38 +14,38 @@ local writer = require("luarocks.manif.writer") | |||
| 14 | local queries = require("luarocks.queries") | 14 | local queries = require("luarocks.queries") |
| 15 | local cmd = require("luarocks.cmd") | 15 | local cmd = require("luarocks.cmd") |
| 16 | 16 | ||
| 17 | cmd_remove.help_summary = "Uninstall a rock." | 17 | function cmd_remove.add_to_parser(parser) |
| 18 | cmd_remove.help_arguments = "[--force|--force-fast] <name> [<version>]" | 18 | local cmd = parser:command("remove", [[ |
| 19 | cmd_remove.help = [[ | 19 | Uninstall a rock. |
| 20 | Argument is the name of a rock to be uninstalled. | 20 | |
| 21 | If a version is not given, try to remove all versions at once. | 21 | If a version is not given, try to remove all versions at once. |
| 22 | Will only perform the removal if it does not break dependencies. | 22 | Will only perform the removal if it does not break dependencies. |
| 23 | To override this check and force the removal, use --force. | 23 | To override this check and force the removal, use --force or --force-fast.]], |
| 24 | To perform a forced removal without reporting dependency issues, | 24 | util.see_also()) |
| 25 | use --force-fast. | 25 | :summary("Uninstall a rock.") |
| 26 | |||
| 27 | cmd:argument("rock", "Name of the rock to be uninstalled.") | ||
| 28 | cmd:argument("version", "Version of the rock to uninstall.") | ||
| 29 | :args("?") | ||
| 26 | 30 | ||
| 27 | ]]..util.deps_mode_help() | 31 | cmd:flag("--force", "Force removal if it would break dependencies.") |
| 32 | cmd:flag("--force-fast", "Perform a forced removal without reporting dependency issues.") | ||
| 33 | util.deps_mode_option(cmd) | ||
| 34 | end | ||
| 28 | 35 | ||
| 29 | --- Driver function for the "remove" command. | 36 | --- Driver function for the "remove" command. |
| 30 | -- @param name string: name of a rock. If a version is given, refer to | ||
| 31 | -- a specific version; otherwise, try to remove all versions. | ||
| 32 | -- @param version string: When passing a package name, a version number | ||
| 33 | -- may also be given. | ||
| 34 | -- @return boolean or (nil, string, exitcode): True if removal was | 37 | -- @return boolean or (nil, string, exitcode): True if removal was |
| 35 | -- successful, nil and an error message otherwise. exitcode is optionally returned. | 38 | -- successful, nil and an error message otherwise. exitcode is optionally returned. |
| 36 | function cmd_remove.command(flags, name, version) | 39 | function cmd_remove.command(args) |
| 37 | if type(name) ~= "string" then | 40 | local name = util.adjust_name_and_namespace(args.rock, args) |
| 38 | return nil, "Argument missing. "..util.see_help("remove") | ||
| 39 | end | ||
| 40 | |||
| 41 | name = util.adjust_name_and_namespace(name, flags) | ||
| 42 | 41 | ||
| 43 | local deps_mode = flags["deps-mode"] or cfg.deps_mode | 42 | local deps_mode = args.deps_mode or cfg.deps_mode |
| 44 | 43 | ||
| 45 | local ok, err = fs.check_command_permissions(flags) | 44 | local ok, err = fs.check_command_permissions(args) |
| 46 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end | 45 | if not ok then return nil, err, cmd.errorcodes.PERMISSIONDENIED end |
| 47 | 46 | ||
| 48 | local rock_type = name:match("%.(rock)$") or name:match("%.(rockspec)$") | 47 | local rock_type = name:match("%.(rock)$") or name:match("%.(rockspec)$") |
| 48 | local version = args.version | ||
| 49 | local filename = name | 49 | local filename = name |
| 50 | if rock_type then | 50 | if rock_type then |
| 51 | name, version = path.parse_name(filename) | 51 | name, version = path.parse_name(filename) |
| @@ -59,12 +59,12 @@ function cmd_remove.command(flags, name, version) | |||
| 59 | return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir) | 59 | return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir) |
| 60 | end | 60 | end |
| 61 | 61 | ||
| 62 | local ok, err = remove.remove_search_results(results, name, deps_mode, flags["force"], flags["force-fast"]) | 62 | local ok, err = remove.remove_search_results(results, name, deps_mode, args.force, args.force_fast) |
| 63 | if not ok then | 63 | if not ok then |
| 64 | return nil, err | 64 | return nil, err |
| 65 | end | 65 | end |
| 66 | 66 | ||
| 67 | writer.check_dependencies(nil, deps.get_deps_mode(flags)) | 67 | writer.check_dependencies(nil, deps.get_deps_mode(args)) |
| 68 | return true | 68 | return true |
| 69 | end | 69 | end |
| 70 | 70 | ||
diff --git a/src/luarocks/cmd/search.lua b/src/luarocks/cmd/search.lua index 8f4d014e..f34cf7b9 100644 --- a/src/luarocks/cmd/search.lua +++ b/src/luarocks/cmd/search.lua | |||
| @@ -9,17 +9,22 @@ local search = require("luarocks.search") | |||
| 9 | local queries = require("luarocks.queries") | 9 | local queries = require("luarocks.queries") |
| 10 | local results = require("luarocks.results") | 10 | local results = require("luarocks.results") |
| 11 | 11 | ||
| 12 | cmd_search.help_summary = "Query the LuaRocks servers." | 12 | function cmd_search.add_to_parser(parser) |
| 13 | cmd_search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }" | 13 | local cmd = parser:command("search", "Query the LuaRocks servers.", util.see_also()) |
| 14 | cmd_search.help = [[ | 14 | |
| 15 | --source Return only rockspecs and source rocks, | 15 | cmd:argument("name", "Name of the rock to search for.") |
| 16 | to be used with the "build" command. | 16 | :args("?") |
| 17 | --binary Return only pure Lua and binary rocks (rocks that can be used | 17 | cmd:argument("version", "Rock version to search for.") |
| 18 | with the "install" command without requiring a C toolchain). | 18 | :args("?") |
| 19 | --all List all contents of the server that are suitable to | 19 | |
| 20 | this platform, do not filter by name. | 20 | cmd:flag("--source", "Return only rockspecs and source rocks, to be used ".. |
| 21 | --porcelain Return a machine readable format. | 21 | 'with the "build" command.') |
| 22 | ]] | 22 | cmd:flag("--binary", "Return only pure Lua and binary rocks (rocks that ".. |
| 23 | 'can be used with the "install" command without requiring a C toolchain).') | ||
| 24 | cmd:flag("--all", "List all contents of the server that are suitable to ".. | ||
| 25 | "this platform, do not filter by name.") | ||
| 26 | cmd:flag("--porcelain", "Return a machine readable format.") | ||
| 27 | end | ||
| 23 | 28 | ||
| 24 | --- Splits a list of search results into two lists, one for "source" results | 29 | --- Splits a list of search results into two lists, one for "source" results |
| 25 | -- to be used with the "build" command, and one for "binary" results to be | 30 | -- to be used with the "build" command, and one for "binary" results to be |
| @@ -45,33 +50,31 @@ local function split_source_and_binary_results(result_tree) | |||
| 45 | end | 50 | end |
| 46 | 51 | ||
| 47 | --- Driver function for "search" command. | 52 | --- Driver function for "search" command. |
| 48 | -- @param name string: A substring of a rock name to search. | ||
| 49 | -- @param version string or nil: a version may also be passed. | ||
| 50 | -- @return boolean or (nil, string): True if build was successful; nil and an | 53 | -- @return boolean or (nil, string): True if build was successful; nil and an |
| 51 | -- error message otherwise. | 54 | -- error message otherwise. |
| 52 | function cmd_search.command(flags, name, version) | 55 | function cmd_search.command(args) |
| 53 | 56 | ||
| 54 | name = util.adjust_name_and_namespace(name, flags) | 57 | local name = util.adjust_name_and_namespace(args.name, args) |
| 55 | 58 | ||
| 56 | if flags["all"] then | 59 | if args.all then |
| 57 | name, version = "", nil | 60 | name, args.version = "", nil |
| 58 | end | 61 | end |
| 59 | 62 | ||
| 60 | if type(name) ~= "string" and not flags["all"] then | 63 | if not args.name and not args.all then |
| 61 | return nil, "Enter name and version or use --all. "..util.see_help("search") | 64 | return nil, "Enter name and version or use --all. "..util.see_help("search") |
| 62 | end | 65 | end |
| 63 | 66 | ||
| 64 | local query = queries.new(name:lower(), version, true) | 67 | local query = queries.new(name:lower(), args.version, true) |
| 65 | local result_tree, err = search.search_repos(query) | 68 | local result_tree, err = search.search_repos(query) |
| 66 | local porcelain = flags["porcelain"] | 69 | local porcelain = args.porcelain |
| 67 | local full_name = name .. (version and " " .. version or "") | 70 | local full_name = name .. (args.version and " " .. args.version or "") |
| 68 | util.title(full_name .. " - Search results for Lua "..cfg.lua_version..":", porcelain, "=") | 71 | util.title(full_name .. " - Search results for Lua "..cfg.lua_version..":", porcelain, "=") |
| 69 | local sources, binaries = split_source_and_binary_results(result_tree) | 72 | local sources, binaries = split_source_and_binary_results(result_tree) |
| 70 | if next(sources) and not flags["binary"] then | 73 | if next(sources) and not args.binary then |
| 71 | util.title("Rockspecs and source rocks:", porcelain) | 74 | util.title("Rockspecs and source rocks:", porcelain) |
| 72 | search.print_result_tree(sources, porcelain) | 75 | search.print_result_tree(sources, porcelain) |
| 73 | end | 76 | end |
| 74 | if next(binaries) and not flags["source"] then | 77 | if next(binaries) and not args.source then |
| 75 | util.title("Binary and pure-Lua rocks:", porcelain) | 78 | util.title("Binary and pure-Lua rocks:", porcelain) |
| 76 | search.print_result_tree(binaries, porcelain) | 79 | search.print_result_tree(binaries, porcelain) |
| 77 | end | 80 | end |
diff --git a/src/luarocks/cmd/show.lua b/src/luarocks/cmd/show.lua index 37c2c55e..db7aed54 100644 --- a/src/luarocks/cmd/show.lua +++ b/src/luarocks/cmd/show.lua | |||
| @@ -13,24 +13,33 @@ local fetch = require("luarocks.fetch") | |||
| 13 | local manif = require("luarocks.manif") | 13 | local manif = require("luarocks.manif") |
| 14 | local repos = require("luarocks.repos") | 14 | local repos = require("luarocks.repos") |
| 15 | 15 | ||
| 16 | show.help_summary = "Show information about an installed rock." | 16 | function show.add_to_parser(parser) |
| 17 | local cmd = parser:command("show", [[ | ||
| 18 | Show information about an installed rock. | ||
| 17 | 19 | ||
| 18 | show.help = [[ | ||
| 19 | <argument> is an existing package name. | ||
| 20 | Without any flags, show all module information. | 20 | Without any flags, show all module information. |
| 21 | With these flags, return only the desired information: | 21 | With flags, return only the desired information.]], util.see_also()) |
| 22 | :summary("Show information about an installed rock.") | ||
| 22 | 23 | ||
| 23 | --home home page of project | 24 | cmd:argument("rock", "Name of an installed rock.") |
| 24 | --modules all modules provided by this package as used by require() | 25 | cmd:argument("version", "Rock version.") |
| 25 | --deps packages this package depends on | 26 | :args("?") |
| 26 | --build-deps build-only dependencies for this package | ||
| 27 | --test-deps dependencies for testing this package | ||
| 28 | --rockspec the full path of the rockspec file | ||
| 29 | --mversion the package version | ||
| 30 | --rock-tree local tree where rock is installed | ||
| 31 | --rock-dir data directory of the installed rock | ||
| 32 | ]] | ||
| 33 | 27 | ||
| 28 | cmd:flag("--home", "Show home page of project.") | ||
| 29 | cmd:flag("--modules", "Show all modules provided by the package as used by require().") | ||
| 30 | cmd:flag("--deps", "Show packages the package depends on.") | ||
| 31 | cmd:flag("--build-deps", "Show build-only dependencies for the package.") | ||
| 32 | cmd:flag("--test-deps", "Show dependencies for testing the package.") | ||
| 33 | cmd:flag("--rockspec", "Show the full path of the rockspec file.") | ||
| 34 | cmd:flag("--mversion", "Show the package version.") | ||
| 35 | cmd:flag("--rock-tree", "Show local tree where rock is installed.") | ||
| 36 | cmd:flag("--rock-namespace", "Show rock namespace.") | ||
| 37 | cmd:flag("--rock-dir", "Show data directory of the installed rock.") | ||
| 38 | cmd:flag("--rock-license", "Show rock license.") | ||
| 39 | cmd:flag("--issues", "Show URL for project's issue tracker.") | ||
| 40 | cmd:flag("--labels", "List the labels of the rock.") | ||
| 41 | cmd:flag("--porcelain", "Produce machine-friendly output.") | ||
| 42 | end | ||
| 34 | 43 | ||
| 35 | local friendly_template = [[ | 44 | local friendly_template = [[ |
| 36 | : | 45 | : |
| @@ -249,19 +258,14 @@ local function show_rock(template, namespace, name, version, rockspec, repo, min | |||
| 249 | end | 258 | end |
| 250 | 259 | ||
| 251 | --- Driver function for "show" command. | 260 | --- Driver function for "show" command. |
| 252 | -- @param name or nil: an existing package name. | ||
| 253 | -- @param version string or nil: a version may also be passed. | ||
| 254 | -- @return boolean: True if succeeded, nil on errors. | 261 | -- @return boolean: True if succeeded, nil on errors. |
| 255 | function show.command(flags, name, version) | 262 | function show.command(args) |
| 256 | if not name then | 263 | local name = util.adjust_name_and_namespace(args.rock, args) |
| 257 | return nil, "Argument missing. "..util.see_help("show") | 264 | local version = args.version |
| 258 | end | ||
| 259 | |||
| 260 | name = util.adjust_name_and_namespace(name, flags) | ||
| 261 | local query = queries.new(name, version) | 265 | local query = queries.new(name, version) |
| 262 | 266 | ||
| 263 | local repo, repo_url | 267 | local repo, repo_url |
| 264 | name, version, repo, repo_url = search.pick_installed_rock(query, flags["tree"]) | 268 | name, version, repo, repo_url = search.pick_installed_rock(query, args.tree) |
| 265 | if not name then | 269 | if not name then |
| 266 | return nil, version | 270 | return nil, version |
| 267 | end | 271 | end |
| @@ -277,32 +281,32 @@ function show.command(flags, name, version) | |||
| 277 | if not manifest then return nil,err end | 281 | if not manifest then return nil,err end |
| 278 | local minfo = manifest.repository[name][version][1] | 282 | local minfo = manifest.repository[name][version][1] |
| 279 | 283 | ||
| 280 | if flags["rock-tree"] then util.printout(tree) | 284 | if args.rock_tree then util.printout(tree) |
| 281 | elseif flags["rock-namespace"] then util.printout(namespace) | 285 | elseif args.rock_namespace then util.printout(namespace) |
| 282 | elseif flags["rock-dir"] then util.printout(directory) | 286 | elseif args.rock_dir then util.printout(directory) |
| 283 | elseif flags["home"] then util.printout(descript.homepage) | 287 | elseif args.home then util.printout(descript.homepage) |
| 284 | elseif flags["rock-license"] then util.printout(descript.license) | 288 | elseif args.rock_license then util.printout(descript.license) |
| 285 | elseif flags["issues"] then util.printout(descript.issues_url) | 289 | elseif args.issues then util.printout(descript.issues_url) |
| 286 | elseif flags["labels"] then util.printout(descript.labels and table.concat(descript.labels, "\n")) | 290 | elseif args.labels then util.printout(descript.labels and table.concat(descript.labels, "\n")) |
| 287 | elseif flags["modules"] then util.printout(keys_as_string(minfo.modules, "\n")) | 291 | elseif args.modules then util.printout(keys_as_string(minfo.modules, "\n")) |
| 288 | elseif flags["deps"] then | 292 | elseif args.deps then |
| 289 | for _, dep in ipairs(rockspec.dependencies) do | 293 | for _, dep in ipairs(rockspec.dependencies) do |
| 290 | util.printout(tostring(dep)) | 294 | util.printout(tostring(dep)) |
| 291 | end | 295 | end |
| 292 | elseif flags["build-deps"] then | 296 | elseif args.build_deps then |
| 293 | for _, dep in ipairs(rockspec.build_dependencies) do | 297 | for _, dep in ipairs(rockspec.build_dependencies) do |
| 294 | util.printout(tostring(dep)) | 298 | util.printout(tostring(dep)) |
| 295 | end | 299 | end |
| 296 | elseif flags["test-deps"] then | 300 | elseif args.test_deps then |
| 297 | for _, dep in ipairs(rockspec.test_dependencies) do | 301 | for _, dep in ipairs(rockspec.test_dependencies) do |
| 298 | util.printout(tostring(dep)) | 302 | util.printout(tostring(dep)) |
| 299 | end | 303 | end |
| 300 | elseif flags["rockspec"] then util.printout(rockspec_file) | 304 | elseif args.rockspec then util.printout(rockspec_file) |
| 301 | elseif flags["mversion"] then util.printout(version) | 305 | elseif args.mversion then util.printout(version) |
| 302 | elseif flags["porcelain"] then | 306 | elseif args.porcelain then |
| 303 | show_rock(porcelain_template, namespace, name, version, rockspec, repo, minfo, flags["tree"]) | 307 | show_rock(porcelain_template, namespace, name, version, rockspec, repo, minfo, args.tree) |
| 304 | else | 308 | else |
| 305 | show_rock(friendly_template, namespace, name, version, rockspec, repo, minfo, flags["tree"]) | 309 | show_rock(friendly_template, namespace, name, version, rockspec, repo, minfo, args.tree) |
| 306 | end | 310 | end |
| 307 | return true | 311 | return true |
| 308 | end | 312 | end |
diff --git a/src/luarocks/cmd/test.lua b/src/luarocks/cmd/test.lua index 413a029c..7a1ffda2 100644 --- a/src/luarocks/cmd/test.lua +++ b/src/luarocks/cmd/test.lua | |||
| @@ -6,42 +6,42 @@ local cmd_test = {} | |||
| 6 | local util = require("luarocks.util") | 6 | local util = require("luarocks.util") |
| 7 | local test = require("luarocks.test") | 7 | local test = require("luarocks.test") |
| 8 | 8 | ||
| 9 | cmd_test.help_summary = "Run the test suite in the current directory." | 9 | function cmd_test.add_to_parser(parser) |
| 10 | cmd_test.help_arguments = "[--test-type=<type>] [<rockspec>] [-- <args>]" | 10 | local cmd = parser:command("test", [[ |
| 11 | cmd_test.help = [[ | ||
| 12 | Run the test suite for the Lua project in the current directory. | 11 | Run the test suite for the Lua project in the current directory. |
| 13 | If the first argument is a rockspec, it will use it to determine | ||
| 14 | the parameters for running tests; otherwise, it will attempt to | ||
| 15 | detect the rockspec. | ||
| 16 | 12 | ||
| 17 | Any additional arguments are forwarded to the test suite. | 13 | If the first argument is a rockspec, it will use it to determine the parameters |
| 18 | To make sure that any flags passed in <args> are not interpreted | 14 | for running tests; otherwise, it will attempt to detect the rockspec. |
| 19 | as LuaRocks flags, use -- to separate LuaRocks arguments from | ||
| 20 | test suite arguments. | ||
| 21 | 15 | ||
| 22 | --test-type=<type> Specify the test suite type manually if it was not | 16 | Any additional arguments are forwarded to the test suite. |
| 23 | specified in the rockspec and it could not be | 17 | To make sure that test suite flags are not interpreted as LuaRocks flags, use -- |
| 24 | auto-detected. | 18 | to separate LuaRocks arguments from test suite arguments.]], |
| 19 | util.see_also()) | ||
| 20 | :summary("Run the test suite in the current directory.") | ||
| 25 | 21 | ||
| 26 | ]]..util.deps_mode_help() | 22 | cmd:argument("rockspec", "Project rockspec.") |
| 23 | :args("?") | ||
| 24 | cmd:argument("args", "Test suite arguments.") | ||
| 25 | :args("*") | ||
| 27 | 26 | ||
| 28 | function cmd_test.command(flags, argument, ...) | 27 | cmd:option("--test-type", "Specify the test suite type manually if it was ".. |
| 29 | assert(type(argument) == "string" or not argument) | 28 | "not specified in the rockspec and it could not be auto-detected.") |
| 30 | 29 | :argname("<type>") | |
| 31 | local arguments = { ... } | 30 | end |
| 32 | 31 | ||
| 33 | if argument and argument:match("rockspec$") then | 32 | function cmd_test.command(args) |
| 34 | return test.run_test_suite(argument, flags["test-type"], arguments) | 33 | if args.rockspec and args.rockspec:match("rockspec$") then |
| 34 | return test.run_test_suite(args.rockspec, args.test_type, args.args) | ||
| 35 | end | 35 | end |
| 36 | 36 | ||
| 37 | table.insert(arguments, 1, argument) | 37 | table.insert(args.args, 1, args.rockspec) |
| 38 | 38 | ||
| 39 | local rockspec, err = util.get_default_rockspec() | 39 | local rockspec, err = util.get_default_rockspec() |
| 40 | if not rockspec then | 40 | if not rockspec then |
| 41 | return nil, err | 41 | return nil, err |
| 42 | end | 42 | end |
| 43 | 43 | ||
| 44 | return test.run_test_suite(rockspec, flags["test-type"], arguments) | 44 | return test.run_test_suite(rockspec, args.test_type, args.args) |
| 45 | end | 45 | end |
| 46 | 46 | ||
| 47 | return cmd_test | 47 | return cmd_test |
diff --git a/src/luarocks/cmd/unpack.lua b/src/luarocks/cmd/unpack.lua index 99263f49..fe0535e4 100644 --- a/src/luarocks/cmd/unpack.lua +++ b/src/luarocks/cmd/unpack.lua | |||
| @@ -10,15 +10,20 @@ local build = require("luarocks.build") | |||
| 10 | local dir = require("luarocks.dir") | 10 | local dir = require("luarocks.dir") |
| 11 | local search = require("luarocks.search") | 11 | local search = require("luarocks.search") |
| 12 | 12 | ||
| 13 | unpack.help_summary = "Unpack the contents of a rock." | 13 | function unpack.add_to_parser(parser) |
| 14 | unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}" | 14 | local cmd = parser:command("unpack", [[ |
| 15 | unpack.help = [[ | ||
| 16 | Unpacks the contents of a rock in a newly created directory. | 15 | Unpacks the contents of a rock in a newly created directory. |
| 17 | Argument may be a rock file, or the name of a rock in a rocks server. | 16 | Argument may be a rock file, or the name of a rock in a rocks server. |
| 18 | In the latter case, the app version may be given as a second argument. | 17 | In the latter case, the rock version may be given as a second argument.]], |
| 18 | util.see_also()) | ||
| 19 | :summary("Unpack the contents of a rock.") | ||
| 19 | 20 | ||
| 20 | --force Unpack files even if the output directory already exists. | 21 | cmd:argument("rock", "A rock file or the name of a rock.") |
| 21 | ]] | 22 | cmd:argument("version", "Rock version.") |
| 23 | :args("?") | ||
| 24 | |||
| 25 | cmd:flag("--force", "Unpack files even if the output directory already exists.") | ||
| 26 | end | ||
| 22 | 27 | ||
| 23 | --- Load a rockspec file to the given directory, fetches the source | 28 | --- Load a rockspec file to the given directory, fetches the source |
| 24 | -- files specified in the rockspec, and unpack them inside the directory. | 29 | -- files specified in the rockspec, and unpack them inside the directory. |
| @@ -141,31 +146,22 @@ local function run_unpacker(file, force) | |||
| 141 | end | 146 | end |
| 142 | 147 | ||
| 143 | --- Driver function for the "unpack" command. | 148 | --- Driver function for the "unpack" command. |
| 144 | -- @param ns_name string: may be a rock filename, for unpacking a | ||
| 145 | -- rock file or the name of a rock to be fetched and unpacked. | ||
| 146 | -- @param version string or nil: if the name of a package is given, a | ||
| 147 | -- version may also be passed. | ||
| 148 | -- @return boolean or (nil, string): true if successful or nil followed | 149 | -- @return boolean or (nil, string): true if successful or nil followed |
| 149 | -- by an error message. | 150 | -- by an error message. |
| 150 | function unpack.command(flags, ns_name, version) | 151 | function unpack.command(args) |
| 151 | assert(type(version) == "string" or not version) | 152 | local ns_name = util.adjust_name_and_namespace(args.rock, args) |
| 152 | if type(ns_name) ~= "string" then | ||
| 153 | return nil, "Argument missing. "..util.see_help("unpack") | ||
| 154 | end | ||
| 155 | |||
| 156 | ns_name = util.adjust_name_and_namespace(ns_name, flags) | ||
| 157 | 153 | ||
| 158 | local url, err | 154 | local url, err |
| 159 | if ns_name:match(".*%.rock") or ns_name:match(".*%.rockspec") then | 155 | if ns_name:match(".*%.rock") or ns_name:match(".*%.rockspec") then |
| 160 | url = ns_name | 156 | url = ns_name |
| 161 | else | 157 | else |
| 162 | url, err = search.find_src_or_rockspec(ns_name, version, true) | 158 | url, err = search.find_src_or_rockspec(ns_name, args.version, true) |
| 163 | if not url then | 159 | if not url then |
| 164 | return nil, err | 160 | return nil, err |
| 165 | end | 161 | end |
| 166 | end | 162 | end |
| 167 | 163 | ||
| 168 | return run_unpacker(url, flags["force"]) | 164 | return run_unpacker(url, args.force) |
| 169 | end | 165 | end |
| 170 | 166 | ||
| 171 | return unpack | 167 | return unpack |
diff --git a/src/luarocks/cmd/upload.lua b/src/luarocks/cmd/upload.lua index b052500e..6e3877ba 100644 --- a/src/luarocks/cmd/upload.lua +++ b/src/luarocks/cmd/upload.lua | |||
| @@ -8,37 +8,33 @@ local pack = require("luarocks.pack") | |||
| 8 | local cfg = require("luarocks.core.cfg") | 8 | local cfg = require("luarocks.core.cfg") |
| 9 | local Api = require("luarocks.upload.api") | 9 | local Api = require("luarocks.upload.api") |
| 10 | 10 | ||
| 11 | upload.help_summary = "Upload a rockspec to the public rocks repository." | 11 | function upload.add_to_parser(parser) |
| 12 | upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>" | 12 | local cmd = parser:command("upload", "Pack a source rock file (.src.rock extension) ".. |
| 13 | upload.help = [[ | 13 | "and upload it and the rockspec to the public rocks repository.", util.see_also()) |
| 14 | <rockspec> Pack a source rock file (.src.rock extension), | 14 | :summary("Upload a rockspec to the public rocks repository.") |
| 15 | upload rockspec and source rock to server. | 15 | |
| 16 | 16 | cmd:argument("rockspec", "Rockspec for the rock to upload.") | |
| 17 | --skip-pack Do not pack and send source rock. | 17 | |
| 18 | 18 | cmd:flag("--skip-pack", "Do not pack and send source rock.") | |
| 19 | --api-key=<key> Give it an API key. It will be stored for subsequent uses. | 19 | cmd:option("--api-key", "Pass an API key. It will be stored for subsequent uses.") |
| 20 | 20 | :argname("<key>") | |
| 21 | --temp-key=<key> Use the given a temporary API key in this invocation only. | 21 | cmd:option("--temp-key", "Use the given a temporary API key in this ".. |
| 22 | It will not be stored. | 22 | "invocation only. It will not be stored.") |
| 23 | 23 | :argname("<key>") | |
| 24 | --force Replace existing rockspec if the same revision of | 24 | cmd:flag("--force", "Replace existing rockspec if the same revision of a ".. |
| 25 | a module already exists. This should be used only | 25 | "module already exists. This should be used only in case of upload ".. |
| 26 | in case of upload mistakes: when updating a rockspec, | 26 | "mistakes: when updating a rockspec, increment the revision number ".. |
| 27 | increment the revision number instead. | 27 | "instead.") |
| 28 | 28 | cmd:flag("--sign", "Upload a signature file alongside each file as well.") | |
| 29 | --sign Upload a signature file alongside each file as well. | 29 | cmd:flag("--debug"):hidden(true) |
| 30 | ]] | 30 | end |
| 31 | 31 | ||
| 32 | local function is_dev_version(version) | 32 | local function is_dev_version(version) |
| 33 | return version:match("^dev") or version:match("^scm") | 33 | return version:match("^dev") or version:match("^scm") |
| 34 | end | 34 | end |
| 35 | 35 | ||
| 36 | function upload.command(flags, fname) | 36 | function upload.command(args) |
| 37 | if not fname then | 37 | local api, err = Api.new(args) |
| 38 | return nil, "Missing rockspec. "..util.see_help("upload") | ||
| 39 | end | ||
| 40 | |||
| 41 | local api, err = Api.new(flags) | ||
| 42 | if not api then | 38 | if not api then |
| 43 | return nil, err | 39 | return nil, err |
| 44 | end | 40 | end |
| @@ -46,12 +42,12 @@ function upload.command(flags, fname) | |||
| 46 | api.debug = true | 42 | api.debug = true |
| 47 | end | 43 | end |
| 48 | 44 | ||
| 49 | local rockspec, err, errcode = fetch.load_rockspec(fname) | 45 | local rockspec, err, errcode = fetch.load_rockspec(args.rockspec) |
| 50 | if err then | 46 | if err then |
| 51 | return nil, err, errcode | 47 | return nil, err, errcode |
| 52 | end | 48 | end |
| 53 | 49 | ||
| 54 | util.printout("Sending " .. tostring(fname) .. " ...") | 50 | util.printout("Sending " .. tostring(args.rockspec) .. " ...") |
| 55 | local res, err = api:method("check_rockspec", { | 51 | local res, err = api:method("check_rockspec", { |
| 56 | package = rockspec.package, | 52 | package = rockspec.package, |
| 57 | version = rockspec.version | 53 | version = rockspec.version |
| @@ -61,15 +57,15 @@ function upload.command(flags, fname) | |||
| 61 | if not res.module then | 57 | if not res.module then |
| 62 | util.printout("Will create new module (" .. tostring(rockspec.package) .. ")") | 58 | util.printout("Will create new module (" .. tostring(rockspec.package) .. ")") |
| 63 | end | 59 | end |
| 64 | if res.version and not flags["force"] then | 60 | if res.version and not args.force then |
| 65 | return nil, "Revision "..rockspec.version.." already exists on the server. "..util.see_help("upload") | 61 | return nil, "Revision "..rockspec.version.." already exists on the server. "..util.see_help("upload") |
| 66 | end | 62 | end |
| 67 | 63 | ||
| 68 | local sigfname | 64 | local sigfname |
| 69 | local rock_sigfname | 65 | local rock_sigfname |
| 70 | 66 | ||
| 71 | if flags["sign"] then | 67 | if args.sign then |
| 72 | sigfname, err = signing.sign_file(fname) | 68 | sigfname, err = signing.sign_file(args.rockspec) |
| 73 | if err then | 69 | if err then |
| 74 | return nil, "Failed signing rockspec: " .. err | 70 | return nil, "Failed signing rockspec: " .. err |
| 75 | end | 71 | end |
| @@ -77,13 +73,13 @@ function upload.command(flags, fname) | |||
| 77 | end | 73 | end |
| 78 | 74 | ||
| 79 | local rock_fname | 75 | local rock_fname |
| 80 | if not flags["skip-pack"] and not is_dev_version(rockspec.version) then | 76 | if not args.skip_pack and not is_dev_version(rockspec.version) then |
| 81 | util.printout("Packing " .. tostring(rockspec.package)) | 77 | util.printout("Packing " .. tostring(rockspec.package)) |
| 82 | rock_fname, err = pack.pack_source_rock(fname) | 78 | rock_fname, err = pack.pack_source_rock(args.rockspec) |
| 83 | if not rock_fname then | 79 | if not rock_fname then |
| 84 | return nil, err | 80 | return nil, err |
| 85 | end | 81 | end |
| 86 | if flags["sign"] then | 82 | if args.sign then |
| 87 | rock_sigfname, err = signing.sign_file(rock_fname) | 83 | rock_sigfname, err = signing.sign_file(rock_fname) |
| 88 | if err then | 84 | if err then |
| 89 | return nil, "Failed signing rock: " .. err | 85 | return nil, "Failed signing rock: " .. err |
| @@ -95,7 +91,7 @@ function upload.command(flags, fname) | |||
| 95 | local multipart = require("luarocks.upload.multipart") | 91 | local multipart = require("luarocks.upload.multipart") |
| 96 | 92 | ||
| 97 | res, err = api:method("upload", nil, { | 93 | res, err = api:method("upload", nil, { |
| 98 | rockspec_file = multipart.new_file(fname), | 94 | rockspec_file = multipart.new_file(args.rockspec), |
| 99 | rockspec_sig = sigfname and multipart.new_file(sigfname), | 95 | rockspec_sig = sigfname and multipart.new_file(sigfname), |
| 100 | }) | 96 | }) |
| 101 | if not res then return nil, err end | 97 | if not res then return nil, err end |
diff --git a/src/luarocks/cmd/which.lua b/src/luarocks/cmd/which.lua index 56db5254..9a363e85 100644 --- a/src/luarocks/cmd/which.lua +++ b/src/luarocks/cmd/which.lua | |||
| @@ -8,20 +8,20 @@ local cfg = require("luarocks.core.cfg") | |||
| 8 | local util = require("luarocks.util") | 8 | local util = require("luarocks.util") |
| 9 | local fs = require("luarocks.fs") | 9 | local fs = require("luarocks.fs") |
| 10 | 10 | ||
| 11 | which_cmd.help_summary = "Tell which file corresponds to a given module name." | 11 | function which_cmd.add_to_parser(parser) |
| 12 | which_cmd.help_arguments = "<modname>" | 12 | local cmd = parser:command("which", 'Given a module name like "foo.bar", '.. |
| 13 | which_cmd.help = [[ | 13 | "output which file would be loaded to resolve that module by ".. |
| 14 | Given a module name like "foo.bar", output which file would be loaded to resolve | 14 | 'luarocks.loader, like "/usr/local/lua/'..cfg.lua_version..'/foo/bar.lua".', |
| 15 | that module by luarocks.loader, like "/usr/local/lua/]]..cfg.lua_version..[[/foo/bar.lua". | 15 | util.see_also()) |
| 16 | ]] | 16 | :summary("Tell which file corresponds to a given module name.") |
| 17 | 17 | ||
| 18 | --- Driver function for "lua" command. | 18 | cmd:argument("modname", "Module name.") |
| 19 | end | ||
| 20 | |||
| 21 | --- Driver function for "which" command. | ||
| 19 | -- @return boolean This function terminates the interpreter. | 22 | -- @return boolean This function terminates the interpreter. |
| 20 | function which_cmd.command(_, modname) | 23 | function which_cmd.command(args) |
| 21 | if modname == nil then | 24 | local pathname, rock_name, rock_version = loader.which(args.modname) |
| 22 | return nil, "Missing module name. " .. util.see_help("which") | ||
| 23 | end | ||
| 24 | local pathname, rock_name, rock_version = loader.which(modname) | ||
| 25 | 25 | ||
| 26 | if pathname then | 26 | if pathname then |
| 27 | util.printout(pathname) | 27 | util.printout(pathname) |
| @@ -29,7 +29,7 @@ function which_cmd.command(_, modname) | |||
| 29 | return true | 29 | return true |
| 30 | end | 30 | end |
| 31 | 31 | ||
| 32 | local modpath = modname:gsub("%.", "/") | 32 | local modpath = args.modname:gsub("%.", "/") |
| 33 | for _, v in ipairs({"path", "cpath"}) do | 33 | for _, v in ipairs({"path", "cpath"}) do |
| 34 | for p in package[v]:gmatch("([^;]+)") do | 34 | for p in package[v]:gmatch("([^;]+)") do |
| 35 | local pathname = p:gsub("%?", modpath) | 35 | local pathname = p:gsub("%?", modpath) |
| @@ -41,7 +41,7 @@ function which_cmd.command(_, modname) | |||
| 41 | end | 41 | end |
| 42 | end | 42 | end |
| 43 | 43 | ||
| 44 | return nil, "Module '" .. modname .. "' not found." | 44 | return nil, "Module '" .. args.modname .. "' not found." |
| 45 | end | 45 | end |
| 46 | 46 | ||
| 47 | return which_cmd | 47 | return which_cmd |
diff --git a/src/luarocks/cmd/write_rockspec.lua b/src/luarocks/cmd/write_rockspec.lua index aad91910..ee825ce4 100644 --- a/src/luarocks/cmd/write_rockspec.lua +++ b/src/luarocks/cmd/write_rockspec.lua | |||
| @@ -11,36 +11,69 @@ local rockspecs = require("luarocks.rockspecs") | |||
| 11 | local type_rockspec = require("luarocks.type.rockspec") | 11 | local type_rockspec = require("luarocks.type.rockspec") |
| 12 | local util = require("luarocks.util") | 12 | local util = require("luarocks.util") |
| 13 | 13 | ||
| 14 | write_rockspec.help_summary = "Write a template for a rockspec file." | 14 | local lua_versions = { |
| 15 | write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]" | 15 | "5.1", |
| 16 | write_rockspec.help = [[ | 16 | "5.2", |
| 17 | "5.3", | ||
| 18 | "5.4", | ||
| 19 | "5.1,5.2", | ||
| 20 | "5.2,5.3", | ||
| 21 | "5.3,5.4", | ||
| 22 | "5.1,5.2,5.3", | ||
| 23 | "5.2,5.3,5.4", | ||
| 24 | "5.1,5.2,5.3,5.4" | ||
| 25 | } | ||
| 26 | |||
| 27 | function write_rockspec.cmd_options(parser) | ||
| 28 | return parser:option("--output", "Write the rockspec with the given filename.\n".. | ||
| 29 | "If not given, a file is written in the current directory with a ".. | ||
| 30 | "filename based on given name and version.") | ||
| 31 | :argname("<file>"), | ||
| 32 | parser:option("--license", 'A license string, such as "MIT/X11" or "GNU GPL v3".') | ||
| 33 | :argname("<string>"), | ||
| 34 | parser:option("--summary", "A short one-line description summary.") | ||
| 35 | :argname("<txt>"), | ||
| 36 | parser:option("--detailed", "A longer description string.") | ||
| 37 | :argname("<txt>"), | ||
| 38 | parser:option("--homepage", "Project homepage.") | ||
| 39 | :argname("<txt>"), | ||
| 40 | parser:option("--lua-versions", 'Supported Lua versions. Accepted values are: "'.. | ||
| 41 | table.concat(lua_versions, '", "')..'".') | ||
| 42 | :argname("<ver>") | ||
| 43 | :choices(lua_versions), | ||
| 44 | parser:option("--rockspec-format", 'Rockspec format version, such as "1.0" or "1.1".') | ||
| 45 | :argname("<ver>"), | ||
| 46 | parser:option("--tag", "Tag to use. Will attempt to extract version number from it."), | ||
| 47 | parser:option("--lib", "A comma-separated list of libraries that C files need to link to.") | ||
| 48 | :argname("<libs>") | ||
| 49 | end | ||
| 50 | |||
| 51 | function write_rockspec.add_to_parser(parser) | ||
| 52 | local cmd = parser:command("write_rockspec", [[ | ||
| 17 | This command writes an initial version of a rockspec file, | 53 | This command writes an initial version of a rockspec file, |
| 18 | based on a name, a version, and a location (an URL or a local path). | 54 | based on a name, a version, and a location (an URL or a local path). |
| 19 | If only two arguments are given, the first one is considered the name and the | 55 | If only two arguments are given, the first one is considered the name and the |
| 20 | second one is the location. | 56 | second one is the location. |
| 21 | If only one argument is given, it must be the location. | 57 | If only one argument is given, it must be the location. |
| 22 | If no arguments are given, current directory is used as location. | 58 | If no arguments are given, current directory is used as the location. |
| 23 | LuaRocks will attempt to infer name and version if not given, | 59 | LuaRocks will attempt to infer name and version if not given, |
| 24 | using 'dev' as a fallback default version. | 60 | using 'dev' as a fallback default version. |
| 25 | 61 | ||
| 26 | Note that the generated file is a _starting point_ for writing a | 62 | Note that the generated file is a _starting point_ for writing a |
| 27 | rockspec, and is not guaranteed to be complete or correct. | 63 | rockspec, and is not guaranteed to be complete or correct. ]], util.see_also()) |
| 28 | 64 | :summary("Write a template for a rockspec file.") | |
| 29 | --output=<file> Write the rockspec with the given filename. | 65 | |
| 30 | If not given, a file is written in the current | 66 | parser:command("write-rockspec"):hidden(true):action(function(args) args.command = "write_rockspec" end) |
| 31 | directory with a filename based on given name and version. | 67 | |
| 32 | --license="<string>" A license string, such as "MIT/X11" or "GNU GPL v3". | 68 | cmd:argument("name", "Name of the rock.") |
| 33 | --summary="<txt>" A short one-line description summary. | 69 | :args("?") |
| 34 | --detailed="<txt>" A longer description string. | 70 | cmd:argument("version", "Rock version.") |
| 35 | --homepage=<url> Project homepage. | 71 | :args("?") |
| 36 | --lua-versions=<ver> Supported Lua versions. Accepted values are: "5.1", "5.2", | 72 | cmd:argument("location", "URL or path to the rock sources.") |
| 37 | "5.3", "5.4", "5.1,5.2", "5.2,5.3", "5.3,5.4", "5.1,5.2,5.3", | 73 | :args("?") |
| 38 | "5.2,5.3,5.4", or "5.1,5.2,5.3,5.4" | 74 | |
| 39 | --rockspec-format=<ver> Rockspec format version, such as "1.0" or "1.1". | 75 | write_rockspec.cmd_options(cmd) |
| 40 | --tag=<tag> Tag to use. Will attempt to extract version number from it. | 76 | end |
| 41 | --lib=<lib>[,<lib>] A comma-separated list of libraries that C files need to | ||
| 42 | link to. | ||
| 43 | ]] | ||
| 44 | 77 | ||
| 45 | local function open_file(name) | 78 | local function open_file(name) |
| 46 | return io.open(dir.path(fs.current_dir(), name), "r") | 79 | return io.open(dir.path(fs.current_dir(), name), "r") |
| @@ -229,40 +262,42 @@ local function rockspec_cleanup(rockspec) | |||
| 229 | end | 262 | end |
| 230 | end | 263 | end |
| 231 | 264 | ||
| 232 | function write_rockspec.command(flags, name, version, url_or_dir) | 265 | function write_rockspec.command(args) |
| 233 | 266 | ||
| 234 | name = util.adjust_name_and_namespace(name, flags) | 267 | local name = util.adjust_name_and_namespace(args.name, args) |
| 268 | local version = args.version | ||
| 269 | local location = args.location | ||
| 235 | 270 | ||
| 236 | if not name then | 271 | if not name then |
| 237 | url_or_dir = "." | 272 | location = "." |
| 238 | elseif not version then | 273 | elseif not version then |
| 239 | url_or_dir = name | 274 | location = name |
| 240 | name = nil | 275 | name = nil |
| 241 | elseif not url_or_dir then | 276 | elseif not location then |
| 242 | url_or_dir = version | 277 | location = version |
| 243 | version = nil | 278 | version = nil |
| 244 | end | 279 | end |
| 245 | 280 | ||
| 246 | if flags["tag"] then | 281 | if args.tag then |
| 247 | if not version then | 282 | if not version then |
| 248 | version = flags["tag"]:gsub("^v", "") | 283 | version = args.tag:gsub("^v", "") |
| 249 | end | 284 | end |
| 250 | end | 285 | end |
| 251 | 286 | ||
| 252 | local protocol, pathname = dir.split_url(url_or_dir) | 287 | local protocol, pathname = dir.split_url(location) |
| 253 | if protocol == "file" then | 288 | if protocol == "file" then |
| 254 | if pathname == "." then | 289 | if pathname == "." then |
| 255 | name = name or dir.base_name(fs.current_dir()) | 290 | name = name or dir.base_name(fs.current_dir()) |
| 256 | end | 291 | end |
| 257 | elseif dir.is_basic_protocol(protocol) then | 292 | elseif dir.is_basic_protocol(protocol) then |
| 258 | local filename = dir.base_name(url_or_dir) | 293 | local filename = dir.base_name(location) |
| 259 | local newname, newversion = filename:match("(.*)-([^-]+)") | 294 | local newname, newversion = filename:match("(.*)-([^-]+)") |
| 260 | if newname then | 295 | if newname then |
| 261 | name = name or newname | 296 | name = name or newname |
| 262 | version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "") | 297 | version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "") |
| 263 | end | 298 | end |
| 264 | else | 299 | else |
| 265 | name = name or dir.base_name(url_or_dir):gsub("%.[^.]+$", "") | 300 | name = name or dir.base_name(location):gsub("%.[^.]+$", "") |
| 266 | end | 301 | end |
| 267 | 302 | ||
| 268 | if not name then | 303 | if not name then |
| @@ -270,27 +305,27 @@ function write_rockspec.command(flags, name, version, url_or_dir) | |||
| 270 | end | 305 | end |
| 271 | version = version or "dev" | 306 | version = version or "dev" |
| 272 | 307 | ||
| 273 | local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") | 308 | local filename = args.output or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") |
| 274 | 309 | ||
| 275 | local url = detect_url(url_or_dir) | 310 | local url = detect_url(location) |
| 276 | local homepage = detect_homepage(url, flags["homepage"]) | 311 | local homepage = detect_homepage(url, args.homepage) |
| 277 | 312 | ||
| 278 | local rockspec, err = rockspecs.from_persisted_table(filename, { | 313 | local rockspec, err = rockspecs.from_persisted_table(filename, { |
| 279 | rockspec_format = flags["rockspec-format"], | 314 | rockspec_format = args.rockspec_format, |
| 280 | package = name, | 315 | package = name, |
| 281 | version = version.."-1", | 316 | version = version.."-1", |
| 282 | source = { | 317 | source = { |
| 283 | url = url, | 318 | url = url, |
| 284 | tag = flags["tag"], | 319 | tag = args.tag, |
| 285 | }, | 320 | }, |
| 286 | description = { | 321 | description = { |
| 287 | summary = flags["summary"] or "*** please specify description summary ***", | 322 | summary = args.summary or "*** please specify description summary ***", |
| 288 | detailed = flags["detailed"] or "*** please enter a detailed description ***", | 323 | detailed = args.detailed or "*** please enter a detailed description ***", |
| 289 | homepage = homepage, | 324 | homepage = homepage, |
| 290 | license = flags["license"] or "*** please specify a license ***", | 325 | license = args.license or "*** please specify a license ***", |
| 291 | }, | 326 | }, |
| 292 | dependencies = { | 327 | dependencies = { |
| 293 | lua_version_dep[flags["lua-versions"]], | 328 | lua_version_dep[args.lua_versions], |
| 294 | }, | 329 | }, |
| 295 | build = {}, | 330 | build = {}, |
| 296 | }) | 331 | }) |
| @@ -301,19 +336,19 @@ function write_rockspec.command(flags, name, version, url_or_dir) | |||
| 301 | util.warning("Please specify supported Lua versions with --lua-versions=<ver>. "..util.see_help("write_rockspec")) | 336 | util.warning("Please specify supported Lua versions with --lua-versions=<ver>. "..util.see_help("write_rockspec")) |
| 302 | end | 337 | end |
| 303 | 338 | ||
| 304 | local local_dir = url_or_dir | 339 | local local_dir = location |
| 305 | 340 | ||
| 306 | if url_or_dir:match("://") then | 341 | if location:match("://") then |
| 307 | rockspec.source.file = dir.base_name(url_or_dir) | 342 | rockspec.source.file = dir.base_name(location) |
| 308 | if not dir.is_basic_protocol(rockspec.source.protocol) then | 343 | if not dir.is_basic_protocol(rockspec.source.protocol) then |
| 309 | if version ~= "dev" then | 344 | if version ~= "dev" then |
| 310 | rockspec.source.tag = flags["tag"] or "v" .. version | 345 | rockspec.source.tag = args.tag or "v" .. version |
| 311 | end | 346 | end |
| 312 | end | 347 | end |
| 313 | rockspec.source.dir = nil | 348 | rockspec.source.dir = nil |
| 314 | local ok, base_dir, temp_dir = fetch_url(rockspec) | 349 | local ok, base_dir, temp_dir = fetch_url(rockspec) |
| 315 | if ok then | 350 | if ok then |
| 316 | if base_dir ~= dir.base_name(url_or_dir) then | 351 | if base_dir ~= dir.base_name(location) then |
| 317 | rockspec.source.dir = base_dir | 352 | rockspec.source.dir = base_dir |
| 318 | end | 353 | end |
| 319 | end | 354 | end |
| @@ -329,10 +364,10 @@ function write_rockspec.command(flags, name, version, url_or_dir) | |||
| 329 | end | 364 | end |
| 330 | 365 | ||
| 331 | local libs = nil | 366 | local libs = nil |
| 332 | if flags["lib"] then | 367 | if args.lib then |
| 333 | libs = {} | 368 | libs = {} |
| 334 | rockspec.external_dependencies = {} | 369 | rockspec.external_dependencies = {} |
| 335 | for lib in flags["lib"]:gmatch("([^,]+)") do | 370 | for lib in args.lib:gmatch("([^,]+)") do |
| 336 | table.insert(libs, lib) | 371 | table.insert(libs, lib) |
| 337 | rockspec.external_dependencies[lib:upper()] = { | 372 | rockspec.external_dependencies[lib:upper()] = { |
| 338 | library = lib | 373 | library = lib |
| @@ -343,13 +378,13 @@ function write_rockspec.command(flags, name, version, url_or_dir) | |||
| 343 | local ok, err = fs.change_dir(local_dir) | 378 | local ok, err = fs.change_dir(local_dir) |
| 344 | if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end | 379 | if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end |
| 345 | 380 | ||
| 346 | if not (flags["summary"] and flags["detailed"]) then | 381 | if not (args.summary and args.detailed) then |
| 347 | local summary, detailed = detect_description() | 382 | local summary, detailed = detect_description() |
| 348 | rockspec.description.summary = flags["summary"] or summary | 383 | rockspec.description.summary = args.summary or summary |
| 349 | rockspec.description.detailed = flags["detailed"] or detailed | 384 | rockspec.description.detailed = args.detailed or detailed |
| 350 | end | 385 | end |
| 351 | 386 | ||
| 352 | if not flags["license"] then | 387 | if not args.license then |
| 353 | local license, fulltext = check_license() | 388 | local license, fulltext = check_license() |
| 354 | if license then | 389 | if license then |
| 355 | rockspec.description.license = license | 390 | rockspec.description.license = license |
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua index 9ee21772..cb85764e 100644 --- a/src/luarocks/deps.lua +++ b/src/luarocks/deps.lua | |||
| @@ -170,12 +170,13 @@ function deps.fulfill_dependency(dep, deps_mode, name, version, rocks_provided, | |||
| 170 | return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err | 170 | return nil, "Could not satisfy dependency "..tostring(dep)..": "..search_err |
| 171 | end | 171 | end |
| 172 | util.printout("Installing "..url) | 172 | util.printout("Installing "..url) |
| 173 | local install_flags = { | 173 | local install_args = { |
| 174 | rock = url, | ||
| 174 | deps_mode = deps_mode, | 175 | deps_mode = deps_mode, |
| 175 | namespace = dep.namespace, | 176 | namespace = dep.namespace, |
| 176 | verify = verify, | 177 | verify = verify, |
| 177 | } | 178 | } |
| 178 | local ok, install_err, errcode = install.command(install_flags, url) | 179 | local ok, install_err, errcode = install.command(install_args) |
| 179 | if not ok then | 180 | if not ok then |
| 180 | return nil, "Failed installing dependency: "..url.." - "..install_err, errcode | 181 | return nil, "Failed installing dependency: "..url.." - "..install_err, errcode |
| 181 | end | 182 | end |
| @@ -569,23 +570,8 @@ function deps.check_lua_libdir(vars) | |||
| 569 | return nil, "Failed finding Lua library. You may need to configure LUA_LIBDIR.", "dependency" | 570 | return nil, "Failed finding Lua library. You may need to configure LUA_LIBDIR.", "dependency" |
| 570 | end | 571 | end |
| 571 | 572 | ||
| 572 | local valid_deps_modes = { | 573 | function deps.get_deps_mode(args) |
| 573 | one = true, | 574 | return args.deps_mode or cfg.deps_mode |
| 574 | order = true, | ||
| 575 | all = true, | ||
| 576 | none = true, | ||
| 577 | } | ||
| 578 | |||
| 579 | function deps.check_deps_mode_flag(flag) | ||
| 580 | return valid_deps_modes[flag] | ||
| 581 | end | ||
| 582 | |||
| 583 | function deps.get_deps_mode(flags) | ||
| 584 | if flags["deps-mode"] then | ||
| 585 | return flags["deps-mode"] | ||
| 586 | else | ||
| 587 | return cfg.deps_mode | ||
| 588 | end | ||
| 589 | end | 575 | end |
| 590 | 576 | ||
| 591 | return deps | 577 | return deps |
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 56583676..6028a925 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua | |||
| @@ -1092,10 +1092,10 @@ end | |||
| 1092 | 1092 | ||
| 1093 | --- Check if user has write permissions for the command. | 1093 | --- Check if user has write permissions for the command. |
| 1094 | -- Assumes the configuration variables under cfg have been previously set up. | 1094 | -- Assumes the configuration variables under cfg have been previously set up. |
| 1095 | -- @param flags table: the flags table passed to run() drivers. | 1095 | -- @param args table: the args table passed to run() drivers. |
| 1096 | -- @return boolean or (boolean, string): true on success, false on failure, | 1096 | -- @return boolean or (boolean, string): true on success, false on failure, |
| 1097 | -- plus an error message. | 1097 | -- plus an error message. |
| 1098 | function fs_lua.check_command_permissions(flags) | 1098 | function fs_lua.check_command_permissions(args) |
| 1099 | local ok = true | 1099 | local ok = true |
| 1100 | local err = "" | 1100 | local err = "" |
| 1101 | for _, directory in ipairs { cfg.rocks_dir, cfg.deploy_lua_dir, cfg.deploy_bin_dir, cfg.deploy_lua_dir } do | 1101 | for _, directory in ipairs { cfg.rocks_dir, cfg.deploy_lua_dir, cfg.deploy_bin_dir, cfg.deploy_lua_dir } do |
| @@ -1124,7 +1124,7 @@ function fs_lua.check_command_permissions(flags) | |||
| 1124 | if ok then | 1124 | if ok then |
| 1125 | return true | 1125 | return true |
| 1126 | else | 1126 | else |
| 1127 | if flags["local"] or cfg.local_by_default then | 1127 | if args["local"] or cfg.local_by_default then |
| 1128 | err = err .. " \n-- please check your permissions." | 1128 | err = err .. " \n-- please check your permissions." |
| 1129 | else | 1129 | else |
| 1130 | err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local." | 1130 | err = err .. " \n-- you may want to run as a privileged user or use your local tree with --local." |
diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua index 23ba2532..d6b70a5f 100644 --- a/src/luarocks/manif/writer.lua +++ b/src/luarocks/manif/writer.lua | |||
| @@ -279,7 +279,7 @@ function writer.make_rock_manifest(name, version) | |||
| 279 | end | 279 | end |
| 280 | 280 | ||
| 281 | -- Writes a 'rock_namespace' file in a locally installed rock directory. | 281 | -- Writes a 'rock_namespace' file in a locally installed rock directory. |
| 282 | -- @param name string: the rock name (may be in user/rock format) | 282 | -- @param name string: the rock name, without a namespace |
| 283 | -- @param version string: the rock version | 283 | -- @param version string: the rock version |
| 284 | -- @param namespace string?: the namespace | 284 | -- @param namespace string?: the namespace |
| 285 | -- @return true if successful (or unnecessary, if there is no namespace), | 285 | -- @return true if successful (or unnecessary, if there is no namespace), |
| @@ -288,8 +288,6 @@ function writer.make_namespace_file(name, version, namespace) | |||
| 288 | assert(type(name) == "string" and not name:match("/")) | 288 | assert(type(name) == "string" and not name:match("/")) |
| 289 | assert(type(version) == "string") | 289 | assert(type(version) == "string") |
| 290 | assert(type(namespace) == "string" or not namespace) | 290 | assert(type(namespace) == "string" or not namespace) |
| 291 | name = util.adjust_name_and_namespace(name, { namespace = namespace }) | ||
| 292 | name, namespace = util.split_namespace(name) | ||
| 293 | if not namespace then | 291 | if not namespace then |
| 294 | return true | 292 | return true |
| 295 | end | 293 | end |
diff --git a/src/luarocks/upload/api.lua b/src/luarocks/upload/api.lua index 0e71432f..a28b517a 100644 --- a/src/luarocks/upload/api.lua +++ b/src/luarocks/upload/api.lua | |||
| @@ -245,20 +245,20 @@ end | |||
| 245 | 245 | ||
| 246 | end | 246 | end |
| 247 | 247 | ||
| 248 | function api.new(flags) | 248 | function api.new(args) |
| 249 | local self = {} | 249 | local self = {} |
| 250 | setmetatable(self, { __index = Api }) | 250 | setmetatable(self, { __index = Api }) |
| 251 | self.config = self:load_config() or {} | 251 | self.config = self:load_config() or {} |
| 252 | self.config.server = flags["server"] or self.config.server or cfg.upload.server | 252 | self.config.server = args.server or self.config.server or cfg.upload.server |
| 253 | self.config.version = self.config.version or cfg.upload.version | 253 | self.config.version = self.config.version or cfg.upload.version |
| 254 | self.config.key = flags["temp-key"] or flags["api-key"] or self.config.key | 254 | self.config.key = args.temp_key or args.api_key or self.config.key |
| 255 | self.debug = flags["debug"] | 255 | self.debug = args.debug |
| 256 | if not self.config.key then | 256 | if not self.config.key then |
| 257 | return nil, "You need an API key to upload rocks.\n" .. | 257 | return nil, "You need an API key to upload rocks.\n" .. |
| 258 | "Navigate to "..self.config.server.."/settings to get a key\n" .. | 258 | "Navigate to "..self.config.server.."/settings to get a key\n" .. |
| 259 | "and then pass it through the --api-key=<key> flag." | 259 | "and then pass it through the --api-key=<key> flag." |
| 260 | end | 260 | end |
| 261 | if flags["api-key"] then | 261 | if args.api_key then |
| 262 | self:save_config() | 262 | self:save_config() |
| 263 | end | 263 | end |
| 264 | return self | 264 | return self |
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua index 8b84df4d..d4461c92 100644 --- a/src/luarocks/util.lua +++ b/src/luarocks/util.lua | |||
| @@ -77,162 +77,6 @@ function util.matchquote(s) | |||
| 77 | return (s:gsub("[?%-+*%[%].%%()$^]","%%%1")) | 77 | return (s:gsub("[?%-+*%[%].%%()$^]","%%%1")) |
| 78 | end | 78 | end |
| 79 | 79 | ||
| 80 | --- List of supported arguments. | ||
| 81 | -- Arguments that take no parameters are marked with the boolean true. | ||
| 82 | -- Arguments that take a parameter are marked with a descriptive string. | ||
| 83 | -- Arguments that may take an empty string are described in quotes, | ||
| 84 | -- (as in the value for --detailed="<text>"). | ||
| 85 | -- For all other string values, it means the parameter is mandatory. | ||
| 86 | local supported_flags = { | ||
| 87 | ["all"] = true, | ||
| 88 | ["api-key"] = "<key>", | ||
| 89 | ["append"] = true, | ||
| 90 | ["arch"] = "<arch>", | ||
| 91 | ["bin"] = true, | ||
| 92 | ["binary"] = true, | ||
| 93 | ["branch"] = "<branch-name>", | ||
| 94 | ["build-deps"] = true, | ||
| 95 | ["debug"] = true, | ||
| 96 | ["deps"] = true, | ||
| 97 | ["deps-mode"] = "<mode>", | ||
| 98 | ["detailed"] = "\"<text>\"", | ||
| 99 | ["dev"] = true, | ||
| 100 | ["dir"] = "<path>", | ||
| 101 | ["force"] = true, | ||
| 102 | ["force-fast"] = true, | ||
| 103 | ["from"] = "<server>", | ||
| 104 | ["global"] = true, | ||
| 105 | ["help"] = true, | ||
| 106 | ["home"] = true, | ||
| 107 | ["homepage"] = "\"<url>\"", | ||
| 108 | ["index"] = true, | ||
| 109 | ["issues"] = true, | ||
| 110 | ["json"] = true, | ||
| 111 | ["keep"] = true, | ||
| 112 | ["labels"] = true, | ||
| 113 | ["lib"] = "<library>", | ||
| 114 | ["license"] = "\"<text>\"", | ||
| 115 | ["list"] = true, | ||
| 116 | ["local"] = true, | ||
| 117 | ["local-tree"] = true, | ||
| 118 | ["lr-bin"] = true, | ||
| 119 | ["lr-cpath"] = true, | ||
| 120 | ["lr-path"] = true, | ||
| 121 | ["lua-dir"] = "<path>", | ||
| 122 | ["lua-version"] = "<vers>", | ||
| 123 | ["lua-versions"] = "<versions>", | ||
| 124 | ["lua-ver"] = true, | ||
| 125 | ["lua-incdir"] = true, | ||
| 126 | ["lua-libdir"] = true, | ||
| 127 | ["modules"] = true, | ||
| 128 | ["mversion"] = true, | ||
| 129 | ["namespace"] = "<namespace>", | ||
| 130 | ["no-bin"] = true, | ||
| 131 | ["no-doc"] = true, | ||
| 132 | ["no-refresh"] = true, | ||
| 133 | ["nodeps"] = true, | ||
| 134 | ["old-versions"] = true, | ||
| 135 | ["only-deps"] = true, | ||
| 136 | ["only-from"] = "<server>", | ||
| 137 | ["only-server"] = "<server>", | ||
| 138 | ["only-sources"] = "<url>", | ||
| 139 | ["only-sources-from"] = "<url>", | ||
| 140 | ["outdated"] = true, | ||
| 141 | ["output"] = "<file>", | ||
| 142 | ["pack-binary-rock"] = true, | ||
| 143 | ["porcelain"] = true, | ||
| 144 | ["project-tree"] = "<tree>", | ||
| 145 | ["quick"] = true, | ||
| 146 | ["reset"] = true, | ||
| 147 | ["rock-dir"] = true, | ||
| 148 | ["rock-license"] = true, | ||
| 149 | ["rock-namespace"] = true, | ||
| 150 | ["rock-tree"] = true, | ||
| 151 | ["rock-trees"] = true, | ||
| 152 | ["rockspec"] = true, | ||
| 153 | ["rockspec-format"] = "<ver>", | ||
| 154 | ["scope"] = "<system|user|project>", | ||
| 155 | ["server"] = "<server>", | ||
| 156 | ["sign"] = true, | ||
| 157 | ["skip-pack"] = true, | ||
| 158 | ["source"] = true, | ||
| 159 | ["summary"] = "\"<text>\"", | ||
| 160 | ["system-config"] = true, | ||
| 161 | ["tag"] = "<tag>", | ||
| 162 | ["test-type"] = "<type>", | ||
| 163 | ["temp-key"] = "<key>", | ||
| 164 | ["timeout"] = "<seconds>", | ||
| 165 | ["to"] = "<path>", | ||
| 166 | ["tree"] = "<path>", | ||
| 167 | ["unset"] = true, | ||
| 168 | ["user-config"] = true, | ||
| 169 | ["verbose"] = true, | ||
| 170 | ["verify"] = true, | ||
| 171 | ["version"] = true, | ||
| 172 | } | ||
| 173 | |||
| 174 | --- Extract flags from an arguments list. | ||
| 175 | -- Given string arguments, extract flag arguments into a flags set. | ||
| 176 | -- For example, given "foo", "--tux=beep", "--bla", "bar", "--baz", | ||
| 177 | -- it would return the following: | ||
| 178 | -- {["bla"] = true, ["tux"] = "beep", ["baz"] = true}, "foo", "bar". | ||
| 179 | function util.parse_flags(...) | ||
| 180 | local args = {...} | ||
| 181 | local flags = {} | ||
| 182 | local i = 1 | ||
| 183 | local out = {} | ||
| 184 | local state = "initial" | ||
| 185 | while i <= #args do | ||
| 186 | local flag = args[i]:match("^%-%-(.*)") | ||
| 187 | if state == "initial" and flag == "" then | ||
| 188 | state = "ignore_flags" | ||
| 189 | elseif state == "initial" and flag then | ||
| 190 | local var,val = flag:match("([a-z_%-]*)=(.*)") | ||
| 191 | if val then | ||
| 192 | local vartype = supported_flags[var] | ||
| 193 | if type(vartype) == "string" then | ||
| 194 | if val == "" and vartype:sub(1,1) ~= '"' then | ||
| 195 | return { ERROR = "Invalid argument: parameter to flag --"..var.."="..vartype.." cannot be empty." } | ||
| 196 | end | ||
| 197 | flags[var] = val | ||
| 198 | else | ||
| 199 | if vartype then | ||
| 200 | return { ERROR = "Invalid argument: flag --"..var.." does not take an parameter." } | ||
| 201 | else | ||
| 202 | return { ERROR = "Invalid argument: unknown flag --"..var.."." } | ||
| 203 | end | ||
| 204 | end | ||
| 205 | else | ||
| 206 | local var = flag | ||
| 207 | local vartype = supported_flags[var] | ||
| 208 | if type(vartype) == "string" then | ||
| 209 | i = i + 1 | ||
| 210 | local val = args[i] | ||
| 211 | if not val then | ||
| 212 | return { ERROR = "Invalid argument: flag --"..var.."="..vartype.." expects a parameter." } | ||
| 213 | end | ||
| 214 | if val:match("^%-%-.*") then | ||
| 215 | return { ERROR = "Invalid argument: flag --"..var.."="..vartype.." expects a parameter (if you really want to pass "..val.." as an argument to --"..var..", use --"..var.."="..val..")." } | ||
| 216 | else | ||
| 217 | if val == "" and vartype:sub(1,1) ~= '"' then | ||
| 218 | return { ERROR = "Invalid argument: parameter to flag --"..var.."="..vartype.." cannot be empty." } | ||
| 219 | end | ||
| 220 | flags[var] = val | ||
| 221 | end | ||
| 222 | elseif vartype == true then | ||
| 223 | flags[var] = true | ||
| 224 | else | ||
| 225 | return { ERROR = "Invalid argument: unknown flag --"..var.."." } | ||
| 226 | end | ||
| 227 | end | ||
| 228 | elseif state == "ignore_flags" or (state == "initial" and not flag) then | ||
| 229 | table.insert(out, args[i]) | ||
| 230 | end | ||
| 231 | i = i + 1 | ||
| 232 | end | ||
| 233 | return flags, unpack(out) | ||
| 234 | end | ||
| 235 | |||
| 236 | local var_format_pattern = "%$%((%a[%a%d_]+)%)" | 80 | local var_format_pattern = "%$%((%a[%a%d_]+)%)" |
| 237 | 81 | ||
| 238 | -- Check if a set of needed variables are referenced | 82 | -- Check if a set of needed variables are referenced |
| @@ -371,29 +215,36 @@ function util.this_program(default) | |||
| 371 | return prog | 215 | return prog |
| 372 | end | 216 | end |
| 373 | 217 | ||
| 374 | function util.deps_mode_help(program) | 218 | function util.deps_mode_option(parser, program) |
| 375 | local cfg = require("luarocks.core.cfg") | 219 | local cfg = require("luarocks.core.cfg") |
| 376 | return [[ | 220 | |
| 377 | --deps-mode=<mode> How to handle dependencies. Four modes are supported: | 221 | parser:option("--deps-mode", "How to handle dependencies. Four modes are supported:\n".. |
| 378 | * all - use all trees from the rocks_trees list | 222 | "* all - use all trees from the rocks_trees list for finding dependencies\n".. |
| 379 | for finding dependencies | 223 | "* one - use only the current tree (possibly set with --tree)\n".. |
| 380 | * one - use only the current tree (possibly set | 224 | "* order - use trees based on order (use the current tree and all ".. |
| 381 | with --tree) | 225 | "trees below it on the rocks_trees list)\n".. |
| 382 | * order - use trees based on order (use the current | 226 | "* none - ignore dependencies altogether.\n".. |
| 383 | tree and all trees below it on the rocks_trees list) | 227 | "The default mode may be set with the deps_mode entry in the configuration file.\n".. |
| 384 | * none - ignore dependencies altogether. | 228 | 'The current default is "'..cfg.deps_mode..'".\n'.. |
| 385 | The default mode may be set with the deps_mode entry | 229 | "Type '"..util.this_program(program or "luarocks").."' with no ".. |
| 386 | in the configuration file. | 230 | "arguments to see your list of rocks trees.") |
| 387 | The current default is "]]..cfg.deps_mode..[[". | 231 | :argname("<mode>") |
| 388 | Type ']]..util.this_program(program or "luarocks")..[[' with no arguments to see | 232 | :choices({"all", "one", "order", "none"}) |
| 389 | your list of rocks trees. | 233 | parser:flag("--nodeps"):hidden(true) |
| 390 | ]] | ||
| 391 | end | 234 | end |
| 392 | 235 | ||
| 393 | function util.see_help(command, program) | 236 | function util.see_help(command, program) |
| 394 | return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." | 237 | return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." |
| 395 | end | 238 | end |
| 396 | 239 | ||
| 240 | function util.see_also(text) | ||
| 241 | local see_also = "See also:\n" | ||
| 242 | if text then | ||
| 243 | see_also = see_also..text.."\n" | ||
| 244 | end | ||
| 245 | return see_also.." '"..util.this_program("luarocks").." help' for general options and configuration." | ||
| 246 | end | ||
| 247 | |||
| 397 | function util.announce_install(rockspec) | 248 | function util.announce_install(rockspec) |
| 398 | local cfg = require("luarocks.core.cfg") | 249 | local cfg = require("luarocks.core.cfg") |
| 399 | local path = require("luarocks.path") | 250 | local path = require("luarocks.path") |
| @@ -487,13 +338,13 @@ function util.LQ(s) | |||
| 487 | return ("%q"):format(s) | 338 | return ("%q"):format(s) |
| 488 | end | 339 | end |
| 489 | 340 | ||
| 490 | --- Normalize the --namespace flag and the user/rock syntax for namespaces. | 341 | --- Normalize the --namespace option and the user/rock syntax for namespaces. |
| 491 | -- If a namespace is given in user/rock syntax, update the --namespace flag; | 342 | -- If a namespace is given in user/rock syntax, update the --namespace option; |
| 492 | -- If a namespace is given in --namespace flag, update the user/rock syntax. | 343 | -- If a namespace is given in --namespace option, update the user/rock syntax. |
| 493 | -- In case of conflicts, the user/rock syntax takes precedence. | 344 | -- In case of conflicts, the user/rock syntax takes precedence. |
| 494 | function util.adjust_name_and_namespace(ns_name, flags) | 345 | function util.adjust_name_and_namespace(ns_name, args) |
| 495 | assert(type(ns_name) == "string" or not ns_name) | 346 | assert(type(ns_name) == "string" or not ns_name) |
| 496 | assert(type(flags) == "table") | 347 | assert(type(args) == "table") |
| 497 | 348 | ||
| 498 | if not ns_name then | 349 | if not ns_name then |
| 499 | return | 350 | return |
| @@ -503,10 +354,10 @@ function util.adjust_name_and_namespace(ns_name, flags) | |||
| 503 | 354 | ||
| 504 | local name, namespace = util.split_namespace(ns_name) | 355 | local name, namespace = util.split_namespace(ns_name) |
| 505 | if namespace then | 356 | if namespace then |
| 506 | flags["namespace"] = namespace | 357 | args.namespace = namespace |
| 507 | end | 358 | end |
| 508 | if flags["namespace"] then | 359 | if args.namespace then |
| 509 | name = flags["namespace"] .. "/" .. name | 360 | name = args.namespace .. "/" .. name |
| 510 | end | 361 | end |
| 511 | return name:lower() | 362 | return name:lower() |
| 512 | end | 363 | end |
