aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPeter Melnichenko <mpeterval@gmail.com>2016-06-13 12:10:59 +0300
committerPeter Melnichenko <mpeterval@gmail.com>2016-06-13 12:29:06 +0300
commit9fa380490931813a153b1cb079c2b3c21092bacf (patch)
treecb0cafa825a7815810d13945d20808cc43869c03 /src
parent0bed8bc1cf789ec3539469ed7d6ec437446b1b95 (diff)
parentf75295ee52bc2c335d12e82282d0f92a419a82d1 (diff)
downloadluarocks-9fa380490931813a153b1cb079c2b3c21092bacf.tar.gz
luarocks-9fa380490931813a153b1cb079c2b3c21092bacf.tar.bz2
luarocks-9fa380490931813a153b1cb079c2b3c21092bacf.zip
Merge branch 'master' into luarocks-3
Diffstat (limited to 'src')
-rw-r--r--src/luarocks/add.lua9
-rw-r--r--src/luarocks/admin_remove.lua7
-rw-r--r--src/luarocks/build.lua51
-rw-r--r--src/luarocks/build/builtin.lua22
-rw-r--r--src/luarocks/build/cmake.lua1
-rw-r--r--src/luarocks/build/command.lua1
-rw-r--r--src/luarocks/build/make.lua1
-rw-r--r--src/luarocks/cache.lua1
-rw-r--r--src/luarocks/cfg.lua2
-rw-r--r--src/luarocks/command_line.lua38
-rw-r--r--src/luarocks/config_cmd.lua5
-rw-r--r--src/luarocks/deps.lua129
-rw-r--r--src/luarocks/dir.lua1
-rw-r--r--src/luarocks/doc.lua5
-rw-r--r--src/luarocks/download.lua11
-rw-r--r--src/luarocks/fetch.lua1
-rw-r--r--src/luarocks/fetch/cvs.lua1
-rw-r--r--src/luarocks/fetch/git.lua1
-rw-r--r--src/luarocks/fetch/git_file.lua1
-rw-r--r--src/luarocks/fetch/git_http.lua1
-rw-r--r--src/luarocks/fetch/hg.lua1
-rw-r--r--src/luarocks/fetch/sscm.lua1
-rw-r--r--src/luarocks/fetch/svn.lua1
-rw-r--r--src/luarocks/fs.lua6
-rw-r--r--src/luarocks/fs/lua.lua23
-rw-r--r--src/luarocks/fs/tools.lua156
-rw-r--r--src/luarocks/fs/unix.lua12
-rw-r--r--src/luarocks/fs/unix/tools.lua152
-rw-r--r--src/luarocks/fs/win32.lua8
-rw-r--r--src/luarocks/fs/win32/tools.lua171
-rw-r--r--src/luarocks/help.lua6
-rw-r--r--src/luarocks/index.lua1
-rw-r--r--src/luarocks/install.lua26
-rw-r--r--src/luarocks/lint.lua6
-rw-r--r--src/luarocks/list.lua27
-rw-r--r--src/luarocks/make.lua68
-rw-r--r--src/luarocks/make_manifest.lua6
-rw-r--r--src/luarocks/manif.lua3
-rw-r--r--src/luarocks/manif_core.lua1
-rw-r--r--src/luarocks/new_version.lua17
-rw-r--r--src/luarocks/pack.lua17
-rw-r--r--src/luarocks/path.lua1
-rw-r--r--src/luarocks/path_cmd.lua4
-rw-r--r--src/luarocks/persist.lua3
-rw-r--r--src/luarocks/purge.lua8
-rw-r--r--src/luarocks/refresh_cache.lua5
-rw-r--r--src/luarocks/remove.lua26
-rw-r--r--src/luarocks/repos.lua18
-rw-r--r--src/luarocks/search.lua6
-rw-r--r--src/luarocks/show.lua6
-rw-r--r--src/luarocks/tools/patch.lua1
-rw-r--r--src/luarocks/tools/tar.lua1
-rw-r--r--src/luarocks/type_check.lua1
-rw-r--r--src/luarocks/unpack.lua9
-rw-r--r--src/luarocks/upload.lua4
-rw-r--r--src/luarocks/util.lua116
-rw-r--r--src/luarocks/validate.lua5
-rw-r--r--src/luarocks/write_rockspec.lua106
58 files changed, 577 insertions, 741 deletions
diff --git a/src/luarocks/add.lua b/src/luarocks/add.lua
index 81adff9b..f37d334d 100644
--- a/src/luarocks/add.lua
+++ b/src/luarocks/add.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the luarocks-admin "add" command. 2--- Module implementing the luarocks-admin "add" command.
3-- Adds a rock or rockspec to a rocks server. 3-- Adds a rock or rockspec to a rocks server.
4--module("luarocks.add", package.seeall)
5local add = {} 4local add = {}
6package.loaded["luarocks.add"] = add 5package.loaded["luarocks.add"] = add
7 6
@@ -13,6 +12,7 @@ local index = require("luarocks.index")
13local fs = require("luarocks.fs") 12local fs = require("luarocks.fs")
14local cache = require("luarocks.cache") 13local cache = require("luarocks.cache")
15 14
15util.add_run_function(add)
16add.help_summary = "Add a rock or rockspec to a rocks server." 16add.help_summary = "Add a rock or rockspec to a rocks server."
17add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" 17add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
18add.help = [[ 18add.help = [[
@@ -54,7 +54,7 @@ local function add_files_to_server(refresh, rockfiles, server, upload_server)
54 if fs.exists(rockfile) then 54 if fs.exists(rockfile) then
55 util.printout("Copying file "..rockfile.." to "..local_cache.."...") 55 util.printout("Copying file "..rockfile.." to "..local_cache.."...")
56 local absolute = fs.absolute_name(rockfile) 56 local absolute = fs.absolute_name(rockfile)
57 fs.copy(absolute, local_cache) 57 fs.copy(absolute, local_cache, cfg.perm_read)
58 table.insert(files, dir.base_name(absolute)) 58 table.insert(files, dir.base_name(absolute))
59 else 59 else
60 util.printerr("File "..rockfile.." not found") 60 util.printerr("File "..rockfile.." not found")
@@ -108,9 +108,8 @@ local function add_files_to_server(refresh, rockfiles, server, upload_server)
108 return true 108 return true
109end 109end
110 110
111function add.run(...) 111function add.command(flags, ...)
112 local files = { util.parse_flags(...) } 112 local files = {...}
113 local flags = table.remove(files, 1)
114 if #files < 1 then 113 if #files < 1 then
115 return nil, "Argument missing. "..util.see_help("add", "luarocks-admin") 114 return nil, "Argument missing. "..util.see_help("add", "luarocks-admin")
116 end 115 end
diff --git a/src/luarocks/admin_remove.lua b/src/luarocks/admin_remove.lua
index 5a1cf20b..621f1317 100644
--- a/src/luarocks/admin_remove.lua
+++ b/src/luarocks/admin_remove.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the luarocks-admin "remove" command. 2--- Module implementing the luarocks-admin "remove" command.
3-- Removes a rock or rockspec from a rocks server. 3-- Removes a rock or rockspec from a rocks server.
4--module("luarocks.admin_remove", package.seeall)
5local admin_remove = {} 4local admin_remove = {}
6package.loaded["luarocks.admin_remove"] = admin_remove 5package.loaded["luarocks.admin_remove"] = admin_remove
7 6
@@ -13,6 +12,7 @@ local index = require("luarocks.index")
13local fs = require("luarocks.fs") 12local fs = require("luarocks.fs")
14local cache = require("luarocks.cache") 13local cache = require("luarocks.cache")
15 14
15util.add_run_function(admin_remove)
16admin_remove.help_summary = "Remove a rock or rockspec from a rocks server." 16admin_remove.help_summary = "Remove a rock or rockspec from a rocks server."
17admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" 17admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
18admin_remove.help = [[ 18admin_remove.help = [[
@@ -78,9 +78,8 @@ local function remove_files_from_server(refresh, rockfiles, server, upload_serve
78 return true 78 return true
79end 79end
80 80
81function admin_remove.run(...) 81function admin_remove.command(flags, ...)
82 local files = { util.parse_flags(...) } 82 local files = {...}
83 local flags = table.remove(files, 1)
84 if #files < 1 then 83 if #files < 1 then
85 return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin") 84 return nil, "Argument missing. "..util.see_help("remove", "luarocks-admin")
86 end 85 end
diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua
index dd0b4441..14130657 100644
--- a/src/luarocks/build.lua
+++ b/src/luarocks/build.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "build" command. 2--- Module implementing the LuaRocks "build" command.
3-- Builds a rock, compiling its C parts if any. 3-- Builds a rock, compiling its C parts if any.
4--module("luarocks.build", package.seeall)
5local build = {} 4local build = {}
6package.loaded["luarocks.build"] = build 5package.loaded["luarocks.build"] = build
7 6
@@ -17,6 +16,7 @@ local manif = require("luarocks.manif")
17local remove = require("luarocks.remove") 16local remove = require("luarocks.remove")
18local cfg = require("luarocks.cfg") 17local cfg = require("luarocks.cfg")
19 18
19util.add_run_function(build)
20build.help_summary = "Build/compile a rock." 20build.help_summary = "Build/compile a rock."
21build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" 21build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}"
22build.help = [[ 22build.help = [[
@@ -53,9 +53,11 @@ or the name of a rock to be fetched from a repository.
53-- @param location string: The base directory files should be copied to. 53-- @param location string: The base directory files should be copied to.
54-- @param is_module_path boolean: True if string keys in files should be 54-- @param is_module_path boolean: True if string keys in files should be
55-- interpreted as dotted module paths. 55-- interpreted as dotted module paths.
56-- @param perms string: Permissions of the newly created files installed.
57-- Directories are always created with the default permissions.
56-- @return boolean or (nil, string): True if succeeded or 58-- @return boolean or (nil, string): True if succeeded or
57-- nil and an error message. 59-- nil and an error message.
58local function install_files(files, location, is_module_path) 60local function install_files(files, location, is_module_path, perms)
59 assert(type(files) == "table" or not files) 61 assert(type(files) == "table" or not files)
60 assert(type(location) == "string") 62 assert(type(location) == "string")
61 if files then 63 if files then
@@ -85,7 +87,7 @@ local function install_files(files, location, is_module_path)
85 local ok, err = fs.make_dir(dest) 87 local ok, err = fs.make_dir(dest)
86 if not ok then return nil, err end 88 if not ok then return nil, err end
87 end 89 end
88 local ok = fs.copy(dir.path(file), dir.path(dest, filename)) 90 local ok = fs.copy(dir.path(file), dir.path(dest, filename), perms)
89 if not ok then 91 if not ok then
90 return nil, "Failed copying "..file 92 return nil, "Failed copying "..file
91 end 93 end
@@ -142,7 +144,7 @@ local function install_default_docs(name, version)
142 fs.make_dir(dest) 144 fs.make_dir(dest)
143 has_dir = true 145 has_dir = true
144 end 146 end
145 fs.copy(file, dest) 147 fs.copy(file, dest, cfg.perm_read)
146 break 148 break
147 end 149 end
148 end 150 end
@@ -200,6 +202,14 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
200 return nil, "Rockspec error: build type not specified" 202 return nil, "Rockspec error: build type not specified"
201 end 203 end
202 204
205 if not build_only_deps then
206 local ok
207 ok, err, errcode = deps.check_external_deps(rockspec, "build")
208 if err then
209 return nil, err, errcode
210 end
211 end
212
203 if deps_mode == "none" then 213 if deps_mode == "none" then
204 util.printerr("Warning: skipping dependency checks.") 214 util.printerr("Warning: skipping dependency checks.")
205 else 215 else
@@ -216,12 +226,6 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
216 return name, version 226 return name, version
217 end 227 end
218 228
219 local ok
220 ok, err, errcode = deps.check_external_deps(rockspec, "build")
221 if err then
222 return nil, err, errcode
223 end
224
225 if repos.is_installed(name, version) then 229 if repos.is_installed(name, version) then
226 repos.delete_version(name, version) 230 repos.delete_version(name, version)
227 end 231 end
@@ -245,10 +249,10 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
245 end 249 end
246 250
247 local dirs = { 251 local dirs = {
248 lua = { name = path.lua_dir(name, version), is_module_path = true }, 252 lua = { name = path.lua_dir(name, version), is_module_path = true, perms = cfg.perm_read },
249 lib = { name = path.lib_dir(name, version), is_module_path = true }, 253 lib = { name = path.lib_dir(name, version), is_module_path = true, perms = cfg.perm_exec },
250 conf = { name = path.conf_dir(name, version), is_module_path = false }, 254 conf = { name = path.conf_dir(name, version), is_module_path = false, perms = cfg.perm_read },
251 bin = { name = path.bin_dir(name, version), is_module_path = false }, 255 bin = { name = path.bin_dir(name, version), is_module_path = false, perms = cfg.perm_exec },
252 } 256 }
253 257
254 for _, d in pairs(dirs) do 258 for _, d in pairs(dirs) do
@@ -300,7 +304,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
300 304
301 if build_spec.install then 305 if build_spec.install then
302 for id, install_dir in pairs(dirs) do 306 for id, install_dir in pairs(dirs) do
303 ok, err = install_files(build_spec.install[id], install_dir.name, install_dir.is_module_path) 307 ok, err = install_files(build_spec.install[id], install_dir.name, install_dir.is_module_path, install_dir.perms)
304 if not ok then 308 if not ok then
305 return nil, err 309 return nil, err
306 end 310 end
@@ -338,7 +342,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
338 342
339 fs.pop_dir() 343 fs.pop_dir()
340 344
341 fs.copy(rockspec.local_filename, path.rockspec_file(name, version)) 345 fs.copy(rockspec.local_filename, path.rockspec_file(name, version), cfg.perm_read)
342 if need_to_fetch then 346 if need_to_fetch then
343 fs.pop_dir() 347 fs.pop_dir()
344 end 348 end
@@ -360,15 +364,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
360 ok, err = manif.update_manifest(name, version, nil, deps_mode) 364 ok, err = manif.update_manifest(name, version, nil, deps_mode)
361 if err then return nil, err end 365 if err then return nil, err end
362 366
363 local license = "" 367 util.announce_install(rockspec)
364 if rockspec.description and rockspec.description.license then
365 license = ("(license: "..rockspec.description.license..")")
366 end
367
368 local root_dir = path.root_dir(cfg.rocks_dir)
369 util.printout(name.." "..version.." is now built and installed in "..root_dir.." "..license)
370 util.printout()
371
372 util.remove_scheduled_function(rollback) 368 util.remove_scheduled_function(rollback)
373 return name, version 369 return name, version
374end 370end
@@ -427,8 +423,7 @@ end
427-- also be given. 423-- also be given.
428-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an 424-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an
429-- error message otherwise. exitcode is optionally returned. 425-- error message otherwise. exitcode is optionally returned.
430function build.run(...) 426function build.command(flags, name, version)
431 local flags, name, version = util.parse_flags(...)
432 if type(name) ~= "string" then 427 if type(name) ~= "string" then
433 return nil, "Argument missing. "..util.see_help("build") 428 return nil, "Argument missing. "..util.see_help("build")
434 end 429 end
@@ -446,7 +441,7 @@ function build.run(...)
446 return name, version 441 return name, version
447 end 442 end
448 if (not flags["keep"]) and not cfg.keep_other_versions then 443 if (not flags["keep"]) and not cfg.keep_other_versions then
449 local ok, err = remove.remove_other_versions(name, version, flags["force"]) 444 local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"])
450 if not ok then util.printerr(err) end 445 if not ok then util.printerr(err) end
451 end 446 end
452 return name, version 447 return name, version
diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua
index 938262ef..81fa8b13 100644
--- a/src/luarocks/build/builtin.lua
+++ b/src/luarocks/build/builtin.lua
@@ -1,6 +1,5 @@
1 1
2--- A builtin build system: back-end to provide a portable way of building C-based Lua modules. 2--- A builtin build system: back-end to provide a portable way of building C-based Lua modules.
3--module("luarocks.build.builtin", package.seeall)
4local builtin = {} 3local builtin = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
@@ -193,7 +192,8 @@ function builtin.run(rockspec)
193 end 192 end
194 193
195 local ok, err 194 local ok, err
196 local built_modules = {} 195 local lua_modules = {}
196 local lib_modules = {}
197 local luadir = path.lua_dir(rockspec.name, rockspec.version) 197 local luadir = path.lua_dir(rockspec.name, rockspec.version)
198 local libdir = path.lib_dir(rockspec.name, rockspec.version) 198 local libdir = path.lib_dir(rockspec.name, rockspec.version)
199 --TODO EXEWRAPPER 199 --TODO EXEWRAPPER
@@ -233,7 +233,7 @@ function builtin.run(rockspec)
233 end 233 end
234 end 234 end
235 local dest = dir.path(luadir, moddir, filename) 235 local dest = dir.path(luadir, moddir, filename)
236 built_modules[info] = dest 236 lua_modules[info] = dest
237 else 237 else
238 info = {info} 238 info = {info}
239 end 239 end
@@ -260,7 +260,7 @@ function builtin.run(rockspec)
260 ok, err = fs.make_dir(moddir) 260 ok, err = fs.make_dir(moddir)
261 if not ok then return nil, err end 261 if not ok then return nil, err end
262 end 262 end
263 built_modules[module_name] = dir.path(libdir, module_name) 263 lib_modules[module_name] = dir.path(libdir, module_name)
264 ok = compile_library(module_name, objects, info.libraries, info.libdirs, name) 264 ok = compile_library(module_name, objects, info.libraries, info.libdirs, name)
265 if not ok then 265 if not ok then
266 return nil, "Failed compiling module "..module_name 266 return nil, "Failed compiling module "..module_name
@@ -269,18 +269,20 @@ function builtin.run(rockspec)
269 if moddir ~= "" then 269 if moddir ~= "" then
270 module_name = dir.path(moddir, module_name) 270 module_name = dir.path(moddir, module_name)
271 end 271 end
272 built_modules[module_name] = dir.path(libdir, module_name) 272 lib_modules[module_name] = dir.path(libdir, module_name)
273 ok = compile_static_library(module_name, objects, info.libraries, info.libdirs, name) 273 ok = compile_static_library(module_name, objects, info.libraries, info.libdirs, name)
274 if not ok then 274 if not ok then
275 return nil, "Failed compiling static library "..module_name 275 return nil, "Failed compiling static library "..module_name
276 end 276 end
277 end 277 end
278 end 278 end
279 for name, dest in pairs(built_modules) do 279 for _, mods in ipairs({{ tbl = lua_modules, perms = cfg.perm_read }, { tbl = lib_modules, perms = cfg.perm_exec }}) do
280 fs.make_dir(dir.dir_name(dest)) 280 for name, dest in pairs(mods.tbl) do
281 ok, err = fs.copy(name, dest) 281 fs.make_dir(dir.dir_name(dest))
282 if not ok then 282 ok, err = fs.copy(name, dest, mods.perms)
283 return nil, "Failed installing "..name.." in "..dest..": "..err 283 if not ok then
284 return nil, "Failed installing "..name.." in "..dest..": "..err
285 end
284 end 286 end
285 end 287 end
286 if fs.is_dir("lua") then 288 if fs.is_dir("lua") then
diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua
index 34f6ada0..c2712bb2 100644
--- a/src/luarocks/build/cmake.lua
+++ b/src/luarocks/build/cmake.lua
@@ -1,6 +1,5 @@
1 1
2--- Build back-end for CMake-based modules. 2--- Build back-end for CMake-based modules.
3--module("luarocks.build.cmake", package.seeall)
4local cmake = {} 3local cmake = {}
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
diff --git a/src/luarocks/build/command.lua b/src/luarocks/build/command.lua
index 650e3236..62dbc282 100644
--- a/src/luarocks/build/command.lua
+++ b/src/luarocks/build/command.lua
@@ -1,6 +1,5 @@
1 1
2--- Build back-end for raw listing of commands in rockspec files. 2--- Build back-end for raw listing of commands in rockspec files.
3--module("luarocks.build.command", package.seeall)
4local command = {} 3local command = {}
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
diff --git a/src/luarocks/build/make.lua b/src/luarocks/build/make.lua
index 0da183e9..69e73c2e 100644
--- a/src/luarocks/build/make.lua
+++ b/src/luarocks/build/make.lua
@@ -1,6 +1,5 @@
1 1
2--- Build back-end for using Makefile-based packages. 2--- Build back-end for using Makefile-based packages.
3--module("luarocks.build.make", package.seeall)
4local make = {} 3local make = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
diff --git a/src/luarocks/cache.lua b/src/luarocks/cache.lua
index fb6344d8..4a95f70e 100644
--- a/src/luarocks/cache.lua
+++ b/src/luarocks/cache.lua
@@ -1,7 +1,6 @@
1 1
2--- Module handling the LuaRocks local cache. 2--- Module handling the LuaRocks local cache.
3-- Adds a rock or rockspec to a rocks server. 3-- Adds a rock or rockspec to a rocks server.
4--module("luarocks.cache", package.seeall)
5local cache = {} 4local cache = {}
6package.loaded["luarocks.cache"] = cache 5package.loaded["luarocks.cache"] = cache
7 6
diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua
index aa298b07..53387276 100644
--- a/src/luarocks/cfg.lua
+++ b/src/luarocks/cfg.lua
@@ -306,6 +306,8 @@ local defaults = {
306 hooks_enabled = true, 306 hooks_enabled = true,
307 deps_mode = "one", 307 deps_mode = "one",
308 check_certificates = false, 308 check_certificates = false,
309 perm_read = "0644",
310 perm_exec = "0755",
309 311
310 lua_modules_path = "/share/lua/"..cfg.lua_version, 312 lua_modules_path = "/share/lua/"..cfg.lua_version,
311 lib_modules_path = "/lib/lua/"..cfg.lua_version, 313 lib_modules_path = "/lib/lua/"..cfg.lua_version,
diff --git a/src/luarocks/command_line.lua b/src/luarocks/command_line.lua
index a016fc72..1a8c0fe7 100644
--- a/src/luarocks/command_line.lua
+++ b/src/luarocks/command_line.lua
@@ -1,6 +1,5 @@
1 1
2--- Functions for command-line scripts. 2--- Functions for command-line scripts.
3--module("luarocks.command_line", package.seeall)
4local command_line = {} 3local command_line = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
@@ -28,20 +27,9 @@ local function die(message, exitcode)
28 os.exit(exitcode or cfg.errorcodes.UNSPECIFIED) 27 os.exit(exitcode or cfg.errorcodes.UNSPECIFIED)
29end 28end
30 29
31local function replace_tree(flags, args, tree) 30local function replace_tree(flags, tree)
32 tree = dir.normalize(tree) 31 tree = dir.normalize(tree)
33 flags["tree"] = tree 32 flags["tree"] = tree
34 local added = false
35 for i = 1, #args do
36 if args[i]:match("%-%-tree=") then
37 args[i] = "--tree="..tree
38 added = true
39 break
40 end
41 end
42 if not added then
43 args[#args + 1] = "--tree="..tree
44 end
45 path.use_tree(tree) 33 path.use_tree(tree)
46end 34end
47 35
@@ -79,7 +67,6 @@ function command_line.run_command(...)
79 if flags["to"] then flags["tree"] = flags["to"] end 67 if flags["to"] then flags["tree"] = flags["to"] end
80 if flags["nodeps"] then 68 if flags["nodeps"] then
81 flags["deps-mode"] = "none" 69 flags["deps-mode"] = "none"
82 table.insert(args, "--deps-mode=none")
83 end 70 end
84 71
85 cfg.flags = flags 72 cfg.flags = flags
@@ -107,15 +94,8 @@ function command_line.run_command(...)
107 os.exit(cfg.errorcodes.OK) 94 os.exit(cfg.errorcodes.OK)
108 elseif flags["help"] or #nonflags == 0 then 95 elseif flags["help"] or #nonflags == 0 then
109 command = "help" 96 command = "help"
110 args = nonflags
111 else 97 else
112 command = nonflags[1] 98 command = table.remove(nonflags, 1)
113 for i, arg in ipairs(args) do
114 if arg == command then
115 table.remove(args, i)
116 break
117 end
118 end
119 end 99 end
120 command = command:gsub("-", "_") 100 command = command:gsub("-", "_")
121 101
@@ -138,14 +118,14 @@ function command_line.run_command(...)
138 if not tree.root then 118 if not tree.root then
139 die("Configuration error: tree '"..tree.name.."' has no 'root' field.") 119 die("Configuration error: tree '"..tree.name.."' has no 'root' field.")
140 end 120 end
141 replace_tree(flags, args, tree.root) 121 replace_tree(flags, tree.root)
142 named = true 122 named = true
143 break 123 break
144 end 124 end
145 end 125 end
146 if not named then 126 if not named then
147 local root_dir = fs.absolute_name(flags["tree"]) 127 local root_dir = fs.absolute_name(flags["tree"])
148 replace_tree(flags, args, root_dir) 128 replace_tree(flags, root_dir)
149 end 129 end
150 elseif flags["local"] then 130 elseif flags["local"] then
151 if not cfg.home_tree then 131 if not cfg.home_tree then
@@ -153,7 +133,7 @@ function command_line.run_command(...)
153 "You are running as a superuser, which is intended for system-wide operation.\n".. 133 "You are running as a superuser, which is intended for system-wide operation.\n"..
154 "To force using the superuser's home, use --tree explicitly.") 134 "To force using the superuser's home, use --tree explicitly.")
155 end 135 end
156 replace_tree(flags, args, cfg.home_tree) 136 replace_tree(flags, cfg.home_tree)
157 else 137 else
158 local trees = cfg.rocks_trees 138 local trees = cfg.rocks_trees
159 path.use_tree(trees[#trees]) 139 path.use_tree(trees[#trees])
@@ -196,14 +176,8 @@ function command_line.run_command(...)
196 end 176 end
197 177
198 if commands[command] then 178 if commands[command] then
199 -- TODO the interface of run should be modified, to receive the
200 -- flags table and the (possibly unpacked) nonflags arguments.
201 -- This would remove redundant parsing of arguments.
202 -- I'm not changing this now to avoid messing with the run()
203 -- interface, which I know some people use (even though
204 -- I never published it as a public API...)
205 local cmd = require(commands[command]) 179 local cmd = require(commands[command])
206 local xp, ok, err, exitcode = xpcall(function() return cmd.run(unpack(args)) end, function(err) 180 local xp, ok, err, exitcode = xpcall(function() return cmd.command(flags, unpack(nonflags)) end, function(err)
207 die(debug.traceback("LuaRocks "..cfg.program_version 181 die(debug.traceback("LuaRocks "..cfg.program_version
208 .." bug (please report at https://github.com/keplerproject/luarocks/issues).\n" 182 .." bug (please report at https://github.com/keplerproject/luarocks/issues).\n"
209 ..err, 2), cfg.errorcodes.CRASH) 183 ..err, 2), cfg.errorcodes.CRASH)
diff --git a/src/luarocks/config_cmd.lua b/src/luarocks/config_cmd.lua
index bf282a7a..fe3cc637 100644
--- a/src/luarocks/config_cmd.lua
+++ b/src/luarocks/config_cmd.lua
@@ -6,6 +6,7 @@ local cfg = require("luarocks.cfg")
6local util = require("luarocks.util") 6local util = require("luarocks.util")
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8 8
9util.add_run_function(config_cmd)
9config_cmd.help_summary = "Query information about the LuaRocks configuration." 10config_cmd.help_summary = "Query information about the LuaRocks configuration."
10config_cmd.help_arguments = "<flag>" 11config_cmd.help_arguments = "<flag>"
11config_cmd.help = [[ 12config_cmd.help = [[
@@ -33,9 +34,7 @@ end
33 34
34--- Driver function for "config" command. 35--- Driver function for "config" command.
35-- @return boolean: True if succeeded, nil on errors. 36-- @return boolean: True if succeeded, nil on errors.
36function config_cmd.run(...) 37function config_cmd.command(flags)
37 local flags = util.parse_flags(...)
38
39 if flags["lua-incdir"] then 38 if flags["lua-incdir"] then
40 print(cfg.variables.LUA_INCDIR) 39 print(cfg.variables.LUA_INCDIR)
41 return true 40 return true
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index 2a458b23..b8a36850 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -11,7 +11,6 @@
11-- comparison criteria is the source code of this module, but the 11-- comparison criteria is the source code of this module, but the
12-- test/test_deps.lua file included with LuaRocks provides some 12-- test/test_deps.lua file included with LuaRocks provides some
13-- insights on what these criteria are. 13-- insights on what these criteria are.
14--module("luarocks.deps", package.seeall)
15local deps = {} 14local deps = {}
16package.loaded["luarocks.deps"] = deps 15package.loaded["luarocks.deps"] = deps
17 16
@@ -333,8 +332,7 @@ end
333-- are program versions and values are 'true'. 332-- are program versions and values are 'true'.
334-- @param provided table: A table of auto-dependencies provided 333-- @param provided table: A table of auto-dependencies provided
335-- by this Lua implementation for the given dependency. 334-- by this Lua implementation for the given dependency.
336-- @return table or nil: A table containing fields 'name' and 'version' 335-- @return string or nil: latest installed version of the rock matching the dependency
337-- representing an installed rock which matches the given dependency,
338-- or nil if it could not be matched. 336-- or nil if it could not be matched.
339local function match_dep(dep, blacklist, deps_mode, rocks_provided) 337local function match_dep(dep, blacklist, deps_mode, rocks_provided)
340 assert(type(dep) == "table") 338 assert(type(dep) == "table")
@@ -343,40 +341,25 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided)
343 local versions 341 local versions
344 local provided = rocks_provided[dep.name] 342 local provided = rocks_provided[dep.name]
345 if provided then 343 if provided then
346 -- provided rocks have higher priority than manifest's rocks 344 -- Provided rocks have higher priority than manifest's rocks.
347 versions = { provided } 345 versions = { provided }
348 else 346 else
349 versions = manif_core.get_versions(dep.name, deps_mode) 347 versions = manif_core.get_versions(dep.name, deps_mode)
350 end 348 end
351 if not versions then 349
352 return nil 350 local latest_version
353 end
354 if blacklist then
355 local i = 1
356 while versions[i] do
357 if blacklist[versions[i]] then
358 table.remove(versions, i)
359 else
360 i = i + 1
361 end
362 end
363 end
364 local candidates = {}
365 for _, vstring in ipairs(versions) do 351 for _, vstring in ipairs(versions) do
366 local version = deps.parse_version(vstring) 352 if not blacklist or not blacklist[vstring] then
367 if deps.match_constraints(version, dep.constraints) then 353 local version = deps.parse_version(vstring)
368 table.insert(candidates, version) 354 if deps.match_constraints(version, dep.constraints) then
355 if not latest_version or version > latest_version then
356 latest_version = version
357 end
358 end
369 end 359 end
370 end 360 end
371 if #candidates == 0 then 361
372 return nil 362 return latest_version and latest_version.string
373 else
374 table.sort(candidates)
375 return {
376 name = dep.name,
377 version = candidates[#candidates].string
378 }
379 end
380end 363end
381 364
382--- Attempt to match dependencies of a rockspec to installed rocks. 365--- Attempt to match dependencies of a rockspec to installed rocks.
@@ -399,7 +382,7 @@ function deps.match_deps(rockspec, blacklist, deps_mode)
399 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rockspec.rocks_provided) 382 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rockspec.rocks_provided)
400 if found then 383 if found then
401 if not rockspec.rocks_provided[dep.name] then 384 if not rockspec.rocks_provided[dep.name] then
402 matched[dep] = found 385 matched[dep] = {name = dep.name, version = found}
403 end 386 end
404 else 387 else
405 if dep.constraints[1] and dep.constraints[1].no_upgrade then 388 if dep.constraints[1] and dep.constraints[1].no_upgrade then
@@ -423,6 +406,13 @@ local function values_set(tbl)
423 return set 406 return set
424end 407end
425 408
409local function rock_status(name, deps_mode, rocks_provided)
410 local search = require("luarocks.search")
411 local installed = match_dep(search.make_query(name), nil, deps_mode, rocks_provided)
412 local installation_type = rocks_provided[name] and "provided by VM" or "installed"
413 return installed and installed.." "..installation_type or "not installed"
414end
415
426--- Check dependencies of a rock and attempt to install any missing ones. 416--- Check dependencies of a rock and attempt to install any missing ones.
427-- Packages are installed using the LuaRocks "install" command. 417-- Packages are installed using the LuaRocks "install" command.
428-- Aborts the program if a dependency could not be fulfilled. 418-- Aborts the program if a dependency could not be fulfilled.
@@ -462,52 +452,53 @@ function deps.fulfill_dependencies(rockspec, deps_mode)
462 end 452 end
463 end 453 end
464 454
465 local _, missing, no_upgrade = deps.match_deps(rockspec, nil, deps_mode) 455 local first_missing_dep = true
466 456
467 if next(no_upgrade) then 457 for _, dep in ipairs(rockspec.dependencies) do
468 util.printerr("Missing dependencies for "..rockspec.name.." "..rockspec.version..":") 458 if not match_dep(dep, nil, deps_mode, rockspec.rocks_provided) then
469 for _, dep in pairs(no_upgrade) do 459 if first_missing_dep then
470 util.printerr(deps.show_dep(dep)) 460 util.printout(("Missing dependencies for %s %s:"):format(rockspec.name, rockspec.version))
471 end 461 first_missing_dep = false
472 if next(missing) then
473 for _, dep in pairs(missing) do
474 util.printerr(deps.show_dep(dep))
475 end 462 end
463
464 util.printout((" %s (%s)"):format(deps.show_dep(dep), rock_status(dep.name, deps_mode, rockspec.rocks_provided)))
476 end 465 end
477 util.printerr()
478 for _, dep in pairs(no_upgrade) do
479 util.printerr("This version of "..rockspec.name.." is designed for use with")
480 util.printerr(deps.show_dep(dep)..", but is configured to avoid upgrading it")
481 util.printerr("automatically. Please upgrade "..dep.name.." with")
482 util.printerr(" luarocks install "..dep.name)
483 util.printerr("or choose an older version of "..rockspec.name.." with")
484 util.printerr(" luarocks search "..rockspec.name)
485 end
486 return nil, "Failed matching dependencies."
487 end 466 end
488 467
489 if next(missing) then 468 first_missing_dep = true
490 util.printerr() 469
491 util.printerr("Missing dependencies for "..rockspec.name..":") 470 for _, dep in ipairs(rockspec.dependencies) do
492 for _, dep in pairs(missing) do 471 if not match_dep(dep, nil, deps_mode, rockspec.rocks_provided) then
493 util.printerr(deps.show_dep(dep)) 472 if first_missing_dep then
494 end 473 util.printout()
495 util.printerr() 474 first_missing_dep = false
496 475 end
497 for _, dep in pairs(missing) do 476
498 -- Double-check in case dependency was filled during recursion. 477 util.printout(("%s %s depends on %s (%s)"):format(
499 if not match_dep(dep, nil, deps_mode, rockspec.rocks_provided) then 478 rockspec.name, rockspec.version, deps.show_dep(dep), rock_status(dep.name, deps_mode, rockspec.rocks_provided)))
500 local url, err = search.find_suitable_rock(dep) 479
501 if not url then 480 if dep.constraints[1] and dep.constraints[1].no_upgrade then
502 return nil, "Could not satisfy dependency "..deps.show_dep(dep)..": "..err 481 util.printerr("This version of "..rockspec.name.." is designed for use with")
503 end 482 util.printerr(deps.show_dep(dep)..", but is configured to avoid upgrading it")
504 local ok, err, errcode = install.run(url, deps.deps_mode_to_flag(deps_mode)) 483 util.printerr("automatically. Please upgrade "..dep.name.." with")
505 if not ok then 484 util.printerr(" luarocks install "..dep.name)
506 return nil, "Failed installing dependency: "..url.." - "..err, errcode 485 util.printerr("or choose an older version of "..rockspec.name.." with")
507 end 486 util.printerr(" luarocks search "..rockspec.name)
487 return nil, "Failed matching dependencies"
488 end
489
490 local url, search_err = search.find_suitable_rock(dep)
491 if not url then
492 return nil, "Could not satisfy dependency "..deps.show_dep(dep)..": "..search_err
493 end
494 util.printout("Installing "..url)
495 local ok, install_err, errcode = install.run(url, deps.deps_mode_to_flag(deps_mode))
496 if not ok then
497 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode
508 end 498 end
509 end 499 end
510 end 500 end
501
511 return true 502 return true
512end 503end
513 504
diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua
index 2ef9881e..f72ebd6c 100644
--- a/src/luarocks/dir.lua
+++ b/src/luarocks/dir.lua
@@ -1,6 +1,5 @@
1 1
2--- Generic utilities for handling pathnames. 2--- Generic utilities for handling pathnames.
3--module("luarocks.dir", package.seeall)
4local dir = {} 3local dir = {}
5package.loaded["luarocks.dir"] = dir 4package.loaded["luarocks.dir"] = dir
6 5
diff --git a/src/luarocks/doc.lua b/src/luarocks/doc.lua
index 53ed0116..ec2b1110 100644
--- a/src/luarocks/doc.lua
+++ b/src/luarocks/doc.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "doc" command. 2--- Module implementing the LuaRocks "doc" command.
3-- Shows documentation for an installed rock. 3-- Shows documentation for an installed rock.
4--module("luarocks.doc", package.seeall)
5local doc = {} 4local doc = {}
6package.loaded["luarocks.doc"] = doc 5package.loaded["luarocks.doc"] = doc
7 6
@@ -13,6 +12,7 @@ local fetch = require("luarocks.fetch")
13local fs = require("luarocks.fs") 12local fs = require("luarocks.fs")
14local download = require("luarocks.download") 13local download = require("luarocks.download")
15 14
15util.add_run_function(doc)
16doc.help_summary = "Show documentation for an installed rock." 16doc.help_summary = "Show documentation for an installed rock."
17 17
18doc.help = [[ 18doc.help = [[
@@ -58,8 +58,7 @@ end
58-- @param name or nil: an existing package name. 58-- @param name or nil: an existing package name.
59-- @param version string or nil: a version may also be passed. 59-- @param version string or nil: a version may also be passed.
60-- @return boolean: True if succeeded, nil on errors. 60-- @return boolean: True if succeeded, nil on errors.
61function doc.run(...) 61function doc.command(flags, name, version)
62 local flags, name, version = util.parse_flags(...)
63 if not name then 62 if not name then
64 return nil, "Argument missing. "..util.see_help("doc") 63 return nil, "Argument missing. "..util.see_help("doc")
65 end 64 end
diff --git a/src/luarocks/download.lua b/src/luarocks/download.lua
index 090f49aa..18573ae4 100644
--- a/src/luarocks/download.lua
+++ b/src/luarocks/download.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the luarocks "download" command. 2--- Module implementing the luarocks "download" command.
3-- Download a rock from the repository. 3-- Download a rock from the repository.
4--module("luarocks.download", package.seeall)
5local download = {} 4local download = {}
6package.loaded["luarocks.download"] = download 5package.loaded["luarocks.download"] = download
7 6
@@ -11,7 +10,9 @@ local fetch = require("luarocks.fetch")
11local search = require("luarocks.search") 10local search = require("luarocks.search")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local dir = require("luarocks.dir") 12local dir = require("luarocks.dir")
13local cfg = require("luarocks.cfg")
14 14
15util.add_run_function(download)
15download.help_summary = "Download a specific rock file from a rocks server." 16download.help_summary = "Download a specific rock file from a rocks server."
16download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" 17download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]"
17 18
@@ -25,7 +26,7 @@ download.help = [[
25local function get_file(filename) 26local function get_file(filename)
26 local protocol, pathname = dir.split_url(filename) 27 local protocol, pathname = dir.split_url(filename)
27 if protocol == "file" then 28 if protocol == "file" then
28 local ok, err = fs.copy(pathname, fs.current_dir()) 29 local ok, err = fs.copy(pathname, fs.current_dir(), cfg.perm_read)
29 if ok then 30 if ok then
30 return pathname 31 return pathname
31 else 32 else
@@ -84,12 +85,10 @@ end
84-- version may also be passed. 85-- version may also be passed.
85-- @return boolean or (nil, string): true if successful or nil followed 86-- @return boolean or (nil, string): true if successful or nil followed
86-- by an error message. 87-- by an error message.
87function download.run(...) 88function download.command(flags, name, version)
88 local flags, name, version = util.parse_flags(...)
89
90 assert(type(version) == "string" or not version) 89 assert(type(version) == "string" or not version)
91 if type(name) ~= "string" and not flags["all"] then 90 if type(name) ~= "string" and not flags["all"] then
92 return nil, "Argument missing, see help." 91 return nil, "Argument missing. "..util.see_help("download")
93 end 92 end
94 if not name then name, version = "", "" end 93 if not name then name, version = "", "" end
95 94
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua
index 1ba26663..3eea61fc 100644
--- a/src/luarocks/fetch.lua
+++ b/src/luarocks/fetch.lua
@@ -1,6 +1,5 @@
1 1
2--- Functions related to fetching and loading local and remote files. 2--- Functions related to fetching and loading local and remote files.
3--module("luarocks.fetch", package.seeall)
4local fetch = {} 3local fetch = {}
5package.loaded["luarocks.fetch"] = fetch 4package.loaded["luarocks.fetch"] = fetch
6 5
diff --git a/src/luarocks/fetch/cvs.lua b/src/luarocks/fetch/cvs.lua
index ccf928c4..ece711b6 100644
--- a/src/luarocks/fetch/cvs.lua
+++ b/src/luarocks/fetch/cvs.lua
@@ -1,6 +1,5 @@
1 1
2--- Fetch back-end for retrieving sources from CVS. 2--- Fetch back-end for retrieving sources from CVS.
3--module("luarocks.fetch.cvs", package.seeall)
4local cvs = {} 3local cvs = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua
index aa735b3f..eaba7ffd 100644
--- a/src/luarocks/fetch/git.lua
+++ b/src/luarocks/fetch/git.lua
@@ -1,6 +1,5 @@
1 1
2--- Fetch back-end for retrieving sources from GIT. 2--- Fetch back-end for retrieving sources from GIT.
3--module("luarocks.fetch.git", package.seeall)
4local git = {} 3local git = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
diff --git a/src/luarocks/fetch/git_file.lua b/src/luarocks/fetch/git_file.lua
index 0144bc2e..8d46bbca 100644
--- a/src/luarocks/fetch/git_file.lua
+++ b/src/luarocks/fetch/git_file.lua
@@ -1,6 +1,5 @@
1 1
2--- Fetch back-end for retrieving sources from local Git repositories. 2--- Fetch back-end for retrieving sources from local Git repositories.
3--module("luarocks.fetch.git_file", package.seeall)
4local git_file = {} 3local git_file = {}
5 4
6local git = require("luarocks.fetch.git") 5local git = require("luarocks.fetch.git")
diff --git a/src/luarocks/fetch/git_http.lua b/src/luarocks/fetch/git_http.lua
index 4ecd4816..d85e2572 100644
--- a/src/luarocks/fetch/git_http.lua
+++ b/src/luarocks/fetch/git_http.lua
@@ -7,7 +7,6 @@
7-- source = { url = "git+http://example.com/foo.git" } 7-- source = { url = "git+http://example.com/foo.git" }
8-- Prefer using the normal git:// fetch mode as it is more widely 8-- Prefer using the normal git:// fetch mode as it is more widely
9-- available in older versions of LuaRocks. 9-- available in older versions of LuaRocks.
10--module("luarocks.fetch.git_http", package.seeall)
11local git_http = {} 10local git_http = {}
12 11
13local git = require("luarocks.fetch.git") 12local git = require("luarocks.fetch.git")
diff --git a/src/luarocks/fetch/hg.lua b/src/luarocks/fetch/hg.lua
index 518130b4..4cf8d028 100644
--- a/src/luarocks/fetch/hg.lua
+++ b/src/luarocks/fetch/hg.lua
@@ -1,6 +1,5 @@
1 1
2--- Fetch back-end for retrieving sources from HG. 2--- Fetch back-end for retrieving sources from HG.
3--module("luarocks.fetch.hg", package.seeall)
4local hg = {} 3local hg = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
diff --git a/src/luarocks/fetch/sscm.lua b/src/luarocks/fetch/sscm.lua
index 53ae86a3..5add10db 100644
--- a/src/luarocks/fetch/sscm.lua
+++ b/src/luarocks/fetch/sscm.lua
@@ -1,6 +1,5 @@
1 1
2--- Fetch back-end for retrieving sources from Surround SCM Server 2--- Fetch back-end for retrieving sources from Surround SCM Server
3--module("luarocks.fetch.sscm", package.seeall)
4local sscm = {} 3local sscm = {}
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
diff --git a/src/luarocks/fetch/svn.lua b/src/luarocks/fetch/svn.lua
index 755e5e32..29bce1b5 100644
--- a/src/luarocks/fetch/svn.lua
+++ b/src/luarocks/fetch/svn.lua
@@ -1,6 +1,5 @@
1 1
2--- Fetch back-end for retrieving sources from Subversion. 2--- Fetch back-end for retrieving sources from Subversion.
3--module("luarocks.fetch.svn", package.seeall)
4local svn = {} 3local svn = {}
5 4
6local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua
index 57302c7f..54cc7d73 100644
--- a/src/luarocks/fs.lua
+++ b/src/luarocks/fs.lua
@@ -7,7 +7,6 @@
7 7
8local pairs = pairs 8local pairs = pairs
9 9
10--module("luarocks.fs", package.seeall)
11local fs = {} 10local fs = {}
12package.loaded["luarocks.fs"] = fs 11package.loaded["luarocks.fs"] = fs
13 12
@@ -68,7 +67,10 @@ load_fns(fs_lua)
68 67
69-- Load platform-specific fallbacks for missing Lua modules 68-- Load platform-specific fallbacks for missing Lua modules
70local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") 69local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools")
71if ok and fs_plat_tools then load_fns(fs_plat_tools) end 70if ok and fs_plat_tools then
71 load_fns(fs_plat_tools)
72 load_fns(require("luarocks.fs.tools"))
73end
72 74
73 75
74return fs 76return fs
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua
index 483b3e3c..a31cbb4e 100644
--- a/src/luarocks/fs/lua.lua
+++ b/src/luarocks/fs/lua.lua
@@ -255,6 +255,10 @@ function fs_lua.make_dir(directory)
255 if not ok then 255 if not ok then
256 return false, err 256 return false, err
257 end 257 end
258 ok, err = fs.chmod(path, cfg.perm_exec)
259 if not ok then
260 return false, err
261 end
258 elseif mode ~= "directory" then 262 elseif mode ~= "directory" then
259 return false, path.." is not a directory" 263 return false, path.." is not a directory"
260 end 264 end
@@ -320,12 +324,14 @@ end
320-- Assumes paths are normalized. 324-- Assumes paths are normalized.
321-- @param src string: Pathname of source 325-- @param src string: Pathname of source
322-- @param dest string: Pathname of destination 326-- @param dest string: Pathname of destination
327-- @param perms string or nil: Optional permissions.
328-- If not given, permissions of the source are copied over to the destination.
323-- @return boolean or (boolean, string): true on success, false on failure 329-- @return boolean or (boolean, string): true on success, false on failure
324local function recursive_copy(src, dest) 330local function recursive_copy(src, dest, perms)
325 local srcmode = lfs.attributes(src, "mode") 331 local srcmode = lfs.attributes(src, "mode")
326 332
327 if srcmode == "file" then 333 if srcmode == "file" then
328 local ok = fs.copy(src, dest) 334 local ok = fs.copy(src, dest, perms)
329 if not ok then return false end 335 if not ok then return false end
330 elseif srcmode == "directory" then 336 elseif srcmode == "directory" then
331 local subdir = dir.path(dest, dir.base_name(src)) 337 local subdir = dir.path(dest, dir.base_name(src))
@@ -333,7 +339,7 @@ local function recursive_copy(src, dest)
333 if not ok then return nil, err end 339 if not ok then return nil, err end
334 for file in lfs.dir(src) do 340 for file in lfs.dir(src) do
335 if file ~= "." and file ~= ".." then 341 if file ~= "." and file ~= ".." then
336 local ok = recursive_copy(dir.path(src, file), subdir) 342 local ok = recursive_copy(dir.path(src, file), subdir, perms)
337 if not ok then return false end 343 if not ok then return false end
338 end 344 end
339 end 345 end
@@ -344,9 +350,10 @@ end
344--- Recursively copy the contents of a directory. 350--- Recursively copy the contents of a directory.
345-- @param src string: Pathname of source 351-- @param src string: Pathname of source
346-- @param dest string: Pathname of destination 352-- @param dest string: Pathname of destination
353-- @param perms string or nil: Optional permissions.
347-- @return boolean or (boolean, string): true on success, false on failure, 354-- @return boolean or (boolean, string): true on success, false on failure,
348-- plus an error message. 355-- plus an error message.
349function fs_lua.copy_contents(src, dest) 356function fs_lua.copy_contents(src, dest, perms)
350 assert(src and dest) 357 assert(src and dest)
351 src = dir.normalize(src) 358 src = dir.normalize(src)
352 dest = dir.normalize(dest) 359 dest = dir.normalize(dest)
@@ -354,7 +361,7 @@ function fs_lua.copy_contents(src, dest)
354 361
355 for file in lfs.dir(src) do 362 for file in lfs.dir(src) do
356 if file ~= "." and file ~= ".." then 363 if file ~= "." and file ~= ".." then
357 local ok = recursive_copy(dir.path(src, file), dest) 364 local ok = recursive_copy(dir.path(src, file), dest, perms)
358 if not ok then 365 if not ok then
359 return false, "Failed copying "..src.." to "..dest 366 return false, "Failed copying "..src.." to "..dest
360 end 367 end
@@ -799,14 +806,16 @@ end
799--- Move a file. 806--- Move a file.
800-- @param src string: Pathname of source 807-- @param src string: Pathname of source
801-- @param dest string: Pathname of destination 808-- @param dest string: Pathname of destination
809-- @param perms string or nil: Permissions for destination file,
810-- or nil to use the source filename permissions.
802-- @return boolean or (boolean, string): true on success, false on failure, 811-- @return boolean or (boolean, string): true on success, false on failure,
803-- plus an error message. 812-- plus an error message.
804function fs_lua.move(src, dest) 813function fs_lua.move(src, dest, perms)
805 assert(src and dest) 814 assert(src and dest)
806 if fs.exists(dest) and not fs.is_dir(dest) then 815 if fs.exists(dest) and not fs.is_dir(dest) then
807 return false, "File already exists: "..dest 816 return false, "File already exists: "..dest
808 end 817 end
809 local ok, err = fs.copy(src, dest) 818 local ok, err = fs.copy(src, dest, perms)
810 if not ok then 819 if not ok then
811 return false, err 820 return false, err
812 end 821 end
diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua
new file mode 100644
index 00000000..ed51b545
--- /dev/null
+++ b/src/luarocks/fs/tools.lua
@@ -0,0 +1,156 @@
1
2--- Common fs operations implemented with third-party tools.
3local tools = {}
4
5local fs = require("luarocks.fs")
6local dir = require("luarocks.dir")
7local cfg = require("luarocks.cfg")
8
9local vars = cfg.variables
10
11local dir_stack = {}
12
13--- Obtain current directory.
14-- Uses the module's internal directory stack.
15-- @return string: the absolute pathname of the current directory.
16function tools.current_dir()
17 local current = cfg.cache_pwd
18 if not current then
19 local pipe = io.popen(fs.quiet_stderr(fs.Q(vars.PWD)))
20 current = pipe:read("*l")
21 pipe:close()
22 cfg.cache_pwd = current
23 end
24 for _, directory in ipairs(dir_stack) do
25 current = fs.absolute_name(directory, current)
26 end
27 return current
28end
29
30--- Change the current directory.
31-- Uses the module's internal directory stack. This does not have exact
32-- semantics of chdir, as it does not handle errors the same way,
33-- but works well for our purposes for now.
34-- @param directory string: The directory to switch to.
35-- @return boolean or (nil, string): true if successful, (nil, error message) if failed.
36function tools.change_dir(directory)
37 assert(type(directory) == "string")
38 if fs.is_dir(directory) then
39 table.insert(dir_stack, directory)
40 return true
41 end
42 return nil, "directory not found: "..directory
43end
44
45--- Change directory to root.
46-- Allows leaving a directory (e.g. for deleting it) in
47-- a crossplatform way.
48function tools.change_dir_to_root()
49 table.insert(dir_stack, "/")
50end
51
52--- Change working directory to the previous in the directory stack.
53function tools.pop_dir()
54 local directory = table.remove(dir_stack)
55 return directory ~= nil
56end
57
58--- Run the given command.
59-- The command is executed in the current directory in the directory stack.
60-- @param cmd string: No quoting/escaping is applied to the command.
61-- @return boolean: true if command succeeds (status code 0), false
62-- otherwise.
63function tools.execute_string(cmd)
64 local current = fs.current_dir()
65 if not current then return false end
66 cmd = fs.command_at(current, cmd)
67 local code = os.execute(cmd)
68 if code == 0 or code == true then
69 return true
70 else
71 return false
72 end
73end
74
75--- Internal implementation function for fs.dir.
76-- Yields a filename on each iteration.
77-- @param at string: directory to list
78-- @return nil
79function tools.dir_iterator(at)
80 local pipe = io.popen(fs.command_at(at, fs.Q(vars.LS)))
81 for file in pipe:lines() do
82 if file ~= "." and file ~= ".." then
83 coroutine.yield(file)
84 end
85 end
86 pipe:close()
87end
88
89--- Download a remote file.
90-- @param url string: URL to be fetched.
91-- @param filename string or nil: this function attempts to detect the
92-- resulting local filename of the remote file as the basename of the URL;
93-- if that is not correct (due to a redirection, for example), the local
94-- filename can be given explicitly as this second argument.
95-- @return (boolean, string): true and the filename on success,
96-- false and the error message on failure.
97function tools.use_downloader(url, filename, cache)
98 assert(type(url) == "string")
99 assert(type(filename) == "string" or not filename)
100
101 filename = fs.absolute_name(filename or dir.base_name(url))
102
103 local ok
104 if cfg.downloader == "wget" then
105 local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet "
106 if cfg.connection_timeout and cfg.connection_timeout > 0 then
107 wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
108 end
109 if cache then
110 -- --timestamping is incompatible with --output-document,
111 -- but that's not a problem for our use cases.
112 fs.change_dir(dir.dir_name(filename))
113 ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
114 fs.pop_dir()
115 elseif filename then
116 ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
117 else
118 ok = fs.execute_quiet(wget_cmd, url)
119 end
120 elseif cfg.downloader == "curl" then
121 local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" "
122 if cfg.connection_timeout and cfg.connection_timeout > 0 then
123 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
124 end
125 ok = fs.execute_string(fs.quiet_stderr(curl_cmd..fs.Q(url).." > "..fs.Q(filename)))
126 end
127 if ok then
128 return true, filename
129 else
130 return false
131 end
132end
133
134local md5_cmd = {
135 md5sum = fs.Q(vars.MD5SUM),
136 openssl = fs.Q(vars.OPENSSL).." md5",
137 md5 = fs.Q(vars.MD5),
138}
139
140--- Get the MD5 checksum for a file.
141-- @param file string: The file to be computed.
142-- @return string: The MD5 checksum or nil + message
143function tools.get_md5(file)
144 local cmd = md5_cmd[cfg.md5checker]
145 if not cmd then return nil, "no MD5 checker command configured" end
146 local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
147 local computed = pipe:read("*a")
148 pipe:close()
149 if computed then
150 computed = computed:match("("..("%x"):rep(32)..")")
151 end
152 if computed then return computed end
153 return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
154end
155
156return tools
diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua
index 570b26e4..5c6b542c 100644
--- a/src/luarocks/fs/unix.lua
+++ b/src/luarocks/fs/unix.lua
@@ -1,6 +1,5 @@
1 1
2--- Unix implementation of filesystem and platform abstractions. 2--- Unix implementation of filesystem and platform abstractions.
3--module("luarocks.fs.unix", package.seeall)
4local unix = {} 3local unix = {}
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
@@ -16,6 +15,13 @@ function unix.quiet(cmd)
16 return cmd.." 1> /dev/null 2> /dev/null" 15 return cmd.." 1> /dev/null 2> /dev/null"
17end 16end
18 17
18--- Annotate command string for execution with quiet stderr.
19-- @param cmd string: A command-line string.
20-- @return string: The command-line, with stderr silencing annotation.
21function unix.quiet_stderr(cmd)
22 return cmd.." 2> /dev/null"
23end
24
19--- Return an absolute pathname from a potentially relative one. 25--- Return an absolute pathname from a potentially relative one.
20-- @param pathname string: pathname to convert. 26-- @param pathname string: pathname to convert.
21-- @param relative_to string or nil: path to prepend when making 27-- @param relative_to string or nil: path to prepend when making
@@ -66,7 +72,7 @@ function unix.wrap_script(file, dest, name, version)
66 local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k and l.add_context("..util.LQ(name)..","..util.LQ(version)..")" 72 local addctx = "local k,l,_=pcall(require,"..util.LQ("luarocks.loader")..") _=k and l.add_context("..util.LQ(name)..","..util.LQ(version)..")"
67 wrapper:write('exec '..fs.Q(lua)..' -e '..fs.Q(ppaths)..' -e '..fs.Q(addctx)..' '..fs.Q(file)..' "$@"\n') 73 wrapper:write('exec '..fs.Q(lua)..' -e '..fs.Q(ppaths)..' -e '..fs.Q(addctx)..' '..fs.Q(file)..' "$@"\n')
68 wrapper:close() 74 wrapper:close()
69 if fs.chmod(wrapname, "0755") then 75 if fs.chmod(wrapname, cfg.perm_exec) then
70 return true 76 return true
71 else 77 else
72 return nil, "Could not make "..wrapname.." executable." 78 return nil, "Could not make "..wrapname.." executable."
@@ -96,7 +102,7 @@ function unix.is_actual_binary(filename)
96end 102end
97 103
98function unix.copy_binary(filename, dest) 104function unix.copy_binary(filename, dest)
99 return fs.copy(filename, dest, "0755") 105 return fs.copy(filename, dest, cfg.perm_exec)
100end 106end
101 107
102--- Move a file on top of the other. 108--- Move a file on top of the other.
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua
index ab55897e..7a67fb22 100644
--- a/src/luarocks/fs/unix/tools.lua
+++ b/src/luarocks/fs/unix/tools.lua
@@ -1,80 +1,21 @@
1 1
2--- fs operations implemented with third-party tools for Unix platform abstractions. 2--- fs operations implemented with third-party tools for Unix platform abstractions.
3--module("luarocks.fs.unix.tools", package.seeall)
4local tools = {} 3local tools = {}
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
8local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.cfg")
9 8
10local dir_stack = {}
11
12local vars = cfg.variables 9local vars = cfg.variables
13 10
14local function command_at(directory, cmd) 11--- Adds prefix to command to make it run from a directory.
12-- @param directory string: Path to a directory.
13-- @param cmd string: A command-line string.
14-- @return string: The command-line with prefix.
15function tools.command_at(directory, cmd)
15 return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd 16 return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd
16end 17end
17 18
18--- Obtain current directory.
19-- Uses the module's internal directory stack.
20-- @return string: the absolute pathname of the current directory.
21function tools.current_dir()
22 local current = cfg.cache_pwd
23 if not current then
24 local pipe = io.popen(fs.Q(vars.PWD).." 2> /dev/null")
25 current = pipe:read("*l")
26 pipe:close()
27 cfg.cache_pwd = current
28 end
29 for _, directory in ipairs(dir_stack) do
30 current = fs.absolute_name(directory, current)
31 end
32 return current
33end
34
35--- Run the given command.
36-- The command is executed in the current directory in the directory stack.
37-- @param cmd string: No quoting/escaping is applied to the command.
38-- @return boolean: true if command succeeds (status code 0), false
39-- otherwise.
40function tools.execute_string(cmd)
41 local current = fs.current_dir()
42 if not current then return false end
43 local code, err = os.execute(command_at(current, cmd))
44 if code == 0 or code == true then
45 return true
46 else
47 return false
48 end
49end
50
51--- Change the current directory.
52-- Uses the module's internal directory stack. This does not have exact
53-- semantics of chdir, as it does not handle errors the same way,
54-- but works well for our purposes for now.
55-- @param directory string: The directory to switch to.
56function tools.change_dir(directory)
57 assert(type(directory) == "string")
58 if fs.is_dir(directory) then
59 table.insert(dir_stack, directory)
60 return true
61 end
62 return nil, "directory not found: "..directory
63end
64
65--- Change directory to root.
66-- Allows leaving a directory (e.g. for deleting it) in
67-- a crossplatform way.
68function tools.change_dir_to_root()
69 table.insert(dir_stack, "/")
70end
71
72--- Change working directory to the previous in the directory stack.
73function tools.pop_dir()
74 local directory = table.remove(dir_stack)
75 return directory ~= nil
76end
77
78--- Create a directory if it does not already exist. 19--- Create a directory if it does not already exist.
79-- If any of the higher levels in the path name does not exist 20-- If any of the higher levels in the path name does not exist
80-- too, they are created as well. 21-- too, they are created as well.
@@ -155,20 +96,6 @@ function tools.delete(arg)
155 fs.execute_quiet(vars.RM, "-rf", arg) 96 fs.execute_quiet(vars.RM, "-rf", arg)
156end 97end
157 98
158--- Internal implementation function for fs.dir.
159-- Yields a filename on each iteration.
160-- @param at string: directory to list
161-- @return nil
162function tools.dir_iterator(at)
163 local pipe = io.popen(command_at(at, vars.LS))
164 for file in pipe:lines() do
165 if file ~= "." and file ~= ".." then
166 coroutine.yield(file)
167 end
168 end
169 pipe:close()
170end
171
172--- Recursively scan the contents of a directory. 99--- Recursively scan the contents of a directory.
173-- @param at string or nil: directory to scan (will be the current 100-- @param at string or nil: directory to scan (will be the current
174-- directory if none is given). 101-- directory if none is given).
@@ -183,7 +110,7 @@ function tools.find(at)
183 return {} 110 return {}
184 end 111 end
185 local result = {} 112 local result = {}
186 local pipe = io.popen(command_at(at, vars.FIND.." * 2>/dev/null")) 113 local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(vars.FIND.." *")))
187 for file in pipe:lines() do 114 for file in pipe:lines() do
188 table.insert(result, file) 115 table.insert(result, file)
189 end 116 end
@@ -232,51 +159,6 @@ function tools.is_file(file)
232 return fs.execute(vars.TEST, "-f", file) 159 return fs.execute(vars.TEST, "-f", file)
233end 160end
234 161
235--- Download a remote file.
236-- @param url string: URL to be fetched.
237-- @param filename string or nil: this function attempts to detect the
238-- resulting local filename of the remote file as the basename of the URL;
239-- if that is not correct (due to a redirection, for example), the local
240-- filename can be given explicitly as this second argument.
241-- @return (boolean, string): true and the filename on success,
242-- false and the error message on failure.
243function tools.use_downloader(url, filename, cache)
244 assert(type(url) == "string")
245 assert(type(filename) == "string" or not filename)
246
247 filename = fs.absolute_name(filename or dir.base_name(url))
248
249 local ok
250 if cfg.downloader == "wget" then
251 local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet "
252 if cfg.connection_timeout and cfg.connection_timeout > 0 then
253 wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
254 end
255 if cache then
256 -- --timestamping is incompatible with --output-document,
257 -- but that's not a problem for our use cases.
258 fs.change_dir(dir.dir_name(filename))
259 ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
260 fs.pop_dir()
261 elseif filename then
262 ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
263 else
264 ok = fs.execute_quiet(wget_cmd, url)
265 end
266 elseif cfg.downloader == "curl" then
267 local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent '"..cfg.user_agent.." via curl' "
268 if cfg.connection_timeout and cfg.connection_timeout > 0 then
269 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
270 end
271 ok = fs.execute_string(curl_cmd..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename))
272 end
273 if ok then
274 return true, filename
275 else
276 return false
277 end
278end
279
280function tools.chmod(pathname, mode) 162function tools.chmod(pathname, mode)
281 if mode then 163 if mode then
282 return fs.execute(vars.CHMOD, mode, pathname) 164 return fs.execute(vars.CHMOD, mode, pathname)
@@ -319,28 +201,6 @@ function tools.unpack_archive(archive)
319 return true 201 return true
320end 202end
321 203
322local md5_cmd = {
323 md5sum = vars.MD5SUM,
324 openssl = vars.OPENSSL.." md5",
325 md5 = vars.MD5,
326}
327
328--- Get the MD5 checksum for a file.
329-- @param file string: The file to be computed.
330-- @return string: The MD5 checksum
331function tools.get_md5(file)
332 local cmd = md5_cmd[cfg.md5checker]
333 if not cmd then return nil, "no MD5 checker command configured" end
334 local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
335 local computed = pipe:read("*a")
336 pipe:close()
337 if computed then
338 computed = computed:match("("..("%x"):rep(32)..")")
339 end
340 if computed then return computed end
341 return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
342end
343
344function tools.get_permissions(filename) 204function tools.get_permissions(filename)
345 local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename)) 205 local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename))
346 local ret = pipe:read("*l") 206 local ret = pipe:read("*l")
diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua
index c14c421b..8debaeef 100644
--- a/src/luarocks/fs/win32.lua
+++ b/src/luarocks/fs/win32.lua
@@ -1,7 +1,6 @@
1--- Windows implementation of filesystem and platform abstractions. 1--- Windows implementation of filesystem and platform abstractions.
2-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities 2-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities
3-- used by this module. 3-- used by this module.
4--module("luarocks.fs.win32", package.seeall)
5local win32 = {} 4local win32 = {}
6 5
7local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
@@ -27,6 +26,13 @@ function win32.quiet(cmd)
27 return cmd.." 2> NUL 1> NUL" 26 return cmd.." 2> NUL 1> NUL"
28end 27end
29 28
29--- Annotate command string for execution with quiet stderr.
30-- @param cmd string: A command-line string.
31-- @return string: The command-line, with stderr silencing annotation.
32function win32.quiet_stderr(cmd)
33 return cmd.." 2> NUL"
34end
35
30local drive_letter = "[%.a-zA-Z]?:?[\\/]" 36local drive_letter = "[%.a-zA-Z]?:?[\\/]"
31 37
32local win_escape_chars = { 38local win_escape_chars = {
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua
index b9dce85c..1d47fa59 100644
--- a/src/luarocks/fs/win32/tools.lua
+++ b/src/luarocks/fs/win32/tools.lua
@@ -2,29 +2,19 @@
2--- fs operations implemented with third-party tools for Windows platform abstractions. 2--- fs operations implemented with third-party tools for Windows platform abstractions.
3-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities 3-- Download http://unxutils.sourceforge.net/ for Windows GNU utilities
4-- used by this module. 4-- used by this module.
5--module("luarocks.fs.win32.tools", package.seeall)
6local tools = {} 5local tools = {}
7 6
8local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
9local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
10local cfg = require("luarocks.cfg") 9local cfg = require("luarocks.cfg")
11 10
12local dir_stack = {}
13
14local vars = cfg.variables 11local vars = cfg.variables
15 12
16--- Strip the last extension of a filename. 13--- Adds prefix to command to make it run from a directory.
17-- Example: "foo.tar.gz" becomes "foo.tar". 14-- @param directory string: Path to a directory.
18-- If filename has no dots, returns it unchanged. 15-- @param cmd string: A command-line string.
19-- @param filename string: The file name to strip. 16-- @return string: The command-line with prefix.
20-- @return string: The stripped name. 17function tools.command_at(directory, cmd)
21local function strip_extension(filename)
22 assert(type(filename) == "string")
23
24 return (filename:gsub("%.[^.]+$", "")) or filename
25end
26
27local function command_at(directory, cmd)
28 local drive = directory:match("^([A-Za-z]:)") 18 local drive = directory:match("^([A-Za-z]:)")
29 cmd = "cd " .. fs.Q(directory) .. " & " .. cmd 19 cmd = "cd " .. fs.Q(directory) .. " & " .. cmd
30 if drive then 20 if drive then
@@ -33,68 +23,6 @@ local function command_at(directory, cmd)
33 return cmd 23 return cmd
34end 24end
35 25
36--- Obtain current directory.
37-- Uses the module's internal directory stack.
38-- @return string: the absolute pathname of the current directory.
39function tools.current_dir()
40 local current = cfg.cache_pwd
41 if not current then
42 local pipe = io.popen(fs.Q(vars.PWD).. " 2> NUL")
43 current = pipe:read("*l")
44 pipe:close()
45 cfg.cache_pwd = current
46 end
47 for _, directory in ipairs(dir_stack) do
48 current = fs.absolute_name(directory, current)
49 end
50 return current
51end
52
53--- Run the given command.
54-- The command is executed in the current directory in the directory stack.
55-- @param cmd string: No quoting/escaping is applied to the command.
56-- @return boolean: true if command succeeds (status code 0), false
57-- otherwise.
58function tools.execute_string(cmd)
59 local current = fs.current_dir()
60 if not current then return false end
61 cmd = command_at(current, cmd)
62 local code = os.execute(cmd)
63 if code == 0 or code == true then
64 return true
65 else
66 return false
67 end
68end
69
70--- Change the current directory.
71-- Uses the module's internal directory stack. This does not have exact
72-- semantics of chdir, as it does not handle errors the same way,
73-- but works well for our purposes for now.
74-- @param directory string: The directory to switch to.
75-- @return boolean or (nil, string): true if successful, (nil, error message) if failed.
76function tools.change_dir(directory)
77 assert(type(directory) == "string")
78 if fs.is_dir(directory) then
79 table.insert(dir_stack, directory)
80 return true
81 end
82 return nil, "directory not found: "..directory
83end
84
85--- Change directory to root.
86-- Allows leaving a directory (e.g. for deleting it) in
87-- a crossplatform way.
88function tools.change_dir_to_root()
89 table.insert(dir_stack, "/")
90end
91
92--- Change working directory to the previous in the directory stack.
93function tools.pop_dir()
94 local directory = table.remove(dir_stack)
95 return directory ~= nil
96end
97
98--- Create a directory if it does not already exist. 26--- Create a directory if it does not already exist.
99-- If any of the higher levels in the path name does not exist 27-- If any of the higher levels in the path name does not exist
100-- too, they are created as well. 28-- too, they are created as well.
@@ -168,20 +96,6 @@ function tools.delete(arg)
168 fs.execute_quiet("if exist "..fs.Q(arg.."\\").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )") 96 fs.execute_quiet("if exist "..fs.Q(arg.."\\").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )")
169end 97end
170 98
171--- Internal implementation function for fs.dir.
172-- Yields a filename on each iteration.
173-- @param at string: directory to list
174-- @return nil
175function tools.dir_iterator(at)
176 local pipe = io.popen(command_at(at, fs.Q(vars.LS)))
177 for file in pipe:lines() do
178 if file ~= "." and file ~= ".." then
179 coroutine.yield(file)
180 end
181 end
182 pipe:close()
183end
184
185--- Recursively scan the contents of a directory. 99--- Recursively scan the contents of a directory.
186-- @param at string or nil: directory to scan (will be the current 100-- @param at string or nil: directory to scan (will be the current
187-- directory if none is given). 101-- directory if none is given).
@@ -196,7 +110,7 @@ function tools.find(at)
196 return {} 110 return {}
197 end 111 end
198 local result = {} 112 local result = {}
199 local pipe = io.popen(command_at(at, fs.Q(vars.FIND).." 2> NUL")) 113 local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(fs.Q(vars.FIND))))
200 for file in pipe:lines() do 114 for file in pipe:lines() do
201 -- Windows find is a bit different 115 -- Windows find is a bit different
202 local first_two = file:sub(1,2) 116 local first_two = file:sub(1,2)
@@ -242,49 +156,14 @@ function tools.is_file(file)
242 return fs.execute(fs.Q(vars.TEST).." -f", file) 156 return fs.execute(fs.Q(vars.TEST).." -f", file)
243end 157end
244 158
245--- Download a remote file. 159--- Strip the last extension of a filename.
246-- @param url string: URL to be fetched. 160-- Example: "foo.tar.gz" becomes "foo.tar".
247-- @param filename string or nil: this function attempts to detect the 161-- If filename has no dots, returns it unchanged.
248-- resulting local filename of the remote file as the basename of the URL; 162-- @param filename string: The file name to strip.
249-- if that is not correct (due to a redirection, for example), the local 163-- @return string: The stripped name.
250-- filename can be given explicitly as this second argument. 164local function strip_extension(filename)
251-- @return (boolean, string): true and the filename on success, 165 assert(type(filename) == "string")
252-- false and the error message on failure. 166 return (filename:gsub("%.[^.]+$", "")) or filename
253function tools.use_downloader(url, filename, cache)
254 assert(type(url) == "string")
255 assert(type(filename) == "string" or not filename)
256
257 filename = fs.absolute_name(filename or dir.base_name(url))
258
259 local ok
260 if cfg.downloader == "wget" then
261 local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet "
262 if cfg.connection_timeout and cfg.connection_timeout > 0 then
263 wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
264 end
265 if cache then
266 -- --timestamping is incompatible with --output-document,
267 -- but that's not a problem for our use cases.
268 fs.change_dir(dir.dir_name(filename))
269 ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
270 fs.pop_dir()
271 elseif filename then
272 ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
273 else
274 ok = fs.execute_quiet(wget_cmd, url)
275 end
276 elseif cfg.downloader == "curl" then
277 local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" "
278 if cfg.connection_timeout and cfg.connection_timeout > 0 then
279 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
280 end
281 ok = fs.execute_string(curl_cmd..fs.Q(url).." 2> NUL 1> "..fs.Q(filename))
282 end
283 if ok then
284 return true, filename
285 else
286 return false
287 end
288end 167end
289 168
290--- Uncompress gzip file. 169--- Uncompress gzip file.
@@ -334,28 +213,6 @@ function tools.unpack_archive(archive)
334 return true 213 return true
335end 214end
336 215
337local md5_cmd = {
338 md5sum = fs.Q(vars.MD5SUM),
339 openssl = fs.Q(vars.OPENSSL).." md5",
340 md5 = fs.Q(vars.MD5),
341}
342
343--- Get the MD5 checksum for a file.
344-- @param file string: The file to be computed.
345-- @return string: The MD5 checksum or nil + message
346function tools.get_md5(file)
347 local cmd = md5_cmd[cfg.md5checker]
348 if not cmd then return nil, "no MD5 checker command configured" end
349 local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
350 local computed = pipe:read("*a")
351 pipe:close()
352 if computed then
353 computed = computed:match("("..("%x"):rep(32)..")")
354 end
355 if computed then return computed end
356 return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
357end
358
359--- Test for existance of a file. 216--- Test for existance of a file.
360-- @param file string: filename to test 217-- @param file string: filename to test
361-- @return boolean: true if file exists, false otherwise. 218-- @return boolean: true if file exists, false otherwise.
diff --git a/src/luarocks/help.lua b/src/luarocks/help.lua
index 5a2681a3..28f97702 100644
--- a/src/luarocks/help.lua
+++ b/src/luarocks/help.lua
@@ -4,7 +4,6 @@
4-- uses a global table called "commands" to find commands 4-- uses a global table called "commands" to find commands
5-- to show help for; each command should be represented by a 5-- to show help for; each command should be represented by a
6-- table containing "help" and "help_summary" fields. 6-- table containing "help" and "help_summary" fields.
7--module("luarocks.help", package.seeall)
8local help = {} 7local help = {}
9 8
10local util = require("luarocks.util") 9local util = require("luarocks.util")
@@ -13,6 +12,7 @@ local dir = require("luarocks.dir")
13 12
14local program = util.this_program("luarocks") 13local program = util.this_program("luarocks")
15 14
15util.add_run_function(help)
16help.help_summary = "Help on commands. Type '"..program.." help <command>' for more." 16help.help_summary = "Help on commands. Type '"..program.." help <command>' for more."
17 17
18help.help_arguments = "[<command>]" 18help.help_arguments = "[<command>]"
@@ -41,9 +41,7 @@ end
41-- given, help summaries for all commands are shown. 41-- given, help summaries for all commands are shown.
42-- @return boolean or (nil, string): true if there were no errors 42-- @return boolean or (nil, string): true if there were no errors
43-- or nil and an error message if an invalid command was requested. 43-- or nil and an error message if an invalid command was requested.
44function help.run(...) 44function help.command(flags, command)
45 local flags, command = util.parse_flags(...)
46
47 if not command then 45 if not command then
48 local conf = cfg.which_config() 46 local conf = cfg.which_config()
49 print_banner() 47 print_banner()
diff --git a/src/luarocks/index.lua b/src/luarocks/index.lua
index 116bdfd2..e1f563ef 100644
--- a/src/luarocks/index.lua
+++ b/src/luarocks/index.lua
@@ -1,6 +1,5 @@
1 1
2--- Module which builds the index.html page to be used in rocks servers. 2--- Module which builds the index.html page to be used in rocks servers.
3--module("luarocks.index", package.seeall)
4local index = {} 3local index = {}
5package.loaded["luarocks.index"] = index 4package.loaded["luarocks.index"] = index
6 5
diff --git a/src/luarocks/install.lua b/src/luarocks/install.lua
index c938aa9f..acbf584a 100644
--- a/src/luarocks/install.lua
+++ b/src/luarocks/install.lua
@@ -1,6 +1,5 @@
1--- Module implementing the LuaRocks "install" command. 1--- Module implementing the LuaRocks "install" command.
2-- Installs binary rocks. 2-- Installs binary rocks.
3--module("luarocks.install", package.seeall)
4local install = {} 3local install = {}
5package.loaded["luarocks.install"] = install 4package.loaded["luarocks.install"] = install
6 5
@@ -14,6 +13,7 @@ local manif = require("luarocks.manif")
14local remove = require("luarocks.remove") 13local remove = require("luarocks.remove")
15local cfg = require("luarocks.cfg") 14local cfg = require("luarocks.cfg")
16 15
16util.add_run_function(install)
17install.help_summary = "Install a rock." 17install.help_summary = "Install a rock."
18 18
19install.help_arguments = "{<rock>|<name> [<version>]}" 19install.help_arguments = "{<rock>|<name> [<version>]}"
@@ -98,15 +98,7 @@ function install.install_binary_rock(rock_file, deps_mode)
98 ok, err = manif.update_manifest(name, version, nil, deps_mode) 98 ok, err = manif.update_manifest(name, version, nil, deps_mode)
99 if err then return nil, err end 99 if err then return nil, err end
100 100
101 local license = "" 101 util.announce_install(rockspec)
102 if rockspec.description.license then
103 license = ("(license: "..rockspec.description.license..")")
104 end
105
106 local root_dir = path.root_dir(cfg.rocks_dir)
107 util.printout()
108 util.printout(name.." "..version.." is now installed in "..root_dir.." "..license)
109
110 util.remove_scheduled_function(rollback) 102 util.remove_scheduled_function(rollback)
111 return name, version 103 return name, version
112end 104end
@@ -143,7 +135,7 @@ function install.install_binary_rock_deps(rock_file, deps_mode)
143 if err then return nil, err, errcode end 135 if err then return nil, err, errcode end
144 136
145 util.printout() 137 util.printout()
146 util.printout("Succesfully installed dependencies for " ..name.." "..version) 138 util.printout("Successfully installed dependencies for " ..name.." "..version)
147 139
148 return name, version 140 return name, version
149end 141end
@@ -158,8 +150,7 @@ end
158-- may also be given. 150-- may also be given.
159-- @return boolean or (nil, string, exitcode): True if installation was 151-- @return boolean or (nil, string, exitcode): True if installation was
160-- successful, nil and an error message otherwise. exitcode is optionally returned. 152-- successful, nil and an error message otherwise. exitcode is optionally returned.
161function install.run(...) 153function install.command(flags, name, version)
162 local flags, name, version = util.parse_flags(...)
163 if type(name) ~= "string" then 154 if type(name) ~= "string" then
164 return nil, "Argument missing. "..util.see_help("install") 155 return nil, "Argument missing. "..util.see_help("install")
165 end 156 end
@@ -168,9 +159,8 @@ function install.run(...)
168 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end 159 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end
169 160
170 if name:match("%.rockspec$") or name:match("%.src%.rock$") then 161 if name:match("%.rockspec$") or name:match("%.src%.rock$") then
171 util.printout("Using "..name.."... switching to 'build' mode")
172 local build = require("luarocks.build") 162 local build = require("luarocks.build")
173 return build.run(name, util.forward_flags(flags, "local", "keep", "deps-mode", "only-deps")) 163 return build.command(flags, name)
174 elseif name:match("%.rock$") then 164 elseif name:match("%.rock$") then
175 if flags["only-deps"] then 165 if flags["only-deps"] then
176 ok, err = install.install_binary_rock_deps(name, deps.get_deps_mode(flags)) 166 ok, err = install.install_binary_rock_deps(name, deps.get_deps_mode(flags))
@@ -180,7 +170,7 @@ function install.run(...)
180 if not ok then return nil, err end 170 if not ok then return nil, err end
181 local name, version = ok, err 171 local name, version = ok, err
182 if (not flags["only-deps"]) and (not flags["keep"]) and not cfg.keep_other_versions then 172 if (not flags["only-deps"]) and (not flags["keep"]) and not cfg.keep_other_versions then
183 local ok, err = remove.remove_other_versions(name, version, flags["force"]) 173 local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"])
184 if not ok then util.printerr(err) end 174 if not ok then util.printerr(err) end
185 end 175 end
186 return name, version 176 return name, version
@@ -190,8 +180,8 @@ function install.run(...)
190 if not url then 180 if not url then
191 return nil, err 181 return nil, err
192 end 182 end
193 util.printout("Installing "..url.."...") 183 util.printout("Installing "..url)
194 return install.run(url, util.forward_flags(flags)) 184 return install.command(flags, url)
195 end 185 end
196end 186end
197 187
diff --git a/src/luarocks/lint.lua b/src/luarocks/lint.lua
index 091c8de4..d5cc48d0 100644
--- a/src/luarocks/lint.lua
+++ b/src/luarocks/lint.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "lint" command. 2--- Module implementing the LuaRocks "lint" command.
3-- Utility function that checks syntax of the rockspec. 3-- Utility function that checks syntax of the rockspec.
4--module("luarocks.lint", package.seeall)
5local lint = {} 4local lint = {}
6package.loaded["luarocks.lint"] = lint 5package.loaded["luarocks.lint"] = lint
7 6
@@ -9,6 +8,7 @@ local util = require("luarocks.util")
9local download = require("luarocks.download") 8local download = require("luarocks.download")
10local fetch = require("luarocks.fetch") 9local fetch = require("luarocks.fetch")
11 10
11util.add_run_function(lint)
12lint.help_summary = "Check syntax of a rockspec." 12lint.help_summary = "Check syntax of a rockspec."
13lint.help_arguments = "<rockspec>" 13lint.help_arguments = "<rockspec>"
14lint.help = [[ 14lint.help = [[
@@ -18,9 +18,7 @@ It returns success or failure if the text of a rockspec is
18syntactically correct. 18syntactically correct.
19]] 19]]
20 20
21function lint.run(...) 21function lint.command(flags, input)
22 local flags, input = util.parse_flags(...)
23
24 if not input then 22 if not input then
25 return nil, "Argument missing. "..util.see_help("lint") 23 return nil, "Argument missing. "..util.see_help("lint")
26 end 24 end
diff --git a/src/luarocks/list.lua b/src/luarocks/list.lua
index 99868028..c65e058f 100644
--- a/src/luarocks/list.lua
+++ b/src/luarocks/list.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "list" command. 2--- Module implementing the LuaRocks "list" command.
3-- Lists currently installed rocks. 3-- Lists currently installed rocks.
4--module("luarocks.list", package.seeall)
5local list = {} 4local list = {}
6package.loaded["luarocks.list"] = list 5package.loaded["luarocks.list"] = list
7 6
@@ -11,6 +10,7 @@ local cfg = require("luarocks.cfg")
11local util = require("luarocks.util") 10local util = require("luarocks.util")
12local path = require("luarocks.path") 11local path = require("luarocks.path")
13 12
13util.add_run_function(list)
14list.help_summary = "List currently installed rocks." 14list.help_summary = "List currently installed rocks."
15list.help_arguments = "[--porcelain] <filter>" 15list.help_arguments = "[--porcelain] <filter>"
16list.help = [[ 16list.help = [[
@@ -29,27 +29,19 @@ local function check_outdated(trees, query)
29 end 29 end
30 local outdated = {} 30 local outdated = {}
31 for name, versions in util.sortedpairs(results_installed) do 31 for name, versions in util.sortedpairs(results_installed) do
32 local latest_installed 32 versions = util.keys(versions)
33 local latest_available, latest_available_repo 33 table.sort(versions, deps.compare_versions)
34 34 local latest_installed = versions[1]
35 for version, _ in util.sortedpairs(versions) do
36 latest_installed = version
37 break
38 end
39 35
40 local query_available = search.make_query(name:lower()) 36 local query_available = search.make_query(name:lower())
41 query.exact_name = true 37 query.exact_name = true
42 local results_available, err = search.search_repos(query_available) 38 local results_available, err = search.search_repos(query_available)
43 39
44 if results_available[name] then 40 if results_available[name] then
45 for version, repos in util.sortedpairs(results_available[name], deps.compare_versions) do 41 local available_versions = util.keys(results_available[name])
46 latest_available = version 42 table.sort(available_versions, deps.compare_versions)
47 for _, repo in ipairs(repos) do 43 local latest_available = available_versions[1]
48 latest_available_repo = repo.repo 44 local latest_available_repo = results_available[name][latest_available][1].repo
49 break
50 end
51 break
52 end
53 45
54 if deps.compare_versions(latest_available, latest_installed) then 46 if deps.compare_versions(latest_available, latest_installed) then
55 table.insert(outdated, { name = name, installed = latest_installed, available = latest_available, repo = latest_available_repo }) 47 table.insert(outdated, { name = name, installed = latest_installed, available = latest_available, repo = latest_available_repo })
@@ -78,8 +70,7 @@ end
78-- @param filter string or nil: A substring of a rock name to filter by. 70-- @param filter string or nil: A substring of a rock name to filter by.
79-- @param version string or nil: a version may also be passed. 71-- @param version string or nil: a version may also be passed.
80-- @return boolean: True if succeeded, nil on errors. 72-- @return boolean: True if succeeded, nil on errors.
81function list.run(...) 73function list.command(flags, filter, version)
82 local flags, filter, version = util.parse_flags(...)
83 local query = search.make_query(filter and filter:lower() or "", version) 74 local query = search.make_query(filter and filter:lower() or "", version)
84 query.exact_name = false 75 query.exact_name = false
85 local trees = cfg.rocks_trees 76 local trees = cfg.rocks_trees
diff --git a/src/luarocks/make.lua b/src/luarocks/make.lua
index 94cf4414..1464def7 100644
--- a/src/luarocks/make.lua
+++ b/src/luarocks/make.lua
@@ -3,14 +3,11 @@
3-- Builds sources in the current directory, but unlike "build", 3-- Builds sources in the current directory, but unlike "build",
4-- it does not fetch sources, etc., assuming everything is 4-- it does not fetch sources, etc., assuming everything is
5-- available in the current directory. 5-- available in the current directory.
6--module("luarocks.make", package.seeall)
7local make = {} 6local make = {}
8package.loaded["luarocks.make"] = make 7package.loaded["luarocks.make"] = make
9 8
10local build = require("luarocks.build") 9local build = require("luarocks.build")
11local fs = require("luarocks.fs") 10local fs = require("luarocks.fs")
12local dir = require("luarocks.dir")
13local path = require("luarocks.path")
14local util = require("luarocks.util") 11local util = require("luarocks.util")
15local cfg = require("luarocks.cfg") 12local cfg = require("luarocks.cfg")
16local fetch = require("luarocks.fetch") 13local fetch = require("luarocks.fetch")
@@ -18,6 +15,7 @@ local pack = require("luarocks.pack")
18local remove = require("luarocks.remove") 15local remove = require("luarocks.remove")
19local deps = require("luarocks.deps") 16local deps = require("luarocks.deps")
20 17
18util.add_run_function(make)
21make.help_summary = "Compile package in current directory using a rockspec." 19make.help_summary = "Compile package in current directory using a rockspec."
22make.help_arguments = "[--pack-binary-rock] [<rockspec>]" 20make.help_arguments = "[--pack-binary-rock] [<rockspec>]"
23make.help = [[ 21make.help = [[
@@ -49,70 +47,18 @@ To install rocks, you'll normally want to use the "install" and
49 47
50]] 48]]
51 49
52--- Collect rockspecs located in a subdirectory.
53-- @param versions table: A table mapping rock names to newest rockspec versions.
54-- @param paths table: A table mapping rock names to newest rockspec paths.
55-- @param unnamed_paths table: An array of rockspec paths that don't contain rock
56-- name and version in regular format.
57-- @param subdir string: path to subdirectory.
58local function collect_rockspecs(versions, paths, unnamed_paths, subdir)
59 if fs.is_dir(subdir) then
60 for file in fs.dir(subdir) do
61 file = dir.path(subdir, file)
62
63 if file:match("rockspec$") and fs.is_file(file) then
64 local rock, version = path.parse_name(file)
65
66 if rock then
67 if not versions[rock] or deps.compare_versions(version, versions[rock]) then
68 versions[rock] = version
69 paths[rock] = file
70 end
71 else
72 table.insert(unnamed_paths, file)
73 end
74 end
75 end
76 end
77end
78
79--- Driver function for "make" command. 50--- Driver function for "make" command.
80-- @param name string: A local rockspec. 51-- @param name string: A local rockspec.
81-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an 52-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an
82-- error message otherwise. exitcode is optionally returned. 53-- error message otherwise. exitcode is optionally returned.
83function make.run(...) 54function make.command(flags, rockspec)
84 local flags, rockspec = util.parse_flags(...)
85 assert(type(rockspec) == "string" or not rockspec) 55 assert(type(rockspec) == "string" or not rockspec)
86 56
87 if not rockspec then 57 if not rockspec then
88 -- Try to infer default rockspec name. 58 local err
89 local versions, paths, unnamed_paths = {}, {}, {} 59 rockspec, err = util.get_default_rockspec()
90 -- Look for rockspecs in some common locations. 60 if not rockspec then
91 collect_rockspecs(versions, paths, unnamed_paths, ".") 61 return nil, err
92 collect_rockspecs(versions, paths, unnamed_paths, "rockspec")
93 collect_rockspecs(versions, paths, unnamed_paths, "rockspecs")
94
95 if #unnamed_paths > 0 then
96 -- There are rockspecs not following "name-version.rockspec" format.
97 -- More than one are ambiguous.
98 if #unnamed_paths > 1 then
99 return nil, "Please specify which rockspec file to use."
100 else
101 rockspec = unnamed_paths[1]
102 end
103 else
104 local rock = next(versions)
105
106 if rock then
107 -- If there are rockspecs for multiple rocks it's ambiguous.
108 if next(versions, rock) then
109 return nil, "Please specify which rockspec file to use."
110 else
111 rockspec = paths[rock]
112 end
113 else
114 return nil, "Argument missing: please specify a rockspec to use on current directory."
115 end
116 end 62 end
117 end 63 end
118 if not rockspec:match("rockspec$") then 64 if not rockspec:match("rockspec$") then
@@ -132,7 +78,7 @@ function make.run(...)
132 if not ok then return nil, err end 78 if not ok then return nil, err end
133 local name, version = ok, err 79 local name, version = ok, err
134 if (not flags["keep"]) and not cfg.keep_other_versions then 80 if (not flags["keep"]) and not cfg.keep_other_versions then
135 local ok, err = remove.remove_other_versions(name, version, flags["force"]) 81 local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"])
136 if not ok then util.printerr(err) end 82 if not ok then util.printerr(err) end
137 end 83 end
138 return name, version 84 return name, version
diff --git a/src/luarocks/make_manifest.lua b/src/luarocks/make_manifest.lua
index b6e65bf8..c39c2939 100644
--- a/src/luarocks/make_manifest.lua
+++ b/src/luarocks/make_manifest.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the luarocks-admin "make_manifest" command. 2--- Module implementing the luarocks-admin "make_manifest" command.
3-- Compile a manifest file for a repository. 3-- Compile a manifest file for a repository.
4--module("luarocks.make_manifest", package.seeall)
5local make_manifest = {} 4local make_manifest = {}
6package.loaded["luarocks.make_manifest"] = make_manifest 5package.loaded["luarocks.make_manifest"] = make_manifest
7 6
@@ -13,6 +12,7 @@ local deps = require("luarocks.deps")
13local fs = require("luarocks.fs") 12local fs = require("luarocks.fs")
14local dir = require("luarocks.dir") 13local dir = require("luarocks.dir")
15 14
15util.add_run_function(make_manifest)
16make_manifest.help_summary = "Compile a manifest file for a repository." 16make_manifest.help_summary = "Compile a manifest file for a repository."
17 17
18make_manifest.help = [[ 18make_manifest.help = [[
@@ -27,9 +27,7 @@ make_manifest.help = [[
27-- the default local repository configured as cfg.rocks_dir is used. 27-- the default local repository configured as cfg.rocks_dir is used.
28-- @return boolean or (nil, string): True if manifest was generated, 28-- @return boolean or (nil, string): True if manifest was generated,
29-- or nil and an error message. 29-- or nil and an error message.
30function make_manifest.run(...) 30function make_manifest.command(flags, repo)
31 local flags, repo = util.parse_flags(...)
32
33 assert(type(repo) == "string" or not repo) 31 assert(type(repo) == "string" or not repo)
34 repo = repo or cfg.rocks_dir 32 repo = repo or cfg.rocks_dir
35 33
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua
index 05621315..e30c2a33 100644
--- a/src/luarocks/manif.lua
+++ b/src/luarocks/manif.lua
@@ -2,7 +2,6 @@
2-- Manifest files describe the contents of a LuaRocks tree or server. 2-- Manifest files describe the contents of a LuaRocks tree or server.
3-- They are loaded into manifest tables, which are then used for 3-- They are loaded into manifest tables, which are then used for
4-- performing searches, matching dependencies, etc. 4-- performing searches, matching dependencies, etc.
5--module("luarocks.manif", package.seeall)
6local manif = {} 5local manif = {}
7package.loaded["luarocks.manif"] = manif 6package.loaded["luarocks.manif"] = manif
8 7
@@ -432,8 +431,6 @@ function manif.update_manifest(name, version, repo, deps_mode)
432 431
433 if deps_mode == "none" then deps_mode = cfg.deps_mode end 432 if deps_mode == "none" then deps_mode = cfg.deps_mode end
434 433
435 util.printout("Updating manifest for "..repo)
436
437 local manifest, err = manif.load_manifest(repo) 434 local manifest, err = manif.load_manifest(repo)
438 if not manifest then 435 if not manifest then
439 util.printerr("No existing manifest. Attempting to rebuild...") 436 util.printerr("No existing manifest. Attempting to rebuild...")
diff --git a/src/luarocks/manif_core.lua b/src/luarocks/manif_core.lua
index 610f9860..5c8928d4 100644
--- a/src/luarocks/manif_core.lua
+++ b/src/luarocks/manif_core.lua
@@ -1,7 +1,6 @@
1 1
2--- Core functions for querying manifest files. 2--- Core functions for querying manifest files.
3-- This module requires no specific 'fs' functionality. 3-- This module requires no specific 'fs' functionality.
4--module("luarocks.manif_core", package.seeall)
5local manif_core = {} 4local manif_core = {}
6package.loaded["luarocks.manif_core"] = manif_core 5package.loaded["luarocks.manif_core"] = manif_core
7 6
diff --git a/src/luarocks/new_version.lua b/src/luarocks/new_version.lua
index 6969d4b2..bd73e308 100644
--- a/src/luarocks/new_version.lua
+++ b/src/luarocks/new_version.lua
@@ -10,14 +10,16 @@ local persist = require("luarocks.persist")
10local fs = require("luarocks.fs") 10local fs = require("luarocks.fs")
11local type_check = require("luarocks.type_check") 11local type_check = require("luarocks.type_check")
12 12
13util.add_run_function(new_version)
13new_version.help_summary = "Auto-write a rockspec for a new version of a rock." 14new_version.help_summary = "Auto-write a rockspec for a new version of a rock."
14new_version.help_arguments = "[--tag=<tag>] {<package>|<rockspec>} [<new_version>] [<new_url>]" 15new_version.help_arguments = "[--tag=<tag>] [<package>|<rockspec>] [<new_version>] [<new_url>]"
15new_version.help = [[ 16new_version.help = [[
16This is a utility function that writes a new rockspec, updating data 17This is a utility function that writes a new rockspec, updating data
17from a previous one. 18from a previous one.
18 19
19If a package name is given, it downloads the latest rockspec from the 20If a package name is given, it downloads the latest rockspec from the
20default server. If a rockspec is given, it uses it instead. 21default server. If a rockspec is given, it uses it instead. If no argument
22is given, it looks for a rockspec same way 'luarocks make' does.
21 23
22If the version number is not given and tag is passed using --tag, 24If the version number is not given and tag is passed using --tag,
23it is used as the version, with 'v' removed from beginning. 25it is used as the version, with 'v' removed from beginning.
@@ -122,15 +124,18 @@ local function update_source_section(out_rs, url, tag, old_ver, new_ver)
122 return true 124 return true
123end 125end
124 126
125function new_version.run(...) 127function new_version.command(flags, input, version, url)
126 local flags, input, version, url = util.parse_flags(...)
127 if not input then 128 if not input then
128 return nil, "Missing argument: expected package or rockspec. "..util.see_help("new_version") 129 local err
130 input, err = util.get_default_rockspec()
131 if not input then
132 return nil, err
133 end
129 end 134 end
130 assert(type(input) == "string") 135 assert(type(input) == "string")
131 136
132 local filename = input 137 local filename = input
133 if not input:match(".rockspec$") then 138 if not input:match("rockspec$") then
134 local err 139 local err
135 filename, err = download.download("rockspec", input) 140 filename, err = download.download("rockspec", input)
136 if not filename then 141 if not filename then
diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua
index c73d66ab..277cf246 100644
--- a/src/luarocks/pack.lua
+++ b/src/luarocks/pack.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "pack" command. 2--- Module implementing the LuaRocks "pack" command.
3-- Creates a rock, packing sources or binaries. 3-- Creates a rock, packing sources or binaries.
4--module("luarocks.pack", package.seeall)
5local pack = {} 4local pack = {}
6package.loaded["luarocks.pack"] = pack 5package.loaded["luarocks.pack"] = pack
7 6
@@ -17,6 +16,7 @@ local dir = require("luarocks.dir")
17local manif = require("luarocks.manif") 16local manif = require("luarocks.manif")
18local search = require("luarocks.search") 17local search = require("luarocks.search")
19 18
19util.add_run_function(pack)
20pack.help_summary = "Create a rock, packing sources or binaries." 20pack.help_summary = "Create a rock, packing sources or binaries."
21pack.help_arguments = "{<rockspec>|<name> [<version>]}" 21pack.help_arguments = "{<rockspec>|<name> [<version>]}"
22pack.help = [[ 22pack.help = [[
@@ -53,7 +53,7 @@ function pack.pack_source_rock(rockspec_file)
53 if not ok then return nil, err end 53 if not ok then return nil, err end
54 54
55 fs.delete(rock_file) 55 fs.delete(rock_file)
56 fs.copy(rockspec_file, source_dir) 56 fs.copy(rockspec_file, source_dir, cfg.perm_read)
57 if not fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) then 57 if not fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) then
58 return nil, "Failed packing "..rock_file 58 return nil, "Failed packing "..rock_file
59 end 59 end
@@ -62,7 +62,7 @@ function pack.pack_source_rock(rockspec_file)
62 return rock_file 62 return rock_file
63end 63end
64 64
65local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir) 65local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir, perms)
66 local ok, err = fs.make_dir(pack_dir) 66 local ok, err = fs.make_dir(pack_dir)
67 if not ok then return nil, err end 67 if not ok then return nil, err end
68 for file, sub in pairs(file_tree) do 68 for file, sub in pairs(file_tree) do
@@ -74,9 +74,9 @@ local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir)
74 else 74 else
75 local versioned = path.versioned_name(source, deploy_dir, name, version) 75 local versioned = path.versioned_name(source, deploy_dir, name, version)
76 if fs.exists(versioned) then 76 if fs.exists(versioned) then
77 fs.copy(versioned, target) 77 fs.copy(versioned, target, perms)
78 else 78 else
79 fs.copy(source, target) 79 fs.copy(source, target, perms)
80 end 80 end
81 end 81 end
82 end 82 end
@@ -135,12 +135,12 @@ local function do_pack_binary_rock(name, version)
135 135
136 local is_binary = false 136 local is_binary = false
137 if rock_manifest.lib then 137 if rock_manifest.lib then
138 local ok, err = copy_back_files(name, version, rock_manifest.lib, path.deploy_lib_dir(root), dir.path(temp_dir, "lib")) 138 local ok, err = copy_back_files(name, version, rock_manifest.lib, path.deploy_lib_dir(root), dir.path(temp_dir, "lib"), cfg.perm_exec)
139 if not ok then return nil, "Failed copying back files: " .. err end 139 if not ok then return nil, "Failed copying back files: " .. err end
140 is_binary = true 140 is_binary = true
141 end 141 end
142 if rock_manifest.lua then 142 if rock_manifest.lua then
143 local ok, err = copy_back_files(name, version, rock_manifest.lua, path.deploy_lua_dir(root), dir.path(temp_dir, "lua")) 143 local ok, err = copy_back_files(name, version, rock_manifest.lua, path.deploy_lua_dir(root), dir.path(temp_dir, "lua"), cfg.perm_read)
144 if not ok then return nil, "Failed copying back files: " .. err end 144 if not ok then return nil, "Failed copying back files: " .. err end
145 end 145 end
146 146
@@ -192,8 +192,7 @@ end
192-- version may also be passed. 192-- version may also be passed.
193-- @return boolean or (nil, string): true if successful or nil followed 193-- @return boolean or (nil, string): true if successful or nil followed
194-- by an error message. 194-- by an error message.
195function pack.run(...) 195function pack.command(flags, arg, version)
196 local flags, arg, version = util.parse_flags(...)
197 assert(type(version) == "string" or not version) 196 assert(type(version) == "string" or not version)
198 if type(arg) ~= "string" then 197 if type(arg) ~= "string" then
199 return nil, "Argument missing. "..util.see_help("pack") 198 return nil, "Argument missing. "..util.see_help("pack")
diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua
index 37ff846a..6219d8c6 100644
--- a/src/luarocks/path.lua
+++ b/src/luarocks/path.lua
@@ -2,7 +2,6 @@
2--- LuaRocks-specific path handling functions. 2--- LuaRocks-specific path handling functions.
3-- All paths are configured in this module, making it a single 3-- All paths are configured in this module, making it a single
4-- point where the layout of the local installation is defined in LuaRocks. 4-- point where the layout of the local installation is defined in LuaRocks.
5--module("luarocks.path", package.seeall)
6local path = {} 5local path = {}
7 6
8local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
diff --git a/src/luarocks/path_cmd.lua b/src/luarocks/path_cmd.lua
index ecd6d4b1..15fb9ca2 100644
--- a/src/luarocks/path_cmd.lua
+++ b/src/luarocks/path_cmd.lua
@@ -7,6 +7,7 @@ local util = require("luarocks.util")
7local deps = require("luarocks.deps") 7local deps = require("luarocks.deps")
8local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.cfg")
9 9
10util.add_run_function(path_cmd)
10path_cmd.help_summary = "Return the currently configured package path." 11path_cmd.help_summary = "Return the currently configured package path."
11path_cmd.help_arguments = "" 12path_cmd.help_arguments = ""
12path_cmd.help = [[ 13path_cmd.help = [[
@@ -33,8 +34,7 @@ And on Windows:
33 34
34--- Driver function for "path" command. 35--- Driver function for "path" command.
35-- @return boolean This function always succeeds. 36-- @return boolean This function always succeeds.
36function path_cmd.run(...) 37function path_cmd.command(flags)
37 local flags = util.parse_flags(...)
38 local deps_mode = deps.get_deps_mode(flags) 38 local deps_mode = deps.get_deps_mode(flags)
39 39
40 local lr_path, lr_cpath, lr_bin = cfg.package_paths(flags["tree"]) 40 local lr_path, lr_cpath, lr_bin = cfg.package_paths(flags["tree"])
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua
index 354b17c3..c2adb570 100644
--- a/src/luarocks/persist.lua
+++ b/src/luarocks/persist.lua
@@ -3,7 +3,6 @@
3-- saving tables into files. 3-- saving tables into files.
4-- Implemented separately to avoid interdependencies, 4-- Implemented separately to avoid interdependencies,
5-- as it is used in the bootstrapping stage of the cfg module. 5-- as it is used in the bootstrapping stage of the cfg module.
6--module("luarocks.persist", package.seeall)
7local persist = {} 6local persist = {}
8package.loaded["luarocks.persist"] = persist 7package.loaded["luarocks.persist"] = persist
9 8
@@ -147,7 +146,7 @@ write_table = function(out, tbl, level, field_order)
147 end 146 end
148 147
149 write_value(out, v, level, sub_order) 148 write_value(out, v, level, sub_order)
150 if type(k) == "number" then 149 if type(v) == "number" then
151 sep = ", " 150 sep = ", "
152 indent = false 151 indent = false
153 else 152 else
diff --git a/src/luarocks/purge.lua b/src/luarocks/purge.lua
index ba9b8705..1ce46c0f 100644
--- a/src/luarocks/purge.lua
+++ b/src/luarocks/purge.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "purge" command. 2--- Module implementing the LuaRocks "purge" command.
3-- Remove all rocks from a given tree. 3-- Remove all rocks from a given tree.
4--module("luarocks.purge", package.seeall)
5local purge = {} 4local purge = {}
6package.loaded["luarocks.purge"] = purge 5package.loaded["luarocks.purge"] = purge
7 6
@@ -15,6 +14,7 @@ local manif = require("luarocks.manif")
15local cfg = require("luarocks.cfg") 14local cfg = require("luarocks.cfg")
16local remove = require("luarocks.remove") 15local remove = require("luarocks.remove")
17 16
17util.add_run_function(purge)
18purge.help_summary = "Remove all installed rocks from a tree." 18purge.help_summary = "Remove all installed rocks from a tree."
19purge.help_arguments = "--tree=<tree> [--old-versions]" 19purge.help_arguments = "--tree=<tree> [--old-versions]"
20purge.help = [[ 20purge.help = [[
@@ -31,9 +31,7 @@ assume a default tree.
31 overridden with the flag --force. 31 overridden with the flag --force.
32]] 32]]
33 33
34function purge.run(...) 34function purge.command(flags)
35 local flags = util.parse_flags(...)
36
37 local tree = flags["tree"] 35 local tree = flags["tree"]
38 36
39 if type(tree) ~= "string" then 37 if type(tree) ~= "string" then
@@ -61,7 +59,7 @@ function purge.run(...)
61 for version, repositories in util.sortedpairs(versions, sort) do 59 for version, repositories in util.sortedpairs(versions, sort) do
62 if flags["old-versions"] then 60 if flags["old-versions"] then
63 util.printout("Keeping "..package.." "..version.."...") 61 util.printout("Keeping "..package.." "..version.."...")
64 local ok, err = remove.remove_other_versions(package, version, flags["force"]) 62 local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"])
65 if not ok then 63 if not ok then
66 util.printerr(err) 64 util.printerr(err)
67 end 65 end
diff --git a/src/luarocks/refresh_cache.lua b/src/luarocks/refresh_cache.lua
index 193e5994..bbfd1f4d 100644
--- a/src/luarocks/refresh_cache.lua
+++ b/src/luarocks/refresh_cache.lua
@@ -1,6 +1,5 @@
1 1
2--- Module implementing the luarocks-admin "refresh_cache" command. 2--- Module implementing the luarocks-admin "refresh_cache" command.
3--module("luarocks.refresh_cache", package.seeall)
4local refresh_cache = {} 3local refresh_cache = {}
5package.loaded["luarocks.refresh_cache"] = refresh_cache 4package.loaded["luarocks.refresh_cache"] = refresh_cache
6 5
@@ -8,6 +7,7 @@ local util = require("luarocks.util")
8local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.cfg")
9local cache = require("luarocks.cache") 8local cache = require("luarocks.cache")
10 9
10util.add_run_function(refresh_cache)
11refresh_cache.help_summary = "Refresh local cache of a remote rocks server." 11refresh_cache.help_summary = "Refresh local cache of a remote rocks server."
12refresh_cache.help_arguments = "[--from=<server>]" 12refresh_cache.help_arguments = "[--from=<server>]"
13refresh_cache.help = [[ 13refresh_cache.help = [[
@@ -16,8 +16,7 @@ If not given, the default server set in the upload_server variable
16from the configuration file is used instead. 16from the configuration file is used instead.
17]] 17]]
18 18
19function refresh_cache.run(...) 19function refresh_cache.command(flags)
20 local flags = util.parse_flags(...)
21 local server, upload_server = cache.get_upload_server(flags["server"]) 20 local server, upload_server = cache.get_upload_server(flags["server"])
22 if not server then return nil, upload_server end 21 if not server then return nil, upload_server end
23 local download_url = cache.get_server_urls(server, upload_server) 22 local download_url = cache.get_server_urls(server, upload_server)
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua
index 5d419817..d72fabaf 100644
--- a/src/luarocks/remove.lua
+++ b/src/luarocks/remove.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "remove" command. 2--- Module implementing the LuaRocks "remove" command.
3-- Uninstalls rocks. 3-- Uninstalls rocks.
4--module("luarocks.remove", package.seeall)
5local remove = {} 4local remove = {}
6package.loaded["luarocks.remove"] = remove 5package.loaded["luarocks.remove"] = remove
7 6
@@ -15,15 +14,16 @@ local cfg = require("luarocks.cfg")
15local manif = require("luarocks.manif") 14local manif = require("luarocks.manif")
16local fs = require("luarocks.fs") 15local fs = require("luarocks.fs")
17 16
17util.add_run_function(remove)
18remove.help_summary = "Uninstall a rock." 18remove.help_summary = "Uninstall a rock."
19remove.help_arguments = "[--force[=fast]] <name> [<version>]" 19remove.help_arguments = "[--force|--force-fast] <name> [<version>]"
20remove.help = [[ 20remove.help = [[
21Argument is the name of a rock to be uninstalled. 21Argument is the name of a rock to be uninstalled.
22If a version is not given, try to remove all versions at once. 22If a version is not given, try to remove all versions at once.
23Will only perform the removal if it does not break dependencies. 23Will only perform the removal if it does not break dependencies.
24To override this check and force the removal, use --force. 24To override this check and force the removal, use --force.
25To perform a forced removal without reporting dependency issues, 25To perform a forced removal without reporting dependency issues,
26use --force=fast. 26use --force-fast.
27 27
28]]..util.deps_mode_help() 28]]..util.deps_mode_help()
29 29
@@ -74,22 +74,22 @@ local function delete_versions(name, versions)
74 return true 74 return true
75end 75end
76 76
77function remove.remove_search_results(results, name, deps_mode, force) 77function remove.remove_search_results(results, name, deps_mode, force, fast)
78 local versions = results[name] 78 local versions = results[name]
79 79
80 local version = next(versions) 80 local version = next(versions)
81 local second = next(versions, version) 81 local second = next(versions, version)
82 82
83 local dependents = {} 83 local dependents = {}
84 if force ~= "fast" then 84 if not fast then
85 util.printout("Checking stability of dependencies on the absence of") 85 util.printout("Checking stability of dependencies in the absence of")
86 util.printout(name.." "..table.concat(util.keys(versions), ", ").."...") 86 util.printout(name.." "..table.concat(util.keys(versions), ", ").."...")
87 util.printout() 87 util.printout()
88 dependents = check_dependents(name, versions, deps_mode) 88 dependents = check_dependents(name, versions, deps_mode)
89 end 89 end
90 90
91 if #dependents > 0 then 91 if #dependents > 0 then
92 if force then 92 if force or fast then
93 util.printerr("The following packages may be broken by this forced removal:") 93 util.printerr("The following packages may be broken by this forced removal:")
94 for _, dependent in ipairs(dependents) do 94 for _, dependent in ipairs(dependents) do
95 util.printerr(dependent.name.." "..dependent.version) 95 util.printerr(dependent.name.." "..dependent.version)
@@ -121,11 +121,11 @@ function remove.remove_search_results(results, name, deps_mode, force)
121 return true 121 return true
122end 122end
123 123
124function remove.remove_other_versions(name, version, force) 124function remove.remove_other_versions(name, version, force, fast)
125 local results = {} 125 local results = {}
126 search.manifest_search(results, cfg.rocks_dir, { name = name, exact_name = true, constraints = {{ op = "~=", version = version}} }) 126 search.manifest_search(results, cfg.rocks_dir, { name = name, exact_name = true, constraints = {{ op = "~=", version = version}} })
127 if results[name] then 127 if results[name] then
128 return remove.remove_search_results(results, name, cfg.deps_mode, force) 128 return remove.remove_search_results(results, name, cfg.deps_mode, force, fast)
129 end 129 end
130 return true 130 return true
131end 131end
@@ -137,11 +137,9 @@ end
137-- may also be given. 137-- may also be given.
138-- @return boolean or (nil, string, exitcode): True if removal was 138-- @return boolean or (nil, string, exitcode): True if removal was
139-- successful, nil and an error message otherwise. exitcode is optionally returned. 139-- successful, nil and an error message otherwise. exitcode is optionally returned.
140function remove.run(...) 140function remove.command(flags, name, version)
141 local flags, name, version = util.parse_flags(...)
142
143 if type(name) ~= "string" then 141 if type(name) ~= "string" then
144 return nil, "Argument missing, see help." 142 return nil, "Argument missing. "..util.see_help("remove")
145 end 143 end
146 144
147 local deps_mode = flags["deps-mode"] or cfg.deps_mode 145 local deps_mode = flags["deps-mode"] or cfg.deps_mode
@@ -162,7 +160,7 @@ function remove.run(...)
162 return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir) 160 return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir)
163 end 161 end
164 162
165 return remove.remove_search_results(results, name, deps_mode, flags["force"]) 163 return remove.remove_search_results(results, name, deps_mode, flags["force"], flags["force-fast"])
166end 164end
167 165
168return remove 166return remove
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
index 17456593..86126a13 100644
--- a/src/luarocks/repos.lua
+++ b/src/luarocks/repos.lua
@@ -1,6 +1,5 @@
1 1
2--- Functions for managing the repository on disk. 2--- Functions for managing the repository on disk.
3--module("luarocks.repos", package.seeall)
4local repos = {} 3local repos = {}
5package.loaded["luarocks.repos"] = repos 4package.loaded["luarocks.repos"] = repos
6 5
@@ -157,11 +156,10 @@ local function install_binary(source, target, name, version)
157 assert(type(target) == "string") 156 assert(type(target) == "string")
158 157
159 if fs.is_lua(source) then 158 if fs.is_lua(source) then
160 repos.ok, repos.err = fs.wrap_script(source, target, name, version) 159 return fs.wrap_script(source, target, name, version)
161 else 160 else
162 repos.ok, repos.err = fs.copy_binary(source, target) 161 return fs.copy_binary(source, target)
163 end 162 end
164 return repos.ok, repos.err
165end 163end
166 164
167local function resolve_conflict(target, deploy_dir, name, version) 165local function resolve_conflict(target, deploy_dir, name, version)
@@ -199,9 +197,6 @@ function repos.deploy_files(name, version, wrap_bin_scripts)
199 197
200 local function deploy_file_tree(file_tree, path_fn, deploy_dir, move_fn) 198 local function deploy_file_tree(file_tree, path_fn, deploy_dir, move_fn)
201 local source_dir = path_fn(name, version) 199 local source_dir = path_fn(name, version)
202 if not move_fn then
203 move_fn = fs.move
204 end
205 return recurse_rock_manifest_tree(file_tree, 200 return recurse_rock_manifest_tree(file_tree,
206 function(parent_path, parent_module, file) 201 function(parent_path, parent_module, file)
207 local source = dir.path(source_dir, parent_path, file) 202 local source = dir.path(source_dir, parent_path, file)
@@ -239,11 +234,16 @@ function repos.deploy_files(name, version, wrap_bin_scripts)
239 local move_bin_fn = wrap_bin_scripts and install_binary or fs.copy_binary 234 local move_bin_fn = wrap_bin_scripts and install_binary or fs.copy_binary
240 ok, err = deploy_file_tree(rock_manifest.bin, path.bin_dir, cfg.deploy_bin_dir, move_bin_fn) 235 ok, err = deploy_file_tree(rock_manifest.bin, path.bin_dir, cfg.deploy_bin_dir, move_bin_fn)
241 end 236 end
237 local function make_mover(perms)
238 return function (src, dest)
239 return fs.move(src, dest, perms)
240 end
241 end
242 if ok and rock_manifest.lua then 242 if ok and rock_manifest.lua then
243 ok, err = deploy_file_tree(rock_manifest.lua, path.lua_dir, cfg.deploy_lua_dir) 243 ok, err = deploy_file_tree(rock_manifest.lua, path.lua_dir, cfg.deploy_lua_dir, make_mover(cfg.perm_read))
244 end 244 end
245 if ok and rock_manifest.lib then 245 if ok and rock_manifest.lib then
246 ok, err = deploy_file_tree(rock_manifest.lib, path.lib_dir, cfg.deploy_lib_dir) 246 ok, err = deploy_file_tree(rock_manifest.lib, path.lib_dir, cfg.deploy_lib_dir, make_mover(cfg.perm_exec))
247 end 247 end
248 return ok, err 248 return ok, err
249end 249end
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
index 6c0020c0..eaa321d5 100644
--- a/src/luarocks/search.lua
+++ b/src/luarocks/search.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "search" command. 2--- Module implementing the LuaRocks "search" command.
3-- Queries LuaRocks servers. 3-- Queries LuaRocks servers.
4--module("luarocks.search", package.seeall)
5local search = {} 4local search = {}
6package.loaded["luarocks.search"] = search 5package.loaded["luarocks.search"] = search
7 6
@@ -12,6 +11,7 @@ local deps = require("luarocks.deps")
12local cfg = require("luarocks.cfg") 11local cfg = require("luarocks.cfg")
13local util = require("luarocks.util") 12local util = require("luarocks.util")
14 13
14util.add_run_function(search)
15search.help_summary = "Query the LuaRocks servers." 15search.help_summary = "Query the LuaRocks servers."
16search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }" 16search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }"
17search.help = [[ 17search.help = [[
@@ -421,9 +421,7 @@ end
421-- @param version string or nil: a version may also be passed. 421-- @param version string or nil: a version may also be passed.
422-- @return boolean or (nil, string): True if build was successful; nil and an 422-- @return boolean or (nil, string): True if build was successful; nil and an
423-- error message otherwise. 423-- error message otherwise.
424function search.run(...) 424function search.command(flags, name, version)
425 local flags, name, version = util.parse_flags(...)
426
427 if flags["all"] then 425 if flags["all"] then
428 name, version = "", nil 426 name, version = "", nil
429 end 427 end
diff --git a/src/luarocks/show.lua b/src/luarocks/show.lua
index ae41a513..01860e78 100644
--- a/src/luarocks/show.lua
+++ b/src/luarocks/show.lua
@@ -1,6 +1,5 @@
1--- Module implementing the LuaRocks "show" command. 1--- Module implementing the LuaRocks "show" command.
2-- Shows information about an installed rock. 2-- Shows information about an installed rock.
3--module("luarocks.show", package.seeall)
4local show = {} 3local show = {}
5package.loaded["luarocks.show"] = show 4package.loaded["luarocks.show"] = show
6 5
@@ -11,6 +10,8 @@ local path = require("luarocks.path")
11local deps = require("luarocks.deps") 10local deps = require("luarocks.deps")
12local fetch = require("luarocks.fetch") 11local fetch = require("luarocks.fetch")
13local manif = require("luarocks.manif") 12local manif = require("luarocks.manif")
13
14util.add_run_function(show)
14show.help_summary = "Show information about an installed rock." 15show.help_summary = "Show information about an installed rock."
15 16
16show.help = [[ 17show.help = [[
@@ -104,8 +105,7 @@ end
104-- @param name or nil: an existing package name. 105-- @param name or nil: an existing package name.
105-- @param version string or nil: a version may also be passed. 106-- @param version string or nil: a version may also be passed.
106-- @return boolean: True if succeeded, nil on errors. 107-- @return boolean: True if succeeded, nil on errors.
107function show.run(...) 108function show.command(flags, name, version)
108 local flags, name, version = util.parse_flags(...)
109 if not name then 109 if not name then
110 return nil, "Argument missing. "..util.see_help("show") 110 return nil, "Argument missing. "..util.see_help("show")
111 end 111 end
diff --git a/src/luarocks/tools/patch.lua b/src/luarocks/tools/patch.lua
index debaf636..44d00ef8 100644
--- a/src/luarocks/tools/patch.lua
+++ b/src/luarocks/tools/patch.lua
@@ -8,7 +8,6 @@
8-- Project home: http://code.google.com/p/python-patch/ . 8-- Project home: http://code.google.com/p/python-patch/ .
9-- Version 0.1 9-- Version 0.1
10 10
11--module("luarocks.tools.patch", package.seeall)
12local patch = {} 11local patch = {}
13 12
14local fs = require("luarocks.fs") 13local fs = require("luarocks.fs")
diff --git a/src/luarocks/tools/tar.lua b/src/luarocks/tools/tar.lua
index cedcceee..ae5c83e2 100644
--- a/src/luarocks/tools/tar.lua
+++ b/src/luarocks/tools/tar.lua
@@ -1,6 +1,5 @@
1 1
2--- A pure-Lua implementation of untar (unpacking .tar archives) 2--- A pure-Lua implementation of untar (unpacking .tar archives)
3--module("luarocks.tools.tar", package.seeall)
4local tar = {} 3local tar = {}
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua
index 83091a29..287d8151 100644
--- a/src/luarocks/type_check.lua
+++ b/src/luarocks/type_check.lua
@@ -1,7 +1,6 @@
1--- Type-checking functions. 1--- Type-checking functions.
2-- Functions and definitions for doing a basic lint check on files 2-- Functions and definitions for doing a basic lint check on files
3-- loaded by LuaRocks. 3-- loaded by LuaRocks.
4--module("luarocks.type_check", package.seeall)
5local type_check = {} 4local type_check = {}
6package.loaded["luarocks.type_check"] = type_check 5package.loaded["luarocks.type_check"] = type_check
7 6
diff --git a/src/luarocks/unpack.lua b/src/luarocks/unpack.lua
index a889bac5..2face005 100644
--- a/src/luarocks/unpack.lua
+++ b/src/luarocks/unpack.lua
@@ -1,7 +1,6 @@
1 1
2--- Module implementing the LuaRocks "unpack" command. 2--- Module implementing the LuaRocks "unpack" command.
3-- Unpack the contents of a rock. 3-- Unpack the contents of a rock.
4--module("luarocks.unpack", package.seeall)
5local unpack = {} 4local unpack = {}
6package.loaded["luarocks.unpack"] = unpack 5package.loaded["luarocks.unpack"] = unpack
7 6
@@ -10,7 +9,9 @@ local fs = require("luarocks.fs")
10local util = require("luarocks.util") 9local util = require("luarocks.util")
11local build = require("luarocks.build") 10local build = require("luarocks.build")
12local dir = require("luarocks.dir") 11local dir = require("luarocks.dir")
12local cfg = require("luarocks.cfg")
13 13
14util.add_run_function(unpack)
14unpack.help_summary = "Unpack the contents of a rock." 15unpack.help_summary = "Unpack the contents of a rock."
15unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}" 16unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}"
16unpack.help = [[ 17unpack.help = [[
@@ -128,7 +129,7 @@ local function run_unpacker(file, force)
128 end 129 end
129 if kind == "src" or kind == "rockspec" then 130 if kind == "src" or kind == "rockspec" then
130 if rockspec.source.dir ~= "." then 131 if rockspec.source.dir ~= "." then
131 local ok = fs.copy(rockspec.local_filename, rockspec.source.dir) 132 local ok = fs.copy(rockspec.local_filename, rockspec.source.dir, cfg.perm_read)
132 if not ok then 133 if not ok then
133 return nil, "Failed copying unpacked rockspec into unpacked source directory." 134 return nil, "Failed copying unpacked rockspec into unpacked source directory."
134 end 135 end
@@ -149,9 +150,7 @@ end
149-- version may also be passed. 150-- version may also be passed.
150-- @return boolean or (nil, string): true if successful or nil followed 151-- @return boolean or (nil, string): true if successful or nil followed
151-- by an error message. 152-- by an error message.
152function unpack.run(...) 153function unpack.command(flags, name, version)
153 local flags, name, version = util.parse_flags(...)
154
155 assert(type(version) == "string" or not version) 154 assert(type(version) == "string" or not version)
156 if type(name) ~= "string" then 155 if type(name) ~= "string" then
157 return nil, "Argument missing. "..util.see_help("unpack") 156 return nil, "Argument missing. "..util.see_help("unpack")
diff --git a/src/luarocks/upload.lua b/src/luarocks/upload.lua
index 19ddee8d..3adc1704 100644
--- a/src/luarocks/upload.lua
+++ b/src/luarocks/upload.lua
@@ -7,6 +7,7 @@ local pack = require("luarocks.pack")
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.cfg")
8local Api = require("luarocks.upload.api") 8local Api = require("luarocks.upload.api")
9 9
10util.add_run_function(upload)
10upload.help_summary = "Upload a rockspec to the public rocks repository." 11upload.help_summary = "Upload a rockspec to the public rocks repository."
11upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>" 12upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>"
12upload.help = [[ 13upload.help = [[
@@ -20,8 +21,7 @@ upload.help = [[
20 increment the revision number instead. 21 increment the revision number instead.
21]] 22]]
22 23
23function upload.run(...) 24function upload.command(flags, fname)
24 local flags, fname = util.parse_flags(...)
25 if not fname then 25 if not fname then
26 return nil, "Missing rockspec. "..util.see_help("upload") 26 return nil, "Missing rockspec. "..util.see_help("upload")
27 end 27 end
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
index fc45c9f4..4aa474ff 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -4,7 +4,6 @@
4-- inside specific functions) to avoid interdependencies, 4-- inside specific functions) to avoid interdependencies,
5-- as this is used in the bootstrapping stage of luarocks.cfg. 5-- as this is used in the bootstrapping stage of luarocks.cfg.
6 6
7--module("luarocks.util", package.seeall)
8local util = {} 7local util = {}
9 8
10local unpack = unpack or table.unpack 9local unpack = unpack or table.unpack
@@ -96,6 +95,7 @@ local supported_flags = {
96 ["deps-mode"] = "<mode>", 95 ["deps-mode"] = "<mode>",
97 ["detailed"] = "\"<text>\"", 96 ["detailed"] = "\"<text>\"",
98 ["force"] = true, 97 ["force"] = true,
98 ["force-fast"] = true,
99 ["from"] = "<server>", 99 ["from"] = "<server>",
100 ["help"] = true, 100 ["help"] = true,
101 ["home"] = true, 101 ["home"] = true,
@@ -210,36 +210,11 @@ function util.parse_flags(...)
210 return flags, unpack(out) 210 return flags, unpack(out)
211end 211end
212 212
213--- Build a sequence of flags for forwarding from one command to 213-- Adds legacy 'run' function to a command module.
214-- another (for example, from "install" to "build"). 214-- @param command table: command module with 'command' function,
215-- @param flags table: A table of parsed flags 215-- the added 'run' function calls it after parseing command-line arguments.
216-- @param ... string...: A variable number of flags to be checked 216function util.add_run_function(command)
217-- in the flags table. If no flags are passed as varargs, the 217 command.run = function(...) return command.command(util.parse_flags(...)) end
218-- entire flags table is forwarded.
219-- @return string... A variable number of strings
220function util.forward_flags(flags, ...)
221 assert(type(flags) == "table")
222 local out = {}
223 local filter = select('#', ...)
224 local function add_flag(flagname)
225 if flags[flagname] then
226 if flags[flagname] == true then
227 table.insert(out, "--"..flagname)
228 else
229 table.insert(out, "--"..flagname.."="..flags[flagname])
230 end
231 end
232 end
233 if filter > 0 then
234 for i = 1, filter do
235 add_flag(select(i, ...))
236 end
237 else
238 for flagname, _ in pairs(flags) do
239 add_flag(flagname)
240 end
241 end
242 return unpack(out)
243end 218end
244 219
245--- Merges contents of src on top of dst's contents. 220--- Merges contents of src on top of dst's contents.
@@ -519,6 +494,85 @@ function util.see_help(command, program)
519 return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." 494 return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'."
520end 495end
521 496
497function util.announce_install(rockspec)
498 local cfg = require("luarocks.cfg")
499 local path = require("luarocks.path")
500
501 local suffix = ""
502 if rockspec.description and rockspec.description.license then
503 suffix = " (license: "..rockspec.description.license..")"
504 end
505
506 local root_dir = path.root_dir(cfg.rocks_dir)
507 util.printout(rockspec.name.." "..rockspec.version.." is now installed in "..root_dir..suffix)
508 util.printout()
509end
510
511--- Collect rockspecs located in a subdirectory.
512-- @param versions table: A table mapping rock names to newest rockspec versions.
513-- @param paths table: A table mapping rock names to newest rockspec paths.
514-- @param unnamed_paths table: An array of rockspec paths that don't contain rock
515-- name and version in regular format.
516-- @param subdir string: path to subdirectory.
517local function collect_rockspecs(versions, paths, unnamed_paths, subdir)
518 local fs = require("luarocks.fs")
519 local dir = require("luarocks.dir")
520 local path = require("luarocks.path")
521 local deps = require("luarocks.deps")
522
523 if fs.is_dir(subdir) then
524 for file in fs.dir(subdir) do
525 file = dir.path(subdir, file)
526
527 if file:match("rockspec$") and fs.is_file(file) then
528 local rock, version = path.parse_name(file)
529
530 if rock then
531 if not versions[rock] or deps.compare_versions(version, versions[rock]) then
532 versions[rock] = version
533 paths[rock] = file
534 end
535 else
536 table.insert(unnamed_paths, file)
537 end
538 end
539 end
540 end
541end
542
543--- Get default rockspec name for commands that take optional rockspec name.
544-- @return string or (nil, string): path to the rockspec or nil and error message.
545function util.get_default_rockspec()
546 local versions, paths, unnamed_paths = {}, {}, {}
547 -- Look for rockspecs in some common locations.
548 collect_rockspecs(versions, paths, unnamed_paths, ".")
549 collect_rockspecs(versions, paths, unnamed_paths, "rockspec")
550 collect_rockspecs(versions, paths, unnamed_paths, "rockspecs")
551
552 if #unnamed_paths > 0 then
553 -- There are rockspecs not following "name-version.rockspec" format.
554 -- More than one are ambiguous.
555 if #unnamed_paths > 1 then
556 return nil, "Please specify which rockspec file to use."
557 else
558 return unnamed_paths[1]
559 end
560 else
561 local rock = next(versions)
562
563 if rock then
564 -- If there are rockspecs for multiple rocks it's ambiguous.
565 if next(versions, rock) then
566 return nil, "Please specify which rockspec file to use."
567 else
568 return paths[rock]
569 end
570 else
571 return nil, "Argument missing: please specify a rockspec to use on current directory."
572 end
573 end
574end
575
522-- from http://lua-users.org/wiki/SplitJoin 576-- from http://lua-users.org/wiki/SplitJoin
523-- by PhilippeLhoste 577-- by PhilippeLhoste
524function util.split_string(str, delim, maxNb) 578function util.split_string(str, delim, maxNb)
diff --git a/src/luarocks/validate.lua b/src/luarocks/validate.lua
index e6e09c33..c4570aa4 100644
--- a/src/luarocks/validate.lua
+++ b/src/luarocks/validate.lua
@@ -1,6 +1,5 @@
1 1
2--- Sandboxed test of build/install of all packages in a repository (unfinished and disabled). 2--- Sandboxed test of build/install of all packages in a repository (unfinished and disabled).
3--module("luarocks.validate", package.seeall)
4local validate = {} 3local validate = {}
5package.loaded["luarocks.validate"] = validate 4package.loaded["luarocks.validate"] = validate
6 5
@@ -12,6 +11,7 @@ local build = require("luarocks.build")
12local install = require("luarocks.install") 11local install = require("luarocks.install")
13local util = require("luarocks.util") 12local util = require("luarocks.util")
14 13
14util.add_run_function(validate)
15validate.help_summary = "Sandboxed test of build/install of all packages in a repository." 15validate.help_summary = "Sandboxed test of build/install of all packages in a repository."
16 16
17validate.help = [[ 17validate.help = [[
@@ -75,8 +75,7 @@ local function validate_rock(file)
75 return ok, err, errcode 75 return ok, err, errcode
76end 76end
77 77
78function validate.run(...) 78function validate.command(flags, repo)
79 local flags, repo = util.parse_flags(...)
80 repo = repo or cfg.rocks_dir 79 repo = repo or cfg.rocks_dir
81 80
82 util.printout("Verifying contents of "..repo) 81 util.printout("Verifying contents of "..repo)
diff --git a/src/luarocks/write_rockspec.lua b/src/luarocks/write_rockspec.lua
index 972562c3..33edeb1b 100644
--- a/src/luarocks/write_rockspec.lua
+++ b/src/luarocks/write_rockspec.lua
@@ -1,8 +1,8 @@
1 1
2--module("luarocks.write_rockspec", package.seeall)
3local write_rockspec = {} 2local write_rockspec = {}
4package.loaded["luarocks.write_rockspec"] = write_rockspec 3package.loaded["luarocks.write_rockspec"] = write_rockspec
5 4
5local cfg = require("luarocks.cfg")
6local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
7local fetch = require("luarocks.fetch") 7local fetch = require("luarocks.fetch")
8local fs = require("luarocks.fs") 8local fs = require("luarocks.fs")
@@ -11,15 +11,18 @@ local persist = require("luarocks.persist")
11local type_check = require("luarocks.type_check") 11local type_check = require("luarocks.type_check")
12local util = require("luarocks.util") 12local util = require("luarocks.util")
13 13
14util.add_run_function(write_rockspec)
14write_rockspec.help_summary = "Write a template for a rockspec file." 15write_rockspec.help_summary = "Write a template for a rockspec file."
15write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] {<url>|<path>}" 16write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]"
16write_rockspec.help = [[ 17write_rockspec.help = [[
17This command writes an initial version of a rockspec file, 18This command writes an initial version of a rockspec file,
18based on an URL or a local path. You may use a relative path such as '.'. 19based on a name, a version, and a location (an URL or a local path).
19If a local path is given, name and version arguments are mandatory. 20If only two arguments are given, the first one is considered the name and the
20For URLs, LuaRocks will attempt to infer name and version if not given. 21second one is the location.
21 22If only one argument is given, it must be the location.
22If a repository URL is given with no version, it creates an 'scm' rock. 23If no arguments are given, current directory is used as location.
24LuaRocks will attempt to infer name and version if not given,
25using 'scm' as default version.
23 26
24Note that the generated file is a _starting point_ for writing a 27Note that the generated file is a _starting point_ for writing a
25rockspec, and is not guaranteed to be complete or correct. 28rockspec, and is not guaranteed to be complete or correct.
@@ -109,6 +112,32 @@ local function detect_mit_license(data)
109 return sum == 78656 112 return sum == 78656
110end 113end
111 114
115local simple_scm_protocols = {
116 git = true, ["git+http"] = true, ["git+https"] = true,
117 hg = true, ["hg+http"] = true, ["hg+https"] = true
118}
119
120local function detect_url_from_command(program, args, directory)
121 local command = fs.Q(cfg.variables[program:upper()]).. " "..args
122 local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command)))
123 if not pipe then return nil end
124 local url = pipe:read("*a"):match("^([^\r\n]+)")
125 pipe:close()
126 if not url then return nil end
127 if not util.starts_with(url, program.."://") then
128 url = program.."+"..url
129 end
130
131 if simple_scm_protocols[dir.split_url(url)] then
132 return url
133 end
134end
135
136local function detect_scm_url(directory)
137 return detect_url_from_command("git", "config --get remote.origin.url", directory) or
138 detect_url_from_command("hg", "paths default", directory)
139end
140
112local function show_license(rockspec) 141local function show_license(rockspec)
113 local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt") 142 local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt")
114 if not fd then return nil end 143 if not fd then return nil end
@@ -196,20 +225,17 @@ local function rockspec_cleanup(rockspec)
196 rockspec.name = nil 225 rockspec.name = nil
197end 226end
198 227
199function write_rockspec.run(...) 228function write_rockspec.command(flags, name, version, url_or_dir)
200 local flags, name, version, url_or_dir = util.parse_flags(...)
201
202 if not name then 229 if not name then
203 return nil, "Missing arguments. "..util.see_help("write_rockspec") 230 url_or_dir = "."
204 end 231 elseif not version then
205
206 if name and not version then
207 url_or_dir = name 232 url_or_dir = name
208 name = nil 233 name = nil
209 elseif not url_or_dir then 234 elseif not url_or_dir then
210 url_or_dir = version 235 url_or_dir = version
236 version = nil
211 end 237 end
212 238
213 if flags["tag"] then 239 if flags["tag"] then
214 if not version then 240 if not version then
215 version = flags["tag"]:gsub("^v", "") 241 version = flags["tag"]:gsub("^v", "")
@@ -217,34 +243,27 @@ function write_rockspec.run(...)
217 end 243 end
218 244
219 local protocol, pathname = dir.split_url(url_or_dir) 245 local protocol, pathname = dir.split_url(url_or_dir)
220 if not fetch.is_basic_protocol(protocol) then 246 if protocol == "file" then
221 if not name then 247 if pathname == "." then
222 name = dir.base_name(url_or_dir):gsub("%.[^.]+$", "") 248 name = name or dir.base_name(fs.current_dir())
223 end 249 end
224 if not version then 250 elseif fetch.is_basic_protocol(protocol) then
225 version = "scm"
226 end
227 elseif protocol ~= "file" then
228 local filename = dir.base_name(url_or_dir) 251 local filename = dir.base_name(url_or_dir)
229 local newname, newversion = filename:match("(.*)-([^-]+)") 252 local newname, newversion = filename:match("(.*)-([^-]+)")
230 if (not name) and newname then 253 if newname then
231 name = newname 254 name = name or newname
232 end 255 version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "")
233 if (not version) and newversion then
234 version = newversion:gsub(".[a-z]+$", ""):gsub(".tar$", "")
235 end 256 end
236 if not (name and version) then 257 else
237 return nil, "Missing name and version arguments. "..util.see_help("write_rockspec") 258 name = name or dir.base_name(url_or_dir):gsub("%.[^.]+$", "")
238 end
239 elseif not version then
240 return nil, "Missing name and version arguments. "..util.see_help("write_rockspec")
241 end 259 end
242 260
243 local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") 261 if not name then
244 262 return nil, "Could not infer rock name. "..util.see_help("write_rockspec")
245 if not flags["homepage"] and url_or_dir:match("^git://github.com") then
246 flags["homepage"] = "http://"..url_or_dir:match("^[^:]+://(.*)")
247 end 263 end
264 version = version or "scm"
265
266 local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec")
248 267
249 local rockspec = { 268 local rockspec = {
250 rockspec_format = flags["rockspec-format"], 269 rockspec_format = flags["rockspec-format"],
@@ -292,11 +311,26 @@ function write_rockspec.run(...)
292 else 311 else
293 local_dir = nil 312 local_dir = nil
294 end 313 end
314 else
315 rockspec.source.url = detect_scm_url(local_dir) or rockspec.source.url
295 end 316 end
296 317
297 if not local_dir then 318 if not local_dir then
298 local_dir = "." 319 local_dir = "."
299 end 320 end
321
322 if not flags["homepage"] then
323 local url_protocol, url_path = dir.split_url(rockspec.source.url)
324
325 if simple_scm_protocols[url_protocol] then
326 for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do
327 if util.starts_with(url_path, domain) then
328 rockspec.description.homepage = "https://"..url_path:gsub("%.git$", "")
329 break
330 end
331 end
332 end
333 end
300 334
301 local libs = nil 335 local libs = nil
302 if flags["lib"] then 336 if flags["lib"] then