diff options
-rw-r--r-- | src/luarocks/cfg.lua | 2 | ||||
-rw-r--r-- | src/luarocks/fetch.lua | 8 | ||||
-rw-r--r-- | src/luarocks/fs/lua.lua | 58 | ||||
-rw-r--r-- | src/luarocks/fs/unix/tools.lua | 30 | ||||
-rw-r--r-- | src/luarocks/fs/win32/tools.lua | 31 | ||||
-rw-r--r-- | src/luarocks/manif.lua | 7 | ||||
-rw-r--r-- | src/luarocks/repos.lua | 46 |
7 files changed, 132 insertions, 50 deletions
diff --git a/src/luarocks/cfg.lua b/src/luarocks/cfg.lua index 94afe0a0..019d9293 100644 --- a/src/luarocks/cfg.lua +++ b/src/luarocks/cfg.lua | |||
@@ -315,6 +315,7 @@ if detected.windows then | |||
315 | defaults.export_path_separator = ";" | 315 | defaults.export_path_separator = ";" |
316 | defaults.export_lua_path = "SET LUA_PATH=%s" | 316 | defaults.export_lua_path = "SET LUA_PATH=%s" |
317 | defaults.export_lua_cpath = "SET LUA_CPATH=%s" | 317 | defaults.export_lua_cpath = "SET LUA_CPATH=%s" |
318 | defaults.wrapper_suffix = ".bat" | ||
318 | defaults.local_cache = home.."/cache/luarocks" | 319 | defaults.local_cache = home.."/cache/luarocks" |
319 | end | 320 | end |
320 | 321 | ||
@@ -372,6 +373,7 @@ if detected.unix then | |||
372 | defaults.export_path_separator = ":" | 373 | defaults.export_path_separator = ":" |
373 | defaults.export_lua_path = "export LUA_PATH='%s'" | 374 | defaults.export_lua_path = "export LUA_PATH='%s'" |
374 | defaults.export_lua_cpath = "export LUA_CPATH='%s'" | 375 | defaults.export_lua_cpath = "export LUA_CPATH='%s'" |
376 | defaults.wrapper_suffix = "" | ||
375 | defaults.local_cache = home.."/.cache/luarocks" | 377 | defaults.local_cache = home.."/.cache/luarocks" |
376 | if not defaults.variables.CFLAGS:match("-fPIC") then | 378 | if not defaults.variables.CFLAGS:match("-fPIC") then |
377 | defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC" | 379 | defaults.variables.CFLAGS = defaults.variables.CFLAGS.." -fPIC" |
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua index 3ba90647..e98d9cc2 100644 --- a/src/luarocks/fetch.lua +++ b/src/luarocks/fetch.lua | |||
@@ -27,7 +27,7 @@ end | |||
27 | -- @return string or (nil, string, [string]): the absolute local pathname for the | 27 | -- @return string or (nil, string, [string]): the absolute local pathname for the |
28 | -- fetched file, or nil and a message in case of errors, followed by | 28 | -- fetched file, or nil and a message in case of errors, followed by |
29 | -- an optional error code. | 29 | -- an optional error code. |
30 | function fetch_url(url, filename) | 30 | function fetch_url(url, filename, cache) |
31 | assert(type(url) == "string") | 31 | assert(type(url) == "string") |
32 | assert(type(filename) == "string" or not filename) | 32 | assert(type(filename) == "string" or not filename) |
33 | 33 | ||
@@ -35,11 +35,11 @@ function fetch_url(url, filename) | |||
35 | if protocol == "file" then | 35 | if protocol == "file" then |
36 | return fs.absolute_name(pathname) | 36 | return fs.absolute_name(pathname) |
37 | elseif is_basic_protocol(protocol, true) then | 37 | elseif is_basic_protocol(protocol, true) then |
38 | local ok, err = fs.download(url, filename) | 38 | local ok, filename = fs.download(url, filename, cache) |
39 | if not ok then | 39 | if not ok then |
40 | return nil, "Failed downloading "..url..(err and " - "..err or ""), "network" | 40 | return nil, "Failed downloading "..url..(filename and " - "..filename or ""), "network" |
41 | end | 41 | end |
42 | return dir.path(fs.current_dir(), filename or dir.base_name(url)) | 42 | return filename |
43 | else | 43 | else |
44 | return nil, "Unsupported protocol "..protocol | 44 | return nil, "Unsupported protocol "..protocol |
45 | end | 45 | end |
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua index 707b82bd..e637f6be 100644 --- a/src/luarocks/fs/lua.lua +++ b/src/luarocks/fs/lua.lua | |||
@@ -190,7 +190,7 @@ function pop_dir() | |||
190 | end | 190 | end |
191 | 191 | ||
192 | --- Create a directory if it does not already exist. | 192 | --- Create a directory if it does not already exist. |
193 | -- If any of the higher levels in the path name does not exist | 193 | -- If any of the higher levels in the path name do not exist |
194 | -- too, they are created as well. | 194 | -- too, they are created as well. |
195 | -- @param directory string: pathname of directory to create. | 195 | -- @param directory string: pathname of directory to create. |
196 | -- @return boolean or (boolean, string): true on success or (false, error message) on failure. | 196 | -- @return boolean or (boolean, string): true on success or (false, error message) on failure. |
@@ -506,7 +506,7 @@ local redirect_protocols = { | |||
506 | https = luasec_ok and https, | 506 | https = luasec_ok and https, |
507 | } | 507 | } |
508 | 508 | ||
509 | local function http_request(url, http, loop_control) | 509 | local function request(url, method, http, loop_control) |
510 | local result = {} | 510 | local result = {} |
511 | 511 | ||
512 | local proxy = cfg.proxy | 512 | local proxy = cfg.proxy |
@@ -516,14 +516,17 @@ local function http_request(url, http, loop_control) | |||
516 | proxy = "http://" .. proxy | 516 | proxy = "http://" .. proxy |
517 | end | 517 | end |
518 | 518 | ||
519 | io.write("Downloading "..url.." ...\n") | 519 | if cfg.show_downloads then |
520 | io.write(method.." "..url.." ...\n") | ||
521 | end | ||
520 | local dots = 0 | 522 | local dots = 0 |
521 | local res, status, headers, err = http.request { | 523 | local res, status, headers, err = http.request { |
522 | url = url, | 524 | url = url, |
523 | proxy = proxy, | 525 | proxy = proxy, |
526 | method = method, | ||
524 | redirect = false, | 527 | redirect = false, |
525 | sink = ltn12.sink.table(result), | 528 | sink = ltn12.sink.table(result), |
526 | step = function(...) | 529 | step = cfg.show_downloads and function(...) |
527 | io.write(".") | 530 | io.write(".") |
528 | io.flush() | 531 | io.flush() |
529 | dots = dots + 1 | 532 | dots = dots + 1 |
@@ -537,7 +540,9 @@ local function http_request(url, http, loop_control) | |||
537 | ["user-agent"] = cfg.user_agent.." via LuaSocket" | 540 | ["user-agent"] = cfg.user_agent.." via LuaSocket" |
538 | }, | 541 | }, |
539 | } | 542 | } |
540 | io.write("\n") | 543 | if cfg.show_downloads then |
544 | io.write("\n") | ||
545 | end | ||
541 | if not res then | 546 | if not res then |
542 | return nil, status | 547 | return nil, status |
543 | elseif status == 301 or status == 302 then | 548 | elseif status == 301 or status == 302 then |
@@ -551,7 +556,7 @@ local function http_request(url, http, loop_control) | |||
551 | return nil, "Redirection loop -- broken URL?" | 556 | return nil, "Redirection loop -- broken URL?" |
552 | end | 557 | end |
553 | loop_control[url] = true | 558 | loop_control[url] = true |
554 | return http_request(location, redirect_protocols[protocol], loop_control) | 559 | return request(location, method, redirect_protocols[protocol], loop_control) |
555 | else | 560 | else |
556 | return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support." | 561 | return nil, "URL redirected to unsupported protocol - install luasec to get HTTPS support." |
557 | end | 562 | end |
@@ -560,7 +565,32 @@ local function http_request(url, http, loop_control) | |||
560 | elseif status ~= 200 then | 565 | elseif status ~= 200 then |
561 | return nil, err | 566 | return nil, err |
562 | else | 567 | else |
568 | return result, status, headers, err | ||
569 | end | ||
570 | end | ||
571 | |||
572 | local function http_request(url, http, cached) | ||
573 | if cached then | ||
574 | local tsfd = io.open(cached..".timestamp", "r") | ||
575 | if tsfd then | ||
576 | local timestamp = tsfd:read("*a") | ||
577 | tsfd:close() | ||
578 | local result, status, headers, err = request(url, "HEAD", http) | ||
579 | if status == 200 and headers["last-modified"] == timestamp then | ||
580 | return true | ||
581 | end | ||
582 | end | ||
583 | end | ||
584 | local result, status, headers, err = request(url, "GET", http) | ||
585 | if result then | ||
586 | if cached and headers["last-modified"] then | ||
587 | local tsfd = io.open(cached..".timestamp", "w") | ||
588 | tsfd:write(headers["last-modified"]) | ||
589 | tsfd:close() | ||
590 | end | ||
563 | return table.concat(result) | 591 | return table.concat(result) |
592 | else | ||
593 | return nil, status | ||
564 | end | 594 | end |
565 | end | 595 | end |
566 | 596 | ||
@@ -570,27 +600,31 @@ end | |||
570 | -- resulting local filename of the remote file as the basename of the URL; | 600 | -- resulting local filename of the remote file as the basename of the URL; |
571 | -- if that is not correct (due to a redirection, for example), the local | 601 | -- if that is not correct (due to a redirection, for example), the local |
572 | -- filename can be given explicitly as this second argument. | 602 | -- filename can be given explicitly as this second argument. |
573 | -- @return boolean: true on success, false on failure. | 603 | -- @return (boolean, string): true and the filename on success, |
574 | function download(url, filename) | 604 | -- false and the error message on failure. |
605 | function download(url, filename, cache) | ||
575 | assert(type(url) == "string") | 606 | assert(type(url) == "string") |
576 | assert(type(filename) == "string" or not filename) | 607 | assert(type(filename) == "string" or not filename) |
577 | 608 | ||
578 | filename = dir.path(fs.current_dir(), filename or dir.base_name(url)) | 609 | filename = fs.absolute_name(filename or dir.base_name(url)) |
579 | 610 | ||
580 | local content, err | 611 | local content, err |
581 | if util.starts_with(url, "http:") then | 612 | if util.starts_with(url, "http:") then |
582 | content, err = http_request(url, http) | 613 | content, err = http_request(url, http, cache and filename) |
583 | elseif util.starts_with(url, "ftp:") then | 614 | elseif util.starts_with(url, "ftp:") then |
584 | content, err = ftp.get(url) | 615 | content, err = ftp.get(url) |
585 | elseif util.starts_with(url, "https:") then | 616 | elseif util.starts_with(url, "https:") then |
586 | if luasec_ok then | 617 | if luasec_ok then |
587 | content, err = http_request(url, https) | 618 | content, err = http_request(url, https, cache and filename) |
588 | else | 619 | else |
589 | err = "Unsupported protocol - install luasec to get HTTPS support." | 620 | err = "Unsupported protocol - install luasec to get HTTPS support." |
590 | end | 621 | end |
591 | else | 622 | else |
592 | err = "Unsupported protocol" | 623 | err = "Unsupported protocol" |
593 | end | 624 | end |
625 | if cache and content == true then | ||
626 | return true, filename | ||
627 | end | ||
594 | if not content then | 628 | if not content then |
595 | return false, tostring(err) | 629 | return false, tostring(err) |
596 | end | 630 | end |
@@ -598,7 +632,7 @@ function download(url, filename) | |||
598 | if not file then return false end | 632 | if not file then return false end |
599 | file:write(content) | 633 | file:write(content) |
600 | file:close() | 634 | file:close() |
601 | return true | 635 | return true, filename |
602 | end | 636 | end |
603 | 637 | ||
604 | end | 638 | end |
diff --git a/src/luarocks/fs/unix/tools.lua b/src/luarocks/fs/unix/tools.lua index 1b2931e9..2dfca715 100644 --- a/src/luarocks/fs/unix/tools.lua +++ b/src/luarocks/fs/unix/tools.lua | |||
@@ -239,21 +239,35 @@ end | |||
239 | -- resulting local filename of the remote file as the basename of the URL; | 239 | -- resulting local filename of the remote file as the basename of the URL; |
240 | -- if that is not correct (due to a redirection, for example), the local | 240 | -- if that is not correct (due to a redirection, for example), the local |
241 | -- filename can be given explicitly as this second argument. | 241 | -- filename can be given explicitly as this second argument. |
242 | -- @return boolean: true on success, false on failure. | 242 | -- @return (boolean, string): true and the filename on success, |
243 | function download(url, filename) | 243 | -- false and the error message on failure. |
244 | function download(url, filename, cache) | ||
244 | assert(type(url) == "string") | 245 | assert(type(url) == "string") |
245 | assert(type(filename) == "string" or not filename) | 246 | assert(type(filename) == "string" or not filename) |
246 | 247 | ||
248 | filename = fs.absolute_name(filename or dir.base_name(url)) | ||
249 | |||
250 | local ok | ||
247 | if cfg.downloader == "wget" then | 251 | if cfg.downloader == "wget" then |
248 | local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet --continue " | 252 | local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent='"..cfg.user_agent.." via wget' --quiet " |
249 | if filename then | 253 | if cache then |
250 | return fs.execute(wget_cmd.." --output-document ", filename, url) | 254 | -- --timestamping is incompatible with --output-document, |
255 | -- but that's not a problem for our use cases. | ||
256 | fs.change_dir(dir.dir_name(filename)) | ||
257 | ok = fs.execute(wget_cmd.." --timestamping ", url) | ||
258 | fs.pop_dir() | ||
259 | elseif filename then | ||
260 | ok = fs.execute(wget_cmd.." --output-document "..fs.Q(filename), url) | ||
251 | else | 261 | else |
252 | return fs.execute(wget_cmd, url) | 262 | ok = fs.execute(wget_cmd, url) |
253 | end | 263 | end |
254 | elseif cfg.downloader == "curl" then | 264 | elseif cfg.downloader == "curl" then |
255 | filename = filename or dir.base_name(url) | 265 | ok = fs.execute_string(vars.CURL.." -L --user-agent '"..cfg.user_agent.." via curl' "..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename)) |
256 | return fs.execute_string(vars.CURL.." -L --user-agent '"..cfg.user_agent.." via curl' "..fs.Q(url).." 2> /dev/null 1> "..fs.Q(filename)) | 266 | end |
267 | if ok then | ||
268 | return true, filename | ||
269 | else | ||
270 | return false | ||
257 | end | 271 | end |
258 | end | 272 | end |
259 | 273 | ||
diff --git a/src/luarocks/fs/win32/tools.lua b/src/luarocks/fs/win32/tools.lua index 2e125923..a79421b6 100644 --- a/src/luarocks/fs/win32/tools.lua +++ b/src/luarocks/fs/win32/tools.lua | |||
@@ -262,22 +262,35 @@ end | |||
262 | -- resulting local filename of the remote file as the basename of the URL; | 262 | -- resulting local filename of the remote file as the basename of the URL; |
263 | -- if that is not correct (due to a redirection, for example), the local | 263 | -- if that is not correct (due to a redirection, for example), the local |
264 | -- filename can be given explicitly as this second argument. | 264 | -- filename can be given explicitly as this second argument. |
265 | -- @return boolean: true on success, false on failure. | 265 | -- @return (boolean, string): true and the filename on success, |
266 | function download(url, filename) | 266 | -- false and the error message on failure. |
267 | function download(url, filename, cache) | ||
267 | assert(type(url) == "string") | 268 | assert(type(url) == "string") |
268 | assert(type(filename) == "string" or not filename) | 269 | assert(type(filename) == "string" or not filename) |
269 | 270 | ||
271 | filename = fs.absolute_name(filename or dir.base_name(url)) | ||
272 | |||
273 | local ok | ||
270 | if cfg.downloader == "wget" then | 274 | if cfg.downloader == "wget" then |
271 | local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet --continue " | 275 | local wget_cmd = vars.WGET.." --no-check-certificate --no-cache --user-agent=\""..cfg.user_agent.." via wget\" --quiet " |
272 | if filename then | 276 | if cache then |
273 | wget_cmd = wget_cmd.." --output-document "..fs.Q(filename).." "..fs.Q(url) | 277 | -- --timestamping is incompatible with --output-document, |
278 | -- but that's not a problem for our use cases. | ||
279 | fs.change_dir(dir.dir_name(filename)) | ||
280 | ok = fs.execute(wget_cmd.." --timestamping "..fs.Q(url).." 2> NUL 1> NUL") | ||
281 | fs.pop_dir() | ||
282 | elseif filename then | ||
283 | ok = fs.execute(wget_cmd.." --output-document "..fs.Q(filename)..fs.Q(url).." 2> NUL 1> NUL") | ||
274 | else | 284 | else |
275 | wget_cmd = wget_cmd.." "..fs.Q(url) | 285 | ok = fs.execute(wget_cmd..fs.Q(url).." 2> NUL 1> NUL") |
276 | end | 286 | end |
277 | return fs.execute(wget_cmd.." 2> NUL 1> NUL") | ||
278 | elseif cfg.downloader == "curl" then | 287 | elseif cfg.downloader == "curl" then |
279 | filename = filename or dir.base_name(url) | 288 | ok = fs.execute_string(vars.CURL.." -L --user-agent \""..cfg.user_agent.." via curl\" "..fs.Q(url).." 2> NUL 1> "..fs.Q(filename)) |
280 | return fs.execute_string(vars.CURL.." -L --user-agent \""..cfg.user_agent.." via curl\" "..fs.Q(url).." 2> NUL 1> "..fs.Q(filename)) | 289 | end |
290 | if ok then | ||
291 | return true, filename | ||
292 | else | ||
293 | return false | ||
281 | end | 294 | end |
282 | end | 295 | end |
283 | 296 | ||
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua index 03377d52..9feb35ce 100644 --- a/src/luarocks/manif.lua +++ b/src/luarocks/manif.lua | |||
@@ -84,7 +84,12 @@ end | |||
84 | local function fetch_manifest_from(repo_url, filename) | 84 | local function fetch_manifest_from(repo_url, filename) |
85 | local url = dir.path(repo_url, filename) | 85 | local url = dir.path(repo_url, filename) |
86 | local name = repo_url:gsub("[/:]","_") | 86 | local name = repo_url:gsub("[/:]","_") |
87 | local file, err, errcode = fetch.fetch_url_at_temp_dir(url, "luarocks-manifest-"..name) | 87 | local cache_dir = dir.path(cfg.local_cache, name) |
88 | local ok = fs.make_dir(cache_dir) | ||
89 | if not ok then | ||
90 | return nil, "Failed creating temporary cache directory "..cache_dir | ||
91 | end | ||
92 | local file, err, errcode = fetch.fetch_url(url, dir.path(cache_dir, filename), true) | ||
88 | if not file then | 93 | if not file then |
89 | return nil, "Failed fetching manifest for "..repo_url..(err and " - "..err or ""), errcode | 94 | return nil, "Failed fetching manifest for "..repo_url..(err and " - "..err or ""), errcode |
90 | end | 95 | end |
diff --git a/src/luarocks/repos.lua b/src/luarocks/repos.lua index 08810015..86e82ec9 100644 --- a/src/luarocks/repos.lua +++ b/src/luarocks/repos.lua | |||
@@ -252,6 +252,20 @@ function deploy_files(name, version, wrap_bin_scripts) | |||
252 | return ok, err | 252 | return ok, err |
253 | end | 253 | end |
254 | 254 | ||
255 | local function delete_suffixed(filename, suffix) | ||
256 | local filenames = { filename } | ||
257 | if suffix and suffix ~= "" then filenames = { filename..suffix, filename } end | ||
258 | for _, name in ipairs(filenames) do | ||
259 | local ok, err = fs.delete(name) | ||
260 | if ok then | ||
261 | return true, name | ||
262 | elseif fs.exists(name) then | ||
263 | return nil, "Failed deleting "..name, "fail" | ||
264 | end | ||
265 | end | ||
266 | return false, "File not found", "not found" | ||
267 | end | ||
268 | |||
255 | --- Delete a package from the local repository. | 269 | --- Delete a package from the local repository. |
256 | -- Version numbers are compared as exact string comparison. | 270 | -- Version numbers are compared as exact string comparison. |
257 | -- @param name string: name of package | 271 | -- @param name string: name of package |
@@ -264,28 +278,28 @@ function delete_version(name, version, quick) | |||
264 | assert(type(name) == "string") | 278 | assert(type(name) == "string") |
265 | assert(type(version) == "string") | 279 | assert(type(version) == "string") |
266 | 280 | ||
267 | local function delete_deployed_file_tree(file_tree, deploy_dir) | 281 | local function delete_deployed_file_tree(file_tree, deploy_dir, suffix) |
268 | return recurse_rock_manifest_tree(file_tree, | 282 | return recurse_rock_manifest_tree(file_tree, |
269 | function(parent_path, parent_module, file) | 283 | function(parent_path, parent_module, file) |
270 | local target = dir.path(deploy_dir, parent_path, file) | 284 | local target = dir.path(deploy_dir, parent_path, file) |
271 | local versioned = path.versioned_name(target, deploy_dir, name, version) | 285 | local versioned = path.versioned_name(target, deploy_dir, name, version) |
272 | if fs.exists(versioned) then | 286 | local ok, name, err = delete_suffixed(versioned, suffix) |
273 | local ok = fs.delete(versioned) | 287 | if ok then |
274 | fs.remove_dir_tree_if_empty(dir.dir_name(versioned)) | 288 | fs.remove_dir_tree_if_empty(dir.dir_name(versioned)) |
275 | if not ok then return nil, "Failed deleting "..versioned end | 289 | return true |
276 | else | 290 | end |
277 | local ok = fs.delete(target) | 291 | if err == "fail" then return nil, name end |
278 | if not quick then | 292 | ok, name, err = delete_suffixed(target, suffix) |
279 | local next_name, next_version = manif.find_next_provider(target) | 293 | if err == "fail" then return nil, name end |
280 | if next_name then | 294 | if not quick then |
281 | local versioned = path.versioned_name(target, deploy_dir, next_name, next_version) | 295 | local next_name, next_version = manif.find_next_provider(target) |
282 | fs.move(versioned, target) | 296 | if next_name then |
283 | fs.remove_dir_tree_if_empty(dir.dir_name(versioned)) | 297 | local versioned = path.versioned_name(name, deploy_dir, next_name, next_version) |
284 | end | 298 | fs.move(versioned, name) |
299 | fs.remove_dir_tree_if_empty(dir.dir_name(versioned)) | ||
285 | end | 300 | end |
286 | fs.remove_dir_tree_if_empty(dir.dir_name(target)) | ||
287 | if not ok then return nil, "Failed deleting "..target end | ||
288 | end | 301 | end |
302 | fs.remove_dir_tree_if_empty(dir.dir_name(target)) | ||
289 | return true | 303 | return true |
290 | end | 304 | end |
291 | ) | 305 | ) |
@@ -298,7 +312,7 @@ function delete_version(name, version, quick) | |||
298 | 312 | ||
299 | local ok, err = true | 313 | local ok, err = true |
300 | if rock_manifest.bin then | 314 | if rock_manifest.bin then |
301 | ok, err = delete_deployed_file_tree(rock_manifest.bin, cfg.deploy_bin_dir) | 315 | ok, err = delete_deployed_file_tree(rock_manifest.bin, cfg.deploy_bin_dir, cfg.wrapper_suffix) |
302 | end | 316 | end |
303 | if ok and rock_manifest.lua then | 317 | if ok and rock_manifest.lua then |
304 | ok, err = delete_deployed_file_tree(rock_manifest.lua, cfg.deploy_lua_dir) | 318 | ok, err = delete_deployed_file_tree(rock_manifest.lua, cfg.deploy_lua_dir) |