aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHisham <hisham@gobolinux.org>2016-06-30 01:15:01 -0300
committerHisham <hisham@gobolinux.org>2016-06-30 01:15:01 -0300
commitf2beb5ee1fd2c54d59a43f4f2a8fe0f7a1701daa (patch)
tree46f958aa7efb4d6b31612178026228ba49e612f5 /src
parent6b38323d10743c83e377d9be2fa734a3a3d5a300 (diff)
downloadluarocks-f2beb5ee1fd2c54d59a43f4f2a8fe0f7a1701daa.tar.gz
luarocks-f2beb5ee1fd2c54d59a43f4f2a8fe0f7a1701daa.tar.bz2
luarocks-f2beb5ee1fd2c54d59a43f4f2a8fe0f7a1701daa.zip
Core modules reorganization.
Isolate all modules used by luarocks.loader in a luarocks.core.* namespace. Core modules can only require other core modules, and they only use require() at the top-level chunk. In other words, after luarocks.loader is setup, package.path can be altered at will and it should not affect the ability of luarocks.loader to run, and the luarocks.loader modules should not interfere with modules loaded later. This was motivated by @robooo's GSoC work on porting the LuaRocks test suite to Lua using Busted. Busted itself runs using luarocks.loader, and we need to ensure that the modules loaded by the tests do not conflict with the ones used by luarocks.loader. A circular dependency between luarocks.manif and luarocks.search was removed by creating a separate luarocks.manif.writer module. Also, luarocks-admin commands were moved to a luarocks.admin.* namespace.
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)20
-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)7
-rw-r--r--src/luarocks/admin/refresh_cache.lua (renamed from src/luarocks/refresh_cache.lua)5
-rw-r--r--src/luarocks/admin/remove.lua (renamed from src/luarocks/admin_remove.lua)9
-rw-r--r--src/luarocks/build.lua9
-rw-r--r--src/luarocks/build/builtin.lua2
-rw-r--r--src/luarocks/build/cmake.lua2
-rw-r--r--src/luarocks/build/make.lua2
-rw-r--r--src/luarocks/command_line.lua2
-rw-r--r--src/luarocks/config_cmd.lua2
-rw-r--r--src/luarocks/core/cfg.lua (renamed from src/luarocks/cfg.lua)14
-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.lua149
-rw-r--r--src/luarocks/core/persist.lua81
-rw-r--r--src/luarocks/core/type_check.lua226
-rw-r--r--src/luarocks/core/util.lua202
-rw-r--r--src/luarocks/deps.lua215
-rw-r--r--src/luarocks/dir.lua49
-rw-r--r--src/luarocks/doc.lua1
-rw-r--r--src/luarocks/download.lua3
-rw-r--r--src/luarocks/fetch.lua3
-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.lua2
-rw-r--r--src/luarocks/index.lua1
-rw-r--r--src/luarocks/install.lua9
-rw-r--r--src/luarocks/lint.lua1
-rw-r--r--src/luarocks/list.lua3
-rw-r--r--src/luarocks/loader.lua31
-rw-r--r--src/luarocks/make.lua3
-rw-r--r--src/luarocks/manif.lua367
-rw-r--r--src/luarocks/manif/writer.lua360
-rw-r--r--src/luarocks/pack.lua3
-rw-r--r--src/luarocks/path.lua142
-rw-r--r--src/luarocks/path_cmd.lua2
-rw-r--r--src/luarocks/persist.lua75
-rw-r--r--src/luarocks/purge.lua9
-rw-r--r--src/luarocks/remove.lua7
-rw-r--r--src/luarocks/repos.lua3
-rw-r--r--src/luarocks/search.lua4
-rw-r--r--src/luarocks/show.lua3
-rw-r--r--src/luarocks/type_check.lua224
-rw-r--r--src/luarocks/unpack.lua3
-rw-r--r--src/luarocks/upload.lua2
-rw-r--r--src/luarocks/upload/api.lua2
-rw-r--r--src/luarocks/util.lua203
-rw-r--r--src/luarocks/validate.lua158
-rw-r--r--src/luarocks/write_rockspec.lua3
58 files changed, 1420 insertions, 1518 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 66f7504f..daf46c1d 100644
--- a/src/luarocks/add.lua
+++ b/src/luarocks/admin/add.lua
@@ -2,15 +2,14 @@
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
15add.help_summary = "Add a rock or rockspec to a rocks server." 14add.help_summary = "Add a rock or rockspec to a rocks server."
16add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" 15add.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
@@ -23,6 +22,15 @@ The flag --no-refresh indicates the local cache should not be refreshed
23prior to generation of the updated manifest. 22prior to generation of the updated manifest.
24]] 23]]
25 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
26local function add_files_to_server(refresh, rockfiles, server, upload_server) 34local function add_files_to_server(refresh, rockfiles, server, upload_server)
27 assert(type(refresh) == "boolean" or not refresh) 35 assert(type(refresh) == "boolean" or not refresh)
28 assert(type(rockfiles) == "table") 36 assert(type(rockfiles) == "table")
@@ -67,9 +75,9 @@ local function add_files_to_server(refresh, rockfiles, server, upload_server)
67 if not ok then return nil, err end 75 if not ok then return nil, err end
68 76
69 util.printout("Updating manifest...") 77 util.printout("Updating manifest...")
70 manif.make_manifest(local_cache, "one", true) 78 writer.make_manifest(local_cache, "one", true)
71 79
72 manif.zip_manifests() 80 zip_manifests()
73 81
74 util.printout("Updating index.html...") 82 util.printout("Updating index.html...")
75 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 b89ba47f..57851942 100644
--- a/src/luarocks/make_manifest.lua
+++ b/src/luarocks/admin/make_manifest.lua
@@ -2,11 +2,10 @@
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")
@@ -36,7 +35,7 @@ function make_manifest.command(flags, repo)
36 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.")
37 end 36 end
38 37
39 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"])
40 if ok and not flags["local-tree"] then 39 if ok and not flags["local-tree"] then
41 util.printout("Generating index.html for "..repo) 40 util.printout("Generating index.html for "..repo)
42 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 1261044f..947dbfb0 100644
--- a/src/luarocks/refresh_cache.lua
+++ b/src/luarocks/admin/refresh_cache.lua
@@ -1,10 +1,9 @@
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 cfg = require("luarocks.cfg") 5local cfg = require("luarocks.core.cfg")
7local cache = require("luarocks.cache") 6local cache = require("luarocks.admin.cache")
8 7
9refresh_cache.help_summary = "Refresh local cache of a remote rocks server." 8refresh_cache.help_summary = "Refresh local cache of a remote rocks server."
10refresh_cache.help_arguments = "[--from=<server>]" 9refresh_cache.help_arguments = "[--from=<server>]"
diff --git a/src/luarocks/admin_remove.lua b/src/luarocks/admin/remove.lua
index be1e7cbc..763a166f 100644
--- a/src/luarocks/admin_remove.lua
+++ b/src/luarocks/admin/remove.lua
@@ -2,15 +2,14 @@
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
15admin_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."
16admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}" 15admin_remove.help_arguments = "[--server=<server>] [--no-refresh] {<rockspec>|<rock>...}"
@@ -64,7 +63,7 @@ local function remove_files_from_server(refresh, rockfiles, server, upload_serve
64 if not ok then return nil, err end 63 if not ok then return nil, err end
65 64
66 util.printout("Updating manifest...") 65 util.printout("Updating manifest...")
67 manif.make_manifest(local_cache, "one", true) 66 writer.make_manifest(local_cache, "one", true)
68 util.printout("Updating index.html...") 67 util.printout("Updating index.html...")
69 index.make_index(local_cache) 68 index.make_index(local_cache)
70 69
diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua
index 2d29e23f..d7d8ed07 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,9 +11,9 @@ 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
19build.help_summary = "Build/compile a rock." 18build.help_summary = "Build/compile a rock."
20build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" 19build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}"
@@ -346,7 +345,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
346 fs.pop_dir() 345 fs.pop_dir()
347 end 346 end
348 347
349 ok, err = manif.make_rock_manifest(name, version) 348 ok, err = writer.make_rock_manifest(name, version)
350 if err then return nil, err end 349 if err then return nil, err end
351 350
352 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec)) 351 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec))
@@ -360,7 +359,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
360 ok, err = repos.run_hook(rockspec, "post_install") 359 ok, err = repos.run_hook(rockspec, "post_install")
361 if err then return nil, err end 360 if err then return nil, err end
362 361
363 ok, err = manif.update_manifest(name, version, nil, deps_mode) 362 ok, err = writer.update_manifest(name, version, nil, deps_mode)
364 if err then return nil, err end 363 if err then return nil, err end
365 364
366 util.announce_install(rockspec) 365 util.announce_install(rockspec)
diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua
index 81fa8b13..d9785b0c 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.
diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua
index c2712bb2..43702979 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")
8local deps = require("luarocks.deps") 8local deps = require("luarocks.deps")
9 9
10--- Driver function for the "cmake" build back-end. 10--- Driver function for the "cmake" build back-end.
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 1a8c0fe7..936e9950 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 9e73d228..b68f7898 100644
--- a/src/luarocks/config_cmd.lua
+++ b/src/luarocks/config_cmd.lua
@@ -2,7 +2,7 @@
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
diff --git a/src/luarocks/cfg.lua b/src/luarocks/core/cfg.lua
index 53387276..42508b9e 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
@@ -13,11 +14,7 @@
13local rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION = 14local 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 15 rawset, next, table, pairs, require, io, os, setmetatable, pcall, ipairs, package, tonumber, type, assert, _VERSION
15 16
16--module("luarocks.cfg")
17local cfg = {} 17local cfg = {}
18package.loaded["luarocks.cfg"] = cfg
19
20local util = require("luarocks.util")
21 18
22cfg.lua_version = _VERSION:sub(5) 19cfg.lua_version = _VERSION:sub(5)
23local version_suffix = cfg.lua_version:gsub("%.", "_") 20local version_suffix = cfg.lua_version:gsub("%.", "_")
@@ -32,15 +29,18 @@ if not ok then
32 site_config = {} 29 site_config = {}
33end 30end
34 31
32local util = require("luarocks.core.util")
33local persist = require("luarocks.core.persist")
34local require = nil
35--------------------------------------------------------------------------------
36
35cfg.program_version = "scm" 37cfg.program_version = "scm"
36cfg.program_series = "2.2" 38cfg.program_series = "3.0"
37cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series 39cfg.major_version = (cfg.program_version:match("([^.]%.[^.])")) or cfg.program_series
38cfg.variables = {} 40cfg.variables = {}
39cfg.rocks_trees = {} 41cfg.rocks_trees = {}
40cfg.platforms = {} 42cfg.platforms = {}
41 43
42local persist = require("luarocks.persist")
43
44cfg.errorcodes = setmetatable({ 44cfg.errorcodes = setmetatable({
45 OK = 0, 45 OK = 0,
46 UNSPECIFIED = 1, 46 UNSPECIFIED = 1,
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 5c8928d4..f0912bfd 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 manifest = {} 92 local manifest = {}
93 path.map_trees(deps_mode, function(tree) 93 path.map_trees(deps_mode, function(tree)
94 local loaded = manif_core.load_local_manifest(path.rocks_dir(tree)) 94 local loaded = manif.load_local_manifest(path.rocks_dir(tree))
95 if loaded then 95 if loaded then
96 util.deep_merge(manifest, loaded) 96 util.deep_merge(manifest, loaded)
97 end 97 end
@@ -104,4 +104,4 @@ function manif_core.get_versions(name, deps_mode)
104 return {} 104 return {}
105end 105end
106 106
107return manif_core 107return manif
diff --git a/src/luarocks/core/path.lua b/src/luarocks/core/path.lua
new file mode 100644
index 00000000..ffde2c68
--- /dev/null
+++ b/src/luarocks/core/path.lua
@@ -0,0 +1,149 @@
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 else
57 name = file:match("(.*)%."..cfg.static_lib_extension.."$")
58 if name then
59 name = name:gsub(dir.separator, ".")
60 end
61 end
62 end
63 if not name then name = file end
64 name = name:gsub("^%.+", ""):gsub("%.+$", "")
65 return name
66end
67
68function path.deploy_lua_dir(tree)
69 if type(tree) == "string" then
70 return dir.path(tree, cfg.lua_modules_path)
71 else
72 assert(type(tree) == "table")
73 return tree.lua_dir or dir.path(tree.root, cfg.lua_modules_path)
74 end
75end
76
77function path.deploy_lib_dir(tree)
78 if type(tree) == "string" then
79 return dir.path(tree, cfg.lib_modules_path)
80 else
81 assert(type(tree) == "table")
82 return tree.lib_dir or dir.path(tree.root, cfg.lib_modules_path)
83 end
84end
85
86local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true }
87
88--- Return the pathname of the file that would be loaded for a module, indexed.
89-- @param file_name string: module file name as in manifest (eg. "socket/core.so")
90-- @param name string: name of the package (eg. "luasocket")
91-- @param version string: version number (eg. "2.0.2-1")
92-- @param tree string: repository path (eg. "/usr/local")
93-- @param i number: the index, 1 if version is the current default, > 1 otherwise.
94-- This is done this way for use by select_module in luarocks.loader.
95-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
96function path.which_i(file_name, name, version, tree, i)
97 local deploy_dir
98 local extension = file_name:match("%.[a-z]+$")
99 if is_src_extension[extension] then
100 deploy_dir = path.deploy_lua_dir(tree)
101 file_name = dir.path(deploy_dir, file_name)
102 else
103 deploy_dir = path.deploy_lib_dir(tree)
104 file_name = dir.path(deploy_dir, file_name)
105 end
106 if i > 1 then
107 file_name = path.versioned_name(file_name, deploy_dir, name, version)
108 end
109 return file_name
110end
111
112function path.rocks_tree_to_string(tree)
113 if type(tree) == "string" then
114 return tree
115 else
116 assert(type(tree) == "table")
117 return tree.root
118 end
119end
120
121--- Apply a given function to the active rocks trees based on chosen dependency mode.
122-- @param deps_mode string: Dependency mode: "one" for the current default tree,
123-- "all" for all trees, "order" for all trees with priority >= the current default,
124-- "none" for no trees (this function becomes a nop).
125-- @param fn function: function to be applied, with the tree dir (string) as the first
126-- argument and the remaining varargs of map_trees as the following arguments.
127-- @return a table with all results of invocations of fn collected.
128function path.map_trees(deps_mode, fn, ...)
129 local result = {}
130 if deps_mode == "one" then
131 table.insert(result, (fn(cfg.root_dir, ...)) or 0)
132 elseif deps_mode == "all" or deps_mode == "order" then
133 local use = false
134 if deps_mode == "all" then
135 use = true
136 end
137 for _, tree in ipairs(cfg.rocks_trees) do
138 if dir.normalize(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then
139 use = true
140 end
141 if use then
142 table.insert(result, (fn(tree, ...)) or 0)
143 end
144 end
145 end
146 return result
147end
148
149return 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..a2e14efd
--- /dev/null
+++ b/src/luarocks/core/type_check.lua
@@ -0,0 +1,226 @@
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 field
138 end
139 return context.."."..field
140end
141
142--- Type check the contents of a table.
143-- The table's contents are compared against a reference table,
144-- which contains the recognized fields, with archetypical values
145-- matching the expected types -- the actual values of items in the
146-- reference table don't matter, only their types (ie, for field x
147-- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
148-- If the reference table contains a field called MORE, then
149-- unknown fields in the checked table are accepted.
150-- If it contains a field called ANY, then its type will be
151-- used to check any unknown fields. If a field is prefixed
152-- with MUST_, it is mandatory; its absence from the table is
153-- a type error.
154-- Tables are type checked recursively.
155-- @param version string: The version of tbl.
156-- @param tbl table: The table to be type checked.
157-- @param typetbl table: The type-checking table, containing
158-- values for recognized fields in the checked table.
159-- @param context string: A string indicating the "context" where the
160-- error occurred (such as the name of the table the item is a part of),
161-- to be used by error messages.
162-- @return boolean or (nil, string): true if type checking
163-- succeeded, or nil and an error message if it failed.
164function type_check.type_check_table(version, tbl, typetbl, context)
165 assert(type(version) == "string")
166 assert(type(tbl) == "table")
167 assert(type(typetbl) == "table")
168
169 local ok, err = check_version(version, typetbl, context)
170 if not ok then
171 return nil, err
172 end
173
174 for k, v in pairs(tbl) do
175 local t = typetbl[k] or typetbl._any
176 if t then
177 local ok, err = type_check_item(version, v, t, mkfield(context, k))
178 if not ok then return nil, err end
179 elseif typetbl._more then
180 -- Accept unknown field
181 else
182 if not cfg.accept_unknown_fields then
183 return nil, "Unknown field "..k
184 end
185 end
186 end
187 for k, v in pairs(typetbl) do
188 if k:sub(1,1) ~= "_" and v._mandatory then
189 if not tbl[k] then
190 return nil, "Mandatory field "..mkfield(context, k).." is missing."
191 end
192 end
193 end
194 return true
195end
196
197function type_check.check_undeclared_globals(globals, typetbl)
198 local undeclared = {}
199 for glob, _ in pairs(globals) do
200 if not (typetbl[glob] or typetbl["MUST_"..glob]) then
201 table.insert(undeclared, glob)
202 end
203 end
204 if #undeclared == 1 then
205 return nil, "Unknown variable: "..undeclared[1]
206 elseif #undeclared > 1 then
207 return nil, "Unknown variables: "..table.concat(undeclared, ", ")
208 end
209 return true
210end
211
212--- Type check a manifest table.
213-- Verify the correctness of elements from a
214-- manifest table, reporting on unknown fields and type
215-- mismatches.
216-- @return boolean or (nil, string): true if type checking
217-- succeeded, or nil and an error message if it failed.
218function type_check.type_check_manifest(manifest, globals)
219 assert(type(manifest) == "table")
220 local ok, err = type_check.check_undeclared_globals(globals, manifest_types)
221 if not ok then return nil, err end
222 return type_check.type_check_table("1.0", manifest, manifest_types, "")
223end
224
225return type_check
226
diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua
new file mode 100644
index 00000000..4f896b17
--- /dev/null
+++ b/src/luarocks/core/util.lua
@@ -0,0 +1,202 @@
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
201return util
202
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index 0d85d33e..acbf1dd6 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,139 +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--- Check if rockspec format version satisfies version requirement.
162-- @param rockspec table: The rockspec table.
163-- @param version string: required version.
164-- @return boolean: true if rockspec format matches version or is newer, false otherwise.
165function deps.format_is_at_least(rockspec, version)
166 local rockspec_format = rockspec.rockspec_format or "1.0"
167 return deps.parse_version(rockspec_format) >= deps.parse_version(version)
168end
169
170--- Consumes a constraint from a string, converting it to table format. 46--- Consumes a constraint from a string, converting it to table format.
171-- 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
172-- 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
@@ -201,7 +77,7 @@ end
201function deps.parse_constraints(input) 77function deps.parse_constraints(input)
202 assert(type(input) == "string") 78 assert(type(input) == "string")
203 79
204 local constraints, constraint, oinput = {}, nil, input 80 local constraints, oinput, constraint = {}, input
205 while #input > 0 do 81 while #input > 0 do
206 constraint, input = parse_constraint(input) 82 constraint, input = parse_constraint(input)
207 if constraint then 83 if constraint then
@@ -267,65 +143,6 @@ function deps.show_dep(dep, internal)
267 end 143 end
268end 144end
269 145
270--- A more lenient check for equivalence between versions.
271-- This returns true if the requested components of a version
272-- match and ignore the ones that were not given. For example,
273-- when requesting "2", then "2", "2.1", "2.3.5-9"... all match.
274-- When requesting "2.1", then "2.1", "2.1.3" match, but "2.2"
275-- doesn't.
276-- @param version string or table: Version to be tested; may be
277-- in string format or already parsed into a table.
278-- @param requested string or table: Version requested; may be
279-- in string format or already parsed into a table.
280-- @return boolean: True if the tested version matches the requested
281-- version, false otherwise.
282local function partial_match(version, requested)
283 assert(type(version) == "string" or type(version) == "table")
284 assert(type(requested) == "string" or type(version) == "table")
285
286 if type(version) ~= "table" then version = deps.parse_version(version) end
287 if type(requested) ~= "table" then requested = deps.parse_version(requested) end
288 if not version or not requested then return false end
289
290 for i, ri in ipairs(requested) do
291 local vi = version[i] or 0
292 if ri ~= vi then return false end
293 end
294 if requested.revision then
295 return requested.revision == version.revision
296 end
297 return true
298end
299
300--- Check if a version satisfies a set of constraints.
301-- @param version table: A version in table format
302-- @param constraints table: An array of constraints in table format.
303-- @return boolean: True if version satisfies all constraints,
304-- false otherwise.
305function deps.match_constraints(version, constraints)
306 assert(type(version) == "table")
307 assert(type(constraints) == "table")
308 local ok = true
309 setmetatable(version, version_mt)
310 for _, constr in pairs(constraints) do
311 if type(constr.version) == "string" then
312 constr.version = deps.parse_version(constr.version)
313 end
314 local constr_version, constr_op = constr.version, constr.op
315 setmetatable(constr_version, version_mt)
316 if constr_op == "==" then ok = version == constr_version
317 elseif constr_op == "~=" then ok = version ~= constr_version
318 elseif constr_op == ">" then ok = version > constr_version
319 elseif constr_op == "<" then ok = version < constr_version
320 elseif constr_op == ">=" then ok = version >= constr_version
321 elseif constr_op == "<=" then ok = version <= constr_version
322 elseif constr_op == "~>" then ok = partial_match(version, constr_version)
323 end
324 if not ok then break end
325 end
326 return ok
327end
328
329--- Attempt to match a dependency to an installed rock. 146--- Attempt to match a dependency to an installed rock.
330-- @param dep table: A dependency parsed in table format. 147-- @param dep table: A dependency parsed in table format.
331-- @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
@@ -344,7 +161,7 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided)
344 -- Provided rocks have higher priority than manifest's rocks. 161 -- Provided rocks have higher priority than manifest's rocks.
345 versions = { provided } 162 versions = { provided }
346 else 163 else
347 versions = manif_core.get_versions(dep.name, deps_mode) 164 versions = manif.get_versions(dep.name, deps_mode)
348 end 165 end
349 166
350 local latest_version 167 local latest_version
@@ -431,7 +248,8 @@ function deps.fulfill_dependencies(rockspec, deps_mode)
431 end 248 end
432 local supported = nil 249 local supported = nil
433 for _, plat in pairs(rockspec.supported_platforms) do 250 for _, plat in pairs(rockspec.supported_platforms) do
434 local neg, plat = plat:match("^(!?)(.*)") 251 local neg
252 neg, plat = plat:match("^(!?)(.*)")
435 if neg == "!" then 253 if neg == "!" then
436 if deps.platforms_set[plat] then 254 if deps.platforms_set[plat] then
437 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms." 255 return nil, "This rockspec for "..rockspec.package.." does not support "..plat.." platforms."
@@ -704,7 +522,6 @@ function deps.scan_deps(results, missing, manifest, name, version, deps_mode)
704 522
705 local fetch = require("luarocks.fetch") 523 local fetch = require("luarocks.fetch")
706 524
707 local err
708 if results[name] then 525 if results[name] then
709 return results, missing 526 return results, missing
710 end 527 end
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 758fd9c5..8378bbc2 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 show = require("luarocks.show") 7local show = require("luarocks.show")
diff --git a/src/luarocks/download.lua b/src/luarocks/download.lua
index d793cab7..c81958de 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,7 +9,7 @@ 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
15download.help_summary = "Download a specific rock file from a rocks server." 14download.help_summary = "Download a specific rock file from a rocks server."
16download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" 15download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]"
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua
index 2590afd4..9bf1922a 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")
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 a31cbb4e..770da2b7 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 5c6b542c..df9d256d 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 8debaeef..c03db6a0 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 5bac77ce..51e2cf57 100644
--- a/src/luarocks/help.lua
+++ b/src/luarocks/help.lua
@@ -7,7 +7,7 @@
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")
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 10d57f37..c4139fd0 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,9 +8,9 @@ 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
16install.help_summary = "Install a rock." 15install.help_summary = "Install a rock."
17 16
@@ -74,7 +73,7 @@ function install.install_binary_rock(rock_file, deps_mode)
74 73
75 -- For compatibility with .rock files built with LuaRocks 1 74 -- For compatibility with .rock files built with LuaRocks 1
76 if not fs.exists(path.rock_manifest_file(name, version)) then 75 if not fs.exists(path.rock_manifest_file(name, version)) then
77 ok, err = manif.make_rock_manifest(name, version) 76 ok, err = writer.make_rock_manifest(name, version)
78 if err then return nil, err end 77 if err then return nil, err end
79 end 78 end
80 79
@@ -94,7 +93,7 @@ function install.install_binary_rock(rock_file, deps_mode)
94 ok, err = repos.run_hook(rockspec, "post_install") 93 ok, err = repos.run_hook(rockspec, "post_install")
95 if err then return nil, err end 94 if err then return nil, err end
96 95
97 ok, err = manif.update_manifest(name, version, nil, deps_mode) 96 ok, err = writer.update_manifest(name, version, nil, deps_mode)
98 if err then return nil, err end 97 if err then return nil, err end
99 98
100 util.announce_install(rockspec) 99 util.announce_install(rockspec)
diff --git a/src/luarocks/lint.lua b/src/luarocks/lint.lua
index 4c30804b..742f1736 100644
--- a/src/luarocks/lint.lua
+++ b/src/luarocks/lint.lua
@@ -2,7 +2,6 @@
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")
diff --git a/src/luarocks/list.lua b/src/luarocks/list.lua
index 8c9c5107..45f1a26f 100644
--- a/src/luarocks/list.lua
+++ b/src/luarocks/list.lua
@@ -2,11 +2,10 @@
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
diff --git a/src/luarocks/loader.lua b/src/luarocks/loader.lua
index 26280e94..0faaebda 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
25loader.context = {} 28loader.context = {}
26 29
@@ -33,7 +36,7 @@ local function load_rocks_trees()
33 local any_ok = false 36 local any_ok = false
34 local trees = {} 37 local trees = {}
35 for _, tree in ipairs(cfg.rocks_trees) do 38 for _, tree in ipairs(cfg.rocks_trees) do
36 local manifest, err = manif_core.load_local_manifest(path.rocks_dir(tree)) 39 local manifest, err = manif.load_local_manifest(path.rocks_dir(tree))
37 if manifest then 40 if manifest then
38 any_ok = true 41 any_ok = true
39 table.insert(trees, {tree=tree, manifest=manifest}) 42 table.insert(trees, {tree=tree, manifest=manifest})
@@ -217,4 +220,12 @@ end
217 220
218table.insert(loaders, 1, loader.luarocks_loader) 221table.insert(loaders, 1, loader.luarocks_loader)
219 222
223if is_clean then
224 for modname, _ in pairs(package.loaded) do
225 if modname:match("^luarocks%.") then
226 package.loaded[modname] = nil
227 end
228 end
229end
230
220return loader 231return loader
diff --git a/src/luarocks/make.lua b/src/luarocks/make.lua
index 476150eb..eb38bff0 100644
--- a/src/luarocks/make.lua
+++ b/src/luarocks/make.lua
@@ -4,12 +4,11 @@
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")
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua
index e30c2a33..c4da9a8e 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")
@@ -53,38 +30,6 @@ function manif.load_rock_manifest(name, version, root)
53 return rock_manifest.rock_manifest 30 return rock_manifest.rock_manifest
54end 31end
55 32
56function manif.make_rock_manifest(name, version)
57 local install_dir = path.install_dir(name, version)
58 local rock_manifest = path.rock_manifest_file(name, version)
59 local tree = {}
60 for _, file in ipairs(fs.find(install_dir)) do
61 local full_path = dir.path(install_dir, file)
62 local walk = tree
63 local last
64 local last_name
65 for name in file:gmatch("[^/]+") do
66 local next = walk[name]
67 if not next then
68 next = {}
69 walk[name] = next
70 end
71 last = walk
72 last_name = name
73 walk = next
74 end
75 if fs.is_file(full_path) then
76 local sum, err = fs.get_md5(full_path)
77 if not sum then
78 return nil, "Failed producing checksum: "..tostring(err)
79 end
80 last[last_name] = sum
81 end
82 end
83 rock_manifest = { rock_manifest=tree }
84 manif.rock_manifest_cache[name.."/"..version] = rock_manifest
85 save_table(install_dir, "rock_manifest", rock_manifest )
86end
87
88local function fetch_manifest_from(repo_url, filename) 33local function fetch_manifest_from(repo_url, filename)
89 local url = dir.path(repo_url, filename) 34 local url = dir.path(repo_url, filename)
90 local name = repo_url:gsub("[/:]","_") 35 local name = repo_url:gsub("[/:]","_")
@@ -112,7 +57,7 @@ function manif.load_manifest(repo_url, lua_version)
112 assert(type(lua_version) == "string" or not lua_version) 57 assert(type(lua_version) == "string" or not lua_version)
113 lua_version = lua_version or cfg.lua_version 58 lua_version = lua_version or cfg.lua_version
114 59
115 local cached_manifest = manif_core.get_cached_manifest(repo_url, lua_version) 60 local cached_manifest = manif.get_cached_manifest(repo_url, lua_version)
116 if cached_manifest then 61 if cached_manifest then
117 return cached_manifest 62 return cached_manifest
118 end 63 end
@@ -159,316 +104,14 @@ function manif.load_manifest(repo_url, lua_version)
159 end 104 end
160 pathname = nozip 105 pathname = nozip
161 end 106 end
162 return manif_core.manifest_loader(pathname, repo_url, lua_version) 107 return manif.manifest_loader(pathname, repo_url, lua_version)
163end
164
165--- Output a table listing items of a package.
166-- @param itemsfn function: a function for obtaining items of a package.
167-- pkg and version will be passed to it; it should return a table with
168-- items as keys.
169-- @param pkg string: package name
170-- @param version string: package version
171-- @param tbl table: the package matching table: keys should be item names
172-- and values arrays of strings with packages names in "name/version" format.
173local function store_package_items(itemsfn, pkg, version, tbl)
174 assert(type(itemsfn) == "function")
175 assert(type(pkg) == "string")
176 assert(type(version) == "string")
177 assert(type(tbl) == "table")
178
179 local pkg_version = pkg.."/"..version
180 local result = {}
181
182 for item, path in pairs(itemsfn(pkg, version)) do
183 result[item] = path
184 if not tbl[item] then
185 tbl[item] = {}
186 end
187 table.insert(tbl[item], pkg_version)
188 end
189 return result
190end
191
192--- Sort function for ordering rock identifiers in a manifest's
193-- modules table. Rocks are ordered alphabetically by name, and then
194-- by version which greater first.
195-- @param a string: Version to compare.
196-- @param b string: Version to compare.
197-- @return boolean: The comparison result, according to the
198-- rule outlined above.
199local function sort_pkgs(a, b)
200 assert(type(a) == "string")
201 assert(type(b) == "string")
202
203 local na, va = a:match("(.*)/(.*)$")
204 local nb, vb = b:match("(.*)/(.*)$")
205
206 return (na == nb) and deps.compare_versions(va, vb) or na < nb
207end
208
209--- Sort items of a package matching table by version number (higher versions first).
210-- @param tbl table: the package matching table: keys should be strings
211-- and values arrays of strings with packages names in "name/version" format.
212local function sort_package_matching_table(tbl)
213 assert(type(tbl) == "table")
214
215 if next(tbl) then
216 for item, pkgs in pairs(tbl) do
217 if #pkgs > 1 then
218 table.sort(pkgs, sort_pkgs)
219 -- Remove duplicates from the sorted array.
220 local prev = nil
221 local i = 1
222 while pkgs[i] do
223 local curr = pkgs[i]
224 if curr == prev then
225 table.remove(pkgs, i)
226 else
227 prev = curr
228 i = i + 1
229 end
230 end
231 end
232 end
233 end
234end
235
236--- Process the dependencies of a manifest table to determine its dependency
237-- chains for loading modules. The manifest dependencies information is filled
238-- and any dependency inconsistencies or missing dependencies are reported to
239-- standard error.
240-- @param manifest table: a manifest table.
241-- @param deps_mode string: Dependency mode: "one" for the current default tree,
242-- "all" for all trees, "order" for all trees with priority >= the current default,
243-- "none" for no trees.
244local function update_dependencies(manifest, deps_mode)
245 assert(type(manifest) == "table")
246 assert(type(deps_mode) == "string")
247
248 for pkg, versions in pairs(manifest.repository) do
249 for version, repositories in pairs(versions) do
250 local current = pkg.." "..version
251 for _, repo in ipairs(repositories) do
252 if repo.arch == "installed" then
253 local missing
254 repo.dependencies, missing = deps.scan_deps({}, {}, manifest, pkg, version, deps_mode)
255 repo.dependencies[pkg] = nil
256 if missing then
257 for miss, err in pairs(missing) do
258 if miss == current then
259 util.printerr("Tree inconsistency detected: "..current.." has no rockspec. "..err)
260 elseif deps_mode ~= "none" then
261 util.printerr("Missing dependency for "..pkg.." "..version..": "..miss)
262 end
263 end
264 end
265 end
266 end
267 end
268 end
269end
270
271--- Filter manifest table by Lua version, removing rockspecs whose Lua version
272-- does not match.
273-- @param manifest table: a manifest table.
274-- @param lua_version string or nil: filter by Lua version
275-- @param repodir string: directory of repository being scanned
276-- @param cache table: temporary rockspec cache table
277local function filter_by_lua_version(manifest, lua_version, repodir, cache)
278 assert(type(manifest) == "table")
279 assert(type(repodir) == "string")
280 assert((not cache) or type(cache) == "table")
281
282 cache = cache or {}
283 lua_version = deps.parse_version(lua_version)
284 for pkg, versions in pairs(manifest.repository) do
285 local to_remove = {}
286 for version, repositories in pairs(versions) do
287 for _, repo in ipairs(repositories) do
288 if repo.arch == "rockspec" then
289 local pathname = dir.path(repodir, pkg.."-"..version..".rockspec")
290 local rockspec, err = cache[pathname]
291 if not rockspec then
292 rockspec, err = fetch.load_local_rockspec(pathname, true)
293 end
294 if rockspec then
295 cache[pathname] = rockspec
296 for _, dep in ipairs(rockspec.dependencies) do
297 if dep.name == "lua" then
298 if not deps.match_constraints(lua_version, dep.constraints) then
299 table.insert(to_remove, version)
300 end
301 break
302 end
303 end
304 else
305 util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err)
306 end
307 end
308 end
309 end
310 if next(to_remove) then
311 for _, incompat in ipairs(to_remove) do
312 versions[incompat] = nil
313 end
314 if not next(versions) then
315 manifest.repository[pkg] = nil
316 end
317 end
318 end
319end
320
321--- Store search results in a manifest table.
322-- @param results table: The search results as returned by search.disk_search.
323-- @param manifest table: A manifest table (must contain repository, modules, commands tables).
324-- It will be altered to include the search results.
325-- @param dep_handler: dependency handler function
326-- @return boolean or (nil, string): true in case of success, or nil followed by an error message.
327local function store_results(results, manifest, dep_handler)
328 assert(type(results) == "table")
329 assert(type(manifest) == "table")
330 assert((not dep_handler) or type(dep_handler) == "function")
331
332 for name, versions in pairs(results) do
333 local pkgtable = manifest.repository[name] or {}
334 for version, entries in pairs(versions) do
335 local versiontable = {}
336 for _, entry in ipairs(entries) do
337 local entrytable = {}
338 entrytable.arch = entry.arch
339 if entry.arch == "installed" then
340 local rock_manifest = manif.load_rock_manifest(name, version)
341 if not rock_manifest then
342 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
343 end
344 entrytable.modules = store_package_items(repos.package_modules, name, version, manifest.modules)
345 entrytable.commands = store_package_items(repos.package_commands, name, version, manifest.commands)
346 end
347 table.insert(versiontable, entrytable)
348 end
349 pkgtable[version] = versiontable
350 end
351 manifest.repository[name] = pkgtable
352 end
353 if dep_handler then
354 dep_handler(manifest)
355 end
356 sort_package_matching_table(manifest.modules)
357 sort_package_matching_table(manifest.commands)
358 return true
359end
360
361--- Scan a LuaRocks repository and output a manifest file.
362-- A file called 'manifest' will be written in the root of the given
363-- repository directory.
364-- @param repo A local repository directory.
365-- @param deps_mode string: Dependency mode: "one" for the current default tree,
366-- "all" for all trees, "order" for all trees with priority >= the current default,
367-- "none" for the default dependency mode from the configuration.
368-- @param versioned boolean: if versioned versions of the manifest should be created.
369-- @return boolean or (nil, string): True if manifest was generated,
370-- or nil and an error message.
371function manif.make_manifest(repo, deps_mode, remote)
372 assert(type(repo) == "string")
373 assert(type(deps_mode) == "string")
374
375 if deps_mode == "none" then deps_mode = cfg.deps_mode end
376
377 if not fs.is_dir(repo) then
378 return nil, "Cannot access repository at "..repo
379 end
380
381 local query = search.make_query("")
382 query.exact_name = false
383 query.arch = "any"
384 local results = search.disk_search(repo, query)
385 local manifest = { repository = {}, modules = {}, commands = {} }
386
387 manif_core.cache_manifest(repo, nil, manifest)
388
389 local dep_handler = nil
390 if not remote then
391 dep_handler = function(manifest)
392 update_dependencies(manifest, deps_mode)
393 end
394 end
395 local ok, err = store_results(results, manifest, dep_handler)
396 if not ok then return nil, err end
397
398 if remote then
399 local cache = {}
400 for luaver in util.lua_versions() do
401 local vmanifest = { repository = {}, modules = {}, commands = {} }
402 local dep_handler = function(manifest)
403 filter_by_lua_version(manifest, luaver, repo, cache)
404 end
405 local ok, err = store_results(results, vmanifest, dep_handler)
406 save_table(repo, "manifest-"..luaver, vmanifest)
407 end
408 end
409
410 return save_table(repo, "manifest", manifest)
411end
412
413--- Load a manifest file from a local repository and add to the repository
414-- information with regard to the given name and version.
415-- A file called 'manifest' will be written in the root of the given
416-- repository directory.
417-- @param name string: Name of a package from the repository.
418-- @param version string: Version of a package from the repository.
419-- @param repo string or nil: Pathname of a local repository. If not given,
420-- the default local repository is used.
421-- @param deps_mode string: Dependency mode: "one" for the current default tree,
422-- "all" for all trees, "order" for all trees with priority >= the current default,
423-- "none" for using the default dependency mode from the configuration.
424-- @return boolean or (nil, string): True if manifest was generated,
425-- or nil and an error message.
426function manif.update_manifest(name, version, repo, deps_mode)
427 assert(type(name) == "string")
428 assert(type(version) == "string")
429 repo = path.rocks_dir(repo or cfg.root_dir)
430 assert(type(deps_mode) == "string")
431
432 if deps_mode == "none" then deps_mode = cfg.deps_mode end
433
434 local manifest, err = manif.load_manifest(repo)
435 if not manifest then
436 util.printerr("No existing manifest. Attempting to rebuild...")
437 local ok, err = manif.make_manifest(repo, deps_mode)
438 if not ok then
439 return nil, err
440 end
441 manifest, err = manif.load_manifest(repo)
442 if not manifest then
443 return nil, err
444 end
445 end
446
447 local results = {[name] = {[version] = {{arch = "installed", repo = repo}}}}
448
449 local dep_handler = function(manifest)
450 update_dependencies(manifest, deps_mode)
451 end
452 local ok, err = store_results(results, manifest, dep_handler)
453 if not ok then return nil, err end
454
455 return save_table(repo, "manifest", manifest)
456end
457
458function manif.zip_manifests()
459 for ver in util.lua_versions() do
460 local file = "manifest-"..ver
461 local zip = file..".zip"
462 fs.delete(dir.path(fs.current_dir(), zip))
463 fs.zip(zip, file)
464 end
465end 108end
466 109
467local function find_providers(file, root) 110local function find_providers(file, root)
468 assert(type(file) == "string") 111 assert(type(file) == "string")
469 root = root or cfg.root_dir 112 root = root or cfg.root_dir
470 113
471 local manifest, err = manif_core.load_local_manifest(path.rocks_dir(root)) 114 local manifest, err = manif.load_local_manifest(path.rocks_dir(root))
472 if not manifest then 115 if not manifest then
473 return nil, "untracked" 116 return nil, "untracked"
474 end 117 end
diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua
new file mode 100644
index 00000000..75ea3b81
--- /dev/null
+++ b/src/luarocks/manif/writer.lua
@@ -0,0 +1,360 @@
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--- Output a table listing items of a package.
17-- @param itemsfn function: a function for obtaining items of a package.
18-- pkg and version will be passed to it; it should return a table with
19-- items as keys.
20-- @param pkg string: package name
21-- @param version string: package version
22-- @param tbl table: the package matching table: keys should be item names
23-- and values arrays of strings with packages names in "name/version" format.
24local function store_package_items(itemsfn, pkg, version, tbl)
25 assert(type(itemsfn) == "function")
26 assert(type(pkg) == "string")
27 assert(type(version) == "string")
28 assert(type(tbl) == "table")
29
30 local pkg_version = pkg.."/"..version
31 local result = {}
32
33 for item, path in pairs(itemsfn(pkg, version)) do
34 result[item] = path
35 if not tbl[item] then
36 tbl[item] = {}
37 end
38 table.insert(tbl[item], pkg_version)
39 end
40 return result
41end
42
43
44--- Process the dependencies of a manifest table to determine its dependency
45-- chains for loading modules. The manifest dependencies information is filled
46-- and any dependency inconsistencies or missing dependencies are reported to
47-- standard error.
48-- @param manifest table: a manifest table.
49-- @param deps_mode string: Dependency mode: "one" for the current default tree,
50-- "all" for all trees, "order" for all trees with priority >= the current default,
51-- "none" for no trees.
52local function update_dependencies(manifest, deps_mode)
53 assert(type(manifest) == "table")
54 assert(type(deps_mode) == "string")
55
56 for pkg, versions in pairs(manifest.repository) do
57 for version, repositories in pairs(versions) do
58 local current = pkg.." "..version
59 for _, repo in ipairs(repositories) do
60 if repo.arch == "installed" then
61 local missing
62 repo.dependencies, missing = deps.scan_deps({}, {}, manifest, pkg, version, deps_mode)
63 repo.dependencies[pkg] = nil
64 if missing then
65 for miss, err in pairs(missing) do
66 if miss == current then
67 util.printerr("Tree inconsistency detected: "..current.." has no rockspec. "..err)
68 elseif deps_mode ~= "none" then
69 util.printerr("Missing dependency for "..pkg.." "..version..": "..miss)
70 end
71 end
72 end
73 end
74 end
75 end
76 end
77end
78
79--- Sort function for ordering rock identifiers in a manifest's
80-- modules table. Rocks are ordered alphabetically by name, and then
81-- by version which greater first.
82-- @param a string: Version to compare.
83-- @param b string: Version to compare.
84-- @return boolean: The comparison result, according to the
85-- rule outlined above.
86local function sort_pkgs(a, b)
87 assert(type(a) == "string")
88 assert(type(b) == "string")
89
90 local na, va = a:match("(.*)/(.*)$")
91 local nb, vb = b:match("(.*)/(.*)$")
92
93 return (na == nb) and deps.compare_versions(va, vb) or na < nb
94end
95
96--- Sort items of a package matching table by version number (higher versions first).
97-- @param tbl table: the package matching table: keys should be strings
98-- and values arrays of strings with packages names in "name/version" format.
99local function sort_package_matching_table(tbl)
100 assert(type(tbl) == "table")
101
102 if next(tbl) then
103 for item, pkgs in pairs(tbl) do
104 if #pkgs > 1 then
105 table.sort(pkgs, sort_pkgs)
106 -- Remove duplicates from the sorted array.
107 local prev = nil
108 local i = 1
109 while pkgs[i] do
110 local curr = pkgs[i]
111 if curr == prev then
112 table.remove(pkgs, i)
113 else
114 prev = curr
115 i = i + 1
116 end
117 end
118 end
119 end
120 end
121end
122
123--- Filter manifest table by Lua version, removing rockspecs whose Lua version
124-- does not match.
125-- @param manifest table: a manifest table.
126-- @param lua_version string or nil: filter by Lua version
127-- @param repodir string: directory of repository being scanned
128-- @param cache table: temporary rockspec cache table
129local function filter_by_lua_version(manifest, lua_version, repodir, cache)
130 assert(type(manifest) == "table")
131 assert(type(repodir) == "string")
132 assert((not cache) or type(cache) == "table")
133
134 cache = cache or {}
135 lua_version = deps.parse_version(lua_version)
136 for pkg, versions in pairs(manifest.repository) do
137 local to_remove = {}
138 for version, repositories in pairs(versions) do
139 for _, repo in ipairs(repositories) do
140 if repo.arch == "rockspec" then
141 local pathname = dir.path(repodir, pkg.."-"..version..".rockspec")
142 local rockspec, err = cache[pathname]
143 if not rockspec then
144 rockspec, err = fetch.load_local_rockspec(pathname, true)
145 end
146 if rockspec then
147 cache[pathname] = rockspec
148 for _, dep in ipairs(rockspec.dependencies) do
149 if dep.name == "lua" then
150 if not deps.match_constraints(lua_version, dep.constraints) then
151 table.insert(to_remove, version)
152 end
153 break
154 end
155 end
156 else
157 util.printerr("Error loading rockspec for "..pkg.." "..version..": "..err)
158 end
159 end
160 end
161 end
162 if next(to_remove) then
163 for _, incompat in ipairs(to_remove) do
164 versions[incompat] = nil
165 end
166 if not next(versions) then
167 manifest.repository[pkg] = nil
168 end
169 end
170 end
171end
172
173--- Store search results in a manifest table.
174-- @param results table: The search results as returned by search.disk_search.
175-- @param manifest table: A manifest table (must contain repository, modules, commands tables).
176-- It will be altered to include the search results.
177-- @param dep_handler: dependency handler function
178-- @return boolean or (nil, string): true in case of success, or nil followed by an error message.
179local function store_results(results, manifest, dep_handler)
180 assert(type(results) == "table")
181 assert(type(manifest) == "table")
182 assert((not dep_handler) or type(dep_handler) == "function")
183
184 for name, versions in pairs(results) do
185 local pkgtable = manifest.repository[name] or {}
186 for version, entries in pairs(versions) do
187 local versiontable = {}
188 for _, entry in ipairs(entries) do
189 local entrytable = {}
190 entrytable.arch = entry.arch
191 if entry.arch == "installed" then
192 local rock_manifest = manif.load_rock_manifest(name, version)
193 if not rock_manifest then
194 return nil, "rock_manifest file not found for "..name.." "..version.." - not a LuaRocks 2 tree?"
195 end
196 entrytable.modules = store_package_items(repos.package_modules, name, version, manifest.modules)
197 entrytable.commands = store_package_items(repos.package_commands, name, version, manifest.commands)
198 end
199 table.insert(versiontable, entrytable)
200 end
201 pkgtable[version] = versiontable
202 end
203 manifest.repository[name] = pkgtable
204 end
205 if dep_handler then
206 dep_handler(manifest)
207 end
208 sort_package_matching_table(manifest.modules)
209 sort_package_matching_table(manifest.commands)
210 return true
211end
212
213--- Commit a table to disk in given local path.
214-- @param where string: The directory where the table should be saved.
215-- @param name string: The filename.
216-- @param tbl table: The table to be saved.
217-- @return boolean or (nil, string): true if successful, or nil and a
218-- message in case of errors.
219local function save_table(where, name, tbl)
220 assert(type(where) == "string")
221 assert(type(name) == "string")
222 assert(type(tbl) == "table")
223
224 local filename = dir.path(where, name)
225 local ok, err = persist.save_from_table(filename..".tmp", tbl)
226 if ok then
227 ok, err = fs.replace_file(filename, filename..".tmp")
228 end
229 return ok, err
230end
231
232function writer.make_rock_manifest(name, version)
233 local install_dir = path.install_dir(name, version)
234 local tree = {}
235 for _, file in ipairs(fs.find(install_dir)) do
236 local full_path = dir.path(install_dir, file)
237 local walk = tree
238 local last
239 local last_name
240 for filename in file:gmatch("[^/]+") do
241 local next = walk[filename]
242 if not next then
243 next = {}
244 walk[filename] = next
245 end
246 last = walk
247 last_name = filename
248 walk = next
249 end
250 if fs.is_file(full_path) then
251 local sum, err = fs.get_md5(full_path)
252 if not sum then
253 return nil, "Failed producing checksum: "..tostring(err)
254 end
255 last[last_name] = sum
256 end
257 end
258 local rock_manifest = { rock_manifest=tree }
259 manif.rock_manifest_cache[name.."/"..version] = rock_manifest
260 save_table(install_dir, "rock_manifest", rock_manifest )
261end
262
263--- Scan a LuaRocks repository and output a manifest file.
264-- A file called 'manifest' will be written in the root of the given
265-- repository directory.
266-- @param repo A local repository directory.
267-- @param deps_mode string: Dependency mode: "one" for the current default tree,
268-- "all" for all trees, "order" for all trees with priority >= the current default,
269-- "none" for the default dependency mode from the configuration.
270-- @param versioned boolean: if versioned versions of the manifest should be created.
271-- @return boolean or (nil, string): True if manifest was generated,
272-- or nil and an error message.
273function writer.make_manifest(repo, deps_mode, remote)
274 assert(type(repo) == "string")
275 assert(type(deps_mode) == "string")
276
277 if deps_mode == "none" then deps_mode = cfg.deps_mode end
278
279 if not fs.is_dir(repo) then
280 return nil, "Cannot access repository at "..repo
281 end
282
283 local query = search.make_query("")
284 query.exact_name = false
285 query.arch = "any"
286 local results = search.disk_search(repo, query)
287 local manifest = { repository = {}, modules = {}, commands = {} }
288
289 manif.cache_manifest(repo, nil, manifest)
290
291 local dep_handler = nil
292 if not remote then
293 dep_handler = function(manifest)
294 update_dependencies(manifest, deps_mode)
295 end
296 end
297 local ok, err = store_results(results, manifest, dep_handler)
298 if not ok then return nil, err end
299
300 if remote then
301 local cache = {}
302 for luaver in util.lua_versions() do
303 local vmanifest = { repository = {}, modules = {}, commands = {} }
304 local dep_handler = function(manifest)
305 filter_by_lua_version(manifest, luaver, repo, cache)
306 end
307 store_results(results, vmanifest, dep_handler)
308 save_table(repo, "manifest-"..luaver, vmanifest)
309 end
310 end
311
312 return save_table(repo, "manifest", manifest)
313end
314
315--- Load a manifest file from a local repository and add to the repository
316-- information with regard to the given name and version.
317-- A file called 'manifest' will be written in the root of the given
318-- repository directory.
319-- @param name string: Name of a package from the repository.
320-- @param version string: Version of a package from the repository.
321-- @param repo string or nil: Pathname of a local repository. If not given,
322-- the default local repository is used.
323-- @param deps_mode string: Dependency mode: "one" for the current default tree,
324-- "all" for all trees, "order" for all trees with priority >= the current default,
325-- "none" for using the default dependency mode from the configuration.
326-- @return boolean or (nil, string): True if manifest was generated,
327-- or nil and an error message.
328function writer.update_manifest(name, version, repo, deps_mode)
329 assert(type(name) == "string")
330 assert(type(version) == "string")
331 repo = path.rocks_dir(repo or cfg.root_dir)
332 assert(type(deps_mode) == "string")
333
334 if deps_mode == "none" then deps_mode = cfg.deps_mode end
335
336 local manifest, err = manif.load_manifest(repo)
337 if not manifest then
338 util.printerr("No existing manifest. Attempting to rebuild...")
339 local ok, err = writer.make_manifest(repo, deps_mode)
340 if not ok then
341 return nil, err
342 end
343 manifest, err = manif.load_manifest(repo)
344 if not manifest then
345 return nil, err
346 end
347 end
348
349 local results = {[name] = {[version] = {{arch = "installed", repo = repo}}}}
350
351 local dep_handler = function(manifest)
352 update_dependencies(manifest, deps_mode)
353 end
354 local ok, err = store_results(results, manifest, dep_handler)
355 if not ok then return nil, err end
356
357 return save_table(repo, "manifest", manifest)
358end
359
360return writer
diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua
index 3a163e92..b85653e9 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,7 +9,7 @@ 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")
diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua
index 6219d8c6..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,39 +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 else
254 name = file:match("(.*)%."..cfg.static_lib_extension.."$")
255 if name then
256 name = name:gsub(dir.separator, ".")
257 end
258 end
259 end
260 if not name then name = file end
261 name = name:gsub("^%.+", ""):gsub("%.+$", "")
262 return name
263end
264
265--- Obtain the directory name where a module should be stored. 197--- Obtain the directory name where a module should be stored.
266-- For example, on Unix, "foo.bar.baz" will return "foo/bar". 198-- For example, on Unix, "foo.bar.baz" will return "foo/bar".
267-- @param mod string: A module name in Lua dot-separated format. 199-- @param mod string: A module name in Lua dot-separated format.
@@ -291,22 +223,6 @@ function path.configure_paths(rockspec)
291 rockspec.variables = vars 223 rockspec.variables = vars
292end 224end
293 225
294--- Produce a versioned version of a filename.
295-- @param file string: filename (must start with prefix)
296-- @param prefix string: Path prefix for file
297-- @param name string: Rock name
298-- @param version string: Rock version
299-- @return string: a pathname with the same directory parts and a versioned basename.
300function path.versioned_name(file, prefix, name, version)
301 assert(type(file) == "string")
302 assert(type(name) == "string")
303 assert(type(version) == "string")
304
305 local rest = file:sub(#prefix+1):gsub("^/*", "")
306 local name_version = (name.."_"..version):gsub("%-", "_"):gsub("%.", "_")
307 return dir.path(prefix, name_version.."-"..rest)
308end
309
310function path.use_tree(tree) 226function path.use_tree(tree)
311 cfg.root_dir = tree 227 cfg.root_dir = tree
312 cfg.rocks_dir = path.rocks_dir(tree) 228 cfg.rocks_dir = path.rocks_dir(tree)
@@ -315,60 +231,6 @@ function path.use_tree(tree)
315 cfg.deploy_lib_dir = path.deploy_lib_dir(tree) 231 cfg.deploy_lib_dir = path.deploy_lib_dir(tree)
316end 232end
317 233
318--- Apply a given function to the active rocks trees based on chosen dependency mode.
319-- @param deps_mode string: Dependency mode: "one" for the current default tree,
320-- "all" for all trees, "order" for all trees with priority >= the current default,
321-- "none" for no trees (this function becomes a nop).
322-- @param fn function: function to be applied, with the tree dir (string) as the first
323-- argument and the remaining varargs of map_trees as the following arguments.
324-- @return a table with all results of invocations of fn collected.
325function path.map_trees(deps_mode, fn, ...)
326 local result = {}
327 if deps_mode == "one" then
328 table.insert(result, (fn(cfg.root_dir, ...)) or 0)
329 elseif deps_mode == "all" or deps_mode == "order" then
330 local use = false
331 if deps_mode == "all" then
332 use = true
333 end
334 for _, tree in ipairs(cfg.rocks_trees) do
335 if dir.normalize(path.rocks_tree_to_string(tree)) == dir.normalize(path.rocks_tree_to_string(cfg.root_dir)) then
336 use = true
337 end
338 if use then
339 table.insert(result, (fn(tree, ...)) or 0)
340 end
341 end
342 end
343 return result
344end
345
346local is_src_extension = { [".lua"] = true, [".tl"] = true, [".tld"] = true, [".moon"] = true }
347
348--- Return the pathname of the file that would be loaded for a module, indexed.
349-- @param file_name string: module file name as in manifest (eg. "socket/core.so")
350-- @param name string: name of the package (eg. "luasocket")
351-- @param version string: version number (eg. "2.0.2-1")
352-- @param tree string: repository path (eg. "/usr/local")
353-- @param i number: the index, 1 if version is the current default, > 1 otherwise.
354-- This is done this way for use by select_module in luarocks.loader.
355-- @return string: filename of the module (eg. "/usr/local/lib/lua/5.1/socket/core.so")
356function path.which_i(file_name, name, version, tree, i)
357 local deploy_dir
358 local extension = file_name:match("%.[a-z]+$")
359 if is_src_extension[extension] then
360 deploy_dir = path.deploy_lua_dir(tree)
361 file_name = dir.path(deploy_dir, file_name)
362 else
363 deploy_dir = path.deploy_lib_dir(tree)
364 file_name = dir.path(deploy_dir, file_name)
365 end
366 if i > 1 then
367 file_name = path.versioned_name(file_name, deploy_dir, name, version)
368 end
369 return file_name
370end
371
372--- 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,
373-- 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
374-- in the given manifest. 236-- in the given manifest.
diff --git a/src/luarocks/path_cmd.lua b/src/luarocks/path_cmd.lua
index c0329977..1f5bb07f 100644
--- a/src/luarocks/path_cmd.lua
+++ b/src/luarocks/path_cmd.lua
@@ -5,7 +5,7 @@ local path_cmd = {}
5 5
6local util = require("luarocks.util") 6local util = require("luarocks.util")
7local deps = require("luarocks.deps") 7local deps = require("luarocks.deps")
8local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.core.cfg")
9 9
10path_cmd.help_summary = "Return the currently configured package path." 10path_cmd.help_summary = "Return the currently configured package path."
11path_cmd.help_arguments = "" 11path_cmd.help_arguments = ""
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 18043cc3..7647a243 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,8 +9,8 @@ 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
17purge.help_summary = "Remove all installed rocks from a tree." 16purge.help_summary = "Remove all installed rocks from a tree."
@@ -55,7 +54,7 @@ function purge.command(flags)
55 end 54 end
56 55
57 for package, versions in util.sortedpairs(results) do 56 for package, versions in util.sortedpairs(results) do
58 for version, repositories in util.sortedpairs(versions, sort) do 57 for version, _ in util.sortedpairs(versions, sort) do
59 if flags["old-versions"] then 58 if flags["old-versions"] then
60 util.printout("Keeping "..package.." "..version.."...") 59 util.printout("Keeping "..package.." "..version.."...")
61 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"])
@@ -72,7 +71,7 @@ function purge.command(flags)
72 end 71 end
73 end 72 end
74 end 73 end
75 return manif.make_manifest(cfg.rocks_dir, "one") 74 return writer.make_manifest(cfg.rocks_dir, "one")
76end 75end
77 76
78return purge 77return purge
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua
index 3f62e89e..e2c05176 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,8 +9,8 @@ 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 manif = require("luarocks.manif") 13local writer = require("luarocks.manif.writer")
15local fs = require("luarocks.fs") 14local fs = require("luarocks.fs")
16 15
17remove.help_summary = "Uninstall a rock." 16remove.help_summary = "Uninstall a rock."
@@ -113,7 +112,7 @@ function remove.remove_search_results(results, name, deps_mode, force, fast)
113 112
114 local ok, err = delete_versions(name, versions) 113 local ok, err = delete_versions(name, versions)
115 if not ok then return nil, err end 114 if not ok then return nil, err end
116 ok, err = manif.make_manifest(cfg.rocks_dir, deps_mode) 115 ok, err = writer.make_manifest(cfg.rocks_dir, deps_mode)
117 if not ok then return nil, err end 116 if not ok then return nil, err end
118 117
119 util.printout("Removal successful.") 118 util.printout("Removal successful.")
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
index 86126a13..7acb00b9 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")
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
index c3f00a7c..7d4f3e81 100644
--- a/src/luarocks/search.lua
+++ b/src/luarocks/search.lua
@@ -2,13 +2,13 @@
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
14search.help_summary = "Query the LuaRocks servers." 14search.help_summary = "Query the LuaRocks servers."
diff --git a/src/luarocks/show.lua b/src/luarocks/show.lua
index df992f5c..f0bf2164 100644
--- a/src/luarocks/show.lua
+++ b/src/luarocks/show.lua
@@ -1,10 +1,9 @@
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")
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua
index 287d8151..382d3f0a 100644
--- a/src/luarocks/type_check.lua
+++ b/src/luarocks/type_check.lua
@@ -2,16 +2,12 @@
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
7local cfg = require("luarocks.cfg")
8local deps = require("luarocks.deps")
9 6
10type_check.rockspec_format = "3.0" 7type_check.rockspec_format = "3.0"
11 8
12local string_1 = { _type = "string" } 9local string_1 = type_check.string_1
13local number_1 = { _type = "number" } 10local mandatory_string_1 = type_check.mandatory_string_1
14local mandatory_string_1 = { _type = "string", _mandatory = true }
15 11
16-- Syntax for type-checking tables: 12-- Syntax for type-checking tables:
17-- 13--
@@ -112,203 +108,6 @@ rockspec_types.external_dependencies.platforms._any = rockspec_types.external_de
112rockspec_types.source.platforms._any = rockspec_types.source 108rockspec_types.source.platforms._any = rockspec_types.source
113rockspec_types.hooks.platforms._any = rockspec_types.hooks 109rockspec_types.hooks.platforms._any = rockspec_types.hooks
114 110
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 field
238 end
239 return context.."."..field
240end
241
242--- Type check the contents of a table.
243-- The table's contents are compared against a reference table,
244-- which contains the recognized fields, with archetypical values
245-- matching the expected types -- the actual values of items in the
246-- reference table don't matter, only their types (ie, for field x
247-- in tbl that is correctly typed, type(tbl.x) == type(types.x)).
248-- If the reference table contains a field called MORE, then
249-- unknown fields in the checked table are accepted.
250-- If it contains a field called ANY, then its type will be
251-- used to check any unknown fields. If a field is prefixed
252-- with MUST_, it is mandatory; its absence from the table is
253-- a type error.
254-- Tables are type checked recursively.
255-- @param version string: The version of tbl.
256-- @param tbl table: The table to be type checked.
257-- @param typetbl table: The type-checking table, containing
258-- values for recognized fields in the checked table.
259-- @param context string: A string indicating the "context" where the
260-- error occurred (such as the name of the table the item is a part of),
261-- to be used by error messages.
262-- @return boolean or (nil, string): true if type checking
263-- succeeded, or nil and an error message if it failed.
264type_check_table = function(version, tbl, typetbl, context)
265 assert(type(version) == "string")
266 assert(type(tbl) == "table")
267 assert(type(typetbl) == "table")
268
269 local ok, err = check_version(version, typetbl, context)
270 if not ok then
271 return nil, err
272 end
273
274 for k, v in pairs(tbl) do
275 local t = typetbl[k] or typetbl._any
276 if t then
277 local ok, err = type_check_item(version, v, t, mkfield(context, k))
278 if not ok then return nil, err end
279 elseif typetbl._more then
280 -- Accept unknown field
281 else
282 if not cfg.accept_unknown_fields then
283 return nil, "Unknown field "..k
284 end
285 end
286 end
287 for k, v in pairs(typetbl) do
288 if k:sub(1,1) ~= "_" and v._mandatory then
289 if not tbl[k] then
290 return nil, "Mandatory field "..mkfield(context, k).." is missing."
291 end
292 end
293 end
294 return true
295end
296
297local function check_undeclared_globals(globals, typetbl)
298 local undeclared = {}
299 for glob, _ in pairs(globals) do
300 if not (typetbl[glob] or typetbl["MUST_"..glob]) then
301 table.insert(undeclared, glob)
302 end
303 end
304 if #undeclared == 1 then
305 return nil, "Unknown variable: "..undeclared[1]
306 elseif #undeclared > 1 then
307 return nil, "Unknown variables: "..table.concat(undeclared, ", ")
308 end
309 return true
310end
311
312--- Type check a rockspec table. 111--- Type check a rockspec table.
313-- Verify the correctness of elements from a 112-- Verify the correctness of elements from a
314-- rockspec table, reporting on unknown fields and type 113-- rockspec table, reporting on unknown fields and type
@@ -320,22 +119,9 @@ function type_check.type_check_rockspec(rockspec, globals)
320 if not rockspec.rockspec_format then 119 if not rockspec.rockspec_format then
321 rockspec.rockspec_format = "1.0" 120 rockspec.rockspec_format = "1.0"
322 end 121 end
323 local ok, err = check_undeclared_globals(globals, rockspec_types) 122 local ok, err = type_check.check_undeclared_globals(globals, rockspec_types)
324 if not ok then return nil, err end
325 return type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "")
326end
327
328--- Type check a manifest table.
329-- Verify the correctness of elements from a
330-- manifest table, reporting on unknown fields and type
331-- mismatches.
332-- @return boolean or (nil, string): true if type checking
333-- succeeded, or nil and an error message if it failed.
334function type_check.type_check_manifest(manifest, globals)
335 assert(type(manifest) == "table")
336 local ok, err = check_undeclared_globals(globals, manifest_types)
337 if not ok then return nil, err end 123 if not ok then return nil, err end
338 return type_check_table("1.0", manifest, manifest_types, "") 124 return type_check.type_check_table(rockspec.rockspec_format, rockspec, rockspec_types, "")
339end 125end
340 126
341return type_check 127return type_check
diff --git a/src/luarocks/unpack.lua b/src/luarocks/unpack.lua
index 4e4d9a06..22b3f49b 100644
--- a/src/luarocks/unpack.lua
+++ b/src/luarocks/unpack.lua
@@ -2,14 +2,13 @@
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
14unpack.help_summary = "Unpack the contents of a rock." 13unpack.help_summary = "Unpack the contents of a rock."
15unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}" 14unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}"
diff --git a/src/luarocks/upload.lua b/src/luarocks/upload.lua
index 5031b1ef..4bda4303 100644
--- a/src/luarocks/upload.lua
+++ b/src/luarocks/upload.lua
@@ -4,7 +4,7 @@ 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
10upload.help_summary = "Upload a rockspec to the public rocks repository." 10upload.help_summary = "Upload a rockspec to the public rocks repository."
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 d27710c1..f41b1c38 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -2,26 +2,13 @@
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
11--- Run a process and read a its output.
12-- Equivalent to io.popen(cmd):read("*l"), except that it
13-- closes the fd right away.
14-- @param cmd string: The command to execute
15-- @param spec string: "*l" by default, to read a single line.
16-- May be used to read more, passing, for instance, "*a".
17-- @return string: the output of the program.
18function util.popen_read(cmd, spec)
19 local fd = io.popen(cmd)
20 local out = fd:read(spec or "*l")
21 fd:close()
22 return out
23end
24
25local scheduled_functions = {} 12local scheduled_functions = {}
26local debug = require("debug") 13local debug = require("debug")
27 14
@@ -210,27 +197,6 @@ function util.parse_flags(...)
210 return flags, unpack(out) 197 return flags, unpack(out)
211end 198end
212 199
213--- Merges contents of src on top of dst's contents.
214-- @param dst Destination table, which will receive src's contents.
215-- @param src Table which provides new contents to dst.
216-- @see platform_overrides
217function util.deep_merge(dst, src)
218 for k, v in pairs(src) do
219 if type(v) == "table" then
220 if not dst[k] then
221 dst[k] = {}
222 end
223 if type(dst[k]) == "table" then
224 util.deep_merge(dst[k], v)
225 else
226 dst[k] = v
227 end
228 else
229 dst[k] = v
230 end
231 end
232end
233
234--- Perform platform-specific overrides on a table. 200--- Perform platform-specific overrides on a table.
235-- Overrides values of table with the contents of the appropriate 201-- Overrides values of table with the contents of the appropriate
236-- subset of its "platforms" field. The "platforms" field should 202-- subset of its "platforms" field. The "platforms" field should
@@ -247,7 +213,7 @@ end
247function util.platform_overrides(tbl) 213function util.platform_overrides(tbl)
248 assert(type(tbl) == "table" or not tbl) 214 assert(type(tbl) == "table" or not tbl)
249 215
250 local cfg = require("luarocks.cfg") 216 local cfg = require("luarocks.core.cfg")
251 217
252 if not tbl then return end 218 if not tbl then return end
253 219
@@ -264,19 +230,6 @@ end
264 230
265local var_format_pattern = "%$%((%a[%a%d_]+)%)" 231local var_format_pattern = "%$%((%a[%a%d_]+)%)"
266 232
267--- Create a new shallow copy of a table: a new table with
268-- the same keys and values. Keys point to the same objects as
269-- the original table (ie, does not copy recursively).
270-- @param tbl table: the input table
271-- @return table: a new table with the same contents.
272function util.make_shallow_copy(tbl)
273 local copy = {}
274 for k,v in pairs(tbl) do
275 copy[k] = v
276 end
277 return copy
278end
279
280-- Check if a set of needed variables are referenced 233-- Check if a set of needed variables are referenced
281-- somewhere in a list of definitions, warning the user 234-- somewhere in a list of definitions, warning the user
282-- about any unused ones. Each key in needed_set should 235-- about any unused ones. Each key in needed_set should
@@ -339,17 +292,6 @@ function util.variable_substitutions(tbl, vars)
339 end 292 end
340end 293end
341 294
342--- Return an array of keys of a table.
343-- @param tbl table: The input table.
344-- @return table: The array of keys.
345function util.keys(tbl)
346 local ks = {}
347 for k,_ in pairs(tbl) do
348 table.insert(ks, k)
349 end
350 return ks
351end
352
353local function default_sort(a, b) 295local function default_sort(a, b)
354 local ta = type(a) 296 local ta = type(a)
355 local tb = type(b) 297 local tb = type(b)
@@ -431,12 +373,6 @@ function util.printout(...)
431 io.stdout:write("\n") 373 io.stdout:write("\n")
432end 374end
433 375
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. 376--- Display a warning message.
441-- @param msg string: the warning message 377-- @param msg string: the warning message
442function util.warning(msg) 378function util.warning(msg)
@@ -465,7 +401,7 @@ function util.this_program(default)
465end 401end
466 402
467function util.deps_mode_help(program) 403function util.deps_mode_help(program)
468 local cfg = require("luarocks.cfg") 404 local cfg = require("luarocks.core.cfg")
469 return [[ 405 return [[
470--deps-mode=<mode> How to handle dependencies. Four modes are supported: 406--deps-mode=<mode> How to handle dependencies. Four modes are supported:
471 * all - use all trees from the rocks_trees list 407 * all - use all trees from the rocks_trees list
@@ -488,7 +424,7 @@ function util.see_help(command, program)
488end 424end
489 425
490function util.announce_install(rockspec) 426function util.announce_install(rockspec)
491 local cfg = require("luarocks.cfg") 427 local cfg = require("luarocks.core.cfg")
492 local path = require("luarocks.path") 428 local path = require("luarocks.path")
493 429
494 local suffix = "" 430 local suffix = ""
@@ -566,135 +502,6 @@ function util.get_default_rockspec()
566 end 502 end
567end 503end
568 504
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) 505function util.array_contains(tbl, value)
699 for _, v in ipairs(tbl) do 506 for _, v in ipairs(tbl) do
700 if v == value then 507 if v == value then
diff --git a/src/luarocks/validate.lua b/src/luarocks/validate.lua
deleted file mode 100644
index f0452bbd..00000000
--- a/src/luarocks/validate.lua
+++ /dev/null
@@ -1,158 +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
14validate.help_summary = "Sandboxed test of build/install of all packages in a repository."
15
16validate.help = [[
17<argument>, if given, is a local repository pathname.
18]]
19
20local function save_settings(repo)
21 local protocol, path = dir.split_url(repo)
22 table.insert(cfg.rocks_servers, 1, protocol.."://"..path)
23 return {
24 root_dir = cfg.root_dir,
25 rocks_dir = cfg.rocks_dir,
26 deploy_bin_dir = cfg.deploy_bin_dir,
27 deploy_lua_dir = cfg.deploy_lua_dir,
28 deploy_lib_dir = cfg.deploy_lib_dir,
29 }
30end
31
32local function restore_settings(settings)
33 cfg.root_dir = settings.root_dir
34 cfg.rocks_dir = settings.rocks_dir
35 cfg.deploy_bin_dir = settings.deploy_bin_dir
36 cfg.deploy_lua_dir = settings.deploy_lua_dir
37 cfg.deploy_lib_dir = settings.deploy_lib_dir
38 cfg.variables.ROCKS_TREE = settings.rocks_dir
39 cfg.variables.SCRIPTS_DIR = settings.deploy_bin_dir
40 table.remove(cfg.rocks_servers, 1)
41end
42
43local function prepare_sandbox(file)
44 local root_dir = fs.make_temp_dir(file):gsub("/+$", "")
45 cfg.root_dir = root_dir
46 cfg.rocks_dir = path.rocks_dir(root_dir)
47 cfg.deploy_bin_dir = path.deploy_bin_dir(root_dir)
48 cfg.variables.ROCKS_TREE = cfg.rocks_dir
49 cfg.variables.SCRIPTS_DIR = cfg.deploy_bin_dir
50 return root_dir
51end
52
53local function validate_rockspec(file)
54 local ok, err, errcode = build.build_rockspec(file, true, "one")
55 if not ok then
56 util.printerr(err)
57 end
58 return ok, err, errcode
59end
60
61local function validate_src_rock(file)
62 local ok, err, errcode = build.build_rock(file, false, "one")
63 if not ok then
64 util.printerr(err)
65 end
66 return ok, err, errcode
67end
68
69local function validate_rock(file)
70 local ok, err, errcode = install.install_binary_rock(file, "one")
71 if not ok then
72 util.printerr(err)
73 end
74 return ok, err, errcode
75end
76
77function validate.command(flags, repo)
78 repo = repo or cfg.rocks_dir
79
80 util.printout("Verifying contents of "..repo)
81
82 local results = {
83 ok = {}
84 }
85 local settings = save_settings(repo)
86 local sandbox
87 if flags["quick"] then
88 sandbox = prepare_sandbox("luarocks_validate")
89 end
90 if not fs.exists(repo) then
91 return nil, repo.." is not a local repository."
92 end
93 for file in fs.dir(repo) do for _=1,1 do
94 if file == "manifest" or file == "index.html" then
95 break -- continue for
96 end
97 local pathname = fs.absolute_name(dir.path(repo, file))
98 if not flags["quick"] then
99 sandbox = prepare_sandbox(file)
100 end
101 local ok, err, errcode
102 util.printout()
103 util.printout("Verifying "..pathname)
104 if file:match("%.rockspec$") then
105 ok, err, errcode = validate_rockspec(pathname, "one")
106 elseif file:match("%.src%.rock$") then
107 ok, err, errcode = validate_src_rock(pathname)
108 elseif file:match("%.rock$") then
109 ok, err, errcode = validate_rock(pathname)
110 end
111 if ok then
112 table.insert(results.ok, {file=file} )
113 else
114 if not errcode then
115 errcode = "misc"
116 end
117 if not results[errcode] then
118 results[errcode] = {}
119 end
120 table.insert(results[errcode], {file=file, err=err} )
121 end
122 util.run_scheduled_functions()
123 if not flags["quick"] then
124 fs.delete(sandbox)
125 end
126 repeat until not fs.pop_dir()
127 end end
128 if flags["quick"] then
129 fs.delete(sandbox)
130 end
131 restore_settings(settings)
132 util.title("Results:")
133 util.printout("OK: "..tostring(#results.ok))
134 for _, entry in ipairs(results.ok) do
135 util.printout(entry.file)
136 end
137 for errcode, errors in pairs(results) do
138 if errcode ~= "ok" then
139 util.printout()
140 util.printout(errcode.." errors: "..tostring(#errors))
141 for _, entry in ipairs(errors) do
142 util.printout(entry.file, entry.err)
143 end
144 end
145 end
146
147 util.title("Summary:")
148 local total = 0
149 for errcode, errors in pairs(results) do
150 util.printout(errcode..": "..tostring(#errors))
151 total = total + #errors
152 end
153 util.printout("Total: "..total)
154 return true
155end
156
157
158return validate
diff --git a/src/luarocks/write_rockspec.lua b/src/luarocks/write_rockspec.lua
index 68c00cce..d6075dbd 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")