aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham <hisham@gobolinux.org>2016-05-25 01:24:58 -0300
committerHisham <hisham@gobolinux.org>2016-05-25 01:24:58 -0300
commit4c12525d1f52bccc71c2a3054d3db328a0577179 (patch)
tree899bca39ac9f2692419a0271306d2f326917e0d7
parent6217339cd4ba6d7ee7f08aa86443032ede033752 (diff)
parenta3650d51e96aef84657cb29e5f52e570fed828c9 (diff)
downloadluarocks-4c12525d1f52bccc71c2a3054d3db328a0577179.tar.gz
luarocks-4c12525d1f52bccc71c2a3054d3db328a0577179.tar.bz2
luarocks-4c12525d1f52bccc71c2a3054d3db328a0577179.zip
Merge branch 'master' of https://github.com/keplerproject/luarocks
-rw-r--r--Makefile.setup.inc2
-rw-r--r--src/luarocks/build.lua10
-rw-r--r--src/luarocks/deps.lua128
-rw-r--r--src/luarocks/fs.lua5
-rw-r--r--src/luarocks/fs/tools.lua156
-rw-r--r--src/luarocks/fs/unix.lua7
-rw-r--r--src/luarocks/fs/unix/tools.lua151
-rw-r--r--src/luarocks/fs/win32.lua7
-rw-r--r--src/luarocks/fs/win32/tools.lua170
-rw-r--r--src/luarocks/install.lua13
-rw-r--r--src/luarocks/manif.lua2
-rw-r--r--src/luarocks/repos.lua5
-rw-r--r--src/luarocks/util.lua14
-rw-r--r--src/luarocks/write_rockspec.lua56
-rw-r--r--test/testing.lua21
-rwxr-xr-xtest/testing.sh16
16 files changed, 335 insertions, 428 deletions
diff --git a/Makefile.setup.inc b/Makefile.setup.inc
index 0a049bc4..092d0423 100644
--- a/Makefile.setup.inc
+++ b/Makefile.setup.inc
@@ -5,7 +5,7 @@ BINDIR ?= $(PREFIX)/bin
5LUADIR ?= $(PREFIX)/share/lua/$(LUA_VERSION)/ 5LUADIR ?= $(PREFIX)/share/lua/$(LUA_VERSION)/
6 6
7BIN_FILES = luarocks luarocks-admin 7BIN_FILES = luarocks luarocks-admin
8LUAROCKS_FILES = fs/unix/tools.lua fs/unix.lua fs/win32/tools.lua fs/win32.lua \ 8LUAROCKS_FILES = fs/tools.lua fs/unix/tools.lua fs/unix.lua fs/win32/tools.lua fs/win32.lua \
9fs/lua.lua persist.lua list.lua require.lua repos.lua dir.lua make_manifest.lua \ 9fs/lua.lua persist.lua list.lua require.lua repos.lua dir.lua make_manifest.lua \
10command_line.lua config_cmd.lua install.lua build/command.lua build/cmake.lua \ 10command_line.lua config_cmd.lua install.lua build/command.lua build/cmake.lua \
11build/make.lua build/builtin.lua fetch/cvs.lua fetch/git.lua fetch/sscm.lua \ 11build/make.lua build/builtin.lua fetch/cvs.lua fetch/git.lua fetch/sscm.lua \
diff --git a/src/luarocks/build.lua b/src/luarocks/build.lua
index a1aeb501..c62e4694 100644
--- a/src/luarocks/build.lua
+++ b/src/luarocks/build.lua
@@ -332,15 +332,7 @@ function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_m
332 ok, err = manif.update_manifest(name, version, nil, deps_mode) 332 ok, err = manif.update_manifest(name, version, nil, deps_mode)
333 if err then return nil, err end 333 if err then return nil, err end
334 334
335 local license = "" 335 util.announce_install(rockspec)
336 if rockspec.description and rockspec.description.license then
337 license = ("(license: "..rockspec.description.license..")")
338 end
339
340 local root_dir = path.root_dir(cfg.rocks_dir)
341 util.printout(name.." "..version.." is now built and installed in "..root_dir.." "..license)
342 util.printout()
343
344 util.remove_scheduled_function(rollback) 336 util.remove_scheduled_function(rollback)
345 return name, version 337 return name, version
346end 338end
diff --git a/src/luarocks/deps.lua b/src/luarocks/deps.lua
index 812e6d18..536b6c51 100644
--- a/src/luarocks/deps.lua
+++ b/src/luarocks/deps.lua
@@ -322,48 +322,32 @@ end
322-- @param dep table: A dependency parsed in table format. 322-- @param dep table: A dependency parsed in table format.
323-- @param blacklist table: Versions that can't be accepted. Table where keys 323-- @param blacklist table: Versions that can't be accepted. Table where keys
324-- are program versions and values are 'true'. 324-- are program versions and values are 'true'.
325-- @return table or nil: A table containing fields 'name' and 'version' 325-- @return string or nil: latest installed version of the rock matching the dependency
326-- representing an installed rock which matches the given dependency,
327-- or nil if it could not be matched. 326-- or nil if it could not be matched.
328local function match_dep(dep, blacklist, deps_mode) 327local function match_dep(dep, blacklist, deps_mode)
329 assert(type(dep) == "table") 328 assert(type(dep) == "table")
330 329
331 local versions = cfg.rocks_provided[dep.name] 330 local versions
332 if cfg.rocks_provided[dep.name] then 331 if cfg.rocks_provided[dep.name] then
333 -- provided rocks have higher priority than manifest's rocks 332 -- provided rocks have higher priority than manifest's rocks
334 versions = { cfg.rocks_provided[dep.name] } 333 versions = { cfg.rocks_provided[dep.name] }
335 else 334 else
336 versions = manif_core.get_versions(dep.name, deps_mode) 335 versions = manif_core.get_versions(dep.name, deps_mode)
337 end 336 end
338 if not versions then 337
339 return nil 338 local latest_version
340 end
341 if blacklist then
342 local i = 1
343 while versions[i] do
344 if blacklist[versions[i]] then
345 table.remove(versions, i)
346 else
347 i = i + 1
348 end
349 end
350 end
351 local candidates = {}
352 for _, vstring in ipairs(versions) do 339 for _, vstring in ipairs(versions) do
353 local version = deps.parse_version(vstring) 340 if not blacklist or not blacklist[vstring] then
354 if deps.match_constraints(version, dep.constraints) then 341 local version = deps.parse_version(vstring)
355 table.insert(candidates, version) 342 if deps.match_constraints(version, dep.constraints) then
343 if not latest_version or version > latest_version then
344 latest_version = version
345 end
346 end
356 end 347 end
357 end 348 end
358 if #candidates == 0 then 349
359 return nil 350 return latest_version and latest_version.string
360 else
361 table.sort(candidates)
362 return {
363 name = dep.name,
364 version = candidates[#candidates].string
365 }
366 end
367end 351end
368 352
369--- Attempt to match dependencies of a rockspec to installed rocks. 353--- Attempt to match dependencies of a rockspec to installed rocks.
@@ -386,7 +370,7 @@ function deps.match_deps(rockspec, blacklist, deps_mode)
386 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode) 370 local found = match_dep(dep, blacklist and blacklist[dep.name] or nil, deps_mode)
387 if found then 371 if found then
388 if not cfg.rocks_provided[dep.name] then 372 if not cfg.rocks_provided[dep.name] then
389 matched[dep] = found 373 matched[dep] = {name = dep.name, version = found}
390 end 374 end
391 else 375 else
392 if dep.constraints[1] and dep.constraints[1].no_upgrade then 376 if dep.constraints[1] and dep.constraints[1].no_upgrade then
@@ -410,6 +394,13 @@ local function values_set(tbl)
410 return set 394 return set
411end 395end
412 396
397local function rock_status(name, deps_mode)
398 local search = require("luarocks.search")
399 local installed = match_dep(search.make_query(name), nil, deps_mode)
400 local installation_type = cfg.rocks_provided[name] and "provided by VM" or "installed"
401 return installed and installed.." "..installation_type or "not installed"
402end
403
413--- Check dependencies of a rock and attempt to install any missing ones. 404--- Check dependencies of a rock and attempt to install any missing ones.
414-- Packages are installed using the LuaRocks "install" command. 405-- Packages are installed using the LuaRocks "install" command.
415-- Aborts the program if a dependency could not be fulfilled. 406-- Aborts the program if a dependency could not be fulfilled.
@@ -449,52 +440,53 @@ function deps.fulfill_dependencies(rockspec, deps_mode)
449 end 440 end
450 end 441 end
451 442
452 local _, missing, no_upgrade = deps.match_deps(rockspec, nil, deps_mode) 443 local first_missing_dep = true
453 444
454 if next(no_upgrade) then 445 for _, dep in ipairs(rockspec.dependencies) do
455 util.printerr("Missing dependencies for "..rockspec.name.." "..rockspec.version..":") 446 if not match_dep(dep, nil, deps_mode) then
456 for _, dep in pairs(no_upgrade) do 447 if first_missing_dep then
457 util.printerr(deps.show_dep(dep)) 448 util.printout(("Missing dependencies for %s %s:"):format(rockspec.name, rockspec.version))
458 end 449 first_missing_dep = false
459 if next(missing) then
460 for _, dep in pairs(missing) do
461 util.printerr(deps.show_dep(dep))
462 end 450 end
451
452 util.printout((" %s (%s)"):format(deps.show_dep(dep), rock_status(dep.name, deps_mode)))
463 end 453 end
464 util.printerr()
465 for _, dep in pairs(no_upgrade) do
466 util.printerr("This version of "..rockspec.name.." is designed for use with")
467 util.printerr(deps.show_dep(dep)..", but is configured to avoid upgrading it")
468 util.printerr("automatically. Please upgrade "..dep.name.." with")
469 util.printerr(" luarocks install "..dep.name)
470 util.printerr("or choose an older version of "..rockspec.name.." with")
471 util.printerr(" luarocks search "..rockspec.name)
472 end
473 return nil, "Failed matching dependencies."
474 end 454 end
475 455
476 if next(missing) then 456 first_missing_dep = true
477 util.printerr() 457
478 util.printerr("Missing dependencies for "..rockspec.name..":") 458 for _, dep in ipairs(rockspec.dependencies) do
479 for _, dep in pairs(missing) do 459 if not match_dep(dep, nil, deps_mode) then
480 util.printerr(deps.show_dep(dep)) 460 if first_missing_dep then
481 end 461 util.printout()
482 util.printerr() 462 first_missing_dep = false
483 463 end
484 for _, dep in pairs(missing) do 464
485 -- Double-check in case dependency was filled during recursion. 465 util.printout(("%s %s depends on %s (%s)"):format(
486 if not match_dep(dep, nil, deps_mode) then 466 rockspec.name, rockspec.version, deps.show_dep(dep), rock_status(dep.name, deps_mode)))
487 local url, err = search.find_suitable_rock(dep) 467
488 if not url then 468 if dep.constraints[1] and dep.constraints[1].no_upgrade then
489 return nil, "Could not satisfy dependency "..deps.show_dep(dep)..": "..err 469 util.printerr("This version of "..rockspec.name.." is designed for use with")
490 end 470 util.printerr(deps.show_dep(dep)..", but is configured to avoid upgrading it")
491 local ok, err, errcode = install.run(url, deps.deps_mode_to_flag(deps_mode)) 471 util.printerr("automatically. Please upgrade "..dep.name.." with")
492 if not ok then 472 util.printerr(" luarocks install "..dep.name)
493 return nil, "Failed installing dependency: "..url.." - "..err, errcode 473 util.printerr("or choose an older version of "..rockspec.name.." with")
494 end 474 util.printerr(" luarocks search "..rockspec.name)
475 return nil, "Failed matching dependencies"
476 end
477
478 local url, search_err = search.find_suitable_rock(dep)
479 if not url then
480 return nil, "Could not satisfy dependency "..deps.show_dep(dep)..": "..search_err
481 end
482 util.printout("Installing "..url)
483 local ok, install_err, errcode = install.run(url, deps.deps_mode_to_flag(deps_mode))
484 if not ok then
485 return nil, "Failed installing dependency: "..url.." - "..install_err, errcode
495 end 486 end
496 end 487 end
497 end 488 end
489
498 return true 490 return true
499end 491end
500 492
diff --git a/src/luarocks/fs.lua b/src/luarocks/fs.lua
index 57302c7f..f3d86a13 100644
--- a/src/luarocks/fs.lua
+++ b/src/luarocks/fs.lua
@@ -68,7 +68,10 @@ load_fns(fs_lua)
68 68
69-- Load platform-specific fallbacks for missing Lua modules 69-- Load platform-specific fallbacks for missing Lua modules
70local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools") 70local ok, fs_plat_tools = pcall(require, "luarocks.fs."..loaded_platform..".tools")
71if ok and fs_plat_tools then load_fns(fs_plat_tools) end 71if ok and fs_plat_tools then
72 load_fns(fs_plat_tools)
73 load_fns(require("luarocks.fs.tools"))
74end
72 75
73 76
74return fs 77return fs
diff --git a/src/luarocks/fs/tools.lua b/src/luarocks/fs/tools.lua
new file mode 100644
index 00000000..ed51b545
--- /dev/null
+++ b/src/luarocks/fs/tools.lua
@@ -0,0 +1,156 @@
1
2--- Common fs operations implemented with third-party tools.
3local tools = {}
4
5local fs = require("luarocks.fs")
6local dir = require("luarocks.dir")
7local cfg = require("luarocks.cfg")
8
9local vars = cfg.variables
10
11local dir_stack = {}
12
13--- Obtain current directory.
14-- Uses the module's internal directory stack.
15-- @return string: the absolute pathname of the current directory.
16function tools.current_dir()
17 local current = cfg.cache_pwd
18 if not current then
19 local pipe = io.popen(fs.quiet_stderr(fs.Q(vars.PWD)))
20 current = pipe:read("*l")
21 pipe:close()
22 cfg.cache_pwd = current
23 end
24 for _, directory in ipairs(dir_stack) do
25 current = fs.absolute_name(directory, current)
26 end
27 return current
28end
29
30--- Change the current directory.
31-- Uses the module's internal directory stack. This does not have exact
32-- semantics of chdir, as it does not handle errors the same way,
33-- but works well for our purposes for now.
34-- @param directory string: The directory to switch to.
35-- @return boolean or (nil, string): true if successful, (nil, error message) if failed.
36function tools.change_dir(directory)
37 assert(type(directory) == "string")
38 if fs.is_dir(directory) then
39 table.insert(dir_stack, directory)
40 return true
41 end
42 return nil, "directory not found: "..directory
43end
44
45--- Change directory to root.
46-- Allows leaving a directory (e.g. for deleting it) in
47-- a crossplatform way.
48function tools.change_dir_to_root()
49 table.insert(dir_stack, "/")
50end
51
52--- Change working directory to the previous in the directory stack.
53function tools.pop_dir()
54 local directory = table.remove(dir_stack)
55 return directory ~= nil
56end
57
58--- Run the given command.
59-- The command is executed in the current directory in the directory stack.
60-- @param cmd string: No quoting/escaping is applied to the command.
61-- @return boolean: true if command succeeds (status code 0), false
62-- otherwise.
63function tools.execute_string(cmd)
64 local current = fs.current_dir()
65 if not current then return false end
66 cmd = fs.command_at(current, cmd)
67 local code = os.execute(cmd)
68 if code == 0 or code == true then
69 return true
70 else
71 return false
72 end
73end
74
75--- Internal implementation function for fs.dir.
76-- Yields a filename on each iteration.
77-- @param at string: directory to list
78-- @return nil
79function tools.dir_iterator(at)
80 local pipe = io.popen(fs.command_at(at, fs.Q(vars.LS)))
81 for file in pipe:lines() do
82 if file ~= "." and file ~= ".." then
83 coroutine.yield(file)
84 end
85 end
86 pipe:close()
87end
88
89--- Download a remote file.
90-- @param url string: URL to be fetched.
91-- @param filename string or nil: this function attempts to detect the
92-- resulting local filename of the remote file as the basename of the URL;
93-- if that is not correct (due to a redirection, for example), the local
94-- filename can be given explicitly as this second argument.
95-- @return (boolean, string): true and the filename on success,
96-- false and the error message on failure.
97function tools.use_downloader(url, filename, cache)
98 assert(type(url) == "string")
99 assert(type(filename) == "string" or not filename)
100
101 filename = fs.absolute_name(filename or dir.base_name(url))
102
103 local ok
104 if cfg.downloader == "wget" then
105 local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet "
106 if cfg.connection_timeout and cfg.connection_timeout > 0 then
107 wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
108 end
109 if cache then
110 -- --timestamping is incompatible with --output-document,
111 -- but that's not a problem for our use cases.
112 fs.change_dir(dir.dir_name(filename))
113 ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
114 fs.pop_dir()
115 elseif filename then
116 ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
117 else
118 ok = fs.execute_quiet(wget_cmd, url)
119 end
120 elseif cfg.downloader == "curl" then
121 local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" "
122 if cfg.connection_timeout and cfg.connection_timeout > 0 then
123 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
124 end
125 ok = fs.execute_string(fs.quiet_stderr(curl_cmd..fs.Q(url).." > "..fs.Q(filename)))
126 end
127 if ok then
128 return true, filename
129 else
130 return false
131 end
132end
133
134local md5_cmd = {
135 md5sum = fs.Q(vars.MD5SUM),
136 openssl = fs.Q(vars.OPENSSL).." md5",
137 md5 = fs.Q(vars.MD5),
138}
139
140--- Get the MD5 checksum for a file.
141-- @param file string: The file to be computed.
142-- @return string: The MD5 checksum or nil + message
143function tools.get_md5(file)
144 local cmd = md5_cmd[cfg.md5checker]
145 if not cmd then return nil, "no MD5 checker command configured" end
146 local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
147 local computed = pipe:read("*a")
148 pipe:close()
149 if computed then
150 computed = computed:match("("..("%x"):rep(32)..")")
151 end
152 if computed then return computed end
153 return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
154end
155
156return tools
diff --git a/src/luarocks/fs/unix.lua b/src/luarocks/fs/unix.lua
index e2cc825b..520b3e99 100644
--- a/src/luarocks/fs/unix.lua
+++ b/src/luarocks/fs/unix.lua
@@ -16,6 +16,13 @@ function unix.quiet(cmd)
16 return cmd.." 1> /dev/null 2> /dev/null" 16 return cmd.." 1> /dev/null 2> /dev/null"
17end 17end
18 18
19--- Annotate command string for execution with quiet stderr.
20-- @param cmd string: A command-line string.
21-- @return string: The command-line, with stderr silencing annotation.
22function unix.quiet_stderr(cmd)
23 return cmd.." 2> /dev/null"
24end
25
19--- Return an absolute pathname from a potentially relative one. 26--- Return an absolute pathname from a potentially relative one.
20-- @param pathname string: pathname to convert. 27-- @param pathname string: pathname to convert.
21-- @param relative_to string or nil: path to prepend when making 28-- @param relative_to string or nil: path to prepend when making
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua
index ab55897e..84bd53fd 100644
--- a/src/luarocks/fs/unix/tools.lua
+++ b/src/luarocks/fs/unix/tools.lua
@@ -7,74 +7,16 @@ local fs = require("luarocks.fs")
7local dir = require("luarocks.dir") 7local dir = require("luarocks.dir")
8local cfg = require("luarocks.cfg") 8local cfg = require("luarocks.cfg")
9 9
10local dir_stack = {}
11
12local vars = cfg.variables 10local vars = cfg.variables
13 11
14local function command_at(directory, cmd) 12--- Adds prefix to command to make it run from a directory.
13-- @param directory string: Path to a directory.
14-- @param cmd string: A command-line string.
15-- @return string: The command-line with prefix.
16function tools.command_at(directory, cmd)
15 return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd 17 return "cd " .. fs.Q(fs.absolute_name(directory)) .. " && " .. cmd
16end 18end
17 19
18--- Obtain current directory.
19-- Uses the module's internal directory stack.
20-- @return string: the absolute pathname of the current directory.
21function tools.current_dir()
22 local current = cfg.cache_pwd
23 if not current then
24 local pipe = io.popen(fs.Q(vars.PWD).." 2> /dev/null")
25 current = pipe:read("*l")
26 pipe:close()
27 cfg.cache_pwd = current
28 end
29 for _, directory in ipairs(dir_stack) do
30 current = fs.absolute_name(directory, current)
31 end
32 return current
33end
34
35--- Run the given command.
36-- The command is executed in the current directory in the directory stack.
37-- @param cmd string: No quoting/escaping is applied to the command.
38-- @return boolean: true if command succeeds (status code 0), false
39-- otherwise.
40function tools.execute_string(cmd)
41 local current = fs.current_dir()
42 if not current then return false end
43 local code, err = os.execute(command_at(current, cmd))
44 if code == 0 or code == true then
45 return true
46 else
47 return false
48 end
49end
50
51--- Change the current directory.
52-- Uses the module's internal directory stack. This does not have exact
53-- semantics of chdir, as it does not handle errors the same way,
54-- but works well for our purposes for now.
55-- @param directory string: The directory to switch to.
56function tools.change_dir(directory)
57 assert(type(directory) == "string")
58 if fs.is_dir(directory) then
59 table.insert(dir_stack, directory)
60 return true
61 end
62 return nil, "directory not found: "..directory
63end
64
65--- Change directory to root.
66-- Allows leaving a directory (e.g. for deleting it) in
67-- a crossplatform way.
68function tools.change_dir_to_root()
69 table.insert(dir_stack, "/")
70end
71
72--- Change working directory to the previous in the directory stack.
73function tools.pop_dir()
74 local directory = table.remove(dir_stack)
75 return directory ~= nil
76end
77
78--- Create a directory if it does not already exist. 20--- Create a directory if it does not already exist.
79-- If any of the higher levels in the path name does not exist 21-- If any of the higher levels in the path name does not exist
80-- too, they are created as well. 22-- too, they are created as well.
@@ -155,20 +97,6 @@ function tools.delete(arg)
155 fs.execute_quiet(vars.RM, "-rf", arg) 97 fs.execute_quiet(vars.RM, "-rf", arg)
156end 98end
157 99
158--- Internal implementation function for fs.dir.
159-- Yields a filename on each iteration.
160-- @param at string: directory to list
161-- @return nil
162function tools.dir_iterator(at)
163 local pipe = io.popen(command_at(at, vars.LS))
164 for file in pipe:lines() do
165 if file ~= "." and file ~= ".." then
166 coroutine.yield(file)
167 end
168 end
169 pipe:close()
170end
171
172--- Recursively scan the contents of a directory. 100--- Recursively scan the contents of a directory.
173-- @param at string or nil: directory to scan (will be the current 101-- @param at string or nil: directory to scan (will be the current
174-- directory if none is given). 102-- directory if none is given).
@@ -183,7 +111,7 @@ function tools.find(at)
183 return {} 111 return {}
184 end 112 end
185 local result = {} 113 local result = {}
186 local pipe = io.popen(command_at(at, vars.FIND.." * 2>/dev/null")) 114 local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(vars.FIND.." *")))
187 for file in pipe:lines() do 115 for file in pipe:lines() do
188 table.insert(result, file) 116 table.insert(result, file)
189 end 117 end
@@ -232,51 +160,6 @@ function tools.is_file(file)
232 return fs.execute(vars.TEST, "-f", file) 160 return fs.execute(vars.TEST, "-f", file)
233end 161end
234 162
235--- Download a remote file.
236-- @param url string: URL to be fetched.
237-- @param filename string or nil: this function attempts to detect the
238-- resulting local filename of the remote file as the basename of the URL;
239-- if that is not correct (due to a redirection, for example), the local
240-- filename can be given explicitly as this second argument.
241-- @return (boolean, string): true and the filename on success,
242-- false and the error message on failure.
243function tools.use_downloader(url, filename, cache)
244 assert(type(url) == "string")
245 assert(type(filename) == "string" or not filename)
246
247 filename = fs.absolute_name(filename or dir.base_name(url))
248
249 local ok
250 if cfg.downloader == "wget" then
251 local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet "
252 if cfg.connection_timeout and cfg.connection_timeout > 0 then
253 wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
254 end
255 if cache then
256 -- --timestamping is incompatible with --output-document,
257 -- but that's not a problem for our use cases.
258 fs.change_dir(dir.dir_name(filename))
259 ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
260 fs.pop_dir()
261 elseif filename then
262 ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
263 else
264 ok = fs.execute_quiet(wget_cmd, url)
265 end
266 elseif cfg.downloader == "curl" then
267 local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent '"..cfg.user_agent.." via curl' "
268 if cfg.connection_timeout and cfg.connection_timeout > 0 then
269 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
270 end
271 ok = fs.execute_string(curl_cmd..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename))
272 end
273 if ok then
274 return true, filename
275 else
276 return false
277 end
278end
279
280function tools.chmod(pathname, mode) 163function tools.chmod(pathname, mode)
281 if mode then 164 if mode then
282 return fs.execute(vars.CHMOD, mode, pathname) 165 return fs.execute(vars.CHMOD, mode, pathname)
@@ -319,28 +202,6 @@ function tools.unpack_archive(archive)
319 return true 202 return true
320end 203end
321 204
322local md5_cmd = {
323 md5sum = vars.MD5SUM,
324 openssl = vars.OPENSSL.." md5",
325 md5 = vars.MD5,
326}
327
328--- Get the MD5 checksum for a file.
329-- @param file string: The file to be computed.
330-- @return string: The MD5 checksum
331function tools.get_md5(file)
332 local cmd = md5_cmd[cfg.md5checker]
333 if not cmd then return nil, "no MD5 checker command configured" end
334 local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
335 local computed = pipe:read("*a")
336 pipe:close()
337 if computed then
338 computed = computed:match("("..("%x"):rep(32)..")")
339 end
340 if computed then return computed end
341 return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
342end
343
344function tools.get_permissions(filename) 205function tools.get_permissions(filename)
345 local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename)) 206 local pipe = io.popen(vars.STAT.." "..vars.STATFLAG.." "..fs.Q(filename))
346 local ret = pipe:read("*l") 207 local ret = pipe:read("*l")
diff --git a/src/luarocks/fs/win32.lua b/src/luarocks/fs/win32.lua
index c14c421b..74f3ed69 100644
--- a/src/luarocks/fs/win32.lua
+++ b/src/luarocks/fs/win32.lua
@@ -27,6 +27,13 @@ function win32.quiet(cmd)
27 return cmd.." 2> NUL 1> NUL" 27 return cmd.." 2> NUL 1> NUL"
28end 28end
29 29
30--- Annotate command string for execution with quiet stderr.
31-- @param cmd string: A command-line string.
32-- @return string: The command-line, with stderr silencing annotation.
33function win32.quiet_stderr(cmd)
34 return cmd.." 2> NUL"
35end
36
30local drive_letter = "[%.a-zA-Z]?:?[\\/]" 37local drive_letter = "[%.a-zA-Z]?:?[\\/]"
31 38
32local win_escape_chars = { 39local win_escape_chars = {
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua
index b9dce85c..9cb6d47a 100644
--- a/src/luarocks/fs/win32/tools.lua
+++ b/src/luarocks/fs/win32/tools.lua
@@ -9,22 +9,13 @@ local fs = require("luarocks.fs")
9local dir = require("luarocks.dir") 9local dir = require("luarocks.dir")
10local cfg = require("luarocks.cfg") 10local cfg = require("luarocks.cfg")
11 11
12local dir_stack = {}
13
14local vars = cfg.variables 12local vars = cfg.variables
15 13
16--- Strip the last extension of a filename. 14--- Adds prefix to command to make it run from a directory.
17-- Example: "foo.tar.gz" becomes "foo.tar". 15-- @param directory string: Path to a directory.
18-- If filename has no dots, returns it unchanged. 16-- @param cmd string: A command-line string.
19-- @param filename string: The file name to strip. 17-- @return string: The command-line with prefix.
20-- @return string: The stripped name. 18function tools.command_at(directory, cmd)
21local function strip_extension(filename)
22 assert(type(filename) == "string")
23
24 return (filename:gsub("%.[^.]+$", "")) or filename
25end
26
27local function command_at(directory, cmd)
28 local drive = directory:match("^([A-Za-z]:)") 19 local drive = directory:match("^([A-Za-z]:)")
29 cmd = "cd " .. fs.Q(directory) .. " & " .. cmd 20 cmd = "cd " .. fs.Q(directory) .. " & " .. cmd
30 if drive then 21 if drive then
@@ -33,68 +24,6 @@ local function command_at(directory, cmd)
33 return cmd 24 return cmd
34end 25end
35 26
36--- Obtain current directory.
37-- Uses the module's internal directory stack.
38-- @return string: the absolute pathname of the current directory.
39function tools.current_dir()
40 local current = cfg.cache_pwd
41 if not current then
42 local pipe = io.popen(fs.Q(vars.PWD).. " 2> NUL")
43 current = pipe:read("*l")
44 pipe:close()
45 cfg.cache_pwd = current
46 end
47 for _, directory in ipairs(dir_stack) do
48 current = fs.absolute_name(directory, current)
49 end
50 return current
51end
52
53--- Run the given command.
54-- The command is executed in the current directory in the directory stack.
55-- @param cmd string: No quoting/escaping is applied to the command.
56-- @return boolean: true if command succeeds (status code 0), false
57-- otherwise.
58function tools.execute_string(cmd)
59 local current = fs.current_dir()
60 if not current then return false end
61 cmd = command_at(current, cmd)
62 local code = os.execute(cmd)
63 if code == 0 or code == true then
64 return true
65 else
66 return false
67 end
68end
69
70--- Change the current directory.
71-- Uses the module's internal directory stack. This does not have exact
72-- semantics of chdir, as it does not handle errors the same way,
73-- but works well for our purposes for now.
74-- @param directory string: The directory to switch to.
75-- @return boolean or (nil, string): true if successful, (nil, error message) if failed.
76function tools.change_dir(directory)
77 assert(type(directory) == "string")
78 if fs.is_dir(directory) then
79 table.insert(dir_stack, directory)
80 return true
81 end
82 return nil, "directory not found: "..directory
83end
84
85--- Change directory to root.
86-- Allows leaving a directory (e.g. for deleting it) in
87-- a crossplatform way.
88function tools.change_dir_to_root()
89 table.insert(dir_stack, "/")
90end
91
92--- Change working directory to the previous in the directory stack.
93function tools.pop_dir()
94 local directory = table.remove(dir_stack)
95 return directory ~= nil
96end
97
98--- Create a directory if it does not already exist. 27--- Create a directory if it does not already exist.
99-- If any of the higher levels in the path name does not exist 28-- If any of the higher levels in the path name does not exist
100-- too, they are created as well. 29-- too, they are created as well.
@@ -168,20 +97,6 @@ function tools.delete(arg)
168 fs.execute_quiet("if exist "..fs.Q(arg.."\\").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )") 97 fs.execute_quiet("if exist "..fs.Q(arg.."\\").." ( RMDIR /S /Q "..fs.Q(arg).." ) else ( DEL /Q /F "..fs.Q(arg).." )")
169end 98end
170 99
171--- Internal implementation function for fs.dir.
172-- Yields a filename on each iteration.
173-- @param at string: directory to list
174-- @return nil
175function tools.dir_iterator(at)
176 local pipe = io.popen(command_at(at, fs.Q(vars.LS)))
177 for file in pipe:lines() do
178 if file ~= "." and file ~= ".." then
179 coroutine.yield(file)
180 end
181 end
182 pipe:close()
183end
184
185--- Recursively scan the contents of a directory. 100--- Recursively scan the contents of a directory.
186-- @param at string or nil: directory to scan (will be the current 101-- @param at string or nil: directory to scan (will be the current
187-- directory if none is given). 102-- directory if none is given).
@@ -196,7 +111,7 @@ function tools.find(at)
196 return {} 111 return {}
197 end 112 end
198 local result = {} 113 local result = {}
199 local pipe = io.popen(command_at(at, fs.Q(vars.FIND).." 2> NUL")) 114 local pipe = io.popen(fs.command_at(at, fs.quiet_stderr(fs.Q(vars.FIND))))
200 for file in pipe:lines() do 115 for file in pipe:lines() do
201 -- Windows find is a bit different 116 -- Windows find is a bit different
202 local first_two = file:sub(1,2) 117 local first_two = file:sub(1,2)
@@ -242,49 +157,14 @@ function tools.is_file(file)
242 return fs.execute(fs.Q(vars.TEST).." -f", file) 157 return fs.execute(fs.Q(vars.TEST).." -f", file)
243end 158end
244 159
245--- Download a remote file. 160--- Strip the last extension of a filename.
246-- @param url string: URL to be fetched. 161-- Example: "foo.tar.gz" becomes "foo.tar".
247-- @param filename string or nil: this function attempts to detect the 162-- If filename has no dots, returns it unchanged.
248-- resulting local filename of the remote file as the basename of the URL; 163-- @param filename string: The file name to strip.
249-- if that is not correct (due to a redirection, for example), the local 164-- @return string: The stripped name.
250-- filename can be given explicitly as this second argument. 165local function strip_extension(filename)
251-- @return (boolean, string): true and the filename on success, 166 assert(type(filename) == "string")
252-- false and the error message on failure. 167 return (filename:gsub("%.[^.]+$", "")) or filename
253function tools.use_downloader(url, filename, cache)
254 assert(type(url) == "string")
255 assert(type(filename) == "string" or not filename)
256
257 filename = fs.absolute_name(filename or dir.base_name(url))
258
259 local ok
260 if cfg.downloader == "wget" then
261 local wget_cmd = fs.Q(vars.WGET).." "..vars.WGETNOCERTFLAG.." --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet "
262 if cfg.connection_timeout and cfg.connection_timeout > 0 then
263 wget_cmd = wget_cmd .. "--timeout="..tonumber(cfg.connection_timeout).." --tries=1 "
264 end
265 if cache then
266 -- --timestamping is incompatible with --output-document,
267 -- but that's not a problem for our use cases.
268 fs.change_dir(dir.dir_name(filename))
269 ok = fs.execute_quiet(wget_cmd.." --timestamping ", url)
270 fs.pop_dir()
271 elseif filename then
272 ok = fs.execute_quiet(wget_cmd.." --output-document ", filename, url)
273 else
274 ok = fs.execute_quiet(wget_cmd, url)
275 end
276 elseif cfg.downloader == "curl" then
277 local curl_cmd = fs.Q(vars.CURL).." "..vars.CURLNOCERTFLAG.." -f -L --user-agent \""..cfg.user_agent.." via curl\" "
278 if cfg.connection_timeout and cfg.connection_timeout > 0 then
279 curl_cmd = curl_cmd .. "--connect-timeout "..tonumber(cfg.connection_timeout).." "
280 end
281 ok = fs.execute_string(curl_cmd..fs.Q(url).." 2> NUL 1> "..fs.Q(filename))
282 end
283 if ok then
284 return true, filename
285 else
286 return false
287 end
288end 168end
289 169
290--- Uncompress gzip file. 170--- Uncompress gzip file.
@@ -334,28 +214,6 @@ function tools.unpack_archive(archive)
334 return true 214 return true
335end 215end
336 216
337local md5_cmd = {
338 md5sum = fs.Q(vars.MD5SUM),
339 openssl = fs.Q(vars.OPENSSL).." md5",
340 md5 = fs.Q(vars.MD5),
341}
342
343--- Get the MD5 checksum for a file.
344-- @param file string: The file to be computed.
345-- @return string: The MD5 checksum or nil + message
346function tools.get_md5(file)
347 local cmd = md5_cmd[cfg.md5checker]
348 if not cmd then return nil, "no MD5 checker command configured" end
349 local pipe = io.popen(cmd.." "..fs.Q(fs.absolute_name(file)))
350 local computed = pipe:read("*a")
351 pipe:close()
352 if computed then
353 computed = computed:match("("..("%x"):rep(32)..")")
354 end
355 if computed then return computed end
356 return nil, "Failed to compute MD5 hash for file "..tostring(fs.absolute_name(file))
357end
358
359--- Test for existance of a file. 217--- Test for existance of a file.
360-- @param file string: filename to test 218-- @param file string: filename to test
361-- @return boolean: true if file exists, false otherwise. 219-- @return boolean: true if file exists, false otherwise.
diff --git a/src/luarocks/install.lua b/src/luarocks/install.lua
index b6af43cc..e3ab6fac 100644
--- a/src/luarocks/install.lua
+++ b/src/luarocks/install.lua
@@ -98,15 +98,7 @@ function install.install_binary_rock(rock_file, deps_mode)
98 ok, err = manif.update_manifest(name, version, nil, deps_mode) 98 ok, err = manif.update_manifest(name, version, nil, deps_mode)
99 if err then return nil, err end 99 if err then return nil, err end
100 100
101 local license = "" 101 util.announce_install(rockspec)
102 if rockspec.description.license then
103 license = ("(license: "..rockspec.description.license..")")
104 end
105
106 local root_dir = path.root_dir(cfg.rocks_dir)
107 util.printout()
108 util.printout(name.." "..version.." is now installed in "..root_dir.." "..license)
109
110 util.remove_scheduled_function(rollback) 102 util.remove_scheduled_function(rollback)
111 return name, version 103 return name, version
112end 104end
@@ -168,7 +160,6 @@ function install.run(...)
168 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end 160 if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end
169 161
170 if name:match("%.rockspec$") or name:match("%.src%.rock$") then 162 if name:match("%.rockspec$") or name:match("%.src%.rock$") then
171 util.printout("Using "..name.."... switching to 'build' mode")
172 local build = require("luarocks.build") 163 local build = require("luarocks.build")
173 return build.run(name, util.forward_flags(flags, "local", "keep", "deps-mode", "only-deps", "force", "force-fast")) 164 return build.run(name, util.forward_flags(flags, "local", "keep", "deps-mode", "only-deps", "force", "force-fast"))
174 elseif name:match("%.rock$") then 165 elseif name:match("%.rock$") then
@@ -190,7 +181,7 @@ function install.run(...)
190 if not url then 181 if not url then
191 return nil, err 182 return nil, err
192 end 183 end
193 util.printout("Installing "..url.."...") 184 util.printout("Installing "..url)
194 return install.run(url, util.forward_flags(flags)) 185 return install.run(url, util.forward_flags(flags))
195 end 186 end
196end 187end
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua
index 05621315..bc202be3 100644
--- a/src/luarocks/manif.lua
+++ b/src/luarocks/manif.lua
@@ -432,8 +432,6 @@ function manif.update_manifest(name, version, repo, deps_mode)
432 432
433 if deps_mode == "none" then deps_mode = cfg.deps_mode end 433 if deps_mode == "none" then deps_mode = cfg.deps_mode end
434 434
435 util.printout("Updating manifest for "..repo)
436
437 local manifest, err = manif.load_manifest(repo) 435 local manifest, err = manif.load_manifest(repo)
438 if not manifest then 436 if not manifest then
439 util.printerr("No existing manifest. Attempting to rebuild...") 437 util.printerr("No existing manifest. Attempting to rebuild...")
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua
index 66b1377f..b6d5825a 100644
--- a/src/luarocks/repos.lua
+++ b/src/luarocks/repos.lua
@@ -157,11 +157,10 @@ local function install_binary(source, target, name, version)
157 assert(type(target) == "string") 157 assert(type(target) == "string")
158 158
159 if fs.is_lua(source) then 159 if fs.is_lua(source) then
160 repos.ok, repos.err = fs.wrap_script(source, target, name, version) 160 return fs.wrap_script(source, target, name, version)
161 else 161 else
162 repos.ok, repos.err = fs.copy_binary(source, target) 162 return fs.copy_binary(source, target)
163 end 163 end
164 return repos.ok, repos.err
165end 164end
166 165
167local function resolve_conflict(target, deploy_dir, name, version) 166local function resolve_conflict(target, deploy_dir, name, version)
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
index 80f1684a..520625c0 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -506,6 +506,20 @@ function util.see_help(command, program)
506 return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'." 506 return "See '"..util.this_program(program or "luarocks")..' help'..(command and " "..command or "").."'."
507end 507end
508 508
509function util.announce_install(rockspec)
510 local cfg = require("luarocks.cfg")
511 local path = require("luarocks.path")
512
513 local suffix = ""
514 if rockspec.description and rockspec.description.license then
515 suffix = " (license: "..rockspec.description.license..")"
516 end
517
518 local root_dir = path.root_dir(cfg.rocks_dir)
519 util.printout(rockspec.name.." "..rockspec.version.." is now installed in "..root_dir..suffix)
520 util.printout()
521end
522
509-- from http://lua-users.org/wiki/SplitJoin 523-- from http://lua-users.org/wiki/SplitJoin
510-- by PhilippeLhoste 524-- by PhilippeLhoste
511function util.split_string(str, delim, maxNb) 525function util.split_string(str, delim, maxNb)
diff --git a/src/luarocks/write_rockspec.lua b/src/luarocks/write_rockspec.lua
index 972562c3..abfca322 100644
--- a/src/luarocks/write_rockspec.lua
+++ b/src/luarocks/write_rockspec.lua
@@ -12,14 +12,16 @@ local type_check = require("luarocks.type_check")
12local util = require("luarocks.util") 12local util = require("luarocks.util")
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>]"
16write_rockspec.help = [[ 16write_rockspec.help = [[
17This command writes an initial version of a rockspec file, 17This command writes an initial version of a rockspec file,
18based on an URL or a local path. You may use a relative path such as '.'. 18based on a name, a version, and a location (an URL or a local path).
19If a local path is given, name and version arguments are mandatory. 19If only two arguments are given, the first one is considered the name and the
20For URLs, LuaRocks will attempt to infer name and version if not given. 20second one is the location.
21 21If only one argument is given, it must be the location.
22If a repository URL is given with no version, it creates an 'scm' rock. 22If no arguments are given, current directory is used as location.
23LuaRocks will attempt to infer name and version if not given,
24using 'scm' as default version.
23 25
24Note that the generated file is a _starting point_ for writing a 26Note that the generated file is a _starting point_ for writing a
25rockspec, and is not guaranteed to be complete or correct. 27rockspec, and is not guaranteed to be complete or correct.
@@ -198,18 +200,17 @@ end
198 200
199function write_rockspec.run(...) 201function write_rockspec.run(...)
200 local flags, name, version, url_or_dir = util.parse_flags(...) 202 local flags, name, version, url_or_dir = util.parse_flags(...)
201
202 if not name then
203 return nil, "Missing arguments. "..util.see_help("write_rockspec")
204 end
205 203
206 if name and not version then 204 if not name then
205 url_or_dir = "."
206 elseif not version then
207 url_or_dir = name 207 url_or_dir = name
208 name = nil 208 name = nil
209 elseif not url_or_dir then 209 elseif not url_or_dir then
210 url_or_dir = version 210 url_or_dir = version
211 version = nil
211 end 212 end
212 213
213 if flags["tag"] then 214 if flags["tag"] then
214 if not version then 215 if not version then
215 version = flags["tag"]:gsub("^v", "") 216 version = flags["tag"]:gsub("^v", "")
@@ -217,28 +218,25 @@ function write_rockspec.run(...)
217 end 218 end
218 219
219 local protocol, pathname = dir.split_url(url_or_dir) 220 local protocol, pathname = dir.split_url(url_or_dir)
220 if not fetch.is_basic_protocol(protocol) then 221 if protocol == "file" then
221 if not name then 222 if pathname == "." then
222 name = dir.base_name(url_or_dir):gsub("%.[^.]+$", "") 223 name = name or dir.base_name(fs.current_dir())
223 end 224 end
224 if not version then 225 elseif fetch.is_basic_protocol(protocol) then
225 version = "scm"
226 end
227 elseif protocol ~= "file" then
228 local filename = dir.base_name(url_or_dir) 226 local filename = dir.base_name(url_or_dir)
229 local newname, newversion = filename:match("(.*)-([^-]+)") 227 local newname, newversion = filename:match("(.*)-([^-]+)")
230 if (not name) and newname then 228 if newname then
231 name = newname 229 name = name or newname
232 end 230 version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "")
233 if (not version) and newversion then
234 version = newversion:gsub(".[a-z]+$", ""):gsub(".tar$", "")
235 end 231 end
236 if not (name and version) then 232 else
237 return nil, "Missing name and version arguments. "..util.see_help("write_rockspec") 233 name = name or dir.base_name(url_or_dir):gsub("%.[^.]+$", "")
238 end 234 end
239 elseif not version then 235
240 return nil, "Missing name and version arguments. "..util.see_help("write_rockspec") 236 if not name then
237 return nil, "Could not infer rock name. "..util.see_help("write_rockspec")
241 end 238 end
239 version = version or "scm"
242 240
243 local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") 241 local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec")
244 242
diff --git a/test/testing.lua b/test/testing.lua
index c37293ee..1a837484 100644
--- a/test/testing.lua
+++ b/test/testing.lua
@@ -459,6 +459,25 @@ local tests = {
459 and assert("lua-compat-5.2" == fetch.url_to_base_dir("https://github.com/hishamhm/lua-compat-5.2.tar.bz2")) 459 and assert("lua-compat-5.2" == fetch.url_to_base_dir("https://github.com/hishamhm/lua-compat-5.2.tar.bz2"))
460 and assert("parser.moon" == fetch.url_to_base_dir("git://github.com/Cirru/parser.moon")) 460 and assert("parser.moon" == fetch.url_to_base_dir("git://github.com/Cirru/parser.moon"))
461 and assert("v0.3" == fetch.url_to_base_dir("https://github.com/hishamhm/lua-compat-5.2/archive/v0.3")) 461 and assert("v0.3" == fetch.url_to_base_dir("https://github.com/hishamhm/lua-compat-5.2/archive/v0.3"))
462 end,
463
464 -- Tests for https://github.com/keplerproject/luarocks/issues/552
465 test_install_break_dependencies_warning = function()
466 need_luasocket()
467 return run "$luarocks install say ${new_version_say}"
468 and run "$luarocks install luassert"
469 and run "$luarocks install say ${old_version_say}"
470 end,
471 test_install_break_dependencies_force = function()
472 need_luasocket()
473 return run "$luarocks install say ${new_version_say}"
474 and run "$luarocks install luassert"
475 and run "$luarocks install --force say ${old_version_say}"
476 end,
477 test_install_break_dependencies_force = function()
478 need_luasocket()
479 return run "$luarocks install say ${new_version_say}"
480 and run "$luarocks install luassert"
481 and run "$luarocks install --force-fast say ${old_version_say}"
462 end 482 end
463
464} 483}
diff --git a/test/testing.sh b/test/testing.sh
index 5269e42a..f56f2aa9 100755
--- a/test/testing.sh
+++ b/test/testing.sh
@@ -179,6 +179,9 @@ srcdir_luasocket=luasocket-3.0-rc1
179version_cprint=0.1 179version_cprint=0.1
180verrev_cprint=0.1-2 180verrev_cprint=0.1-2
181 181
182new_version_say=1.2-1
183old_version_say=1.0-1
184
182version_luacov=0.11.0 185version_luacov=0.11.0
183verrev_luacov=${version_luacov}-1 186verrev_luacov=${version_luacov}-1
184version_lxsh=0.8.6 187version_lxsh=0.8.6
@@ -260,6 +263,9 @@ mkdir -p "$testing_server"
260 get "$luarocks_repo/lua-path-0.2.3-1.src.rock" 263 get "$luarocks_repo/lua-path-0.2.3-1.src.rock"
261 get "$luarocks_repo/lua-cjson-2.1.0-1.src.rock" 264 get "$luarocks_repo/lua-cjson-2.1.0-1.src.rock"
262 get "$luarocks_repo/luacov-coveralls-0.1.1-1.src.rock" 265 get "$luarocks_repo/luacov-coveralls-0.1.1-1.src.rock"
266 get "$luarocks_repo/say-1.2-1.src.rock"
267 get "$luarocks_repo/say-1.0-1.src.rock"
268 get "$luarocks_repo/luassert-1.7.0-1.src.rock"
263) 269)
264$luarocks_admin_nocov make_manifest "$testing_server" 270$luarocks_admin_nocov make_manifest "$testing_server"
265 271
@@ -358,7 +364,6 @@ fail_upload_noarg() { $luarocks upload; }
358fail_remove_noarg() { $luarocks remove; } 364fail_remove_noarg() { $luarocks remove; }
359fail_doc_noarg() { $luarocks doc; } 365fail_doc_noarg() { $luarocks doc; }
360fail_new_version_noarg() { $luarocks new_version; } 366fail_new_version_noarg() { $luarocks new_version; }
361fail_write_rockspec_noarg() { $luarocks write_rockspec; }
362 367
363fail_build_invalid() { $luarocks build invalid; } 368fail_build_invalid() { $luarocks build invalid; }
364fail_download_invalid() { $luarocks download invalid; } 369fail_download_invalid() { $luarocks download invalid; }
@@ -517,6 +522,9 @@ test_deps_mode_make_order() { $luarocks build --tree="$testing_sys_tree" lpeg &&
517test_deps_mode_make_order_sys() { $luarocks build --tree="$testing_tree" lpeg && rm -rf ./lxsh-${verrev_lxsh} && $luarocks download --source lxsh ${verrev_lxsh} && $luarocks unpack ./lxsh-${verrev_lxsh}.src.rock && cd lxsh-${verrev_lxsh}/lxsh-${version_lxsh}-1 && $luarocks make --tree="$testing_sys_tree" --deps-mode=order && cd ../.. && [ `$luarocks_noecho list --tree="$testing_tree" --porcelain lpeg | wc -l` = 1 ] && rm -rf ./lxsh-${verrev_lxsh}; } 522test_deps_mode_make_order_sys() { $luarocks build --tree="$testing_tree" lpeg && rm -rf ./lxsh-${verrev_lxsh} && $luarocks download --source lxsh ${verrev_lxsh} && $luarocks unpack ./lxsh-${verrev_lxsh}.src.rock && cd lxsh-${verrev_lxsh}/lxsh-${version_lxsh}-1 && $luarocks make --tree="$testing_sys_tree" --deps-mode=order && cd ../.. && [ `$luarocks_noecho list --tree="$testing_tree" --porcelain lpeg | wc -l` = 1 ] && rm -rf ./lxsh-${verrev_lxsh}; }
518 523
519test_write_rockspec() { $luarocks write_rockspec git://github.com/keplerproject/luarocks; } 524test_write_rockspec() { $luarocks write_rockspec git://github.com/keplerproject/luarocks; }
525test_write_rockspec_name() { $luarocks write_rockspec luarocks git://github.com/keplerproject/luarocks; }
526test_write_rockspec_name_version() { $luarocks write_rockspec luarocks 7.8.9 git://github.com/keplerproject/luarocks; }
527test_write_rockspec_current_dir() { $luarocks write_rockspec; }
520test_write_rockspec_tag() { $luarocks write_rockspec git://github.com/keplerproject/luarocks --tag=v2.3.0; } 528test_write_rockspec_tag() { $luarocks write_rockspec git://github.com/keplerproject/luarocks --tag=v2.3.0; }
521test_write_rockspec_lib() { $luarocks write_rockspec git://github.com/mbalmer/luafcgi --lib=fcgi --license="3-clause BSD" --lua-version=5.1,5.2; } 529test_write_rockspec_lib() { $luarocks write_rockspec git://github.com/mbalmer/luafcgi --lib=fcgi --license="3-clause BSD" --lua-version=5.1,5.2; }
522test_write_rockspec_format() { $luarocks write_rockspec git://github.com/keplerproject/luarocks --rockspec-format=1.1 --lua-version=5.1,5.2; } 530test_write_rockspec_format() { $luarocks write_rockspec git://github.com/keplerproject/luarocks --rockspec-format=1.1 --lua-version=5.1,5.2; }
@@ -558,8 +566,12 @@ test_doc_list() { $luarocks install luacov; $luarocks doc luacov --list; }
558test_doc_local() { $luarocks install luacov; $luarocks doc luacov --local; } 566test_doc_local() { $luarocks install luacov; $luarocks doc luacov --local; }
559test_doc_porcelain() { $luarocks install luacov; $luarocks doc luacov --porcelain; } 567test_doc_porcelain() { $luarocks install luacov; $luarocks doc luacov --porcelain; }
560 568
561# Driver ######################################### 569# Tests for https://github.com/keplerproject/luarocks/pull/552
570test_install_break_dependencies_warning() { need_luasocket; $luarocks install say ${new_version_say} && $luarocks install luassert && $luarocks install say ${old_version_say}; }
571test_install_break_dependencies_force() { need_luasocket; $luarocks install say ${new_version_say} && $luarocks install luassert && $luarocks install --force say ${old_version_say}; }
572test_install_break_dependencies_forcefast() { need_luasocket; $luarocks install say ${new_version_say} && $luarocks install luassert && $luarocks install --force-fast say ${old_version_say}; }
562 573
574# Driver #########################################
563run_tests() { 575run_tests() {
564 grep "^test_$1.*(" < $testing_dir/testing.sh | cut -d'(' -f1 | while read test 576 grep "^test_$1.*(" < $testing_dir/testing.sh | cut -d'(' -f1 | while read test
565 do 577 do