diff options
author | Hisham Muhammad <hisham@gobolinux.org> | 2021-04-13 16:52:15 -0300 |
---|---|---|
committer | Hisham Muhammad <hisham@gobolinux.org> | 2021-04-13 18:51:26 -0300 |
commit | ff58301bd9755f8e86e35dbc16d925b1fc65105a (patch) | |
tree | 781335ed3fa8a66f02c8c66276e5fa7086ee3fea | |
parent | a07bc4c9e0be86b4edee78b9a7ef924eb9e2faaf (diff) | |
download | luarocks-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.lua | 76 | ||||
-rw-r--r-- | src/luarocks/manif.lua | 2 |
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") | |||
10 | local util = require("luarocks.util") | 10 | local util = require("luarocks.util") |
11 | local cfg = require("luarocks.core.cfg") | 11 | local cfg = require("luarocks.core.cfg") |
12 | 12 | ||
13 | function 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. | ||
31 | function 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 |
37 | end | 55 | end |
38 | 56 | ||
57 | local function ensure_trailing_slash(url) | ||
58 | return (url:gsub("/*$", "/")) | ||
59 | end | ||
60 | |||
61 | local 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 | ||
72 | end | ||
73 | |||
74 | local 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 | ||
98 | end | ||
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. |
60 | function fetch.fetch_url(url, filename, cache) | 123 | function 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 |