aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.setup.inc2
-rw-r--r--spec/dir_spec.lua13
-rw-r--r--spec/fetch_spec.lua9
-rw-r--r--spec/util_spec.lua1
-rw-r--r--src/luarocks/build.lua536
-rw-r--r--src/luarocks/build/builtin.lua2
-rw-r--r--src/luarocks/build/cmake.lua2
-rw-r--r--src/luarocks/build/command.lua2
-rw-r--r--src/luarocks/build/make.lua2
-rw-r--r--src/luarocks/cmd/build.lua115
-rw-r--r--src/luarocks/cmd/make.lua38
-rw-r--r--src/luarocks/cmd/unpack.lua27
-rw-r--r--src/luarocks/cmd/write_rockspec.lua173
-rw-r--r--src/luarocks/command_line.lua6
-rw-r--r--src/luarocks/core/util.lua1
-rw-r--r--src/luarocks/deps.lua41
-rw-r--r--src/luarocks/dir.lua16
-rw-r--r--src/luarocks/fetch.lua143
-rw-r--r--src/luarocks/fetch/cvs.lua2
-rw-r--r--src/luarocks/fetch/git.lua2
-rw-r--r--src/luarocks/fetch/hg.lua2
-rw-r--r--src/luarocks/fetch/sscm.lua2
-rw-r--r--src/luarocks/fetch/svn.lua2
-rw-r--r--src/luarocks/manif/writer.lua1
-rw-r--r--src/luarocks/pack.lua2
-rw-r--r--src/luarocks/path.lua20
-rw-r--r--src/luarocks/remove.lua2
-rw-r--r--src/luarocks/repos.lua4
-rw-r--r--src/luarocks/rockspecs.lua159
-rw-r--r--src/luarocks/search.lua32
-rw-r--r--src/luarocks/type_check.lua4
-rw-r--r--src/luarocks/util.lua31
32 files changed, 767 insertions, 627 deletions
diff --git a/Makefile.setup.inc b/Makefile.setup.inc
index e4c15b64..127898cf 100644
--- a/Makefile.setup.inc
+++ b/Makefile.setup.inc
@@ -23,5 +23,5 @@ fetch/cvs.lua fetch/git_https.lua fetch/git_ssh.lua fetch/hg_http.lua \
23fetch/git_http.lua fetch/svn.lua fetch/git.lua fetch/hg_ssh.lua \ 23fetch/git_http.lua fetch/svn.lua fetch/git.lua fetch/hg_ssh.lua \
24fetch/hg_https.lua fetch/hg.lua core/vers.lua cmd/which.lua \ 24fetch/hg_https.lua fetch/hg.lua core/vers.lua cmd/which.lua \
25fun.lua type/manifest.lua type/rockspec.lua queries.lua results.lua \ 25fun.lua type/manifest.lua type/rockspec.lua queries.lua results.lua \
26test/busted.lua test/command.lua cmd/init.lua 26test/busted.lua test/command.lua cmd/init.lua rockspecs.lua
27 27
diff --git a/spec/dir_spec.lua b/spec/dir_spec.lua
index 04e26b57..27966777 100644
--- a/spec/dir_spec.lua
+++ b/spec/dir_spec.lua
@@ -12,8 +12,19 @@ describe("Luarocks dir test #unit", function()
12 assert.truthy(dir.is_basic_protocol("https")) 12 assert.truthy(dir.is_basic_protocol("https"))
13 assert.truthy(dir.is_basic_protocol("ftp")) 13 assert.truthy(dir.is_basic_protocol("ftp"))
14 assert.truthy(dir.is_basic_protocol("file")) 14 assert.truthy(dir.is_basic_protocol("file"))
15 assert.falsy(dir.is_basic_protocol("file", true)) 15 assert.falsy(dir.is_basic_protocol("git"))
16 assert.falsy(dir.is_basic_protocol("git+https"))
16 assert.falsy(dir.is_basic_protocol("invalid")) 17 assert.falsy(dir.is_basic_protocol("invalid"))
17 end) 18 end)
18 end) 19 end)
20
21 describe("dir.deduce_base_dir", function()
22 assert.are.same("v0.3", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3.zip"))
23 assert.are.same("lua-compat-5.2", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2.zip"))
24 assert.are.same("lua-compat-5.2", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.gz"))
25 assert.are.same("lua-compat-5.2", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.bz2"))
26 assert.are.same("parser.moon", dir.deduce_base_dir("git://example.com/Cirru/parser.moon"))
27 assert.are.same("v0.3", dir.deduce_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3"))
28 end)
29
19end) 30end)
diff --git a/spec/fetch_spec.lua b/spec/fetch_spec.lua
index c02c5736..aa107970 100644
--- a/spec/fetch_spec.lua
+++ b/spec/fetch_spec.lua
@@ -208,15 +208,6 @@ describe("Luarocks fetch test #unit", function()
208 end) 208 end)
209 end) 209 end)
210 210
211 describe("fetch.url_to_base_dir", function()
212 assert.are.same("v0.3", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3.zip"))
213 assert.are.same("lua-compat-5.2", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2.zip"))
214 assert.are.same("lua-compat-5.2", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.gz"))
215 assert.are.same("lua-compat-5.2", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2.tar.bz2"))
216 assert.are.same("parser.moon", fetch.url_to_base_dir("git://example.com/Cirru/parser.moon"))
217 assert.are.same("v0.3", fetch.url_to_base_dir("https://example.com/hishamhm/lua-compat-5.2/archive/v0.3"))
218 end)
219
220 describe("fetch.load_local_rockspec", function() 211 describe("fetch.load_local_rockspec", function()
221 it("returns a table representing the rockspec from the given file skipping some checks if the quick argument is enabled", function() 212 it("returns a table representing the rockspec from the given file skipping some checks if the quick argument is enabled", function()
222 local rockspec = fetch.load_local_rockspec(testing_paths.fixtures_dir .. "/a_rock-1.0-1.rockspec", true) 213 local rockspec = fetch.load_local_rockspec(testing_paths.fixtures_dir .. "/a_rock-1.0-1.rockspec", true)
diff --git a/spec/util_spec.lua b/spec/util_spec.lua
index 28f99550..3bb97a5b 100644
--- a/spec/util_spec.lua
+++ b/spec/util_spec.lua
@@ -2,7 +2,6 @@ local test_env = require("spec.util.test_env")
2local lfs = require("lfs") 2local lfs = require("lfs")
3local run = test_env.run 3local run = test_env.run
4local testing_paths = test_env.testing_paths 4local testing_paths = test_env.testing_paths
5local env_variables = test_env.env_variables
6 5
7describe("Basic tests #integration", function() 6describe("Basic tests #integration", function()
8 7
diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua
index 25e73b0d..ac4ecfad 100644
--- a/src/luarocks/build.lua
+++ b/src/luarocks/build.lua
@@ -12,26 +12,226 @@ local cfg = require("luarocks.core.cfg")
12local repos = require("luarocks.repos") 12local repos = require("luarocks.repos")
13local writer = require("luarocks.manif.writer") 13local writer = require("luarocks.manif.writer")
14 14
15--- Install files to a given location. 15local opts_mt = {}
16-- Takes a table where the array part is a list of filenames to be copied. 16
17-- In the hash part, other keys, if is_module_path is set, are identifiers 17opts_mt.__index = opts_mt
18-- in Lua module format, to indicate which subdirectory the file should be 18
19-- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo") 19function opts_mt.type()
20-- will copy src/bar.lua to boo/foo. 20 return "build.opts"
21-- @param files table or nil: A table containing a list of files to copy in 21end
22-- the format described above. If nil is passed, this function is a no-op. 22
23-- Directories should be delimited by forward slashes as in internet URLs. 23function build.opts(opts)
24-- @param location string: The base directory files should be copied to. 24 local valid_opts = {
25-- @param is_module_path boolean: True if string keys in files should be 25 need_to_fetch = "boolean",
26-- interpreted as dotted module paths. 26 minimal_mode = "boolean",
27-- @param perms string ("read" or "exec"): Permissions of the newly created files installed. 27 deps_mode = "string",
28-- Directories are always created with the default permissions. 28 build_only_deps = "boolean",
29-- @return boolean or (nil, string): True if succeeded or 29 namespace = "string?",
30-- nil and an error message. 30 branch = "boolean",
31local function install_files(files, location, is_module_path, perms) 31 }
32 assert(type(files) == "table" or not files) 32 for k, v in pairs(opts) do
33 assert(type(location) == "string") 33 local tv = type(v)
34 if files then 34 if not valid_opts[k] then
35 error("invalid build option: "..k)
36 end
37 local vo, optional = valid_opts[k]:match("^(.-)(%??)$")
38 if not (tv == vo or (optional == "?" and tv == nil)) then
39 error("invalid type build option: "..k.." - got "..tv..", expected "..vo)
40 end
41 end
42 for k, v in pairs(valid_opts) do
43 if (not v:find("?", 1, true)) and opts[k] == nil then
44 error("missing build option: "..k)
45 end
46 end
47 return setmetatable(opts, opts_mt)
48end
49
50do
51 --- Write to the current directory the contents of a table,
52 -- where each key is a file name and its value is the file content.
53 -- @param files table: The table of files to be written.
54 local function extract_from_rockspec(files)
55 for name, content in pairs(files) do
56 local fd = io.open(dir.path(fs.current_dir(), name), "w+")
57 fd:write(content)
58 fd:close()
59 end
60 end
61
62 --- Applies patches inlined in the build.patches section
63 -- and extracts files inlined in the build.extra_files section
64 -- of a rockspec.
65 -- @param rockspec table: A rockspec table.
66 -- @return boolean or (nil, string): True if succeeded or
67 -- nil and an error message.
68 function build.apply_patches(rockspec)
69 assert(rockspec:type() == "rockspec")
70
71 if rockspec.build.extra_files then
72 extract_from_rockspec(rockspec.build.extra_files)
73 end
74 if rockspec.build.patches then
75 extract_from_rockspec(rockspec.build.patches)
76 for patch, patchdata in util.sortedpairs(rockspec.build.patches) do
77 util.printout("Applying patch "..patch.."...")
78 local create_delete = rockspec:format_is_at_least("3.0")
79 local ok, err = fs.apply_patch(tostring(patch), patchdata, create_delete)
80 if not ok then
81 return nil, "Failed applying patch "..patch
82 end
83 end
84 end
85 return true
86 end
87end
88
89local function check_macosx_deployment_target(rockspec)
90 local target = rockspec.build.macosx_deployment_target
91 local function minor(version)
92 return tonumber(version and version:match("^[^.]+%.([^.]+)"))
93 end
94 local function patch_variable(var)
95 if rockspec.variables[var]:match("MACOSX_DEPLOYMENT_TARGET") then
96 rockspec.variables[var] = (rockspec.variables[var]):gsub("MACOSX_DEPLOYMENT_TARGET=[^ ]*", "MACOSX_DEPLOYMENT_TARGET="..target)
97 else
98 rockspec.variables[var] = "env MACOSX_DEPLOYMENT_TARGET="..target.." "..rockspec.variables[var]
99 end
100 end
101 if cfg.platforms.macosx and rockspec:format_is_at_least("3.0") and target then
102 local version = util.popen_read("sw_vers -productVersion")
103 local versionminor = minor(version)
104 local targetminor = minor(target)
105 if targetminor > versionminor then
106 return nil, ("This rock requires Mac OSX 10.%d, and you are running 10.%d."):format(targetminor, versionminor)
107 end
108 patch_variable("CC", target)
109 patch_variable("LD", target)
110 end
111 return true
112end
113
114local function process_dependencies(rockspec, opts)
115 if not opts.build_only_deps then
116 local ok, err, errcode = deps.check_external_deps(rockspec, "build")
117 if err then
118 return nil, err, errcode
119 end
120 end
121 if opts.deps_mode == "none" then
122 util.warning("skipping dependency checks.")
123 return true
124 end
125 if not opts.build_only_deps then
126 if next(rockspec.build_dependencies) then
127 local ok, err, errcode = deps.fulfill_dependencies(rockspec, "build_dependencies", opts.deps_mode)
128 if err then
129 return nil, err, errcode
130 end
131 end
132 end
133 local ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", opts.deps_mode)
134 if err then
135 return nil, err, errcode
136 end
137 return true
138end
139
140local function fetch_and_change_to_source_dir(rockspec, opts)
141 if opts.minimal_mode then
142 return true
143 end
144 if opts.need_to_fetch then
145 if opts.branch then
146 rockspec.source.branch = opts.branch
147 end
148 local ok, source_dir, errcode = fetch.fetch_sources(rockspec, true)
149 if not ok then
150 return nil, source_dir, errcode
151 end
152 local err
153 ok, err = fs.change_dir(source_dir)
154 if not ok then
155 return nil, err
156 end
157 elseif rockspec.source.file then
158 local ok, err = fs.unpack_archive(rockspec.source.file)
159 if not ok then
160 return nil, err
161 end
162 end
163 fs.change_dir(rockspec.source.dir)
164 return true
165end
166
167local function prepare_install_dirs(name, version)
168 local dirs = {
169 lua = { name = path.lua_dir(name, version), is_module_path = true, perms = "read" },
170 lib = { name = path.lib_dir(name, version), is_module_path = true, perms = "exec" },
171 bin = { name = path.bin_dir(name, version), is_module_path = false, perms = "exec" },
172 conf = { name = path.conf_dir(name, version), is_module_path = false, perms = "read" },
173 }
174
175 for _, d in pairs(dirs) do
176 local ok, err = fs.make_dir(d.name)
177 if not ok then
178 return nil, err
179 end
180 end
181
182 return dirs
183end
184
185local function run_build_driver(rockspec)
186 local btype = rockspec.build.type
187 if btype == "none" then
188 return true
189 end
190 -- Temporary compatibility
191 if btype == "module" then
192 util.printout("Do not use 'module' as a build type. Use 'builtin' instead.")
193 btype = "builtin"
194 rockspec.build.type = btype
195 end
196 if cfg.accepted_build_types and not fun.contains(cfg.accepted_build_types, btype) then
197 return nil, "This rockspec uses the '"..btype.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration."
198 end
199 local pok, driver = pcall(require, "luarocks.build." .. btype)
200 if not pok or type(driver) ~= "table" then
201 return nil, "Failed initializing build back-end for build type '"..btype.."': "..driver
202 end
203 local ok, err = driver.run(rockspec)
204 if not ok then
205 return nil, "Build error: " .. err
206 end
207 return true
208end
209
210local install_files
211do
212 --- Install files to a given location.
213 -- Takes a table where the array part is a list of filenames to be copied.
214 -- In the hash part, other keys, if is_module_path is set, are identifiers
215 -- in Lua module format, to indicate which subdirectory the file should be
216 -- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo")
217 -- will copy src/bar.lua to boo/foo.
218 -- @param files table or nil: A table containing a list of files to copy in
219 -- the format described above. If nil is passed, this function is a no-op.
220 -- Directories should be delimited by forward slashes as in internet URLs.
221 -- @param location string: The base directory files should be copied to.
222 -- @param is_module_path boolean: True if string keys in files should be
223 -- interpreted as dotted module paths.
224 -- @param perms string ("read" or "exec"): Permissions of the newly created
225 -- files installed.
226 -- Directories are always created with the default permissions.
227 -- @return boolean or (nil, string): True if succeeded or
228 -- nil and an error message.
229 local function install_to(files, location, is_module_path, perms)
230 assert(type(files) == "table" or not files)
231 assert(type(location) == "string")
232 if not files then
233 return true
234 end
35 for k, file in pairs(files) do 235 for k, file in pairs(files) do
36 local dest = location 236 local dest = location
37 local filename = dir.base_name(file) 237 local filename = dir.base_name(file)
@@ -60,88 +260,76 @@ local function install_files(files, location, is_module_path, perms)
60 return nil, "Failed copying "..file 260 return nil, "Failed copying "..file
61 end 261 end
62 end 262 end
263 return true
63 end 264 end
64 return true
65end
66 265
67--- Write to the current directory the contents of a table, 266 local function install_default_docs(name, version)
68-- where each key is a file name and its value is the file content. 267 local patterns = { "readme", "license", "copying", ".*%.md" }
69-- @param files table: The table of files to be written. 268 local dest = dir.path(path.install_dir(name, version), "doc")
70local function extract_from_rockspec(files) 269 local has_dir = false
71 for name, content in pairs(files) do 270 for file in fs.dir() do
72 local fd = io.open(dir.path(fs.current_dir(), name), "w+") 271 for _, pattern in ipairs(patterns) do
73 fd:write(content) 272 if file:lower():match("^"..pattern) then
74 fd:close() 273 if not has_dir then
274 fs.make_dir(dest)
275 has_dir = true
276 end
277 fs.copy(file, dest, "read")
278 break
279 end
280 end
281 end
75 end 282 end
76end
77 283
78--- Applies patches inlined in the build.patches section 284 install_files = function(rockspec, dirs)
79-- and extracts files inlined in the build.extra_files section 285 local name, version = rockspec.name, rockspec.version
80-- of a rockspec. 286
81-- @param rockspec table: A rockspec table. 287 if rockspec.build.install then
82-- @return boolean or (nil, string): True if succeeded or 288 for k, d in pairs(dirs) do
83-- nil and an error message. 289 local ok, err = install_to(rockspec.build.install[k], d.name, d.is_module_path, d.perms)
84function build.apply_patches(rockspec) 290 if not ok then return nil, err end
85 assert(type(rockspec) == "table")
86
87 local build_spec = rockspec.build
88 if build_spec.extra_files then
89 extract_from_rockspec(build_spec.extra_files)
90 end
91 if build_spec.patches then
92 extract_from_rockspec(build_spec.patches)
93 for patch, patchdata in util.sortedpairs(build_spec.patches) do
94 util.printout("Applying patch "..patch.."...")
95 local create_delete = rockspec:format_is_at_least("3.0")
96 local ok, err = fs.apply_patch(tostring(patch), patchdata, create_delete)
97 if not ok then
98 return nil, "Failed applying patch "..patch
99 end 291 end
100 end 292 end
101 end
102 return true
103end
104 293
105local function install_default_docs(name, version) 294 local copy_directories = rockspec.build.copy_directories
106 local patterns = { "readme", "license", "copying", ".*%.md" } 295 local copying_default = false
107 local dest = dir.path(path.install_dir(name, version), "doc") 296 if not copy_directories then
108 local has_dir = false 297 copy_directories = {"doc"}
109 for file in fs.dir() do 298 copying_default = true
110 for _, pattern in ipairs(patterns) do 299 end
111 if file:lower():match("^"..pattern) then 300
112 if not has_dir then 301 local any_docs = false
113 fs.make_dir(dest) 302 for _, copy_dir in pairs(copy_directories) do
114 has_dir = true 303 if fs.is_dir(copy_dir) then
304 local dest = dir.path(path.install_dir(name, version), copy_dir)
305 fs.make_dir(dest)
306 fs.copy_contents(copy_dir, dest)
307 any_docs = true
308 else
309 if not copying_default then
310 return nil, "Directory '"..copy_dir.."' not found"
115 end 311 end
116 fs.copy(file, dest, "read")
117 break
118 end 312 end
119 end 313 end
314 if not any_docs then
315 install_default_docs(name, version)
316 end
317
318 return true
120 end 319 end
121end 320end
122 321
123local function check_macosx_deployment_target(rockspec) 322local function write_rock_dir_files(rockspec, opts)
124 local target = rockspec.build.macosx_deployment_target 323 local name, version = rockspec.name, rockspec.version
125 local function minor(version) 324
126 return tonumber(version and version:match("^[^.]+%.([^.]+)")) 325 fs.copy(rockspec.local_abs_filename, path.rockspec_file(name, version), "read")
127 end 326
128 local function patch_variable(var, target) 327 local ok, err = writer.make_rock_manifest(name, version)
129 if rockspec.variables[var]:match("MACOSX_DEPLOYMENT_TARGET") then 328 if not ok then return nil, err end
130 rockspec.variables[var] = (rockspec.variables[var]):gsub("MACOSX_DEPLOYMENT_TARGET=[^ ]*", "MACOSX_DEPLOYMENT_TARGET="..target) 329
131 else 330 ok, err = writer.make_namespace_file(name, version, opts.namespace)
132 rockspec.variables[var] = "env MACOSX_DEPLOYMENT_TARGET="..target.." "..rockspec.variables[var] 331 if not ok then return nil, err end
133 end 332
134 end
135 if cfg.platforms.macosx and rockspec:format_is_at_least("3.0") and target then
136 local version = util.popen_read("sw_vers -productVersion")
137 local versionminor = minor(version)
138 local targetminor = minor(target)
139 if targetminor > versionminor then
140 return nil, ("This rock requires Mac OSX 10.%d, and you are running 10.%d."):format(targetminor, versionminor)
141 end
142 patch_variable("CC", target)
143 patch_variable("LD", target)
144 end
145 return true 333 return true
146end 334end
147 335
@@ -157,18 +345,14 @@ end
157-- "none" for no trees. 345-- "none" for no trees.
158-- @param build_only_deps boolean: true to build the listed dependencies only. 346-- @param build_only_deps boolean: true to build the listed dependencies only.
159-- @param namespace string?: a namespace for the rockspec 347-- @param namespace string?: a namespace for the rockspec
348-- @param branch string?: a forced branch to use
160-- @return (string, string) or (nil, string, [string]): Name and version of 349-- @return (string, string) or (nil, string, [string]): Name and version of
161-- installed rock if succeeded or nil and an error message followed by an error code. 350-- installed rock if succeeded or nil and an error message followed by an error code.
162function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode, build_only_deps, namespace) 351function build.build_rockspec(rockspec, opts)
163 assert(type(rockspec_file) == "string") 352 assert(rockspec:type() == "rockspec")
164 assert(type(need_to_fetch) == "boolean") 353 assert(opts:type() == "build.opts")
165 assert(type(namespace) == "string" or not namespace)
166 354
167 local ok 355 if not rockspec.build then
168 local rockspec, err, errcode = fetch.load_rockspec(rockspec_file)
169 if err then
170 return nil, err, errcode
171 elseif not rockspec.build then
172 return nil, "Rockspec error: build table not specified" 356 return nil, "Rockspec error: build table not specified"
173 end 357 end
174 358
@@ -180,175 +364,65 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
180 end 364 end
181 end 365 end
182 366
183 if not build_only_deps then 367 local ok, err = process_dependencies(rockspec, opts)
184 local ok, err, errcode = deps.check_external_deps(rockspec, "build") 368 if not ok then return nil, err end
185 if err then
186 return nil, err, errcode
187 end
188 end
189
190 if deps_mode == "none" then
191 util.warning("skipping dependency checks.")
192 else
193 if not build_only_deps then
194 if next(rockspec.build_dependencies) then
195 local ok, err, errcode = deps.fulfill_dependencies(rockspec, "build_dependencies", deps_mode)
196 if err then
197 return nil, err, errcode
198 end
199 end
200 end
201
202 local ok, err, errcode = deps.fulfill_dependencies(rockspec, "dependencies", deps_mode)
203 if err then
204 return nil, err, errcode
205 end
206 end
207 369
208 local name, version = rockspec.name, rockspec.version 370 local name, version = rockspec.name, rockspec.version
209 if build_only_deps then 371 if opts.build_only_deps then
210 util.printout("Stopping after installing dependencies for " ..name.." "..version)
211 util.printout()
212 return name, version 372 return name, version
213 end 373 end
214 374
215 if repos.is_installed(name, version) then 375 if repos.is_installed(name, version) then
216 repos.delete_version(name, version, deps_mode) 376 repos.delete_version(name, version, opts.deps_mode)
217 end 377 end
218 378
219 if not minimal_mode then 379 ok, err = fetch_and_change_to_source_dir(rockspec, opts)
220 local source_dir 380 if not ok then return nil, err end
221 if need_to_fetch then
222 ok, source_dir, errcode = fetch.fetch_sources(rockspec, true)
223 if not ok then
224 return nil, source_dir, errcode
225 end
226 local ok, err = fs.change_dir(source_dir)
227 if not ok then return nil, err end
228 elseif rockspec.source.file then
229 local ok, err = fs.unpack_archive(rockspec.source.file)
230 if not ok then
231 return nil, err
232 end
233 end
234 fs.change_dir(rockspec.source.dir)
235 end
236 381
237 local dirs = { 382 local dirs, err = prepare_install_dirs(name, version)
238 lua = { name = path.lua_dir(name, version), is_module_path = true, perms = "read" }, 383 if not dirs then return nil, err end
239 lib = { name = path.lib_dir(name, version), is_module_path = true, perms = "exec" },
240 conf = { name = path.conf_dir(name, version), is_module_path = false, perms = "read" },
241 bin = { name = path.bin_dir(name, version), is_module_path = false, perms = "exec" },
242 }
243 384
244 for _, d in pairs(dirs) do
245 local ok, err = fs.make_dir(d.name)
246 if not ok then return nil, err end
247 end
248 local rollback = util.schedule_function(function() 385 local rollback = util.schedule_function(function()
249 fs.delete(path.install_dir(name, version)) 386 fs.delete(path.install_dir(name, version))
250 fs.remove_dir_if_empty(path.versions_dir(name)) 387 fs.remove_dir_if_empty(path.versions_dir(name))
251 end) 388 end)
252 389
253 local build_spec = rockspec.build 390 if not opts.minimal_mode then
254 391 local ok, err = build.apply_patches(rockspec)
255 if not minimal_mode then 392 if not ok then return nil, err end
256 ok, err = build.apply_patches(rockspec)
257 if err then
258 return nil, err
259 end
260 end 393 end
261 394
262 ok, err = check_macosx_deployment_target(rockspec) 395 ok, err = check_macosx_deployment_target(rockspec)
263 if not ok then 396 if not ok then return nil, err end
264 return nil, err
265 end
266
267 if build_spec.type ~= "none" then
268
269 -- Temporary compatibility
270 if build_spec.type == "module" then
271 util.printout("Do not use 'module' as a build type. Use 'builtin' instead.")
272 build_spec.type = "builtin"
273 end
274
275 if cfg.accepted_build_types and fun.contains(cfg.accepted_build_types, build_spec.type) then
276 return nil, "This rockspec uses the '"..build_spec.type.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration."
277 end
278
279 local build_type
280 ok, build_type = pcall(require, "luarocks.build." .. build_spec.type)
281 if not ok or not type(build_type) == "table" then
282 return nil, "Failed initializing build back-end for build type '"..build_spec.type.."': "..build_type
283 end
284
285 ok, err = build_type.run(rockspec)
286 if not ok then
287 return nil, "Build error: " .. err
288 end
289 end
290
291 if build_spec.install then
292 for id, install_dir in pairs(dirs) do
293 ok, err = install_files(build_spec.install[id], install_dir.name, install_dir.is_module_path, install_dir.perms)
294 if not ok then
295 return nil, err
296 end
297 end
298 end
299 397
300 local copy_directories = build_spec.copy_directories 398 ok, err = run_build_driver(rockspec)
301 local copying_default = false 399 if not ok then return nil, err end
302 if not copy_directories then
303 copy_directories = {"doc"}
304 copying_default = true
305 end
306
307 local any_docs = false
308 for _, copy_dir in pairs(copy_directories) do
309 if fs.is_dir(copy_dir) then
310 local dest = dir.path(path.install_dir(name, version), copy_dir)
311 fs.make_dir(dest)
312 fs.copy_contents(copy_dir, dest)
313 any_docs = true
314 else
315 if not copying_default then
316 return nil, "Directory '"..copy_dir.."' not found"
317 end
318 end
319 end
320 400
321 if not any_docs then 401 ok, err = install_files(rockspec, dirs)
322 install_default_docs(name, version) 402 if not ok then return nil, err end
323 end
324 403
325 for _, d in pairs(dirs) do 404 for _, d in pairs(dirs) do
326 fs.remove_dir_if_empty(d.name) 405 fs.remove_dir_if_empty(d.name)
327 end 406 end
328 407
329 fs.pop_dir() 408 fs.pop_dir()
330 409 if opts.need_to_fetch then
331 fs.copy(rockspec.local_filename, path.rockspec_file(name, version), "read")
332 if need_to_fetch then
333 fs.pop_dir() 410 fs.pop_dir()
334 end 411 end
335 412
336 ok, err = writer.make_rock_manifest(name, version) 413 ok, err = write_rock_dir_files(rockspec, opts)
337 if err then return nil, err end 414 if not ok then return nil, err end
338
339 ok, err = writer.make_namespace_file(name, version, namespace)
340 if err then return nil, err end
341 415
342 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode) 416 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), opts.deps_mode)
343 if err then return nil, err end 417 if not ok then return nil, err end
344 418
345 util.remove_scheduled_function(rollback) 419 util.remove_scheduled_function(rollback)
346 rollback = util.schedule_function(function() 420 rollback = util.schedule_function(function()
347 repos.delete_version(name, version, deps_mode) 421 repos.delete_version(name, version, opts.deps_mode)
348 end) 422 end)
349 423
350 ok, err = repos.run_hook(rockspec, "post_install") 424 ok, err = repos.run_hook(rockspec, "post_install")
351 if err then return nil, err end 425 if not ok then return nil, err end
352 426
353 util.announce_install(rockspec) 427 util.announce_install(rockspec)
354 util.remove_scheduled_function(rollback) 428 util.remove_scheduled_function(rollback)
diff --git a/src/luarocks/build/builtin.lua b/src/luarocks/build/builtin.lua
index e8b0943d..41cc31b0 100644
--- a/src/luarocks/build/builtin.lua
+++ b/src/luarocks/build/builtin.lua
@@ -23,7 +23,7 @@ end
23-- @return boolean or (nil, string): true if no errors ocurred, 23-- @return boolean or (nil, string): true if no errors ocurred,
24-- nil and an error message otherwise. 24-- nil and an error message otherwise.
25function builtin.run(rockspec) 25function builtin.run(rockspec)
26 assert(type(rockspec) == "table") 26 assert(rockspec:type() == "rockspec")
27 local compile_object, compile_library, compile_static_library 27 local compile_object, compile_library, compile_static_library
28 28
29 local build = rockspec.build 29 local build = rockspec.build
diff --git a/src/luarocks/build/cmake.lua b/src/luarocks/build/cmake.lua
index 8ee6b6b2..e5db695c 100644
--- a/src/luarocks/build/cmake.lua
+++ b/src/luarocks/build/cmake.lua
@@ -11,7 +11,7 @@ local cfg = require("luarocks.core.cfg")
11-- @return boolean or (nil, string): true if no errors ocurred, 11-- @return boolean or (nil, string): true if no errors ocurred,
12-- nil and an error message otherwise. 12-- nil and an error message otherwise.
13function cmake.run(rockspec) 13function cmake.run(rockspec)
14 assert(type(rockspec) == "table") 14 assert(rockspec:type() == "rockspec")
15 local build = rockspec.build 15 local build = rockspec.build
16 local variables = build.variables or {} 16 local variables = build.variables or {}
17 17
diff --git a/src/luarocks/build/command.lua b/src/luarocks/build/command.lua
index 62dbc282..23d6d80d 100644
--- a/src/luarocks/build/command.lua
+++ b/src/luarocks/build/command.lua
@@ -10,7 +10,7 @@ local util = require("luarocks.util")
10-- @return boolean or (nil, string): true if no errors ocurred, 10-- @return boolean or (nil, string): true if no errors ocurred,
11-- nil and an error message otherwise. 11-- nil and an error message otherwise.
12function command.run(rockspec) 12function command.run(rockspec)
13 assert(type(rockspec) == "table") 13 assert(rockspec:type() == "rockspec")
14 14
15 local build = rockspec.build 15 local build = rockspec.build
16 16
diff --git a/src/luarocks/build/make.lua b/src/luarocks/build/make.lua
index ded015b7..22b8628b 100644
--- a/src/luarocks/build/make.lua
+++ b/src/luarocks/build/make.lua
@@ -39,7 +39,7 @@ end
39-- @return boolean or (nil, string): true if no errors ocurred, 39-- @return boolean or (nil, string): true if no errors ocurred,
40-- nil and an error message otherwise. 40-- nil and an error message otherwise.
41function make.run(rockspec) 41function make.run(rockspec)
42 assert(type(rockspec) == "table") 42 assert(rockspec:type() == "rockspec")
43 43
44 local build = rockspec.build 44 local build = rockspec.build
45 45
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua
index 0c8c4d47..08a05296 100644
--- a/src/luarocks/cmd/build.lua
+++ b/src/luarocks/cmd/build.lua
@@ -41,7 +41,7 @@ or the name of a rock to be fetched from a repository.
41]]..util.deps_mode_help() 41]]..util.deps_mode_help()
42 42
43--- Build and install a rock. 43--- Build and install a rock.
44-- @param rock_file string: local or remote filename of a rock. 44-- @param rock_filename string: local or remote filename of a rock.
45-- @param need_to_fetch boolean: true if sources need to be fetched, 45-- @param need_to_fetch boolean: true if sources need to be fetched,
46-- false if the rockspec was obtained from inside a source rock. 46-- false if the rockspec was obtained from inside a source rock.
47-- @param deps_mode: string: Which trees to check dependencies for: 47-- @param deps_mode: string: Which trees to check dependencies for:
@@ -51,42 +51,65 @@ or the name of a rock to be fetched from a repository.
51-- @param namespace string?: an optional namespace 51-- @param namespace string?: an optional namespace
52-- @return boolean or (nil, string, [string]): True if build was successful, 52-- @return boolean or (nil, string, [string]): True if build was successful,
53-- or false and an error message and an optional error code. 53-- or false and an error message and an optional error code.
54local function build_rock(rock_file, need_to_fetch, deps_mode, build_only_deps, namespace) 54local function build_rock(rock_filename, opts)
55 assert(type(rock_file) == "string") 55 assert(type(rock_filename) == "string")
56 assert(type(need_to_fetch) == "boolean") 56 assert(opts:type() == "build.opts")
57 57
58 local ok, err, errcode 58 local ok, err, errcode
59
59 local unpack_dir 60 local unpack_dir
60 unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file) 61 unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_filename)
61 if not unpack_dir then 62 if not unpack_dir then
62 return nil, err, errcode 63 return nil, err, errcode
63 end 64 end
64 local rockspec_file = path.rockspec_name_from_rock(rock_file) 65
66 local rockspec_filename = path.rockspec_name_from_rock(rock_filename)
67
65 ok, err = fs.change_dir(unpack_dir) 68 ok, err = fs.change_dir(unpack_dir)
66 if not ok then return nil, err end 69 if not ok then return nil, err end
67 ok, err, errcode = build.build_rockspec(rockspec_file, need_to_fetch, false, deps_mode, build_only_deps, namespace) 70
71 local rockspec
72 rockspec, err, errcode = fetch.load_rockspec(rockspec_filename)
73 if not rockspec then
74 return nil, err, errcode
75 end
76
77 ok, err, errcode = build.build_rockspec(rockspec, opts)
78
68 fs.pop_dir() 79 fs.pop_dir()
69 return ok, err, errcode 80 return ok, err, errcode
70end 81end
71 82
72local function build_file(filename, namespace, deps_mode, build_only_deps) 83local function do_build(ns_name, version, opts)
73 if filename:match("%.rockspec$") then 84 assert(type(ns_name) == "string")
74 return build.build_rockspec(filename, true, false, deps_mode, build_only_deps, namespace) 85 assert(version == nil or type(version) == "string")
75 elseif filename:match("%.src%.rock$") then 86 assert(opts:type() == "build.opts")
76 return build_rock(filename, false, deps_mode, build_only_deps, namespace)
77 elseif filename:match("%.all%.rock$") then
78 return build_rock(filename, true, deps_mode, build_only_deps, namespace)
79 elseif filename:match("%.rock$") then
80 return build_rock(filename, true, deps_mode, build_only_deps, namespace)
81 end
82end
83 87
84local function do_build(name, version, namespace, deps_mode, build_only_deps) 88 local url, err
85 if name:match("%.rockspec$") or name:match("%.rock$") then 89 if ns_name:match("%.rockspec$") or ns_name:match("%.rock$") then
86 return build_file(name, namespace, deps_mode, build_only_deps) 90 url = ns_name
87 else 91 else
88 return search.act_on_src_or_rockspec(build_file, name, version, deps_mode, build_only_deps) 92 url, err = search.find_src_or_rockspec(ns_name, version)
93 if not url then
94 return nil, err
95 end
96 local _, namespace = util.split_namespace(ns_name)
97 opts.namespace = namespace
98 end
99
100 if url:match("%.rockspec$") then
101 local rockspec, err, errcode = fetch.load_rockspec(url)
102 if not rockspec then
103 return nil, err, errcode
104 end
105 return build.build_rockspec(rockspec, opts)
106 end
107
108 if url:match("%.src%.rock$") then
109 opts.need_to_fetch = false
89 end 110 end
111
112 return build_rock(url, opts)
90end 113end
91 114
92--- Driver function for "build" command. 115--- Driver function for "build" command.
@@ -106,28 +129,46 @@ function cmd_build.command(flags, name, version)
106 end 129 end
107 130
108 name = util.adjust_name_and_namespace(name, flags) 131 name = util.adjust_name_and_namespace(name, flags)
109 local deps_mode = deps.get_deps_mode(flags) 132
110 local namespace = flags["namespace"] 133 local opts = build.opts({
111 local build_only_deps = flags["only-deps"] 134 need_to_fetch = true,
135 minimal_mode = false,
136 deps_mode = deps.get_deps_mode(flags),
137 build_only_deps = not not flags["only-deps"],
138 namespace = flags["namespace"],
139 branch = not not flags["branch"],
140 })
112 141
113 if flags["pack-binary-rock"] then 142 if flags["pack-binary-rock"] then
114 return pack.pack_binary_rock(name, version, function() return do_build(name, version, namespace, deps_mode) end) 143 return pack.pack_binary_rock(name, version, function()
115 else 144 opts.build_only_deps = false
116 local ok, err = fs.check_command_permissions(flags) 145 return do_build(name, version, opts)
117 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end 146 end)
147 end
148
149 local ok, err = fs.check_command_permissions(flags)
150 if not ok then
151 return nil, err, cfg.errorcodes.PERMISSIONDENIED
152 end
118 153
119 ok, err = do_build(name, version, namespace, deps_mode, build_only_deps) 154 ok, err = do_build(name, version, opts)
120 if not ok then return nil, err end 155 if not ok then return nil, err end
121 name, version = ok, err 156 name, version = ok, err
122 157
123 if (not build_only_deps) and (not flags["keep"]) and not cfg.keep_other_versions then 158 if opts.build_only_deps then
159 util.printout("Stopping after installing dependencies for " ..name.." "..version)
160 util.printout()
161 else
162 if (not flags["keep"]) and not cfg.keep_other_versions then
124 local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) 163 local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"])
125 if not ok then util.printerr(err) end 164 if not ok then
165 util.printerr(err)
166 end
126 end 167 end
127
128 writer.check_dependencies(nil, deps.get_deps_mode(flags))
129 return name, version
130 end 168 end
169
170 writer.check_dependencies(nil, deps.get_deps_mode(flags))
171 return name, version
131end 172end
132 173
133return cmd_build 174return cmd_build
diff --git a/src/luarocks/cmd/make.lua b/src/luarocks/cmd/make.lua
index 850da6f4..caf64721 100644
--- a/src/luarocks/cmd/make.lua
+++ b/src/luarocks/cmd/make.lua
@@ -53,30 +53,44 @@ only dependencies of the rockspec (see `luarocks help install`).
53-- @param name string: A local rockspec. 53-- @param name string: A local rockspec.
54-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an 54-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an
55-- error message otherwise. exitcode is optionally returned. 55-- error message otherwise. exitcode is optionally returned.
56function make.command(flags, rockspec) 56function make.command(flags, rockspec_filename)
57 assert(type(rockspec) == "string" or not rockspec) 57 assert(type(rockspec_filename) == "string" or not rockspec_filename)
58 58
59 if not rockspec then 59 if not rockspec_filename then
60 local err 60 local err
61 rockspec, err = util.get_default_rockspec() 61 rockspec_filename, err = util.get_default_rockspec()
62 if not rockspec then 62 if not rockspec_filename then
63 return nil, err 63 return nil, err
64 end 64 end
65 end 65 end
66 if not rockspec:match("rockspec$") then 66 if not rockspec_filename:match("rockspec$") then
67 return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make") 67 return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make")
68 end 68 end
69
70 local rockspec, err, errcode = fetch.load_rockspec(rockspec_filename)
71 if not rockspec then
72 return nil, err
73 end
74
75 local name = util.adjust_name_and_namespace(rockspec.name, flags)
76
77 local opts = build.opts({
78 need_to_fetch = false,
79 minimal_mode = true,
80 deps_mode = deps.get_deps_mode(flags),
81 build_only_deps = false,
82 namespace = flags["namespace"],
83 branch = not not flags["branch"],
84 })
69 85
70 if flags["pack-binary-rock"] then 86 if flags["pack-binary-rock"] then
71 local rspec, err, errcode = fetch.load_rockspec(rockspec) 87 return pack.pack_binary_rock(name, rockspec.version, function()
72 if not rspec then 88 return build.build_rockspec(rockspec, opts)
73 return nil, err 89 end)
74 end
75 return pack.pack_binary_rock(rspec.name, rspec.version, function() return build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) end)
76 else 90 else
77 local ok, err = fs.check_command_permissions(flags) 91 local ok, err = fs.check_command_permissions(flags)
78 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end 92 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end
79 ok, err = build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) 93 ok, err = build.build_rockspec(rockspec, opts)
80 if not ok then return nil, err end 94 if not ok then return nil, err end
81 local name, version = ok, err 95 local name, version = ok, err
82 96
diff --git a/src/luarocks/cmd/unpack.lua b/src/luarocks/cmd/unpack.lua
index 3e512d5d..83dec7fe 100644
--- a/src/luarocks/cmd/unpack.lua
+++ b/src/luarocks/cmd/unpack.lua
@@ -8,7 +8,7 @@ local fs = require("luarocks.fs")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local build = require("luarocks.build") 9local build = require("luarocks.build")
10local dir = require("luarocks.dir") 10local dir = require("luarocks.dir")
11local cfg = require("luarocks.core.cfg") 11local search = require("luarocks.search")
12 12
13unpack.help_summary = "Unpack the contents of a rock." 13unpack.help_summary = "Unpack the contents of a rock."
14unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}" 14unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}"
@@ -92,7 +92,7 @@ end
92-- @param file string: A rockspec or .rock URL. 92-- @param file string: A rockspec or .rock URL.
93-- @return boolean or (nil, string): true if successful or nil followed 93-- @return boolean or (nil, string): true if successful or nil followed
94-- by an error message. 94-- by an error message.
95local function run_unpacker(file, namespace, force) 95local function run_unpacker(file, force)
96 assert(type(file) == "string") 96 assert(type(file) == "string")
97 97
98 local base_name = dir.base_name(file) 98 local base_name = dir.base_name(file)
@@ -126,7 +126,7 @@ local function run_unpacker(file, namespace, force)
126 end 126 end
127 if kind == "src" or kind == "rockspec" then 127 if kind == "src" or kind == "rockspec" then
128 if rockspec.source.dir ~= "." then 128 if rockspec.source.dir ~= "." then
129 local ok = fs.copy(rockspec.local_filename, rockspec.source.dir, "read") 129 local ok = fs.copy(rockspec.local_abs_filename, rockspec.source.dir, "read")
130 if not ok then 130 if not ok then
131 return nil, "Failed copying unpacked rockspec into unpacked source directory." 131 return nil, "Failed copying unpacked rockspec into unpacked source directory."
132 end 132 end
@@ -141,26 +141,31 @@ local function run_unpacker(file, namespace, force)
141end 141end
142 142
143--- Driver function for the "unpack" command. 143--- Driver function for the "unpack" command.
144-- @param name string: may be a rock filename, for unpacking a 144-- @param ns_name string: may be a rock filename, for unpacking a
145-- rock file or the name of a rock to be fetched and unpacked. 145-- rock file or the name of a rock to be fetched and unpacked.
146-- @param version string or nil: if the name of a package is given, a 146-- @param version string or nil: if the name of a package is given, a
147-- version may also be passed. 147-- version may also be passed.
148-- @return boolean or (nil, string): true if successful or nil followed 148-- @return boolean or (nil, string): true if successful or nil followed
149-- by an error message. 149-- by an error message.
150function unpack.command(flags, name, version) 150function unpack.command(flags, ns_name, version)
151 assert(type(version) == "string" or not version) 151 assert(type(version) == "string" or not version)
152 if type(name) ~= "string" then 152 if type(ns_name) ~= "string" then
153 return nil, "Argument missing. "..util.see_help("unpack") 153 return nil, "Argument missing. "..util.see_help("unpack")
154 end 154 end
155 155
156 name = util.adjust_name_and_namespace(name, flags) 156 ns_name = util.adjust_name_and_namespace(ns_name, flags)
157 157
158 if name:match(".*%.rock") or name:match(".*%.rockspec") then 158 local url, err
159 return run_unpacker(name, flags["namespace"], flags["force"]) 159 if ns_name:match(".*%.rock") or ns_name:match(".*%.rockspec") then
160 url = ns_name
160 else 161 else
161 local search = require("luarocks.search") 162 url, err = search.find_src_or_rockspec(ns_name, version)
162 return search.act_on_src_or_rockspec(run_unpacker, name, version) 163 if not url then
164 return nil, err
165 end
163 end 166 end
167
168 return run_unpacker(url, flags["force"])
164end 169end
165 170
166return unpack 171return unpack
diff --git a/src/luarocks/cmd/write_rockspec.lua b/src/luarocks/cmd/write_rockspec.lua
index f3398a6a..36beffd0 100644
--- a/src/luarocks/cmd/write_rockspec.lua
+++ b/src/luarocks/cmd/write_rockspec.lua
@@ -7,9 +7,9 @@ local fetch = require("luarocks.fetch")
7local fs = require("luarocks.fs") 7local fs = require("luarocks.fs")
8local path = require("luarocks.path") 8local path = require("luarocks.path")
9local persist = require("luarocks.persist") 9local persist = require("luarocks.persist")
10local rockspecs = require("luarocks.rockspecs")
10local type_rockspec = require("luarocks.type.rockspec") 11local type_rockspec = require("luarocks.type.rockspec")
11local util = require("luarocks.util") 12local util = require("luarocks.util")
12local vers = require("luarocks.core.vers")
13 13
14write_rockspec.help_summary = "Write a template for a rockspec file." 14write_rockspec.help_summary = "Write a template for a rockspec file."
15write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]" 15write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]"
@@ -46,7 +46,7 @@ local function open_file(name)
46 return io.open(dir.path(fs.current_dir(), name), "r") 46 return io.open(dir.path(fs.current_dir(), name), "r")
47end 47end
48 48
49local function get_url(rockspec) 49local function fetch_url(rockspec)
50 local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false) 50 local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false)
51 if err_code == "source.dir" then 51 if err_code == "source.dir" then
52 file, temp_dir = err_file, err_temp_dir 52 file, temp_dir = err_file, err_temp_dir
@@ -55,37 +55,78 @@ local function get_url(rockspec)
55 return false 55 return false
56 end 56 end
57 util.printout("File successfully downloaded. Making checksum and checking base dir...") 57 util.printout("File successfully downloaded. Making checksum and checking base dir...")
58 if fetch.is_basic_protocol(rockspec.source.protocol) then 58 if dir.is_basic_protocol(rockspec.source.protocol) then
59 rockspec.source.md5 = fs.get_md5(file) 59 rockspec.source.md5 = fs.get_md5(file)
60 end 60 end
61 local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url) 61 local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url)
62 return true, found_dir or inferred_dir, temp_dir 62 return true, found_dir or inferred_dir, temp_dir
63end 63end
64 64
65local function configure_lua_version(rockspec, luaver) 65local lua_version_dep = {
66 if luaver == "5.1" then 66 ["5.1"] = "lua ~> 5.1",
67 table.insert(rockspec.dependencies, "lua ~> 5.1") 67 ["5.2"] = "lua ~> 5.2",
68 elseif luaver == "5.2" then 68 ["5.3"] = "lua ~> 5.3",
69 table.insert(rockspec.dependencies, "lua ~> 5.2") 69 ["5.4"] = "lua ~> 5.4",
70 elseif luaver == "5.3" then 70 ["5.1,5.2"] = "lua >= 5.1, < 5.3",
71 table.insert(rockspec.dependencies, "lua ~> 5.3") 71 ["5.2,5.3"] = "lua >= 5.2, < 5.4",
72 elseif luaver == "5.4" then 72 ["5.3,5.4"] = "lua >= 5.3, < 5.5",
73 table.insert(rockspec.dependencies, "lua ~> 5.4") 73 ["5.1,5.2,5.3"] = "lua >= 5.1, < 5.4",
74 elseif luaver == "5.1,5.2" then 74 ["5.2,5.3,5.4"] = "lua >= 5.2, < 5.5",
75 table.insert(rockspec.dependencies, "lua >= 5.1, < 5.3") 75 ["5.1,5.2,5.3,5.4"] = "lua >= 5.1, < 5.5",
76 elseif luaver == "5.2,5.3" then 76}
77 table.insert(rockspec.dependencies, "lua >= 5.2, < 5.4") 77
78 elseif luaver == "5.3,5.4" then 78local simple_scm_protocols = {
79 table.insert(rockspec.dependencies, "lua >= 5.3, < 5.5") 79 git = true, ["git+http"] = true, ["git+https"] = true,
80 elseif luaver == "5.1,5.2,5.3" then 80 hg = true, ["hg+http"] = true, ["hg+https"] = true
81 table.insert(rockspec.dependencies, "lua >= 5.1, < 5.4") 81}
82 elseif luaver == "5.2,5.3,5.4" then 82
83 table.insert(rockspec.dependencies, "lua >= 5.2, < 5.5") 83local detect_url
84 elseif luaver == "5.1,5.2,5.3,5.4" then 84do
85 table.insert(rockspec.dependencies, "lua >= 5.1, < 5.5") 85 local function detect_url_from_command(program, args, directory)
86 else 86 local command = fs.Q(cfg.variables[program:upper()]).. " "..args
87 util.warning("Please specify supported Lua version with --lua-version=<ver>. "..util.see_help("write_rockspec")) 87 local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command)))
88 if not pipe then return nil end
89 local url = pipe:read("*a"):match("^([^\r\n]+)")
90 pipe:close()
91 if not url then return nil end
92 if not util.starts_with(url, program.."://") then
93 url = program.."+"..url
94 end
95
96 if simple_scm_protocols[dir.split_url(url)] then
97 return url
98 end
99 end
100
101 local function detect_scm_url(directory)
102 return detect_url_from_command("git", "config --get remote.origin.url", directory) or
103 detect_url_from_command("hg", "paths default", directory)
88 end 104 end
105
106 detect_url = function(url_or_dir)
107 if url_or_dir:match("://") then
108 return url_or_dir
109 else
110 return detect_scm_url(url_or_dir) or "*** please add URL for source tarball, zip or repository here ***"
111 end
112 end
113end
114
115local function detect_homepage(url, homepage)
116 if homepage then
117 return homepage
118 end
119 local url_protocol, url_path = dir.split_url(url)
120
121 if simple_scm_protocols[url_protocol] then
122 for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do
123 if util.starts_with(url_path, domain) then
124 return "https://"..url_path:gsub("%.git$", "")
125 end
126 end
127 end
128
129 return "*** please enter a project homepage ***"
89end 130end
90 131
91local function detect_description() 132local function detect_description()
@@ -120,32 +161,6 @@ local function detect_mit_license(data)
120 return sum == 78656 161 return sum == 78656
121end 162end
122 163
123local simple_scm_protocols = {
124 git = true, ["git+http"] = true, ["git+https"] = true,
125 hg = true, ["hg+http"] = true, ["hg+https"] = true
126}
127
128local function detect_url_from_command(program, args, directory)
129 local command = fs.Q(cfg.variables[program:upper()]).. " "..args
130 local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command)))
131 if not pipe then return nil end
132 local url = pipe:read("*a"):match("^([^\r\n]+)")
133 pipe:close()
134 if not url then return nil end
135 if not util.starts_with(url, program.."://") then
136 url = program.."+"..url
137 end
138
139 if simple_scm_protocols[dir.split_url(url)] then
140 return url
141 end
142end
143
144local function detect_scm_url(directory)
145 return detect_url_from_command("git", "config --get remote.origin.url", directory) or
146 detect_url_from_command("hg", "paths default", directory)
147end
148
149local function check_license() 164local function check_license()
150 local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt") 165 local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt")
151 if not fd then return nil end 166 if not fd then return nil end
@@ -182,7 +197,7 @@ local function fill_as_builtin(rockspec, libs)
182 break 197 break
183 end 198 end
184 end 199 end
185 200
186 local incdirs, libdirs 201 local incdirs, libdirs
187 if libs then 202 if libs then
188 incdirs, libdirs = {}, {} 203 incdirs, libdirs = {}, {}
@@ -259,7 +274,7 @@ function write_rockspec.command(flags, name, version, url_or_dir)
259 if pathname == "." then 274 if pathname == "." then
260 name = name or dir.base_name(fs.current_dir()) 275 name = name or dir.base_name(fs.current_dir())
261 end 276 end
262 elseif fetch.is_basic_protocol(protocol) then 277 elseif dir.is_basic_protocol(protocol) then
263 local filename = dir.base_name(url_or_dir) 278 local filename = dir.base_name(url_or_dir)
264 local newname, newversion = filename:match("(.*)-([^-]+)") 279 local newname, newversion = filename:match("(.*)-([^-]+)")
265 if newname then 280 if newname then
@@ -276,48 +291,47 @@ function write_rockspec.command(flags, name, version, url_or_dir)
276 version = version or "dev" 291 version = version or "dev"
277 292
278 local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") 293 local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec")
279 294
280 local rockspec = { 295 local url = detect_url(url_or_dir)
296 local homepage = detect_homepage(url, flags["homepage"])
297
298 local rockspec, err = rockspecs.from_persisted_table(filename, {
281 rockspec_format = flags["rockspec-format"], 299 rockspec_format = flags["rockspec-format"],
282 package = name, 300 package = name,
283 name = name:lower(),
284 version = version.."-1", 301 version = version.."-1",
285 source = { 302 source = {
286 url = "*** please add URL for source tarball, zip or repository here ***", 303 url = url,
287 tag = flags["tag"], 304 tag = flags["tag"],
288 }, 305 },
289 description = { 306 description = {
290 summary = flags["summary"] or "*** please specify description summary ***", 307 summary = flags["summary"] or "*** please specify description summary ***",
291 detailed = flags["detailed"] or "*** please enter a detailed description ***", 308 detailed = flags["detailed"] or "*** please enter a detailed description ***",
292 homepage = flags["homepage"] or "*** please enter a project homepage ***", 309 homepage = homepage,
293 license = flags["license"] or "*** please specify a license ***", 310 license = flags["license"] or "*** please specify a license ***",
294 }, 311 },
295 dependencies = {}, 312 dependencies = {
313 lua_version_dep[flags["lua-version"]],
314 },
296 build = {}, 315 build = {},
297 } 316 })
298 path.configure_paths(rockspec) 317 assert(not err, err)
299 rockspec.source.protocol = protocol 318 rockspec.source.protocol = protocol
300 319
301 local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0") 320 if not next(rockspec.dependencies) then
302 rockspec.format_is_at_least = function(_, v) 321 util.warning("Please specify supported Lua version with --lua-version=<ver>. "..util.see_help("write_rockspec"))
303 return parsed_format >= vers.parse_version(v)
304 end 322 end
305 323
306 configure_lua_version(rockspec, flags["lua-version"])
307
308 local local_dir = url_or_dir 324 local local_dir = url_or_dir
309 325
310 if url_or_dir:match("://") then 326 if url_or_dir:match("://") then
311 rockspec.source.url = url_or_dir
312 rockspec.source.file = dir.base_name(url_or_dir) 327 rockspec.source.file = dir.base_name(url_or_dir)
313 rockspec.source.dir = "dummy" 328 if not dir.is_basic_protocol(rockspec.source.protocol) then
314 if not fetch.is_basic_protocol(rockspec.source.protocol) then
315 if version ~= "dev" then 329 if version ~= "dev" then
316 rockspec.source.tag = flags["tag"] or "v" .. version 330 rockspec.source.tag = flags["tag"] or "v" .. version
317 end 331 end
318 end 332 end
319 rockspec.source.dir = nil 333 rockspec.source.dir = nil
320 local ok, base_dir, temp_dir = get_url(rockspec) 334 local ok, base_dir, temp_dir = fetch_url(rockspec)
321 if ok then 335 if ok then
322 if base_dir ~= dir.base_name(url_or_dir) then 336 if base_dir ~= dir.base_name(url_or_dir) then
323 rockspec.source.dir = base_dir 337 rockspec.source.dir = base_dir
@@ -328,26 +342,11 @@ function write_rockspec.command(flags, name, version, url_or_dir)
328 else 342 else
329 local_dir = nil 343 local_dir = nil
330 end 344 end
331 else
332 rockspec.source.url = detect_scm_url(local_dir) or rockspec.source.url
333 end 345 end
334 346
335 if not local_dir then 347 if not local_dir then
336 local_dir = "." 348 local_dir = "."
337 end 349 end
338
339 if not flags["homepage"] then
340 local url_protocol, url_path = dir.split_url(rockspec.source.url)
341
342 if simple_scm_protocols[url_protocol] then
343 for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do
344 if util.starts_with(url_path, domain) then
345 rockspec.description.homepage = "https://"..url_path:gsub("%.git$", "")
346 break
347 end
348 end
349 end
350 end
351 350
352 local libs = nil 351 local libs = nil
353 if flags["lib"] then 352 if flags["lib"] then
@@ -364,7 +363,7 @@ function write_rockspec.command(flags, name, version, url_or_dir)
364 local ok, err = fs.change_dir(local_dir) 363 local ok, err = fs.change_dir(local_dir)
365 if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end 364 if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end
366 365
367 if (not flags["summary"]) or (not flags["detailed"]) then 366 if not (flags["summary"] and flags["detailed"]) then
368 local summary, detailed = detect_description() 367 local summary, detailed = detect_description()
369 rockspec.description.summary = flags["summary"] or summary 368 rockspec.description.summary = flags["summary"] or summary
370 rockspec.description.detailed = flags["detailed"] or detailed 369 rockspec.description.detailed = flags["detailed"] or detailed
diff --git a/src/luarocks/command_line.lua b/src/luarocks/command_line.lua
index a9cf9968..7d9cc4af 100644
--- a/src/luarocks/command_line.lua
+++ b/src/luarocks/command_line.lua
@@ -23,7 +23,7 @@ end
23-- @param message string: The error message. 23-- @param message string: The error message.
24-- @param exitcode number: the exitcode to use 24-- @param exitcode number: the exitcode to use
25local function die(message, exitcode) 25local function die(message, exitcode)
26 assert(type(message) == "string") 26 assert(type(message) == "string", "bad error, expected string, got: " .. type(message))
27 util.printerr("\nError: "..message) 27 util.printerr("\nError: "..message)
28 28
29 local ok, err = xpcall(util.run_scheduled_functions, error_handler) 29 local ok, err = xpcall(util.run_scheduled_functions, error_handler)
@@ -138,10 +138,6 @@ function command_line.run_command(...)
138 die("Invalid entry for --deps-mode.") 138 die("Invalid entry for --deps-mode.")
139 end 139 end
140 140
141 if flags["branch"] then
142 cfg.branch = flags["branch"]
143 end
144
145 if flags["tree"] then 141 if flags["tree"] then
146 local named = false 142 local named = false
147 for _, tree in ipairs(cfg.rocks_trees) do 143 for _, tree in ipairs(cfg.rocks_trees) do
diff --git a/src/luarocks/core/util.lua b/src/luarocks/core/util.lua
index 68fd931d..3582cb54 100644
--- a/src/luarocks/core/util.lua
+++ b/src/luarocks/core/util.lua
@@ -116,7 +116,6 @@ end
116--- Merges contents of src on top of dst's contents. 116--- Merges contents of src on top of dst's contents.
117-- @param dst Destination table, which will receive src's contents. 117-- @param dst Destination table, which will receive src's contents.
118-- @param src Table which provides new contents to dst. 118-- @param src Table which provides new contents to dst.
119-- @see platform_overrides
120function util.deep_merge(dst, src) 119function util.deep_merge(dst, src)
121 for k, v in pairs(src) do 120 for k, v in pairs(src) do
122 if type(v) == "table" then 121 if type(v) == "table" then
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index b1ff6c47..3ec1aa93 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -14,7 +14,7 @@ local queries = require("luarocks.queries")
14-- @param dep table: A dependency parsed in table format. 14-- @param dep table: A dependency parsed in table format.
15-- @param blacklist table: Versions that can't be accepted. Table where keys 15-- @param blacklist table: Versions that can't be accepted. Table where keys
16-- are program versions and values are 'true'. 16-- are program versions and values are 'true'.
17-- @param rocks_provided table: A table of auto-dependencies provided 17-- @param rocks_provided table: A table of auto-provided dependencies.
18-- by this Lua implementation for the given dependency. 18-- by this Lua implementation for the given dependency.
19-- @return string or nil: latest installed version of the rock matching the dependency 19-- @return string or nil: latest installed version of the rock matching the dependency
20-- or nil if it could not be matched. 20-- or nil if it could not be matched.
@@ -48,7 +48,8 @@ local function match_dep(dep, blacklist, deps_mode, rocks_provided)
48end 48end
49 49
50--- Attempt to match dependencies of a rockspec to installed rocks. 50--- Attempt to match dependencies of a rockspec to installed rocks.
51-- @param rockspec table: The rockspec loaded as a table. 51-- @param dependencies table: The table of dependencies.
52-- @param rocks_provided table: The table of auto-provided dependencies.
52-- @param blacklist table or nil: Program versions to not use as valid matches. 53-- @param blacklist table or nil: Program versions to not use as valid matches.
53-- Table where keys are program names and values are tables where keys 54-- Table where keys are program names and values are tables where keys
54-- are program versions and values are 'true'. 55-- are program versions and values are 'true'.
@@ -58,15 +59,14 @@ end
58-- parsed as tables; and a table of "no-upgrade" missing dependencies 59-- parsed as tables; and a table of "no-upgrade" missing dependencies
59-- (to be used in plugin modules so that a plugin does not force upgrade of 60-- (to be used in plugin modules so that a plugin does not force upgrade of
60-- its parent application). 61-- its parent application).
61function deps.match_deps(rockspec, blacklist, deps_mode) 62function deps.match_deps(dependencies, rocks_provided, blacklist, deps_mode)
62 assert(type(rockspec) == "table")
63 assert(type(blacklist) == "table" or not blacklist) 63 assert(type(blacklist) == "table" or not blacklist)
64 local matched, missing, no_upgrade = {}, {}, {} 64 local matched, missing, no_upgrade = {}, {}, {}
65 65
66 for _, dep in ipairs(rockspec.dependencies) do 66 for _, dep in ipairs(dependencies) do
67 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rockspec.rocks_provided) 67 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode, rocks_provided)
68 if found then 68 if found then
69 if not rockspec.rocks_provided[dep.name] then 69 if not rocks_provided[dep.name] then
70 matched[dep] = {name = dep.name, version = found} 70 matched[dep] = {name = dep.name, version = found}
71 end 71 end
72 else 72 else
@@ -266,7 +266,7 @@ end
266-- @return boolean or (nil, string): True if no errors occurred, or 266-- @return boolean or (nil, string): True if no errors occurred, or
267-- nil and an error message if any test failed. 267-- nil and an error message if any test failed.
268function deps.check_external_deps(rockspec, mode) 268function deps.check_external_deps(rockspec, mode)
269 assert(type(rockspec) == "table") 269 assert(rockspec:type() == "rockspec")
270 270
271 local fs = require("luarocks.fs") 271 local fs = require("luarocks.fs")
272 272
@@ -431,25 +431,24 @@ function deps.scan_deps(results, manifest, name, version, deps_mode)
431 return 431 return
432 end 432 end
433 if not manifest.dependencies then manifest.dependencies = {} end 433 if not manifest.dependencies then manifest.dependencies = {} end
434 local dependencies = manifest.dependencies 434 local md = manifest.dependencies
435 if not dependencies[name] then dependencies[name] = {} end 435 if not md[name] then md[name] = {} end
436 local dependencies_name = dependencies[name] 436 local mdn = md[name]
437 local deplist = dependencies_name[version] 437 local dependencies = mdn[version]
438 local rockspec, err 438 local rocks_provided
439 if not deplist then 439 if not dependencies then
440 rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false) 440 local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version), false)
441 if not rockspec then 441 if not rockspec then
442 util.printerr("Couldn't load rockspec for "..name.." "..version..": "..err) 442 util.printerr("Couldn't load rockspec for "..name.." "..version..": "..err)
443 return 443 return
444 end 444 end
445 dependencies_name[version] = rockspec.dependencies 445 dependencies = rockspec.dependencies
446 rocks_provided = rockspec.rocks_provided
447 mdn[version] = dependencies
446 else 448 else
447 rockspec = { 449 rocks_provided = setmetatable({}, { __index = cfg.rocks_provided_3_0 })
448 dependencies = deplist,
449 rocks_provided = setmetatable({}, { __index = cfg.rocks_provided_3_0 })
450 }
451 end 450 end
452 local matched = deps.match_deps(rockspec, nil, deps_mode) 451 local matched = deps.match_deps(dependencies, rocks_provided, nil, deps_mode)
453 results[name] = version 452 results[name] = version
454 for _, match in pairs(matched) do 453 for _, match in pairs(matched) do
455 deps.scan_deps(results, manifest, match.name, match.version, deps_mode) 454 deps.scan_deps(results, manifest, match.name, match.version, deps_mode)
diff --git a/src/luarocks/dir.lua b/src/luarocks/dir.lua
index 72395e47..679e8f0d 100644
--- a/src/luarocks/dir.lua
+++ b/src/luarocks/dir.lua
@@ -40,4 +40,20 @@ function dir.normalize(name)
40 return pathname 40 return pathname
41end 41end
42 42
43--- Returns true if protocol does not require additional tools.
44-- @param protocol The protocol name
45function dir.is_basic_protocol(protocol)
46 return protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file"
47end
48
49function dir.deduce_base_dir(url)
50 -- for extensions like foo.tar.gz, "gz" is stripped first
51 local known_exts = {}
52 for _, ext in ipairs{"zip", "git", "tgz", "tar", "gz", "bz2"} do
53 known_exts[ext] = ""
54 end
55 local base = dir.base_name(url)
56 return (base:gsub("%.([^.]*)$", known_exts):gsub("%.tar", ""))
57end
58
43return dir 59return dir
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua
index 9ea2b487..074b0e45 100644
--- a/src/luarocks/fetch.lua
+++ b/src/luarocks/fetch.lua
@@ -4,18 +4,11 @@ local fetch = {}
4 4
5local fs = require("luarocks.fs") 5local fs = require("luarocks.fs")
6local dir = require("luarocks.dir") 6local dir = require("luarocks.dir")
7local type_rockspec = require("luarocks.type.rockspec") 7local rockspecs = require("luarocks.rockspecs")
8local path = require("luarocks.path")
9local vers = require("luarocks.core.vers")
10local queries = require("luarocks.queries")
11local persist = require("luarocks.persist") 8local persist = require("luarocks.persist")
12local util = require("luarocks.util") 9local util = require("luarocks.util")
13local cfg = require("luarocks.core.cfg") 10local cfg = require("luarocks.core.cfg")
14 11
15function fetch.is_basic_protocol(protocol, remote)
16 return protocol == "http" or protocol == "https" or protocol == "ftp" or (not remote and protocol == "file")
17end
18
19--- Fetch a local or remote file. 12--- Fetch a local or remote file.
20-- Make a remote or local URL/pathname local, fetching the file if necessary. 13-- Make a remote or local URL/pathname local, fetching the file if necessary.
21-- Other "fetch" and "load" functions use this function to obtain files. 14-- Other "fetch" and "load" functions use this function to obtain files.
@@ -37,7 +30,7 @@ function fetch.fetch_url(url, filename, cache)
37 local protocol, pathname = dir.split_url(url) 30 local protocol, pathname = dir.split_url(url)
38 if protocol == "file" then 31 if protocol == "file" then
39 return fs.absolute_name(pathname) 32 return fs.absolute_name(pathname)
40 elseif fetch.is_basic_protocol(protocol, true) then 33 elseif dir.is_basic_protocol(protocol) then
41 local ok, name = fs.download(url, filename, cache) 34 local ok, name = fs.download(url, filename, cache)
42 if not ok then 35 if not ok then
43 return nil, "Failed downloading "..url..(filename and " - "..filename or ""), "network" 36 return nil, "Failed downloading "..url..(filename and " - "..filename or ""), "network"
@@ -105,7 +98,7 @@ function fetch.find_base_dir(file, temp_dir, src_url, src_dir)
105 local ok, err = fs.change_dir(temp_dir) 98 local ok, err = fs.change_dir(temp_dir)
106 if not ok then return nil, err end 99 if not ok then return nil, err end
107 fs.unpack_archive(file) 100 fs.unpack_archive(file)
108 local inferred_dir = src_dir or fetch.url_to_base_dir(src_url) 101 local inferred_dir = src_dir or dir.deduce_base_dir(src_url)
109 local found_dir = nil 102 local found_dir = nil
110 if fs.exists(inferred_dir) then 103 if fs.exists(inferred_dir) then
111 found_dir = inferred_dir 104 found_dir = inferred_dir
@@ -170,131 +163,39 @@ function fetch.fetch_and_unpack_rock(rock_file, dest)
170 return unpack_dir 163 return unpack_dir
171end 164end
172 165
173function fetch.url_to_base_dir(url)
174 -- for extensions like foo.tar.gz, "gz" is stripped first
175 local known_exts = {}
176 for _, ext in ipairs{"zip", "git", "tgz", "tar", "gz", "bz2"} do
177 known_exts[ext] = ""
178 end
179 local base = dir.base_name(url)
180 return (base:gsub("%.([^.]*)$", known_exts):gsub("%.tar", ""))
181end
182
183local function convert_dependencies(rockspec, key)
184 if rockspec[key] then
185 for i = 1, #rockspec[key] do
186 local parsed, err = queries.from_dep_string(rockspec[key][i])
187 if not parsed then
188 return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err)
189 end
190 rockspec[key][i] = parsed
191 end
192 else
193 rockspec[key] = {}
194 end
195end
196
197--- Back-end function that actually loads the local rockspec. 166--- Back-end function that actually loads the local rockspec.
198-- Performs some validation and postprocessing of the rockspec contents. 167-- Performs some validation and postprocessing of the rockspec contents.
199-- @param filename string: The local filename of the rockspec file. 168-- @param rel_filename string: The local filename of the rockspec file.
200-- @param quick boolean: if true, skips some steps when loading 169-- @param quick boolean: if true, skips some steps when loading
201-- rockspec. 170-- rockspec.
202-- @return table or (nil, string): A table representing the rockspec 171-- @return table or (nil, string): A table representing the rockspec
203-- or nil followed by an error message. 172-- or nil followed by an error message.
204function fetch.load_local_rockspec(filename, quick) 173function fetch.load_local_rockspec(rel_filename, quick)
205 assert(type(filename) == "string") 174 assert(type(rel_filename) == "string")
206 filename = fs.absolute_name(filename) 175 local abs_filename = fs.absolute_name(rel_filename)
207 local rockspec, err = persist.load_into_table(filename)
208 if not rockspec then
209 return nil, "Could not load rockspec file "..filename.." ("..err..")"
210 end
211 if cfg.branch and (type(rockspec.source) == "table") then
212 rockspec.source.branch = cfg.branch
213 end
214 local globals = err
215
216 if rockspec.rockspec_format then
217 if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then
218 return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks."
219 end
220 end
221
222 if not quick then
223 local ok, err = type_rockspec.check(rockspec, globals)
224 if not ok then
225 return nil, filename..": "..err
226 end
227 end
228
229 --- Check if rockspec format version satisfies version requirement.
230 -- @param rockspec table: The rockspec table.
231 -- @param version string: required version.
232 -- @return boolean: true if rockspec format matches version or is newer, false otherwise.
233 do
234 local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0")
235 rockspec.format_is_at_least = function(self, version)
236 return parsed_format >= vers.parse_version(version)
237 end
238 end
239 176
240 util.platform_overrides(rockspec.build) 177 local basename = dir.base_name(abs_filename)
241 util.platform_overrides(rockspec.dependencies) 178 if basename ~= "rockspec" then
242 util.platform_overrides(rockspec.build_dependencies) 179 if not basename:match("(.*)%-[^-]*%-[0-9]*") then
243 util.platform_overrides(rockspec.test_dependencies)
244 util.platform_overrides(rockspec.external_dependencies)
245 util.platform_overrides(rockspec.source)
246 util.platform_overrides(rockspec.hooks)
247 util.platform_overrides(rockspec.test)
248
249 local basename = dir.base_name(filename)
250 if basename == "rockspec" then
251 rockspec.name = rockspec.package:lower()
252 else
253 rockspec.name = basename:match("(.*)-[^-]*-[0-9]*")
254 if not rockspec.name then
255 return nil, "Expected filename in format 'name-version-revision.rockspec'." 180 return nil, "Expected filename in format 'name-version-revision.rockspec'."
256 end 181 end
257 end 182 end
258 183
259 local protocol, pathname = dir.split_url(rockspec.source.url) 184 local tbl, err = persist.load_into_table(abs_filename)
260 if fetch.is_basic_protocol(protocol) then 185 if not tbl then
261 rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) 186 return nil, "Could not load rockspec file "..abs_filename.." ("..err..")"
187 end
188
189 local rockspec, err = rockspecs.from_persisted_table(abs_filename, tbl, err, quick)
190 if not rockspec then
191 return nil, abs_filename .. ": " .. err
262 end 192 end
263 rockspec.source.protocol, rockspec.source.pathname = protocol, pathname
264
265 -- Temporary compatibility
266 if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end
267 if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end
268 193
269 local name_version = rockspec.package:lower() .. "-" .. rockspec.version 194 local name_version = rockspec.package:lower() .. "-" .. rockspec.version
270 if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then 195 if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then
271 return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." 196 return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)."
272 end 197 end
273 198
274 rockspec.local_filename = filename
275 local filebase = rockspec.source.file or rockspec.source.url
276 local base = fetch.url_to_base_dir(filebase)
277 rockspec.source.dir_set = rockspec.source.dir ~= nil
278 rockspec.source.dir = rockspec.source.dir
279 or rockspec.source.module
280 or ( (filebase:match("%.lua$") or filebase:match("%.c$"))
281 and (rockspec:format_is_at_least("3.0")
282 and (fetch.is_basic_protocol(protocol) and "." or base)
283 or ".") )
284 or base
285
286 rockspec.rocks_provided = (rockspec:format_is_at_least("3.0")
287 and cfg.rocks_provided_3_0
288 or cfg.rocks_provided)
289
290 convert_dependencies(rockspec, "dependencies")
291 convert_dependencies(rockspec, "build_dependencies")
292 convert_dependencies(rockspec, "test_dependencies")
293
294 if not quick then
295 path.configure_paths(rockspec)
296 end
297
298 return rockspec 199 return rockspec
299end 200end
300 201
@@ -347,7 +248,7 @@ end
347-- the fetched source tarball and the temporary directory created to 248-- the fetched source tarball and the temporary directory created to
348-- store it; or nil and an error message and optional error code. 249-- store it; or nil and an error message and optional error code.
349function fetch.get_sources(rockspec, extract, dest_dir) 250function fetch.get_sources(rockspec, extract, dest_dir)
350 assert(type(rockspec) == "table") 251 assert(rockspec:type() == "rockspec")
351 assert(type(extract) == "boolean") 252 assert(type(extract) == "boolean")
352 assert(type(dest_dir) == "string" or not dest_dir) 253 assert(type(dest_dir) == "string" or not dest_dir)
353 254
@@ -417,13 +318,13 @@ end
417-- the fetched source tarball and the temporary directory created to 318-- the fetched source tarball and the temporary directory created to
418-- store it; or nil and an error message. 319-- store it; or nil and an error message.
419function fetch.fetch_sources(rockspec, extract, dest_dir) 320function fetch.fetch_sources(rockspec, extract, dest_dir)
420 assert(type(rockspec) == "table") 321 assert(rockspec:type() == "rockspec")
421 assert(type(extract) == "boolean") 322 assert(type(extract) == "boolean")
422 assert(type(dest_dir) == "string" or not dest_dir) 323 assert(type(dest_dir) == "string" or not dest_dir)
423 324
424 local protocol = rockspec.source.protocol 325 local protocol = rockspec.source.protocol
425 local ok, proto 326 local ok, proto
426 if fetch.is_basic_protocol(protocol) then 327 if dir.is_basic_protocol(protocol) then
427 proto = fetch 328 proto = fetch
428 else 329 else
429 ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) 330 ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_"))
diff --git a/src/luarocks/fetch/cvs.lua b/src/luarocks/fetch/cvs.lua
index ece711b6..d78e6e60 100644
--- a/src/luarocks/fetch/cvs.lua
+++ b/src/luarocks/fetch/cvs.lua
@@ -16,7 +16,7 @@ local util = require("luarocks.util")
16-- the fetched source tarball and the temporary directory created to 16-- the fetched source tarball and the temporary directory created to
17-- store it; or nil and an error message. 17-- store it; or nil and an error message.
18function cvs.get_sources(rockspec, extract, dest_dir) 18function cvs.get_sources(rockspec, extract, dest_dir)
19 assert(type(rockspec) == "table") 19 assert(rockspec:type() == "rockspec")
20 assert(type(dest_dir) == "string" or not dest_dir) 20 assert(type(dest_dir) == "string" or not dest_dir)
21 21
22 local cvs_cmd = rockspec.variables.CVS 22 local cvs_cmd = rockspec.variables.CVS
diff --git a/src/luarocks/fetch/git.lua b/src/luarocks/fetch/git.lua
index a14a5bfb..49ee7183 100644
--- a/src/luarocks/fetch/git.lua
+++ b/src/luarocks/fetch/git.lua
@@ -77,7 +77,7 @@ end
77-- the fetched source tarball and the temporary directory created to 77-- the fetched source tarball and the temporary directory created to
78-- store it; or nil and an error message. 78-- store it; or nil and an error message.
79function git.get_sources(rockspec, extract, dest_dir, depth) 79function git.get_sources(rockspec, extract, dest_dir, depth)
80 assert(type(rockspec) == "table") 80 assert(rockspec:type() == "rockspec")
81 assert(type(dest_dir) == "string" or not dest_dir) 81 assert(type(dest_dir) == "string" or not dest_dir)
82 82
83 local git_cmd = rockspec.variables.GIT 83 local git_cmd = rockspec.variables.GIT
diff --git a/src/luarocks/fetch/hg.lua b/src/luarocks/fetch/hg.lua
index 4cf8d028..0ef0f5e4 100644
--- a/src/luarocks/fetch/hg.lua
+++ b/src/luarocks/fetch/hg.lua
@@ -16,7 +16,7 @@ local util = require("luarocks.util")
16-- the fetched source tarball and the temporary directory created to 16-- the fetched source tarball and the temporary directory created to
17-- store it; or nil and an error message. 17-- store it; or nil and an error message.
18function hg.get_sources(rockspec, extract, dest_dir) 18function hg.get_sources(rockspec, extract, dest_dir)
19 assert(type(rockspec) == "table") 19 assert(rockspec:type() == "rockspec")
20 assert(type(dest_dir) == "string" or not dest_dir) 20 assert(type(dest_dir) == "string" or not dest_dir)
21 21
22 local hg_cmd = rockspec.variables.HG 22 local hg_cmd = rockspec.variables.HG
diff --git a/src/luarocks/fetch/sscm.lua b/src/luarocks/fetch/sscm.lua
index 5add10db..32bb2ecc 100644
--- a/src/luarocks/fetch/sscm.lua
+++ b/src/luarocks/fetch/sscm.lua
@@ -13,7 +13,7 @@ local dir = require("luarocks.dir")
13-- the fetched source tarball and the temporary directory created to 13-- the fetched source tarball and the temporary directory created to
14-- store it; or nil and an error message. 14-- store it; or nil and an error message.
15function sscm.get_sources(rockspec, extract, dest_dir) 15function sscm.get_sources(rockspec, extract, dest_dir)
16 assert(type(rockspec) == "table") 16 assert(rockspec:type() == "rockspec")
17 assert(type(dest_dir) == "string" or not dest_dir) 17 assert(type(dest_dir) == "string" or not dest_dir)
18 18
19 local sscm_cmd = rockspec.variables.SSCM 19 local sscm_cmd = rockspec.variables.SSCM
diff --git a/src/luarocks/fetch/svn.lua b/src/luarocks/fetch/svn.lua
index 29bce1b5..ceb15350 100644
--- a/src/luarocks/fetch/svn.lua
+++ b/src/luarocks/fetch/svn.lua
@@ -16,7 +16,7 @@ local util = require("luarocks.util")
16-- the fetched source tarball and the temporary directory created to 16-- the fetched source tarball and the temporary directory created to
17-- store it; or nil and an error message. 17-- store it; or nil and an error message.
18function svn.get_sources(rockspec, extract, dest_dir) 18function svn.get_sources(rockspec, extract, dest_dir)
19 assert(type(rockspec) == "table") 19 assert(rockspec:type() == "rockspec")
20 assert(type(dest_dir) == "string" or not dest_dir) 20 assert(type(dest_dir) == "string" or not dest_dir)
21 21
22 local svn_cmd = rockspec.variables.SVN 22 local svn_cmd = rockspec.variables.SVN
diff --git a/src/luarocks/manif/writer.lua b/src/luarocks/manif/writer.lua
index 8e8d5525..6f70338b 100644
--- a/src/luarocks/manif/writer.lua
+++ b/src/luarocks/manif/writer.lua
@@ -275,6 +275,7 @@ function writer.make_rock_manifest(name, version)
275 local rock_manifest = { rock_manifest=tree } 275 local rock_manifest = { rock_manifest=tree }
276 manif.rock_manifest_cache[name.."/"..version] = rock_manifest 276 manif.rock_manifest_cache[name.."/"..version] = rock_manifest
277 save_table(install_dir, "rock_manifest", rock_manifest ) 277 save_table(install_dir, "rock_manifest", rock_manifest )
278 return true
278end 279end
279 280
280-- Writes a 'rock_namespace' file in a locally installed rock directory. 281-- Writes a 'rock_namespace' file in a locally installed rock directory.
diff --git a/src/luarocks/pack.lua b/src/luarocks/pack.lua
index 6423de2c..cec370db 100644
--- a/src/luarocks/pack.lua
+++ b/src/luarocks/pack.lua
@@ -29,7 +29,7 @@ function pack.pack_source_rock(rockspec_file)
29 if err then 29 if err then
30 return nil, "Error loading rockspec: "..err 30 return nil, "Error loading rockspec: "..err
31 end 31 end
32 rockspec_file = rockspec.local_filename 32 rockspec_file = rockspec.local_abs_filename
33 33
34 local name_version = rockspec.name .. "-" .. rockspec.version 34 local name_version = rockspec.name .. "-" .. rockspec.version
35 local rock_file = fs.absolute_name(name_version .. ".src.rock") 35 local rock_file = fs.absolute_name(name_version .. ".src.rock")
diff --git a/src/luarocks/path.lua b/src/luarocks/path.lua
index a8426090..8fe6da8d 100644
--- a/src/luarocks/path.lua
+++ b/src/luarocks/path.lua
@@ -211,26 +211,6 @@ function path.module_to_path(mod)
211 return (mod:gsub("[^.]*$", ""):gsub("%.", "/")) 211 return (mod:gsub("[^.]*$", ""):gsub("%.", "/"))
212end 212end
213 213
214--- Set up path-related variables for a given rock.
215-- Create a "variables" table in the rockspec table, containing
216-- adjusted variables according to the configuration file.
217-- @param rockspec table: The rockspec table.
218function path.configure_paths(rockspec)
219 assert(type(rockspec) == "table")
220 local vars = {}
221 for k,v in pairs(cfg.variables) do
222 vars[k] = v
223 end
224 local name, version = rockspec.name, rockspec.version
225 vars.PREFIX = path.install_dir(name, version)
226 vars.LUADIR = path.lua_dir(name, version)
227 vars.LIBDIR = path.lib_dir(name, version)
228 vars.CONFDIR = path.conf_dir(name, version)
229 vars.BINDIR = path.bin_dir(name, version)
230 vars.DOCDIR = path.doc_dir(name, version)
231 rockspec.variables = vars
232end
233
234function path.use_tree(tree) 214function path.use_tree(tree)
235 cfg.root_dir = tree 215 cfg.root_dir = tree
236 cfg.rocks_dir = path.rocks_dir(tree) 216 cfg.rocks_dir = path.rocks_dir(tree)
diff --git a/src/luarocks/remove.lua b/src/luarocks/remove.lua
index 1b4e3562..9ae89da4 100644
--- a/src/luarocks/remove.lua
+++ b/src/luarocks/remove.lua
@@ -30,7 +30,7 @@ local function check_dependents(name, versions, deps_mode)
30 for rock_version, _ in pairs(rock_versions) do 30 for rock_version, _ in pairs(rock_versions) do
31 local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version)) 31 local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version))
32 if rockspec then 32 if rockspec then
33 local _, missing = deps.match_deps(rockspec, blacklist, deps_mode) 33 local _, missing = deps.match_deps(rockspec.dependencies, rockspec.rocks_provided, blacklist, deps_mode)
34 if missing[name] then 34 if missing[name] then
35 table.insert(dependents, { name = rock_name, version = rock_version }) 35 table.insert(dependents, { name = rock_name, version = rock_version })
36 end 36 end
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
index 54610489..454ec79f 100644
--- a/src/luarocks/repos.lua
+++ b/src/luarocks/repos.lua
@@ -147,7 +147,7 @@ function repos.has_binaries(name, version)
147end 147end
148 148
149function repos.run_hook(rockspec, hook_name) 149function repos.run_hook(rockspec, hook_name)
150 assert(type(rockspec) == "table") 150 assert(rockspec:type() == "rockspec")
151 assert(type(hook_name) == "string") 151 assert(type(hook_name) == "string")
152 152
153 local hooks = rockspec.hooks 153 local hooks = rockspec.hooks
@@ -174,7 +174,7 @@ function repos.run_hook(rockspec, hook_name)
174end 174end
175 175
176function repos.should_wrap_bin_scripts(rockspec) 176function repos.should_wrap_bin_scripts(rockspec)
177 assert(type(rockspec) == "table") 177 assert(rockspec:type() == "rockspec")
178 178
179 if cfg.wrap_bin_scripts ~= nil then 179 if cfg.wrap_bin_scripts ~= nil then
180 return cfg.wrap_bin_scripts 180 return cfg.wrap_bin_scripts
diff --git a/src/luarocks/rockspecs.lua b/src/luarocks/rockspecs.lua
new file mode 100644
index 00000000..373f6caa
--- /dev/null
+++ b/src/luarocks/rockspecs.lua
@@ -0,0 +1,159 @@
1local rockspecs = {}
2
3local cfg = require("luarocks.core.cfg")
4local dir = require("luarocks.dir")
5local path = require("luarocks.path")
6local queries = require("luarocks.queries")
7local type_rockspec = require("luarocks.type.rockspec")
8local util = require("luarocks.core.util")
9local vers = require("luarocks.core.vers")
10
11local rockspec_mt = {}
12
13rockspec_mt.__index = rockspec_mt
14
15function rockspec_mt.type()
16 return "rockspec"
17end
18
19--- Perform platform-specific overrides on a table.
20-- Overrides values of table with the contents of the appropriate
21-- subset of its "platforms" field. The "platforms" field should
22-- be a table containing subtables keyed with strings representing
23-- platform names. Names that match the contents of the global
24-- cfg.platforms setting are used. For example, if
25-- cfg.platforms= {"foo"}, then the fields of
26-- tbl.platforms.foo will overwrite those of tbl with the same
27-- names. For table values, the operation is performed recursively
28-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of
29-- tbl.x are preserved).
30-- @param tbl table or nil: Table which may contain a "platforms" field;
31-- if it doesn't (or if nil is passed), this function does nothing.
32local function platform_overrides(tbl)
33 assert(type(tbl) == "table" or not tbl)
34
35 if not tbl then return end
36
37 if tbl.platforms then
38 for _, platform in ipairs(cfg.platforms) do
39 local platform_tbl = tbl.platforms[platform]
40 if platform_tbl then
41 util.deep_merge(tbl, platform_tbl)
42 end
43 end
44 end
45 tbl.platforms = nil
46end
47
48local function convert_dependencies(rockspec, key)
49 if rockspec[key] then
50 for i = 1, #rockspec[key] do
51 local parsed, err = queries.from_dep_string(rockspec[key][i])
52 if not parsed then
53 return nil, "Parse error processing dependency '"..rockspec[key][i].."': "..tostring(err)
54 end
55 rockspec[key][i] = parsed
56 end
57 else
58 rockspec[key] = {}
59 end
60end
61
62--- Set up path-related variables for a given rock.
63-- Create a "variables" table in the rockspec table, containing
64-- adjusted variables according to the configuration file.
65-- @param rockspec table: The rockspec table.
66local function configure_paths(rockspec)
67 local vars = {}
68 for k,v in pairs(cfg.variables) do
69 vars[k] = v
70 end
71 local name, version = rockspec.name, rockspec.version
72 vars.PREFIX = path.install_dir(name, version)
73 vars.LUADIR = path.lua_dir(name, version)
74 vars.LIBDIR = path.lib_dir(name, version)
75 vars.CONFDIR = path.conf_dir(name, version)
76 vars.BINDIR = path.bin_dir(name, version)
77 vars.DOCDIR = path.doc_dir(name, version)
78 rockspec.variables = vars
79end
80
81function rockspecs.from_persisted_table(filename, rockspec, globals, quick)
82 assert(type(rockspec) == "table")
83 assert(type(globals) == "table" or globals == nil)
84 assert(type(filename) == "string")
85 assert(type(quick) == "boolean" or quick == nil)
86
87 if rockspec.rockspec_format then
88 if vers.compare_versions(rockspec.rockspec_format, type_rockspec.rockspec_format) then
89 return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks."
90 end
91 end
92
93 if not quick then
94 local ok, err = type_rockspec.check(rockspec, globals or {})
95 if not ok then
96 return nil, err
97 end
98 end
99
100 --- Check if rockspec format version satisfies version requirement.
101 -- @param rockspec table: The rockspec table.
102 -- @param version string: required version.
103 -- @return boolean: true if rockspec format matches version or is newer, false otherwise.
104 do
105 local parsed_format = vers.parse_version(rockspec.rockspec_format or "1.0")
106 rockspec.format_is_at_least = function(self, version)
107 return parsed_format >= vers.parse_version(version)
108 end
109 end
110
111 platform_overrides(rockspec.build)
112 platform_overrides(rockspec.dependencies)
113 platform_overrides(rockspec.build_dependencies)
114 platform_overrides(rockspec.test_dependencies)
115 platform_overrides(rockspec.external_dependencies)
116 platform_overrides(rockspec.source)
117 platform_overrides(rockspec.hooks)
118 platform_overrides(rockspec.test)
119
120 rockspec.name = rockspec.package:lower()
121
122 local protocol, pathname = dir.split_url(rockspec.source.url)
123 if dir.is_basic_protocol(protocol) then
124 rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url)
125 end
126 rockspec.source.protocol, rockspec.source.pathname = protocol, pathname
127
128 -- Temporary compatibility
129 if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end
130 if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end
131
132 rockspec.local_abs_filename = filename
133 local filebase = rockspec.source.file or rockspec.source.url
134 local base = dir.deduce_base_dir(filebase)
135 rockspec.source.dir_set = rockspec.source.dir ~= nil
136 rockspec.source.dir = rockspec.source.dir
137 or rockspec.source.module
138 or ( (filebase:match("%.lua$") or filebase:match("%.c$"))
139 and (rockspec:format_is_at_least("3.0")
140 and (dir.is_basic_protocol(protocol) and "." or base)
141 or ".") )
142 or base
143
144 rockspec.rocks_provided = (rockspec:format_is_at_least("3.0")
145 and cfg.rocks_provided_3_0
146 or cfg.rocks_provided)
147
148 convert_dependencies(rockspec, "dependencies")
149 convert_dependencies(rockspec, "build_dependencies")
150 convert_dependencies(rockspec, "test_dependencies")
151
152 if not quick then
153 configure_paths(rockspec)
154 end
155
156 return setmetatable(rockspec, rockspec_mt)
157end
158
159return rockspecs \ No newline at end of file
diff --git a/src/luarocks/search.lua b/src/luarocks/search.lua
index 90626f3c..da527bc6 100644
--- a/src/luarocks/search.lua
+++ b/src/luarocks/search.lua
@@ -221,6 +221,15 @@ local function supported_lua_versions(query)
221 return result_tree 221 return result_tree
222end 222end
223 223
224function search.find_src_or_rockspec(ns_name, version)
225 local query = queries.new(ns_name, version, false, "src|rockspec")
226 local url, err = search.find_suitable_rock(query)
227 if not url then
228 return nil, "Could not find a result named "..tostring(query)..": "..err
229 end
230 return url
231end
232
224--- Attempt to get a single URL for a given search for a rock. 233--- Attempt to get a single URL for a given search for a rock.
225-- @param query table: a query object. 234-- @param query table: a query object.
226-- @return string or (nil, string): URL for latest matching version 235-- @return string or (nil, string): URL for latest matching version
@@ -308,29 +317,6 @@ function search.print_result_tree(result_tree, porcelain)
308 end 317 end
309end 318end
310 319
311--- Given a name and optionally a version, try to find in the rocks
312-- servers a single .src.rock or .rockspec file that satisfies
313-- the request, and run the given function on it; or display to the
314-- user possibilities if it couldn't narrow down a single match.
315-- @param action function: A function that takes a .src.rock or
316-- .rockspec URL as a parameter.
317-- @param ns_name string: A rock name, may be namespaced
318-- @param version string or nil: A version number may also be given.
319-- @return The result of the action function, or nil and an error message.
320function search.act_on_src_or_rockspec(action, ns_name, version, ...)
321 assert(type(action) == "function")
322 assert(type(ns_name) == "string")
323 assert(type(version) == "string" or not version)
324
325 local query = queries.new(ns_name, version, false, "src|rockspec")
326 local url, err = search.find_suitable_rock(query)
327 if not url then
328 return nil, "Could not find a result named "..tostring(query)..": "..err
329 end
330 local _, namespace = util.split_namespace(ns_name)
331 return action(url, namespace, ...)
332end
333
334function search.pick_installed_rock(query, given_tree) 320function search.pick_installed_rock(query, given_tree)
335 assert(query:type() == "query") 321 assert(query:type() == "query")
336 322
diff --git a/src/luarocks/type_check.lua b/src/luarocks/type_check.lua
index 9e3b7c9e..ebd59f85 100644
--- a/src/luarocks/type_check.lua
+++ b/src/luarocks/type_check.lua
@@ -110,12 +110,12 @@ function type_check.type_check_table(version, tbl, typetbl, context)
110 assert(type(version) == "string") 110 assert(type(version) == "string")
111 assert(type(tbl) == "table") 111 assert(type(tbl) == "table")
112 assert(type(typetbl) == "table") 112 assert(type(typetbl) == "table")
113 113
114 local ok, err = check_version(version, typetbl, context) 114 local ok, err = check_version(version, typetbl, context)
115 if not ok then 115 if not ok then
116 return nil, err 116 return nil, err
117 end 117 end
118 118
119 for k, v in pairs(tbl) do 119 for k, v in pairs(tbl) do
120 local t = typetbl[k] or typetbl._any 120 local t = typetbl[k] or typetbl._any
121 if t then 121 if t then
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
index ea18071f..cd946451 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -215,37 +215,6 @@ function util.parse_flags(...)
215 return flags, unpack(out) 215 return flags, unpack(out)
216end 216end
217 217
218--- Perform platform-specific overrides on a table.
219-- Overrides values of table with the contents of the appropriate
220-- subset of its "platforms" field. The "platforms" field should
221-- be a table containing subtables keyed with strings representing
222-- platform names. Names that match the contents of the global
223-- cfg.platforms setting are used. For example, if
224-- cfg.platforms= {"foo"}, then the fields of
225-- tbl.platforms.foo will overwrite those of tbl with the same
226-- names. For table values, the operation is performed recursively
227-- (tbl.platforms.foo.x.y.z overrides tbl.x.y.z; other contents of
228-- tbl.x are preserved).
229-- @param tbl table or nil: Table which may contain a "platforms" field;
230-- if it doesn't (or if nil is passed), this function does nothing.
231function util.platform_overrides(tbl)
232 assert(type(tbl) == "table" or not tbl)
233
234 local cfg = require("luarocks.core.cfg")
235
236 if not tbl then return end
237
238 if tbl.platforms then
239 for _, platform in ipairs(cfg.platforms) do
240 local platform_tbl = tbl.platforms[platform]
241 if platform_tbl then
242 core.deep_merge(tbl, platform_tbl)
243 end
244 end
245 end
246 tbl.platforms = nil
247end
248
249local var_format_pattern = "%$%((%a[%a%d_]+)%)" 218local var_format_pattern = "%$%((%a[%a%d_]+)%)"
250 219
251-- Check if a set of needed variables are referenced 220-- Check if a set of needed variables are referenced