aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/bin/luarocks2
-rwxr-xr-xsrc/bin/luarocks-admin10
-rw-r--r--src/luarocks/admin/add.lua (renamed from src/luarocks/add.lua)21
-rw-r--r--src/luarocks/admin/cache.lua (renamed from src/luarocks/cache.lua)3
-rw-r--r--src/luarocks/admin/make_manifest.lua (renamed from src/luarocks/make_manifest.lua)8
-rw-r--r--src/luarocks/admin/refresh_cache.lua (renamed from src/luarocks/refresh_cache.lua)7
-rw-r--r--src/luarocks/admin/remove.lua (renamed from src/luarocks/admin_remove.lua)10
-rw-r--r--src/luarocks/build.lua40
-rw-r--r--src/luarocks/build/builtin.lua37
-rw-r--r--src/luarocks/build/cmake.lua23
-rw-r--r--src/luarocks/build/make.lua2
-rw-r--r--src/luarocks/command_line.lua2
-rw-r--r--src/luarocks/config_cmd.lua3
-rw-r--r--src/luarocks/core/cfg.lua (renamed from src/luarocks/cfg.lua)34
-rw-r--r--src/luarocks/core/deps.lua192
-rw-r--r--src/luarocks/core/dir.lua55
-rw-r--r--src/luarocks/core/manif.lua (renamed from src/luarocks/manif_core.lua)38
-rw-r--r--src/luarocks/core/path.lua151
-rw-r--r--src/luarocks/core/persist.lua81
-rw-r--r--src/luarocks/core/type_check.lua229
-rw-r--r--src/luarocks/core/util.lua272
-rw-r--r--src/luarocks/deps.lua242
-rw-r--r--src/luarocks/dir.lua49
-rw-r--r--src/luarocks/doc.lua2
-rw-r--r--src/luarocks/download.lua4
-rw-r--r--src/luarocks/fetch.lua40
-rw-r--r--src/luarocks/fetch/git.lua57
-rw-r--r--src/luarocks/fs.lua3
-rw-r--r--src/luarocks/fs/lua.lua2
-rw-r--r--src/luarocks/fs/tools.lua2
-rw-r--r--src/luarocks/fs/unix.lua2
-rw-r--r--src/luarocks/fs/unix/tools.lua2
-rw-r--r--src/luarocks/fs/win32.lua2
-rw-r--r--src/luarocks/fs/win32/tools.lua2
-rw-r--r--src/luarocks/help.lua3
-rw-r--r--src/luarocks/index.lua1
-rw-r--r--src/luarocks/install.lua10
-rw-r--r--src/luarocks/lint.lua2
-rw-r--r--src/luarocks/list.lua4
-rw-r--r--src/luarocks/loader.lua31
-rw-r--r--src/luarocks/make.lua8
-rw-r--r--src/luarocks/manif.lua448
-rw-r--r--src/luarocks/manif/writer.lua436
-rw-r--r--src/luarocks/new_version.lua1
-rw-r--r--src/luarocks/pack.lua10
-rw-r--r--src/luarocks/path.lua137
-rw-r--r--src/luarocks/path_cmd.lua3
-rw-r--r--src/luarocks/persist.lua75
-rw-r--r--src/luarocks/purge.lua10
-rw-r--r--src/luarocks/remove.lua8
-rw-r--r--src/luarocks/repos.lua26
-rw-r--r--src/luarocks/search.lua5
-rw-r--r--src/luarocks/show.lua12
-rw-r--r--src/luarocks/tools/tar.lua6
-rw-r--r--src/luarocks/type_check.lua232
-rw-r--r--src/luarocks/unpack.lua4
-rw-r--r--src/luarocks/upload.lua3
-rw-r--r--src/luarocks/upload/api.lua2
-rw-r--r--src/luarocks/util.lua267
-rw-r--r--src/luarocks/validate.lua159
-rw-r--r--src/luarocks/write_rockspec.lua7
61 files changed, 1814 insertions, 1725 deletions
diff --git a/src/bin/luarocks b/src/bin/luarocks
index be6c2b81..21f17da9 100755
--- a/src/bin/luarocks
+++ b/src/bin/luarocks
@@ -1,7 +1,7 @@
1#!/usr/bin/env lua 1#!/usr/bin/env lua
2 2
3-- this should be loaded first. 3-- this should be loaded first.
4local cfg = require("luarocks.cfg") 4local cfg = require("luarocks.core.cfg")
5 5
6local loader = require("luarocks.loader") 6local loader = require("luarocks.loader")
7local command_line = require("luarocks.command_line") 7local command_line = require("luarocks.command_line")
diff --git a/src/bin/luarocks-admin b/src/bin/luarocks-admin
index 2890d1f1..660c0a70 100755
--- a/src/bin/luarocks-admin
+++ b/src/bin/luarocks-admin
@@ -1,7 +1,7 @@
1#!/usr/bin/env lua 1#!/usr/bin/env lua
2 2
3-- this should be loaded first. 3-- this should be loaded first.
4local cfg = require("luarocks.cfg") 4local cfg = require("luarocks.core.cfg")
5 5
6local loader = require("luarocks.loader") 6local loader = require("luarocks.loader")
7local command_line = require("luarocks.command_line") 7local command_line = require("luarocks.command_line")
@@ -10,10 +10,10 @@ program_description = "LuaRocks repository administration interface"
10 10
11commands = { 11commands = {
12 help = "luarocks.help", 12 help = "luarocks.help",
13 make_manifest = "luarocks.make_manifest", 13 make_manifest = "luarocks.admin.make_manifest",
14 add = "luarocks.add", 14 add = "luarocks.admin.add",
15 remove = "luarocks.admin_remove", 15 remove = "luarocks.admin.remove",
16 refresh_cache = "luarocks.refresh_cache", 16 refresh_cache = "luarocks.admin.refresh_cache",
17} 17}
18 18
19command_line.run_command(...) 19command_line.run_command(...)
diff --git a/src/luarocks/add.lua b/src/luarocks/admin/add.lua
index f37d334d..daf46c1d 100644
--- a/src/luarocks/add.lua
+++ b/src/luarocks/admin/add.lua
@@ -2,17 +2,15 @@
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.
4local add = {} 4local add = {}
5package.loaded["luarocks.add"] = add
6 5
7local cfg = require("luarocks.cfg") 6local cfg = require("luarocks.core.cfg")
8local util = require("luarocks.util") 7local util = require("luarocks.util")
9local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
10local manif = require("luarocks.manif") 9local writer = require("luarocks.manif.writer")
11local index = require("luarocks.index") 10local index = require("luarocks.index")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local cache = require("luarocks.cache") 12local cache = require("luarocks.admin.cache")
14 13
15util.add_run_function(add)
16add.help_summary = "Add a rock or rockspec to a rocks server." 14add.help_summary = "Add a rock or rockspec to a rocks server."
17add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" 15add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
18add.help = [[ 16add.help = [[
@@ -24,6 +22,15 @@ The flag --no-refresh indicates the local cache should not be refreshed
24prior to generation of the updated manifest. 22prior to generation of the updated manifest.
25]] 23]]
26 24
25local function zip_manifests()
26 for ver in util.lua_versions() do
27 local file = "manifest-"..ver
28 local zip = file..".zip"
29 fs.delete(dir.path(fs.current_dir(), zip))
30 fs.zip(zip, file)
31 end
32end
33
27local function add_files_to_server(refresh, rockfiles, server, upload_server) 34local function add_files_to_server(refresh, rockfiles, server, upload_server)
28 assert(type(refresh) == "boolean" or not refresh) 35 assert(type(refresh) == "boolean" or not refresh)
29 assert(type(rockfiles) == "table") 36 assert(type(rockfiles) == "table")
@@ -68,9 +75,9 @@ local function add_files_to_server(refresh, rockfiles, server, upload_server)
68 if not ok then return nil, err end 75 if not ok then return nil, err end
69 76
70 util.printout("Updating manifest...") 77 util.printout("Updating manifest...")
71 manif.make_manifest(local_cache, "one", true) 78 writer.make_manifest(local_cache, "one", true)
72 79
73 manif.zip_manifests() 80 zip_manifests()
74 81
75 util.printout("Updating index.html...") 82 util.printout("Updating index.html...")
76 index.make_index(local_cache) 83 index.make_index(local_cache)
diff --git a/src/luarocks/cache.lua b/src/luarocks/admin/cache.lua
index 4a95f70e..0daa0fc0 100644
--- a/src/luarocks/cache.lua
+++ b/src/luarocks/admin/cache.lua
@@ -2,10 +2,9 @@
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.
4local cache = {} 4local cache = {}
5package.loaded["luarocks.cache"] = cache
6 5
7local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
8local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
9local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
10local util = require("luarocks.util") 9local util = require("luarocks.util")
11 10
diff --git a/src/luarocks/make_manifest.lua b/src/luarocks/admin/make_manifest.lua
index c39c2939..57851942 100644
--- a/src/luarocks/make_manifest.lua
+++ b/src/luarocks/admin/make_manifest.lua
@@ -2,17 +2,15 @@
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.
4local make_manifest = {} 4local make_manifest = {}
5package.loaded["luarocks.make_manifest"] = make_manifest
6 5
7local manif = require("luarocks.manif") 6local writer = require("luarocks.manif.writer")
8local index = require("luarocks.index") 7local index = require("luarocks.index")
9local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.core.cfg")
10local util = require("luarocks.util") 9local util = require("luarocks.util")
11local deps = require("luarocks.deps") 10local deps = require("luarocks.deps")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local dir = require("luarocks.dir") 12local dir = require("luarocks.dir")
14 13
15util.add_run_function(make_manifest)
16make_manifest.help_summary = "Compile a manifest file for a repository." 14make_manifest.help_summary = "Compile a manifest file for a repository."
17 15
18make_manifest.help = [[ 16make_manifest.help = [[
@@ -37,7 +35,7 @@ function make_manifest.command(flags, repo)
37 util.warning("This looks like a local rocks tree, but you did not pass --local-tree.") 35 util.warning("This looks like a local rocks tree, but you did not pass --local-tree.")
38 end 36 end
39 37
40 local ok, err = manif.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"]) 38 local ok, err = writer.make_manifest(repo, deps.get_deps_mode(flags), not flags["local-tree"])
41 if ok and not flags["local-tree"] then 39 if ok and not flags["local-tree"] then
42 util.printout("Generating index.html for "..repo) 40 util.printout("Generating index.html for "..repo)
43 index.make_index(repo) 41 index.make_index(repo)
diff --git a/src/luarocks/refresh_cache.lua b/src/luarocks/admin/refresh_cache.lua
index bbfd1f4d..947dbfb0 100644
--- a/src/luarocks/refresh_cache.lua
+++ b/src/luarocks/admin/refresh_cache.lua
@@ -1,13 +1,10 @@
1 1
2--- Module implementing the luarocks-admin "refresh_cache" command. 2--- Module implementing the luarocks-admin "refresh_cache" command.
3local refresh_cache = {} 3local refresh_cache = {}
4package.loaded["luarocks.refresh_cache"] = refresh_cache
5 4
6local util = require("luarocks.util") 5local cfg = require("luarocks.core.cfg")
7local cfg = require("luarocks.cfg") 6local cache = require("luarocks.admin.cache")
8local cache = require("luarocks.cache")
9 7
10util.add_run_function(refresh_cache)
11refresh_cache.help_summary = "Refresh local cache of a remote rocks server." 8refresh_cache.help_summary = "Refresh local cache of a remote rocks server."
12refresh_cache.help_arguments = "[--from=<server>]" 9refresh_cache.help_arguments = "[--from=<server>]"
13refresh_cache.help = [[ 10refresh_cache.help = [[
diff --git a/src/luarocks/admin_remove.lua b/src/luarocks/admin/remove.lua
index 621f1317..763a166f 100644
--- a/src/luarocks/admin_remove.lua
+++ b/src/luarocks/admin/remove.lua
@@ -2,17 +2,15 @@
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.
4local admin_remove = {} 4local admin_remove = {}
5package.loaded["luarocks.admin_remove"] = admin_remove
6 5
7local cfg = require("luarocks.cfg") 6local cfg = require("luarocks.core.cfg")
8local util = require("luarocks.util") 7local util = require("luarocks.util")
9local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
10local manif = require("luarocks.manif") 9local writer = require("luarocks.manif.writer")
11local index = require("luarocks.index") 10local index = require("luarocks.index")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local cache = require("luarocks.cache") 12local cache = require("luarocks.admin.cache")
14 13
15util.add_run_function(admin_remove)
16admin_remove.help_summary = "Remove a rock or rockspec from a rocks server." 14admin_remove.help_summary = "Remove a rock or rockspec from a rocks server."
17admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" 15admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
18admin_remove.help = [[ 16admin_remove.help = [[
@@ -65,7 +63,7 @@ local function remove_files_from_server(refresh, rockfiles, server, upload_serve
65 if not ok then return nil, err end 63 if not ok then return nil, err end
66 64
67 util.printout("Updating manifest...") 65 util.printout("Updating manifest...")
68 manif.make_manifest(local_cache, "one", true) 66 writer.make_manifest(local_cache, "one", true)
69 util.printout("Updating index.html...") 67 util.printout("Updating index.html...")
70 index.make_index(local_cache) 68 index.make_index(local_cache)
71 69
diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua
index 96b232ff..7808bce9 100644
--- a/src/luarocks/build.lua
+++ b/src/luarocks/build.lua
@@ -2,7 +2,6 @@
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.
4local build = {} 4local build = {}
5package.loaded["luarocks.build"] = build
6 5
7local pack = require("luarocks.pack") 6local pack = require("luarocks.pack")
8local path = require("luarocks.path") 7local path = require("luarocks.path")
@@ -12,11 +11,10 @@ local fetch = require("luarocks.fetch")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local dir = require("luarocks.dir") 12local dir = require("luarocks.dir")
14local deps = require("luarocks.deps") 13local deps = require("luarocks.deps")
15local manif = require("luarocks.manif") 14local writer = require("luarocks.manif.writer")
16local remove = require("luarocks.remove") 15local remove = require("luarocks.remove")
17local cfg = require("luarocks.cfg") 16local cfg = require("luarocks.core.cfg")
18 17
19util.add_run_function(build)
20build.help_summary = "Build/compile a rock." 18build.help_summary = "Build/compile a rock."
21build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" 19build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}"
22build.help = [[ 20build.help = [[
@@ -148,6 +146,31 @@ local function install_default_docs(name, version)
148 end 146 end
149end 147end
150 148
149local function check_macosx_deployment_target(rockspec)
150 local target = rockspec.build.macosx_deployment_target
151 local function minor(version)
152 return tonumber(version and version:match("^[^.]+%.([^.]+)"))
153 end
154 local function patch_variable(var, target)
155 if rockspec.variables[var]:match("MACOSX_DEPLOYMENT_TARGET") then
156 rockspec.variables[var] = (rockspec.variables[var]):gsub("MACOSX_DEPLOYMENT_TARGET=[^ ]*", "MACOSX_DEPLOYMENT_TARGET="..target)
157 else
158 rockspec.variables[var] = "env MACOSX_DEPLOYMENT_TARGET="..target.." "..rockspec.variables[var]
159 end
160 end
161 if cfg.platforms.macosx and rockspec:format_is_at_least("3.0") and target then
162 local version = util.popen_read("sw_vers -productVersion")
163 local versionminor = minor(version)
164 local targetminor = minor(target)
165 if targetminor > versionminor then
166 return nil, ("This rock requires Mac OSX 10.%d, and you are running 10.%d."):format(targetminor, versionminor)
167 end
168 patch_variable("CC", target)
169 patch_variable("LD", target)
170 end
171 return true
172end
173
151--- Build and install a rock given a rockspec. 174--- Build and install a rock given a rockspec.
152-- @param rockspec_file string: local or remote filename of a rockspec. 175-- @param rockspec_file string: local or remote filename of a rockspec.
153-- @param need_to_fetch boolean: true if sources need to be fetched, 176-- @param need_to_fetch boolean: true if sources need to be fetched,
@@ -245,6 +268,11 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
245 end 268 end
246 end 269 end
247 270
271 ok, err = check_macosx_deployment_target(rockspec)
272 if not ok then
273 return nil, err
274 end
275
248 if build_spec.type ~= "none" then 276 if build_spec.type ~= "none" then
249 277
250 -- Temporary compatibility 278 -- Temporary compatibility
@@ -314,7 +342,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
314 fs.pop_dir() 342 fs.pop_dir()
315 end 343 end
316 344
317 ok, err = manif.make_rock_manifest(name, version) 345 ok, err = writer.make_rock_manifest(name, version)
318 if err then return nil, err end 346 if err then return nil, err end
319 347
320 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode) 348 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode)
@@ -407,7 +435,7 @@ function build.command(flags, name, version)
407 if not ok then util.printerr(err) end 435 if not ok then util.printerr(err) end
408 end 436 end
409 437
410 manif.check_dependencies(nil, deps.get_deps_mode(flags)) 438 writer.check_dependencies(nil, deps.get_deps_mode(flags))
411 return name, version 439 return name, version
412 end 440 end
413end 441end
diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua
index c36aa96f..59c530a4 100644
--- a/src/luarocks/build/builtin.lua
+++ b/src/luarocks/build/builtin.lua
@@ -7,7 +7,7 @@ local unpack = unpack or table.unpack
7local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
8local path = require("luarocks.path") 8local path = require("luarocks.path")
9local util = require("luarocks.util") 9local util = require("luarocks.util")
10local cfg = require("luarocks.cfg") 10local cfg = require("luarocks.core.cfg")
11local dir = require("luarocks.dir") 11local dir = require("luarocks.dir")
12 12
13--- Run a command displaying its execution on standard output. 13--- Run a command displaying its execution on standard output.
@@ -49,7 +49,7 @@ end
49-- nil and an error message otherwise. 49-- nil and an error message otherwise.
50function builtin.run(rockspec) 50function builtin.run(rockspec)
51 assert(type(rockspec) == "table") 51 assert(type(rockspec) == "table")
52 local compile_object, compile_library, compile_wrapper_binary --TODO EXEWRAPPER 52 local compile_object, compile_library, compile_static_library, compile_wrapper_binary --TODO EXEWRAPPER
53 53
54 local build = rockspec.build 54 local build = rockspec.build
55 local variables = rockspec.variables 55 local variables = rockspec.variables
@@ -82,6 +82,15 @@ function builtin.run(rockspec)
82 local ok = execute(variables.LD.." "..variables.LIBFLAG, "-o", library, unpack(extras)) 82 local ok = execute(variables.LD.." "..variables.LIBFLAG, "-o", library, unpack(extras))
83 return ok 83 return ok
84 end 84 end
85 --[[ TODO disable static libs until we fix the conflict in the manifest, which will take extending the manifest format.
86 compile_static_library = function(library, objects, libraries, libdirs, name)
87 local ok = execute(variables.AR, "rc", library, unpack(objects))
88 if ok then
89 ok = execute(variables.RANLIB, library)
90 end
91 return ok
92 end
93 ]]
85 compile_wrapper_binary = function(fullname, name) 94 compile_wrapper_binary = function(fullname, name)
86 --TODO EXEWRAPPER 95 --TODO EXEWRAPPER
87 local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\") 96 local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\")
@@ -128,6 +137,12 @@ function builtin.run(rockspec)
128 end 137 end
129 return ok 138 return ok
130 end 139 end
140 --[[ TODO disable static libs until we fix the conflict in the manifest, which will take extending the manifest format.
141 compile_static_library = function(library, objects, libraries, libdirs, name)
142 local ok = execute(variables.AR, "-out:"..library, unpack(objects))
143 return ok
144 end
145 ]]
131 compile_wrapper_binary = function(fullname, name) 146 compile_wrapper_binary = function(fullname, name)
132 --TODO EXEWRAPPER 147 --TODO EXEWRAPPER
133 local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\") 148 local fullbasename = fullname:gsub("%.lua$", ""):gsub("/", "\\")
@@ -169,6 +184,13 @@ function builtin.run(rockspec)
169 end 184 end
170 return execute(variables.LD.." "..variables.LIBFLAG, "-o", library, "-L"..variables.LUA_LIBDIR, unpack(extras)) 185 return execute(variables.LD.." "..variables.LIBFLAG, "-o", library, "-L"..variables.LUA_LIBDIR, unpack(extras))
171 end 186 end
187 compile_static_library = function(library, objects, libraries, libdirs, name)
188 local ok = execute(variables.AR, "rc", library, unpack(objects))
189 if ok then
190 ok = execute(variables.RANLIB, library)
191 end
192 return ok
193 end
172 compile_wrapper_binary = function(_, name) return true, name end 194 compile_wrapper_binary = function(_, name) return true, name end
173 --TODO EXEWRAPPER 195 --TODO EXEWRAPPER
174 end 196 end
@@ -244,6 +266,17 @@ function builtin.run(rockspec)
244 if not ok then 266 if not ok then
245 return nil, "Failed compiling module "..module_name 267 return nil, "Failed compiling module "..module_name
246 end 268 end
269 --[[ TODO disable static libs until we fix the conflict in the manifest, which will take extending the manifest format.
270 module_name = name:match("([^.]*)$").."."..util.matchquote(cfg.static_lib_extension)
271 if moddir ~= "" then
272 module_name = dir.path(moddir, module_name)
273 end
274 lib_modules[module_name] = dir.path(libdir, module_name)
275 ok = compile_static_library(module_name, objects, info.libraries, info.libdirs, name)
276 if not ok then
277 return nil, "Failed compiling static library "..module_name
278 end
279 ]]
247 end 280 end
248 end 281 end
249 for _, mods in ipairs({{ tbl = lua_modules, perms = cfg.perm_read }, { tbl = lib_modules, perms = cfg.perm_exec }}) do 282 for _, mods in ipairs({{ tbl = lua_modules, perms = cfg.perm_read }, { tbl = lib_modules, perms = cfg.perm_exec }}) do
diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua
index da5a31f1..8ee6b6b2 100644
--- a/src/luarocks/build/cmake.lua
+++ b/src/luarocks/build/cmake.lua
@@ -4,7 +4,7 @@ local cmake = {}
4 4
5local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
6local util = require("luarocks.util") 6local util = require("luarocks.util")
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
8 8
9--- Driver function for the "cmake" build back-end. 9--- Driver function for the "cmake" build back-end.
10-- @param rockspec table: the loaded rockspec. 10-- @param rockspec table: the loaded rockspec.
@@ -52,13 +52,26 @@ function cmake.run(rockspec)
52 return nil, "Failed cmake." 52 return nil, "Failed cmake."
53 end 53 end
54 54
55 if not fs.execute_string(rockspec.variables.CMAKE.." --build build.luarocks --config Release") then 55 local do_build, do_install
56 return nil, "Failed building." 56 if rockspec:format_is_at_least("3.0") then
57 do_build = (build.build_pass == nil) and true or build.build_pass
58 do_install = (build.install_pass == nil) and true or build.install_pass
59 else
60 do_build = true
61 do_install = true
57 end 62 end
58 63
59 if not fs.execute_string(rockspec.variables.CMAKE.." --build build.luarocks --target install --config Release") then 64 if do_build then
60 return nil, "Failed installing." 65 if not fs.execute_string(rockspec.variables.CMAKE.." --build build.luarocks --config Release") then
66 return nil, "Failed building."
67 end
61 end 68 end
69 if do_install then
70 if not fs.execute_string(rockspec.variables.CMAKE.." --build build.luarocks --target install --config Release") then
71 return nil, "Failed installing."
72 end
73 end
74
62 return true 75 return true
63end 76end
64 77
diff --git a/src/luarocks/build/make.lua b/src/luarocks/build/make.lua
index 69e73c2e..ded015b7 100644
--- a/src/luarocks/build/make.lua
+++ b/src/luarocks/build/make.lua
@@ -6,7 +6,7 @@ local unpack = unpack or table.unpack
6 6
7local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local cfg = require("luarocks.cfg") 9local cfg = require("luarocks.core.cfg")
10 10
11--- Call "make" with given target and variables 11--- Call "make" with given target and variables
12-- @param make_cmd string: the make command to be used (typically 12-- @param make_cmd string: the make command to be used (typically
diff --git a/src/luarocks/command_line.lua b/src/luarocks/command_line.lua
index ecf3a61b..96891b75 100644
--- a/src/luarocks/command_line.lua
+++ b/src/luarocks/command_line.lua
@@ -5,7 +5,7 @@ local command_line = {}
5local unpack = unpack or table.unpack 5local unpack = unpack or table.unpack
6 6
7local util = require("luarocks.util") 7local util = require("luarocks.util")
8local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.core.cfg")
9local path = require("luarocks.path") 9local path = require("luarocks.path")
10local dir = require("luarocks.dir") 10local dir = require("luarocks.dir")
11local deps = require("luarocks.deps") 11local deps = require("luarocks.deps")
diff --git a/src/luarocks/config_cmd.lua b/src/luarocks/config_cmd.lua
index fe3cc637..b68f7898 100644
--- a/src/luarocks/config_cmd.lua
+++ b/src/luarocks/config_cmd.lua
@@ -2,11 +2,10 @@
2-- Queries information about the LuaRocks configuration. 2-- Queries information about the LuaRocks configuration.
3local config_cmd = {} 3local config_cmd = {}
4 4
5local cfg = require("luarocks.cfg") 5local cfg = require("luarocks.core.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)
10config_cmd.help_summary = "Query information about the LuaRocks configuration." 9config_cmd.help_summary = "Query information about the LuaRocks configuration."
11config_cmd.help_arguments = "<flag>" 10config_cmd.help_arguments = "<flag>"
12config_cmd.help = [[ 11config_cmd.help = [[
diff --git a/src/luarocks/cfg.lua b/src/luarocks/core/cfg.lua
index 1141acf6..de8b9281 100644
--- a/src/luarocks/cfg.lua
+++ b/src/luarocks/core/cfg.lua
@@ -1,3 +1,4 @@
1
1--- Configuration for LuaRocks. 2--- Configuration for LuaRocks.
2-- Tries to load the user's configuration file and 3-- Tries to load the user's configuration file and
3-- defines defaults for unset values. See the 4-- defines defaults for unset values. See the
@@ -12,11 +13,7 @@
12local rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION = 13local rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION =
13 rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION 14 rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION
14 15
15--module("luarocks.cfg")
16local cfg = {} 16local cfg = {}
17package.loaded["luarocks.cfg"] = cfg
18
19local util = require("luarocks.util")
20 17
21cfg.lua_version = _VERSION:match(" (5%.[123])$") or "5.1" 18cfg.lua_version = _VERSION:match(" (5%.[123])$") or "5.1"
22local version_suffix = cfg.lua_version:gsub("%.", "_") 19local version_suffix = cfg.lua_version:gsub("%.", "_")
@@ -31,15 +28,18 @@ if not ok then
31 site_config = {} 28 site_config = {}
32end 29end
33 30
31local util = require("luarocks.core.util")
32local persist = require("luarocks.core.persist")
33local require = nil
34--------------------------------------------------------------------------------
35
34cfg.program_version = "scm" 36cfg.program_version = "scm"
35cfg.program_series = "2.2" 37cfg.program_series = "3.0"
36cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series 38cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series
37cfg.variables = {} 39cfg.variables = {}
38cfg.rocks_trees = {} 40cfg.rocks_trees = {}
39cfg.platforms = {} 41cfg.platforms = {}
40 42
41local persist = require("luarocks.persist")
42
43cfg.errorcodes = setmetatable({ 43cfg.errorcodes = setmetatable({
44 OK = 0, 44 OK = 0,
45 UNSPECIFIED = 1, 45 UNSPECIFIED = 1,
@@ -75,8 +75,8 @@ end
75-- so that this detection does not run every time. When it is 75-- so that this detection does not run every time. When it is
76-- performed, we use the Unix way to identify the system, 76-- performed, we use the Unix way to identify the system,
77-- even on Windows (assuming UnxUtils or Cygwin). 77-- even on Windows (assuming UnxUtils or Cygwin).
78local system = site_config.LUAROCKS_UNAME_S or io.popen("uname -s"):read("*l") 78local system = site_config.LUAROCKS_UNAME_S or util.popen_read("uname -s")
79local proc = site_config.LUAROCKS_UNAME_M or io.popen("uname -m"):read("*l") 79local proc = site_config.LUAROCKS_UNAME_M or util.popen_read("uname -m")
80if proc:match("i[%d]86") then 80if proc:match("i[%d]86") then
81 cfg.target_cpu = "x86" 81 cfg.target_cpu = "x86"
82elseif proc:match("amd64") or proc:match("x86_64") then 82elseif proc:match("amd64") or proc:match("x86_64") then
@@ -370,6 +370,8 @@ local defaults = {
370 MAKE = "make", 370 MAKE = "make",
371 CC = "cc", 371 CC = "cc",
372 LD = "ld", 372 LD = "ld",
373 AR = "ar",
374 RANLIB = "ranlib",
373 375
374 CVS = "cvs", 376 CVS = "cvs",
375 GIT = "git", 377 GIT = "git",
@@ -425,7 +427,8 @@ local defaults = {
425 include = "include" 427 include = "include"
426 }, 428 },
427 429
428 rocks_provided = {} 430 rocks_provided = {},
431 rocks_provided_3_0 = {},
429} 432}
430 433
431if cfg.platforms.windows then 434if cfg.platforms.windows then
@@ -437,6 +440,7 @@ if cfg.platforms.windows then
437 defaults.arch = "win32-"..cfg.target_cpu 440 defaults.arch = "win32-"..cfg.target_cpu
438 defaults.lib_extension = "dll" 441 defaults.lib_extension = "dll"
439 defaults.external_lib_extension = "dll" 442 defaults.external_lib_extension = "dll"
443 defaults.static_lib_extension = "lib"
440 defaults.obj_extension = "obj" 444 defaults.obj_extension = "obj"
441 defaults.external_deps_dirs = { "c:/external/" } 445 defaults.external_deps_dirs = { "c:/external/" }
442 defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR and site_config.LUA_BINDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/bin" 446 defaults.variables.LUA_BINDIR = site_config.LUA_BINDIR and site_config.LUA_BINDIR:gsub("\\", "/") or "c:/lua"..cfg.lua_version.."/bin"
@@ -450,6 +454,7 @@ if cfg.platforms.windows then
450 defaults.variables.WRAPPER = full_prefix.."\\rclauncher.c" 454 defaults.variables.WRAPPER = full_prefix.."\\rclauncher.c"
451 defaults.variables.LD = "link" 455 defaults.variables.LD = "link"
452 defaults.variables.MT = "mt" 456 defaults.variables.MT = "mt"
457 defaults.variables.AR = "lib"
453 defaults.variables.LUALIB = "lua"..cfg.lua_version..".lib" 458 defaults.variables.LUALIB = "lua"..cfg.lua_version..".lib"
454 defaults.variables.CFLAGS = "/nologo /MD /O2" 459 defaults.variables.CFLAGS = "/nologo /MD /O2"
455 defaults.variables.LIBFLAG = "/nologo /dll" 460 defaults.variables.LIBFLAG = "/nologo /dll"
@@ -489,11 +494,14 @@ end
489 494
490if cfg.platforms.mingw32 then 495if cfg.platforms.mingw32 then
491 defaults.obj_extension = "o" 496 defaults.obj_extension = "o"
497 defaults.static_lib_extension = "a"
492 defaults.cmake_generator = "MinGW Makefiles" 498 defaults.cmake_generator = "MinGW Makefiles"
493 defaults.variables.MAKE = "mingw32-make" 499 defaults.variables.MAKE = "mingw32-make"
494 defaults.variables.CC = "mingw32-gcc" 500 defaults.variables.CC = "mingw32-gcc"
495 defaults.variables.RC = "windres" 501 defaults.variables.RC = "windres"
496 defaults.variables.LD = "mingw32-gcc" 502 defaults.variables.LD = "mingw32-gcc"
503 defaults.variables.AR = "ar"
504 defaults.variables.RANLIB = "ranlib"
497 defaults.variables.CFLAGS = "-O2" 505 defaults.variables.CFLAGS = "-O2"
498 defaults.variables.LIBFLAG = "-shared" 506 defaults.variables.LIBFLAG = "-shared"
499 defaults.makefile = "Makefile" 507 defaults.makefile = "Makefile"
@@ -514,6 +522,7 @@ end
514 522
515if cfg.platforms.unix then 523if cfg.platforms.unix then
516 defaults.lib_extension = "so" 524 defaults.lib_extension = "so"
525 defaults.static_lib_extension = "a"
517 defaults.external_lib_extension = "so" 526 defaults.external_lib_extension = "so"
518 defaults.obj_extension = "o" 527 defaults.obj_extension = "o"
519 defaults.external_deps_dirs = { "/usr/local", "/usr" } 528 defaults.external_deps_dirs = { "/usr/local", "/usr" }
@@ -587,7 +596,7 @@ if cfg.platforms.macosx then
587 defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load" 596 defaults.variables.LIBFLAG = "-bundle -undefined dynamic_lookup -all_load"
588 defaults.variables.STAT = "/usr/bin/stat" 597 defaults.variables.STAT = "/usr/bin/stat"
589 defaults.variables.STATFLAG = "-f '%A'" 598 defaults.variables.STATFLAG = "-f '%A'"
590 local version = io.popen("sw_vers -productVersion"):read("*l") 599 local version = util.popen_read("sw_vers -productVersion")
591 version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3 600 version = tonumber(version and version:match("^[^.]+%.([^.]+)")) or 3
592 if version >= 10 then 601 if version >= 10 then
593 version = 8 602 version = 8
@@ -646,8 +655,8 @@ end
646if package.loaded.jit then 655if package.loaded.jit then
647 -- LuaJIT 656 -- LuaJIT
648 local lj_version = package.loaded.jit.version:match("LuaJIT (.*)"):gsub("%-","") 657 local lj_version = package.loaded.jit.version:match("LuaJIT (.*)"):gsub("%-","")
649 --defaults.rocks_provided["luajit"] = lj_version.."-1"
650 defaults.rocks_provided["luabitop"] = lj_version.."-1" 658 defaults.rocks_provided["luabitop"] = lj_version.."-1"
659 defaults.rocks_provided_3_0["luajit"] = lj_version.."-1"
651end 660end
652 661
653-- Use defaults: 662-- Use defaults:
@@ -664,6 +673,7 @@ for _, entry in ipairs({"variables", "rocks_provided"}) do
664 end 673 end
665 end 674 end
666end 675end
676setmetatable(defaults.rocks_provided_3_0, { __index = cfg.rocks_provided })
667 677
668-- For values not set in the config file, use values from the 'defaults' table. 678-- For values not set in the config file, use values from the 'defaults' table.
669local cfg_mt = { 679local cfg_mt = {
diff --git a/src/luarocks/core/deps.lua b/src/luarocks/core/deps.lua
new file mode 100644
index 00000000..6d539eb8
--- /dev/null
+++ b/src/luarocks/core/deps.lua
@@ -0,0 +1,192 @@
1
2local deps = {}
3
4local util = require("luarocks.core.util")
5local require = nil
6--------------------------------------------------------------------------------
7
8local deltas = {
9 scm = 1100,
10 cvs = 1000,
11 rc = -1000,
12 pre = -10000,
13 beta = -100000,
14 alpha = -1000000
15}
16
17local version_mt = {
18 --- Equality comparison for versions.
19 -- All version numbers must be equal.
20 -- If both versions have revision numbers, they must be equal;
21 -- otherwise the revision number is ignored.
22 -- @param v1 table: version table to compare.
23 -- @param v2 table: version table to compare.
24 -- @return boolean: true if they are considered equivalent.
25 __eq = function(v1, v2)
26 if #v1 ~= #v2 then
27 return false
28 end
29 for i = 1, #v1 do
30 if v1[i] ~= v2[i] then
31 return false
32 end
33 end
34 if v1.revision and v2.revision then
35 return (v1.revision == v2.revision)
36 end
37 return true
38 end,
39 --- Size comparison for versions.
40 -- All version numbers are compared.
41 -- If both versions have revision numbers, they are compared;
42 -- otherwise the revision number is ignored.
43 -- @param v1 table: version table to compare.
44 -- @param v2 table: version table to compare.
45 -- @return boolean: true if v1 is considered lower than v2.
46 __lt = function(v1, v2)
47 for i = 1, math.max(#v1, #v2) do
48 local v1i, v2i = v1[i] or 0, v2[i] or 0
49 if v1i ~= v2i then
50 return (v1i < v2i)
51 end
52 end
53 if v1.revision and v2.revision then
54 return (v1.revision < v2.revision)
55 end
56 return false
57 end
58}
59
60local version_cache = {}
61setmetatable(version_cache, {
62 __mode = "kv"
63})
64
65--- Parse a version string, converting to table format.
66-- A version table contains all components of the version string
67-- converted to numeric format, stored in the array part of the table.
68-- If the version contains a revision, it is stored numerically
69-- in the 'revision' field. The original string representation of
70-- the string is preserved in the 'string' field.
71-- Returned version tables use a metatable
72-- allowing later comparison through relational operators.
73-- @param vstring string: A version number in string format.
74-- @return table or nil: A version table or nil
75-- if the input string contains invalid characters.
76function deps.parse_version(vstring)
77 if not vstring then return nil end
78 assert(type(vstring) == "string")
79
80 local cached = version_cache[vstring]
81 if cached then
82 return cached
83 end
84
85 local version = {}
86 local i = 1
87
88 local function add_token(number)
89 version[i] = version[i] and version[i] + number/100000 or number
90 i = i + 1
91 end
92
93 -- trim leading and trailing spaces
94 vstring = vstring:match("^%s*(.*)%s*$")
95 version.string = vstring
96 -- store revision separately if any
97 local main, revision = vstring:match("(.*)%-(%d+)$")
98 if revision then
99 vstring = main
100 version.revision = tonumber(revision)
101 end
102 while #vstring > 0 do
103 -- extract a number
104 local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)")
105 if token then
106 add_token(tonumber(token))
107 else
108 -- extract a word
109 token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)")
110 if not token then
111 util.printerr("Warning: version number '"..vstring.."' could not be parsed.")
112 version[i] = 0
113 break
114 end
115 version[i] = deltas[token] or (token:byte() / 1000)
116 end
117 vstring = rest
118 end
119 setmetatable(version, version_mt)
120 version_cache[vstring] = version
121 return version
122end
123
124--- Utility function to compare version numbers given as strings.
125-- @param a string: one version.
126-- @param b string: another version.
127-- @return boolean: True if a > b.
128function deps.compare_versions(a, b)
129 return deps.parse_version(a) > deps.parse_version(b)
130end
131
132--- A more lenient check for equivalence between versions.
133-- This returns true if the requested components of a version
134-- match and ignore the ones that were not given. For example,
135-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
136-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
137-- doesn't.
138-- @param version string or table: Version to be tested; may be
139-- in string format or already parsed into a table.
140-- @param requested string or table: Version requested; may be
141-- in string format or already parsed into a table.
142-- @return boolean: True if the tested version matches the requested
143-- version, false otherwise.
144local function partial_match(version, requested)
145 assert(type(version) == "string" or type(version) == "table")
146 assert(type(requested) == "string" or type(version) == "table")
147
148 if type(version) ~= "table" then version = deps.parse_version(version) end
149 if type(requested) ~= "table" then requested = deps.parse_version(requested) end
150 if not version or not requested then return false end
151
152 for i, ri in ipairs(requested) do
153 local vi = version[i] or 0
154 if ri ~= vi then return false end
155 end
156 if requested.revision then
157 return requested.revision == version.revision
158 end
159 return true
160end
161
162--- Check if a version satisfies a set of constraints.
163-- @param version table: A version in table format
164-- @param constraints table: An array of constraints in table format.
165-- @return boolean: True if version satisfies all constraints,
166-- false otherwise.
167function deps.match_constraints(version, constraints)
168 assert(type(version) == "table")
169 assert(type(constraints) == "table")
170 local ok = true
171 setmetatable(version, version_mt)
172 for _, constr in pairs(constraints) do
173 if type(constr.version) == "string" then
174 constr.version = deps.parse_version(constr.version)
175 end
176 local constr_version, constr_op = constr.version, constr.op
177 setmetatable(constr_version, version_mt)
178 if constr_op == "==" then ok = version == constr_version
179 elseif constr_op == "~=" then ok = version ~= constr_version
180 elseif constr_op == ">" then ok = version > constr_version
181 elseif constr_op == "<" then ok = version < constr_version
182 elseif constr_op == ">=" then ok = version >= constr_version
183 elseif constr_op == "<=" then ok = version <= constr_version
184 elseif constr_op == "~>" then ok = partial_match(version, constr_version)
185 end
186 if not ok then break end
187 end
188 return ok
189end
190
191return deps
192
diff --git a/src/luarocks/core/dir.lua b/src/luarocks/core/dir.lua
new file mode 100644
index 00000000..240bb38a
--- /dev/null
+++ b/src/luarocks/core/dir.lua
@@ -0,0 +1,55 @@
1
2local dir = {}
3
4local require = nil
5--------------------------------------------------------------------------------
6
7dir.separator = "/"
8
9--- Describe a path in a cross-platform way.
10-- Use this function to avoid platform-specific directory
11-- separators in other modules. Removes trailing slashes from
12-- each component given, to avoid repeated separators.
13-- Separators inside strings are kept, to handle URLs containing
14-- protocols.
15-- @param ... strings representing directories
16-- @return string: a string with a platform-specific representation
17-- of the path.
18function dir.path(...)
19 local t = {...}
20 while t[1] == "" do
21 table.remove(t, 1)
22 end
23 return (table.concat(t, "/"):gsub("([^:])/+", "%1/"):gsub("^/+", "/"):gsub("/*$", ""))
24end
25
26--- Split protocol and path from an URL or local pathname.
27-- URLs should be in the "protocol://path" format.
28-- For local pathnames, "file" is returned as the protocol.
29-- @param url string: an URL or a local pathname.
30-- @return string, string: the protocol, and the pathname without the protocol.
31function dir.split_url(url)
32 assert(type(url) == "string")
33
34 local protocol, pathname = url:match("^([^:]*)://(.*)")
35 if not protocol then
36 protocol = "file"
37 pathname = url
38 end
39 return protocol, pathname
40end
41
42--- Normalize a url or local path.
43-- URLs should be in the "protocol://path" format. System independent
44-- forward slashes are used, removing trailing and double slashes
45-- @param url string: an URL or a local pathname.
46-- @return string: Normalized result.
47function dir.normalize(name)
48 local protocol, pathname = dir.split_url(name)
49 pathname = pathname:gsub("\\", "/"):gsub("(.)/*$", "%1"):gsub("//", "/")
50 if protocol ~= "file" then pathname = protocol .."://"..pathname end
51 return pathname
52end
53
54return dir
55
diff --git a/src/luarocks/manif_core.lua b/src/luarocks/core/manif.lua
index 82e7ea4d..49619e7f 100644
--- a/src/luarocks/manif_core.lua
+++ b/src/luarocks/core/manif.lua
@@ -1,15 +1,15 @@
1 1
2--- Core functions for querying manifest files. 2--- Core functions for querying manifest files.
3-- This module requires no specific 'fs' functionality. 3local manif = {}
4local manif_core = {}
5package.loaded["luarocks.manif_core"] = manif_core
6 4
7local persist = require("luarocks.persist") 5local persist = require("luarocks.core.persist")
8local type_check = require("luarocks.type_check") 6local type_check = require("luarocks.core.type_check")
9local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
10local dir = require("luarocks.dir") 8local dir = require("luarocks.core.dir")
11local util = require("luarocks.util") 9local util = require("luarocks.core.util")
12local path = require("luarocks.path") 10local path = require("luarocks.core.path")
11local require = nil
12--------------------------------------------------------------------------------
13 13
14-- Table with repository identifiers as keys and tables mapping 14-- Table with repository identifiers as keys and tables mapping
15-- Lua versions to cached loaded manifests as values. 15-- Lua versions to cached loaded manifests as values.
@@ -19,7 +19,7 @@ local manifest_cache = {}
19-- @param repo_url string: The repository identifier. 19-- @param repo_url string: The repository identifier.
20-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. 20-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
21-- @param manifest table: the manifest to be cached. 21-- @param manifest table: the manifest to be cached.
22function manif_core.cache_manifest(repo_url, lua_version, manifest) 22function manif.cache_manifest(repo_url, lua_version, manifest)
23 lua_version = lua_version or cfg.lua_version 23 lua_version = lua_version or cfg.lua_version
24 manifest_cache[repo_url] = manifest_cache[repo_url] or {} 24 manifest_cache[repo_url] = manifest_cache[repo_url] or {}
25 manifest_cache[repo_url][lua_version] = manifest 25 manifest_cache[repo_url][lua_version] = manifest
@@ -29,7 +29,7 @@ end
29-- @param repo_url string: The repository identifier. 29-- @param repo_url string: The repository identifier.
30-- @param lua_version string: Lua version in "5.x" format, defaults to installed version. 30-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
31-- @return table or nil: loaded manifest or nil if cache is empty. 31-- @return table or nil: loaded manifest or nil if cache is empty.
32function manif_core.get_cached_manifest(repo_url, lua_version) 32function manif.get_cached_manifest(repo_url, lua_version)
33 lua_version = lua_version or cfg.lua_version 33 lua_version = lua_version or cfg.lua_version
34 return manifest_cache[repo_url] and manifest_cache[repo_url][lua_version] 34 return manifest_cache[repo_url] and manifest_cache[repo_url][lua_version]
35end 35end
@@ -42,7 +42,7 @@ end
42-- @param quick boolean: If given, skips type checking. 42-- @param quick boolean: If given, skips type checking.
43-- @return table or (nil, string, string): the manifest or nil, 43-- @return table or (nil, string, string): the manifest or nil,
44-- error message and error code ("open", "load", "run" or "type"). 44-- error message and error code ("open", "load", "run" or "type").
45function manif_core.manifest_loader(file, repo_url, lua_version, quick) 45function manif.manifest_loader(file, repo_url, lua_version, quick)
46 local manifest, err, errcode = persist.load_into_table(file) 46 local manifest, err, errcode = persist.load_into_table(file)
47 if not manifest then 47 if not manifest then
48 return nil, "Failed loading manifest for "..repo_url..": "..err, errcode 48 return nil, "Failed loading manifest for "..repo_url..": "..err, errcode
@@ -55,7 +55,7 @@ function manif_core.manifest_loader(file, repo_url, lua_version, quick)
55 end 55 end
56 end 56 end
57 57
58 manif_core.cache_manifest(repo_url, lua_version, manifest) 58 manif.cache_manifest(repo_url, lua_version, manifest)
59 return manifest 59 return manifest
60end 60end
61 61
@@ -65,16 +65,16 @@ end
65-- @param repo_url string: URL or pathname for the repository. 65-- @param repo_url string: URL or pathname for the repository.
66-- @return table or (nil, string, string): A table representing the manifest, 66-- @return table or (nil, string, string): A table representing the manifest,
67-- or nil followed by an error message and an error code, see manifest_loader. 67-- or nil followed by an error message and an error code, see manifest_loader.
68function manif_core.load_local_manifest(repo_url) 68function manif.load_local_manifest(repo_url)
69 assert(type(repo_url) == "string") 69 assert(type(repo_url) == "string")
70 70
71 local cached_manifest = manif_core.get_cached_manifest(repo_url) 71 local cached_manifest = manif.get_cached_manifest(repo_url)
72 if cached_manifest then 72 if cached_manifest then
73 return cached_manifest 73 return cached_manifest
74 end 74 end
75 75
76 local pathname = dir.path(repo_url, "manifest") 76 local pathname = dir.path(repo_url, "manifest")
77 return manif_core.manifest_loader(pathname, repo_url, nil, true) 77 return manif.manifest_loader(pathname, repo_url, nil, true)
78end 78end
79 79
80--- Get all versions of a package listed in a manifest file. 80--- Get all versions of a package listed in a manifest file.
@@ -85,13 +85,13 @@ end
85-- or "all", to use all trees. 85-- or "all", to use all trees.
86-- @return table: An array of strings listing installed 86-- @return table: An array of strings listing installed
87-- versions of a package. 87-- versions of a package.
88function manif_core.get_versions(name, deps_mode) 88function manif.get_versions(name, deps_mode)
89 assert(type(name) == "string") 89 assert(type(name) == "string")
90 assert(type(deps_mode) == "string") 90 assert(type(deps_mode) == "string")
91 91
92 local version_set = {} 92 local version_set = {}
93 path.map_trees(deps_mode, function(tree) 93 path.map_trees(deps_mode, function(tree)
94 local manifest = manif_core.load_local_manifest(path.rocks_dir(tree)) 94 local manifest = manif.load_local_manifest(path.rocks_dir(tree))
95 95
96 if manifest and manifest.repository[name] then 96 if manifest and manifest.repository[name] then
97 for version in pairs(manifest.repository[name]) do 97 for version in pairs(manifest.repository[name]) do
@@ -103,4 +103,4 @@ function manif_core.get_versions(name, deps_mode)
103 return util.keys(version_set) 103 return util.keys(version_set)
104end 104end
105 105
106return manif_core 106return manif
diff --git a/src/luarocks/core/path.lua b/src/luarocks/core/path.lua
new file mode 100644
index 00000000..a4eb8b4b
--- /dev/null
+++ b/src/luarocks/core/path.lua
@@ -0,0 +1,151 @@
1
2--- Core LuaRocks-specific path handling functions.
3local path = {}
4
5local cfg = require("luarocks.core.cfg")
6local dir = require("luarocks.core.dir")
7local require = nil
8--------------------------------------------------------------------------------
9
10function path.rocks_dir(tree)
11 if type(tree) == "string" then
12 return dir.path(tree, cfg.rocks_subdir)
13 else
14 assert(type(tree) == "table")
15 return tree.rocks_dir or dir.path(tree.root, cfg.rocks_subdir)
16 end
17end
18
19--- Produce a versioned version of a filename.
20-- @param file string: filename (must start with prefix)
21-- @param prefix string: Path prefix for file
22-- @param name string: Rock name
23-- @param version string: Rock version
24-- @return string: a pathname with the same directory parts and a versioned basename.
25function path.versioned_name(file, prefix, name, version)
26 assert(type(file) == "string")
27 assert(type(name) == "string")
28 assert(type(version) == "string")
29
30 local rest = file:sub(#prefix+1):gsub("^/*", "")
31 local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_")
32 return dir.path(prefix, name_version.."-"..rest)
33end
34
35--- Convert a pathname to a module identifier.
36-- In Unix, for example, a path "foo/bar/baz.lua" is converted to
37-- "foo.bar.baz"; "bla/init.lua" returns "bla"; "foo.so" returns "foo".
38-- @param file string: Pathname of module
39-- @return string: The module identifier, or nil if given path is
40-- not a conformant module path (the function does not check if the
41-- path actually exists).
42function path.path_to_module(file)
43 assert(type(file) == "string")
44
45 local name = file:match("(.*)%."..cfg.lua_extension.."$")
46 if name then
47 name = name:gsub(dir.separator, ".")
48 local init = name:match("(.*)%.init$")
49 if init then
50 name = init
51 end
52 else
53 name = file:match("(.*)%."..cfg.lib_extension.."$")
54 if name then
55 name = name:gsub(dir.separator, ".")
56 --[[ TODO disable static libs until we fix the conflict in the manifest, which will take extending the manifest format.
57 else
58 name = file:match("(.*)%."..cfg.static_lib_extension.."$")
59 if name then
60 name = name:gsub(dir.separator, ".")
61 end
62 ]]
63 end
64 end
65 if not name then name = file end
66 name = name:gsub("^%.+", ""):gsub("%.+$", "")
67 return name
68end
69
70function path.deploy_lua_dir(tree)
71 if type(tree) == "string" then
72 return dir.path(tree, cfg.lua_modules_path)
73 else
74 assert(type(tree) == "table")
75 return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path)
76 end
77end
78
79function path.deploy_lib_dir(tree)
80 if type(tree) == "string" then
81 return dir.path(tree, cfg.lib_modules_path)
82 else
83 assert(type(tree) == "table")
84 return tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path)
85 end
86end
87
88local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true }
89
90--- Return the pathname of the file that would be loaded for a module, indexed.
91-- @param file_name string: module file name as in manifest (eg. "socket/core.so")
92-- @param name string: name of the package (eg. "luasocket")
93-- @param version string: version number (eg. "2.0.2-1")
94-- @param tree string: repository path (eg. "/usr/local")
95-- @param i number: the index, 1 if version is the current default, > 1 otherwise.
96-- This is done this way for use by select_module in luarocks.loader.
97-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
98function path.which_i(file_name, name, version, tree, i)
99 local deploy_dir
100 local extension = file_name:match("%.[a-z]+$")
101 if is_src_extension[extension] then
102 deploy_dir = path.deploy_lua_dir(tree)
103 file_name = dir.path(deploy_dir, file_name)
104 else
105 deploy_dir = path.deploy_lib_dir(tree)
106 file_name = dir.path(deploy_dir, file_name)
107 end
108 if i > 1 then
109 file_name = path.versioned_name(file_name, deploy_dir, name, version)
110 end
111 return file_name
112end
113
114function path.rocks_tree_to_string(tree)
115 if type(tree) == "string" then
116 return tree
117 else
118 assert(type(tree) == "table")
119 return tree.root
120 end
121end
122
123--- Apply a given function to the active rocks trees based on chosen dependency mode.
124-- @param deps_mode string: Dependency mode: "one" for the current default tree,
125-- "all" for all trees, "order" for all trees with priority >= the current default,
126-- "none" for no trees (this function becomes a nop).
127-- @param fn function: function to be applied, with the tree dir (string) as the first
128-- argument and the remaining varargs of map_trees as the following arguments.
129-- @return a table with all results of invocations of fn collected.
130function path.map_trees(deps_mode, fn, ...)
131 local result = {}
132 if deps_mode == "one" then
133 table.insert(result, (fn(cfg.root_dir, ...)) or 0)
134 elseif deps_mode == "all" or deps_mode == "order" then
135 local use = false
136 if deps_mode == "all" then
137 use = true
138 end
139 for _, tree in ipairs(cfg.rocks_trees) do
140 if dir.normalize(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then
141 use = true
142 end
143 if use then
144 table.insert(result, (fn(tree, ...)) or 0)
145 end
146 end
147 end
148 return result
149end
150
151return path
diff --git a/src/luarocks/core/persist.lua b/src/luarocks/core/persist.lua
new file mode 100644
index 00000000..48979184
--- /dev/null
+++ b/src/luarocks/core/persist.lua
@@ -0,0 +1,81 @@
1
2local persist = {}
3
4local require = nil
5--------------------------------------------------------------------------------
6
7--- Load and run a Lua file in an environment.
8-- @param filename string: the name of the file.
9-- @param env table: the environment table.
10-- @return (true, any) or (nil, string, string): true and the return value
11-- of the file, or nil, an error message and an error code ("open", "load"
12-- or "run") in case of errors.
13local function run_file(filename, env)
14 local fd, err = io.open(filename)
15 if not fd then
16 return nil, err, "open"
17 end
18 local str, err = fd:read("*a")
19 fd:close()
20 if not str then
21 return nil, err, "open"
22 end
23 str = str:gsub("^#![^\n]*\n", "")
24 local chunk, ran
25 if _VERSION == "Lua 5.1" then -- Lua 5.1
26 chunk, err = loadstring(str, filename)
27 if chunk then
28 setfenv(chunk, env)
29 ran, err = pcall(chunk)
30 end
31 else -- Lua 5.2
32 chunk, err = load(str, filename, "t", env)
33 if chunk then
34 ran, err = pcall(chunk)
35 end
36 end
37 if not chunk then
38 return nil, "Error loading file: "..err, "load"
39 end
40 if not ran then
41 return nil, "Error running file: "..err, "run"
42 end
43 return true, err
44end
45
46--- Load a Lua file containing assignments, storing them in a table.
47-- The global environment is not propagated to the loaded file.
48-- @param filename string: the name of the file.
49-- @param tbl table or nil: if given, this table is used to store
50-- loaded values.
51-- @return (table, table) or (nil, string, string): a table with the file's assignments
52-- as fields and set of undefined globals accessed in file,
53-- or nil, an error message and an error code ("open"; couldn't open the file,
54-- "load"; compile-time error, or "run"; run-time error)
55-- in case of errors.
56function persist.load_into_table(filename, tbl)
57 assert(type(filename) == "string")
58 assert(type(tbl) == "table" or not tbl)
59
60 local result = tbl or {}
61 local globals = {}
62 local globals_mt = {
63 __index = function(t, k)
64 globals[k] = true
65 end
66 }
67 local save_mt = getmetatable(result)
68 setmetatable(result, globals_mt)
69
70 local ok, err, errcode = run_file(filename, result)
71
72 setmetatable(result, save_mt)
73
74 if not ok then
75 return nil, err, errcode
76 end
77 return result, globals
78end
79
80return persist
81
diff --git a/src/luarocks/core/type_check.lua b/src/luarocks/core/type_check.lua
new file mode 100644
index 00000000..1822312b
--- /dev/null
+++ b/src/luarocks/core/type_check.lua
@@ -0,0 +1,229 @@
1
2local type_check = {}
3
4local cfg = require("luarocks.core.cfg")
5local deps = require("luarocks.core.deps")
6local require = nil
7--------------------------------------------------------------------------------
8
9type_check.string_1 = { _type = "string" }
10type_check.number_1 = { _type = "number" }
11type_check.mandatory_string_1 = { _type = "string", _mandatory = true }
12
13local number_1 = type_check.number_1
14local string_1 = type_check.string_1
15local mandatory_string_1 = type_check.mandatory_string_1
16
17local manifest_types = {
18 repository = {
19 _mandatory = true,
20 -- packages
21 _any = {
22 -- versions
23 _any = {
24 -- items
25 _any = {
26 arch = mandatory_string_1,
27 modules = { _any = string_1 },
28 commands = { _any = string_1 },
29 dependencies = { _any = string_1 },
30 -- TODO: to be extended with more metadata.
31 }
32 }
33 }
34 },
35 modules = {
36 _mandatory = true,
37 -- modules
38 _any = {
39 -- providers
40 _any = string_1
41 }
42 },
43 commands = {
44 _mandatory = true,
45 -- modules
46 _any = {
47 -- commands
48 _any = string_1
49 }
50 },
51 dependencies = {
52 -- each module
53 _any = {
54 -- each version
55 _any = {
56 -- each dependency
57 _any = {
58 name = string_1,
59 constraints = {
60 _any = {
61 no_upgrade = { _type = "boolean" },
62 op = string_1,
63 version = {
64 string = string_1,
65 _any = number_1,
66 }
67 }
68 }
69 }
70 }
71 }
72 }
73}
74
75local function check_version(version, typetbl, context)
76 local typetbl_version = typetbl._version or "1.0"
77 if deps.compare_versions(typetbl_version, version) then
78 if context == "" then
79 return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly."
80 else
81 return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly."
82 end
83 end
84 return true
85end
86
87--- Type check an object.
88-- The object is compared against an archetypical value
89-- matching the expected type -- the actual values don't matter,
90-- only their types. Tables are type checked recursively.
91-- @param version string: The version of the item.
92-- @param item any: The object being checked.
93-- @param typetbl any: The type-checking table for the object.
94-- @param context string: A string indicating the "context" where the
95-- error occurred (the full table path), for error messages.
96-- @return boolean or (nil, string): true if type checking
97-- succeeded, or nil and an error message if it failed.
98-- @see type_check_table
99local function type_check_item(version, item, typetbl, context)
100 assert(type(version) == "string")
101
102 local ok, err = check_version(version, typetbl, context)
103 if not ok then
104 return nil, err
105 end
106
107 local item_type = type(item) or "nil"
108 local expected_type = typetbl._type or "table"
109
110 if expected_type == "number" then
111 if not tonumber(item) then
112 return nil, "Type mismatch on field "..context..": expected a number"
113 end
114 elseif expected_type == "string" then
115 if item_type ~= "string" then
116 return nil, "Type mismatch on field "..context..": expected a string, got "..item_type
117 end
118 if typetbl._pattern then
119 if not item:match("^"..typetbl._pattern.."$") then
120 return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'"
121 end
122 end
123 elseif expected_type == "table" then
124 if item_type ~= expected_type then
125 return nil, "Type mismatch on field "..context..": expected a table"
126 else
127 return type_check.type_check_table(version, item, typetbl, context)
128 end
129 elseif item_type ~= expected_type then
130 return nil, "Type mismatch on field "..context..": expected "..expected_type
131 end
132 return true
133end
134
135local function mkfield(context, field)
136 if context == "" then
137 return tostring(field)
138 elseif type(field) == "string" then
139 return context.."."..field
140 else
141 return context.."["..tostring(field).."]"
142 end
143end
144
145--- Type check the contents of a table.
146-- The table's contents are compared against a reference table,
147-- which contains the recognized fields, with archetypical values
148-- matching the expected types -- the actual values of items in the
149-- reference table don't matter, only their types (ie, for field x
150-- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
151-- If the reference table contains a field called MORE, then
152-- unknown fields in the checked table are accepted.
153-- If it contains a field called ANY, then its type will be
154-- used to check any unknown fields. If a field is prefixed
155-- with MUST_, it is mandatory; its absence from the table is
156-- a type error.
157-- Tables are type checked recursively.
158-- @param version string: The version of tbl.
159-- @param tbl table: The table to be type checked.
160-- @param typetbl table: The type-checking table, containing
161-- values for recognized fields in the checked table.
162-- @param context string: A string indicating the "context" where the
163-- error occurred (such as the name of the table the item is a part of),
164-- to be used by error messages.
165-- @return boolean or (nil, string): true if type checking
166-- succeeded, or nil and an error message if it failed.
167function type_check.type_check_table(version, tbl, typetbl, context)
168 assert(type(version) == "string")
169 assert(type(tbl) == "table")
170 assert(type(typetbl) == "table")
171
172 local ok, err = check_version(version, typetbl, context)
173 if not ok then
174 return nil, err
175 end
176
177 for k, v in pairs(tbl) do
178 local t = typetbl[k] or typetbl._any
179 if t then
180 local ok, err = type_check_item(version, v, t, mkfield(context, k))
181 if not ok then return nil, err end
182 elseif typetbl._more then
183 -- Accept unknown field
184 else
185 if not cfg.accept_unknown_fields then
186 return nil, "Unknown field "..k
187 end
188 end
189 end
190 for k, v in pairs(typetbl) do
191 if k:sub(1,1) ~= "_" and v._mandatory then
192 if not tbl[k] then
193 return nil, "Mandatory field "..mkfield(context, k).." is missing."
194 end
195 end
196 end
197 return true
198end
199
200function type_check.check_undeclared_globals(globals, typetbl)
201 local undeclared = {}
202 for glob, _ in pairs(globals) do
203 if not (typetbl[glob] or typetbl["MUST_"..glob]) then
204 table.insert(undeclared, glob)
205 end
206 end
207 if #undeclared == 1 then
208 return nil, "Unknown variable: "..undeclared[1]
209 elseif #undeclared > 1 then
210 return nil, "Unknown variables: "..table.concat(undeclared, ", ")
211 end
212 return true
213end
214
215--- Type check a manifest table.
216-- Verify the correctness of elements from a
217-- manifest table, reporting on unknown fields and type
218-- mismatches.
219-- @return boolean or (nil, string): true if type checking
220-- succeeded, or nil and an error message if it failed.
221function type_check.type_check_manifest(manifest, globals)
222 assert(type(manifest) == "table")
223 local ok, err = type_check.check_undeclared_globals(globals, manifest_types)
224 if not ok then return nil, err end
225 return type_check.type_check_table("1.0", manifest, manifest_types, "")
226end
227
228return type_check
229
diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua
new file mode 100644
index 00000000..85b59af6
--- /dev/null
+++ b/src/luarocks/core/util.lua
@@ -0,0 +1,272 @@
1
2local util = {}
3
4local require = nil
5--------------------------------------------------------------------------------
6
7--- Run a process and read a its output.
8-- Equivalent to io.popen(cmd):read("*l"), except that it
9-- closes the fd right away.
10-- @param cmd string: The command to execute
11-- @param spec string: "*l" by default, to read a single line.
12-- May be used to read more, passing, for instance, "*a".
13-- @return string: the output of the program.
14function util.popen_read(cmd, spec)
15 local fd = io.popen(cmd)
16 local out = fd:read(spec or "*l")
17 fd:close()
18 return out
19end
20
21--- Create a new shallow copy of a table: a new table with
22-- the same keys and values. Keys point to the same objects as
23-- the original table (ie, does not copy recursively).
24-- @param tbl table: the input table
25-- @return table: a new table with the same contents.
26function util.make_shallow_copy(tbl)
27 local copy = {}
28 for k,v in pairs(tbl) do
29 copy[k] = v
30 end
31 return copy
32end
33
34---
35-- Formats tables with cycles recursively to any depth.
36-- References to other tables are shown as values.
37-- Self references are indicated.
38-- The string returned is "Lua code", which can be procesed
39-- (in the case in which indent is composed by spaces or "--").
40-- Userdata and function keys and values are shown as strings,
41-- which logically are exactly not equivalent to the original code.
42-- This routine can serve for pretty formating tables with
43-- proper indentations, apart from printing them:
44-- io.write(table.show(t, "t")) -- a typical use
45-- Written by Julio Manuel Fernandez-Diaz,
46-- Heavily based on "Saving tables with cycles", PIL2, p. 113.
47-- @param t table: is the table.
48-- @param name string: is the name of the table (optional)
49-- @param indent string: is a first indentation (optional).
50-- @return string: the pretty-printed table
51function util.show_table(t, name, indent)
52 local cart -- a container
53 local autoref -- for self references
54
55 local function is_empty_table(t) return next(t) == nil end
56
57 local function basic_serialize (o)
58 local so = tostring(o)
59 if type(o) == "function" then
60 local info = debug.getinfo(o, "S")
61 -- info.name is nil because o is not a calling level
62 if info.what == "C" then
63 return ("%q"):format(so .. ", C function")
64 else
65 -- the information is defined through lines
66 return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source)
67 end
68 elseif type(o) == "number" then
69 return so
70 else
71 return ("%q"):format(so)
72 end
73 end
74
75 local function add_to_cart (value, name, indent, saved, field)
76 indent = indent or ""
77 saved = saved or {}
78 field = field or name
79
80 cart = cart .. indent .. field
81
82 if type(value) ~= "table" then
83 cart = cart .. " = " .. basic_serialize(value) .. ";\n"
84 else
85 if saved[value] then
86 cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n"
87 autoref = autoref .. name .. " = " .. saved[value] .. ";\n"
88 else
89 saved[value] = name
90 --if tablecount(value) == 0 then
91 if is_empty_table(value) then
92 cart = cart .. " = {};\n"
93 else
94 cart = cart .. " = {\n"
95 for k, v in pairs(value) do
96 k = basic_serialize(k)
97 local fname = ("%s[%s]"):format(name, k)
98 field = ("[%s]"):format(k)
99 -- three spaces between levels
100 add_to_cart(v, fname, indent .. " ", saved, field)
101 end
102 cart = cart .. indent .. "};\n"
103 end
104 end
105 end
106 end
107
108 name = name or "__unnamed__"
109 if type(t) ~= "table" then
110 return name .. " = " .. basic_serialize(t)
111 end
112 cart, autoref = "", ""
113 add_to_cart(t, name, indent)
114 return cart .. autoref
115end
116
117--- Merges contents of src on top of dst's contents.
118-- @param dst Destination table, which will receive src's contents.
119-- @param src Table which provides new contents to dst.
120-- @see platform_overrides
121function util.deep_merge(dst, src)
122 for k, v in pairs(src) do
123 if type(v) == "table" then
124 if not dst[k] then
125 dst[k] = {}
126 end
127 if type(dst[k]) == "table" then
128 util.deep_merge(dst[k], v)
129 else
130 dst[k] = v
131 end
132 else
133 dst[k] = v
134 end
135 end
136end
137
138--- Remove repeated entries from a path-style string.
139-- Example: given ("a;b;c;a;b;d", ";"), returns "a;b;c;d".
140-- @param list string: A path string (from $PATH or package.path)
141-- @param sep string: The separator
142function util.remove_path_dupes(list, sep)
143 assert(type(list) == "string")
144 assert(type(sep) == "string")
145 local parts = util.split_string(list, sep)
146 local final, entries = {}, {}
147 for _, part in ipairs(parts) do
148 part = part:gsub("//", "/")
149 if not entries[part] then
150 table.insert(final, part)
151 entries[part] = true
152 end
153 end
154 return table.concat(final, sep)
155end
156
157-- from http://lua-users.org/wiki/SplitJoin
158-- by Philippe Lhoste
159function util.split_string(str, delim, maxNb)
160 -- Eliminate bad cases...
161 if string.find(str, delim) == nil then
162 return { str }
163 end
164 if maxNb == nil or maxNb < 1 then
165 maxNb = 0 -- No limit
166 end
167 local result = {}
168 local pat = "(.-)" .. delim .. "()"
169 local nb = 0
170 local lastPos
171 for part, pos in string.gmatch(str, pat) do
172 nb = nb + 1
173 result[nb] = part
174 lastPos = pos
175 if nb == maxNb then break end
176 end
177 -- Handle the last field
178 if nb ~= maxNb then
179 result[nb + 1] = string.sub(str, lastPos)
180 end
181 return result
182end
183
184--- Return an array of keys of a table.
185-- @param tbl table: The input table.
186-- @return table: The array of keys.
187function util.keys(tbl)
188 local ks = {}
189 for k,_ in pairs(tbl) do
190 table.insert(ks, k)
191 end
192 return ks
193end
194
195--- Print a line to standard error
196function util.printerr(...)
197 io.stderr:write(table.concat({...},"\t"))
198 io.stderr:write("\n")
199end
200
201--- Simple sort function used as a default for util.sortedpairs.
202local function default_sort(a, b)
203 local ta = type(a)
204 local tb = type(b)
205 if ta == "number" and tb == "number" then
206 return a < b
207 elseif ta == "number" then
208 return true
209 elseif tb == "number" then
210 return false
211 else
212 return tostring(a) < tostring(b)
213 end
214end
215
216--- A table iterator generator that returns elements sorted by key,
217-- to be used in "for" loops.
218-- @param tbl table: The table to be iterated.
219-- @param sort_function function or table or nil: An optional comparison function
220-- to be used by table.sort when sorting keys, or an array listing an explicit order
221-- for keys. If a value itself is an array, it is taken so that the first element
222-- is a string representing the field name, and the second element is a priority table
223-- for that key, which is returned by the iterator as the third value after the key
224-- and the value.
225-- @return function: the iterator function.
226function util.sortedpairs(tbl, sort_function)
227 sort_function = sort_function or default_sort
228 local keys = util.keys(tbl)
229 local sub_orders = {}
230
231 if type(sort_function) == "function" then
232 table.sort(keys, sort_function)
233 else
234 local order = sort_function
235 local ordered_keys = {}
236 local all_keys = keys
237 keys = {}
238
239 for _, order_entry in ipairs(order) do
240 local key, sub_order
241 if type(order_entry) == "table" then
242 key = order_entry[1]
243 sub_order = order_entry[2]
244 else
245 key = order_entry
246 end
247
248 if tbl[key] then
249 ordered_keys[key] = true
250 sub_orders[key] = sub_order
251 table.insert(keys, key)
252 end
253 end
254
255 table.sort(all_keys, default_sort)
256 for _, key in ipairs(all_keys) do
257 if not ordered_keys[key] then
258 table.insert(keys, key)
259 end
260 end
261 end
262
263 local i = 1
264 return function()
265 local key = keys[i]
266 i = i + 1
267 return key, tbl[key], sub_orders[key]
268 end
269end
270
271return util
272
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index dcebec9b..d9419ec3 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -12,14 +12,23 @@
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.
14local deps = {} 14local deps = {}
15package.loaded["luarocks.deps"] = deps 15setmetatable(deps, { __index = require("luarocks.core.deps") })
16 16
17local cfg = require("luarocks.cfg") 17local cfg = require("luarocks.core.cfg")
18local manif_core = require("luarocks.manif_core") 18local manif = require("luarocks.core.manif")
19local path = require("luarocks.path") 19local path = require("luarocks.path")
20local dir = require("luarocks.dir") 20local dir = require("luarocks.dir")
21local util = require("luarocks.util") 21local util = require("luarocks.util")
22 22
23--- Check if rockspec format version satisfies version requirement.
24-- @param rockspec table: The rockspec table.
25-- @param version string: required version.
26-- @return boolean: true if rockspec format matches version or is newer, false otherwise.
27function deps.format_is_at_least(rockspec, version)
28 local rockspec_format = rockspec.rockspec_format or "1.0"
29 return deps.parse_version(rockspec_format) >= deps.parse_version(version)
30end
31
23local operators = { 32local operators = {
24 ["=="] = "==", 33 ["=="] = "==",
25 ["~="] = "~=", 34 ["~="] = "~=",
@@ -34,130 +43,6 @@ local operators = {
34 ["!="] = "~=" 43 ["!="] = "~="
35} 44}
36 45
37local deltas = {
38 scm = 1100,
39 cvs = 1000,
40 rc = -1000,
41 pre = -10000,
42 beta = -100000,
43 alpha = -1000000
44}
45
46local version_mt = {
47 --- Equality comparison for versions.
48 -- All version numbers must be equal.
49 -- If both versions have revision numbers, they must be equal;
50 -- otherwise the revision number is ignored.
51 -- @param v1 table: version table to compare.
52 -- @param v2 table: version table to compare.
53 -- @return boolean: true if they are considered equivalent.
54 __eq = function(v1, v2)
55 if #v1 ~= #v2 then
56 return false
57 end
58 for i = 1, #v1 do
59 if v1[i] ~= v2[i] then
60 return false
61 end
62 end
63 if v1.revision and v2.revision then
64 return (v1.revision == v2.revision)
65 end
66 return true
67 end,
68 --- Size comparison for versions.
69 -- All version numbers are compared.
70 -- If both versions have revision numbers, they are compared;
71 -- otherwise the revision number is ignored.
72 -- @param v1 table: version table to compare.
73 -- @param v2 table: version table to compare.
74 -- @return boolean: true if v1 is considered lower than v2.
75 __lt = function(v1, v2)
76 for i = 1, math.max(#v1, #v2) do
77 local v1i, v2i = v1[i] or 0, v2[i] or 0
78 if v1i ~= v2i then
79 return (v1i < v2i)
80 end
81 end
82 if v1.revision and v2.revision then
83 return (v1.revision < v2.revision)
84 end
85 return false
86 end
87}
88
89local version_cache = {}
90setmetatable(version_cache, {
91 __mode = "kv"
92})
93
94--- Parse a version string, converting to table format.
95-- A version table contains all components of the version string
96-- converted to numeric format, stored in the array part of the table.
97-- If the version contains a revision, it is stored numerically
98-- in the 'revision' field. The original string representation of
99-- the string is preserved in the 'string' field.
100-- Returned version tables use a metatable
101-- allowing later comparison through relational operators.
102-- @param vstring string: A version number in string format.
103-- @return table or nil: A version table or nil
104-- if the input string contains invalid characters.
105function deps.parse_version(vstring)
106 if not vstring then return nil end
107 assert(type(vstring) == "string")
108
109 local cached = version_cache[vstring]
110 if cached then
111 return cached
112 end
113
114 local version = {}
115 local i = 1
116
117 local function add_token(number)
118 version[i] = version[i] and version[i] + number/100000 or number
119 i = i + 1
120 end
121
122 -- trim leading and trailing spaces
123 vstring = vstring:match("^%s*(.*)%s*$")
124 version.string = vstring
125 -- store revision separately if any
126 local main, revision = vstring:match("(.*)%-(%d+)$")
127 if revision then
128 vstring = main
129 version.revision = tonumber(revision)
130 end
131 while #vstring > 0 do
132 -- extract a number
133 local token, rest = vstring:match("^(%d+)[%.%-%_]*(.*)")
134 if token then
135 add_token(tonumber(token))
136 else
137 -- extract a word
138 token, rest = vstring:match("^(%a+)[%.%-%_]*(.*)")
139 if not token then
140 util.printerr("Warning: version number '"..vstring.."' could not be parsed.")
141 version[i] = 0
142 break
143 end
144 version[i] = deltas[token] or (token:byte() / 1000)
145 end
146 vstring = rest
147 end
148 setmetatable(version, version_mt)
149 version_cache[vstring] = version
150 return version
151end
152
153--- Utility function to compare version numbers given as strings.
154-- @param a string: one version.
155-- @param b string: another version.
156-- @return boolean: True if a > b.
157function deps.compare_versions(a, b)
158 return deps.parse_version(a) > deps.parse_version(b)
159end
160
161--- Consumes a constraint from a string, converting it to table format. 46--- Consumes a constraint from a string, converting it to table format.
162-- For example, a string ">= 1.0, > 2.0" is converted to a table in the 47-- For example, a string ">= 1.0, > 2.0" is converted to a table in the
163-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned 48-- format {op = ">=", version={1,0}} and the rest, "> 2.0", is returned
@@ -192,7 +77,7 @@ end
192function deps.parse_constraints(input) 77function deps.parse_constraints(input)
193 assert(type(input) == "string") 78 assert(type(input) == "string")
194 79
195 local constraints, constraint, oinput = {}, nil, input 80 local constraints, oinput, constraint = {}, input
196 while #input > 0 do 81 while #input > 0 do
197 constraint, input = parse_constraint(input) 82 constraint, input = parse_constraint(input)
198 if constraint then 83 if constraint then
@@ -258,80 +143,25 @@ function deps.show_dep(dep, internal)
258 end 143 end
259end 144end
260 145
261--- A more lenient check for equivalence between versions.
262-- This returns true if the requested components of a version
263-- match and ignore the ones that were not given. For example,
264-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
265-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
266-- doesn't.
267-- @param version string or table: Version to be tested; may be
268-- in string format or already parsed into a table.
269-- @param requested string or table: Version requested; may be
270-- in string format or already parsed into a table.
271-- @return boolean: True if the tested version matches the requested
272-- version, false otherwise.
273local function partial_match(version, requested)
274 assert(type(version) == "string" or type(version) == "table")
275 assert(type(requested) == "string" or type(version) == "table")
276
277 if type(version) ~= "table" then version = deps.parse_version(version) end
278 if type(requested) ~= "table" then requested = deps.parse_version(requested) end
279 if not version or not requested then return false end
280
281 for i, ri in ipairs(requested) do
282 local vi = version[i] or 0
283 if ri ~= vi then return false end
284 end
285 if requested.revision then
286 return requested.revision == version.revision
287 end
288 return true
289end
290
291--- Check if a version satisfies a set of constraints.
292-- @param version table: A version in table format
293-- @param constraints table: An array of constraints in table format.
294-- @return boolean: True if version satisfies all constraints,
295-- false otherwise.
296function deps.match_constraints(version, constraints)
297 assert(type(version) == "table")
298 assert(type(constraints) == "table")
299 local ok = true
300 setmetatable(version, version_mt)
301 for _, constr in pairs(constraints) do
302 if type(constr.version) == "string" then
303 constr.version = deps.parse_version(constr.version)
304 end
305 local constr_version, constr_op = constr.version, constr.op
306 setmetatable(constr_version, version_mt)
307 if constr_op == "==" then ok = version == constr_version
308 elseif constr_op == "~=" then ok = version ~= constr_version
309 elseif constr_op == ">" then ok = version > constr_version
310 elseif constr_op == "<" then ok = version < constr_version
311 elseif constr_op == ">=" then ok = version >= constr_version
312 elseif constr_op == "<=" then ok = version <= constr_version
313 elseif constr_op == "~>" then ok = partial_match(version, constr_version)
314 end
315 if not ok then break end
316 end
317 return ok
318end
319
320--- Attempt to match a dependency to an installed rock. 146--- Attempt to match a dependency to an installed rock.
321-- @param dep table: A dependency parsed in table format. 147-- @param dep table: A dependency parsed in table format.
322-- @param blacklist table: Versions that can't be accepted. Table where keys 148-- @param blacklist table: Versions that can't be accepted. Table where keys
323-- are program versions and values are 'true'. 149-- are program versions and values are 'true'.
150-- @param provided table: A table of auto-dependencies provided
151-- by this Lua implementation for the given dependency.
324-- @return string or nil: latest installed version of the rock matching the dependency 152-- @return string or nil: latest installed version of the rock matching the dependency
325-- or nil if it could not be matched. 153-- or nil if it could not be matched.
326local function match_dep(dep, blacklist, deps_mode) 154local function match_dep(dep, blacklist, deps_mode, rocks_provided)
327 assert(type(dep) == "table") 155 assert(type(dep) == "table")
328 156 assert(type(rocks_provided) == "table")
157
329 local versions 158 local versions
330 if cfg.rocks_provided[dep.name] then 159 local provided = rocks_provided[dep.name]
331 -- provided rocks have higher priority than manifest's rocks 160 if provided then
332 versions = { cfg.rocks_provided[dep.name] } 161 -- Provided rocks have higher priority than manifest's rocks.
162 versions = { provided }
333 else 163 else
334 versions = manif_core.get_versions(dep.name, deps_mode) 164 versions = manif.get_versions(dep.name, deps_mode)
335 end 165 end
336 166
337 local latest_version 167 local latest_version
@@ -366,9 +196,9 @@ function deps.match_deps(rockspec, blacklist, deps_mode)
366 local matched, missing, no_upgrade = {}, {}, {} 196 local matched, missing, no_upgrade = {}, {}, {}
367 197
368 for _, dep in ipairs(rockspec.dependencies) do 198 for _, dep in ipairs(rockspec.dependencies) do
369 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode) 199 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rockspec.rocks_provided)
370 if found then 200 if found then
371 if not cfg.rocks_provided[dep.name] then 201 if not rockspec.rocks_provided[dep.name] then
372 matched[dep] = {name = dep.name, version = found} 202 matched[dep] = {name = dep.name, version = found}
373 end 203 end
374 else 204 else
@@ -393,10 +223,10 @@ local function values_set(tbl)
393 return set 223 return set
394end 224end
395 225
396local function rock_status(name, deps_mode) 226local function rock_status(name, deps_mode, rocks_provided)
397 local search = require("luarocks.search") 227 local search = require("luarocks.search")
398 local installed = match_dep(search.make_query(name), nil, deps_mode) 228 local installed = match_dep(search.make_query(name), nil, deps_mode, rocks_provided)
399 local installation_type = cfg.rocks_provided[name] and "provided by VM" or "installed" 229 local installation_type = rocks_provided[name] and "provided by VM" or "installed"
400 return installed and installed.." "..installation_type or "not installed" 230 return installed and installed.." "..installation_type or "not installed"
401end 231end
402 232
@@ -440,7 +270,8 @@ function deps.fulfill_dependencies(rockspec, deps_mode)
440 end 270 end
441 local supported = nil 271 local supported = nil
442 for _, plat in pairs(rockspec.supported_platforms) do 272 for _, plat in pairs(rockspec.supported_platforms) do
443 local neg, plat = plat:match("^(!?)(.*)") 273 local neg
274 neg, plat = plat:match("^(!?)(.*)")
444 if neg == "!" then 275 if neg == "!" then
445 if deps.platforms_set[plat] then 276 if deps.platforms_set[plat] then
446 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." 277 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms."
@@ -466,14 +297,14 @@ function deps.fulfill_dependencies(rockspec, deps_mode)
466 local first_missing_dep = true 297 local first_missing_dep = true
467 298
468 for _, dep in ipairs(rockspec.dependencies) do 299 for _, dep in ipairs(rockspec.dependencies) do
469 if not match_dep(dep, nil, deps_mode) then 300 if not match_dep(dep, nil, deps_mode, rockspec.rocks_provided) then
470 if first_missing_dep then 301 if first_missing_dep then
471 util.printout() 302 util.printout()
472 first_missing_dep = false 303 first_missing_dep = false
473 end 304 end
474 305
475 util.printout(("%s %s depends on %s (%s)"):format( 306 util.printout(("%s %s depends on %s (%s)"):format(
476 rockspec.name, rockspec.version, deps.show_dep(dep), rock_status(dep.name, deps_mode))) 307 rockspec.name, rockspec.version, deps.show_dep(dep), rock_status(dep.name, deps_mode, rockspec.rocks_provided)))
477 308
478 if dep.constraints[1] and dep.constraints[1].no_upgrade then 309 if dep.constraints[1] and dep.constraints[1].no_upgrade then
479 util.printerr("This version of "..rockspec.name.." is designed for use with") 310 util.printerr("This version of "..rockspec.name.." is designed for use with")
@@ -717,7 +548,10 @@ function deps.scan_deps(results, manifest, name, version, deps_mode)
717 end 548 end
718 dependencies_name[version] = rockspec.dependencies 549 dependencies_name[version] = rockspec.dependencies
719 else 550 else
720 rockspec = { dependencies = deplist } 551 rockspec = {
552 dependencies = deplist,
553 rocks_provided = setmetatable({}, { __index = cfg.rocks_provided_3_0 })
554 }
721 end 555 end
722 local matched = deps.match_deps(rockspec, nil, deps_mode) 556 local matched = deps.match_deps(rockspec, nil, deps_mode)
723 results[name] = version 557 results[name] = version
@@ -745,8 +579,4 @@ function deps.get_deps_mode(flags)
745 end 579 end
746end 580end
747 581
748function deps.deps_mode_to_flag(deps_mode)
749 return "--deps-mode="..deps_mode
750end
751
752return deps 582return deps
diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua
index f72ebd6c..ad7fb870 100644
--- a/src/luarocks/dir.lua
+++ b/src/luarocks/dir.lua
@@ -1,9 +1,7 @@
1 1
2--- Generic utilities for handling pathnames. 2--- Generic utilities for handling pathnames.
3local dir = {} 3local dir = {}
4package.loaded["luarocks.dir"] = dir 4setmetatable(dir, { __index = require("luarocks.core.dir") })
5
6dir.separator = "/"
7 5
8--- Strip the path off a path+filename. 6--- Strip the path off a path+filename.
9-- @param pathname string: A path+name, such as "/a/b/c" 7-- @param pathname string: A path+name, such as "/a/b/c"
@@ -26,49 +24,4 @@ function dir.dir_name(pathname)
26 return (pathname:gsub("/*$", ""):match("(.*)[/]+[^/]*")) or "" 24 return (pathname:gsub("/*$", ""):match("(.*)[/]+[^/]*")) or ""
27end 25end
28 26
29--- Describe a path in a cross-platform way.
30-- Use this function to avoid platform-specific directory
31-- separators in other modules. Removes trailing slashes from
32-- each component given, to avoid repeated separators.
33-- Separators inside strings are kept, to handle URLs containing
34-- protocols.
35-- @param ... strings representing directories
36-- @return string: a string with a platform-specific representation
37-- of the path.
38function dir.path(...)
39 local t = {...}
40 while t[1] == "" do
41 table.remove(t, 1)
42 end
43 return (table.concat(t, "/"):gsub("([^:])/+", "%1/"):gsub("^/+", "/"):gsub("/*$", ""))
44end
45
46--- Split protocol and path from an URL or local pathname.
47-- URLs should be in the "protocol://path" format.
48-- For local pathnames, "file" is returned as the protocol.
49-- @param url string: an URL or a local pathname.
50-- @return string, string: the protocol, and the pathname without the protocol.
51function dir.split_url(url)
52 assert(type(url) == "string")
53
54 local protocol, pathname = url:match("^([^:]*)://(.*)")
55 if not protocol then
56 protocol = "file"
57 pathname = url
58 end
59 return protocol, pathname
60end
61
62--- Normalize a url or local path.
63-- URLs should be in the "protocol://path" format. System independent
64-- forward slashes are used, removing trailing and double slashes
65-- @param url string: an URL or a local pathname.
66-- @return string: Normalized result.
67function dir.normalize(name)
68 local protocol, pathname = dir.split_url(name)
69 pathname = pathname:gsub("\\", "/"):gsub("(.)/*$", "%1"):gsub("//", "/")
70 if protocol ~= "file" then pathname = protocol .."://"..pathname end
71 return pathname
72end
73
74return dir 27return dir
diff --git a/src/luarocks/doc.lua b/src/luarocks/doc.lua
index 423ebe02..5d521276 100644
--- a/src/luarocks/doc.lua
+++ b/src/luarocks/doc.lua
@@ -2,7 +2,6 @@
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.
4local doc = {} 4local doc = {}
5package.loaded["luarocks.doc"] = doc
6 5
7local util = require("luarocks.util") 6local util = require("luarocks.util")
8local search = require("luarocks.search") 7local search = require("luarocks.search")
@@ -12,7 +11,6 @@ local fetch = require("luarocks.fetch")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local download = require("luarocks.download") 12local download = require("luarocks.download")
14 13
15util.add_run_function(doc)
16doc.help_summary = "Show documentation for an installed rock." 14doc.help_summary = "Show documentation for an installed rock."
17 15
18doc.help = [[ 16doc.help = [[
diff --git a/src/luarocks/download.lua b/src/luarocks/download.lua
index e434cdbb..557d1b65 100644
--- a/src/luarocks/download.lua
+++ b/src/luarocks/download.lua
@@ -2,7 +2,6 @@
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.
4local download = {} 4local download = {}
5package.loaded["luarocks.download"] = download
6 5
7local util = require("luarocks.util") 6local util = require("luarocks.util")
8local path = require("luarocks.path") 7local path = require("luarocks.path")
@@ -10,9 +9,8 @@ local fetch = require("luarocks.fetch")
10local search = require("luarocks.search") 9local search = require("luarocks.search")
11local fs = require("luarocks.fs") 10local fs = require("luarocks.fs")
12local dir = require("luarocks.dir") 11local dir = require("luarocks.dir")
13local cfg = require("luarocks.cfg") 12local cfg = require("luarocks.core.cfg")
14 13
15util.add_run_function(download)
16download.help_summary = "Download a specific rock file from a rocks server." 14download.help_summary = "Download a specific rock file from a rocks server."
17download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" 15download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]"
18 16
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua
index 76f366cd..d03de1c6 100644
--- a/src/luarocks/fetch.lua
+++ b/src/luarocks/fetch.lua
@@ -1,7 +1,6 @@
1 1
2--- Functions related to fetching and loading local and remote files. 2--- Functions related to fetching and loading local and remote files.
3local fetch = {} 3local fetch = {}
4package.loaded["luarocks.fetch"] = fetch
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
@@ -10,7 +9,7 @@ local path = require("luarocks.path")
10local deps = require("luarocks.deps") 9local deps = require("luarocks.deps")
11local persist = require("luarocks.persist") 10local persist = require("luarocks.persist")
12local util = require("luarocks.util") 11local util = require("luarocks.util")
13local cfg = require("luarocks.cfg") 12local cfg = require("luarocks.core.cfg")
14 13
15function fetch.is_basic_protocol(protocol, remote) 14function fetch.is_basic_protocol(protocol, remote)
16 return protocol == "http" or protocol == "https" or protocol == "ftp" or (not remote and protocol == "file") 15 return protocol == "http" or protocol == "https" or protocol == "ftp" or (not remote and protocol == "file")
@@ -209,6 +208,8 @@ function fetch.load_local_rockspec(filename, quick)
209 return nil, filename..": "..err 208 return nil, filename..": "..err
210 end 209 end
211 end 210 end
211
212 rockspec.format_is_at_least = deps.format_is_at_least
212 213
213 util.platform_overrides(rockspec.build) 214 util.platform_overrides(rockspec.build)
214 util.platform_overrides(rockspec.dependencies) 215 util.platform_overrides(rockspec.dependencies)
@@ -244,10 +245,19 @@ function fetch.load_local_rockspec(filename, quick)
244 rockspec.local_filename = filename 245 rockspec.local_filename = filename
245 local filebase = rockspec.source.file or rockspec.source.url 246 local filebase = rockspec.source.file or rockspec.source.url
246 local base = fetch.url_to_base_dir(filebase) 247 local base = fetch.url_to_base_dir(filebase)
248 rockspec.source.dir_set = rockspec.source.dir ~= nil
247 rockspec.source.dir = rockspec.source.dir 249 rockspec.source.dir = rockspec.source.dir
248 or rockspec.source.module 250 or rockspec.source.module
249 or ((filebase:match("%.lua$") or filebase:match("%.c$")) and ".") 251 or ( (filebase:match("%.lua$") or filebase:match("%.c$"))
252 and (rockspec:format_is_at_least("3.0")
253 and (fetch.is_basic_protocol(protocol) and "." or base)
254 or ".") )
250 or base 255 or base
256
257 rockspec.rocks_provided = (rockspec:format_is_at_least("3.0")
258 and cfg.rocks_provided_3_0
259 or cfg.rocks_provided)
260
251 if rockspec.dependencies then 261 if rockspec.dependencies then
252 for i = 1, #rockspec.dependencies do 262 for i = 1, #rockspec.dependencies do
253 local parsed, err = deps.parse_dep(rockspec.dependencies[i]) 263 local parsed, err = deps.parse_dep(rockspec.dependencies[i])
@@ -347,7 +357,29 @@ function fetch.get_sources(rockspec, extract, dest_dir)
347 ok, err = fs.unpack_archive(rockspec.source.file) 357 ok, err = fs.unpack_archive(rockspec.source.file)
348 if not ok then return nil, err end 358 if not ok then return nil, err end
349 if not fs.exists(rockspec.source.dir) then 359 if not fs.exists(rockspec.source.dir) then
350 return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file, "source.dir", source_file, store_dir 360
361 -- If rockspec.source.dir can't be found, see if we only have one
362 -- directory in store_dir. If that's the case, assume it's what
363 -- we're looking for.
364 -- We only do this if the rockspec source.dir was not set, and only
365 -- with rockspecs newer than 3.0.
366 local dir_count, found_dir = 0
367
368 if not rockspec.source.dir_set and rockspec:format_is_at_least("3.0") then
369 local files = fs.list_dir()
370 for _, f in ipairs(files) do
371 if fs.is_dir(f) then
372 dir_count = dir_count + 1
373 found_dir = f
374 end
375 end
376 end
377
378 if dir_count == 1 then
379 rockspec.source.dir = found_dir
380 else
381 return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file, "source.dir", source_file, store_dir
382 end
351 end 383 end
352 fs.pop_dir() 384 fs.pop_dir()
353 end 385 end
diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua
index f61d89e9..72da4974 100644
--- a/src/luarocks/fetch/git.lua
+++ b/src/luarocks/fetch/git.lua
@@ -6,20 +6,48 @@ local unpack = unpack or table.unpack
6 6
7local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
8local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
9local deps = require("luarocks.deps")
9local util = require("luarocks.util") 10local util = require("luarocks.util")
10 11
12local cached_git_version
13
14--- Get git version.
15-- @param git_cmd string: name of git command.
16-- @return table: git version as returned by luarocks.deps.parse_version.
17local function git_version(git_cmd)
18 if not cached_git_version then
19 local version_line = io.popen(fs.Q(git_cmd)..' --version'):read()
20 local version_string = version_line:match('%d-%.%d+%.?%d*')
21 cached_git_version = deps.parse_version(version_string)
22 end
23
24 return cached_git_version
25end
26
27--- Check if git satisfies version requirement.
28-- @param git_cmd string: name of git command.
29-- @param version string: required version.
30-- @return boolean: true if git matches version or is newer, false otherwise.
31local function git_is_at_least(git_cmd, version)
32 return git_version(git_cmd) >= deps.parse_version(version)
33end
34
11--- Git >= 1.7.10 can clone a branch **or tag**, < 1.7.10 by branch only. We 35--- Git >= 1.7.10 can clone a branch **or tag**, < 1.7.10 by branch only. We
12-- need to know this in order to build the appropriate command; if we can't 36-- need to know this in order to build the appropriate command; if we can't
13-- clone by tag then we'll have to issue a subsequent command to check out the 37-- clone by tag then we'll have to issue a subsequent command to check out the
14-- given tag. 38-- given tag.
39-- @param git_cmd string: name of git command.
15-- @return boolean: Whether Git can clone by tag. 40-- @return boolean: Whether Git can clone by tag.
16local function git_can_clone_by_tag(git_cmd) 41local function git_can_clone_by_tag(git_cmd)
17 local version_string = io.popen(fs.Q(git_cmd)..' --version'):read() 42 return git_is_at_least(git_cmd, "1.7.10")
18 local major, minor, tiny = version_string:match('(%d-)%.(%d+)%.?(%d*)') 43end
19 major, minor, tiny = tonumber(major), tonumber(minor), tonumber(tiny) or 0 44
20 local value = major > 1 or (major == 1 and (minor > 7 or (minor == 7 and tiny >= 10))) 45--- Git >= 1.8.4 can fetch submodules shallowly, saving bandwidth and time for
21 git_can_clone_by_tag = function() return value end 46-- submodules with large history.
22 return value 47-- @param git_cmd string: name of git command.
48-- @return boolean: Whether Git can fetch submodules shallowly.
49local function git_supports_shallow_submodules(git_cmd)
50 return git_is_at_least(git_cmd, "1.8.4")
23end 51end
24 52
25--- Download sources for building a rock, using git. 53--- Download sources for building a rock, using git.
@@ -76,12 +104,25 @@ function git.get_sources(rockspec, extract, dest_dir, depth)
76 ok, err = fs.change_dir(module) 104 ok, err = fs.change_dir(module)
77 if not ok then return nil, err end 105 if not ok then return nil, err end
78 if tag_or_branch and not git_can_clone_by_tag() then 106 if tag_or_branch and not git_can_clone_by_tag() then
79 local checkout_command = {fs.Q(git_cmd), "checkout", tag_or_branch} 107 if not fs.execute(fs.Q(git_cmd), "checkout", tag_or_branch) then
80 if not fs.execute(unpack(checkout_command)) then
81 return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.' 108 return nil, 'Failed to check out the "' .. tag_or_branch ..'" tag or branch.'
82 end 109 end
83 end 110 end
84 111
112 -- Fetching git submodules is supported only when rockspec format is >= 3.0.
113 if rockspec:format_is_at_least("3.0") then
114 command = {fs.Q(git_cmd), "submodule", "update", "--init", "--recursive"}
115
116 if git_supports_shallow_submodules(git_cmd) then
117 -- Fetch only the last commit of each submodule.
118 table.insert(command, 5, "--depth=1")
119 end
120
121 if not fs.execute(unpack(command)) then
122 return nil, 'Failed to fetch submodules.'
123 end
124 end
125
85 fs.delete(dir.path(store_dir, module, ".git")) 126 fs.delete(dir.path(store_dir, module, ".git"))
86 fs.delete(dir.path(store_dir, module, ".gitignore")) 127 fs.delete(dir.path(store_dir, module, ".gitignore"))
87 fs.pop_dir() 128 fs.pop_dir()
diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua
index 54cc7d73..7322e552 100644
--- a/src/luarocks/fs.lua
+++ b/src/luarocks/fs.lua
@@ -8,9 +8,10 @@
8local pairs = pairs 8local pairs = pairs
9 9
10local fs = {} 10local fs = {}
11-- To avoid a loop when loading the other fs modules.
11package.loaded["luarocks.fs"] = fs 12package.loaded["luarocks.fs"] = fs
12 13
13local cfg = require("luarocks.cfg") 14local cfg = require("luarocks.core.cfg")
14 15
15local pack = table.pack or function(...) return { n = select("#", ...), ... } end 16local pack = table.pack or function(...) return { n = select("#", ...), ... } end
16local unpack = table.unpack or unpack 17local unpack = table.unpack or unpack
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua
index 41711eab..e4c6ca05 100644
--- a/src/luarocks/fs/lua.lua
+++ b/src/luarocks/fs/lua.lua
@@ -6,7 +6,7 @@ local fs_lua = {}
6 6
7local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
8 8
9local cfg = require("luarocks.cfg") 9local cfg = require("luarocks.core.cfg")
10local dir = require("luarocks.dir") 10local dir = require("luarocks.dir")
11local util = require("luarocks.util") 11local util = require("luarocks.util")
12local path = require("luarocks.path") 12local path = require("luarocks.path")
diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua
index ed51b545..d2062ed8 100644
--- a/src/luarocks/fs/tools.lua
+++ b/src/luarocks/fs/tools.lua
@@ -4,7 +4,7 @@ local tools = {}
4 4
5local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
6local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
8 8
9local vars = cfg.variables 9local vars = cfg.variables
10 10
diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua
index e2bdc7b8..aca64ac0 100644
--- a/src/luarocks/fs/unix.lua
+++ b/src/luarocks/fs/unix.lua
@@ -4,7 +4,7 @@ local unix = {}
4 4
5local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
6 6
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
8local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
9local util = require("luarocks.util") 9local util = require("luarocks.util")
10 10
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua
index d0802725..d9dc009f 100644
--- a/src/luarocks/fs/unix/tools.lua
+++ b/src/luarocks/fs/unix/tools.lua
@@ -4,7 +4,7 @@ local tools = {}
4 4
5local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
6local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
8 8
9local vars = cfg.variables 9local vars = cfg.variables
10 10
diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua
index cfc28d35..789913a7 100644
--- a/src/luarocks/fs/win32.lua
+++ b/src/luarocks/fs/win32.lua
@@ -5,7 +5,7 @@ local win32 = {}
5 5
6local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
7 7
8local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.core.cfg")
9local dir = require("luarocks.dir") 9local dir = require("luarocks.dir")
10local util = require("luarocks.util") 10local util = require("luarocks.util")
11 11
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua
index 4adc78d1..7f6b853e 100644
--- a/src/luarocks/fs/win32/tools.lua
+++ b/src/luarocks/fs/win32/tools.lua
@@ -6,7 +6,7 @@ local tools = {}
6 6
7local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
8local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
9local cfg = require("luarocks.cfg") 9local cfg = require("luarocks.core.cfg")
10 10
11local vars = cfg.variables 11local vars = cfg.variables
12 12
diff --git a/src/luarocks/help.lua b/src/luarocks/help.lua
index 871e97e9..d27c3a50 100644
--- a/src/luarocks/help.lua
+++ b/src/luarocks/help.lua
@@ -7,12 +7,11 @@
7local help = {} 7local help = {}
8 8
9local util = require("luarocks.util") 9local util = require("luarocks.util")
10local cfg = require("luarocks.cfg") 10local cfg = require("luarocks.core.cfg")
11local dir = require("luarocks.dir") 11local dir = require("luarocks.dir")
12 12
13local program = util.this_program("luarocks") 13local program = util.this_program("luarocks")
14 14
15util.add_run_function(help)
16help.help_summary = "Help on commands. Type '"..program.." help <command>' for more." 15help.help_summary = "Help on commands. Type '"..program.." help <command>' for more."
17 16
18help.help_arguments = "[<command>]" 17help.help_arguments = "[<command>]"
diff --git a/src/luarocks/index.lua b/src/luarocks/index.lua
index e1f563ef..468f5cf8 100644
--- a/src/luarocks/index.lua
+++ b/src/luarocks/index.lua
@@ -1,7 +1,6 @@
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.
3local index = {} 3local index = {}
4package.loaded["luarocks.index"] = index
5 4
6local util = require("luarocks.util") 5local util = require("luarocks.util")
7local fs = require("luarocks.fs") 6local fs = require("luarocks.fs")
diff --git a/src/luarocks/install.lua b/src/luarocks/install.lua
index e28c24f0..3a33fcae 100644
--- a/src/luarocks/install.lua
+++ b/src/luarocks/install.lua
@@ -1,7 +1,6 @@
1--- Module implementing the LuaRocks "install" command. 1--- Module implementing the LuaRocks "install" command.
2-- Installs binary rocks. 2-- Installs binary rocks.
3local install = {} 3local install = {}
4package.loaded["luarocks.install"] = install
5 4
6local path = require("luarocks.path") 5local path = require("luarocks.path")
7local repos = require("luarocks.repos") 6local repos = require("luarocks.repos")
@@ -9,11 +8,10 @@ local fetch = require("luarocks.fetch")
9local util = require("luarocks.util") 8local util = require("luarocks.util")
10local fs = require("luarocks.fs") 9local fs = require("luarocks.fs")
11local deps = require("luarocks.deps") 10local deps = require("luarocks.deps")
12local manif = require("luarocks.manif") 11local writer = require("luarocks.manif.writer")
13local remove = require("luarocks.remove") 12local remove = require("luarocks.remove")
14local cfg = require("luarocks.cfg") 13local cfg = require("luarocks.core.cfg")
15 14
16util.add_run_function(install)
17install.help_summary = "Install a rock." 15install.help_summary = "Install a rock."
18 16
19install.help_arguments = "{<rock>|<name> [<version>]}" 17install.help_arguments = "{<rock>|<name> [<version>]}"
@@ -75,7 +73,7 @@ function install.install_binary_rock(rock_file, deps_mode)
75 73
76 -- For compatibility with .rock files built with LuaRocks 1 74 -- For compatibility with .rock files built with LuaRocks 1
77 if not fs.exists(path.rock_manifest_file(name, version)) then 75 if not fs.exists(path.rock_manifest_file(name, version)) then
78 ok, err = manif.make_rock_manifest(name, version) 76 ok, err = writer.make_rock_manifest(name, version)
79 if err then return nil, err end 77 if err then return nil, err end
80 end 78 end
81 79
@@ -172,7 +170,7 @@ function install.command(flags, name, version)
172 if not ok then util.printerr(err) end 170 if not ok then util.printerr(err) end
173 end 171 end
174 172
175 manif.check_dependencies(nil, deps.get_deps_mode(flags)) 173 writer.check_dependencies(nil, deps.get_deps_mode(flags))
176 return name, version 174 return name, version
177 else 175 else
178 local search = require("luarocks.search") 176 local search = require("luarocks.search")
diff --git a/src/luarocks/lint.lua b/src/luarocks/lint.lua
index 0fd81a20..c9ea45ea 100644
--- a/src/luarocks/lint.lua
+++ b/src/luarocks/lint.lua
@@ -2,13 +2,11 @@
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.
4local lint = {} 4local lint = {}
5package.loaded["luarocks.lint"] = lint
6 5
7local util = require("luarocks.util") 6local util = require("luarocks.util")
8local download = require("luarocks.download") 7local download = require("luarocks.download")
9local fetch = require("luarocks.fetch") 8local fetch = require("luarocks.fetch")
10 9
11util.add_run_function(lint)
12lint.help_summary = "Check syntax of a rockspec." 10lint.help_summary = "Check syntax of a rockspec."
13lint.help_arguments = "<rockspec>" 11lint.help_arguments = "<rockspec>"
14lint.help = [[ 12lint.help = [[
diff --git a/src/luarocks/list.lua b/src/luarocks/list.lua
index c65e058f..45f1a26f 100644
--- a/src/luarocks/list.lua
+++ b/src/luarocks/list.lua
@@ -2,15 +2,13 @@
2--- Module implementing the LuaRocks "list" command. 2--- Module implementing the LuaRocks "list" command.
3-- Lists currently installed rocks. 3-- Lists currently installed rocks.
4local list = {} 4local list = {}
5package.loaded["luarocks.list"] = list
6 5
7local search = require("luarocks.search") 6local search = require("luarocks.search")
8local deps = require("luarocks.deps") 7local deps = require("luarocks.deps")
9local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.core.cfg")
10local util = require("luarocks.util") 9local util = require("luarocks.util")
11local path = require("luarocks.path") 10local path = require("luarocks.path")
12 11
13util.add_run_function(list)
14list.help_summary = "List currently installed rocks." 12list.help_summary = "List currently installed rocks."
15list.help_arguments = "[--porcelain] <filter>" 13list.help_arguments = "[--porcelain] <filter>"
16list.help = [[ 14list.help = [[
diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua
index 874bc10c..b8072110 100644
--- a/src/luarocks/loader.lua
+++ b/src/luarocks/loader.lua
@@ -6,21 +6,24 @@
6-- used to load previous modules, so that the loader chooses versions 6-- used to load previous modules, so that the loader chooses versions
7-- that are declared to be compatible with the ones loaded earlier. 7-- that are declared to be compatible with the ones loaded earlier.
8local loaders = package.loaders or package.searchers 8local loaders = package.loaders or package.searchers
9local package, require, ipairs, table, type, next, tostring, error = 9local require, ipairs, table, type, next, tostring, error =
10 package, require, ipairs, table, type, next, tostring, error 10 require, ipairs, table, type, next, tostring, error
11local unpack = unpack or table.unpack 11local unpack = unpack or table.unpack
12 12
13--module("luarocks.loader")
14local loader = {} 13local loader = {}
15package.loaded["luarocks.loader"] = loader
16 14
17local cfg = require("luarocks.cfg") 15local is_clean = not package.loaded["luarocks.core.cfg"]
16
17-- This loader module depends only on core modules.
18local cfg = require("luarocks.core.cfg")
18cfg.init_package_paths() 19cfg.init_package_paths()
19 20
20local path = require("luarocks.path") 21local path = require("luarocks.core.path")
21local manif_core = require("luarocks.manif_core") 22local manif = require("luarocks.core.manif")
22local deps = require("luarocks.deps") 23local deps = require("luarocks.core.deps")
23local util = require("luarocks.util") 24local util = require("luarocks.core.util")
25local require = nil
26--------------------------------------------------------------------------------
24 27
25-- Workaround for wrappers produced by older versions of LuaRocks 28-- Workaround for wrappers produced by older versions of LuaRocks
26local temporary_global = false 29local temporary_global = false
@@ -55,7 +58,7 @@ local function load_rocks_trees()
55 local any_ok = false 58 local any_ok = false
56 local trees = {} 59 local trees = {}
57 for _, tree in ipairs(cfg.rocks_trees) do 60 for _, tree in ipairs(cfg.rocks_trees) do
58 local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree)) 61 local manifest, err = manif.load_local_manifest(path.rocks_dir(tree))
59 if manifest then 62 if manifest then
60 any_ok = true 63 any_ok = true
61 table.insert(trees, {tree=tree, manifest=manifest}) 64 table.insert(trees, {tree=tree, manifest=manifest})
@@ -246,4 +249,12 @@ end
246 249
247table.insert(loaders, 1, loader.luarocks_loader) 250table.insert(loaders, 1, loader.luarocks_loader)
248 251
252if is_clean then
253 for modname, _ in pairs(package.loaded) do
254 if modname:match("^luarocks%.") then
255 package.loaded[modname] = nil
256 end
257 end
258end
259
249return loader 260return loader
diff --git a/src/luarocks/make.lua b/src/luarocks/make.lua
index 15167c1e..d3d02814 100644
--- a/src/luarocks/make.lua
+++ b/src/luarocks/make.lua
@@ -4,19 +4,17 @@
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.
6local make = {} 6local make = {}
7package.loaded["luarocks.make"] = make
8 7
9local build = require("luarocks.build") 8local build = require("luarocks.build")
10local fs = require("luarocks.fs") 9local fs = require("luarocks.fs")
11local util = require("luarocks.util") 10local util = require("luarocks.util")
12local cfg = require("luarocks.cfg") 11local cfg = require("luarocks.core.cfg")
13local fetch = require("luarocks.fetch") 12local fetch = require("luarocks.fetch")
14local pack = require("luarocks.pack") 13local pack = require("luarocks.pack")
15local remove = require("luarocks.remove") 14local remove = require("luarocks.remove")
16local deps = require("luarocks.deps") 15local deps = require("luarocks.deps")
17local manif = require("luarocks.manif") 16local writer = require("luarocks.manif.writer")
18 17
19util.add_run_function(make)
20make.help_summary = "Compile package in current directory using a rockspec." 18make.help_summary = "Compile package in current directory using a rockspec."
21make.help_arguments = "[--pack-binary-rock] [<rockspec>]" 19make.help_arguments = "[--pack-binary-rock] [<rockspec>]"
22make.help = [[ 20make.help = [[
@@ -84,7 +82,7 @@ function make.command(flags, rockspec)
84 if not ok then util.printerr(err) end 82 if not ok then util.printerr(err) end
85 end 83 end
86 84
87 manif.check_dependencies(nil, deps.get_deps_mode(flags)) 85 writer.check_dependencies(nil, deps.get_deps_mode(flags))
88 return name, version 86 return name, version
89 end 87 end
90end 88end
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua
index 86209d06..8277b3a5 100644
--- a/src/luarocks/manif.lua
+++ b/src/luarocks/manif.lua
@@ -3,41 +3,18 @@
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.
5local manif = {} 5local manif = {}
6package.loaded["luarocks.manif"] = manif 6setmetatable(manif, { __index = require("luarocks.core.manif") })
7 7
8local manif_core = require("luarocks.manif_core")
9local persist = require("luarocks.persist") 8local persist = require("luarocks.persist")
10local fetch = require("luarocks.fetch") 9local fetch = require("luarocks.fetch")
11local dir = require("luarocks.dir") 10local dir = require("luarocks.dir")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local search = require("luarocks.search")
14local util = require("luarocks.util") 12local util = require("luarocks.util")
15local cfg = require("luarocks.cfg") 13local cfg = require("luarocks.core.cfg")
16local path = require("luarocks.path") 14local path = require("luarocks.path")
17local repos = require("luarocks.repos")
18local deps = require("luarocks.deps")
19 15
20manif.rock_manifest_cache = {} 16manif.rock_manifest_cache = {}
21 17
22--- Commit a table to disk in given local path.
23-- @param where string: The directory where the table should be saved.
24-- @param name string: The filename.
25-- @param tbl table: The table to be saved.
26-- @return boolean or (nil, string): true if successful, or nil and a
27-- message in case of errors.
28local function save_table(where, name, tbl)
29 assert(type(where) == "string")
30 assert(type(name) == "string")
31 assert(type(tbl) == "table")
32
33 local filename = dir.path(where, name)
34 local ok, err = persist.save_from_table(filename..".tmp", tbl)
35 if ok then
36 ok, err = fs.replace_file(filename, filename..".tmp")
37 end
38 return ok, err
39end
40
41function manif.load_rock_manifest(name, version, root) 18function manif.load_rock_manifest(name, version, root)
42 assert(type(name) == "string") 19 assert(type(name) == "string")
43 assert(type(version) == "string") 20 assert(type(version) == "string")
@@ -48,41 +25,13 @@ function manif.load_rock_manifest(name, version, root)
48 end 25 end
49 local pathname = path.rock_manifest_file(name, version, root) 26 local pathname = path.rock_manifest_file(name, version, root)
50 local rock_manifest = persist.load_into_table(pathname) 27 local rock_manifest = persist.load_into_table(pathname)
51 if not rock_manifest then return nil end 28 if not rock_manifest then
29 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks tree?"
30 end
52 manif.rock_manifest_cache[name_version] = rock_manifest 31 manif.rock_manifest_cache[name_version] = rock_manifest
53 return rock_manifest.rock_manifest 32 return rock_manifest.rock_manifest
54end 33end
55 34
56function manif.make_rock_manifest(name, version)
57 local install_dir = path.install_dir(name, version)
58 local tree = {}
59 for _, file in ipairs(fs.find(install_dir)) do
60 local full_path = dir.path(install_dir, file)
61 local walk = tree
62 local last
63 local last_name
64 for name in file:gmatch("[^/]+") do
65 local next = walk[name]
66 if not next then
67 next = {}
68 walk[name] = next
69 end
70 last = walk
71 last_name = name
72 walk = next
73 end
74 if fs.is_file(full_path) then
75 local sum, err = fs.get_md5(full_path)
76 if not sum then
77 return nil, "Failed producing checksum: "..tostring(err)
78 end
79 last[last_name] = sum
80 end
81 end
82 local rock_manifest = { rock_manifest=tree }
83 manif.rock_manifest_cache[name.."/"..version] = rock_manifest
84 save_table(install_dir, "rock_manifest", rock_manifest )
85end
86 35
87local function fetch_manifest_from(repo_url, filename) 36local function fetch_manifest_from(repo_url, filename)
88 local url = dir.path(repo_url, filename) 37 local url = dir.path(repo_url, filename)
@@ -111,7 +60,7 @@ function manif.load_manifest(repo_url, lua_version)
111 assert(type(lua_version) == "string" or not lua_version) 60 assert(type(lua_version) == "string" or not lua_version)
112 lua_version = lua_version or cfg.lua_version 61 lua_version = lua_version or cfg.lua_version
113 62
114 local cached_manifest = manif_core.get_cached_manifest(repo_url, lua_version) 63 local cached_manifest = manif.get_cached_manifest(repo_url, lua_version)
115 if cached_manifest then 64 if cached_manifest then
116 return cached_manifest 65 return cached_manifest
117 end 66 end
@@ -158,386 +107,7 @@ function manif.load_manifest(repo_url, lua_version)
158 end 107 end
159 pathname = nozip 108 pathname = nozip
160 end 109 end
161 return manif_core.manifest_loader(pathname, repo_url, lua_version) 110 return manif.manifest_loader(pathname, repo_url, lua_version)
162end
163
164--- Update storage table to account for items provided by a package.
165-- @param storage table: a table storing items in the following format:
166-- keys are item names and values are arrays of packages providing each item,
167-- where a package is specified as string `name/version`.
168-- @param items table: a table mapping item names to paths.
169-- @param name string: package name.
170-- @param version string: package version.
171local function store_package_items(storage, name, version, items)
172 assert(type(storage) == "table")
173 assert(type(items) == "table")
174 assert(type(name) == "string")
175 assert(type(version) == "string")
176
177 local package_identifier = name.."/"..version
178
179 for item_name, path in pairs(items) do
180 if not storage[item_name] then
181 storage[item_name] = {}
182 end
183
184 table.insert(storage[item_name], package_identifier)
185 end
186end
187
188--- Update storage table removing items provided by a package.
189-- @param storage table: a table storing items in the following format:
190-- keys are item names and values are arrays of packages providing each item,
191-- where a package is specified as string `name/version`.
192-- @param items table: a table mapping item names to paths.
193-- @param name string: package name.
194-- @param version string: package version.
195local function remove_package_items(storage, name, version, items)
196 assert(type(storage) == "table")
197 assert(type(items) == "table")
198 assert(type(name) == "string")
199 assert(type(version) == "string")
200
201 local package_identifier = name.."/"..version
202
203 for item_name, path in pairs(items) do
204 local all_identifiers = storage[item_name]
205
206 for i, identifier in ipairs(all_identifiers) do
207 if identifier == package_identifier then
208 table.remove(all_identifiers, i)
209 break
210 end
211 end
212
213 if #all_identifiers == 0 then
214 storage[item_name] = nil
215 end
216 end
217end
218
219--- Sort function for ordering rock identifiers in a manifest's
220-- modules table. Rocks are ordered alphabetically by name, and then
221-- by version which greater first.
222-- @param a string: Version to compare.
223-- @param b string: Version to compare.
224-- @return boolean: The comparison result, according to the
225-- rule outlined above.
226local function sort_pkgs(a, b)
227 assert(type(a) == "string")
228 assert(type(b) == "string")
229
230 local na, va = a:match("(.*)/(.*)$")
231 local nb, vb = b:match("(.*)/(.*)$")
232
233 return (na == nb) and deps.compare_versions(va, vb) or na < nb
234end
235
236--- Sort items of a package matching table by version number (higher versions first).
237-- @param tbl table: the package matching table: keys should be strings
238-- and values arrays of strings with packages names in "name/version" format.
239local function sort_package_matching_table(tbl)
240 assert(type(tbl) == "table")
241
242 if next(tbl) then
243 for item, pkgs in pairs(tbl) do
244 if #pkgs > 1 then
245 table.sort(pkgs, sort_pkgs)
246 -- Remove duplicates from the sorted array.
247 local prev = nil
248 local i = 1
249 while pkgs[i] do
250 local curr = pkgs[i]
251 if curr == prev then
252 table.remove(pkgs, i)
253 else
254 prev = curr
255 i = i + 1
256 end
257 end
258 end
259 end
260 end
261end
262
263--- Process the dependencies of a manifest table to determine its dependency
264-- chains for loading modules. The manifest dependencies information is filled
265-- and any dependency inconsistencies or missing dependencies are reported to
266-- standard error.
267-- @param manifest table: a manifest table.
268-- @param deps_mode string: Dependency mode: "one" for the current default tree,
269-- "all" for all trees, "order" for all trees with priority >= the current default,
270-- "none" for no trees.
271local function update_dependencies(manifest, deps_mode)
272 assert(type(manifest) == "table")
273 assert(type(deps_mode) == "string")
274
275 for pkg, versions in pairs(manifest.repository) do
276 for version, repositories in pairs(versions) do
277 for _, repo in ipairs(repositories) do
278 if repo.arch == "installed" then
279 repo.dependencies = {}
280 deps.scan_deps(repo.dependencies, manifest, pkg, version, deps_mode)
281 repo.dependencies[pkg] = nil
282 end
283 end
284 end
285 end
286end
287
288--- Filter manifest table by Lua version, removing rockspecs whose Lua version
289-- does not match.
290-- @param manifest table: a manifest table.
291-- @param lua_version string or nil: filter by Lua version
292-- @param repodir string: directory of repository being scanned
293-- @param cache table: temporary rockspec cache table
294local function filter_by_lua_version(manifest, lua_version, repodir, cache)
295 assert(type(manifest) == "table")
296 assert(type(repodir) == "string")
297 assert((not cache) or type(cache) == "table")
298
299 cache = cache or {}
300 lua_version = deps.parse_version(lua_version)
301 for pkg, versions in pairs(manifest.repository) do
302 local to_remove = {}
303 for version, repositories in pairs(versions) do
304 for _, repo in ipairs(repositories) do
305 if repo.arch == "rockspec" then
306 local pathname = dir.path(repodir, pkg.."-"..version..".rockspec")
307 local rockspec, err = cache[pathname]
308 if not rockspec then
309 rockspec, err = fetch.load_local_rockspec(pathname, true)
310 end
311 if rockspec then
312 cache[pathname] = rockspec
313 for _, dep in ipairs(rockspec.dependencies) do
314 if dep.name == "lua" then
315 if not deps.match_constraints(lua_version, dep.constraints) then
316 table.insert(to_remove, version)
317 end
318 break
319 end
320 end
321 else
322 util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err)
323 end
324 end
325 end
326 end
327 if next(to_remove) then
328 for _, incompat in ipairs(to_remove) do
329 versions[incompat] = nil
330 end
331 if not next(versions) then
332 manifest.repository[pkg] = nil
333 end
334 end
335 end
336end
337
338--- Store search results in a manifest table.
339-- @param results table: The search results as returned by search.disk_search.
340-- @param manifest table: A manifest table (must contain repository, modules, commands tables).
341-- It will be altered to include the search results.
342-- @return boolean or (nil, string): true in case of success, or nil followed by an error message.
343local function store_results(results, manifest)
344 assert(type(results) == "table")
345 assert(type(manifest) == "table")
346
347 for name, versions in pairs(results) do
348 local pkgtable = manifest.repository[name] or {}
349 for version, entries in pairs(versions) do
350 local versiontable = {}
351 for _, entry in ipairs(entries) do
352 local entrytable = {}
353 entrytable.arch = entry.arch
354 if entry.arch == "installed" then
355 local rock_manifest = manif.load_rock_manifest(name, version)
356 if not rock_manifest then
357 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
358 end
359
360 entrytable.modules = repos.package_modules(name, version)
361 store_package_items(manifest.modules, name, version, entrytable.modules)
362 entrytable.commands = repos.package_commands(name, version)
363 store_package_items(manifest.commands, name, version, entrytable.commands)
364 end
365 table.insert(versiontable, entrytable)
366 end
367 pkgtable[version] = versiontable
368 end
369 manifest.repository[name] = pkgtable
370 end
371 sort_package_matching_table(manifest.modules)
372 sort_package_matching_table(manifest.commands)
373 return true
374end
375
376--- Scan a LuaRocks repository and output a manifest file.
377-- A file called 'manifest' will be written in the root of the given
378-- repository directory.
379-- @param repo A local repository directory.
380-- @param deps_mode string: Dependency mode: "one" for the current default tree,
381-- "all" for all trees, "order" for all trees with priority >= the current default,
382-- "none" for the default dependency mode from the configuration.
383-- @param remote boolean: 'true' if making a manifest for a rocks server.
384-- @return boolean or (nil, string): True if manifest was generated,
385-- or nil and an error message.
386function manif.make_manifest(repo, deps_mode, remote)
387 assert(type(repo) == "string")
388 assert(type(deps_mode) == "string")
389
390 if deps_mode == "none" then deps_mode = cfg.deps_mode end
391
392 if not fs.is_dir(repo) then
393 return nil, "Cannot access repository at "..repo
394 end
395
396 local query = search.make_query("")
397 query.exact_name = false
398 query.arch = "any"
399 local results = search.disk_search(repo, query)
400 local manifest = { repository = {}, modules = {}, commands = {} }
401
402 manif_core.cache_manifest(repo, nil, manifest)
403
404 local ok, err = store_results(results, manifest)
405 if not ok then return nil, err end
406
407 if remote then
408 local cache = {}
409 for luaver in util.lua_versions() do
410 local vmanifest = { repository = {}, modules = {}, commands = {} }
411 local ok, err = store_results(results, vmanifest)
412 filter_by_lua_version(vmanifest, luaver, repo, cache)
413 save_table(repo, "manifest-"..luaver, vmanifest)
414 end
415 else
416 update_dependencies(manifest, deps_mode)
417 end
418
419 return save_table(repo, "manifest", manifest)
420end
421
422--- Update manifest file for a local repository
423-- adding information about a version of a package installed in that repository.
424-- @param name string: Name of a package from the repository.
425-- @param version string: Version of a package from the repository.
426-- @param repo string or nil: Pathname of a local repository. If not given,
427-- the default local repository is used.
428-- @param deps_mode string: Dependency mode: "one" for the current default tree,
429-- "all" for all trees, "order" for all trees with priority >= the current default,
430-- "none" for using the default dependency mode from the configuration.
431-- @return boolean or (nil, string): True if manifest was updated successfully,
432-- or nil and an error message.
433function manif.add_to_manifest(name, version, repo, deps_mode)
434 assert(type(name) == "string")
435 assert(type(version) == "string")
436 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
437 assert(type(deps_mode) == "string")
438
439 if deps_mode == "none" then deps_mode = cfg.deps_mode end
440
441 local manifest, err = manif_core.load_local_manifest(rocks_dir)
442 if not manifest then
443 util.printerr("No existing manifest. Attempting to rebuild...")
444 -- Manifest built by `manif.make_manifest` should already
445 -- include information about given name and version,
446 -- no need to update it.
447 return manif.make_manifest(rocks_dir, deps_mode)
448 end
449
450 local results = {[name] = {[version] = {{arch = "installed", repo = rocks_dir}}}}
451
452 local ok, err = store_results(results, manifest)
453 if not ok then return nil, err end
454
455 update_dependencies(manifest, deps_mode)
456 return save_table(rocks_dir, "manifest", manifest)
457end
458
459--- Update manifest file for a local repository
460-- removing information about a version of a package.
461-- @param name string: Name of a package removed from the repository.
462-- @param version string: Version of a package removed from the repository.
463-- @param repo string or nil: Pathname of a local repository. If not given,
464-- the default local repository is used.
465-- @param deps_mode string: Dependency mode: "one" for the current default tree,
466-- "all" for all trees, "order" for all trees with priority >= the current default,
467-- "none" for using the default dependency mode from the configuration.
468-- @return boolean or (nil, string): True if manifest was updated successfully,
469-- or nil and an error message.
470function manif.remove_from_manifest(name, version, repo, deps_mode)
471 assert(type(name) == "string")
472 assert(type(version) == "string")
473 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
474 assert(type(deps_mode) == "string")
475
476 if deps_mode == "none" then deps_mode = cfg.deps_mode end
477
478 local manifest, err = manif_core.load_local_manifest(rocks_dir)
479 if not manifest then
480 util.printerr("No existing manifest. Attempting to rebuild...")
481 -- Manifest built by `manif.make_manifest` should already
482 -- include up-to-date information, no need to update it.
483 return manif.make_manifest(rocks_dir, deps_mode)
484 end
485
486 local package_entry = manifest.repository[name]
487
488 local version_entry = package_entry[version][1]
489 remove_package_items(manifest.modules, name, version, version_entry.modules)
490 remove_package_items(manifest.commands, name, version, version_entry.commands)
491
492 package_entry[version] = nil
493 manifest.dependencies[name][version] = nil
494
495 if not next(package_entry) then
496 -- No more versions of this package.
497 manifest.repository[name] = nil
498 manifest.dependencies[name] = nil
499 end
500
501 update_dependencies(manifest, deps_mode)
502 return save_table(rocks_dir, "manifest", manifest)
503end
504
505--- Report missing dependencies for all rocks installed in a repository.
506-- @param repo string or nil: Pathname of a local repository. If not given,
507-- the default local repository is used.
508-- @param deps_mode string: Dependency mode: "one" for the current default tree,
509-- "all" for all trees, "order" for all trees with priority >= the current default,
510-- "none" for using the default dependency mode from the configuration.
511function manif.check_dependencies(repo, deps_mode)
512 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
513 assert(type(deps_mode) == "string")
514 if deps_mode == "none" then deps_mode = cfg.deps_mode end
515
516 local manifest = manif_core.load_local_manifest(rocks_dir)
517 if not manifest then
518 return
519 end
520
521 for name, versions in util.sortedpairs(manifest.repository) do
522 for version, version_entries in util.sortedpairs(versions, deps.compare_versions) do
523 for _, entry in ipairs(version_entries) do
524 if entry.arch == "installed" then
525 if manifest.dependencies[name] and manifest.dependencies[name][version] then
526 deps.report_missing_dependencies(name, version, manifest.dependencies[name][version], deps_mode)
527 end
528 end
529 end
530 end
531 end
532end
533
534function manif.zip_manifests()
535 for ver in util.lua_versions() do
536 local file = "manifest-"..ver
537 local zip = file..".zip"
538 fs.delete(dir.path(fs.current_dir(), zip))
539 fs.zip(zip, file)
540 end
541end 111end
542 112
543local function relative_path(from_dir, to_file) 113local function relative_path(from_dir, to_file)
@@ -565,7 +135,7 @@ local function find_providers(file, root)
565 assert(type(file) == "string") 135 assert(type(file) == "string")
566 root = root or cfg.root_dir 136 root = root or cfg.root_dir
567 137
568 local manifest, err = manif_core.load_local_manifest(path.rocks_dir(root)) 138 local manifest, err = manif.load_local_manifest(path.rocks_dir(root))
569 if not manifest then 139 if not manifest then
570 return nil, "untracked" 140 return nil, "untracked"
571 end 141 end
@@ -611,7 +181,7 @@ end
611function manif.find_conflicting_file(name, version, file, root) 181function manif.find_conflicting_file(name, version, file, root)
612 root = root or cfg.root_dir 182 root = root or cfg.root_dir
613 183
614 local manifest = manif_core.load_local_manifest(path.rocks_dir(root)) 184 local manifest = manif.load_local_manifest(path.rocks_dir(root))
615 if not manifest then 185 if not manifest then
616 return 186 return
617 end 187 end
diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua
new file mode 100644
index 00000000..cf35f38d
--- /dev/null
+++ b/src/luarocks/manif/writer.lua
@@ -0,0 +1,436 @@
1
2local writer = {}
3
4local cfg = require("luarocks.core.cfg")
5local search = require("luarocks.search")
6local repos = require("luarocks.repos")
7local deps = require("luarocks.deps")
8local fs = require("luarocks.fs")
9local util = require("luarocks.util")
10local dir = require("luarocks.dir")
11local fetch = require("luarocks.fetch")
12local path = require("luarocks.path")
13local persist = require("luarocks.persist")
14local manif = require("luarocks.manif")
15
16--- Update storage table to account for items provided by a package.
17-- @param storage table: a table storing items in the following format:
18-- keys are item names and values are arrays of packages providing each item,
19-- where a package is specified as string `name/version`.
20-- @param items table: a table mapping item names to paths.
21-- @param name string: package name.
22-- @param version string: package version.
23local function store_package_items(storage, name, version, items)
24 assert(type(storage) == "table")
25 assert(type(items) == "table")
26 assert(type(name) == "string")
27 assert(type(version) == "string")
28
29 local package_identifier = name.."/"..version
30
31 for item_name, path in pairs(items) do
32 if not storage[item_name] then
33 storage[item_name] = {}
34 end
35
36 table.insert(storage[item_name], package_identifier)
37 end
38end
39
40--- Update storage table removing items provided by a package.
41-- @param storage table: a table storing items in the following format:
42-- keys are item names and values are arrays of packages providing each item,
43-- where a package is specified as string `name/version`.
44-- @param items table: a table mapping item names to paths.
45-- @param name string: package name.
46-- @param version string: package version.
47local function remove_package_items(storage, name, version, items)
48 assert(type(storage) == "table")
49 assert(type(items) == "table")
50 assert(type(name) == "string")
51 assert(type(version) == "string")
52
53 local package_identifier = name.."/"..version
54
55 for item_name, path in pairs(items) do
56 local all_identifiers = storage[item_name]
57
58 for i, identifier in ipairs(all_identifiers) do
59 if identifier == package_identifier then
60 table.remove(all_identifiers, i)
61 break
62 end
63 end
64
65 if #all_identifiers == 0 then
66 storage[item_name] = nil
67 end
68 end
69end
70
71--- Process the dependencies of a manifest table to determine its dependency
72-- chains for loading modules. The manifest dependencies information is filled
73-- and any dependency inconsistencies or missing dependencies are reported to
74-- standard error.
75-- @param manifest table: a manifest table.
76-- @param deps_mode string: Dependency mode: "one" for the current default tree,
77-- "all" for all trees, "order" for all trees with priority >= the current default,
78-- "none" for no trees.
79local function update_dependencies(manifest, deps_mode)
80 assert(type(manifest) == "table")
81 assert(type(deps_mode) == "string")
82
83 for pkg, versions in pairs(manifest.repository) do
84 for version, repositories in pairs(versions) do
85 for _, repo in ipairs(repositories) do
86 if repo.arch == "installed" then
87 repo.dependencies = {}
88 deps.scan_deps(repo.dependencies, {}, manifest, pkg, version, deps_mode)
89 repo.dependencies[pkg] = nil
90 end
91 end
92 end
93 end
94end
95
96--- Sort function for ordering rock identifiers in a manifest's
97-- modules table. Rocks are ordered alphabetically by name, and then
98-- by version which greater first.
99-- @param a string: Version to compare.
100-- @param b string: Version to compare.
101-- @return boolean: The comparison result, according to the
102-- rule outlined above.
103local function sort_pkgs(a, b)
104 assert(type(a) == "string")
105 assert(type(b) == "string")
106
107 local na, va = a:match("(.*)/(.*)$")
108 local nb, vb = b:match("(.*)/(.*)$")
109
110 return (na == nb) and deps.compare_versions(va, vb) or na < nb
111end
112
113--- Sort items of a package matching table by version number (higher versions first).
114-- @param tbl table: the package matching table: keys should be strings
115-- and values arrays of strings with packages names in "name/version" format.
116local function sort_package_matching_table(tbl)
117 assert(type(tbl) == "table")
118
119 if next(tbl) then
120 for item, pkgs in pairs(tbl) do
121 if #pkgs > 1 then
122 table.sort(pkgs, sort_pkgs)
123 -- Remove duplicates from the sorted array.
124 local prev = nil
125 local i = 1
126 while pkgs[i] do
127 local curr = pkgs[i]
128 if curr == prev then
129 table.remove(pkgs, i)
130 else
131 prev = curr
132 i = i + 1
133 end
134 end
135 end
136 end
137 end
138end
139
140--- Filter manifest table by Lua version, removing rockspecs whose Lua version
141-- does not match.
142-- @param manifest table: a manifest table.
143-- @param lua_version string or nil: filter by Lua version
144-- @param repodir string: directory of repository being scanned
145-- @param cache table: temporary rockspec cache table
146local function filter_by_lua_version(manifest, lua_version, repodir, cache)
147 assert(type(manifest) == "table")
148 assert(type(repodir) == "string")
149 assert((not cache) or type(cache) == "table")
150
151 cache = cache or {}
152 lua_version = deps.parse_version(lua_version)
153 for pkg, versions in pairs(manifest.repository) do
154 local to_remove = {}
155 for version, repositories in pairs(versions) do
156 for _, repo in ipairs(repositories) do
157 if repo.arch == "rockspec" then
158 local pathname = dir.path(repodir, pkg.."-"..version..".rockspec")
159 local rockspec, err = cache[pathname]
160 if not rockspec then
161 rockspec, err = fetch.load_local_rockspec(pathname, true)
162 end
163 if rockspec then
164 cache[pathname] = rockspec
165 for _, dep in ipairs(rockspec.dependencies) do
166 if dep.name == "lua" then
167 if not deps.match_constraints(lua_version, dep.constraints) then
168 table.insert(to_remove, version)
169 end
170 break
171 end
172 end
173 else
174 util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err)
175 end
176 end
177 end
178 end
179 if next(to_remove) then
180 for _, incompat in ipairs(to_remove) do
181 versions[incompat] = nil
182 end
183 if not next(versions) then
184 manifest.repository[pkg] = nil
185 end
186 end
187 end
188end
189
190--- Store search results in a manifest table.
191-- @param results table: The search results as returned by search.disk_search.
192-- @param manifest table: A manifest table (must contain repository, modules, commands tables).
193-- It will be altered to include the search results.
194-- @return boolean or (nil, string): true in case of success, or nil followed by an error message.
195local function store_results(results, manifest)
196 assert(type(results) == "table")
197 assert(type(manifest) == "table")
198
199 for name, versions in pairs(results) do
200 local pkgtable = manifest.repository[name] or {}
201 for version, entries in pairs(versions) do
202 local versiontable = {}
203 for _, entry in ipairs(entries) do
204 local entrytable = {}
205 entrytable.arch = entry.arch
206 if entry.arch == "installed" then
207 local rock_manifest = manif.load_rock_manifest(name, version)
208 if not rock_manifest then
209 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
210 end
211
212 entrytable.modules = repos.package_modules(name, version)
213 store_package_items(manifest.modules, name, version, entrytable.modules)
214 entrytable.commands = repos.package_commands(name, version)
215 store_package_items(manifest.commands, name, version, entrytable.commands)
216 end
217 table.insert(versiontable, entrytable)
218 end
219 pkgtable[version] = versiontable
220 end
221 manifest.repository[name] = pkgtable
222 end
223 sort_package_matching_table(manifest.modules)
224 sort_package_matching_table(manifest.commands)
225 return true
226end
227
228--- Commit a table to disk in given local path.
229-- @param where string: The directory where the table should be saved.
230-- @param name string: The filename.
231-- @param tbl table: The table to be saved.
232-- @return boolean or (nil, string): true if successful, or nil and a
233-- message in case of errors.
234local function save_table(where, name, tbl)
235 assert(type(where) == "string")
236 assert(type(name) == "string")
237 assert(type(tbl) == "table")
238
239 local filename = dir.path(where, name)
240 local ok, err = persist.save_from_table(filename..".tmp", tbl)
241 if ok then
242 ok, err = fs.replace_file(filename, filename..".tmp")
243 end
244 return ok, err
245end
246
247function writer.make_rock_manifest(name, version)
248 local install_dir = path.install_dir(name, version)
249 local tree = {}
250 for _, file in ipairs(fs.find(install_dir)) do
251 local full_path = dir.path(install_dir, file)
252 local walk = tree
253 local last
254 local last_name
255 for filename in file:gmatch("[^/]+") do
256 local next = walk[filename]
257 if not next then
258 next = {}
259 walk[filename] = next
260 end
261 last = walk
262 last_name = filename
263 walk = next
264 end
265 if fs.is_file(full_path) then
266 local sum, err = fs.get_md5(full_path)
267 if not sum then
268 return nil, "Failed producing checksum: "..tostring(err)
269 end
270 last[last_name] = sum
271 end
272 end
273 local rock_manifest = { rock_manifest=tree }
274 manif.rock_manifest_cache[name.."/"..version] = rock_manifest
275 save_table(install_dir, "rock_manifest", rock_manifest )
276end
277
278--- Scan a LuaRocks repository and output a manifest file.
279-- A file called 'manifest' will be written in the root of the given
280-- repository directory.
281-- @param repo A local repository directory.
282-- @param deps_mode string: Dependency mode: "one" for the current default tree,
283-- "all" for all trees, "order" for all trees with priority >= the current default,
284-- "none" for the default dependency mode from the configuration.
285-- @param remote boolean: 'true' if making a manifest for a rocks server.
286-- @return boolean or (nil, string): True if manifest was generated,
287-- or nil and an error message.
288function writer.make_manifest(repo, deps_mode, remote)
289 assert(type(repo) == "string")
290 assert(type(deps_mode) == "string")
291
292 if deps_mode == "none" then deps_mode = cfg.deps_mode end
293
294 if not fs.is_dir(repo) then
295 return nil, "Cannot access repository at "..repo
296 end
297
298 local query = search.make_query("")
299 query.exact_name = false
300 query.arch = "any"
301 local results = search.disk_search(repo, query)
302 local manifest = { repository = {}, modules = {}, commands = {} }
303
304 manif.cache_manifest(repo, nil, manifest)
305
306 local ok, err = store_results(results, manifest)
307 if not ok then return nil, err end
308
309 if remote then
310 local cache = {}
311 for luaver in util.lua_versions() do
312 local vmanifest = { repository = {}, modules = {}, commands = {} }
313 local ok, err = store_results(results, vmanifest)
314 filter_by_lua_version(vmanifest, luaver, repo, cache)
315 save_table(repo, "manifest-"..luaver, vmanifest)
316 end
317 else
318 update_dependencies(manifest, deps_mode)
319 end
320
321 return save_table(repo, "manifest", manifest)
322end
323
324--- Update manifest file for a local repository
325-- adding information about a version of a package installed in that repository.
326-- @param name string: Name of a package from the repository.
327-- @param version string: Version of a package from the repository.
328-- @param repo string or nil: Pathname of a local repository. If not given,
329-- the default local repository is used.
330-- @param deps_mode string: Dependency mode: "one" for the current default tree,
331-- "all" for all trees, "order" for all trees with priority >= the current default,
332-- "none" for using the default dependency mode from the configuration.
333-- @return boolean or (nil, string): True if manifest was updated successfully,
334-- or nil and an error message.
335function writer.add_to_manifest(name, version, repo, deps_mode)
336 assert(type(name) == "string")
337 assert(type(version) == "string")
338 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
339 assert(type(deps_mode) == "string")
340
341 if deps_mode == "none" then deps_mode = cfg.deps_mode end
342
343 local manifest, err = manif.load_local_manifest(rocks_dir)
344 if not manifest then
345 util.printerr("No existing manifest. Attempting to rebuild...")
346 -- Manifest built by `writer.make_manifest` should already
347 -- include information about given name and version,
348 -- no need to update it.
349 return writer.make_manifest(rocks_dir, deps_mode)
350 end
351
352 local results = {[name] = {[version] = {{arch = "installed", repo = rocks_dir}}}}
353
354 local ok, err = store_results(results, manifest)
355 if not ok then return nil, err end
356
357 update_dependencies(manifest, deps_mode)
358 return save_table(rocks_dir, "manifest", manifest)
359end
360
361--- Update manifest file for a local repository
362-- removing information about a version of a package.
363-- @param name string: Name of a package removed from the repository.
364-- @param version string: Version of a package removed from the repository.
365-- @param repo string or nil: Pathname of a local repository. If not given,
366-- the default local repository is used.
367-- @param deps_mode string: Dependency mode: "one" for the current default tree,
368-- "all" for all trees, "order" for all trees with priority >= the current default,
369-- "none" for using the default dependency mode from the configuration.
370-- @return boolean or (nil, string): True if manifest was updated successfully,
371-- or nil and an error message.
372function writer.remove_from_manifest(name, version, repo, deps_mode)
373 assert(type(name) == "string")
374 assert(type(version) == "string")
375 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
376 assert(type(deps_mode) == "string")
377
378 if deps_mode == "none" then deps_mode = cfg.deps_mode end
379
380 local manifest, err = manif.load_local_manifest(rocks_dir)
381 if not manifest then
382 util.printerr("No existing manifest. Attempting to rebuild...")
383 -- Manifest built by `writer.make_manifest` should already
384 -- include up-to-date information, no need to update it.
385 return writer.make_manifest(rocks_dir, deps_mode)
386 end
387
388 local package_entry = manifest.repository[name]
389
390 local version_entry = package_entry[version][1]
391 remove_package_items(manifest.modules, name, version, version_entry.modules)
392 remove_package_items(manifest.commands, name, version, version_entry.commands)
393
394 package_entry[version] = nil
395 manifest.dependencies[name][version] = nil
396
397 if not next(package_entry) then
398 -- No more versions of this package.
399 manifest.repository[name] = nil
400 manifest.dependencies[name] = nil
401 end
402
403 update_dependencies(manifest, deps_mode)
404 return save_table(rocks_dir, "manifest", manifest)
405end
406
407--- Report missing dependencies for all rocks installed in a repository.
408-- @param repo string or nil: Pathname of a local repository. If not given,
409-- the default local repository is used.
410-- @param deps_mode string: Dependency mode: "one" for the current default tree,
411-- "all" for all trees, "order" for all trees with priority >= the current default,
412-- "none" for using the default dependency mode from the configuration.
413function writer.check_dependencies(repo, deps_mode)
414 local rocks_dir = path.rocks_dir(repo or cfg.root_dir)
415 assert(type(deps_mode) == "string")
416 if deps_mode == "none" then deps_mode = cfg.deps_mode end
417
418 local manifest = manif.load_local_manifest(rocks_dir)
419 if not manifest then
420 return
421 end
422
423 for name, versions in util.sortedpairs(manifest.repository) do
424 for version, version_entries in util.sortedpairs(versions, deps.compare_versions) do
425 for _, entry in ipairs(version_entries) do
426 if entry.arch == "installed" then
427 if manifest.dependencies[name] and manifest.dependencies[name][version] then
428 deps.report_missing_dependencies(name, version, manifest.dependencies[name][version], deps_mode)
429 end
430 end
431 end
432 end
433 end
434end
435
436return writer
diff --git a/src/luarocks/new_version.lua b/src/luarocks/new_version.lua
index 91f7607c..b13dbb97 100644
--- a/src/luarocks/new_version.lua
+++ b/src/luarocks/new_version.lua
@@ -10,7 +10,6 @@ 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)
14new_version.help_summary = "Auto-write a rockspec for a new version of a rock." 13new_version.help_summary = "Auto-write a rockspec for a new version of a rock."
15new_version.help_arguments = "[--tag=<tag>] [<package>|<rockspec>] [<new_version>] [<new_url>]" 14new_version.help_arguments = "[--tag=<tag>] [<package>|<rockspec>] [<new_version>] [<new_url>]"
16new_version.help = [[ 15new_version.help = [[
diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua
index 35bbe838..655cbf37 100644
--- a/src/luarocks/pack.lua
+++ b/src/luarocks/pack.lua
@@ -2,7 +2,6 @@
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.
4local pack = {} 4local pack = {}
5package.loaded["luarocks.pack"] = pack
6 5
7local unpack = unpack or table.unpack 6local unpack = unpack or table.unpack
8 7
@@ -10,13 +9,12 @@ local path = require("luarocks.path")
10local repos = require("luarocks.repos") 9local repos = require("luarocks.repos")
11local fetch = require("luarocks.fetch") 10local fetch = require("luarocks.fetch")
12local fs = require("luarocks.fs") 11local fs = require("luarocks.fs")
13local cfg = require("luarocks.cfg") 12local cfg = require("luarocks.core.cfg")
14local util = require("luarocks.util") 13local util = require("luarocks.util")
15local dir = require("luarocks.dir") 14local dir = require("luarocks.dir")
16local manif = require("luarocks.manif") 15local manif = require("luarocks.manif")
17local search = require("luarocks.search") 16local search = require("luarocks.search")
18 17
19util.add_run_function(pack)
20pack.help_summary = "Create a rock, packing sources or binaries." 18pack.help_summary = "Create a rock, packing sources or binaries."
21pack.help_arguments = "{<rockspec>|<name> [<version>]}" 19pack.help_arguments = "{<rockspec>|<name> [<version>]}"
22pack.help = [[ 20pack.help = [[
@@ -104,10 +102,8 @@ local function do_pack_binary_rock(name, version, tree)
104 return nil, "'"..name.." "..version.."' does not seem to be an installed rock." 102 return nil, "'"..name.." "..version.."' does not seem to be an installed rock."
105 end 103 end
106 104
107 local rock_manifest = manif.load_rock_manifest(name, version, root) 105 local rock_manifest, err = manif.load_rock_manifest(name, version, root)
108 if not rock_manifest then 106 if not rock_manifest then return nil, err end
109 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
110 end
111 107
112 local name_version = name .. "-" .. version 108 local name_version = name .. "-" .. version
113 local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock") 109 local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock")
diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua
index dafc64e7..83e9c295 100644
--- a/src/luarocks/path.lua
+++ b/src/luarocks/path.lua
@@ -3,9 +3,10 @@
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.
5local path = {} 5local path = {}
6setmetatable(path, { __index = require("luarocks.core.path") })
6 7
7local dir = require("luarocks.dir") 8local dir = require("luarocks.dir")
8local cfg = require("luarocks.cfg") 9local cfg = require("luarocks.core.cfg")
9local util = require("luarocks.util") 10local util = require("luarocks.util")
10 11
11--- Infer rockspec filename from a rock filename. 12--- Infer rockspec filename from a rock filename.
@@ -17,29 +18,11 @@ function path.rockspec_name_from_rock(rock_name)
17 return base_name:match("(.*)%.[^.]*.rock") .. ".rockspec" 18 return base_name:match("(.*)%.[^.]*.rock") .. ".rockspec"
18end 19end
19 20
20function path.rocks_dir(tree)
21 if type(tree) == "string" then
22 return dir.path(tree, cfg.rocks_subdir)
23 else
24 assert(type(tree) == "table")
25 return tree.rocks_dir or dir.path(tree.root, cfg.rocks_subdir)
26 end
27end
28
29function path.root_dir(rocks_dir) 21function path.root_dir(rocks_dir)
30 assert(type(rocks_dir) == "string") 22 assert(type(rocks_dir) == "string")
31 return rocks_dir:match("(.*)" .. util.matchquote(cfg.rocks_subdir) .. ".*$") 23 return rocks_dir:match("(.*)" .. util.matchquote(cfg.rocks_subdir) .. ".*$")
32end 24end
33 25
34function path.rocks_tree_to_string(tree)
35 if type(tree) == "string" then
36 return tree
37 else
38 assert(type(tree) == "table")
39 return tree.root
40 end
41end
42
43function path.deploy_bin_dir(tree) 26function path.deploy_bin_dir(tree)
44 if type(tree) == "string" then 27 if type(tree) == "string" then
45 return dir.path(tree, "bin") 28 return dir.path(tree, "bin")
@@ -49,24 +32,6 @@ function path.deploy_bin_dir(tree)
49 end 32 end
50end 33end
51 34
52function path.deploy_lua_dir(tree)
53 if type(tree) == "string" then
54 return dir.path(tree, cfg.lua_modules_path)
55 else
56 assert(type(tree) == "table")
57 return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path)
58 end
59end
60
61function path.deploy_lib_dir(tree)
62 if type(tree) == "string" then
63 return dir.path(tree, cfg.lib_modules_path)
64 else
65 assert(type(tree) == "table")
66 return tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path)
67 end
68end
69
70function path.manifest_file(tree) 35function path.manifest_file(tree)
71 if type(tree) == "string" then 36 if type(tree) == "string" then
72 return dir.path(tree, cfg.rocks_subdir, "manifest") 37 return dir.path(tree, cfg.rocks_subdir, "manifest")
@@ -229,34 +194,6 @@ function path.make_url(pathname, name, version, arch)
229 return dir.path(pathname, filename) 194 return dir.path(pathname, filename)
230end 195end
231 196
232--- Convert a pathname to a module identifier.
233-- In Unix, for example, a path "foo/bar/baz.lua" is converted to
234-- "foo.bar.baz"; "bla/init.lua" returns "bla"; "foo.so" returns "foo".
235-- @param file string: Pathname of module
236-- @return string: The module identifier, or nil if given path is
237-- not a conformant module path (the function does not check if the
238-- path actually exists).
239function path.path_to_module(file)
240 assert(type(file) == "string")
241
242 local name = file:match("(.*)%."..cfg.lua_extension.."$")
243 if name then
244 name = name:gsub(dir.separator, ".")
245 local init = name:match("(.*)%.init$")
246 if init then
247 name = init
248 end
249 else
250 name = file:match("(.*)%."..cfg.lib_extension.."$")
251 if name then
252 name = name:gsub(dir.separator, ".")
253 end
254 end
255 if not name then name = file end
256 name = name:gsub("^%.+", ""):gsub("%.+$", "")
257 return name
258end
259
260--- Obtain the directory name where a module should be stored. 197--- Obtain the directory name where a module should be stored.
261-- For example, on Unix, "foo.bar.baz" will return "foo/bar". 198-- For example, on Unix, "foo.bar.baz" will return "foo/bar".
262-- @param mod string: A module name in Lua dot-separated format. 199-- @param mod string: A module name in Lua dot-separated format.
@@ -286,22 +223,6 @@ function path.configure_paths(rockspec)
286 rockspec.variables = vars 223 rockspec.variables = vars
287end 224end
288 225
289--- Produce a versioned version of a filename.
290-- @param file string: filename (must start with prefix)
291-- @param prefix string: Path prefix for file
292-- @param name string: Rock name
293-- @param version string: Rock version
294-- @return string: a pathname with the same directory parts and a versioned basename.
295function path.versioned_name(file, prefix, name, version)
296 assert(type(file) == "string")
297 assert(type(name) == "string")
298 assert(type(version) == "string")
299
300 local rest = file:sub(#prefix+1):gsub("^/*", "")
301 local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_")
302 return dir.path(prefix, name_version.."-"..rest)
303end
304
305function path.use_tree(tree) 226function path.use_tree(tree)
306 cfg.root_dir = tree 227 cfg.root_dir = tree
307 cfg.rocks_dir = path.rocks_dir(tree) 228 cfg.rocks_dir = path.rocks_dir(tree)
@@ -310,60 +231,6 @@ function path.use_tree(tree)
310 cfg.deploy_lib_dir = path.deploy_lib_dir(tree) 231 cfg.deploy_lib_dir = path.deploy_lib_dir(tree)
311end 232end
312 233
313--- Apply a given function to the active rocks trees based on chosen dependency mode.
314-- @param deps_mode string: Dependency mode: "one" for the current default tree,
315-- "all" for all trees, "order" for all trees with priority >= the current default,
316-- "none" for no trees (this function becomes a nop).
317-- @param fn function: function to be applied, with the tree dir (string) as the first
318-- argument and the remaining varargs of map_trees as the following arguments.
319-- @return a table with all results of invocations of fn collected.
320function path.map_trees(deps_mode, fn, ...)
321 local result = {}
322 if deps_mode == "one" then
323 table.insert(result, (fn(cfg.root_dir, ...)) or 0)
324 elseif deps_mode == "all" or deps_mode == "order" then
325 local use = false
326 if deps_mode == "all" then
327 use = true
328 end
329 for _, tree in ipairs(cfg.rocks_trees) do
330 if dir.normalize(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then
331 use = true
332 end
333 if use then
334 table.insert(result, (fn(tree, ...)) or 0)
335 end
336 end
337 end
338 return result
339end
340
341local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true }
342
343--- Return the pathname of the file that would be loaded for a module, indexed.
344-- @param file_name string: module file name as in manifest (eg. "socket/core.so")
345-- @param name string: name of the package (eg. "luasocket")
346-- @param version string: version number (eg. "2.0.2-1")
347-- @param tree string: repository path (eg. "/usr/local")
348-- @param i number: the index, 1 if version is the current default, > 1 otherwise.
349-- This is done this way for use by select_module in luarocks.loader.
350-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
351function path.which_i(file_name, name, version, tree, i)
352 local deploy_dir
353 local extension = file_name:match("%.[a-z]+$")
354 if is_src_extension[extension] then
355 deploy_dir = path.deploy_lua_dir(tree)
356 file_name = dir.path(deploy_dir, file_name)
357 else
358 deploy_dir = path.deploy_lib_dir(tree)
359 file_name = dir.path(deploy_dir, file_name)
360 end
361 if i > 1 then
362 file_name = path.versioned_name(file_name, deploy_dir, name, version)
363 end
364 return file_name
365end
366
367--- Return the pathname of the file that would be loaded for a module, 234--- Return the pathname of the file that would be loaded for a module,
368-- returning the versioned pathname if given version is not the default version 235-- returning the versioned pathname if given version is not the default version
369-- in the given manifest. 236-- in the given manifest.
diff --git a/src/luarocks/path_cmd.lua b/src/luarocks/path_cmd.lua
index eba85d46..516a0c47 100644
--- a/src/luarocks/path_cmd.lua
+++ b/src/luarocks/path_cmd.lua
@@ -4,9 +4,8 @@
4local path_cmd = {} 4local path_cmd = {}
5 5
6local util = require("luarocks.util") 6local util = require("luarocks.util")
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
8 8
9util.add_run_function(path_cmd)
10path_cmd.help_summary = "Return the currently configured package path." 9path_cmd.help_summary = "Return the currently configured package path."
11path_cmd.help_arguments = "" 10path_cmd.help_arguments = ""
12path_cmd.help = [[ 11path_cmd.help = [[
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua
index c2adb570..16ff5065 100644
--- a/src/luarocks/persist.lua
+++ b/src/luarocks/persist.lua
@@ -4,83 +4,10 @@
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.
6local persist = {} 6local persist = {}
7package.loaded["luarocks.persist"] = persist 7setmetatable(persist, { __index = require("luarocks.core.persist") })
8 8
9local util = require("luarocks.util") 9local util = require("luarocks.util")
10 10
11--- Load and run a Lua file in an environment.
12-- @param filename string: the name of the file.
13-- @param env table: the environment table.
14-- @return (true, any) or (nil, string, string): true and the return value
15-- of the file, or nil, an error message and an error code ("open", "load"
16-- or "run") in case of errors.
17local function run_file(filename, env)
18 local fd, err = io.open(filename)
19 if not fd then
20 return nil, err, "open"
21 end
22 local str, err = fd:read("*a")
23 fd:close()
24 if not str then
25 return nil, err, "open"
26 end
27 str = str:gsub("^#![^\n]*\n", "")
28 local chunk, ran
29 if _VERSION == "Lua 5.1" then -- Lua 5.1
30 chunk, err = loadstring(str, filename)
31 if chunk then
32 setfenv(chunk, env)
33 ran, err = pcall(chunk)
34 end
35 else -- Lua 5.2
36 chunk, err = load(str, filename, "t", env)
37 if chunk then
38 ran, err = pcall(chunk)
39 end
40 end
41 if not chunk then
42 return nil, "Error loading file: "..err, "load"
43 end
44 if not ran then
45 return nil, "Error running file: "..err, "run"
46 end
47 return true, err
48end
49
50--- Load a Lua file containing assignments, storing them in a table.
51-- The global environment is not propagated to the loaded file.
52-- @param filename string: the name of the file.
53-- @param tbl table or nil: if given, this table is used to store
54-- loaded values.
55-- @return (table, table) or (nil, string, string): a table with the file's assignments
56-- as fields and set of undefined globals accessed in file,
57-- or nil, an error message and an error code ("open"; couldn't open the file,
58-- "load"; compile-time error, or "run"; run-time error)
59-- in case of errors.
60function persist.load_into_table(filename, tbl)
61 assert(type(filename) == "string")
62 assert(type(tbl) == "table" or not tbl)
63
64 local result = tbl or {}
65 local globals = {}
66 local globals_mt = {
67 __index = function(t, k)
68 globals[k] = true
69 end
70 }
71 local save_mt = getmetatable(result)
72 setmetatable(result, globals_mt)
73
74 local ok, err, errcode = run_file(filename, result)
75
76 setmetatable(result, save_mt)
77
78 if not ok then
79 return nil, err, errcode
80 end
81 return result, globals
82end
83
84local write_table 11local write_table
85 12
86--- Write a value as Lua code. 13--- Write a value as Lua code.
diff --git a/src/luarocks/purge.lua b/src/luarocks/purge.lua
index 17724e84..50f290c8 100644
--- a/src/luarocks/purge.lua
+++ b/src/luarocks/purge.lua
@@ -2,7 +2,6 @@
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.
4local purge = {} 4local purge = {}
5package.loaded["luarocks.purge"] = purge
6 5
7local util = require("luarocks.util") 6local util = require("luarocks.util")
8local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
@@ -10,11 +9,10 @@ local path = require("luarocks.path")
10local search = require("luarocks.search") 9local search = require("luarocks.search")
11local deps = require("luarocks.deps") 10local deps = require("luarocks.deps")
12local repos = require("luarocks.repos") 11local repos = require("luarocks.repos")
13local manif = require("luarocks.manif") 12local writer = require("luarocks.manif.writer")
14local cfg = require("luarocks.cfg") 13local cfg = require("luarocks.core.cfg")
15local remove = require("luarocks.remove") 14local remove = require("luarocks.remove")
16 15
17util.add_run_function(purge)
18purge.help_summary = "Remove all installed rocks from a tree." 16purge.help_summary = "Remove all installed rocks from a tree."
19purge.help_arguments = "--tree=<tree> [--old-versions]" 17purge.help_arguments = "--tree=<tree> [--old-versions]"
20purge.help = [[ 18purge.help = [[
@@ -56,7 +54,7 @@ function purge.command(flags)
56 end 54 end
57 55
58 for package, versions in util.sortedpairs(results) do 56 for package, versions in util.sortedpairs(results) do
59 for version, repositories in util.sortedpairs(versions, sort) do 57 for version, _ in util.sortedpairs(versions, sort) do
60 if flags["old-versions"] then 58 if flags["old-versions"] then
61 util.printout("Keeping "..package.." "..version.."...") 59 util.printout("Keeping "..package.." "..version.."...")
62 local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"]) 60 local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"])
@@ -73,7 +71,7 @@ function purge.command(flags)
73 end 71 end
74 end 72 end
75 end 73 end
76 return manif.make_manifest(cfg.rocks_dir, "one") 74 return writer.make_manifest(cfg.rocks_dir, "one")
77end 75end
78 76
79return purge 77return purge
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua
index 514c6dfa..08b5bd5e 100644
--- a/src/luarocks/remove.lua
+++ b/src/luarocks/remove.lua
@@ -2,7 +2,6 @@
2--- Module implementing the LuaRocks "remove" command. 2--- Module implementing the LuaRocks "remove" command.
3-- Uninstalls rocks. 3-- Uninstalls rocks.
4local remove = {} 4local remove = {}
5package.loaded["luarocks.remove"] = remove
6 5
7local search = require("luarocks.search") 6local search = require("luarocks.search")
8local deps = require("luarocks.deps") 7local deps = require("luarocks.deps")
@@ -10,11 +9,10 @@ local fetch = require("luarocks.fetch")
10local repos = require("luarocks.repos") 9local repos = require("luarocks.repos")
11local path = require("luarocks.path") 10local path = require("luarocks.path")
12local util = require("luarocks.util") 11local util = require("luarocks.util")
13local cfg = require("luarocks.cfg") 12local cfg = require("luarocks.core.cfg")
14local fs = require("luarocks.fs") 13local fs = require("luarocks.fs")
15local manif = require("luarocks.manif") 14local writer = require("luarocks.manif.writer")
16 15
17util.add_run_function(remove)
18remove.help_summary = "Uninstall a rock." 16remove.help_summary = "Uninstall a rock."
19remove.help_arguments = "[--force|--force-fast] <name> [<version>]" 17remove.help_arguments = "[--force|--force-fast] <name> [<version>]"
20remove.help = [[ 18remove.help = [[
@@ -167,7 +165,7 @@ function remove.command(flags, name, version)
167 return nil, err 165 return nil, err
168 end 166 end
169 167
170 manif.check_dependencies(nil, deps.get_deps_mode(flags)) 168 writer.check_dependencies(nil, deps.get_deps_mode(flags))
171 return true 169 return true
172end 170end
173 171
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
index d4d9694e..bbc9da79 100644
--- a/src/luarocks/repos.lua
+++ b/src/luarocks/repos.lua
@@ -1,11 +1,10 @@
1 1
2--- Functions for managing the repository on disk. 2--- Functions for managing the repository on disk.
3local repos = {} 3local repos = {}
4package.loaded["luarocks.repos"] = repos
5 4
6local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
7local path = require("luarocks.path") 6local path = require("luarocks.path")
8local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
9local util = require("luarocks.util") 8local util = require("luarocks.util")
10local dir = require("luarocks.dir") 9local dir = require("luarocks.dir")
11local manif = require("luarocks.manif") 10local manif = require("luarocks.manif")
@@ -79,6 +78,7 @@ function repos.package_modules(package, version)
79 78
80 local result = {} 79 local result = {}
81 local rock_manifest = manif.load_rock_manifest(package, version) 80 local rock_manifest = manif.load_rock_manifest(package, version)
81 if not rock_manifest then return result end
82 store_package_data(result, package, rock_manifest.lib) 82 store_package_data(result, package, rock_manifest.lib)
83 store_package_data(result, package, rock_manifest.lua) 83 store_package_data(result, package, rock_manifest.lua)
84 return result 84 return result
@@ -98,6 +98,7 @@ function repos.package_commands(package, version)
98 98
99 local result = {} 99 local result = {}
100 local rock_manifest = manif.load_rock_manifest(package, version) 100 local rock_manifest = manif.load_rock_manifest(package, version)
101 if not rock_manifest then return result end
101 store_package_data(result, package, rock_manifest.bin) 102 store_package_data(result, package, rock_manifest.bin)
102 return result 103 return result
103end 104end
@@ -113,7 +114,7 @@ function repos.has_binaries(name, version)
113 assert(type(version) == "string") 114 assert(type(version) == "string")
114 115
115 local rock_manifest = manif.load_rock_manifest(name, version) 116 local rock_manifest = manif.load_rock_manifest(name, version)
116 if rock_manifest.bin then 117 if rock_manifest and rock_manifest.bin then
117 for name, md5 in pairs(rock_manifest.bin) do 118 for name, md5 in pairs(rock_manifest.bin) do
118 -- TODO verify that it is the same file. If it isn't, find the actual command. 119 -- TODO verify that it is the same file. If it isn't, find the actual command.
119 if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, name)) then 120 if fs.is_actual_binary(dir.path(cfg.deploy_bin_dir, name)) then
@@ -243,7 +244,7 @@ function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode)
243 244
244 local function deploy_file_tree(file_tree, path_fn, deploy_dir, move_fn, suffix) 245 local function deploy_file_tree(file_tree, path_fn, deploy_dir, move_fn, suffix)
245 local source_dir = path_fn(name, version) 246 local source_dir = path_fn(name, version)
246 return recurse_rock_manifest_tree(file_tree, 247 return recurse_rock_manifest_tree(file_tree,
247 function(parent_path, parent_module, file) 248 function(parent_path, parent_module, file)
248 local source = dir.path(source_dir, parent_path, file) 249 local source = dir.path(source_dir, parent_path, file)
249 local target = dir.path(deploy_dir, parent_path, file) 250 local target = dir.path(deploy_dir, parent_path, file)
@@ -281,7 +282,8 @@ function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode)
281 ) 282 )
282 end 283 end
283 284
284 local rock_manifest = manif.load_rock_manifest(name, version) 285 local rock_manifest, err = manif.load_rock_manifest(name, version)
286 if not rock_manifest then return nil, err end
285 287
286 local function install_binary(source, target, name, version) 288 local function install_binary(source, target, name, version)
287 if wrap_bin_scripts and fs.is_lua(source) then 289 if wrap_bin_scripts and fs.is_lua(source) then
@@ -312,7 +314,8 @@ function repos.deploy_files(name, version, wrap_bin_scripts, deps_mode)
312 return nil, err 314 return nil, err
313 end 315 end
314 316
315 return manif.add_to_manifest(name, version, nil, deps_mode) 317 local writer = require("luarocks.manif.writer")
318 return writer.add_to_manifest(name, version, nil, deps_mode)
316end 319end
317 320
318--- Delete a package from the local repository. 321--- Delete a package from the local repository.
@@ -372,12 +375,10 @@ function repos.delete_version(name, version, deps_mode, quick)
372 ) 375 )
373 end 376 end
374 377
375 local rock_manifest = manif.load_rock_manifest(name, version) 378 local rock_manifest, err = manif.load_rock_manifest(name, version)
376 if not rock_manifest then 379 if not rock_manifest then return nil, err end
377 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
378 end
379 380
380 local ok, err = true 381 local ok = true
381 if rock_manifest.bin then 382 if rock_manifest.bin then
382 ok, err = delete_deployed_file_tree(rock_manifest.bin, cfg.deploy_bin_dir, cfg.wrapper_suffix) 383 ok, err = delete_deployed_file_tree(rock_manifest.bin, cfg.deploy_bin_dir, cfg.wrapper_suffix)
383 end 384 end
@@ -398,7 +399,8 @@ function repos.delete_version(name, version, deps_mode, quick)
398 return true 399 return true
399 end 400 end
400 401
401 return manif.remove_from_manifest(name, version, nil, deps_mode) 402 local writer = require("luarocks.manif.writer")
403 return writer.remove_from_manifest(name, version, nil, deps_mode)
402end 404end
403 405
404return repos 406return repos
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
index d22c2a18..44eff694 100644
--- a/src/luarocks/search.lua
+++ b/src/luarocks/search.lua
@@ -2,16 +2,15 @@
2--- Module implementing the LuaRocks "search" command. 2--- Module implementing the LuaRocks "search" command.
3-- Queries LuaRocks servers. 3-- Queries LuaRocks servers.
4local search = {} 4local search = {}
5package.loaded["luarocks.search"] = search 5
6 6
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8local path = require("luarocks.path") 8local path = require("luarocks.path")
9local manif = require("luarocks.manif") 9local manif = require("luarocks.manif")
10local deps = require("luarocks.deps") 10local deps = require("luarocks.deps")
11local cfg = require("luarocks.cfg") 11local cfg = require("luarocks.core.cfg")
12local util = require("luarocks.util") 12local util = require("luarocks.util")
13 13
14util.add_run_function(search)
15search.help_summary = "Query the LuaRocks servers." 14search.help_summary = "Query the LuaRocks servers."
16search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }" 15search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }"
17search.help = [[ 16search.help = [[
diff --git a/src/luarocks/show.lua b/src/luarocks/show.lua
index 85c7edcb..1ff81e08 100644
--- a/src/luarocks/show.lua
+++ b/src/luarocks/show.lua
@@ -1,17 +1,15 @@
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.
3local show = {} 3local show = {}
4package.loaded["luarocks.show"] = show
5 4
6local search = require("luarocks.search") 5local search = require("luarocks.search")
7local cfg = require("luarocks.cfg") 6local cfg = require("luarocks.core.cfg")
8local util = require("luarocks.util") 7local util = require("luarocks.util")
9local path = require("luarocks.path") 8local path = require("luarocks.path")
10local deps = require("luarocks.deps") 9local deps = require("luarocks.deps")
11local fetch = require("luarocks.fetch") 10local fetch = require("luarocks.fetch")
12local manif = require("luarocks.manif") 11local manif = require("luarocks.manif")
13 12
14util.add_run_function(show)
15show.help_summary = "Show information about an installed rock." 13show.help_summary = "Show information about an installed rock."
16 14
17show.help = [[ 15show.help = [[
@@ -96,6 +94,8 @@ function show.command(flags, name, version)
96 if flags["rock-tree"] then util.printout(path.rocks_tree_to_string(repo)) 94 if flags["rock-tree"] then util.printout(path.rocks_tree_to_string(repo))
97 elseif flags["rock-dir"] then util.printout(directory) 95 elseif flags["rock-dir"] then util.printout(directory)
98 elseif flags["home"] then util.printout(descript.homepage) 96 elseif flags["home"] then util.printout(descript.homepage)
97 elseif flags["issues"] then util.printout(descript.issues_url)
98 elseif flags["labels"] then util.printout(descript.labels and table.concat(descript.labels, "\n"))
99 elseif flags["modules"] then util.printout(keys_as_string(minfo.modules, "\n")) 99 elseif flags["modules"] then util.printout(keys_as_string(minfo.modules, "\n"))
100 elseif flags["deps"] then util.printout(keys_as_string(minfo.dependencies)) 100 elseif flags["deps"] then util.printout(keys_as_string(minfo.dependencies))
101 elseif flags["rockspec"] then util.printout(rockspec_file) 101 elseif flags["rockspec"] then util.printout(rockspec_file)
@@ -114,6 +114,12 @@ function show.command(flags, name, version)
114 if descript.homepage then 114 if descript.homepage then
115 util.printout("Homepage: ", descript.homepage) 115 util.printout("Homepage: ", descript.homepage)
116 end 116 end
117 if descript.issues_url then
118 util.printout("Issues: ", descript.issues_url)
119 end
120 if descript.labels then
121 util.printout("Labels: ", table.concat(descript.labels, ", "))
122 end
117 util.printout("Installed in: ", path.rocks_tree_to_string(repo)) 123 util.printout("Installed in: ", path.rocks_tree_to_string(repo))
118 if next(minfo.modules) then 124 if next(minfo.modules) then
119 util.printout() 125 util.printout()
diff --git a/src/luarocks/tools/tar.lua b/src/luarocks/tools/tar.lua
index 637a6c95..ae5c83e2 100644
--- a/src/luarocks/tools/tar.lua
+++ b/src/luarocks/tools/tar.lua
@@ -56,10 +56,11 @@ end
56local function read_header_block(block) 56local function read_header_block(block)
57 local header = {} 57 local header = {}
58 header.name = nullterm(block:sub(1,100)) 58 header.name = nullterm(block:sub(1,100))
59 header.mode = nullterm(block:sub(101,108)) 59 header.mode = nullterm(block:sub(101,108)):gsub(" ", "")
60 header.uid = octal_to_number(nullterm(block:sub(109,116))) 60 header.uid = octal_to_number(nullterm(block:sub(109,116)))
61 header.gid = octal_to_number(nullterm(block:sub(117,124))) 61 header.gid = octal_to_number(nullterm(block:sub(117,124)))
62 header.size = octal_to_number(nullterm(block:sub(125,136))) 62 header.size = octal_to_number(nullterm(block:sub(125,136)))
63print("{"..block:sub(125,136).."}", "{"..nullterm(block:sub(125,136)).."}", "{"..octal_to_number(nullterm(block:sub(125,136))).."}", header.size)
63 header.mtime = octal_to_number(nullterm(block:sub(137,148))) 64 header.mtime = octal_to_number(nullterm(block:sub(137,148)))
64 header.chksum = octal_to_number(nullterm(block:sub(149,156))) 65 header.chksum = octal_to_number(nullterm(block:sub(149,156)))
65 header.typeflag = get_typeflag(block:sub(157,157)) 66 header.typeflag = get_typeflag(block:sub(157,157))
@@ -93,13 +94,14 @@ function tar.untar(filename, destdir)
93 local long_name, long_link_name 94 local long_name, long_link_name
94 while true do 95 while true do
95 local block 96 local block
96 repeat 97 repeat
97 block = tar_handle:read(blocksize) 98 block = tar_handle:read(blocksize)
98 until (not block) or checksum_header(block) > 256 99 until (not block) or checksum_header(block) > 256
99 if not block then break end 100 if not block then break end
100 local header, err = read_header_block(block) 101 local header, err = read_header_block(block)
101 if not header then 102 if not header then
102 util.printerr(err) 103 util.printerr(err)
104 return nil, err
103 end 105 end
104 106
105 local file_data = tar_handle:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size) 107 local file_data = tar_handle:read(math.ceil(header.size / blocksize) * blocksize):sub(1,header.size)
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua
index 63c59ca2..4b7e68d7 100644
--- a/src/luarocks/type_check.lua
+++ b/src/luarocks/type_check.lua
@@ -2,16 +2,15 @@
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.
4local type_check = {} 4local type_check = {}
5package.loaded["luarocks.type_check"] = type_check 5setmetatable(type_check, { __index = require("luarocks.core.type_check") })
6 6
7local cfg = require("luarocks.cfg") 7type_check.rockspec_format = "3.0"
8local deps = require("luarocks.deps")
9 8
10type_check.rockspec_format = "1.1" 9local string_1 = type_check.string_1
10local mandatory_string_1 = type_check.mandatory_string_1
11 11
12local string_1 = { _type = "string" } 12local string_3 = { _type = "string", _version = "3.0" }
13local number_1 = { _type = "number" } 13local list_of_strings_3 = { _any = string_3, _version = "3.0" }
14local mandatory_string_1 = { _type = "string", _mandatory = true }
15 14
16-- Syntax for type-checking tables: 15-- Syntax for type-checking tables:
17-- 16--
@@ -37,6 +36,8 @@ local rockspec_types = {
37 homepage = string_1, 36 homepage = string_1,
38 license = string_1, 37 license = string_1,
39 maintainer = string_1, 38 maintainer = string_1,
39 labels = list_of_strings_3,
40 issues_url = string_3,
40 }, 41 },
41 dependencies = { 42 dependencies = {
42 platforms = {}, -- recursively defined below 43 platforms = {}, -- recursively defined below
@@ -112,206 +113,6 @@ rockspec_types.external_dependencies.platforms._any = rockspec_types.external_de
112rockspec_types.source.platforms._any = rockspec_types.source 113rockspec_types.source.platforms._any = rockspec_types.source
113rockspec_types.hooks.platforms._any = rockspec_types.hooks 114rockspec_types.hooks.platforms._any = rockspec_types.hooks
114 115
115local manifest_types = {
116 repository = {
117 _mandatory = true,
118 -- packages
119 _any = {
120 -- versions
121 _any = {
122 -- items
123 _any = {
124 arch = mandatory_string_1,
125 modules = { _any = string_1 },
126 commands = { _any = string_1 },
127 dependencies = { _any = string_1 },
128 -- TODO: to be extended with more metadata.
129 }
130 }
131 }
132 },
133 modules = {
134 _mandatory = true,
135 -- modules
136 _any = {
137 -- providers
138 _any = string_1
139 }
140 },
141 commands = {
142 _mandatory = true,
143 -- modules
144 _any = {
145 -- commands
146 _any = string_1
147 }
148 },
149 dependencies = {
150 -- each module
151 _any = {
152 -- each version
153 _any = {
154 -- each dependency
155 _any = {
156 name = string_1,
157 constraints = {
158 _any = {
159 no_upgrade = { _type = "boolean" },
160 op = string_1,
161 version = {
162 string = string_1,
163 _any = number_1,
164 }
165 }
166 }
167 }
168 }
169 }
170 }
171}
172
173local function check_version(version, typetbl, context)
174 local typetbl_version = typetbl._version or "1.0"
175 if deps.compare_versions(typetbl_version, version) then
176 if context == "" then
177 return nil, "Invalid rockspec_format version number in rockspec? Please fix rockspec accordingly."
178 else
179 return nil, context.." is not supported in rockspec format "..version.." (requires version "..typetbl_version.."), please fix the rockspec_format field accordingly."
180 end
181 end
182 return true
183end
184
185local type_check_table
186
187--- Type check an object.
188-- The object is compared against an archetypical value
189-- matching the expected type -- the actual values don't matter,
190-- only their types. Tables are type checked recursively.
191-- @param version string: The version of the item.
192-- @param item any: The object being checked.
193-- @param typetbl any: The type-checking table for the object.
194-- @param context string: A string indicating the "context" where the
195-- error occurred (the full table path), for error messages.
196-- @return boolean or (nil, string): true if type checking
197-- succeeded, or nil and an error message if it failed.
198-- @see type_check_table
199local function type_check_item(version, item, typetbl, context)
200 assert(type(version) == "string")
201
202 local ok, err = check_version(version, typetbl, context)
203 if not ok then
204 return nil, err
205 end
206
207 local item_type = type(item) or "nil"
208 local expected_type = typetbl._type or "table"
209
210 if expected_type == "number" then
211 if not tonumber(item) then
212 return nil, "Type mismatch on field "..context..": expected a number"
213 end
214 elseif expected_type == "string" then
215 if item_type ~= "string" then
216 return nil, "Type mismatch on field "..context..": expected a string, got "..item_type
217 end
218 if typetbl._pattern then
219 if not item:match("^"..typetbl._pattern.."$") then
220 return nil, "Type mismatch on field "..context..": invalid value "..item.." does not match '"..typetbl._pattern.."'"
221 end
222 end
223 elseif expected_type == "table" then
224 if item_type ~= expected_type then
225 return nil, "Type mismatch on field "..context..": expected a table"
226 else
227 return type_check_table(version, item, typetbl, context)
228 end
229 elseif item_type ~= expected_type then
230 return nil, "Type mismatch on field "..context..": expected "..expected_type
231 end
232 return true
233end
234
235local function mkfield(context, field)
236 if context == "" then
237 return tostring(field)
238 elseif type(field) == "string" then
239 return context.."."..field
240 else
241 return context.."["..tostring(field).."]"
242 end
243end
244
245--- Type check the contents of a table.
246-- The table's contents are compared against a reference table,
247-- which contains the recognized fields, with archetypical values
248-- matching the expected types -- the actual values of items in the
249-- reference table don't matter, only their types (ie, for field x
250-- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
251-- If the reference table contains a field called MORE, then
252-- unknown fields in the checked table are accepted.
253-- If it contains a field called ANY, then its type will be
254-- used to check any unknown fields. If a field is prefixed
255-- with MUST_, it is mandatory; its absence from the table is
256-- a type error.
257-- Tables are type checked recursively.
258-- @param version string: The version of tbl.
259-- @param tbl table: The table to be type checked.
260-- @param typetbl table: The type-checking table, containing
261-- values for recognized fields in the checked table.
262-- @param context string: A string indicating the "context" where the
263-- error occurred (such as the name of the table the item is a part of),
264-- to be used by error messages.
265-- @return boolean or (nil, string): true if type checking
266-- succeeded, or nil and an error message if it failed.
267type_check_table = function(version, tbl, typetbl, context)
268 assert(type(version) == "string")
269 assert(type(tbl) == "table")
270 assert(type(typetbl) == "table")
271
272 local ok, err = check_version(version, typetbl, context)
273 if not ok then
274 return nil, err
275 end
276
277 for k, v in pairs(tbl) do
278 local t = typetbl[k] or typetbl._any
279 if t then
280 local ok, err = type_check_item(version, v, t, mkfield(context, k))
281 if not ok then return nil, err end
282 elseif typetbl._more then
283 -- Accept unknown field
284 else
285 if not cfg.accept_unknown_fields then
286 return nil, "Unknown field "..k
287 end
288 end
289 end
290 for k, v in pairs(typetbl) do
291 if k:sub(1,1) ~= "_" and v._mandatory then
292 if not tbl[k] then
293 return nil, "Mandatory field "..mkfield(context, k).." is missing."
294 end
295 end
296 end
297 return true
298end
299
300local function check_undeclared_globals(globals, typetbl)
301 local undeclared = {}
302 for glob, _ in pairs(globals) do
303 if not (typetbl[glob] or typetbl["MUST_"..glob]) then
304 table.insert(undeclared, glob)
305 end
306 end
307 if #undeclared == 1 then
308 return nil, "Unknown variable: "..undeclared[1]
309 elseif #undeclared > 1 then
310 return nil, "Unknown variables: "..table.concat(undeclared, ", ")
311 end
312 return true
313end
314
315--- Type check a rockspec table. 116--- Type check a rockspec table.
316-- Verify the correctness of elements from a 117-- Verify the correctness of elements from a
317-- rockspec table, reporting on unknown fields and type 118-- rockspec table, reporting on unknown fields and type
@@ -323,22 +124,9 @@ function type_check.type_check_rockspec(rockspec, globals)
323 if not rockspec.rockspec_format then 124 if not rockspec.rockspec_format then
324 rockspec.rockspec_format = "1.0" 125 rockspec.rockspec_format = "1.0"
325 end 126 end
326 local ok, err = check_undeclared_globals(globals, rockspec_types) 127 local ok, err = type_check.check_undeclared_globals(globals, rockspec_types)
327 if not ok then return nil, err end
328 return type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "")
329end
330
331--- Type check a manifest table.
332-- Verify the correctness of elements from a
333-- manifest table, reporting on unknown fields and type
334-- mismatches.
335-- @return boolean or (nil, string): true if type checking
336-- succeeded, or nil and an error message if it failed.
337function type_check.type_check_manifest(manifest, globals)
338 assert(type(manifest) == "table")
339 local ok, err = check_undeclared_globals(globals, manifest_types)
340 if not ok then return nil, err end 128 if not ok then return nil, err end
341 return type_check_table("1.0", manifest, manifest_types, "") 129 return type_check.type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "")
342end 130end
343 131
344return type_check 132return type_check
diff --git a/src/luarocks/unpack.lua b/src/luarocks/unpack.lua
index 0922f9b9..c50701b0 100644
--- a/src/luarocks/unpack.lua
+++ b/src/luarocks/unpack.lua
@@ -2,16 +2,14 @@
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.
4local unpack = {} 4local unpack = {}
5package.loaded["luarocks.unpack"] = unpack
6 5
7local fetch = require("luarocks.fetch") 6local fetch = require("luarocks.fetch")
8local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
9local util = require("luarocks.util") 8local util = require("luarocks.util")
10local build = require("luarocks.build") 9local build = require("luarocks.build")
11local dir = require("luarocks.dir") 10local dir = require("luarocks.dir")
12local cfg = require("luarocks.cfg") 11local cfg = require("luarocks.core.cfg")
13 12
14util.add_run_function(unpack)
15unpack.help_summary = "Unpack the contents of a rock." 13unpack.help_summary = "Unpack the contents of a rock."
16unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}" 14unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}"
17unpack.help = [[ 15unpack.help = [[
diff --git a/src/luarocks/upload.lua b/src/luarocks/upload.lua
index 7c0c416c..baee47ab 100644
--- a/src/luarocks/upload.lua
+++ b/src/luarocks/upload.lua
@@ -4,10 +4,9 @@ local upload = {}
4local util = require("luarocks.util") 4local util = require("luarocks.util")
5local fetch = require("luarocks.fetch") 5local fetch = require("luarocks.fetch")
6local pack = require("luarocks.pack") 6local pack = require("luarocks.pack")
7local cfg = require("luarocks.cfg") 7local cfg = require("luarocks.core.cfg")
8local Api = require("luarocks.upload.api") 8local Api = require("luarocks.upload.api")
9 9
10util.add_run_function(upload)
11upload.help_summary = "Upload a rockspec to the public rocks repository." 10upload.help_summary = "Upload a rockspec to the public rocks repository."
12upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>" 11upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>"
13upload.help = [[ 12upload.help = [[
diff --git a/src/luarocks/upload/api.lua b/src/luarocks/upload/api.lua
index 6df24569..3e28bbda 100644
--- a/src/luarocks/upload/api.lua
+++ b/src/luarocks/upload/api.lua
@@ -1,7 +1,7 @@
1 1
2local api = {} 2local api = {}
3 3
4local cfg = require("luarocks.cfg") 4local cfg = require("luarocks.core.cfg")
5local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
6local util = require("luarocks.util") 6local util = require("luarocks.util")
7local persist = require("luarocks.persist") 7local persist = require("luarocks.persist")
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
index c9fb7d63..b23f4fab 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -2,9 +2,10 @@
2--- Assorted utilities for managing tables, plus a scheduler for rollback functions. 2--- Assorted utilities for managing tables, plus a scheduler for rollback functions.
3-- Does not requires modules directly (only as locals 3-- Does not requires modules directly (only as locals
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.core.cfg.
6 6
7local util = {} 7local util = {}
8setmetatable(util, { __index = require("luarocks.core.util") })
8 9
9local unpack = unpack or table.unpack 10local unpack = unpack or table.unpack
10 11
@@ -86,7 +87,9 @@ local supported_flags = {
86 ["help"] = true, 87 ["help"] = true,
87 ["home"] = true, 88 ["home"] = true,
88 ["homepage"] = "\"<url>\"", 89 ["homepage"] = "\"<url>\"",
90 ["issues"] = true,
89 ["keep"] = true, 91 ["keep"] = true,
92 ["labels"] = true,
90 ["lib"] = "<library>", 93 ["lib"] = "<library>",
91 ["license"] = "\"<text>\"", 94 ["license"] = "\"<text>\"",
92 ["list"] = true, 95 ["list"] = true,
@@ -196,34 +199,6 @@ function util.parse_flags(...)
196 return flags, unpack(out) 199 return flags, unpack(out)
197end 200end
198 201
199-- Adds legacy 'run' function to a command module.
200-- @param command table: command module with 'command' function,
201-- the added 'run' function calls it after parseing command-line arguments.
202function util.add_run_function(command)
203 command.run = function(...) return command.command(util.parse_flags(...)) end
204end
205
206--- Merges contents of src on top of dst's contents.
207-- @param dst Destination table, which will receive src's contents.
208-- @param src Table which provides new contents to dst.
209-- @see platform_overrides
210function util.deep_merge(dst, src)
211 for k, v in pairs(src) do
212 if type(v) == "table" then
213 if not dst[k] then
214 dst[k] = {}
215 end
216 if type(dst[k]) == "table" then
217 util.deep_merge(dst[k], v)
218 else
219 dst[k] = v
220 end
221 else
222 dst[k] = v
223 end
224 end
225end
226
227--- Perform platform-specific overrides on a table. 202--- Perform platform-specific overrides on a table.
228-- Overrides values of table with the contents of the appropriate 203-- Overrides values of table with the contents of the appropriate
229-- subset of its "platforms" field. The "platforms" field should 204-- subset of its "platforms" field. The "platforms" field should
@@ -240,7 +215,7 @@ end
240function util.platform_overrides(tbl) 215function util.platform_overrides(tbl)
241 assert(type(tbl) == "table" or not tbl) 216 assert(type(tbl) == "table" or not tbl)
242 217
243 local cfg = require("luarocks.cfg") 218 local cfg = require("luarocks.core.cfg")
244 219
245 if not tbl then return end 220 if not tbl then return end
246 221
@@ -257,19 +232,6 @@ end
257 232
258local var_format_pattern = "%$%((%a[%a%d_]+)%)" 233local var_format_pattern = "%$%((%a[%a%d_]+)%)"
259 234
260--- Create a new shallow copy of a table: a new table with
261-- the same keys and values. Keys point to the same objects as
262-- the original table (ie, does not copy recursively).
263-- @param tbl table: the input table
264-- @return table: a new table with the same contents.
265function util.make_shallow_copy(tbl)
266 local copy = {}
267 for k,v in pairs(tbl) do
268 copy[k] = v
269 end
270 return copy
271end
272
273-- Check if a set of needed variables are referenced 235-- Check if a set of needed variables are referenced
274-- somewhere in a list of definitions, warning the user 236-- somewhere in a list of definitions, warning the user
275-- about any unused ones. Each key in needed_set should 237-- about any unused ones. Each key in needed_set should
@@ -332,86 +294,6 @@ function util.variable_substitutions(tbl, vars)
332 end 294 end
333end 295end
334 296
335--- Return an array of keys of a table.
336-- @param tbl table: The input table.
337-- @return table: The array of keys.
338function util.keys(tbl)
339 local ks = {}
340 for k,_ in pairs(tbl) do
341 table.insert(ks, k)
342 end
343 return ks
344end
345
346local function default_sort(a, b)
347 local ta = type(a)
348 local tb = type(b)
349 if ta == "number" and tb == "number" then
350 return a < b
351 elseif ta == "number" then
352 return true
353 elseif tb == "number" then
354 return false
355 else
356 return tostring(a) < tostring(b)
357 end
358end
359
360--- A table iterator generator that returns elements sorted by key,
361-- to be used in "for" loops.
362-- @param tbl table: The table to be iterated.
363-- @param sort_function function or table or nil: An optional comparison function
364-- to be used by table.sort when sorting keys, or an array listing an explicit order
365-- for keys. If a value itself is an array, it is taken so that the first element
366-- is a string representing the field name, and the second element is a priority table
367-- for that key, which is returned by the iterator as the third value after the key
368-- and the value.
369-- @return function: the iterator function.
370function util.sortedpairs(tbl, sort_function)
371 sort_function = sort_function or default_sort
372 local keys = util.keys(tbl)
373 local sub_orders = {}
374
375 if type(sort_function) == "function" then
376 table.sort(keys, sort_function)
377 else
378 local order = sort_function
379 local ordered_keys = {}
380 local all_keys = keys
381 keys = {}
382
383 for _, order_entry in ipairs(order) do
384 local key, sub_order
385 if type(order_entry) == "table" then
386 key = order_entry[1]
387 sub_order = order_entry[2]
388 else
389 key = order_entry
390 end
391
392 if tbl[key] then
393 ordered_keys[key] = true
394 sub_orders[key] = sub_order
395 table.insert(keys, key)
396 end
397 end
398
399 table.sort(all_keys, default_sort)
400 for _, key in ipairs(all_keys) do
401 if not ordered_keys[key] then
402 table.insert(keys, key)
403 end
404 end
405 end
406
407 local i = 1
408 return function()
409 local key = keys[i]
410 i = i + 1
411 return key, tbl[key], sub_orders[key]
412 end
413end
414
415function util.lua_versions() 297function util.lua_versions()
416 local versions = { "5.1", "5.2", "5.3" } 298 local versions = { "5.1", "5.2", "5.3" }
417 local i = 0 299 local i = 0
@@ -431,12 +313,6 @@ function util.printout(...)
431 io.stdout:write("\n") 313 io.stdout:write("\n")
432end 314end
433 315
434--- Print a line to standard error
435function util.printerr(...)
436 io.stderr:write(table.concat({...},"\t"))
437 io.stderr:write("\n")
438end
439
440--- Display a warning message. 316--- Display a warning message.
441-- @param msg string: the warning message 317-- @param msg string: the warning message
442function util.warning(msg) 318function util.warning(msg)
@@ -465,7 +341,7 @@ function util.this_program(default)
465end 341end
466 342
467function util.deps_mode_help(program) 343function util.deps_mode_help(program)
468 local cfg = require("luarocks.cfg") 344 local cfg = require("luarocks.core.cfg")
469 return [[ 345 return [[
470--deps-mode=<mode> How to handle dependencies. Four modes are supported: 346--deps-mode=<mode> How to handle dependencies. Four modes are supported:
471 * all - use all trees from the rocks_trees list 347 * all - use all trees from the rocks_trees list
@@ -488,7 +364,7 @@ function util.see_help(command, program)
488end 364end
489 365
490function util.announce_install(rockspec) 366function util.announce_install(rockspec)
491 local cfg = require("luarocks.cfg") 367 local cfg = require("luarocks.core.cfg")
492 local path = require("luarocks.path") 368 local path = require("luarocks.path")
493 369
494 local suffix = "" 370 local suffix = ""
@@ -566,135 +442,6 @@ function util.get_default_rockspec()
566 end 442 end
567end 443end
568 444
569-- from http://lua-users.org/wiki/SplitJoin
570-- by PhilippeLhoste
571function util.split_string(str, delim, maxNb)
572 -- Eliminate bad cases...
573 if string.find(str, delim) == nil then
574 return { str }
575 end
576 if maxNb == nil or maxNb < 1 then
577 maxNb = 0 -- No limit
578 end
579 local result = {}
580 local pat = "(.-)" .. delim .. "()"
581 local nb = 0
582 local lastPos
583 for part, pos in string.gmatch(str, pat) do
584 nb = nb + 1
585 result[nb] = part
586 lastPos = pos
587 if nb == maxNb then break end
588 end
589 -- Handle the last field
590 if nb ~= maxNb then
591 result[nb + 1] = string.sub(str, lastPos)
592 end
593 return result
594end
595
596--- Remove repeated entries from a path-style string.
597-- Example: given ("a;b;c;a;b;d", ";"), returns "a;b;c;d".
598-- @param list string: A path string (from $PATH or package.path)
599-- @param sep string: The separator
600function util.remove_path_dupes(list, sep)
601 assert(type(list) == "string")
602 assert(type(sep) == "string")
603 local parts = util.split_string(list, sep)
604 local final, entries = {}, {}
605 for _, part in ipairs(parts) do
606 part = part:gsub("//", "/")
607 if not entries[part] then
608 table.insert(final, part)
609 entries[part] = true
610 end
611 end
612 return table.concat(final, sep)
613end
614
615---
616-- Formats tables with cycles recursively to any depth.
617-- References to other tables are shown as values.
618-- Self references are indicated.
619-- The string returned is "Lua code", which can be procesed
620-- (in the case in which indent is composed by spaces or "--").
621-- Userdata and function keys and values are shown as strings,
622-- which logically are exactly not equivalent to the original code.
623-- This routine can serve for pretty formating tables with
624-- proper indentations, apart from printing them:
625-- io.write(table.show(t, "t")) -- a typical use
626-- Written by Julio Manuel Fernandez-Diaz,
627-- Heavily based on "Saving tables with cycles", PIL2, p. 113.
628-- @param t table: is the table.
629-- @param name string: is the name of the table (optional)
630-- @param indent string: is a first indentation (optional).
631-- @return string: the pretty-printed table
632function util.show_table(t, name, indent)
633 local cart -- a container
634 local autoref -- for self references
635
636 local function isemptytable(t) return next(t) == nil end
637
638 local function basicSerialize (o)
639 local so = tostring(o)
640 if type(o) == "function" then
641 local info = debug.getinfo(o, "S")
642 -- info.name is nil because o is not a calling level
643 if info.what == "C" then
644 return ("%q"):format(so .. ", C function")
645 else
646 -- the information is defined through lines
647 return ("%q"):format(so .. ", defined in (" .. info.linedefined .. "-" .. info.lastlinedefined .. ")" .. info.source)
648 end
649 elseif type(o) == "number" then
650 return so
651 else
652 return ("%q"):format(so)
653 end
654 end
655
656 local function addtocart (value, name, indent, saved, field)
657 indent = indent or ""
658 saved = saved or {}
659 field = field or name
660
661 cart = cart .. indent .. field
662
663 if type(value) ~= "table" then
664 cart = cart .. " = " .. basicSerialize(value) .. ";\n"
665 else
666 if saved[value] then
667 cart = cart .. " = {}; -- " .. saved[value] .. " (self reference)\n"
668 autoref = autoref .. name .. " = " .. saved[value] .. ";\n"
669 else
670 saved[value] = name
671 --if tablecount(value) == 0 then
672 if isemptytable(value) then
673 cart = cart .. " = {};\n"
674 else
675 cart = cart .. " = {\n"
676 for k, v in pairs(value) do
677 k = basicSerialize(k)
678 local fname = ("%s[%s]"):format(name, k)
679 field = ("[%s]"):format(k)
680 -- three spaces between levels
681 addtocart(v, fname, indent .. " ", saved, field)
682 end
683 cart = cart .. indent .. "};\n"
684 end
685 end
686 end
687 end
688
689 name = name or "__unnamed__"
690 if type(t) ~= "table" then
691 return name .. " = " .. basicSerialize(t)
692 end
693 cart, autoref = "", ""
694 addtocart(t, name, indent)
695 return cart .. autoref
696end
697
698function util.array_contains(tbl, value) 445function util.array_contains(tbl, value)
699 for _, v in ipairs(tbl) do 446 for _, v in ipairs(tbl) do
700 if v == value then 447 if v == value then
diff --git a/src/luarocks/validate.lua b/src/luarocks/validate.lua
deleted file mode 100644
index c4570aa4..00000000
--- a/src/luarocks/validate.lua
+++ /dev/null
@@ -1,159 +0,0 @@
1
2--- Sandboxed test of build/install of all packages in a repository (unfinished and disabled).
3local validate = {}
4package.loaded["luarocks.validate"] = validate
5
6local fs = require("luarocks.fs")
7local dir = require("luarocks.dir")
8local path = require("luarocks.path")
9local cfg = require("luarocks.cfg")
10local build = require("luarocks.build")
11local install = require("luarocks.install")
12local util = require("luarocks.util")
13
14util.add_run_function(validate)
15validate.help_summary = "Sandboxed test of build/install of all packages in a repository."
16
17validate.help = [[
18<argument>, if given, is a local repository pathname.
19]]
20
21local function save_settings(repo)
22 local protocol, path = dir.split_url(repo)
23 table.insert(cfg.rocks_servers, 1, protocol.."://"..path)
24 return {
25 root_dir = cfg.root_dir,
26 rocks_dir = cfg.rocks_dir,
27 deploy_bin_dir = cfg.deploy_bin_dir,
28 deploy_lua_dir = cfg.deploy_lua_dir,
29 deploy_lib_dir = cfg.deploy_lib_dir,
30 }
31end
32
33local function restore_settings(settings)
34 cfg.root_dir = settings.root_dir
35 cfg.rocks_dir = settings.rocks_dir
36 cfg.deploy_bin_dir = settings.deploy_bin_dir
37 cfg.deploy_lua_dir = settings.deploy_lua_dir
38 cfg.deploy_lib_dir = settings.deploy_lib_dir
39 cfg.variables.ROCKS_TREE = settings.rocks_dir
40 cfg.variables.SCRIPTS_DIR = settings.deploy_bin_dir
41 table.remove(cfg.rocks_servers, 1)
42end
43
44local function prepare_sandbox(file)
45 local root_dir = fs.make_temp_dir(file):gsub("/+$", "")
46 cfg.root_dir = root_dir
47 cfg.rocks_dir = path.rocks_dir(root_dir)
48 cfg.deploy_bin_dir = path.deploy_bin_dir(root_dir)
49 cfg.variables.ROCKS_TREE = cfg.rocks_dir
50 cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir
51 return root_dir
52end
53
54local function validate_rockspec(file)
55 local ok, err, errcode = build.build_rockspec(file, true, "one")
56 if not ok then
57 util.printerr(err)
58 end
59 return ok, err, errcode
60end
61
62local function validate_src_rock(file)
63 local ok, err, errcode = build.build_rock(file, false, "one")
64 if not ok then
65 util.printerr(err)
66 end
67 return ok, err, errcode
68end
69
70local function validate_rock(file)
71 local ok, err, errcode = install.install_binary_rock(file, "one")
72 if not ok then
73 util.printerr(err)
74 end
75 return ok, err, errcode
76end
77
78function validate.command(flags, repo)
79 repo = repo or cfg.rocks_dir
80
81 util.printout("Verifying contents of "..repo)
82
83 local results = {
84 ok = {}
85 }
86 local settings = save_settings(repo)
87 local sandbox
88 if flags["quick"] then
89 sandbox = prepare_sandbox("luarocks_validate")
90 end
91 if not fs.exists(repo) then
92 return nil, repo.." is not a local repository."
93 end
94 for file in fs.dir(repo) do for _=1,1 do
95 if file == "manifest" or file == "index.html" then
96 break -- continue for
97 end
98 local pathname = fs.absolute_name(dir.path(repo, file))
99 if not flags["quick"] then
100 sandbox = prepare_sandbox(file)
101 end
102 local ok, err, errcode
103 util.printout()
104 util.printout("Verifying "..pathname)
105 if file:match("%.rockspec$") then
106 ok, err, errcode = validate_rockspec(pathname, "one")
107 elseif file:match("%.src%.rock$") then
108 ok, err, errcode = validate_src_rock(pathname)
109 elseif file:match("%.rock$") then
110 ok, err, errcode = validate_rock(pathname)
111 end
112 if ok then
113 table.insert(results.ok, {file=file} )
114 else
115 if not errcode then
116 errcode = "misc"
117 end
118 if not results[errcode] then
119 results[errcode] = {}
120 end
121 table.insert(results[errcode], {file=file, err=err} )
122 end
123 util.run_scheduled_functions()
124 if not flags["quick"] then
125 fs.delete(sandbox)
126 end
127 repeat until not fs.pop_dir()
128 end end
129 if flags["quick"] then
130 fs.delete(sandbox)
131 end
132 restore_settings(settings)
133 util.title("Results:")
134 util.printout("OK: "..tostring(#results.ok))
135 for _, entry in ipairs(results.ok) do
136 util.printout(entry.file)
137 end
138 for errcode, errors in pairs(results) do
139 if errcode ~= "ok" then
140 util.printout()
141 util.printout(errcode.." errors: "..tostring(#errors))
142 for _, entry in ipairs(errors) do
143 util.printout(entry.file, entry.err)
144 end
145 end
146 end
147
148 util.title("Summary:")
149 local total = 0
150 for errcode, errors in pairs(results) do
151 util.printout(errcode..": "..tostring(#errors))
152 total = total + #errors
153 end
154 util.printout("Total: "..total)
155 return true
156end
157
158
159return validate
diff --git a/src/luarocks/write_rockspec.lua b/src/luarocks/write_rockspec.lua
index 33edeb1b..be563eaa 100644
--- a/src/luarocks/write_rockspec.lua
+++ b/src/luarocks/write_rockspec.lua
@@ -1,8 +1,7 @@
1 1
2local write_rockspec = {} 2local write_rockspec = {}
3package.loaded["luarocks.write_rockspec"] = write_rockspec
4 3
5local cfg = require("luarocks.cfg") 4local cfg = require("luarocks.core.cfg")
6local dir = require("luarocks.dir") 5local dir = require("luarocks.dir")
7local fetch = require("luarocks.fetch") 6local fetch = require("luarocks.fetch")
8local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
@@ -10,8 +9,8 @@ local path = require("luarocks.path")
10local persist = require("luarocks.persist") 9local persist = require("luarocks.persist")
11local type_check = require("luarocks.type_check") 10local type_check = require("luarocks.type_check")
12local util = require("luarocks.util") 11local util = require("luarocks.util")
12local deps = require("luarocks.deps")
13 13
14util.add_run_function(write_rockspec)
15write_rockspec.help_summary = "Write a template for a rockspec file." 14write_rockspec.help_summary = "Write a template for a rockspec file."
16write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]" 15write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]"
17write_rockspec.help = [[ 16write_rockspec.help = [[
@@ -223,6 +222,7 @@ local function rockspec_cleanup(rockspec)
223 rockspec.source.protocol = nil 222 rockspec.source.protocol = nil
224 rockspec.variables = nil 223 rockspec.variables = nil
225 rockspec.name = nil 224 rockspec.name = nil
225 rockspec.format_is_at_least = nil
226end 226end
227 227
228function write_rockspec.command(flags, name, version, url_or_dir) 228function write_rockspec.command(flags, name, version, url_or_dir)
@@ -285,6 +285,7 @@ function write_rockspec.command(flags, name, version, url_or_dir)
285 } 285 }
286 path.configure_paths(rockspec) 286 path.configure_paths(rockspec)
287 rockspec.source.protocol = protocol 287 rockspec.source.protocol = protocol
288 rockspec.format_is_at_least = deps.format_is_at_least
288 289
289 configure_lua_version(rockspec, flags["lua-version"]) 290 configure_lua_version(rockspec, flags["lua-version"])
290 291