Mercurial > repo
comparison share/lua/5.2/luarocks/fetch.lua @ 1132:d137f631bad5
<GreyKnight> (cd luabuild/luarocks-2.0.12; make install)
author | HackBot |
---|---|
date | Fri, 14 Dec 2012 22:24:27 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1131:ff65dfb63263 | 1132:d137f631bad5 |
---|---|
1 | |
2 --- Functions related to fetching and loading local and remote files. | |
3 module("luarocks.fetch", package.seeall) | |
4 | |
5 local fs = require("luarocks.fs") | |
6 local dir = require("luarocks.dir") | |
7 local type_check = require("luarocks.type_check") | |
8 local path = require("luarocks.path") | |
9 local deps = require("luarocks.deps") | |
10 local persist = require("luarocks.persist") | |
11 local util = require("luarocks.util") | |
12 local cfg = require("luarocks.cfg") | |
13 | |
14 --- Fetch a local or remote file. | |
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 filename string or nil: this function attempts to detect the | |
20 -- resulting local filename of the remote file as the basename of the URL; | |
21 -- if that is not correct (due to a redirection, for example), the local | |
22 -- filename can be given explicitly as this second argument. | |
23 -- @return string or (nil, string, [string]): the absolute local pathname for the | |
24 -- fetched file, or nil and a message in case of errors, followed by | |
25 -- an optional error code. | |
26 function fetch_url(url, filename) | |
27 assert(type(url) == "string") | |
28 assert(type(filename) == "string" or not filename) | |
29 | |
30 local protocol, pathname = dir.split_url(url) | |
31 if protocol == "file" then | |
32 return fs.absolute_name(pathname) | |
33 elseif protocol == "http" or protocol == "ftp" or protocol == "https" then | |
34 local ok, err = fs.download(url, filename) | |
35 if not ok then | |
36 return nil, "Failed downloading "..url..(err and " - "..err or ""), "network" | |
37 end | |
38 return dir.path(fs.current_dir(), filename or dir.base_name(url)) | |
39 else | |
40 return nil, "Unsupported protocol "..protocol | |
41 end | |
42 end | |
43 | |
44 --- For remote URLs, create a temporary directory and download URL inside it. | |
45 -- This temporary directory will be deleted on program termination. | |
46 -- For local URLs, just return the local pathname and its directory. | |
47 -- @param url string: URL to be downloaded | |
48 -- @param tmpname string: name pattern to use for avoiding conflicts | |
49 -- when creating temporary directory. | |
50 -- @param filename string or nil: local filename of URL to be downloaded, | |
51 -- in case it can't be inferred from the URL. | |
52 -- @return (string, string) or (nil, string, [string]): absolute local pathname of | |
53 -- the fetched file and temporary directory name; or nil and an error message | |
54 -- followed by an optional error code | |
55 function fetch_url_at_temp_dir(url, tmpname, filename) | |
56 assert(type(url) == "string") | |
57 assert(type(tmpname) == "string") | |
58 assert(type(filename) == "string" or not filename) | |
59 filename = filename or dir.base_name(url) | |
60 | |
61 local protocol, pathname = dir.split_url(url) | |
62 if protocol == "file" then | |
63 if fs.exists(pathname) then | |
64 return pathname, dir.dir_name(fs.absolute_name(pathname)) | |
65 else | |
66 return nil, "File not found: "..pathname | |
67 end | |
68 else | |
69 local temp_dir = fs.make_temp_dir(tmpname) | |
70 if not temp_dir then | |
71 return nil, "Failed creating temporary directory." | |
72 end | |
73 util.schedule_function(fs.delete, temp_dir) | |
74 fs.change_dir(temp_dir) | |
75 local file, err, errcode = fetch_url(url, filename) | |
76 fs.pop_dir() | |
77 if not file then | |
78 return nil, "Error fetching file: "..err, errcode | |
79 end | |
80 return file, temp_dir | |
81 end | |
82 end | |
83 | |
84 --- Obtain a rock and unpack it. | |
85 -- If a directory is not given, a temporary directory will be created, | |
86 -- which will be deleted on program termination. | |
87 -- @param rock_file string: URL or filename of the rock. | |
88 -- @param dest string or nil: if given, directory will be used as | |
89 -- a permanent destination. | |
90 -- @return string or (nil, string, [string]): the directory containing the contents | |
91 -- of the unpacked rock. | |
92 function fetch_and_unpack_rock(rock_file, dest) | |
93 assert(type(rock_file) == "string") | |
94 assert(type(dest) == "string" or not dest) | |
95 | |
96 local name = dir.base_name(rock_file):match("(.*)%.[^.]*%.rock") | |
97 | |
98 local rock_file, err, errcode = fetch_url_at_temp_dir(rock_file,"luarocks-rock-"..name) | |
99 if not rock_file then | |
100 return nil, "Could not fetch rock file: " .. err, errcode | |
101 end | |
102 | |
103 rock_file = fs.absolute_name(rock_file) | |
104 local unpack_dir | |
105 if dest then | |
106 unpack_dir = dest | |
107 fs.make_dir(unpack_dir) | |
108 else | |
109 unpack_dir = fs.make_temp_dir(name) | |
110 end | |
111 if not dest then | |
112 util.schedule_function(fs.delete, unpack_dir) | |
113 end | |
114 fs.change_dir(unpack_dir) | |
115 local ok = fs.unzip(rock_file) | |
116 if not ok then | |
117 return nil, "Failed unpacking rock file: " .. rock_file | |
118 end | |
119 fs.pop_dir() | |
120 return unpack_dir | |
121 end | |
122 | |
123 --- Back-end function that actually loads the local rockspec. | |
124 -- Performs some validation and postprocessing of the rockspec contents. | |
125 -- @param filename string: The local filename of the rockspec file. | |
126 -- @return table or (nil, string): A table representing the rockspec | |
127 -- or nil followed by an error message. | |
128 function load_local_rockspec(filename) | |
129 assert(type(filename) == "string") | |
130 filename = fs.absolute_name(filename) | |
131 local rockspec, err = persist.load_into_table(filename) | |
132 if not rockspec then | |
133 return nil, "Could not load rockspec file "..filename.." ("..err..")" | |
134 end | |
135 | |
136 local ok, err = type_check.type_check_rockspec(rockspec) | |
137 if not ok then | |
138 return nil, filename..": "..err | |
139 end | |
140 | |
141 if rockspec.rockspec_format then | |
142 if deps.compare_versions(rockspec.rockspec_format, type_check.rockspec_format) then | |
143 return nil, "Rockspec format "..rockspec.rockspec_format.." is not supported, please upgrade LuaRocks." | |
144 end | |
145 end | |
146 | |
147 util.platform_overrides(rockspec.build) | |
148 util.platform_overrides(rockspec.dependencies) | |
149 util.platform_overrides(rockspec.external_dependencies) | |
150 util.platform_overrides(rockspec.source) | |
151 util.platform_overrides(rockspec.hooks) | |
152 | |
153 local basename = dir.base_name(filename) | |
154 if basename == "rockspec" then | |
155 rockspec.name = rockspec.package:lower() | |
156 else | |
157 rockspec.name = basename:match("(.*)-[^-]*-[0-9]*") | |
158 if not rockspec.name then | |
159 return nil, "Expected filename in format 'name-version-revision.rockspec'." | |
160 end | |
161 end | |
162 | |
163 local protocol, pathname = dir.split_url(rockspec.source.url) | |
164 if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then | |
165 rockspec.source.file = rockspec.source.file or dir.base_name(rockspec.source.url) | |
166 end | |
167 rockspec.source.protocol, rockspec.source.pathname = protocol, pathname | |
168 | |
169 -- Temporary compatibility | |
170 if rockspec.source.cvs_module then rockspec.source.module = rockspec.source.cvs_module end | |
171 if rockspec.source.cvs_tag then rockspec.source.tag = rockspec.source.cvs_tag end | |
172 | |
173 local name_version = rockspec.package:lower() .. "-" .. rockspec.version | |
174 if basename ~= "rockspec" and basename ~= name_version .. ".rockspec" then | |
175 return nil, "Inconsistency between rockspec filename ("..basename..") and its contents ("..name_version..".rockspec)." | |
176 end | |
177 | |
178 rockspec.local_filename = filename | |
179 local filebase = rockspec.source.file or rockspec.source.url | |
180 local base = dir.base_name(filebase) | |
181 base = base:gsub("%.[^.]*$", ""):gsub("%.tar$", "") | |
182 rockspec.source.dir = rockspec.source.dir | |
183 or rockspec.source.module | |
184 or ((filebase:match(".lua$") or filebase:match(".c$")) and ".") | |
185 or base | |
186 if rockspec.dependencies then | |
187 for i = 1, #rockspec.dependencies do | |
188 local parsed = deps.parse_dep(rockspec.dependencies[i]) | |
189 if not parsed then | |
190 return nil, "Parse error processing dependency '"..rockspec.dependencies[i].."'" | |
191 end | |
192 rockspec.dependencies[i] = parsed | |
193 end | |
194 else | |
195 rockspec.dependencies = {} | |
196 end | |
197 local ok, err = path.configure_paths(rockspec) | |
198 if err then | |
199 return nil, "Error verifying paths: "..err | |
200 end | |
201 | |
202 return rockspec | |
203 end | |
204 | |
205 --- Load a local or remote rockspec into a table. | |
206 -- This is the entry point for the LuaRocks tools. | |
207 -- Only the LuaRocks runtime loader should use | |
208 -- load_local_rockspec directly. | |
209 -- @param filename string: Local or remote filename of a rockspec. | |
210 -- @param location string or nil: Where to download. If not given, | |
211 -- a temporary dir is created. | |
212 -- @return table or (nil, string, [string]): A table representing the rockspec | |
213 -- or nil followed by an error message and optional error code. | |
214 function load_rockspec(filename, location) | |
215 assert(type(filename) == "string") | |
216 | |
217 local name | |
218 local basename = dir.base_name(filename) | |
219 if basename == "rockspec" then | |
220 name = "rockspec" | |
221 else | |
222 name = basename:match("(.*)%.rockspec") | |
223 if not name and not basename == "rockspec" then | |
224 return nil, "Filename '"..filename.."' does not look like a rockspec." | |
225 end | |
226 end | |
227 | |
228 local err, errcode | |
229 if location then | |
230 fs.change_dir(location) | |
231 filename, err = fetch_url(filename) | |
232 fs.pop_dir() | |
233 else | |
234 filename, err, errcode = fetch_url_at_temp_dir(filename,"luarocks-rockspec-"..name) | |
235 end | |
236 if not filename then | |
237 return nil, err, errcode | |
238 end | |
239 | |
240 return load_local_rockspec(filename) | |
241 end | |
242 | |
243 --- Download sources for building a rock using the basic URL downloader. | |
244 -- @param rockspec table: The rockspec table | |
245 -- @param extract boolean: Whether to extract the sources from | |
246 -- the fetched source tarball or not. | |
247 -- @param dest_dir string or nil: If set, will extract to the given directory. | |
248 -- @return (string, string) or (nil, string, [string]): The absolute pathname of | |
249 -- the fetched source tarball and the temporary directory created to | |
250 -- store it; or nil and an error message and optional error code. | |
251 function get_sources(rockspec, extract, dest_dir) | |
252 assert(type(rockspec) == "table") | |
253 assert(type(extract) == "boolean") | |
254 assert(type(dest_dir) == "string" or not dest_dir) | |
255 | |
256 local url = rockspec.source.url | |
257 local name = rockspec.name.."-"..rockspec.version | |
258 local filename = rockspec.source.file | |
259 local source_file, store_dir, err, errcode | |
260 if dest_dir then | |
261 fs.change_dir(dest_dir) | |
262 source_file, err, errcode = fetch_url(url, filename) | |
263 fs.pop_dir() | |
264 store_dir = dest_dir | |
265 else | |
266 source_file, store_dir, errcode = fetch_url_at_temp_dir(url, "luarocks-source-"..name, filename) | |
267 end | |
268 if not source_file then | |
269 return nil, err or store_dir, errcode | |
270 end | |
271 if rockspec.source.md5 then | |
272 if not fs.check_md5(source_file, rockspec.source.md5) then | |
273 return nil, "MD5 check for "..filename.." has failed." | |
274 end | |
275 end | |
276 if extract then | |
277 fs.change_dir(store_dir) | |
278 fs.unpack_archive(rockspec.source.file) | |
279 if not fs.exists(rockspec.source.dir) then | |
280 return nil, "Directory "..rockspec.source.dir.." not found inside archive "..rockspec.source.file | |
281 end | |
282 fs.pop_dir() | |
283 end | |
284 return source_file, store_dir | |
285 end | |
286 | |
287 --- Download sources for building a rock, calling the appropriate protocol method. | |
288 -- @param rockspec table: The rockspec table | |
289 -- @param extract boolean: When downloading compressed formats, whether to extract | |
290 -- the sources from the fetched archive or not. | |
291 -- @param dest_dir string or nil: If set, will extract to the given directory. | |
292 -- @return (string, string) or (nil, string): The absolute pathname of | |
293 -- the fetched source tarball and the temporary directory created to | |
294 -- store it; or nil and an error message. | |
295 function fetch_sources(rockspec, extract, dest_dir) | |
296 assert(type(rockspec) == "table") | |
297 assert(type(extract) == "boolean") | |
298 assert(type(dest_dir) == "string" or not dest_dir) | |
299 | |
300 local protocol = rockspec.source.protocol | |
301 local ok, proto | |
302 if protocol == "http" or protocol == "https" or protocol == "ftp" or protocol == "file" then | |
303 proto = require("luarocks.fetch") | |
304 else | |
305 ok, proto = pcall(require, "luarocks.fetch."..protocol:gsub("[+-]", "_")) | |
306 if not ok then | |
307 return nil, "Unknown protocol "..protocol | |
308 end | |
309 end | |
310 | |
311 if cfg.only_sources_from | |
312 and rockspec.source.pathname | |
313 and #rockspec.source.pathname > 0 then | |
314 if #cfg.only_sources_from == 0 then | |
315 return nil, "Can't download "..rockspec.source.url.." -- download from remote servers disabled" | |
316 elseif rockspec.source.pathname:find(cfg.only_sources_from, 1, true) ~= 1 then | |
317 return nil, "Can't download "..rockspec.source.url.." -- only downloading from "..cfg.only_sources_from | |
318 end | |
319 end | |
320 return proto.get_sources(rockspec, extract, dest_dir) | |
321 end |