diff options
author | V1K1NGbg <victor@ilchev.com> | 2024-08-18 01:44:35 +0300 |
---|---|---|
committer | V1K1NGbg <victor@ilchev.com> | 2024-08-18 01:44:35 +0300 |
commit | 9ada3aebd73450e29c64b2b6b56f85eba98e2634 (patch) | |
tree | b5546d4a00ffc22a913dacefbff7a20d366140b3 | |
parent | c9b9fe3dda11afaf5b3a65798bb8072e0c9dc790 (diff) | |
download | luarocks-9ada3aebd73450e29c64b2b6b56f85eba98e2634.tar.gz luarocks-9ada3aebd73450e29c64b2b6b56f85eba98e2634.tar.bz2 luarocks-9ada3aebd73450e29c64b2b6b56f85eba98e2634.zip |
some of cmd
35 files changed, 3512 insertions, 45 deletions
diff --git a/src/luarocks/build.tl b/src/luarocks/build.tl index 610391b4..ffbc4f01 100644 --- a/src/luarocks/build.tl +++ b/src/luarocks/build.tl | |||
@@ -1,17 +1,5 @@ | |||
1 | 1 | ||
2 | local record build | 2 | local record build |
3 | record Op_b | ||
4 | build_only_deps: boolean | ||
5 | deps_mode: string | ||
6 | verify: boolean | ||
7 | minimal_mode: boolean | ||
8 | need_to_fetch: boolean | ||
9 | branch: string | ||
10 | no_install: boolean | ||
11 | pin: boolean | ||
12 | namespace: string | ||
13 | end | ||
14 | |||
15 | record Builds | 3 | record Builds |
16 | skip_lua_inc_lib_check: boolean | 4 | skip_lua_inc_lib_check: boolean |
17 | run: function(Rockspec, boolean): boolean, string, string | 5 | run: function(Rockspec, boolean): boolean, string, string |
@@ -46,7 +34,10 @@ local type b = require("luarocks.core.types.build") | |||
46 | local type Build = b.Build | 34 | local type Build = b.Build |
47 | local type Module = b.BuiltinBuild.Module | 35 | local type Module = b.BuiltinBuild.Module |
48 | 36 | ||
49 | local type Op_b = build.Op_b | 37 | local type bo = require("luarocks.core.types.bopts") |
38 | local type BOpts = bo.BOpts | ||
39 | |||
40 | |||
50 | local type Builds = build.Builds | 41 | local type Builds = build.Builds |
51 | 42 | ||
52 | do | 43 | do |
@@ -125,7 +116,7 @@ local function check_macosx_deployment_target(rockspec: Rockspec): boolean, stri | |||
125 | return true | 116 | return true |
126 | end | 117 | end |
127 | 118 | ||
128 | local function process_dependencies(rockspec: Rockspec, opts: Op_b, cwd: string): boolean, string, string | 119 | local function process_dependencies(rockspec: Rockspec, opts: BOpts, cwd: string): boolean, string, string |
129 | if not opts.build_only_deps then | 120 | if not opts.build_only_deps then |
130 | local ok, err, errcode = deps.check_external_deps(rockspec, "build") | 121 | local ok, err, errcode = deps.check_external_deps(rockspec, "build") |
131 | if err then | 122 | if err then |
@@ -181,7 +172,7 @@ local function process_dependencies(rockspec: Rockspec, opts: Op_b, cwd: string) | |||
181 | return deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode, opts.verify, deplock_dir) | 172 | return deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode, opts.verify, deplock_dir) |
182 | end | 173 | end |
183 | 174 | ||
184 | local function fetch_and_change_to_source_dir(rockspec: Rockspec, opts: Op_b): boolean, string, string | 175 | local function fetch_and_change_to_source_dir(rockspec: Rockspec, opts: BOpts): boolean, string, string |
185 | if opts.minimal_mode or opts.build_only_deps then | 176 | if opts.minimal_mode or opts.build_only_deps then |
186 | return true | 177 | return true |
187 | end | 178 | end |
@@ -414,7 +405,7 @@ end | |||
414 | -- @param cwd string or nil: The current working directory | 405 | -- @param cwd string or nil: The current working directory |
415 | -- @return (string, string) or (nil, string, [string]): Name and version of | 406 | -- @return (string, string) or (nil, string, [string]): Name and version of |
416 | -- installed rock if succeeded or nil and an error message followed by an error code. | 407 | -- installed rock if succeeded or nil and an error message followed by an error code. |
417 | function build.build_rockspec(rockspec: Rockspec, opts: Op_b, cwd: string): string, string | 408 | function build.build_rockspec(rockspec: Rockspec, opts: BOpts, cwd: string): string, string |
418 | 409 | ||
419 | cwd = cwd or dir.path(".") | 410 | cwd = cwd or dir.path(".") |
420 | 411 | ||
diff --git a/src/luarocks/cmd/build.tl b/src/luarocks/cmd/build.tl new file mode 100644 index 00000000..13577c1a --- /dev/null +++ b/src/luarocks/cmd/build.tl | |||
@@ -0,0 +1,209 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "build" command. | ||
3 | -- Builds a rock, compiling its C parts if any. | ||
4 | local record cmd_build | ||
5 | needs_lock: function(Args): boolean | ||
6 | end | ||
7 | |||
8 | local pack = require("luarocks.pack") | ||
9 | local path = require("luarocks.path") | ||
10 | local dir = require("luarocks.dir") | ||
11 | local util = require("luarocks.util") | ||
12 | local fetch = require("luarocks.fetch") | ||
13 | local fs = require("luarocks.fs") | ||
14 | local deps = require("luarocks.deps") | ||
15 | local remove = require("luarocks.remove") | ||
16 | local cfg = require("luarocks.core.cfg") | ||
17 | local build = require("luarocks.build") | ||
18 | local search = require("luarocks.search") | ||
19 | local make = require("luarocks.cmd.make") | ||
20 | local repos = require("luarocks.repos") | ||
21 | |||
22 | local argparse = require("luarocks.vendor.argparse") | ||
23 | local type Parser = argparse.Parser | ||
24 | |||
25 | local type a = require("luarocks.core.types.args") | ||
26 | local type Args = a.Args | ||
27 | |||
28 | local type bo = require("luarocks.core.types.bopts") | ||
29 | local type BOpts = bo.BOpts | ||
30 | |||
31 | local type r = require("luarocks.core.types.rockspec") | ||
32 | local type Rockspec = r.Rockspec | ||
33 | |||
34 | function cmd_build.add_to_parser(parser: Parser) | ||
35 | local cmd = parser:command("build", "Build and install a rock, compiling its C parts if any.\n".. -- luacheck: ignore 431 | ||
36 | "If the sources contain a luarocks.lock file, uses it as an authoritative source for ".. | ||
37 | "exact version of dependencies.\n".. | ||
38 | "If no arguments are given, behaves as luarocks make.", util.see_also()) | ||
39 | :summary("Build/compile a rock.") | ||
40 | |||
41 | cmd:argument("rock", "A rockspec file, a source rock file, or the name of ".. | ||
42 | "a rock to be fetched from a repository.") | ||
43 | :args("?") | ||
44 | :action(util.namespaced_name_action) | ||
45 | cmd:argument("version", "Rock version.") | ||
46 | :args("?") | ||
47 | |||
48 | cmd:flag("--only-deps --deps-only", "Install only the dependencies of the rock.") | ||
49 | cmd:option("--branch", "Override the `source.branch` field in the loaded ".. | ||
50 | "rockspec. Allows to specify a different branch to fetch. Particularly ".. | ||
51 | 'for "dev" rocks.') | ||
52 | :argname("<name>") | ||
53 | cmd:flag("--pin", "Create a luarocks.lock file listing the exact ".. | ||
54 | "versions of each dependency found for this rock (recursively), ".. | ||
55 | "and store it in the rock's directory. ".. | ||
56 | "Ignores any existing luarocks.lock file in the rock's sources.") | ||
57 | make.cmd_options(cmd) --! | ||
58 | end | ||
59 | |||
60 | --- Build and install a rock. | ||
61 | -- @param rock_filename string: local or remote filename of a rock. | ||
62 | -- @param opts table: build options | ||
63 | -- @return boolean or (nil, string, [string]): True if build was successful, | ||
64 | -- or false and an error message and an optional error code. | ||
65 | local function build_rock(rock_filename: string, opts: BOpts): boolean, string, string | ||
66 | |||
67 | local cwd = fs.absolute_name(dir.path(".")) | ||
68 | |||
69 | local ok, err, errcode: boolean, string, string | ||
70 | |||
71 | local unpack_dir: string | ||
72 | unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_filename, nil, opts.verify) | ||
73 | if not unpack_dir then | ||
74 | return nil, err, errcode | ||
75 | end | ||
76 | |||
77 | local rockspec_filename = path.rockspec_name_from_rock(rock_filename) | ||
78 | |||
79 | ok, err = fs.change_dir(unpack_dir) | ||
80 | if not ok then return nil, err end | ||
81 | |||
82 | local rockspec: Rockspec | ||
83 | rockspec, err, errcode = fetch.load_rockspec(rockspec_filename) | ||
84 | if not rockspec then | ||
85 | return nil, err, errcode | ||
86 | end | ||
87 | |||
88 | ok, err, errcode = build.build_rockspec(rockspec, opts, cwd) | ||
89 | |||
90 | fs.pop_dir() | ||
91 | return ok, err, errcode | ||
92 | end | ||
93 | |||
94 | local function do_build(name: string, namespace: string, version: string, opts: BOpts): string, string, string | ||
95 | |||
96 | local url, err: string, string | ||
97 | if name:match("%.rockspec$") or name:match("%.rock$") then | ||
98 | url = name | ||
99 | else | ||
100 | url, err = search.find_src_or_rockspec(name, namespace, version, opts.check_lua_versions) | ||
101 | if not url then | ||
102 | return nil, err | ||
103 | end | ||
104 | end | ||
105 | |||
106 | name, version = path.parse_name(url) | ||
107 | if name and repos.is_installed(name, version) then | ||
108 | if not opts.rebuild then | ||
109 | util.printout(name .. " " .. version .. " is already installed in " .. path.root_dir(cfg.root_dir)) | ||
110 | util.printout("Use --force to reinstall.") | ||
111 | return name, version, "skip" | ||
112 | end | ||
113 | end | ||
114 | |||
115 | if url:match("%.rockspec$") then | ||
116 | local cwd = fs.absolute_name(dir.path(".")) | ||
117 | local rockspec, err = fetch.load_rockspec(url, nil, opts.verify) | ||
118 | if not rockspec then | ||
119 | return nil, err | ||
120 | end | ||
121 | return build.build_rockspec(rockspec, opts, cwd) | ||
122 | end | ||
123 | |||
124 | if url:match("%.src%.rock$") then | ||
125 | opts.need_to_fetch = false | ||
126 | end | ||
127 | |||
128 | return build_rock(url, opts) | ||
129 | end | ||
130 | |||
131 | --- Driver function for "build" command. | ||
132 | -- If a package name is given, forwards the request to "search" and, | ||
133 | -- if returned a result, installs the matching rock. | ||
134 | -- When passing a package name, a version number may also be given. | ||
135 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an | ||
136 | -- error message otherwise. exitcode is optionally returned. | ||
137 | function cmd_build.command(args: Args): boolean, string, string | ||
138 | if not args.rock then | ||
139 | return make.command(args) | ||
140 | end | ||
141 | |||
142 | local opts = { | ||
143 | need_to_fetch = true, | ||
144 | minimal_mode = false, | ||
145 | deps_mode = deps.get_deps_mode(args), | ||
146 | build_only_deps = not not (args.only_deps and not args.pack_binary_rock), | ||
147 | namespace = args.namespace, | ||
148 | branch = args.branch, | ||
149 | verify = not not args.verify, | ||
150 | check_lua_versions = not not args.check_lua_versions, | ||
151 | pin = not not args.pin, | ||
152 | rebuild = not not (args.force or args.force_fast), | ||
153 | no_install = false | ||
154 | } | ||
155 | |||
156 | if args.sign and not args.pack_binary_rock then | ||
157 | return nil, "In the build command, --sign is meant to be used only with --pack-binary-rock" | ||
158 | end | ||
159 | |||
160 | if args.pack_binary_rock then | ||
161 | return pack.pack_binary_rock(args.rock, args.namespace, args.version, args.sign, function(): string, string | ||
162 | local name, version = do_build(args.rock, args.namespace, args.version, opts) | ||
163 | if name and args.no_doc then | ||
164 | util.remove_doc_dir(name, version) | ||
165 | end | ||
166 | return name, version | ||
167 | end) | ||
168 | end | ||
169 | |||
170 | local name, version, skip = do_build(args.rock, args.namespace, args.version, opts) | ||
171 | if not name then | ||
172 | return nil, version | ||
173 | end | ||
174 | if skip == "skip" then | ||
175 | return name, version | ||
176 | end | ||
177 | |||
178 | if args.no_doc then | ||
179 | util.remove_doc_dir(name, version) | ||
180 | end | ||
181 | |||
182 | if opts.build_only_deps then | ||
183 | util.printout("Stopping after installing dependencies for " ..name.." "..version) | ||
184 | util.printout() | ||
185 | else | ||
186 | if (not args.keep) and not cfg.keep_other_versions then | ||
187 | local ok, err, warn = remove.remove_other_versions(name, version, args.force, args.force_fast) | ||
188 | if not ok then | ||
189 | return nil, err | ||
190 | elseif warn then | ||
191 | util.printerr(err) | ||
192 | end | ||
193 | end | ||
194 | end | ||
195 | |||
196 | if opts.deps_mode ~= "none" then | ||
197 | deps.check_dependencies(nil, deps.get_deps_mode(args)) | ||
198 | end | ||
199 | return name, version | ||
200 | end | ||
201 | |||
202 | cmd_build.needs_lock = function(args: Args): boolean | ||
203 | if args.pack_binary_rock then | ||
204 | return false | ||
205 | end | ||
206 | return true | ||
207 | end | ||
208 | |||
209 | return cmd_build | ||
diff --git a/src/luarocks/cmd/config.tl b/src/luarocks/cmd/config.tl new file mode 100644 index 00000000..75e99198 --- /dev/null +++ b/src/luarocks/cmd/config.tl | |||
@@ -0,0 +1,403 @@ | |||
1 | --- Module implementing the LuaRocks "config" command. | ||
2 | -- Queries information about the LuaRocks configuration. | ||
3 | local record config_cmd | ||
4 | end | ||
5 | |||
6 | local persist = require("luarocks.persist") | ||
7 | local config = require("luarocks.config") | ||
8 | local cfg = require("luarocks.core.cfg") | ||
9 | local util = require("luarocks.util") | ||
10 | local deps = require("luarocks.deps") | ||
11 | local dir = require("luarocks.dir") | ||
12 | local fs = require("luarocks.fs") | ||
13 | local json = require("luarocks.vendor.dkjson") | ||
14 | |||
15 | local argparse = require("luarocks.vendor.argparse") | ||
16 | local type Parser = argparse.Parser | ||
17 | |||
18 | local type a = require("luarocks.core.types.args") | ||
19 | local type Args = a.Args | ||
20 | |||
21 | local type p = require("luarocks.core.types.persist") | ||
22 | local type PersistableTable = p.PersistableTable | ||
23 | |||
24 | function config_cmd.add_to_parser(parser: Parser) | ||
25 | local cmd = parser:command("config", [[ | ||
26 | Query information about the LuaRocks configuration. | ||
27 | |||
28 | * When given a configuration key, it prints the value of that key according to | ||
29 | the currently active configuration (taking into account all config files and | ||
30 | any command-line flags passed) | ||
31 | |||
32 | Examples: | ||
33 | luarocks config variables.LUA_INCDIR | ||
34 | luarocks config lua_version | ||
35 | |||
36 | * When given a configuration key and a value, it overwrites the config file (see | ||
37 | the --scope option below to determine which) and replaces the value of the | ||
38 | given key with the given value. | ||
39 | |||
40 | * `lua_dir` is a special key as it checks for a valid Lua installation | ||
41 | (equivalent to --lua-dir) and sets several keys at once. | ||
42 | * `lua_version` is a special key as it changes the default Lua version | ||
43 | used by LuaRocks commands (equivalent to passing --lua-version). | ||
44 | |||
45 | Examples: | ||
46 | luarocks config variables.OPENSSL_DIR /usr/local/openssl | ||
47 | luarocks config lua_dir /usr/local | ||
48 | luarocks config lua_version 5.3 | ||
49 | |||
50 | * When given a configuration key and --unset, it overwrites the config file (see | ||
51 | the --scope option below to determine which) and deletes that key from the | ||
52 | file. | ||
53 | |||
54 | Example: luarocks config variables.OPENSSL_DIR --unset | ||
55 | |||
56 | * When given no arguments, it prints the entire currently active configuration, | ||
57 | resulting from reading the config files from all scopes. | ||
58 | |||
59 | Example: luarocks config]], util.see_also([[ | ||
60 | https://github.com/luarocks/luarocks/wiki/Config-file-format | ||
61 | for detailed information on the LuaRocks config file format. | ||
62 | ]])) | ||
63 | :summary("Query information about the LuaRocks configuration.") | ||
64 | |||
65 | cmd:argument("key", "The configuration key.") | ||
66 | :args("?") | ||
67 | cmd:argument("value", "The configuration value.") | ||
68 | :args("?") | ||
69 | |||
70 | cmd:option("--scope", "The scope indicates which config file should be rewritten.\n".. | ||
71 | '* Using a wrapper created with `luarocks init`, the default is "project".\n'.. | ||
72 | '* Using --local (or when `local_by_default` is `true`), the default is "user".\n'.. | ||
73 | '* Otherwise, the default is "system".') | ||
74 | :choices({"system", "user", "project"}) | ||
75 | cmd:flag("--unset", "Delete the key from the configuration file.") | ||
76 | cmd:flag("--json", "Output as JSON.") | ||
77 | |||
78 | -- Deprecated flags | ||
79 | cmd:flag("--lua-incdir"):hidden(true) | ||
80 | cmd:flag("--lua-libdir"):hidden(true) | ||
81 | cmd:flag("--lua-ver"):hidden(true) | ||
82 | cmd:flag("--system-config"):hidden(true) | ||
83 | cmd:flag("--user-config"):hidden(true) | ||
84 | cmd:flag("--rock-trees"):hidden(true) | ||
85 | end | ||
86 | |||
87 | local function config_file(conf: cfg.conf): boolean, string | ||
88 | print(dir.normalize(conf.file)) | ||
89 | if conf.found then | ||
90 | return true | ||
91 | else | ||
92 | return nil, "file not found" | ||
93 | end | ||
94 | end | ||
95 | |||
96 | local function traverse_varstring(var: string, tbl: PersistableTable, fn: function(PersistableTable, string): (boolean, string), missing_parent?: function): boolean, string | ||
97 | local k, rs = var:match("^%[([0-9]+)%]%.(.*)$") | ||
98 | local r: string | ||
99 | if k then | ||
100 | k = tonumber(k) | ||
101 | else | ||
102 | k, r = var:match("^([^.[]+)%.(.*)$") | ||
103 | if not k then | ||
104 | k, r = var:match("^([^[]+)(%[.*)$") | ||
105 | end | ||
106 | end | ||
107 | |||
108 | if k then | ||
109 | if not tbl[k] and missing_parent then | ||
110 | missing_parent(tbl, k) | ||
111 | end | ||
112 | |||
113 | if tbl[k] then | ||
114 | return traverse_varstring(r, tbl[k] as PersistableTable, fn, missing_parent) | ||
115 | else | ||
116 | return nil, "Unknown entry " .. k | ||
117 | end | ||
118 | end | ||
119 | |||
120 | local i = var:match("^%[([0-9]+)%]$") | ||
121 | if i then | ||
122 | local var = tonumber(i) | ||
123 | end | ||
124 | |||
125 | return fn(tbl, var) | ||
126 | end | ||
127 | |||
128 | local function print_json(value: {string : any}): boolean | ||
129 | print(json.encode(value)) | ||
130 | return true | ||
131 | end | ||
132 | |||
133 | local function print_entry(var: string, tbl: PersistableTable, is_json: boolean): boolean, string | ||
134 | return traverse_varstring(var, tbl, function(t: PersistableTable, k: string): boolean, string | ||
135 | if not t[k] then | ||
136 | return nil, "Unknown entry " .. k | ||
137 | end | ||
138 | local val = t[k] | ||
139 | |||
140 | if not config.should_skip(var, val) then | ||
141 | if is_json then | ||
142 | return print_json(val as {string : any}) | ||
143 | elseif type(val) == "string" then | ||
144 | print(val) | ||
145 | else | ||
146 | persist.write_value(io.stdout as persist.Writer, val) | ||
147 | end | ||
148 | end | ||
149 | return true | ||
150 | end) | ||
151 | end | ||
152 | |||
153 | local function infer_type(var: string): string | ||
154 | local typ: string | ||
155 | traverse_varstring(var, cfg as PersistableTable, function(t: PersistableTable, k: string): boolean, string --! | ||
156 | if t[k] ~= nil then | ||
157 | typ = type(t[k]) | ||
158 | end | ||
159 | end) | ||
160 | return typ | ||
161 | end | ||
162 | |||
163 | local function write_entries(keys: {string: any}, scope: string, do_unset: boolean): boolean, string | ||
164 | if scope == "project" and not cfg.config_files.project then | ||
165 | return nil, "Current directory is not part of a project. You may want to run `luarocks init`." | ||
166 | end | ||
167 | |||
168 | local file_name = (cfg.config_files as {string: {string: string}})[scope].file | ||
169 | |||
170 | local tbl, err = persist.load_config_file_if_basic(file_name, cfg) | ||
171 | if not tbl then | ||
172 | return nil, err | ||
173 | end | ||
174 | |||
175 | for var, val in util.sortedpairs(keys) do | ||
176 | traverse_varstring(var, tbl, function(t: PersistableTable, k: string): boolean, string | ||
177 | if do_unset then | ||
178 | t[k] = nil | ||
179 | else | ||
180 | local typ = infer_type(var) | ||
181 | local v | ||
182 | if typ == "number" and tonumber(val) then | ||
183 | v = tonumber(val) | ||
184 | elseif typ == "boolean" and val == "true" then | ||
185 | v = true | ||
186 | elseif typ == "boolean" and val == "false" then | ||
187 | v = false | ||
188 | else | ||
189 | v = val | ||
190 | end | ||
191 | t[k] = v | ||
192 | keys[var] = v | ||
193 | end | ||
194 | return true | ||
195 | end, function(p, k) | ||
196 | p[k] = {} | ||
197 | end) | ||
198 | end | ||
199 | |||
200 | local ok, err = fs.make_dir(dir.dir_name(file_name)) | ||
201 | if not ok then | ||
202 | return nil, err | ||
203 | end | ||
204 | |||
205 | ok, err = persist.save_from_table(file_name, tbl) | ||
206 | if ok then | ||
207 | print(do_unset and "Removed" or "Wrote") | ||
208 | for var, val in util.sortedpairs(keys) do | ||
209 | if do_unset then | ||
210 | print(("\t%s"):format(var)) | ||
211 | else | ||
212 | if type(val) == "string" then | ||
213 | print(("\t%s = %q"):format(var, val)) | ||
214 | else | ||
215 | print(("\t%s = %s"):format(var, tostring(val))) | ||
216 | end | ||
217 | end | ||
218 | end | ||
219 | print(do_unset and "from" or "to") | ||
220 | print("\t" .. file_name) | ||
221 | return true | ||
222 | else | ||
223 | return nil, err | ||
224 | end | ||
225 | end | ||
226 | |||
227 | local function get_scope(args: Args): string | ||
228 | return args.scope | ||
229 | or (args["local"] and "user") | ||
230 | or (args.project_tree and "project") | ||
231 | or (cfg.local_by_default and "user") | ||
232 | or (fs.is_writable(cfg.config_files["system"].file) and "system") | ||
233 | or "user" | ||
234 | end | ||
235 | |||
236 | local function report_on_lua_incdir_config(value: string, lua_version: string): boolean | ||
237 | local variables = { | ||
238 | ["LUA_DIR"] = cfg.variables.LUA_DIR, | ||
239 | ["LUA_BINDIR"] = cfg.variables.LUA_BINDIR, | ||
240 | ["LUA_INCDIR"] = value, | ||
241 | ["LUA_LIBDIR"] = cfg.variables.LUA_LIBDIR, | ||
242 | ["LUA"] = cfg.variables.LUA, | ||
243 | } | ||
244 | |||
245 | local ok, err = deps.check_lua_incdir(variables, lua_version) --! | ||
246 | if not ok then | ||
247 | util.printerr() | ||
248 | util.warning((err:gsub(" You can use.*", ""))) | ||
249 | end | ||
250 | return ok | ||
251 | end | ||
252 | |||
253 | local function report_on_lua_libdir_config(value: string, lua_version: string): boolean | ||
254 | local variables = { | ||
255 | ["LUA_DIR"] = cfg.variables.LUA_DIR, | ||
256 | ["LUA_BINDIR"] = cfg.variables.LUA_BINDIR, | ||
257 | ["LUA_INCDIR"] = cfg.variables.LUA_INCDIR, | ||
258 | ["LUA_LIBDIR"] = value, | ||
259 | ["LUA"] = cfg.variables.LUA, | ||
260 | } | ||
261 | |||
262 | local ok, err, _, err_files = deps.check_lua_libdir(variables, lua_version) --! | ||
263 | if not ok then | ||
264 | util.printerr() | ||
265 | util.warning((err:gsub(" You can use.*", ""))) | ||
266 | util.printerr("Tried:") | ||
267 | for _, l in pairs(err_files or {}) do | ||
268 | for _, d in ipairs(l) do | ||
269 | util.printerr("\t" .. d) | ||
270 | end | ||
271 | end | ||
272 | end | ||
273 | return ok | ||
274 | end | ||
275 | |||
276 | local function warn_bad_c_config() | ||
277 | util.printerr() | ||
278 | util.printerr("LuaRocks may not work correctly when building C modules using this configuration.") | ||
279 | util.printerr() | ||
280 | end | ||
281 | |||
282 | --- Driver function for "config" command. | ||
283 | -- @return boolean: True if succeeded, nil on errors. | ||
284 | function config_cmd.command(args: Args): boolean, string | ||
285 | local lua_version = args.lua_version or cfg.lua_version | ||
286 | |||
287 | deps.check_lua_incdir(cfg.variables, lua_version) | ||
288 | deps.check_lua_libdir(cfg.variables, lua_version) | ||
289 | |||
290 | -- deprecated flags | ||
291 | if args.lua_incdir then | ||
292 | print(cfg.variables.LUA_INCDIR) | ||
293 | return true | ||
294 | end | ||
295 | if args.lua_libdir then | ||
296 | print(cfg.variables.LUA_LIBDIR) | ||
297 | return true | ||
298 | end | ||
299 | if args.lua_ver then | ||
300 | print(cfg.lua_version) | ||
301 | return true | ||
302 | end | ||
303 | if args.system_config then | ||
304 | return config_file(cfg.config_files.system) | ||
305 | end | ||
306 | if args.user_config then | ||
307 | return config_file(cfg.config_files.user) | ||
308 | end | ||
309 | if args.rock_trees then | ||
310 | for _, tree in ipairs(cfg.rocks_trees) do | ||
311 | if tree is string then | ||
312 | util.printout(dir.normalize(tree)) | ||
313 | else | ||
314 | local name = tree.name and "\t"..tree.name or "" | ||
315 | util.printout(dir.normalize(tree.root)..name) | ||
316 | end | ||
317 | end | ||
318 | return true | ||
319 | end | ||
320 | |||
321 | if args.key == "lua_version" and args.value then | ||
322 | local scope = get_scope(args) | ||
323 | if scope == "project" and not cfg.config_files.project then | ||
324 | return nil, "Current directory is not part of a project. You may want to run `luarocks init`." | ||
325 | end | ||
326 | |||
327 | local location = (cfg.config_files as {string: {string: string}})[scope] | ||
328 | if (not location) or (not location.file) then | ||
329 | return nil, "could not get config file location for " .. tostring(scope) .. " scope" | ||
330 | end | ||
331 | |||
332 | local prefix = dir.dir_name(location.file) | ||
333 | local ok, err = persist.save_default_lua_version(prefix, args.value) | ||
334 | if not ok then | ||
335 | return nil, "could not set default Lua version: " .. err | ||
336 | end | ||
337 | print("Lua version will default to " .. args.value .. " in " .. prefix) | ||
338 | end | ||
339 | |||
340 | if args.key == "lua_dir" and args.value then | ||
341 | local scope = get_scope(args) | ||
342 | local keys = { | ||
343 | ["variables.LUA_DIR"] = cfg.variables.LUA_DIR, | ||
344 | ["variables.LUA_BINDIR"] = cfg.variables.LUA_BINDIR, | ||
345 | ["variables.LUA_INCDIR"] = cfg.variables.LUA_INCDIR, | ||
346 | ["variables.LUA_LIBDIR"] = cfg.variables.LUA_LIBDIR, | ||
347 | ["variables.LUA"] = cfg.variables.LUA, | ||
348 | } | ||
349 | if args.lua_version then | ||
350 | local prefix = dir.dir_name((cfg.config_files as {string: {string: string}})[scope].file) | ||
351 | persist.save_default_lua_version(prefix, args.lua_version) | ||
352 | end | ||
353 | local ok, err = write_entries(keys, scope, args.unset) | ||
354 | if ok then | ||
355 | local inc_ok = report_on_lua_incdir_config(cfg.variables.LUA_INCDIR, lua_version) | ||
356 | local lib_ok = ok and report_on_lua_libdir_config(cfg.variables.LUA_LIBDIR, lua_version) | ||
357 | if not (inc_ok and lib_ok) then | ||
358 | warn_bad_c_config() | ||
359 | end | ||
360 | end | ||
361 | |||
362 | return ok, err | ||
363 | end | ||
364 | |||
365 | if args.key then | ||
366 | if args.key:match("^[A-Z]") then | ||
367 | args.key = "variables." .. args.key | ||
368 | end | ||
369 | |||
370 | if args.value or args.unset then | ||
371 | local scope = get_scope(args) | ||
372 | |||
373 | local ok, err = write_entries({ [args.key] = args.value or args.unset }, scope, args.unset) | ||
374 | |||
375 | if ok then | ||
376 | if args.key == "variables.LUA_INCDIR" then | ||
377 | local ok = report_on_lua_incdir_config(args.value, lua_version) | ||
378 | if not ok then | ||
379 | warn_bad_c_config() | ||
380 | end | ||
381 | elseif args.key == "variables.LUA_LIBDIR" then | ||
382 | local ok = report_on_lua_libdir_config(args.value, lua_version) | ||
383 | if not ok then | ||
384 | warn_bad_c_config() | ||
385 | end | ||
386 | end | ||
387 | end | ||
388 | |||
389 | return ok, err | ||
390 | else | ||
391 | return print_entry(args.key, cfg as PersistableTable, args.json) | ||
392 | end | ||
393 | end | ||
394 | |||
395 | if args.json then | ||
396 | return print_json(config.get_config_for_display(cfg as PersistableTable) as {string : any}) | ||
397 | else | ||
398 | print(config.to_string(cfg as PersistableTable)) | ||
399 | return true | ||
400 | end | ||
401 | end | ||
402 | |||
403 | return config_cmd | ||
diff --git a/src/luarocks/cmd/doc.tl b/src/luarocks/cmd/doc.tl new file mode 100644 index 00000000..79d8e019 --- /dev/null +++ b/src/luarocks/cmd/doc.tl | |||
@@ -0,0 +1,160 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "doc" command. | ||
3 | -- Shows documentation for an installed rock. | ||
4 | local record doc | ||
5 | end | ||
6 | |||
7 | local util = require("luarocks.util") | ||
8 | local queries = require("luarocks.queries") | ||
9 | local search = require("luarocks.search") | ||
10 | local path = require("luarocks.path") | ||
11 | local dir = require("luarocks.dir") | ||
12 | local fetch = require("luarocks.fetch") | ||
13 | local fs = require("luarocks.fs") | ||
14 | local download = require("luarocks.download") | ||
15 | |||
16 | local argparse = require("luarocks.vendor.argparse") | ||
17 | local type Parser = argparse.Parser | ||
18 | |||
19 | local type a = require("luarocks.core.types.args") | ||
20 | local type Args = a.Args | ||
21 | |||
22 | function doc.add_to_parser(parser: Parser) | ||
23 | local cmd = parser:command("doc", "Show documentation for an installed rock.\n\n".. | ||
24 | "Without any flags, tries to load the documentation using a series of heuristics.\n".. | ||
25 | "With flags, return only the desired information.", util.see_also([[ | ||
26 | For more information about a rock, see the 'show' command. | ||
27 | ]])) | ||
28 | :summary("Show documentation for an installed rock.") | ||
29 | |||
30 | cmd:argument("rock", "Name of the rock.") | ||
31 | :action(util.namespaced_name_action) | ||
32 | cmd:argument("version", "Version of the rock.") | ||
33 | :args("?") | ||
34 | |||
35 | cmd:flag("--home", "Open the home page of project.") | ||
36 | cmd:flag("--list", "List documentation files only.") | ||
37 | cmd:flag("--porcelain", "Produce machine-friendly output.") | ||
38 | end | ||
39 | |||
40 | local function show_homepage(homepage: string, name: string, namespace: string, version: string): boolean, string | ||
41 | if not homepage then | ||
42 | return nil, "No 'homepage' field in rockspec for "..util.format_rock_name(name, namespace, version) | ||
43 | end | ||
44 | util.printout("Opening "..homepage.." ...") | ||
45 | fs.browser(homepage) | ||
46 | return true | ||
47 | end | ||
48 | |||
49 | local function try_to_open_homepage(name: string, namespace: string, version: string): boolean, string | ||
50 | local temp_dir, err = fs.make_temp_dir("doc-"..name.."-"..(version or "")) | ||
51 | if not temp_dir then | ||
52 | return nil, "Failed creating temporary directory: "..err | ||
53 | end | ||
54 | util.schedule_function(fs.delete, temp_dir) | ||
55 | local ok, err = fs.change_dir(temp_dir) | ||
56 | if not ok then return nil, err end | ||
57 | local filename, err = download.download_file("rockspec", name, namespace, version) | ||
58 | if not filename then return nil, err end | ||
59 | local rockspec, err = fetch.load_local_rockspec(filename) | ||
60 | if not rockspec then return nil, err end | ||
61 | fs.pop_dir() | ||
62 | local descript = rockspec.description or {} | ||
63 | return show_homepage(descript.homepage, name, namespace, version) | ||
64 | end | ||
65 | |||
66 | --- Driver function for "doc" command. | ||
67 | -- @return boolean: True if succeeded, nil on errors. | ||
68 | function doc.command(args: Args): boolean, string | ||
69 | local query = queries.new(args.rock, args.namespace, args.version) | ||
70 | local iname, iversion, repo = search.pick_installed_rock(query, args.tree) | ||
71 | if not iname then | ||
72 | local rock = util.format_rock_name(args.rock, args.namespace, args.version) | ||
73 | util.printout(rock.." is not installed. Looking for it in the rocks servers...") | ||
74 | return try_to_open_homepage(args.rock, args.namespace, args.version) | ||
75 | end | ||
76 | local name, version = iname, iversion | ||
77 | |||
78 | local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version, repo)) | ||
79 | if not rockspec then return nil,err end | ||
80 | local descript = rockspec.description or {} | ||
81 | |||
82 | if args.home then | ||
83 | return show_homepage(descript.homepage, name, args.namespace, version) | ||
84 | end | ||
85 | |||
86 | local directory = path.install_dir(name, version, repo) | ||
87 | |||
88 | local docdir: string | ||
89 | local directories = { "doc", "docs" } | ||
90 | for _, d in ipairs(directories) do | ||
91 | local dirname = dir.path(directory, d) | ||
92 | if fs.is_dir(dirname) then | ||
93 | docdir = dirname | ||
94 | break | ||
95 | end | ||
96 | end | ||
97 | if not docdir then | ||
98 | if descript.homepage and not args.list then | ||
99 | util.printout("Local documentation directory not found -- opening "..descript.homepage.." ...") | ||
100 | fs.browser(descript.homepage) | ||
101 | return true | ||
102 | end | ||
103 | return nil, "Documentation directory not found for "..name.." "..version | ||
104 | end | ||
105 | |||
106 | docdir = dir.normalize(docdir) | ||
107 | local files = fs.find(docdir) | ||
108 | local htmlpatt = "%.html?$" | ||
109 | local extensions = { htmlpatt, "%.md$", "%.txt$", "%.textile$", "" } | ||
110 | local basenames = { "index", "readme", "manual" } | ||
111 | |||
112 | local porcelain = args.porcelain | ||
113 | if #files > 0 then | ||
114 | util.title("Documentation files for "..name.." "..version, porcelain) | ||
115 | if porcelain then | ||
116 | for _, file in ipairs(files) do | ||
117 | util.printout(docdir.."/"..file) | ||
118 | end | ||
119 | else | ||
120 | util.printout(docdir.."/") | ||
121 | for _, file in ipairs(files) do | ||
122 | util.printout("\t"..file) | ||
123 | end | ||
124 | end | ||
125 | end | ||
126 | |||
127 | if args.list then | ||
128 | return true | ||
129 | end | ||
130 | |||
131 | for _, extension in ipairs(extensions) do | ||
132 | for _, basename in ipairs(basenames) do | ||
133 | local filename = basename..extension | ||
134 | local found: string | ||
135 | for _, file in ipairs(files) do | ||
136 | if file:lower():match(filename) and ((not found) or #file < #found) then | ||
137 | found = file | ||
138 | end | ||
139 | end | ||
140 | if found then | ||
141 | local pathname = dir.path(docdir, found) | ||
142 | util.printout() | ||
143 | util.printout("Opening "..pathname.." ...") | ||
144 | util.printout() | ||
145 | local ok = fs.browser(pathname) | ||
146 | if not ok and not pathname:match(htmlpatt) then | ||
147 | local fd = io.open(pathname, "r") | ||
148 | util.printout(fd:read("*a")) | ||
149 | fd:close() | ||
150 | end | ||
151 | return true | ||
152 | end | ||
153 | end | ||
154 | end | ||
155 | |||
156 | return true | ||
157 | end | ||
158 | |||
159 | |||
160 | return doc | ||
diff --git a/src/luarocks/cmd/download.tl b/src/luarocks/cmd/download.tl new file mode 100644 index 00000000..d088ea71 --- /dev/null +++ b/src/luarocks/cmd/download.tl | |||
@@ -0,0 +1,63 @@ | |||
1 | |||
2 | --- Module implementing the luarocks "download" command. | ||
3 | -- Download a rock from the repository. | ||
4 | local record cmd_download | ||
5 | end | ||
6 | |||
7 | local util = require("luarocks.util") | ||
8 | local download = require("luarocks.download") | ||
9 | |||
10 | local argparse = require("luarocks.vendor.argparse") | ||
11 | local type Parser = argparse.Parser | ||
12 | |||
13 | local type a = require("luarocks.core.types.args") | ||
14 | local type Args = a.Args | ||
15 | |||
16 | function cmd_download.add_to_parser(parser: Parser) | ||
17 | local cmd = parser:command("download", "Download a specific rock file from a rocks server.", util.see_also()) | ||
18 | |||
19 | cmd:argument("name", "Name of the rock.") | ||
20 | :args("?") | ||
21 | :action(util.namespaced_name_action) | ||
22 | cmd:argument("version", "Version of the rock.") | ||
23 | :args("?") | ||
24 | |||
25 | cmd:flag("--all", "Download all files if there are multiple matches.") | ||
26 | cmd:mutex( | ||
27 | cmd:flag("--source", "Download .src.rock if available."), | ||
28 | cmd:flag("--rockspec", "Download .rockspec if available."), | ||
29 | cmd:option("--arch", "Download rock for a specific architecture.")) | ||
30 | cmd:flag("--check-lua-versions", "If the rock can't be found, check repository ".. | ||
31 | "and report if it is available for another Lua version.") | ||
32 | end | ||
33 | |||
34 | --- Driver function for the "download" command. | ||
35 | -- @return boolean or (nil, string): true if successful or nil followed | ||
36 | -- by an error message. | ||
37 | function cmd_download.command(args: Args): boolean, string | ||
38 | if not args.name and not args.all then | ||
39 | return nil, "Argument missing. "..util.see_help("download") | ||
40 | end | ||
41 | |||
42 | args.name = args.name or "" | ||
43 | |||
44 | local arch: string | ||
45 | |||
46 | if args.source then | ||
47 | arch = "src" | ||
48 | elseif args.rockspec then | ||
49 | arch = "rockspec" | ||
50 | elseif args.arch then | ||
51 | arch = args.arch | ||
52 | end | ||
53 | |||
54 | if args.all then | ||
55 | local ok, err = download.download_all(arch, args.name, args.namespace, args.version) | ||
56 | return ok, err | ||
57 | else | ||
58 | local dl, err = download.download_file(arch, args.name, args.namespace, args.version, args.check_lua_versions) | ||
59 | return dl and true, err | ||
60 | end | ||
61 | end | ||
62 | |||
63 | return cmd_download | ||
diff --git a/src/luarocks/cmd/init.tl b/src/luarocks/cmd/init.tl new file mode 100644 index 00000000..5223d01c --- /dev/null +++ b/src/luarocks/cmd/init.tl | |||
@@ -0,0 +1,234 @@ | |||
1 | |||
2 | local record init | ||
3 | needs_lock: function(Args): boolean | ||
4 | end | ||
5 | |||
6 | local cfg = require("luarocks.core.cfg") | ||
7 | local fs = require("luarocks.fs") | ||
8 | local path = require("luarocks.path") | ||
9 | local deps = require("luarocks.deps") | ||
10 | local dir = require("luarocks.dir") | ||
11 | local util = require("luarocks.util") | ||
12 | local persist = require("luarocks.persist") | ||
13 | local write_rockspec = require("luarocks.cmd.write_rockspec") | ||
14 | |||
15 | local argparse = require("luarocks.vendor.argparse") | ||
16 | local type Parser = argparse.Parser | ||
17 | |||
18 | local type a = require("luarocks.core.types.args") | ||
19 | local type Args = a.Args | ||
20 | |||
21 | |||
22 | local type p = require("luarocks.core.types.persist") | ||
23 | local type PersistableTable = p.PersistableTable | ||
24 | |||
25 | local type t = require("luarocks.core.types.tree") | ||
26 | local type Tree = t.Tree | ||
27 | |||
28 | function init.add_to_parser(parser: Parser) | ||
29 | local cmd = parser:command("init", "Initialize a directory for a Lua project using LuaRocks.", util.see_also()) | ||
30 | |||
31 | cmd:argument("name", "The project name.") | ||
32 | :args("?") | ||
33 | cmd:argument("version", "An optional project version.") | ||
34 | :args("?") | ||
35 | cmd:option("--wrapper-dir", "Location where the 'lua' and 'luarocks' wrapper scripts " .. | ||
36 | "should be generated; if not given, the current directory is used as a default.") | ||
37 | cmd:flag("--reset", "Delete any .luarocks/config-5.x.lua and ./lua and generate new ones.") | ||
38 | cmd:flag("--no-wrapper-scripts", "Do not generate wrapper ./lua and ./luarocks launcher scripts.") | ||
39 | cmd:flag("--no-gitignore", "Do not generate a .gitignore file.") | ||
40 | |||
41 | cmd:group("Options for specifying rockspec data", write_rockspec.cmd_options(cmd)) --! | ||
42 | end | ||
43 | |||
44 | local function gitignore_path(pwd: string, wrapper_dir: string, filename: string): string | ||
45 | local norm_cur = fs.absolute_name(pwd) | ||
46 | local norm_file = fs.absolute_name(dir.path(wrapper_dir, filename)) | ||
47 | if norm_file:sub(1, #norm_cur) == norm_cur then | ||
48 | return norm_file:sub(#norm_cur + 2) | ||
49 | else | ||
50 | return filename | ||
51 | end | ||
52 | end | ||
53 | |||
54 | local function write_gitignore(entries: {string}) | ||
55 | local gitignore = "" | ||
56 | local fd = io.open(".gitignore", "r") | ||
57 | if fd then | ||
58 | gitignore = fd:read("*a") | ||
59 | fd:close() | ||
60 | gitignore = "\n" .. gitignore .. "\n" | ||
61 | end | ||
62 | |||
63 | fd = io.open(".gitignore", gitignore and "a" or "w") | ||
64 | if fd then | ||
65 | for _, entry in ipairs(entries) do | ||
66 | entry = "/" .. entry | ||
67 | if not gitignore:find("\n"..entry.."\n", 1, true) then | ||
68 | fd:write(entry.."\n") | ||
69 | end | ||
70 | end | ||
71 | fd:close() | ||
72 | end | ||
73 | end | ||
74 | |||
75 | local function inject_tree(tree: string | Tree) | ||
76 | path.use_tree(tree) | ||
77 | local tree_set = false | ||
78 | for _, t in ipairs(cfg.rocks_trees) do | ||
79 | if t is Tree then | ||
80 | if t.name == "project" then | ||
81 | t.root = tree as string | ||
82 | tree_set = true | ||
83 | end | ||
84 | end | ||
85 | end | ||
86 | if not tree_set then | ||
87 | table.insert(cfg.rocks_trees, 1, { name = "project", root = tree } as Tree) | ||
88 | end | ||
89 | end | ||
90 | |||
91 | local function write_wrapper_scripts(wrapper_dir: string, luarocks_wrapper: string, lua_wrapper: string) | ||
92 | local tree = dir.path(fs.current_dir(), "lua_modules") | ||
93 | |||
94 | fs.make_dir(wrapper_dir) | ||
95 | |||
96 | luarocks_wrapper = dir.path(wrapper_dir, luarocks_wrapper) | ||
97 | if not fs.exists(luarocks_wrapper) then | ||
98 | util.printout("Preparing " .. luarocks_wrapper .. " ...") | ||
99 | fs.wrap_script(arg[0], luarocks_wrapper, "none", nil, nil, "--project-tree", tree) | ||
100 | else | ||
101 | util.printout(luarocks_wrapper .. " already exists. Not overwriting it!") | ||
102 | end | ||
103 | |||
104 | lua_wrapper = dir.path(wrapper_dir, lua_wrapper) | ||
105 | local write_lua_wrapper = true | ||
106 | if fs.exists(lua_wrapper) then | ||
107 | if not util.lua_is_wrapper(lua_wrapper) then | ||
108 | util.printout(lua_wrapper .. " already exists and does not look like a wrapper script. Not overwriting.") | ||
109 | write_lua_wrapper = false | ||
110 | end | ||
111 | end | ||
112 | |||
113 | if write_lua_wrapper then | ||
114 | if util.check_lua_version(cfg.variables.LUA, cfg.lua_version) then | ||
115 | util.printout("Preparing " .. lua_wrapper .. " for version " .. cfg.lua_version .. "...") | ||
116 | |||
117 | -- Inject tree so it shows up as a lookup path in the wrappers | ||
118 | inject_tree(tree) | ||
119 | |||
120 | fs.wrap_script(nil, lua_wrapper, "all") | ||
121 | else | ||
122 | util.warning("No Lua interpreter detected for version " .. cfg.lua_version .. ". Not creating " .. lua_wrapper) | ||
123 | end | ||
124 | end | ||
125 | end | ||
126 | |||
127 | --- Driver function for "init" command. | ||
128 | -- @return boolean: True if succeeded, nil on errors. | ||
129 | function init.command(args: Args): boolean, string | ||
130 | local do_gitignore = not args.no_gitignore | ||
131 | local do_wrapper_scripts = not args.no_wrapper_scripts | ||
132 | local wrapper_dir = args.wrapper_dir or "." | ||
133 | |||
134 | local pwd = fs.current_dir() | ||
135 | |||
136 | if not args.name then | ||
137 | args.name = dir.base_name(pwd) | ||
138 | if args.name == "/" then | ||
139 | return nil, "When running from the root directory, please specify the <name> argument" | ||
140 | end | ||
141 | end | ||
142 | |||
143 | util.title("Initializing project '" .. args.name .. "' for Lua " .. cfg.lua_version .. " ...") | ||
144 | |||
145 | local ok, err = deps.check_lua_incdir(cfg.variables) | ||
146 | if not ok then | ||
147 | return nil, err | ||
148 | end | ||
149 | |||
150 | local has_rockspec = false | ||
151 | for file in fs.dir() do | ||
152 | if file:match("%.rockspec$") then | ||
153 | has_rockspec = true | ||
154 | break | ||
155 | end | ||
156 | end | ||
157 | |||
158 | if not has_rockspec then | ||
159 | args.version = args.version or "dev" | ||
160 | args.location = pwd | ||
161 | local ok, err = write_rockspec.command(args) | ||
162 | if not ok then | ||
163 | util.printerr(err) | ||
164 | end | ||
165 | end | ||
166 | |||
167 | local ext = cfg.wrapper_suffix | ||
168 | local luarocks_wrapper = "luarocks" .. ext | ||
169 | local lua_wrapper = "lua" .. ext | ||
170 | |||
171 | if do_gitignore then | ||
172 | util.printout("Adding entries to .gitignore ...") | ||
173 | local ignores = { "lua_modules", ".luarocks" } | ||
174 | if do_wrapper_scripts then | ||
175 | table.insert(ignores, 1, gitignore_path(pwd, wrapper_dir, luarocks_wrapper)) | ||
176 | table.insert(ignores, 2, gitignore_path(pwd, wrapper_dir, lua_wrapper)) | ||
177 | end | ||
178 | write_gitignore(ignores) | ||
179 | end | ||
180 | |||
181 | util.printout("Preparing ./.luarocks/ ...") | ||
182 | fs.make_dir(".luarocks") | ||
183 | local config_file = ".luarocks/config-" .. cfg.lua_version .. ".lua" | ||
184 | |||
185 | if args.reset then | ||
186 | if do_wrapper_scripts then | ||
187 | fs.delete(fs.absolute_name(dir.path(wrapper_dir, lua_wrapper))) | ||
188 | end | ||
189 | fs.delete(fs.absolute_name(config_file)) | ||
190 | end | ||
191 | |||
192 | local config_tbl, err = persist.load_config_file_if_basic(config_file, cfg) | ||
193 | if config_tbl then | ||
194 | local varnames = { | ||
195 | "LUA_DIR", | ||
196 | "LUA_INCDIR", | ||
197 | "LUA_LIBDIR", | ||
198 | "LUA_BINDIR", | ||
199 | "LUA", | ||
200 | } | ||
201 | for _, varname in ipairs(varnames) do | ||
202 | if cfg.variables[varname] then | ||
203 | config_tbl.variables = config_tbl.variables as PersistableTable or {} | ||
204 | (config_tbl.variables as PersistableTable)[varname] = cfg.variables[varname] | ||
205 | end | ||
206 | end | ||
207 | local ok, err = persist.save_from_table(config_file, config_tbl) | ||
208 | if ok then | ||
209 | util.printout("Wrote " .. config_file) | ||
210 | else | ||
211 | util.printout("Failed writing " .. config_file .. ": " .. err) | ||
212 | end | ||
213 | else | ||
214 | util.printout("Will not attempt to overwrite " .. config_file) | ||
215 | end | ||
216 | |||
217 | ok, err = persist.save_default_lua_version(".luarocks", cfg.lua_version) | ||
218 | if not ok then | ||
219 | util.printout("Failed setting default Lua version: " .. err) | ||
220 | end | ||
221 | |||
222 | util.printout("Preparing ./lua_modules/ ...") | ||
223 | fs.make_dir("lua_modules/lib/luarocks/rocks-" .. cfg.lua_version) | ||
224 | |||
225 | if do_wrapper_scripts then | ||
226 | write_wrapper_scripts(wrapper_dir, luarocks_wrapper, lua_wrapper) | ||
227 | end | ||
228 | |||
229 | return true | ||
230 | end | ||
231 | |||
232 | init.needs_lock = function(): boolean return true end | ||
233 | |||
234 | return init | ||
diff --git a/src/luarocks/cmd/install.tl b/src/luarocks/cmd/install.tl new file mode 100644 index 00000000..db72c77d --- /dev/null +++ b/src/luarocks/cmd/install.tl | |||
@@ -0,0 +1,262 @@ | |||
1 | --- Module implementing the LuaRocks "install" command. | ||
2 | -- Installs binary rocks. | ||
3 | local record install | ||
4 | needs_lock: function(Args): boolean | ||
5 | end | ||
6 | |||
7 | local dir = require("luarocks.dir") | ||
8 | local path = require("luarocks.path") | ||
9 | local repos = require("luarocks.repos") | ||
10 | local fetch = require("luarocks.fetch") | ||
11 | local util = require("luarocks.util") | ||
12 | local fs = require("luarocks.fs") | ||
13 | local deps = require("luarocks.deps") | ||
14 | local repo_writer = require("luarocks.repo_writer") | ||
15 | local remove = require("luarocks.remove") | ||
16 | local search = require("luarocks.search") | ||
17 | local queries = require("luarocks.queries") | ||
18 | local cfg = require("luarocks.core.cfg") | ||
19 | |||
20 | local argparse = require("luarocks.vendor.argparse") | ||
21 | local type Parser = argparse.Parser | ||
22 | |||
23 | local type a = require("luarocks.core.types.args") | ||
24 | local type Args = a.Args | ||
25 | |||
26 | |||
27 | local type i = require("luarocks.core.types.installs") | ||
28 | local type IOpts = i.IOpts | ||
29 | |||
30 | function install.add_to_parser(parser: Parser) | ||
31 | local cmd = parser:command("install", "Install a rock.", util.see_also()) -- luacheck: ignore 431 | ||
32 | |||
33 | cmd:argument("rock", "The name of a rock to be fetched from a repository ".. | ||
34 | "or a filename of a locally available rock.") | ||
35 | :action(util.namespaced_name_action) | ||
36 | cmd:argument("version", "Version of the rock.") | ||
37 | :args("?") | ||
38 | |||
39 | cmd:flag("--keep", "Do not remove previously installed versions of the ".. | ||
40 | "rock after building a new one. This behavior can be made permanent by ".. | ||
41 | "setting keep_other_versions=true in the configuration file.") | ||
42 | cmd:flag("--force", "If --keep is not specified, force removal of ".. | ||
43 | "previously installed versions if it would break dependencies. ".. | ||
44 | "If rock is already installed, reinstall it anyway.") | ||
45 | cmd:flag("--force-fast", "Like --force, but performs a forced removal ".. | ||
46 | "without reporting dependency issues.") | ||
47 | cmd:flag("--only-deps --deps-only", "Install only the dependencies of the rock.") | ||
48 | cmd:flag("--no-doc", "Install the rock without its documentation.") | ||
49 | cmd:flag("--verify", "Verify signature of the rockspec or src.rock being ".. | ||
50 | "built. If the rockspec or src.rock is being downloaded, LuaRocks will ".. | ||
51 | "attempt to download the signature as well. Otherwise, the signature ".. | ||
52 | "file should be already available locally in the same directory.\n".. | ||
53 | "You need the signer’s public key in your local keyring for this ".. | ||
54 | "option to work properly.") | ||
55 | cmd:flag("--check-lua-versions", "If the rock can't be found, check repository ".. | ||
56 | "and report if it is available for another Lua version.") | ||
57 | util.deps_mode_option(cmd) --! | ||
58 | cmd:flag("--no-manifest", "Skip creating/updating the manifest") | ||
59 | cmd:flag("--pin", "If the installed rock is a Lua module, create a ".. | ||
60 | "luarocks.lock file listing the exact versions of each dependency found for ".. | ||
61 | "this rock (recursively), and store it in the rock's directory. ".. | ||
62 | "Ignores any existing luarocks.lock file in the rock's sources.") | ||
63 | -- luarocks build options | ||
64 | parser:flag("--pack-binary-rock"):hidden(true) | ||
65 | parser:option("--branch"):hidden(true) | ||
66 | parser:flag("--sign"):hidden(true) | ||
67 | end | ||
68 | |||
69 | |||
70 | --- Install a binary rock. | ||
71 | -- @param rock_file string: local or remote filename of a rock. | ||
72 | -- @param opts table: installation options | ||
73 | -- @return (string, string) or (nil, string, [string]): Name and version of | ||
74 | -- installed rock if succeeded or nil and an error message followed by an error code. | ||
75 | function install.install_binary_rock(rock_file: string, opts: IOpts): string, string, string | ||
76 | assert(type(rock_file) == "string") | ||
77 | |||
78 | local namespace = opts.namespace | ||
79 | local deps_mode = opts.deps_mode | ||
80 | |||
81 | local name, version, arch = path.parse_name(rock_file) | ||
82 | if not name then | ||
83 | return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." | ||
84 | end | ||
85 | |||
86 | if arch ~= "all" and arch ~= cfg.arch then | ||
87 | return nil, "Incompatible architecture "..arch, "arch" | ||
88 | end | ||
89 | if repos.is_installed(name, version) then | ||
90 | if not (opts.force or opts.force_fast) then | ||
91 | util.printout(name .. " " .. version .. " is already installed in " .. path.root_dir(cfg.root_dir)) | ||
92 | util.printout("Use --force to reinstall.") | ||
93 | return name, version | ||
94 | end | ||
95 | repo_writer.delete_version(name, version, opts.deps_mode) | ||
96 | end | ||
97 | |||
98 | local install_dir = path.install_dir(name, version) | ||
99 | |||
100 | local rollback = util.schedule_function(function() | ||
101 | fs.delete(install_dir) | ||
102 | fs.remove_dir_if_empty(path.versions_dir(name)) | ||
103 | end) | ||
104 | local ok: boolean | ||
105 | local oks, err, errcode = fetch.fetch_and_unpack_rock(rock_file, install_dir, opts.verify) | ||
106 | if not oks then return nil, err, errcode end | ||
107 | |||
108 | local rockspec, err = fetch.load_rockspec(path.rockspec_file(name, version)) | ||
109 | if err then | ||
110 | return nil, "Failed loading rockspec for installed package: "..err, errcode | ||
111 | end | ||
112 | |||
113 | if opts.deps_mode ~= "none" then | ||
114 | ok, err, errcode = deps.check_external_deps(rockspec, "install") | ||
115 | if err then return nil, err, errcode end | ||
116 | end | ||
117 | |||
118 | if deps_mode ~= "none" then | ||
119 | local deplock_dir = fs.exists(dir.path(".", "luarocks.lock")) | ||
120 | and "." | ||
121 | or install_dir | ||
122 | ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", deps_mode, opts.verify, deplock_dir) | ||
123 | if err then return nil, err, errcode end | ||
124 | end | ||
125 | |||
126 | ok, err = repo_writer.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode, namespace) | ||
127 | if err then return nil, err end | ||
128 | |||
129 | util.remove_scheduled_function(rollback) | ||
130 | rollback = util.schedule_function(function() | ||
131 | repo_writer.delete_version(name, version, deps_mode) | ||
132 | end) | ||
133 | |||
134 | ok, err = repos.run_hook(rockspec, "post_install") | ||
135 | if err then return nil, err end | ||
136 | |||
137 | util.announce_install(rockspec) | ||
138 | util.remove_scheduled_function(rollback) | ||
139 | return name, version | ||
140 | end | ||
141 | |||
142 | --- Installs the dependencies of a binary rock. | ||
143 | -- @param rock_file string: local or remote filename of a rock. | ||
144 | -- @param opts table: installation options | ||
145 | -- @return (string, string) or (nil, string, [string]): Name and version of | ||
146 | -- the rock whose dependencies were installed if succeeded or nil and an error message | ||
147 | -- followed by an error code. | ||
148 | function install.install_binary_rock_deps(rock_file: string, opts: IOpts): string, string, string | ||
149 | assert(type(rock_file) == "string") | ||
150 | |||
151 | local name, version, arch = path.parse_name(rock_file) | ||
152 | if not name then | ||
153 | return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." | ||
154 | end | ||
155 | |||
156 | if arch ~= "all" and arch ~= cfg.arch then | ||
157 | return nil, "Incompatible architecture "..arch, "arch" | ||
158 | end | ||
159 | |||
160 | local install_dir = path.install_dir(name, version) | ||
161 | |||
162 | local ok: boolean | ||
163 | local oks, err, errcode = fetch.fetch_and_unpack_rock(rock_file, install_dir, opts.verify) | ||
164 | if not oks then return nil, err, errcode end | ||
165 | |||
166 | local rockspec, err = fetch.load_rockspec(path.rockspec_file(name, version)) | ||
167 | if err then | ||
168 | return nil, "Failed loading rockspec for installed package: "..err, errcode | ||
169 | end | ||
170 | |||
171 | local deplock_dir = fs.exists(dir.path(".", "luarocks.lock")) | ||
172 | and "." | ||
173 | or install_dir | ||
174 | ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode, opts.verify, deplock_dir) | ||
175 | if err then return nil, err, errcode end | ||
176 | |||
177 | util.printout() | ||
178 | util.printout("Successfully installed dependencies for " ..name.." "..version) | ||
179 | |||
180 | return name, version | ||
181 | end | ||
182 | |||
183 | local function install_rock_file_deps(filename: string, opts: IOpts): string, string | ||
184 | |||
185 | local name, version = install.install_binary_rock_deps(filename, opts) | ||
186 | if not name then return nil, version end | ||
187 | |||
188 | deps.check_dependencies(nil, opts.deps_mode) | ||
189 | return name, version | ||
190 | end | ||
191 | |||
192 | local function install_rock_file(filename: string, opts: IOpts): string, string | ||
193 | |||
194 | local name, version = install.install_binary_rock(filename, opts) | ||
195 | if not name then return nil, version end | ||
196 | |||
197 | if opts.no_doc then | ||
198 | util.remove_doc_dir(name, version) | ||
199 | end | ||
200 | |||
201 | if (not opts.keep) and not cfg.keep_other_versions then | ||
202 | local ok, err, warn = remove.remove_other_versions(name, version, opts.force, opts.force_fast) | ||
203 | if not ok then | ||
204 | return nil, err | ||
205 | elseif warn then | ||
206 | util.printerr(err) | ||
207 | end | ||
208 | end | ||
209 | |||
210 | deps.check_dependencies(nil, opts.deps_mode) | ||
211 | return name, version | ||
212 | end | ||
213 | |||
214 | --- Driver function for the "install" command. | ||
215 | -- If an URL or pathname to a binary rock is given, fetches and installs it. | ||
216 | -- If a rockspec or a source rock is given, forwards the request to the "build" | ||
217 | -- command. | ||
218 | -- If a package name is given, forwards the request to "search" and, | ||
219 | -- if returned a result, installs the matching rock. | ||
220 | -- @return boolean or (nil, string, exitcode): True if installation was | ||
221 | -- successful, nil and an error message otherwise. exitcode is optionally returned. | ||
222 | function install.command(args: Args): boolean, string, string | ||
223 | if args.rock:match("%.rockspec$") or args.rock:match("%.src%.rock$") then | ||
224 | local build = require("luarocks.cmd.build") | ||
225 | return build.command(args) | ||
226 | elseif args.rock:match("%.rock$") then | ||
227 | local deps_mode = deps.get_deps_mode(args) | ||
228 | local opts = { | ||
229 | namespace = args.namespace, | ||
230 | keep = not not args.keep, | ||
231 | force = not not args.force, | ||
232 | force_fast = not not args.force_fast, | ||
233 | no_doc = not not args.no_doc, | ||
234 | deps_mode = deps_mode, | ||
235 | verify = not not args.verify, | ||
236 | } | ||
237 | if args.only_deps then | ||
238 | return install_rock_file_deps(args.rock, opts) | ||
239 | else | ||
240 | return install_rock_file(args.rock, opts) | ||
241 | end | ||
242 | else | ||
243 | local url, err = search.find_rock_checking_lua_versions( | ||
244 | queries.new(args.rock, args.namespace, args.version), | ||
245 | args.check_lua_versions) | ||
246 | if not url then | ||
247 | return nil, err | ||
248 | end | ||
249 | util.printout("Installing "..url) | ||
250 | args.rock = url | ||
251 | return install.command(args) | ||
252 | end | ||
253 | end | ||
254 | |||
255 | install.needs_lock = function(args: Args): boolean | ||
256 | if args.pack_binary_rock then | ||
257 | return false | ||
258 | end | ||
259 | return true | ||
260 | end | ||
261 | |||
262 | return install | ||
diff --git a/src/luarocks/cmd/lint.tl b/src/luarocks/cmd/lint.tl new file mode 100644 index 00000000..41fdf096 --- /dev/null +++ b/src/luarocks/cmd/lint.tl | |||
@@ -0,0 +1,57 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "lint" command. | ||
3 | -- Utility function that checks syntax of the rockspec. | ||
4 | local record lint | ||
5 | end | ||
6 | |||
7 | local util = require("luarocks.util") | ||
8 | local download = require("luarocks.download") | ||
9 | local fetch = require("luarocks.fetch") | ||
10 | |||
11 | local argparse = require("luarocks.vendor.argparse") | ||
12 | local type Parser = argparse.Parser | ||
13 | |||
14 | local type a = require("luarocks.core.types.args") | ||
15 | local type Args = a.Args | ||
16 | |||
17 | function lint.add_to_parser(parser: Parser) | ||
18 | local cmd = parser:command("lint", "Check syntax of a rockspec.\n\n".. | ||
19 | "Returns success if the text of the rockspec is syntactically correct, else failure.", | ||
20 | util.see_also()) | ||
21 | :summary("Check syntax of a rockspec.") | ||
22 | |||
23 | cmd:argument("rockspec", "The rockspec to check.") | ||
24 | end | ||
25 | |||
26 | function lint.command(args: Args): boolean, string, string | ||
27 | |||
28 | local filename = args.rockspec | ||
29 | if not filename:match(".rockspec$") then | ||
30 | local err: string | ||
31 | filename, err = download.download_file("rockspec", filename:lower()) | ||
32 | if not filename then | ||
33 | return nil, err | ||
34 | end | ||
35 | end | ||
36 | |||
37 | local rs, err = fetch.load_local_rockspec(filename) | ||
38 | if not rs then | ||
39 | return nil, "Failed loading rockspec: "..err | ||
40 | end | ||
41 | |||
42 | local ok = true | ||
43 | |||
44 | -- This should have been done in the type checker, | ||
45 | -- but it would break compatibility of other commands. | ||
46 | -- Making 'lint' alone be stricter shouldn't be a problem, | ||
47 | -- because extra-strict checks is what lint-type commands | ||
48 | -- are all about. | ||
49 | if not rs.description or not rs.description.license then | ||
50 | util.printerr("Rockspec has no description.license field.") | ||
51 | ok = false | ||
52 | end | ||
53 | |||
54 | return ok, ok or filename.." failed consistency checks." | ||
55 | end | ||
56 | |||
57 | return lint | ||
diff --git a/src/luarocks/cmd/list.tl b/src/luarocks/cmd/list.tl new file mode 100644 index 00000000..56f4de02 --- /dev/null +++ b/src/luarocks/cmd/list.tl | |||
@@ -0,0 +1,123 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "list" command. | ||
3 | -- Lists currently installed rocks. | ||
4 | local record list | ||
5 | end | ||
6 | |||
7 | local search = require("luarocks.search") | ||
8 | local queries = require("luarocks.queries") | ||
9 | local vers = require("luarocks.core.vers") | ||
10 | local cfg = require("luarocks.core.cfg") | ||
11 | local util = require("luarocks.util") | ||
12 | local path = require("luarocks.path") | ||
13 | |||
14 | local argparse = require("luarocks.vendor.argparse") | ||
15 | local type Parser = argparse.Parser | ||
16 | local type Option = argparse.Option | ||
17 | |||
18 | local type a = require("luarocks.core.types.args") | ||
19 | local type Args = a.Args | ||
20 | |||
21 | local type bo = require("luarocks.core.types.bopts") | ||
22 | local type BOpts = bo.BOpts | ||
23 | |||
24 | local type i = require("luarocks.core.types.installs") | ||
25 | local type IOpts = i.IOpts | ||
26 | |||
27 | local type p = require("luarocks.core.types.persist") | ||
28 | local type PersistableTable = p.PersistableTable | ||
29 | |||
30 | local type t = require("luarocks.core.types.tree") | ||
31 | local type Tree = t.Tree | ||
32 | |||
33 | local type b = require("luarocks.core.types.build") | ||
34 | local type BuiltinBuild = b.BuiltinBuild | ||
35 | |||
36 | local type r = require("luarocks.core.types.rockspec") | ||
37 | local type Rockspec = r.Rockspec | ||
38 | local type Dependencies = r.Dependencies | ||
39 | |||
40 | function list.add_to_parser(parser) | ||
41 | local cmd = parser:command("list", "List currently installed rocks.", util.see_also()) | ||
42 | |||
43 | cmd:argument("filter", "A substring of a rock name to filter by.") | ||
44 | :args("?") | ||
45 | cmd:argument("version", "Rock version to filter by.") | ||
46 | :args("?") | ||
47 | |||
48 | cmd:flag("--outdated", "List only rocks for which there is a higher ".. | ||
49 | "version available in the rocks server.") | ||
50 | cmd:flag("--porcelain", "Produce machine-friendly output.") | ||
51 | end | ||
52 | |||
53 | local function check_outdated(trees, query) | ||
54 | local results_installed = {} | ||
55 | for _, tree in ipairs(trees) do | ||
56 | search.local_manifest_search(results_installed, path.rocks_dir(tree), query) | ||
57 | end | ||
58 | local outdated = {} | ||
59 | for name, versions in util.sortedpairs(results_installed) do | ||
60 | versions = util.keys(versions) | ||
61 | table.sort(versions, vers.compare_versions) | ||
62 | local latest_installed = versions[1] | ||
63 | |||
64 | local query_available = queries.new(name:lower()) | ||
65 | local results_available, err = search.search_repos(query_available) | ||
66 | |||
67 | if results_available[name] then | ||
68 | local available_versions = util.keys(results_available[name]) | ||
69 | table.sort(available_versions, vers.compare_versions) | ||
70 | local latest_available = available_versions[1] | ||
71 | local latest_available_repo = results_available[name][latest_available][1].repo | ||
72 | |||
73 | if vers.compare_versions(latest_available, latest_installed) then | ||
74 | table.insert(outdated, { name = name, installed = latest_installed, available = latest_available, repo = latest_available_repo }) | ||
75 | end | ||
76 | end | ||
77 | end | ||
78 | return outdated | ||
79 | end | ||
80 | |||
81 | local function list_outdated(trees, query, porcelain) | ||
82 | util.title("Outdated rocks:", porcelain) | ||
83 | local outdated = check_outdated(trees, query) | ||
84 | for _, item in ipairs(outdated) do | ||
85 | if porcelain then | ||
86 | util.printout(item.name, item.installed, item.available, item.repo) | ||
87 | else | ||
88 | util.printout(item.name) | ||
89 | util.printout(" "..item.installed.." < "..item.available.." at "..item.repo) | ||
90 | util.printout() | ||
91 | end | ||
92 | end | ||
93 | return true | ||
94 | end | ||
95 | |||
96 | --- Driver function for "list" command. | ||
97 | -- @return boolean: True if succeeded, nil on errors. | ||
98 | function list.command(args) | ||
99 | local query = queries.new(args.filter and args.filter:lower() or "", args.namespace, args.version, true) | ||
100 | local trees = cfg.rocks_trees | ||
101 | local title = "Rocks installed for Lua "..cfg.lua_version | ||
102 | if args.tree then | ||
103 | trees = { args.tree } | ||
104 | title = title .. " in " .. args.tree | ||
105 | end | ||
106 | |||
107 | if args.outdated then | ||
108 | return list_outdated(trees, query, args.porcelain) | ||
109 | end | ||
110 | |||
111 | local results = {} | ||
112 | for _, tree in ipairs(trees) do | ||
113 | local ok, err, errcode = search.local_manifest_search(results, path.rocks_dir(tree), query) | ||
114 | if not ok and errcode ~= "open" then | ||
115 | util.warning(err) | ||
116 | end | ||
117 | end | ||
118 | util.title(title, args.porcelain) | ||
119 | search.print_result_tree(results, args.porcelain) | ||
120 | return true | ||
121 | end | ||
122 | |||
123 | return list | ||
diff --git a/src/luarocks/cmd/make.tl b/src/luarocks/cmd/make.tl new file mode 100644 index 00000000..ab6c83da --- /dev/null +++ b/src/luarocks/cmd/make.tl | |||
@@ -0,0 +1,176 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "make" command. | ||
3 | -- Builds sources in the current directory, but unlike "build", | ||
4 | -- it does not fetch sources, etc., assuming everything is | ||
5 | -- available in the current directory. | ||
6 | local record make | ||
7 | needs_lock: function(Args): boolean | ||
8 | end | ||
9 | |||
10 | local build = require("luarocks.build") | ||
11 | local util = require("luarocks.util") | ||
12 | local cfg = require("luarocks.core.cfg") | ||
13 | local fetch = require("luarocks.fetch") | ||
14 | local pack = require("luarocks.pack") | ||
15 | local remove = require("luarocks.remove") | ||
16 | local deps = require("luarocks.deps") | ||
17 | local dir = require("luarocks.dir") | ||
18 | local fs = require("luarocks.fs") | ||
19 | |||
20 | local argparse = require("luarocks.vendor.argparse") | ||
21 | local type Parser = argparse.Parser | ||
22 | |||
23 | local type a = require("luarocks.core.types.args") | ||
24 | local type Args = a.Args | ||
25 | |||
26 | local type bo = require("luarocks.core.types.bopts") | ||
27 | local type BOpts = bo.BOpts | ||
28 | |||
29 | function make.cmd_options(parser: Parser) | ||
30 | parser:flag("--no-install", "Do not install the rock.") | ||
31 | parser:flag("--no-doc", "Install the rock without its documentation.") | ||
32 | parser:flag("--pack-binary-rock", "Do not install rock. Instead, produce a ".. | ||
33 | ".rock file with the contents of compilation in the current directory.") | ||
34 | parser:flag("--keep", "Do not remove previously installed versions of the ".. | ||
35 | "rock after building a new one. This behavior can be made permanent by ".. | ||
36 | "setting keep_other_versions=true in the configuration file.") | ||
37 | parser:flag("--force", "If --keep is not specified, force removal of ".. | ||
38 | "previously installed versions if it would break dependencies. ".. | ||
39 | "If rock is already installed, reinstall it anyway.") | ||
40 | parser:flag("--force-fast", "Like --force, but performs a forced removal ".. | ||
41 | "without reporting dependency issues.") | ||
42 | parser:flag("--verify", "Verify signature of the rockspec or src.rock being ".. | ||
43 | "built. If the rockspec or src.rock is being downloaded, LuaRocks will ".. | ||
44 | "attempt to download the signature as well. Otherwise, the signature ".. | ||
45 | "file should be already available locally in the same directory.\n".. | ||
46 | "You need the signer’s public key in your local keyring for this ".. | ||
47 | "option to work properly.") | ||
48 | parser:flag("--sign", "To be used with --pack-binary-rock. Also produce a ".. | ||
49 | "signature file for the generated .rock file.") | ||
50 | parser:flag("--check-lua-versions", "If the rock can't be found, check repository ".. | ||
51 | "and report if it is available for another Lua version.") | ||
52 | parser:flag("--pin", "Pin the exact dependencies used for the rockspec".. | ||
53 | "being built into a luarocks.lock file in the current directory.") | ||
54 | parser:flag("--no-manifest", "Skip creating/updating the manifest") | ||
55 | parser:flag("--only-deps --deps-only", "Install only the dependencies of the rock.") | ||
56 | util.deps_mode_option(parser) | ||
57 | end | ||
58 | |||
59 | function make.add_to_parser(parser: Parser) | ||
60 | -- luacheck: push ignore 431 | ||
61 | local cmd = parser:command("make", [[ | ||
62 | Builds sources in the current directory, but unlike "build", it does not fetch | ||
63 | sources, etc., assuming everything is available in the current directory. If no | ||
64 | argument is given, it looks for a rockspec in the current directory and in | ||
65 | "rockspec/" and "rockspecs/" subdirectories, picking the rockspec with newest | ||
66 | version or without version name. If rockspecs for different rocks are found or | ||
67 | there are several rockspecs without version, you must specify which to use, | ||
68 | through the command-line. | ||
69 | |||
70 | This command is useful as a tool for debugging rockspecs. | ||
71 | To install rocks, you'll normally want to use the "install" and "build" | ||
72 | commands. See the help on those for details. | ||
73 | |||
74 | If the current directory contains a luarocks.lock file, it is used as the | ||
75 | authoritative source for exact version of dependencies. The --pin flag | ||
76 | overrides and recreates this file scanning dependency based on ranges. | ||
77 | ]], util.see_also()) | ||
78 | :summary("Compile package in current directory using a rockspec.") | ||
79 | -- luacheck: pop | ||
80 | |||
81 | cmd:argument("rockspec", "Rockspec for the rock to build.") | ||
82 | :args("?") | ||
83 | |||
84 | make.cmd_options(cmd) --! | ||
85 | end | ||
86 | |||
87 | --- Driver function for "make" command. | ||
88 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an | ||
89 | -- error message otherwise. exitcode is optionally returned. | ||
90 | function make.command(args: Args): boolean, string | ||
91 | local rockspec_filename = args.rockspec | ||
92 | if not rockspec_filename then | ||
93 | local err: string | ||
94 | rockspec_filename, err = util.get_default_rockspec() | ||
95 | if not rockspec_filename then | ||
96 | return nil, err | ||
97 | end | ||
98 | end | ||
99 | if not rockspec_filename:match("rockspec$") then | ||
100 | return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make") | ||
101 | end | ||
102 | |||
103 | local cwd = fs.absolute_name(dir.path(".")) | ||
104 | local rockspec, err, errcode = fetch.load_rockspec(rockspec_filename) | ||
105 | if not rockspec then | ||
106 | return nil, err | ||
107 | end | ||
108 | |||
109 | local name, namespace = util.split_namespace(rockspec.name) | ||
110 | namespace = namespace or args.namespace | ||
111 | |||
112 | local opts: BOpts = { | ||
113 | need_to_fetch = false, | ||
114 | minimal_mode = true, | ||
115 | deps_mode = deps.get_deps_mode(args), | ||
116 | build_only_deps = not not (args.only_deps and not args.pack_binary_rock), | ||
117 | namespace = namespace, | ||
118 | branch = args.branch, | ||
119 | verify = not not args.verify, | ||
120 | check_lua_versions = not not args.check_lua_versions, | ||
121 | pin = not not args.pin, | ||
122 | rebuild = true, | ||
123 | no_install = not not args.no_install | ||
124 | } | ||
125 | |||
126 | if args.sign and not args.pack_binary_rock then | ||
127 | return nil, "In the make command, --sign is meant to be used only with --pack-binary-rock" | ||
128 | end | ||
129 | |||
130 | if args.no_install then | ||
131 | return build.build_rockspec(rockspec, opts, cwd) | ||
132 | elseif args.pack_binary_rock then | ||
133 | return pack.pack_binary_rock(name, namespace, rockspec.version, args.sign, function(): string, string | ||
134 | local name, version = build.build_rockspec(rockspec, opts, cwd) -- luacheck: ignore 431 | ||
135 | if name and args.no_doc then | ||
136 | util.remove_doc_dir(name, version) | ||
137 | end | ||
138 | return name, version | ||
139 | end) | ||
140 | else | ||
141 | local ok, err = build.build_rockspec(rockspec, opts, cwd) | ||
142 | if not ok then return nil, err end | ||
143 | local name, version = ok, err -- luacheck: ignore 421 | ||
144 | |||
145 | if opts.build_only_deps then | ||
146 | util.printout("Stopping after installing dependencies for " ..name.." "..version) | ||
147 | util.printout() | ||
148 | return name, version | ||
149 | end | ||
150 | |||
151 | if args.no_doc then | ||
152 | util.remove_doc_dir(name, version) | ||
153 | end | ||
154 | |||
155 | if (not args.keep) and not cfg.keep_other_versions then | ||
156 | local ok, err, warn = remove.remove_other_versions(name, version, args.force, args.force_fast) | ||
157 | if not ok then | ||
158 | return nil, err | ||
159 | elseif warn then | ||
160 | util.printerr(warn) | ||
161 | end | ||
162 | end | ||
163 | |||
164 | deps.check_dependencies(nil, deps.get_deps_mode(args)) | ||
165 | return name, version | ||
166 | end | ||
167 | end | ||
168 | |||
169 | make.needs_lock = function(args: Args): boolean | ||
170 | if args.pack_binary_rock or args.no_install then | ||
171 | return false | ||
172 | end | ||
173 | return true | ||
174 | end | ||
175 | |||
176 | return make | ||
diff --git a/src/luarocks/cmd/new_version.tl b/src/luarocks/cmd/new_version.tl new file mode 100644 index 00000000..2ec084e0 --- /dev/null +++ b/src/luarocks/cmd/new_version.tl | |||
@@ -0,0 +1,228 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "new_version" command. | ||
3 | -- Utility function that writes a new rockspec, updating data from a previous one. | ||
4 | local new_version = {} | ||
5 | |||
6 | local util = require("luarocks.util") | ||
7 | local download = require("luarocks.download") | ||
8 | local fetch = require("luarocks.fetch") | ||
9 | local persist = require("luarocks.persist") | ||
10 | local fs = require("luarocks.fs") | ||
11 | local dir = require("luarocks.dir") | ||
12 | local type_rockspec = require("luarocks.type.rockspec") | ||
13 | |||
14 | function new_version.add_to_parser(parser) | ||
15 | local cmd = parser:command("new_version", [[ | ||
16 | This is a utility function that writes a new rockspec, updating data from a | ||
17 | previous one. | ||
18 | |||
19 | If a package name is given, it downloads the latest rockspec from the default | ||
20 | server. If a rockspec is given, it uses it instead. If no argument is given, it | ||
21 | looks for a rockspec same way 'luarocks make' does. | ||
22 | |||
23 | If the version number is not given and tag is passed using --tag, it is used as | ||
24 | the version, with 'v' removed from beginning. Otherwise, it only increments the | ||
25 | revision number of the given (or downloaded) rockspec. | ||
26 | |||
27 | If a URL is given, it replaces the one from the old rockspec with the given URL. | ||
28 | If a URL is not given and a new version is given, it tries to guess the new URL | ||
29 | by replacing occurrences of the version number in the URL or tag; if the guessed | ||
30 | URL is invalid, the old URL is restored. It also tries to download the new URL | ||
31 | to determine the new MD5 checksum. | ||
32 | |||
33 | If a tag is given, it replaces the one from the old rockspec. If there is an old | ||
34 | tag but no new one passed, it is guessed in the same way URL is. | ||
35 | |||
36 | If a directory is not given, it defaults to the current directory. | ||
37 | |||
38 | WARNING: it writes the new rockspec to the given directory, overwriting the file | ||
39 | if it already exists.]], util.see_also()) | ||
40 | :summary("Auto-write a rockspec for a new version of a rock.") | ||
41 | |||
42 | cmd:argument("rock", "Package name or rockspec.") | ||
43 | :args("?") | ||
44 | cmd:argument("new_version", "New version of the rock.") | ||
45 | :args("?") | ||
46 | cmd:argument("new_url", "New URL of the rock.") | ||
47 | :args("?") | ||
48 | |||
49 | cmd:option("--dir", "Output directory for the new rockspec.") | ||
50 | cmd:option("--tag", "New SCM tag.") | ||
51 | end | ||
52 | |||
53 | |||
54 | local function try_replace(tbl, field, old, new) | ||
55 | if not tbl[field] then | ||
56 | return false | ||
57 | end | ||
58 | local old_field = tbl[field] | ||
59 | local new_field = tbl[field]:gsub(old, new) | ||
60 | if new_field ~= old_field then | ||
61 | util.printout("Guessing new '"..field.."' field as "..new_field) | ||
62 | tbl[field] = new_field | ||
63 | return true | ||
64 | end | ||
65 | return false | ||
66 | end | ||
67 | |||
68 | -- Try to download source file using URL from a rockspec. | ||
69 | -- If it specified MD5, update it. | ||
70 | -- @return (true, false) if MD5 was not specified or it stayed same, | ||
71 | -- (true, true) if MD5 changed, (nil, string) on error. | ||
72 | local function check_url_and_update_md5(out_rs, invalid_is_error) | ||
73 | local file, temp_dir = fetch.fetch_url_at_temp_dir(out_rs.source.url, "luarocks-new-version-"..out_rs.package) | ||
74 | if not file then | ||
75 | if invalid_is_error then | ||
76 | return nil, "invalid URL - "..temp_dir | ||
77 | end | ||
78 | util.warning("invalid URL - "..temp_dir) | ||
79 | return true, false | ||
80 | end | ||
81 | do | ||
82 | local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, out_rs.source.url, out_rs.source.dir) | ||
83 | if not inferred_dir then | ||
84 | return nil, found_dir | ||
85 | end | ||
86 | |||
87 | if found_dir and found_dir ~= inferred_dir then | ||
88 | out_rs.source.dir = found_dir | ||
89 | end | ||
90 | end | ||
91 | if file then | ||
92 | if out_rs.source.md5 then | ||
93 | util.printout("File successfully downloaded. Updating MD5 checksum...") | ||
94 | local new_md5, err = fs.get_md5(file) | ||
95 | if not new_md5 then | ||
96 | return nil, err | ||
97 | end | ||
98 | local old_md5 = out_rs.source.md5 | ||
99 | out_rs.source.md5 = new_md5 | ||
100 | return true, new_md5 ~= old_md5 | ||
101 | else | ||
102 | util.printout("File successfully downloaded.") | ||
103 | return true, false | ||
104 | end | ||
105 | end | ||
106 | end | ||
107 | |||
108 | local function update_source_section(out_rs, url, tag, old_ver, new_ver) | ||
109 | if tag then | ||
110 | out_rs.source.tag = tag | ||
111 | end | ||
112 | if url then | ||
113 | out_rs.source.url = url | ||
114 | return check_url_and_update_md5(out_rs) | ||
115 | end | ||
116 | if new_ver == old_ver then | ||
117 | return true | ||
118 | end | ||
119 | if out_rs.source.dir then | ||
120 | try_replace(out_rs.source, "dir", old_ver, new_ver) | ||
121 | end | ||
122 | if out_rs.source.file then | ||
123 | try_replace(out_rs.source, "file", old_ver, new_ver) | ||
124 | end | ||
125 | |||
126 | local old_url = out_rs.source.url | ||
127 | if try_replace(out_rs.source, "url", old_ver, new_ver) then | ||
128 | local ok, md5_changed = check_url_and_update_md5(out_rs, true) | ||
129 | if ok then | ||
130 | return ok, md5_changed | ||
131 | end | ||
132 | out_rs.source.url = old_url | ||
133 | end | ||
134 | if tag or try_replace(out_rs.source, "tag", old_ver, new_ver) then | ||
135 | return true | ||
136 | end | ||
137 | -- Couldn't replace anything significant, use the old URL. | ||
138 | local ok, md5_changed = check_url_and_update_md5(out_rs) | ||
139 | if not ok then | ||
140 | return nil, md5_changed | ||
141 | end | ||
142 | if md5_changed then | ||
143 | util.warning("URL is the same, but MD5 has changed. Old rockspec is broken.") | ||
144 | end | ||
145 | return true | ||
146 | end | ||
147 | |||
148 | function new_version.command(args) | ||
149 | if not args.rock then | ||
150 | local err | ||
151 | args.rock, err = util.get_default_rockspec() | ||
152 | if not args.rock then | ||
153 | return nil, err | ||
154 | end | ||
155 | end | ||
156 | |||
157 | local filename, err | ||
158 | if args.rock:match("rockspec$") then | ||
159 | filename, err = fetch.fetch_url(args.rock) | ||
160 | if not filename then | ||
161 | return nil, err | ||
162 | end | ||
163 | else | ||
164 | filename, err = download.download_file("rockspec", args.rock:lower()) | ||
165 | if not filename then | ||
166 | return nil, err | ||
167 | end | ||
168 | end | ||
169 | |||
170 | local valid_rs, err = fetch.load_rockspec(filename) | ||
171 | if not valid_rs then | ||
172 | return nil, err | ||
173 | end | ||
174 | |||
175 | local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$") | ||
176 | local new_ver, new_rev | ||
177 | |||
178 | if args.tag and not args.new_version then | ||
179 | args.new_version = args.tag:gsub("^v", "") | ||
180 | end | ||
181 | |||
182 | local out_dir | ||
183 | if args.dir then | ||
184 | out_dir = dir.normalize(args.dir) | ||
185 | end | ||
186 | |||
187 | if args.new_version then | ||
188 | new_ver, new_rev = args.new_version:match("(.*)%-(%d+)$") | ||
189 | new_rev = tonumber(new_rev) | ||
190 | if not new_rev then | ||
191 | new_ver = args.new_version | ||
192 | new_rev = 1 | ||
193 | end | ||
194 | else | ||
195 | new_ver = old_ver | ||
196 | new_rev = tonumber(old_rev) + 1 | ||
197 | end | ||
198 | local new_rockver = new_ver:gsub("-", "") | ||
199 | |||
200 | local out_rs, err = persist.load_into_table(filename) | ||
201 | local out_name = out_rs.package:lower() | ||
202 | out_rs.version = new_rockver.."-"..new_rev | ||
203 | |||
204 | local ok, err = update_source_section(out_rs, args.new_url, args.tag, old_ver, new_ver) | ||
205 | if not ok then return nil, err end | ||
206 | |||
207 | if out_rs.build and out_rs.build.type == "module" then | ||
208 | out_rs.build.type = "builtin" | ||
209 | end | ||
210 | |||
211 | local out_filename = out_name.."-"..new_rockver.."-"..new_rev..".rockspec" | ||
212 | if out_dir then | ||
213 | out_filename = dir.path(out_dir, out_filename) | ||
214 | fs.make_dir(out_dir) | ||
215 | end | ||
216 | persist.save_from_table(out_filename, out_rs, type_rockspec.order) | ||
217 | |||
218 | util.printout("Wrote "..out_filename) | ||
219 | |||
220 | local valid_out_rs, err = fetch.load_local_rockspec(out_filename) | ||
221 | if not valid_out_rs then | ||
222 | return nil, "Failed loading generated rockspec: "..err | ||
223 | end | ||
224 | |||
225 | return true | ||
226 | end | ||
227 | |||
228 | return new_version | ||
diff --git a/src/luarocks/cmd/pack.tl b/src/luarocks/cmd/pack.tl new file mode 100644 index 00000000..29a43e7b --- /dev/null +++ b/src/luarocks/cmd/pack.tl | |||
@@ -0,0 +1,36 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "pack" command. | ||
3 | -- Creates a rock, packing sources or binaries. | ||
4 | local cmd_pack = {} | ||
5 | |||
6 | local util = require("luarocks.util") | ||
7 | local pack = require("luarocks.pack") | ||
8 | local queries = require("luarocks.queries") | ||
9 | |||
10 | function cmd_pack.add_to_parser(parser) | ||
11 | local cmd = parser:command("pack", "Create a rock, packing sources or binaries.", util.see_also()) | ||
12 | |||
13 | cmd:argument("rock", "A rockspec file, for creating a source rock, or the ".. | ||
14 | "name of an installed package, for creating a binary rock.") | ||
15 | :action(util.namespaced_name_action) | ||
16 | cmd:argument("version", "A version may be given if the first argument is a rock name.") | ||
17 | :args("?") | ||
18 | |||
19 | cmd:flag("--sign", "Produce a signature file as well.") | ||
20 | end | ||
21 | |||
22 | --- Driver function for the "pack" command. | ||
23 | -- @return boolean or (nil, string): true if successful or nil followed | ||
24 | -- by an error message. | ||
25 | function cmd_pack.command(args) | ||
26 | local file, err | ||
27 | if args.rock:match(".*%.rockspec") then | ||
28 | file, err = pack.pack_source_rock(args.rock) | ||
29 | else | ||
30 | local query = queries.new(args.rock, args.namespace, args.version) | ||
31 | file, err = pack.pack_installed_rock(query, args.tree) | ||
32 | end | ||
33 | return pack.report_and_sign_local_file(file, err, args.sign) | ||
34 | end | ||
35 | |||
36 | return cmd_pack | ||
diff --git a/src/luarocks/cmd/path.tl b/src/luarocks/cmd/path.tl new file mode 100644 index 00000000..ba346550 --- /dev/null +++ b/src/luarocks/cmd/path.tl | |||
@@ -0,0 +1,83 @@ | |||
1 | |||
2 | --- @module luarocks.path_cmd | ||
3 | -- Driver for the `luarocks path` command. | ||
4 | local path_cmd = {} | ||
5 | |||
6 | local util = require("luarocks.util") | ||
7 | local cfg = require("luarocks.core.cfg") | ||
8 | local fs = require("luarocks.fs") | ||
9 | |||
10 | function path_cmd.add_to_parser(parser) | ||
11 | local cmd = parser:command("path", [[ | ||
12 | Returns the package path currently configured for this installation | ||
13 | of LuaRocks, formatted as shell commands to update LUA_PATH and LUA_CPATH. | ||
14 | |||
15 | On Unix systems, you may run: | ||
16 | eval `luarocks path` | ||
17 | And on Windows: | ||
18 | luarocks path > "%temp%\_lrp.bat" | ||
19 | call "%temp%\_lrp.bat" && del "%temp%\_lrp.bat"]], | ||
20 | util.see_also()) | ||
21 | :summary("Return the currently configured package path.") | ||
22 | |||
23 | cmd:flag("--no-bin", "Do not export the PATH variable.") | ||
24 | cmd:flag("--append", "Appends the paths to the existing paths. Default is ".. | ||
25 | "to prefix the LR paths to the existing paths.") | ||
26 | cmd:flag("--lr-path", "Prints Lua path components defined by the configured rocks trees " .. | ||
27 | "(not formatted as a shell command)") | ||
28 | cmd:flag("--lr-cpath", "Prints Lua cpath components defined by the configured rocks trees " .. | ||
29 | "(not formatted as a shell command)") | ||
30 | cmd:flag("--full", "By default, --lr-path and --lr-cpath only include the paths " .. | ||
31 | "derived by the LuaRocks rocks_trees. Using --full includes any other components " .. | ||
32 | "defined in your system's package.(c)path, either via the running interpreter's " .. | ||
33 | "default paths or via LUA_(C)PATH(_5_x) environment variables (in short, using " .. | ||
34 | "--full produces the same lists as shown in the shell outputs of 'luarocks path').") | ||
35 | cmd:flag("--lr-bin", "Exports the system path (not formatted as shell command).") | ||
36 | cmd:flag("--bin"):hidden(true) | ||
37 | end | ||
38 | |||
39 | --- Driver function for "path" command. | ||
40 | -- @return boolean This function always succeeds. | ||
41 | function path_cmd.command(args) | ||
42 | local lr_path, lr_cpath, lr_bin = cfg.package_paths(args.tree) | ||
43 | local path_sep = cfg.export_path_separator | ||
44 | |||
45 | local full_list = ((not args.lr_path) and (not args.lr_cpath) and (not args.lr_bin)) | ||
46 | or args.full | ||
47 | |||
48 | local clean_path = util.cleanup_path(os.getenv("PATH") or "", path_sep, nil, true) | ||
49 | |||
50 | if full_list then | ||
51 | if args.append then | ||
52 | lr_path = package.path .. ";" .. lr_path | ||
53 | lr_cpath = package.cpath .. ";" .. lr_cpath | ||
54 | lr_bin = clean_path .. path_sep .. lr_bin | ||
55 | else | ||
56 | lr_path = lr_path.. ";" .. package.path | ||
57 | lr_cpath = lr_cpath .. ";" .. package.cpath | ||
58 | lr_bin = lr_bin .. path_sep .. clean_path | ||
59 | end | ||
60 | end | ||
61 | |||
62 | if args.lr_path then | ||
63 | util.printout(util.cleanup_path(lr_path, ';', cfg.lua_version, true)) | ||
64 | return true | ||
65 | elseif args.lr_cpath then | ||
66 | util.printout(util.cleanup_path(lr_cpath, ';', cfg.lua_version, true)) | ||
67 | return true | ||
68 | elseif args.lr_bin then | ||
69 | util.printout(util.cleanup_path(lr_bin, path_sep, nil, true)) | ||
70 | return true | ||
71 | end | ||
72 | |||
73 | local lpath_var, lcpath_var = util.lua_path_variables() | ||
74 | |||
75 | util.printout(fs.export_cmd(lpath_var, util.cleanup_path(lr_path, ';', cfg.lua_version, args.append))) | ||
76 | util.printout(fs.export_cmd(lcpath_var, util.cleanup_path(lr_cpath, ';', cfg.lua_version, args.append))) | ||
77 | if not args.no_bin then | ||
78 | util.printout(fs.export_cmd("PATH", util.cleanup_path(lr_bin, path_sep, nil, args.append))) | ||
79 | end | ||
80 | return true | ||
81 | end | ||
82 | |||
83 | return path_cmd | ||
diff --git a/src/luarocks/cmd/purge.tl b/src/luarocks/cmd/purge.tl new file mode 100644 index 00000000..fda8ab88 --- /dev/null +++ b/src/luarocks/cmd/purge.tl | |||
@@ -0,0 +1,72 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "purge" command. | ||
3 | -- Remove all rocks from a given tree. | ||
4 | local purge = {} | ||
5 | |||
6 | local util = require("luarocks.util") | ||
7 | local path = require("luarocks.path") | ||
8 | local search = require("luarocks.search") | ||
9 | local vers = require("luarocks.core.vers") | ||
10 | local repo_writer = require("luarocks.repo_writer") | ||
11 | local cfg = require("luarocks.core.cfg") | ||
12 | local remove = require("luarocks.remove") | ||
13 | local queries = require("luarocks.queries") | ||
14 | |||
15 | function purge.add_to_parser(parser) | ||
16 | -- luacheck: push ignore 431 | ||
17 | local cmd = parser:command("purge", [[ | ||
18 | This command removes rocks en masse from a given tree. | ||
19 | By default, it removes all rocks from a tree. | ||
20 | |||
21 | The --tree option is mandatory: luarocks purge does not assume a default tree.]], | ||
22 | util.see_also()) | ||
23 | :summary("Remove all installed rocks from a tree.") | ||
24 | -- luacheck: pop | ||
25 | |||
26 | cmd:flag("--old-versions", "Keep the highest-numbered version of each ".. | ||
27 | "rock and remove the other ones. By default it only removes old ".. | ||
28 | "versions if they are not needed as dependencies. This can be ".. | ||
29 | "overridden with the flag --force.") | ||
30 | cmd:flag("--force", "If --old-versions is specified, force removal of ".. | ||
31 | "previously installed versions if it would break dependencies.") | ||
32 | cmd:flag("--force-fast", "Like --force, but performs a forced removal ".. | ||
33 | "without reporting dependency issues.") | ||
34 | end | ||
35 | |||
36 | function purge.command(args) | ||
37 | local tree = args.tree | ||
38 | |||
39 | local results = {} | ||
40 | search.local_manifest_search(results, path.rocks_dir(tree), queries.all()) | ||
41 | |||
42 | local sort = function(a,b) return vers.compare_versions(b,a) end | ||
43 | if args.old_versions then | ||
44 | sort = vers.compare_versions | ||
45 | end | ||
46 | |||
47 | for package, versions in util.sortedpairs(results) do | ||
48 | for version, _ in util.sortedpairs(versions, sort) do | ||
49 | if args.old_versions then | ||
50 | util.printout("Keeping "..package.." "..version.."...") | ||
51 | local ok, err, warn = remove.remove_other_versions(package, version, args.force, args.force_fast) | ||
52 | if not ok then | ||
53 | util.printerr(err) | ||
54 | elseif warn then | ||
55 | util.printerr(err) | ||
56 | end | ||
57 | break | ||
58 | else | ||
59 | util.printout("Removing "..package.." "..version.."...") | ||
60 | local ok, err = repo_writer.delete_version(package, version, "none", true) | ||
61 | if not ok then | ||
62 | util.printerr(err) | ||
63 | end | ||
64 | end | ||
65 | end | ||
66 | end | ||
67 | return repo_writer.refresh_manifest(cfg.rocks_dir) | ||
68 | end | ||
69 | |||
70 | purge.needs_lock = function() return true end | ||
71 | |||
72 | return purge | ||
diff --git a/src/luarocks/cmd/remove.tl b/src/luarocks/cmd/remove.tl new file mode 100644 index 00000000..630303ca --- /dev/null +++ b/src/luarocks/cmd/remove.tl | |||
@@ -0,0 +1,71 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "remove" command. | ||
3 | -- Uninstalls rocks. | ||
4 | local cmd_remove = {} | ||
5 | |||
6 | local remove = require("luarocks.remove") | ||
7 | local util = require("luarocks.util") | ||
8 | local cfg = require("luarocks.core.cfg") | ||
9 | local search = require("luarocks.search") | ||
10 | local path = require("luarocks.path") | ||
11 | local deps = require("luarocks.deps") | ||
12 | local queries = require("luarocks.queries") | ||
13 | |||
14 | function cmd_remove.add_to_parser(parser) | ||
15 | -- luacheck: push ignore 431 | ||
16 | local cmd = parser:command("remove", [[ | ||
17 | Uninstall a rock. | ||
18 | |||
19 | If a version is not given, try to remove all versions at once. | ||
20 | Will only perform the removal if it does not break dependencies. | ||
21 | To override this check and force the removal, use --force or --force-fast.]], | ||
22 | util.see_also()) | ||
23 | :summary("Uninstall a rock.") | ||
24 | -- luacheck: pop | ||
25 | |||
26 | cmd:argument("rock", "Name of the rock to be uninstalled.") | ||
27 | :action(util.namespaced_name_action) | ||
28 | cmd:argument("version", "Version of the rock to uninstall.") | ||
29 | :args("?") | ||
30 | |||
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 | ||
35 | |||
36 | --- Driver function for the "remove" command. | ||
37 | -- @return boolean or (nil, string, exitcode): True if removal was | ||
38 | -- successful, nil and an error message otherwise. exitcode is optionally returned. | ||
39 | function cmd_remove.command(args) | ||
40 | local name = args.rock | ||
41 | local deps_mode = deps.get_deps_mode(args) | ||
42 | |||
43 | local rock_type = name:match("%.(rock)$") or name:match("%.(rockspec)$") | ||
44 | local version = args.version | ||
45 | local filename = name | ||
46 | if rock_type then | ||
47 | name, version = path.parse_name(filename) | ||
48 | if not name then return nil, "Invalid "..rock_type.." filename: "..filename end | ||
49 | end | ||
50 | |||
51 | name = name:lower() | ||
52 | |||
53 | local results = {} | ||
54 | search.local_manifest_search(results, cfg.rocks_dir, queries.new(name, args.namespace, version)) | ||
55 | if not results[name] then | ||
56 | local rock = util.format_rock_name(name, args.namespace, version) | ||
57 | return nil, "Could not find rock '"..rock.."' in "..path.rocks_tree_to_string(cfg.root_dir) | ||
58 | end | ||
59 | |||
60 | local ok, err = remove.remove_search_results(results, name, deps_mode, args.force, args.force_fast) | ||
61 | if not ok then | ||
62 | return nil, err | ||
63 | end | ||
64 | |||
65 | deps.check_dependencies(nil, deps.get_deps_mode(args)) | ||
66 | return true | ||
67 | end | ||
68 | |||
69 | cmd_remove.needs_lock = function() return true end | ||
70 | |||
71 | return cmd_remove | ||
diff --git a/src/luarocks/cmd/search.tl b/src/luarocks/cmd/search.tl new file mode 100644 index 00000000..6cab6d80 --- /dev/null +++ b/src/luarocks/cmd/search.tl | |||
@@ -0,0 +1,84 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "search" command. | ||
3 | -- Queries LuaRocks servers. | ||
4 | local cmd_search = {} | ||
5 | |||
6 | local cfg = require("luarocks.core.cfg") | ||
7 | local util = require("luarocks.util") | ||
8 | local search = require("luarocks.search") | ||
9 | local queries = require("luarocks.queries") | ||
10 | local results = require("luarocks.results") | ||
11 | |||
12 | function cmd_search.add_to_parser(parser) | ||
13 | local cmd = parser:command("search", "Query the LuaRocks servers.", util.see_also()) | ||
14 | |||
15 | cmd:argument("name", "Name of the rock to search for.") | ||
16 | :args("?") | ||
17 | :action(util.namespaced_name_action) | ||
18 | cmd:argument("version", "Rock version to search for.") | ||
19 | :args("?") | ||
20 | |||
21 | cmd:flag("--source", "Return only rockspecs and source rocks, to be used ".. | ||
22 | 'with the "build" command.') | ||
23 | cmd:flag("--binary", "Return only pure Lua and binary rocks (rocks that ".. | ||
24 | 'can be used with the "install" command without requiring a C toolchain).') | ||
25 | cmd:flag("--all", "List all contents of the server that are suitable to ".. | ||
26 | "this platform, do not filter by name.") | ||
27 | cmd:flag("--porcelain", "Return a machine readable format.") | ||
28 | end | ||
29 | |||
30 | --- Splits a list of search results into two lists, one for "source" results | ||
31 | -- to be used with the "build" command, and one for "binary" results to be | ||
32 | -- used with the "install" command. | ||
33 | -- @param result_tree table: A search results table. | ||
34 | -- @return (table, table): Two tables, one for source and one for binary | ||
35 | -- results. | ||
36 | local function split_source_and_binary_results(result_tree) | ||
37 | local sources, binaries = {}, {} | ||
38 | for name, versions in pairs(result_tree) do | ||
39 | for version, repositories in pairs(versions) do | ||
40 | for _, repo in ipairs(repositories) do | ||
41 | local where = sources | ||
42 | if repo.arch == "all" or repo.arch == cfg.arch then | ||
43 | where = binaries | ||
44 | end | ||
45 | local entry = results.new(name, version, repo.repo, repo.arch) | ||
46 | search.store_result(where, entry) | ||
47 | end | ||
48 | end | ||
49 | end | ||
50 | return sources, binaries | ||
51 | end | ||
52 | |||
53 | --- Driver function for "search" command. | ||
54 | -- @return boolean or (nil, string): True if build was successful; nil and an | ||
55 | -- error message otherwise. | ||
56 | function cmd_search.command(args) | ||
57 | local name = args.name | ||
58 | |||
59 | if args.all then | ||
60 | name, args.version = "", nil | ||
61 | end | ||
62 | |||
63 | if not args.name and not args.all then | ||
64 | return nil, "Enter name and version or use --all. "..util.see_help("search") | ||
65 | end | ||
66 | |||
67 | local query = queries.new(name, args.namespace, args.version, true) | ||
68 | local result_tree, err = search.search_repos(query) | ||
69 | local porcelain = args.porcelain | ||
70 | local full_name = util.format_rock_name(name, args.namespace, args.version) | ||
71 | util.title(full_name .. " - Search results for Lua "..cfg.lua_version..":", porcelain, "=") | ||
72 | local sources, binaries = split_source_and_binary_results(result_tree) | ||
73 | if next(sources) and not args.binary then | ||
74 | util.title("Rockspecs and source rocks:", porcelain) | ||
75 | search.print_result_tree(sources, porcelain) | ||
76 | end | ||
77 | if next(binaries) and not args.source then | ||
78 | util.title("Binary and pure-Lua rocks:", porcelain) | ||
79 | search.print_result_tree(binaries, porcelain) | ||
80 | end | ||
81 | return true | ||
82 | end | ||
83 | |||
84 | return cmd_search | ||
diff --git a/src/luarocks/cmd/show.tl b/src/luarocks/cmd/show.tl new file mode 100644 index 00000000..88cbbada --- /dev/null +++ b/src/luarocks/cmd/show.tl | |||
@@ -0,0 +1,314 @@ | |||
1 | --- Module implementing the LuaRocks "show" command. | ||
2 | -- Shows information about an installed rock. | ||
3 | local show = {} | ||
4 | |||
5 | local queries = require("luarocks.queries") | ||
6 | local search = require("luarocks.search") | ||
7 | local dir = require("luarocks.core.dir") | ||
8 | local fs = require("luarocks.fs") | ||
9 | local cfg = require("luarocks.core.cfg") | ||
10 | local util = require("luarocks.util") | ||
11 | local path = require("luarocks.path") | ||
12 | local fetch = require("luarocks.fetch") | ||
13 | local manif = require("luarocks.manif") | ||
14 | local repos = require("luarocks.repos") | ||
15 | |||
16 | function show.add_to_parser(parser) | ||
17 | local cmd = parser:command("show", [[ | ||
18 | Show information about an installed rock. | ||
19 | |||
20 | Without any flags, show all module information. | ||
21 | With flags, return only the desired information.]], util.see_also()) | ||
22 | :summary("Show information about an installed rock.") | ||
23 | |||
24 | cmd:argument("rock", "Name of an installed rock.") | ||
25 | :action(util.namespaced_name_action) | ||
26 | cmd:argument("version", "Rock version.") | ||
27 | :args("?") | ||
28 | |||
29 | cmd:flag("--home", "Show home page of project.") | ||
30 | cmd:flag("--modules", "Show all modules provided by the package as used by require().") | ||
31 | cmd:flag("--deps", "Show packages the package depends on.") | ||
32 | cmd:flag("--build-deps", "Show build-only dependencies for the package.") | ||
33 | cmd:flag("--test-deps", "Show dependencies for testing the package.") | ||
34 | cmd:flag("--rockspec", "Show the full path of the rockspec file.") | ||
35 | cmd:flag("--mversion", "Show the package version.") | ||
36 | cmd:flag("--rock-tree", "Show local tree where rock is installed.") | ||
37 | cmd:flag("--rock-namespace", "Show rock namespace.") | ||
38 | cmd:flag("--rock-dir", "Show data directory of the installed rock.") | ||
39 | cmd:flag("--rock-license", "Show rock license.") | ||
40 | cmd:flag("--issues", "Show URL for project's issue tracker.") | ||
41 | cmd:flag("--labels", "List the labels of the rock.") | ||
42 | cmd:flag("--porcelain", "Produce machine-friendly output.") | ||
43 | end | ||
44 | |||
45 | local friendly_template = [[ | ||
46 | : | ||
47 | ?namespace:${namespace}/${package} ${version} - ${summary} | ||
48 | !namespace:${package} ${version} - ${summary} | ||
49 | : | ||
50 | *detailed :${detailed} | ||
51 | ?detailed : | ||
52 | ?license :License: \t${license} | ||
53 | ?homepage :Homepage: \t${homepage} | ||
54 | ?issues :Issues: \t${issues} | ||
55 | ?labels :Labels: \t${labels} | ||
56 | ?location :Installed in: \t${location} | ||
57 | ?commands : | ||
58 | ?commands :Commands: | ||
59 | *commands :\t${name} (${file}) | ||
60 | ?modules : | ||
61 | ?modules :Modules: | ||
62 | *modules :\t${name} (${file}) | ||
63 | ?bdeps : | ||
64 | ?bdeps :Has build dependency on: | ||
65 | *bdeps :\t${name} (${label}) | ||
66 | ?tdeps : | ||
67 | ?tdeps :Tests depend on: | ||
68 | *tdeps :\t${name} (${label}) | ||
69 | ?deps : | ||
70 | ?deps :Depends on: | ||
71 | *deps :\t${name} (${label}) | ||
72 | ?ideps : | ||
73 | ?ideps :Indirectly pulling: | ||
74 | *ideps :\t${name} (${label}) | ||
75 | : | ||
76 | ]] | ||
77 | |||
78 | local porcelain_template = [[ | ||
79 | ?namespace:namespace\t${namespace} | ||
80 | ?package :package\t${package} | ||
81 | ?version :version\t${version} | ||
82 | ?summary :summary\t${summary} | ||
83 | *detailed :detailed\t${detailed} | ||
84 | ?license :license\t${license} | ||
85 | ?homepage :homepage\t${homepage} | ||
86 | ?issues :issues\t${issues} | ||
87 | ?labels :labels\t${labels} | ||
88 | ?location :location\t${location} | ||
89 | *commands :command\t${name}\t${file} | ||
90 | *modules :module\t${name}\t${file} | ||
91 | *bdeps :build_dependency\t${name}\t${label} | ||
92 | *tdeps :test_dependency\t${name}\t${label} | ||
93 | *deps :dependency\t${name}\t${label} | ||
94 | *ideps :indirect_dependency\t${name}\t${label} | ||
95 | ]] | ||
96 | |||
97 | local function keys_as_string(t, sep) | ||
98 | local keys = util.keys(t) | ||
99 | table.sort(keys) | ||
100 | return table.concat(keys, sep or " ") | ||
101 | end | ||
102 | |||
103 | local function word_wrap(line) | ||
104 | local width = tonumber(os.getenv("COLUMNS")) or 80 | ||
105 | if width > 80 then width = 80 end | ||
106 | if #line > width then | ||
107 | local brk = width | ||
108 | while brk > 0 and line:sub(brk, brk) ~= " " do | ||
109 | brk = brk - 1 | ||
110 | end | ||
111 | if brk > 0 then | ||
112 | return line:sub(1, brk-1) .. "\n" .. word_wrap(line:sub(brk+1)) | ||
113 | end | ||
114 | end | ||
115 | return line | ||
116 | end | ||
117 | |||
118 | local function format_text(text) | ||
119 | text = text:gsub("^%s*",""):gsub("%s$", ""):gsub("\n[ \t]+","\n"):gsub("([^\n])\n([^\n])","%1 %2") | ||
120 | local paragraphs = util.split_string(text, "\n\n") | ||
121 | for n, line in ipairs(paragraphs) do | ||
122 | paragraphs[n] = word_wrap(line) | ||
123 | end | ||
124 | return (table.concat(paragraphs, "\n\n"):gsub("%s$", "")) | ||
125 | end | ||
126 | |||
127 | local function installed_rock_label(dep, tree) | ||
128 | local installed, version | ||
129 | local rocks_provided = util.get_rocks_provided() | ||
130 | if rocks_provided[dep.name] then | ||
131 | installed, version = true, rocks_provided[dep.name] | ||
132 | else | ||
133 | installed, version = search.pick_installed_rock(dep, tree) | ||
134 | end | ||
135 | return installed and "using "..version or "missing" | ||
136 | end | ||
137 | |||
138 | local function render(template, data) | ||
139 | local out = {} | ||
140 | for cmd, var, line in template:gmatch("(.)([a-z]*)%s*:([^\n]*)\n") do | ||
141 | line = line:gsub("\\t", "\t") | ||
142 | local d = data[var] | ||
143 | if cmd == " " then | ||
144 | table.insert(out, line) | ||
145 | elseif cmd == "?" or cmd == "*" or cmd == "!" then | ||
146 | if (cmd == "!" and d == nil) | ||
147 | or (cmd ~= "!" and (type(d) == "string" | ||
148 | or (type(d) == "table" and next(d)))) then | ||
149 | local n = cmd == "*" and #d or 1 | ||
150 | for i = 1, n do | ||
151 | local tbl = cmd == "*" and d[i] or data | ||
152 | if type(tbl) == "string" then | ||
153 | tbl = tbl:gsub("%%", "%%%%") | ||
154 | end | ||
155 | table.insert(out, (line:gsub("${([a-z]+)}", tbl))) | ||
156 | end | ||
157 | end | ||
158 | end | ||
159 | end | ||
160 | return table.concat(out, "\n") | ||
161 | end | ||
162 | |||
163 | local function adjust_path(name, version, basedir, pathname, suffix) | ||
164 | pathname = dir.path(basedir, pathname) | ||
165 | local vpathname = path.versioned_name(pathname, basedir, name, version) | ||
166 | return (fs.exists(vpathname) | ||
167 | and vpathname | ||
168 | or pathname) .. (suffix or "") | ||
169 | end | ||
170 | |||
171 | local function modules_to_list(name, version, repo) | ||
172 | local ret = {} | ||
173 | local rock_manifest = manif.load_rock_manifest(name, version, repo) | ||
174 | |||
175 | local lua_dir = path.deploy_lua_dir(repo) | ||
176 | local lib_dir = path.deploy_lib_dir(repo) | ||
177 | repos.recurse_rock_manifest_entry(rock_manifest.lua, function(pathname) | ||
178 | table.insert(ret, { | ||
179 | name = path.path_to_module(pathname), | ||
180 | file = adjust_path(name, version, lua_dir, pathname), | ||
181 | }) | ||
182 | end) | ||
183 | repos.recurse_rock_manifest_entry(rock_manifest.lib, function(pathname) | ||
184 | table.insert(ret, { | ||
185 | name = path.path_to_module(pathname), | ||
186 | file = adjust_path(name, version, lib_dir, pathname), | ||
187 | }) | ||
188 | end) | ||
189 | table.sort(ret, function(a, b) | ||
190 | if a.name == b.name then | ||
191 | return a.file < b.file | ||
192 | end | ||
193 | return a.name < b.name | ||
194 | end) | ||
195 | return ret | ||
196 | end | ||
197 | |||
198 | local function commands_to_list(name, version, repo) | ||
199 | local ret = {} | ||
200 | local rock_manifest = manif.load_rock_manifest(name, version, repo) | ||
201 | |||
202 | local bin_dir = path.deploy_bin_dir(repo) | ||
203 | repos.recurse_rock_manifest_entry(rock_manifest.bin, function(pathname) | ||
204 | table.insert(ret, { | ||
205 | name = name, | ||
206 | file = adjust_path(name, version, bin_dir, pathname, cfg.wrapper_suffix), | ||
207 | }) | ||
208 | end) | ||
209 | table.sort(ret, function(a, b) | ||
210 | if a.name == b.name then | ||
211 | return a.file < b.file | ||
212 | end | ||
213 | return a.name < b.name | ||
214 | end) | ||
215 | return ret | ||
216 | end | ||
217 | |||
218 | local function deps_to_list(dependencies, tree) | ||
219 | local ret = {} | ||
220 | for _, dep in ipairs(dependencies or {}) do | ||
221 | table.insert(ret, { name = tostring(dep), label = installed_rock_label(dep, tree) }) | ||
222 | end | ||
223 | return ret | ||
224 | end | ||
225 | |||
226 | local function indirect_deps(mdeps, rdeps, tree) | ||
227 | local ret = {} | ||
228 | local direct_deps = {} | ||
229 | for _, dep in ipairs(rdeps) do | ||
230 | direct_deps[dep] = true | ||
231 | end | ||
232 | for dep_name in util.sortedpairs(mdeps or {}) do | ||
233 | if not direct_deps[dep_name] then | ||
234 | table.insert(ret, { name = tostring(dep_name), label = installed_rock_label(queries.new(dep_name), tree) }) | ||
235 | end | ||
236 | end | ||
237 | return ret | ||
238 | end | ||
239 | |||
240 | local function show_rock(template, namespace, name, version, rockspec, repo, minfo, tree) | ||
241 | local desc = rockspec.description or {} | ||
242 | local data = { | ||
243 | namespace = namespace, | ||
244 | package = rockspec.package, | ||
245 | version = rockspec.version, | ||
246 | summary = desc.summary or "", | ||
247 | detailed = desc.detailed and util.split_string(format_text(desc.detailed), "\n"), | ||
248 | license = desc.license, | ||
249 | homepage = desc.homepage, | ||
250 | issues = desc.issues_url, | ||
251 | labels = desc.labels and table.concat(desc.labels, ", "), | ||
252 | location = path.rocks_tree_to_string(repo), | ||
253 | commands = commands_to_list(name, version, repo), | ||
254 | modules = modules_to_list(name, version, repo), | ||
255 | bdeps = deps_to_list(rockspec.build_dependencies, tree), | ||
256 | tdeps = deps_to_list(rockspec.test_dependencies, tree), | ||
257 | deps = deps_to_list(rockspec.dependencies, tree), | ||
258 | ideps = indirect_deps(minfo.dependencies, rockspec.dependencies, tree), | ||
259 | } | ||
260 | util.printout(render(template, data)) | ||
261 | end | ||
262 | |||
263 | --- Driver function for "show" command. | ||
264 | -- @return boolean: True if succeeded, nil on errors. | ||
265 | function show.command(args) | ||
266 | local query = queries.new(args.rock, args.namespace, args.version, true) | ||
267 | |||
268 | local name, version, repo, repo_url = search.pick_installed_rock(query, args.tree) | ||
269 | if not name then | ||
270 | return nil, version | ||
271 | end | ||
272 | local tree = path.rocks_tree_to_string(repo) | ||
273 | local directory = path.install_dir(name, version, repo) | ||
274 | local namespace = path.read_namespace(name, version, tree) | ||
275 | local rockspec_file = path.rockspec_file(name, version, repo) | ||
276 | local rockspec, err = fetch.load_local_rockspec(rockspec_file) | ||
277 | if not rockspec then return nil,err end | ||
278 | |||
279 | local descript = rockspec.description or {} | ||
280 | local manifest, err = manif.load_manifest(repo_url) | ||
281 | if not manifest then return nil,err end | ||
282 | local minfo = manifest.repository[name][version][1] | ||
283 | |||
284 | if args.rock_tree then util.printout(tree) | ||
285 | elseif args.rock_namespace then util.printout(namespace) | ||
286 | elseif args.rock_dir then util.printout(directory) | ||
287 | elseif args.home then util.printout(descript.homepage) | ||
288 | elseif args.rock_license then util.printout(descript.license) | ||
289 | elseif args.issues then util.printout(descript.issues_url) | ||
290 | elseif args.labels then util.printout(descript.labels and table.concat(descript.labels, "\n")) | ||
291 | elseif args.modules then util.printout(keys_as_string(minfo.modules, "\n")) | ||
292 | elseif args.deps then | ||
293 | for _, dep in ipairs(rockspec.dependencies) do | ||
294 | util.printout(tostring(dep)) | ||
295 | end | ||
296 | elseif args.build_deps then | ||
297 | for _, dep in ipairs(rockspec.build_dependencies) do | ||
298 | util.printout(tostring(dep)) | ||
299 | end | ||
300 | elseif args.test_deps then | ||
301 | for _, dep in ipairs(rockspec.test_dependencies) do | ||
302 | util.printout(tostring(dep)) | ||
303 | end | ||
304 | elseif args.rockspec then util.printout(rockspec_file) | ||
305 | elseif args.mversion then util.printout(version) | ||
306 | elseif args.porcelain then | ||
307 | show_rock(porcelain_template, namespace, name, version, rockspec, repo, minfo, args.tree) | ||
308 | else | ||
309 | show_rock(friendly_template, namespace, name, version, rockspec, repo, minfo, args.tree) | ||
310 | end | ||
311 | return true | ||
312 | end | ||
313 | |||
314 | return show | ||
diff --git a/src/luarocks/cmd/test.tl b/src/luarocks/cmd/test.tl new file mode 100644 index 00000000..b353bd80 --- /dev/null +++ b/src/luarocks/cmd/test.tl | |||
@@ -0,0 +1,48 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "test" command. | ||
3 | -- Tests a rock, compiling its C parts if any. | ||
4 | local cmd_test = {} | ||
5 | |||
6 | local util = require("luarocks.util") | ||
7 | local test = require("luarocks.test") | ||
8 | |||
9 | function cmd_test.add_to_parser(parser) | ||
10 | local cmd = parser:command("test", [[ | ||
11 | Run the test suite for the Lua project in the current directory. | ||
12 | |||
13 | If the first argument is a rockspec, it will use it to determine the parameters | ||
14 | for running tests; otherwise, it will attempt to detect the rockspec. | ||
15 | |||
16 | Any additional arguments are forwarded to the test suite. | ||
17 | To make sure that test suite flags are not interpreted as LuaRocks flags, use -- | ||
18 | to separate LuaRocks arguments from test suite arguments.]], | ||
19 | util.see_also()) | ||
20 | :summary("Run the test suite in the current directory.") | ||
21 | |||
22 | cmd:argument("rockspec", "Project rockspec.") | ||
23 | :args("?") | ||
24 | cmd:argument("args", "Test suite arguments.") | ||
25 | :args("*") | ||
26 | cmd:flag("--prepare", "Only install dependencies needed for testing only, but do not run the test") | ||
27 | |||
28 | cmd:option("--test-type", "Specify the test suite type manually if it was ".. | ||
29 | "not specified in the rockspec and it could not be auto-detected.") | ||
30 | :argname("<type>") | ||
31 | end | ||
32 | |||
33 | function cmd_test.command(args) | ||
34 | if args.rockspec and args.rockspec:match("rockspec$") then | ||
35 | return test.run_test_suite(args.rockspec, args.test_type, args.args, args.prepare) | ||
36 | end | ||
37 | |||
38 | table.insert(args.args, 1, args.rockspec) | ||
39 | |||
40 | local rockspec, err = util.get_default_rockspec() | ||
41 | if not rockspec then | ||
42 | return nil, err | ||
43 | end | ||
44 | |||
45 | return test.run_test_suite(rockspec, args.test_type, args.args, args.prepare) | ||
46 | end | ||
47 | |||
48 | return cmd_test | ||
diff --git a/src/luarocks/cmd/unpack.tl b/src/luarocks/cmd/unpack.tl new file mode 100644 index 00000000..a0ade4f3 --- /dev/null +++ b/src/luarocks/cmd/unpack.tl | |||
@@ -0,0 +1,169 @@ | |||
1 | |||
2 | --- Module implementing the LuaRocks "unpack" command. | ||
3 | -- Unpack the contents of a rock. | ||
4 | local unpack = {} | ||
5 | |||
6 | local fetch = require("luarocks.fetch") | ||
7 | local fs = require("luarocks.fs") | ||
8 | local util = require("luarocks.util") | ||
9 | local build = require("luarocks.build") | ||
10 | local dir = require("luarocks.dir") | ||
11 | local search = require("luarocks.search") | ||
12 | |||
13 | function unpack.add_to_parser(parser) | ||
14 | local cmd = parser:command("unpack", [[ | ||
15 | Unpacks the contents of a rock in a newly created directory. | ||
16 | Argument may be a rock file, or the name of a rock in a rocks server. | ||
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.") | ||
20 | |||
21 | cmd:argument("rock", "A rock file or the name of a rock.") | ||
22 | :action(util.namespaced_name_action) | ||
23 | cmd:argument("version", "Rock version.") | ||
24 | :args("?") | ||
25 | |||
26 | cmd:flag("--force", "Unpack files even if the output directory already exists.") | ||
27 | cmd:flag("--check-lua-versions", "If the rock can't be found, check repository ".. | ||
28 | "and report if it is available for another Lua version.") | ||
29 | end | ||
30 | |||
31 | --- Load a rockspec file to the given directory, fetches the source | ||
32 | -- files specified in the rockspec, and unpack them inside the directory. | ||
33 | -- @param rockspec_file string: The URL for a rockspec file. | ||
34 | -- @param dir_name string: The directory where to store and unpack files. | ||
35 | -- @return table or (nil, string): the loaded rockspec table or | ||
36 | -- nil and an error message. | ||
37 | local function unpack_rockspec(rockspec_file, dir_name) | ||
38 | assert(type(rockspec_file) == "string") | ||
39 | assert(type(dir_name) == "string") | ||
40 | |||
41 | local rockspec, err = fetch.load_rockspec(rockspec_file) | ||
42 | if not rockspec then | ||
43 | return nil, "Failed loading rockspec "..rockspec_file..": "..err | ||
44 | end | ||
45 | local ok, err = fs.change_dir(dir_name) | ||
46 | if not ok then return nil, err end | ||
47 | local ok, sources_dir = fetch.fetch_sources(rockspec, true, ".") | ||
48 | if not ok then | ||
49 | return nil, sources_dir | ||
50 | end | ||
51 | ok, err = fs.change_dir(sources_dir) | ||
52 | if not ok then return nil, err end | ||
53 | ok, err = build.apply_patches(rockspec) | ||
54 | fs.pop_dir() | ||
55 | if not ok then return nil, err end | ||
56 | return rockspec | ||
57 | end | ||
58 | |||
59 | --- Load a .rock file to the given directory and unpack it inside it. | ||
60 | -- @param rock_file string: The URL for a .rock file. | ||
61 | -- @param dir_name string: The directory where to unpack. | ||
62 | -- @param kind string: the kind of rock file, as in the second-level | ||
63 | -- extension in the rock filename (eg. "src", "all", "linux-x86") | ||
64 | -- @return table or (nil, string): the loaded rockspec table or | ||
65 | -- nil and an error message. | ||
66 | local function unpack_rock(rock_file, dir_name, kind) | ||
67 | assert(type(rock_file) == "string") | ||
68 | assert(type(dir_name) == "string") | ||
69 | |||
70 | local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, dir_name) | ||
71 | if not ok then | ||
72 | return nil, err, errcode | ||
73 | end | ||
74 | ok, err = fs.change_dir(dir_name) | ||
75 | if not ok then return nil, err end | ||
76 | local rockspec_file = dir_name..".rockspec" | ||
77 | local rockspec, err = fetch.load_rockspec(rockspec_file) | ||
78 | if not rockspec then | ||
79 | return nil, "Failed loading rockspec "..rockspec_file..": "..err | ||
80 | end | ||
81 | if kind == "src" then | ||
82 | if rockspec.source.file then | ||
83 | local ok, err = fs.unpack_archive(rockspec.source.file) | ||
84 | if not ok then return nil, err end | ||
85 | ok, err = fetch.find_rockspec_source_dir(rockspec, ".") | ||
86 | if not ok then return nil, err end | ||
87 | ok, err = fs.change_dir(rockspec.source.dir) | ||
88 | if not ok then return nil, err end | ||
89 | ok, err = build.apply_patches(rockspec) | ||
90 | fs.pop_dir() | ||
91 | if not ok then return nil, err end | ||
92 | end | ||
93 | end | ||
94 | return rockspec | ||
95 | end | ||
96 | |||
97 | --- Create a directory and perform the necessary actions so that | ||
98 | -- the sources for the rock and its rockspec are unpacked inside it, | ||
99 | -- laid out properly so that the 'make' command is able to build the module. | ||
100 | -- @param file string: A rockspec or .rock URL. | ||
101 | -- @return boolean or (nil, string): true if successful or nil followed | ||
102 | -- by an error message. | ||
103 | local function run_unpacker(file, force) | ||
104 | assert(type(file) == "string") | ||
105 | |||
106 | local base_name = dir.base_name(file) | ||
107 | local dir_name, kind, extension = base_name:match("(.*)%.([^.]+)%.(rock)$") | ||
108 | if not extension then | ||
109 | dir_name, extension = base_name:match("(.*)%.(rockspec)$") | ||
110 | kind = "rockspec" | ||
111 | end | ||
112 | if not extension then | ||
113 | return nil, file.." does not seem to be a valid filename." | ||
114 | end | ||
115 | |||
116 | local exists = fs.exists(dir_name) | ||
117 | if exists and not force then | ||
118 | return nil, "Directory "..dir_name.." already exists." | ||
119 | end | ||
120 | if not exists then | ||
121 | local ok, err = fs.make_dir(dir_name) | ||
122 | if not ok then return nil, err end | ||
123 | end | ||
124 | local rollback = util.schedule_function(fs.delete, fs.absolute_name(dir_name)) | ||
125 | |||
126 | local rockspec, err | ||
127 | if extension == "rock" then | ||
128 | rockspec, err = unpack_rock(file, dir_name, kind) | ||
129 | elseif extension == "rockspec" then | ||
130 | rockspec, err = unpack_rockspec(file, dir_name) | ||
131 | end | ||
132 | if not rockspec then | ||
133 | return nil, err | ||
134 | end | ||
135 | if kind == "src" or kind == "rockspec" then | ||
136 | fetch.find_rockspec_source_dir(rockspec, ".") | ||
137 | if rockspec.source.dir ~= "." then | ||
138 | local ok = fs.copy(rockspec.local_abs_filename, rockspec.source.dir, "read") | ||
139 | if not ok then | ||
140 | return nil, "Failed copying unpacked rockspec into unpacked source directory." | ||
141 | end | ||
142 | end | ||
143 | util.printout() | ||
144 | util.printout("Done. You may now enter directory ") | ||
145 | util.printout(dir.path(dir_name, rockspec.source.dir)) | ||
146 | util.printout("and type 'luarocks make' to build.") | ||
147 | end | ||
148 | util.remove_scheduled_function(rollback) | ||
149 | return true | ||
150 | end | ||
151 | |||
152 | --- Driver function for the "unpack" command. | ||
153 | -- @return boolean or (nil, string): true if successful or nil followed | ||
154 | -- by an error message. | ||
155 | function unpack.command(args) | ||
156 | local url, err | ||
157 | if args.rock:match(".*%.rock") or args.rock:match(".*%.rockspec") then | ||
158 | url = args.rock | ||
159 | else | ||
160 | url, err = search.find_src_or_rockspec(args.rock, args.namespace, args.version, args.check_lua_versions) | ||
161 | if not url then | ||
162 | return nil, err | ||
163 | end | ||
164 | end | ||
165 | |||
166 | return run_unpacker(url, args.force) | ||
167 | end | ||
168 | |||
169 | return unpack | ||
diff --git a/src/luarocks/cmd/upload.tl b/src/luarocks/cmd/upload.tl new file mode 100644 index 00000000..6b84e452 --- /dev/null +++ b/src/luarocks/cmd/upload.tl | |||
@@ -0,0 +1,128 @@ | |||
1 | |||
2 | local upload = {} | ||
3 | |||
4 | local signing = require("luarocks.signing") | ||
5 | local util = require("luarocks.util") | ||
6 | local fetch = require("luarocks.fetch") | ||
7 | local pack = require("luarocks.pack") | ||
8 | local cfg = require("luarocks.core.cfg") | ||
9 | local Api = require("luarocks.upload.api") | ||
10 | |||
11 | function upload.add_to_parser(parser) | ||
12 | local cmd = parser:command("upload", "Pack a source rock file (.src.rock extension) ".. | ||
13 | "and upload it and the rockspec to the public rocks repository.", util.see_also()) | ||
14 | :summary("Upload a rockspec to the public rocks repository.") | ||
15 | |||
16 | cmd:argument("rockspec", "Rockspec for the rock to upload.") | ||
17 | cmd:argument("src-rock", "A corresponding .src.rock file; if not given it will be generated.") | ||
18 | :args("?") | ||
19 | |||
20 | cmd:flag("--skip-pack", "Do not pack and send source rock.") | ||
21 | cmd:option("--api-key", "Pass an API key. It will be stored for subsequent uses.") | ||
22 | :argname("<key>") | ||
23 | cmd:option("--temp-key", "Use the given a temporary API key in this ".. | ||
24 | "invocation only. It will not be stored.") | ||
25 | :argname("<key>") | ||
26 | cmd:flag("--force", "Replace existing rockspec if the same revision of a ".. | ||
27 | "module already exists. This should be used only in case of upload ".. | ||
28 | "mistakes: when updating a rockspec, increment the revision number ".. | ||
29 | "instead.") | ||
30 | cmd:flag("--sign", "Upload a signature file alongside each file as well.") | ||
31 | cmd:flag("--debug"):hidden(true) | ||
32 | end | ||
33 | |||
34 | local function is_dev_version(version) | ||
35 | return version:match("^dev") or version:match("^scm") | ||
36 | end | ||
37 | |||
38 | function upload.command(args) | ||
39 | local api, err = Api.new(args) | ||
40 | if not api then | ||
41 | return nil, err | ||
42 | end | ||
43 | if cfg.verbose then | ||
44 | api.debug = true | ||
45 | end | ||
46 | |||
47 | local rockspec, err, errcode = fetch.load_rockspec(args.rockspec) | ||
48 | if err then | ||
49 | return nil, err, errcode | ||
50 | end | ||
51 | |||
52 | util.printout("Sending " .. tostring(args.rockspec) .. " ...") | ||
53 | local res, err = api:method("check_rockspec", { | ||
54 | package = rockspec.package, | ||
55 | version = rockspec.version | ||
56 | }) | ||
57 | if not res then return nil, err end | ||
58 | |||
59 | if not res.module then | ||
60 | util.printout("Will create new module (" .. tostring(rockspec.package) .. ")") | ||
61 | end | ||
62 | if res.version and not args.force then | ||
63 | return nil, "Revision "..rockspec.version.." already exists on the server. "..util.see_help("upload") | ||
64 | end | ||
65 | |||
66 | local sigfname | ||
67 | local rock_sigfname | ||
68 | |||
69 | if args.sign then | ||
70 | sigfname, err = signing.sign_file(args.rockspec) | ||
71 | if err then | ||
72 | return nil, "Failed signing rockspec: " .. err | ||
73 | end | ||
74 | util.printout("Signed rockspec: "..sigfname) | ||
75 | end | ||
76 | |||
77 | local rock_fname | ||
78 | if args.src_rock then | ||
79 | rock_fname = args.src_rock | ||
80 | elseif not args.skip_pack and not is_dev_version(rockspec.version) then | ||
81 | util.printout("Packing " .. tostring(rockspec.package)) | ||
82 | rock_fname, err = pack.pack_source_rock(args.rockspec) | ||
83 | if not rock_fname then | ||
84 | return nil, err | ||
85 | end | ||
86 | end | ||
87 | |||
88 | if rock_fname and args.sign then | ||
89 | rock_sigfname, err = signing.sign_file(rock_fname) | ||
90 | if err then | ||
91 | return nil, "Failed signing rock: " .. err | ||
92 | end | ||
93 | util.printout("Signed packed rock: "..rock_sigfname) | ||
94 | end | ||
95 | |||
96 | local multipart = require("luarocks.upload.multipart") | ||
97 | |||
98 | res, err = api:method("upload", nil, { | ||
99 | rockspec_file = multipart.new_file(args.rockspec), | ||
100 | rockspec_sig = sigfname and multipart.new_file(sigfname), | ||
101 | }) | ||
102 | if not res then return nil, err end | ||
103 | |||
104 | if res.is_new and #res.manifests == 0 then | ||
105 | util.printerr("Warning: module not added to root manifest due to name taken.") | ||
106 | end | ||
107 | |||
108 | local module_url = res.module_url | ||
109 | |||
110 | if rock_fname then | ||
111 | if (not res.version) or (not res.version.id) then | ||
112 | return nil, "Invalid response from server." | ||
113 | end | ||
114 | util.printout(("Sending " .. tostring(rock_fname) .. " ...")) | ||
115 | res, err = api:method("upload_rock/" .. ("%d"):format(res.version.id), nil, { | ||
116 | rock_file = multipart.new_file(rock_fname), | ||
117 | rock_sig = rock_sigfname and multipart.new_file(rock_sigfname), | ||
118 | }) | ||
119 | if not res then return nil, err end | ||
120 | end | ||
121 | |||
122 | util.printout() | ||
123 | util.printout("Done: " .. tostring(module_url)) | ||
124 | util.printout() | ||
125 | return true | ||
126 | end | ||
127 | |||
128 | return upload | ||
diff --git a/src/luarocks/cmd/which.tl b/src/luarocks/cmd/which.tl new file mode 100644 index 00000000..f50a43c3 --- /dev/null +++ b/src/luarocks/cmd/which.tl | |||
@@ -0,0 +1,40 @@ | |||
1 | |||
2 | --- @module luarocks.which_cmd | ||
3 | -- Driver for the `luarocks which` command. | ||
4 | local which_cmd = {} | ||
5 | |||
6 | local loader = require("luarocks.loader") | ||
7 | local cfg = require("luarocks.core.cfg") | ||
8 | local util = require("luarocks.util") | ||
9 | |||
10 | function which_cmd.add_to_parser(parser) | ||
11 | local cmd = parser:command("which", 'Given a module name like "foo.bar", '.. | ||
12 | "output which file would be loaded to resolve that module by ".. | ||
13 | 'luarocks.loader, like "/usr/local/lua/'..cfg.lua_version..'/foo/bar.lua".', | ||
14 | util.see_also()) | ||
15 | :summary("Tell which file corresponds to a given module name.") | ||
16 | |||
17 | cmd:argument("modname", "Module name.") | ||
18 | end | ||
19 | |||
20 | --- Driver function for "which" command. | ||
21 | -- @return boolean This function terminates the interpreter. | ||
22 | function which_cmd.command(args) | ||
23 | local pathname, rock_name, rock_version, where = loader.which(args.modname, "lp") | ||
24 | |||
25 | if pathname then | ||
26 | util.printout(pathname) | ||
27 | if where == "l" then | ||
28 | util.printout("(provided by " .. tostring(rock_name) .. " " .. tostring(rock_version) .. ")") | ||
29 | else | ||
30 | local key = rock_name | ||
31 | util.printout("(found directly via package." .. key.. " -- not installed as a rock?)") | ||
32 | end | ||
33 | return true | ||
34 | end | ||
35 | |||
36 | return nil, "Module '" .. args.modname .. "' not found." | ||
37 | end | ||
38 | |||
39 | return which_cmd | ||
40 | |||
diff --git a/src/luarocks/cmd/write_rockspec.tl b/src/luarocks/cmd/write_rockspec.tl new file mode 100644 index 00000000..e8d65cba --- /dev/null +++ b/src/luarocks/cmd/write_rockspec.tl | |||
@@ -0,0 +1,425 @@ | |||
1 | |||
2 | local record write_rockspec | ||
3 | end | ||
4 | |||
5 | local builtin = require("luarocks.build.builtin") | ||
6 | local cfg = require("luarocks.core.cfg") | ||
7 | local dir = require("luarocks.dir") | ||
8 | local fetch = require("luarocks.fetch") | ||
9 | local fs = require("luarocks.fs") | ||
10 | local persist = require("luarocks.persist") | ||
11 | local rockspecs = require("luarocks.rockspecs") | ||
12 | local type_rockspec = require("luarocks.type.rockspec") | ||
13 | local util = require("luarocks.util") | ||
14 | |||
15 | local argparse = require("luarocks.vendor.argparse") | ||
16 | local type Parser = argparse.Parser | ||
17 | local type Option = argparse.Option | ||
18 | |||
19 | local type a = require("luarocks.core.types.args") | ||
20 | local type Args = a.Args | ||
21 | |||
22 | local type p = require("luarocks.core.types.persist") | ||
23 | local type PersistableTable = p.PersistableTable | ||
24 | |||
25 | local type b = require("luarocks.core.types.build") | ||
26 | local type BuiltinBuild = b.BuiltinBuild | ||
27 | |||
28 | local type r = require("luarocks.core.types.rockspec") | ||
29 | local type Rockspec = r.Rockspec | ||
30 | local type Dependencies = r.Dependencies | ||
31 | |||
32 | local lua_versions = { | ||
33 | "5.1", | ||
34 | "5.2", | ||
35 | "5.3", | ||
36 | "5.4", | ||
37 | "5.1,5.2", | ||
38 | "5.2,5.3", | ||
39 | "5.3,5.4", | ||
40 | "5.1,5.2,5.3", | ||
41 | "5.2,5.3,5.4", | ||
42 | "5.1,5.2,5.3,5.4" | ||
43 | } | ||
44 | |||
45 | function write_rockspec.cmd_options(parser: Parser): Option, Option, Option, Option, Option, Option, Option, Option, Option | ||
46 | return parser:option("--output", "Write the rockspec with the given filename.\n".. | ||
47 | "If not given, a file is written in the current directory with a ".. | ||
48 | "filename based on given name and version.") | ||
49 | :argname("<file>"), | ||
50 | parser:option("--license", 'A license string, such as "MIT/X11" or "GNU GPL v3".') | ||
51 | :argname("<string>"), | ||
52 | parser:option("--summary", "A short one-line description summary.") | ||
53 | :argname("<txt>"), | ||
54 | parser:option("--detailed", "A longer description string.") | ||
55 | :argname("<txt>"), | ||
56 | parser:option("--homepage", "Project homepage.") | ||
57 | :argname("<txt>"), | ||
58 | parser:option("--lua-versions", 'Supported Lua versions. Accepted values are: "'.. | ||
59 | table.concat(lua_versions, '", "')..'".') | ||
60 | :argname("<ver>") | ||
61 | :choices(lua_versions), | ||
62 | parser:option("--rockspec-format", 'Rockspec format version, such as "1.0" or "1.1".') | ||
63 | :argname("<ver>"), | ||
64 | parser:option("--tag", "Tag to use. Will attempt to extract version number from it."), | ||
65 | parser:option("--lib", "A comma-separated list of libraries that C files need to link to.") | ||
66 | :argname("<libs>") | ||
67 | end | ||
68 | |||
69 | function write_rockspec.add_to_parser(parser: Parser) | ||
70 | local cmd = parser:command("write_rockspec", [[ | ||
71 | This command writes an initial version of a rockspec file, | ||
72 | based on a name, a version, and a location (an URL or a local path). | ||
73 | If only two arguments are given, the first one is considered the name and the | ||
74 | second one is the location. | ||
75 | If only one argument is given, it must be the location. | ||
76 | If no arguments are given, current directory is used as the location. | ||
77 | LuaRocks will attempt to infer name and version if not given, | ||
78 | using 'dev' as a fallback default version. | ||
79 | |||
80 | Note that the generated file is a _starting point_ for writing a | ||
81 | rockspec, and is not guaranteed to be complete or correct. ]], util.see_also()) | ||
82 | :summary("Write a template for a rockspec file.") | ||
83 | |||
84 | cmd:argument("name", "Name of the rock.") | ||
85 | :args("?") | ||
86 | cmd:argument("version", "Rock version.") | ||
87 | :args("?") | ||
88 | cmd:argument("location", "URL or path to the rock sources.") | ||
89 | :args("?") | ||
90 | |||
91 | write_rockspec.cmd_options(cmd) --! | ||
92 | end | ||
93 | |||
94 | local function open_file(name: string): FILE, string, integer | ||
95 | return io.open(dir.path(fs.current_dir(), name), "r") | ||
96 | end | ||
97 | |||
98 | local function fetch_url(rockspec: Rockspec): boolean, string, string | ||
99 | local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false) | ||
100 | if err_code == "source.dir" then | ||
101 | file, temp_dir = err_file, err_temp_dir | ||
102 | elseif not file then | ||
103 | util.warning("Could not fetch sources - "..temp_dir) | ||
104 | return false | ||
105 | end | ||
106 | util.printout("File successfully downloaded. Making checksum and checking base dir...") | ||
107 | if dir.is_basic_protocol(rockspec.source.protocol) then | ||
108 | rockspec.source.md5 = fs.get_md5(file) | ||
109 | end | ||
110 | local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url) | ||
111 | return true, found_dir or inferred_dir, temp_dir | ||
112 | end | ||
113 | |||
114 | local lua_version_dep = { | ||
115 | ["5.1"] = "lua ~> 5.1", | ||
116 | ["5.2"] = "lua ~> 5.2", | ||
117 | ["5.3"] = "lua ~> 5.3", | ||
118 | ["5.4"] = "lua ~> 5.4", | ||
119 | ["5.1,5.2"] = "lua >= 5.1, < 5.3", | ||
120 | ["5.2,5.3"] = "lua >= 5.2, < 5.4", | ||
121 | ["5.3,5.4"] = "lua >= 5.3, < 5.5", | ||
122 | ["5.1,5.2,5.3"] = "lua >= 5.1, < 5.4", | ||
123 | ["5.2,5.3,5.4"] = "lua >= 5.2, < 5.5", | ||
124 | ["5.1,5.2,5.3,5.4"] = "lua >= 5.1, < 5.5", | ||
125 | } | ||
126 | |||
127 | local simple_scm_protocols = { | ||
128 | git = true, | ||
129 | ["git+http"] = true, | ||
130 | ["git+https"] = true, | ||
131 | ["git+ssh"] = true, | ||
132 | hg = true, | ||
133 | ["hg+http"] = true, | ||
134 | ["hg+https"] = true, | ||
135 | ["hg+ssh"] = true, | ||
136 | } | ||
137 | |||
138 | local detect_url: function(string): string | ||
139 | do | ||
140 | local function detect_url_from_command(program: string, args: string, directory: string): string | ||
141 | local command = fs.Q(cfg.variables[program:upper()]).. " "..args | ||
142 | local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command))) | ||
143 | if not pipe then return nil end | ||
144 | local url = pipe:read("*a"):match("^([^\r\n]+)") | ||
145 | pipe:close() | ||
146 | if not url then return nil end | ||
147 | if url:match("^[^@:/]+@[^@:/]+:.*$") then | ||
148 | local u, h, p = url:match("^([^@]+)@([^:]+):(.*)$") | ||
149 | url = program.."+ssh://"..u.."@"..h.."/"..p | ||
150 | elseif not util.starts_with(url, program.."://") then | ||
151 | url = program.."+"..url | ||
152 | end | ||
153 | |||
154 | if (simple_scm_protocols as {string: boolean})[dir.split_url(url)] then | ||
155 | return url | ||
156 | end | ||
157 | end | ||
158 | |||
159 | local function detect_scm_url(directory: string): string | ||
160 | return detect_url_from_command("git", "config --get remote.origin.url", directory) or | ||
161 | detect_url_from_command("hg", "paths default", directory) | ||
162 | end | ||
163 | |||
164 | detect_url = function(url_or_dir: string): string | ||
165 | if url_or_dir:match("://") then | ||
166 | return url_or_dir | ||
167 | else | ||
168 | return detect_scm_url(url_or_dir) or "*** please add URL for source tarball, zip or repository here ***" | ||
169 | end | ||
170 | end | ||
171 | end | ||
172 | |||
173 | local function detect_homepage(url: string, homepage: string): string | ||
174 | if homepage then | ||
175 | return homepage | ||
176 | end | ||
177 | local url_protocol, url_path = dir.split_url(url) | ||
178 | |||
179 | if (simple_scm_protocols as {string: boolean})[url_protocol] then | ||
180 | for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do | ||
181 | if util.starts_with(url_path, domain) then | ||
182 | return "https://"..url_path:gsub("%.git$", "") | ||
183 | end | ||
184 | end | ||
185 | end | ||
186 | |||
187 | return "*** please enter a project homepage ***" | ||
188 | end | ||
189 | |||
190 | local function detect_description(): string, string | ||
191 | local fd = open_file("README.md") or open_file("README") | ||
192 | if not fd then return end | ||
193 | local data = fd:read("*a") | ||
194 | fd:close() | ||
195 | local paragraph = data:match("\n\n([^%[].-)\n\n") | ||
196 | if not paragraph then paragraph = data:match("\n\n(.*)") end | ||
197 | local summary, detailed: string, string | ||
198 | if paragraph then | ||
199 | detailed = paragraph | ||
200 | |||
201 | if #paragraph < 80 then | ||
202 | summary = paragraph:gsub("\n", "") | ||
203 | else | ||
204 | summary = paragraph:gsub("\n", " "):match("([^.]*%.) ") | ||
205 | end | ||
206 | end | ||
207 | return summary, detailed | ||
208 | end | ||
209 | |||
210 | local licenses = { | ||
211 | [78656] = "MIT", | ||
212 | [49311] = "ISC", | ||
213 | } | ||
214 | |||
215 | local function detect_license(data: string): string | ||
216 | local strip_copyright = (data:gsub("^Copyright [^\n]*\n", "")) | ||
217 | local sum = 0 | ||
218 | for i = 1, #strip_copyright do | ||
219 | local num = string.byte(strip_copyright:sub(i,i)) | ||
220 | if num > 32 and num <= 128 then | ||
221 | sum = sum + num | ||
222 | end | ||
223 | end | ||
224 | return licenses[sum] | ||
225 | end | ||
226 | |||
227 | local function check_license(): string, string | ||
228 | local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt") | ||
229 | if not fd then return nil end | ||
230 | local data = fd:read("*a") | ||
231 | fd:close() | ||
232 | local license = detect_license(data) | ||
233 | if license then | ||
234 | return license, data | ||
235 | end | ||
236 | return nil, data | ||
237 | end | ||
238 | |||
239 | local function fill_as_builtin(rockspec: Rockspec, libs: {string}) | ||
240 | rockspec.build.type = "builtin" | ||
241 | |||
242 | local incdirs, libdirs: {string}, {string} | ||
243 | if libs then | ||
244 | incdirs, libdirs = {}, {} | ||
245 | for _, lib in ipairs(libs) do | ||
246 | local upper = lib:upper() | ||
247 | incdirs[#incdirs+1] = "$("..upper.."_INCDIR)" | ||
248 | libdirs[#libdirs+1] = "$("..upper.."_LIBDIR)" | ||
249 | end | ||
250 | end | ||
251 | (rockspec.build as BuiltinBuild).modules, rockspec.build.install, rockspec.build.copy_directories = builtin.autodetect_modules(libs, incdirs, libdirs) | ||
252 | end | ||
253 | |||
254 | local function rockspec_cleanup(rockspec: Rockspec) | ||
255 | rockspec.source.file = nil | ||
256 | rockspec.source.protocol = nil | ||
257 | rockspec.source.identifier = nil | ||
258 | rockspec.source.dir = nil | ||
259 | rockspec.source.dir_set = nil | ||
260 | rockspec.source.pathname = nil | ||
261 | rockspec.variables = nil | ||
262 | rockspec.name = nil | ||
263 | rockspec.format_is_at_least = nil | ||
264 | rockspec.local_abs_filename = nil | ||
265 | rockspec.rocks_provided = nil | ||
266 | for _, list in ipairs({"dependencies", "build_dependencies", "test_dependencies"}) do | ||
267 | if (rockspec as {string: Dependencies})[list] and not next((rockspec as {string: Dependencies})[list]) then | ||
268 | (rockspec as {string: Dependencies})[list] = nil | ||
269 | end | ||
270 | end | ||
271 | for _, list in ipairs({"dependencies", "build_dependencies", "test_dependencies"}) do | ||
272 | if (rockspec as {string: Dependencies})[list] then | ||
273 | for i, entry in ipairs((rockspec as {string: Dependencies})[list]) do | ||
274 | (rockspec as {string: Dependencies})[list][i] = tostring(entry) | ||
275 | end | ||
276 | end | ||
277 | end | ||
278 | end | ||
279 | |||
280 | function write_rockspec.command(args: Args): boolean, string | ||
281 | local name, version = args.name, args.version | ||
282 | local location = args.location | ||
283 | |||
284 | if not name then | ||
285 | location = "." | ||
286 | elseif not version then | ||
287 | location = name | ||
288 | name = nil | ||
289 | elseif not location then | ||
290 | location = version | ||
291 | version = nil | ||
292 | end | ||
293 | |||
294 | if args.tag then | ||
295 | if not version then | ||
296 | version = args.tag:gsub("^v", "") | ||
297 | end | ||
298 | end | ||
299 | |||
300 | local protocol, pathname = dir.split_url(location) | ||
301 | if protocol == "file" then | ||
302 | if pathname == "." then | ||
303 | name = name or dir.base_name(fs.current_dir()) | ||
304 | end | ||
305 | elseif dir.is_basic_protocol(protocol) then | ||
306 | local filename = dir.base_name(location) | ||
307 | local newname, newversion = filename:match("(.*)-([^-]+)") | ||
308 | if newname then | ||
309 | name = name or newname | ||
310 | version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "") | ||
311 | end | ||
312 | else | ||
313 | name = name or dir.base_name(location):gsub("%.[^.]+$", "") | ||
314 | end | ||
315 | |||
316 | if not name then | ||
317 | return nil, "Could not infer rock name. "..util.see_help("write_rockspec") | ||
318 | end | ||
319 | version = version or "dev" | ||
320 | |||
321 | local filename = args.output or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") | ||
322 | |||
323 | local url = detect_url(location) | ||
324 | local homepage = detect_homepage(url, args.homepage) | ||
325 | |||
326 | local rockspec, err = rockspecs.from_persisted_table(filename, { | ||
327 | rockspec_format = args.rockspec_format, | ||
328 | package = name, | ||
329 | version = version.."-1", | ||
330 | source = { | ||
331 | url = url, | ||
332 | tag = args.tag, | ||
333 | }, | ||
334 | description = { | ||
335 | summary = args.summary or "*** please specify description summary ***", | ||
336 | detailed = args.detailed or "*** please enter a detailed description ***", | ||
337 | homepage = homepage, | ||
338 | license = args.license or "*** please specify a license ***", | ||
339 | }, | ||
340 | dependencies = { | ||
341 | (lua_version_dep as {string: string})[args.lua_versions], | ||
342 | }, | ||
343 | build = {}, | ||
344 | }) | ||
345 | assert(not err, err) | ||
346 | rockspec.source.protocol = protocol | ||
347 | |||
348 | if not next(rockspec.dependencies) then | ||
349 | util.warning("Please specify supported Lua versions with --lua-versions=<ver>. "..util.see_help("write_rockspec")) | ||
350 | end | ||
351 | |||
352 | local local_dir = location | ||
353 | |||
354 | if location:match("://") then | ||
355 | rockspec.source.file = dir.base_name(location) | ||
356 | if not dir.is_basic_protocol(rockspec.source.protocol) then | ||
357 | if version ~= "dev" then | ||
358 | rockspec.source.tag = args.tag or "v" .. version | ||
359 | end | ||
360 | end | ||
361 | rockspec.source.dir = nil | ||
362 | local ok, base_dir, temp_dir = fetch_url(rockspec) | ||
363 | if ok then | ||
364 | if base_dir ~= dir.base_name(location) then | ||
365 | rockspec.source.dir = base_dir | ||
366 | end | ||
367 | end | ||
368 | if base_dir then | ||
369 | local_dir = dir.path(temp_dir, base_dir) | ||
370 | else | ||
371 | local_dir = nil | ||
372 | end | ||
373 | end | ||
374 | |||
375 | if not local_dir then | ||
376 | local_dir = "." | ||
377 | end | ||
378 | |||
379 | local libs: {string} = nil | ||
380 | if args.lib then | ||
381 | libs = {} | ||
382 | rockspec.external_dependencies = {} | ||
383 | for lib in args.lib:gmatch("([^,]+)") do | ||
384 | table.insert(libs, lib) | ||
385 | rockspec.external_dependencies[lib:upper()] = { | ||
386 | library = lib | ||
387 | } | ||
388 | end | ||
389 | end | ||
390 | |||
391 | local ok, err = fs.change_dir(local_dir) | ||
392 | if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end | ||
393 | |||
394 | if not (args.summary and args.detailed) then | ||
395 | local summary, detailed = detect_description() | ||
396 | rockspec.description.summary = args.summary or summary | ||
397 | rockspec.description.detailed = args.detailed or detailed | ||
398 | end | ||
399 | |||
400 | if not args.license then | ||
401 | local license, fulltext = check_license() | ||
402 | if license then | ||
403 | rockspec.description.license = license | ||
404 | elseif license then | ||
405 | util.title("Could not auto-detect type for project license:") | ||
406 | util.printout(fulltext) | ||
407 | util.printout() | ||
408 | util.title("Please fill in the source.license field manually or use --license.") | ||
409 | end | ||
410 | end | ||
411 | |||
412 | fill_as_builtin(rockspec, libs) | ||
413 | |||
414 | rockspec_cleanup(rockspec) | ||
415 | |||
416 | persist.save_from_table(filename, rockspec as PersistableTable, type_rockspec.order) | ||
417 | |||
418 | util.printout() | ||
419 | util.printout("Wrote template at "..filename.." -- you should now edit and finish it.") | ||
420 | util.printout() | ||
421 | |||
422 | return true | ||
423 | end | ||
424 | |||
425 | return write_rockspec | ||
diff --git a/src/luarocks/core/cfg.d.tl b/src/luarocks/core/cfg.d.tl index cbe53663..7dea5b32 100644 --- a/src/luarocks/core/cfg.d.tl +++ b/src/luarocks/core/cfg.d.tl | |||
@@ -38,19 +38,15 @@ local record cfg | |||
38 | -- queries | 38 | -- queries |
39 | arch: string | 39 | arch: string |
40 | -- api | 40 | -- api |
41 | record conf | ||
42 | file: string | ||
43 | found: boolean | ||
44 | end | ||
45 | |||
41 | record config_files | 46 | record config_files |
42 | record system | 47 | system: conf |
43 | file: string | 48 | user: conf |
44 | found: boolean | 49 | project: conf |
45 | end | ||
46 | record user | ||
47 | file: string | ||
48 | found: boolean | ||
49 | end | ||
50 | record project | ||
51 | file: string | ||
52 | found: boolean | ||
53 | end | ||
54 | end | 50 | end |
55 | -- type_check | 51 | -- type_check |
56 | accept_unknown_fields: boolean | 52 | accept_unknown_fields: boolean |
@@ -109,6 +105,8 @@ local record cfg | |||
109 | project_dir: string | 105 | project_dir: string |
110 | verbose: boolean | 106 | verbose: boolean |
111 | project_tree: string | 107 | project_tree: string |
108 | -- cmd make | ||
109 | keep_other_versions: boolean | ||
112 | end | 110 | end |
113 | 111 | ||
114 | return cfg \ No newline at end of file | 112 | return cfg \ No newline at end of file |
diff --git a/src/luarocks/core/types/args.d.tl b/src/luarocks/core/types/args.d.tl index a8e4ef88..a4f240cc 100644 --- a/src/luarocks/core/types/args.d.tl +++ b/src/luarocks/core/types/args.d.tl | |||
@@ -21,6 +21,52 @@ local record args | |||
21 | only_sources: string | 21 | only_sources: string |
22 | no_manifest: boolean | 22 | no_manifest: boolean |
23 | force_lock: boolean | 23 | force_lock: boolean |
24 | rockspec: string | ||
25 | namespace: string | ||
26 | pack_binary_rock: boolean | ||
27 | only_deps: boolean | ||
28 | branch: string | ||
29 | verify: boolean --! | ||
30 | check_lua_versions: boolean --! | ||
31 | pin: boolean | ||
32 | no_install: boolean | ||
33 | sign: boolean | ||
34 | no_doc: boolean | ||
35 | keep: boolean | ||
36 | force: boolean | ||
37 | force_fast: boolean | ||
38 | rock: string | ||
39 | version: string | ||
40 | scope: string | ||
41 | lua_incdir: string | ||
42 | lua_libdir: string | ||
43 | lua_ver: string | ||
44 | system_config: string | ||
45 | user_config: string | ||
46 | rock_trees: string | ||
47 | unset: boolean | ||
48 | json: boolean | ||
49 | home: boolean | ||
50 | porcelain: boolean | ||
51 | list: boolean --! | ||
52 | name: string | ||
53 | all: boolean | ||
54 | source: string | ||
55 | arch: string | ||
56 | location: string | ||
57 | tag: string | ||
58 | output: string | ||
59 | homepage: string | ||
60 | rockspec_format: string | ||
61 | summary: string | ||
62 | detailed: string | ||
63 | license: string | ||
64 | lua_versions: string | ||
65 | lib: string | ||
66 | no_gitignore: boolean | ||
67 | no_wrapper_scripts: boolean | ||
68 | wrapper_dir: string | ||
69 | reset: boolean | ||
24 | end | 70 | end |
25 | end | 71 | end |
26 | 72 | ||
diff --git a/src/luarocks/core/types/bopts.d.tl b/src/luarocks/core/types/bopts.d.tl new file mode 100644 index 00000000..81575c0c --- /dev/null +++ b/src/luarocks/core/types/bopts.d.tl | |||
@@ -0,0 +1,17 @@ | |||
1 | local record bopts | ||
2 | record BOpts | ||
3 | build_only_deps: boolean | ||
4 | deps_mode: string | ||
5 | verify: boolean | ||
6 | minimal_mode: boolean | ||
7 | need_to_fetch: boolean | ||
8 | branch: string | ||
9 | no_install: boolean | ||
10 | pin: boolean | ||
11 | namespace: string | ||
12 | check_lua_versions: boolean | ||
13 | rebuild: boolean | ||
14 | end | ||
15 | end | ||
16 | |||
17 | return bopts \ No newline at end of file | ||
diff --git a/src/luarocks/core/types/installs.d.tl b/src/luarocks/core/types/installs.d.tl index 57ad750a..ec406760 100644 --- a/src/luarocks/core/types/installs.d.tl +++ b/src/luarocks/core/types/installs.d.tl | |||
@@ -12,6 +12,16 @@ local record installs | |||
12 | bin: InstallDir | 12 | bin: InstallDir |
13 | end | 13 | end |
14 | 14 | ||
15 | record IOpts | ||
16 | namespace: string | ||
17 | deps_mode: string | ||
18 | force: boolean | ||
19 | force_fast: boolean | ||
20 | verify: boolean | ||
21 | no_doc: boolean | ||
22 | keep: boolean | ||
23 | end | ||
24 | |||
15 | end | 25 | end |
16 | 26 | ||
17 | return installs \ No newline at end of file | 27 | return installs \ No newline at end of file |
diff --git a/src/luarocks/deps.tl b/src/luarocks/deps.tl index 69c739ca..1f5f24aa 100644 --- a/src/luarocks/deps.tl +++ b/src/luarocks/deps.tl | |||
@@ -41,6 +41,9 @@ local type dr = require("luarocks.core.types.dir") | |||
41 | local type Dir = dr.Dir | 41 | local type Dir = dr.Dir |
42 | local type Dirs = dr.Dirs | 42 | local type Dirs = dr.Dirs |
43 | 43 | ||
44 | local type arg = require("luarocks.core.types.args") | ||
45 | local type Args = arg.Args | ||
46 | |||
44 | --- Generate a function that matches dep queries against the manifest, | 47 | --- Generate a function that matches dep queries against the manifest, |
45 | -- taking into account rocks_provided, the list of versions to skip, | 48 | -- taking into account rocks_provided, the list of versions to skip, |
46 | -- and the lockfile. | 49 | -- and the lockfile. |
@@ -761,7 +764,7 @@ local function find_lua_incdir(prefix: string, luaver: string, luajitver: string | |||
761 | end | 764 | end |
762 | 765 | ||
763 | function deps.check_lua_incdir(vars: {string: string}): boolean, string, string | 766 | function deps.check_lua_incdir(vars: {string: string}): boolean, string, string |
764 | if vars.LUA_INCDIR_OK == "ok" | 767 | if vars.LUA_INCDIR_OK == "ok" --! fix later |
765 | then return true | 768 | then return true |
766 | end | 769 | end |
767 | 770 | ||
@@ -846,7 +849,7 @@ function deps.check_lua_libdir(vars: {string: string}): boolean, string, string, | |||
846 | end | 849 | end |
847 | end | 850 | end |
848 | 851 | ||
849 | function deps.get_deps_mode(args: {string: string}): string | 852 | function deps.get_deps_mode(args: Args): string |
850 | return args.deps_mode or cfg.deps_mode | 853 | return args.deps_mode or cfg.deps_mode |
851 | end | 854 | end |
852 | 855 | ||
diff --git a/src/luarocks/download.tl b/src/luarocks/download.tl index 508f74b4..f993da0f 100644 --- a/src/luarocks/download.tl +++ b/src/luarocks/download.tl | |||
@@ -59,7 +59,7 @@ function download.download_all(arch: string, name: string, namespace: string, ve | |||
59 | return nil, "Could not find a result named "..rock..(search_err and ": "..search_err or ".") | 59 | return nil, "Could not find a result named "..rock..(search_err and ": "..search_err or ".") |
60 | end | 60 | end |
61 | 61 | ||
62 | function download.download_file(arch: string, name: string, namespace: string, version: string, check_lua_versions?: boolean): string, string | 62 | function download.download_file(arch: string, name: string, namespace?: string, version?: string, check_lua_versions?: boolean): string, string |
63 | local query = queries.new(name, namespace, version, false, arch) | 63 | local query = queries.new(name, namespace, version, false, arch) |
64 | local search_err: string | 64 | local search_err: string |
65 | 65 | ||
diff --git a/src/luarocks/fetch.tl b/src/luarocks/fetch.tl index 30c45b56..ccd8680e 100644 --- a/src/luarocks/fetch.tl +++ b/src/luarocks/fetch.tl | |||
@@ -311,7 +311,7 @@ end | |||
311 | -- be nil if not found), or nil followed by an error message. | 311 | -- be nil if not found), or nil followed by an error message. |
312 | -- The inferred dir is returned first to avoid confusion with errors, | 312 | -- The inferred dir is returned first to avoid confusion with errors, |
313 | -- because it is never nil. | 313 | -- because it is never nil. |
314 | function fetch.find_base_dir(file: string, temp_dir: string, src_url: string, src_dir: string): string, string | 314 | function fetch.find_base_dir(file: string, temp_dir: string, src_url: string, src_dir?: string): string, string |
315 | local ok, err = fs.change_dir(temp_dir) | 315 | local ok, err = fs.change_dir(temp_dir) |
316 | if not ok then return nil, err end | 316 | if not ok then return nil, err end |
317 | fs.unpack_archive(file) | 317 | fs.unpack_archive(file) |
diff --git a/src/luarocks/fs.d.tl b/src/luarocks/fs.d.tl index f3ff6eb2..a0fca017 100644 --- a/src/luarocks/fs.d.tl +++ b/src/luarocks/fs.d.tl | |||
@@ -75,6 +75,13 @@ local record fs | |||
75 | modules: function(string): {string} | 75 | modules: function(string): {string} |
76 | system_cache_dir: function(): string | 76 | system_cache_dir: function(): string |
77 | check_command_permissions: function(Args): boolean, string | 77 | check_command_permissions: function(Args): boolean, string |
78 | -- cmd config | ||
79 | is_writable: function(string): boolean | ||
80 | browser: function(string): boolean | ||
81 | -- cmd write_rockspec | ||
82 | quiet_stderr: function(string): string | ||
83 | -- cmd innit | ||
84 | wrap_script: function(string, string, string, ...:string): boolean, string | ||
78 | end | 85 | end |
79 | 86 | ||
80 | return fs | 87 | return fs |
diff --git a/src/luarocks/pack.tl b/src/luarocks/pack.tl index 7b257161..037a1069 100644 --- a/src/luarocks/pack.tl +++ b/src/luarocks/pack.tl | |||
@@ -159,7 +159,7 @@ function pack.report_and_sign_local_file(file: string, err: string, sign: boolea | |||
159 | return true | 159 | return true |
160 | end | 160 | end |
161 | 161 | ||
162 | function pack.pack_binary_rock(name: string, namespace: string, version: string, sign: boolean, cmd: function(): (boolean, string)): boolean, string | 162 | function pack.pack_binary_rock(name: string, namespace: string, version: string, sign: boolean, cmd: function(): (string, string)): boolean, string |
163 | 163 | ||
164 | -- The --pack-binary-rock option for "luarocks build" basically performs | 164 | -- The --pack-binary-rock option for "luarocks build" basically performs |
165 | -- "luarocks build" on a temporary tree and then "luarocks pack". The | 165 | -- "luarocks build" on a temporary tree and then "luarocks pack". The |
diff --git a/src/luarocks/persist.tl b/src/luarocks/persist.tl index cc07d295..a2666563 100644 --- a/src/luarocks/persist.tl +++ b/src/luarocks/persist.tl | |||
@@ -4,6 +4,11 @@ | |||
4 | local record persist | 4 | local record persist |
5 | run_file: function(string, {string:any}): boolean, any | string, string | 5 | run_file: function(string, {string:any}): boolean, any | string, string |
6 | load_into_table: function(string, ?{string:any}) : {any: any}, {any: any} | string, string | 6 | load_into_table: function(string, ?{string:any}) : {any: any}, {any: any} | string, string |
7 | |||
8 | interface Writer | ||
9 | write: function(self: Writer, data: string) | ||
10 | buffer: {number | string} | ||
11 | end | ||
7 | end | 12 | end |
8 | 13 | ||
9 | local core = require("luarocks.core.persist") | 14 | local core = require("luarocks.core.persist") |
@@ -20,14 +25,11 @@ local type SortBy = o.SortBy | |||
20 | local type p = require("luarocks.core.types.persist") | 25 | local type p = require("luarocks.core.types.persist") |
21 | local type PersistableTable = p.PersistableTable | 26 | local type PersistableTable = p.PersistableTable |
22 | 27 | ||
28 | local type Writer = persist.Writer | ||
29 | |||
23 | persist.run_file = core.run_file | 30 | persist.run_file = core.run_file |
24 | persist.load_into_table = core.load_into_table | 31 | persist.load_into_table = core.load_into_table |
25 | 32 | ||
26 | local interface Writer | ||
27 | write: function(self: Writer, data: string) | ||
28 | buffer: {number | string} | ||
29 | end | ||
30 | |||
31 | local write_table: function(out: Writer, tbl: PersistableTable, level: integer, sort_by: SortBy<number | string>) | 33 | local write_table: function(out: Writer, tbl: PersistableTable, level: integer, sort_by: SortBy<number | string>) |
32 | 34 | ||
33 | --- Write a value as Lua code. | 35 | --- Write a value as Lua code. |
@@ -38,7 +40,7 @@ local write_table: function(out: Writer, tbl: PersistableTable, level: integer, | |||
38 | -- @param level number: the indentation level | 40 | -- @param level number: the indentation level |
39 | -- @param sub_order table: optional prioritization table | 41 | -- @param sub_order table: optional prioritization table |
40 | -- @see write_table | 42 | -- @see write_table |
41 | function persist.write_value(out: Writer, v: any, level: integer, sub_order?: SortBy<number | string>) | 43 | function persist.write_value(out: Writer, v: any, level?: integer, sub_order?: SortBy<number | string>) |
42 | if v is PersistableTable then | 44 | if v is PersistableTable then |
43 | level = level or 0 | 45 | level = level or 0 |
44 | write_table(out, v, level + 1, sub_order) | 46 | write_table(out, v, level + 1, sub_order) |
diff --git a/src/luarocks/util.tl b/src/luarocks/util.tl index 27a9c117..53e363a5 100644 --- a/src/luarocks/util.tl +++ b/src/luarocks/util.tl | |||
@@ -53,7 +53,9 @@ util.matchquote = core.matchquote | |||
53 | local type Fn = util.Fn | 53 | local type Fn = util.Fn |
54 | local type r = require("luarocks.core.types.rockspec") | 54 | local type r = require("luarocks.core.types.rockspec") |
55 | local type Rockspec = r.Rockspec | 55 | local type Rockspec = r.Rockspec |
56 | local type Parser = util.Parser | 56 | |
57 | local argparse = require("luarocks.vendor.argparse") | ||
58 | local type Parser = argparse.Parser | ||
57 | 59 | ||
58 | 60 | ||
59 | local scheduled_functions: {Fn} = {} | 61 | local scheduled_functions: {Fn} = {} |
@@ -207,7 +209,7 @@ function util.printout(...: string) | |||
207 | io.stdout:write("\n") | 209 | io.stdout:write("\n") |
208 | end | 210 | end |
209 | 211 | ||
210 | function util.title(msg: string, porcelain: boolean, underline: string) | 212 | function util.title(msg: string, porcelain?: boolean, underline?: string) |
211 | if porcelain then return end | 213 | if porcelain then return end |
212 | util.printout() | 214 | util.printout() |
213 | util.printout(msg) | 215 | util.printout(msg) |
@@ -241,7 +243,7 @@ function util.format_rock_name(name: string, namespace: string, version: string) | |||
241 | return (namespace and namespace.."/" or "")..name..(version and " "..version or "") | 243 | return (namespace and namespace.."/" or "")..name..(version and " "..version or "") |
242 | end | 244 | end |
243 | 245 | ||
244 | function util.deps_mode_option(parser: Parser, program: string) | 246 | function util.deps_mode_option(parser: Parser, program?: string) |
245 | 247 | ||
246 | parser:option("--deps-mode", "How to handle dependencies. Four modes are supported:\n".. | 248 | parser:option("--deps-mode", "How to handle dependencies. Four modes are supported:\n".. |
247 | "* all - use all trees from the rocks_trees list for finding dependencies\n".. | 249 | "* all - use all trees from the rocks_trees list for finding dependencies\n".. |
@@ -258,7 +260,7 @@ function util.deps_mode_option(parser: Parser, program: string) | |||
258 | parser:flag("--nodeps"):hidden(true) | 260 | parser:flag("--nodeps"):hidden(true) |
259 | end | 261 | end |
260 | 262 | ||
261 | function util.see_help(command: string, program: string): string | 263 | function util.see_help(command: string, program?: string): string |
262 | return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." | 264 | return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." |
263 | end | 265 | end |
264 | 266 | ||
diff --git a/src/luarocks/vendor/argparse.d.tl b/src/luarocks/vendor/argparse.d.tl index 42e35787..812786c4 100644 --- a/src/luarocks/vendor/argparse.d.tl +++ b/src/luarocks/vendor/argparse.d.tl | |||
@@ -34,6 +34,8 @@ local record argparse | |||
34 | add_help_command: function(self: Parser, ?string | {string: any}): Parser | 34 | add_help_command: function(self: Parser, ?string | {string: any}): Parser |
35 | add_complete_command: function(self: Parser, ?string | {string: any}): Parser | 35 | add_complete_command: function(self: Parser, ?string | {string: any}): Parser |
36 | 36 | ||
37 | group: function(self: Parser, ...:any): Parser | ||
38 | |||
37 | -- TODO: should be Argument | Option | 39 | -- TODO: should be Argument | Option |
38 | mutex: function(self: Parser, ...: any) | 40 | mutex: function(self: Parser, ...: any) |
39 | 41 | ||
@@ -94,9 +96,13 @@ local record argparse | |||
94 | 96 | ||
95 | option: function(self: Command, name: string, description: string): Option | 97 | option: function(self: Command, name: string, description: string): Option |
96 | 98 | ||
97 | flag: function(self: Command, string, string): Option | 99 | flag: function(self: Command, string, ?string): Option |
98 | 100 | ||
99 | handle_options: function(self: Command, boolean): Command | 101 | handle_options: function(self: Command, boolean): Command |
102 | |||
103 | mutex: function(self: Command, ...: any) --! copied over from Parser | ||
104 | |||
105 | group: function(self: Command, ...:any): Command --! copied over from Parser | ||
100 | end | 106 | end |
101 | 107 | ||
102 | metamethod __call: function(self: argparse, name: string, description: string, epilog: string): Parser | 108 | metamethod __call: function(self: argparse, name: string, description: string, epilog: string): Parser |
diff --git a/src/luarocks/vendor/dkjson.d.tl b/src/luarocks/vendor/dkjson.d.tl index 4dee43d3..a7c76389 100644 --- a/src/luarocks/vendor/dkjson.d.tl +++ b/src/luarocks/vendor/dkjson.d.tl | |||
@@ -13,7 +13,7 @@ local record dkjson | |||
13 | tables: {table:boolean} | 13 | tables: {table:boolean} |
14 | exception: function(string, string, string, string): boolean|string, string | 14 | exception: function(string, string, string, string): boolean|string, string |
15 | end | 15 | end |
16 | encode: function({string:any}, JsonState): string | 16 | encode: function({string:any}, ?JsonState): string |
17 | 17 | ||
18 | decode: function(string, ?number, ?any, ?table): {string:any} | 18 | decode: function(string, ?number, ?any, ?table): {string:any} |
19 | 19 | ||