aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2021-04-13 16:52:15 -0300
committerHisham Muhammad <hisham@gobolinux.org>2021-04-13 18:51:26 -0300
commitff58301bd9755f8e86e35dbc16d925b1fc65105a (patch)
tree781335ed3fa8a66f02c8c66276e5fa7086ee3fea
parenta07bc4c9e0be86b4edee78b9a7ef924eb9e2faaf (diff)
downloadluarocks-ff58301bd9755f8e86e35dbc16d925b1fc65105a.tar.gz
luarocks-ff58301bd9755f8e86e35dbc16d925b1fc65105a.tar.bz2
luarocks-ff58301bd9755f8e86e35dbc16d925b1fc65105a.zip
use mirrors when downloading rocks even if manifest succeeds
LuaRocks generally only checked whether to use a mirror in the first operation, when it fetches the manifest. If the manifest fails to load, it switches to the mirror and everything works from there. But if the manifest fetches ok and the then actual rock download fails with a 504, it gives up, instead of trying that in a mirror as well. Changing that to make it retry every download on a mirror when the base URL matches one configured in cfg.rocks_servers should make it much more resilient. Fixes #1299.
-rw-r--r--src/luarocks/fetch.lua76
-rw-r--r--src/luarocks/manif.lua2
2 files changed, 73 insertions, 5 deletions
diff --git a/src/luarocks/fetch.lua b/src/luarocks/fetch.lua
index 1882c348..c7f2d549 100644
--- a/src/luarocks/fetch.lua
+++ b/src/luarocks/fetch.lua
@@ -10,7 +10,25 @@ local persist = require("luarocks.persist")
10local util = require("luarocks.util") 10local util = require("luarocks.util")
11local cfg = require("luarocks.core.cfg") 11local cfg = require("luarocks.core.cfg")
12 12
13function fetch.fetch_caching(url) 13
14--- Fetch a local or remote file, using a local cache directory.
15-- Make a remote or local URL/pathname local, fetching the file if necessary.
16-- Other "fetch" and "load" functions use this function to obtain files.
17-- If a local pathname is given, it is returned as a result.
18-- @param url string: a local pathname or a remote URL.
19-- @param mirroring string: mirroring mode.
20-- If set to "no_mirror", then rocks_servers mirror configuration is not used.
21-- @return (string, nil, nil, boolean) or (nil, string, [string]):
22-- in case of success:
23-- * the absolute local pathname for the fetched file
24-- * nil
25-- * nil
26-- * `true` if the file was fetched from cache
27-- in case of failure:
28-- * nil
29-- * an error message
30-- * an optional error code.
31function fetch.fetch_caching(url, mirroring)
14 local repo_url, filename = url:match("^(.*)/([^/]+)$") 32 local repo_url, filename = url:match("^(.*)/([^/]+)$")
15 local name = repo_url:gsub("[/:]","_") 33 local name = repo_url:gsub("[/:]","_")
16 local cache_dir = dir.path(cfg.local_cache, name) 34 local cache_dir = dir.path(cfg.local_cache, name)
@@ -29,13 +47,56 @@ function fetch.fetch_caching(url)
29 return cachefile, nil, nil, true 47 return cachefile, nil, nil, true
30 end 48 end
31 49
32 local file, err, errcode, from_cache = fetch.fetch_url(url, cachefile, true) 50 local file, err, errcode, from_cache = fetch.fetch_url(url, cachefile, true, mirroring)
33 if not file then 51 if not file then
34 return nil, err or "Failed downloading "..url, errcode 52 return nil, err or "Failed downloading "..url, errcode
35 end 53 end
36 return file, nil, nil, from_cache 54 return file, nil, nil, from_cache
37end 55end
38 56
57local function ensure_trailing_slash(url)
58 return (url:gsub("/*$", "/"))
59end
60
61local function is_url_relative_to_rocks_servers(url, servers)
62 for _, item in ipairs(servers) do
63 if type(item) == "table" then
64 for i, s in ipairs(item) do
65 local base = ensure_trailing_slash(s)
66 if string.find(url, base, 1, true) == 1 then
67 return i, url:sub(#base + 1), item
68 end
69 end
70 end
71 end
72end
73
74local function download_with_mirrors(url, filename, cache, servers)
75 local idx, rest, mirrors = is_url_relative_to_rocks_servers(url, servers)
76
77 if not idx then
78 -- URL is not from a rock server
79 return fs.download(url, filename, cache)
80 end
81
82 -- URL is from a rock server: try to download it falling back to mirrors.
83 local err = "\n"
84 for i = idx, #mirrors do
85 local try_url = ensure_trailing_slash(mirrors[i]) .. rest
86 if i > idx then
87 util.warning("Failed downloading. Attempting mirror at " .. try_url)
88 end
89 local ok, name, from_cache = fs.download(try_url, filename, cache)
90 if ok then
91 return ok, name, from_cache
92 else
93 err = err .. name .. "\n"
94 end
95 end
96
97 return nil, err
98end
99
39--- Fetch a local or remote file. 100--- Fetch a local or remote file.
40-- Make a remote or local URL/pathname local, fetching the file if necessary. 101-- Make a remote or local URL/pathname local, fetching the file if necessary.
41-- Other "fetch" and "load" functions use this function to obtain files. 102-- Other "fetch" and "load" functions use this function to obtain files.
@@ -47,6 +108,8 @@ end
47-- filename can be given explicitly as this second argument. 108-- filename can be given explicitly as this second argument.
48-- @param cache boolean: compare remote timestamps via HTTP HEAD prior to 109-- @param cache boolean: compare remote timestamps via HTTP HEAD prior to
49-- re-downloading the file. 110-- re-downloading the file.
111-- @param mirroring string: mirroring mode.
112-- If set to "no_mirror", then rocks_servers mirror configuration is not used.
50-- @return (string, nil, nil, boolean) or (nil, string, [string]): 113-- @return (string, nil, nil, boolean) or (nil, string, [string]):
51-- in case of success: 114-- in case of success:
52-- * the absolute local pathname for the fetched file 115-- * the absolute local pathname for the fetched file
@@ -57,7 +120,7 @@ end
57-- * nil 120-- * nil
58-- * an error message 121-- * an error message
59-- * an optional error code. 122-- * an optional error code.
60function fetch.fetch_url(url, filename, cache) 123function fetch.fetch_url(url, filename, cache, mirroring)
61 assert(type(url) == "string") 124 assert(type(url) == "string")
62 assert(type(filename) == "string" or not filename) 125 assert(type(filename) == "string" or not filename)
63 126
@@ -84,7 +147,12 @@ function fetch.fetch_url(url, filename, cache)
84 return nil, "Failed copying local file " .. fullname .. " to " .. dstname .. ": " .. err 147 return nil, "Failed copying local file " .. fullname .. " to " .. dstname .. ": " .. err
85 end 148 end
86 elseif dir.is_basic_protocol(protocol) then 149 elseif dir.is_basic_protocol(protocol) then
87 local ok, name, from_cache = fs.download(url, filename, cache) 150 local ok, name, from_cache
151 if mirroring ~= "no_mirror" then
152 ok, name, from_cache = download_with_mirrors(url, filename, cache, cfg.rocks_servers)
153 else
154 ok, name, from_cache = fs.download(url, filename, cache)
155 end
88 if not ok then 156 if not ok then
89 return nil, "Failed downloading "..url..(name and " - "..name or ""), "network" 157 return nil, "Failed downloading "..url..(name and " - "..name or ""), "network"
90 end 158 end
diff --git a/src/luarocks/manif.lua b/src/luarocks/manif.lua
index 5790ef18..a4ddda11 100644
--- a/src/luarocks/manif.lua
+++ b/src/luarocks/manif.lua
@@ -105,7 +105,7 @@ function manif.load_manifest(repo_url, lua_version, versioned_only)
105 else 105 else
106 local err, errcode 106 local err, errcode
107 for _, filename in ipairs(filenames) do 107 for _, filename in ipairs(filenames) do
108 pathname, err, errcode, from_cache = fetch.fetch_caching(dir.path(repo_url, filename)) 108 pathname, err, errcode, from_cache = fetch.fetch_caching(dir.path(repo_url, filename), "no_mirror")
109 if pathname then 109 if pathname then
110 break 110 break
111 end 111 end