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