aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHisham <hisham@gobolinux.org>2016-10-28 20:59:42 -0200
committerHisham <hisham@gobolinux.org>2016-10-28 20:59:42 -0200
commit5c140a5da73d304653621a0ac40f363d234928ed (patch)
tree5bf34d6c10e8d4bb692feb9589477ac08f7f4863 /src
parent5bd20308b881c63dd886b71395dbc9baaab25dfd (diff)
downloadluarocks-5c140a5da73d304653621a0ac40f363d234928ed.tar.gz
luarocks-5c140a5da73d304653621a0ac40f363d234928ed.tar.bz2
luarocks-5c140a5da73d304653621a0ac40f363d234928ed.zip
Keep only command driver functions in luarocks.cmd
Diffstat (limited to 'src')
-rw-r--r--src/luarocks/cmd/build.lua347
-rw-r--r--src/luarocks/cmd/download.lua76
-rw-r--r--src/luarocks/cmd/pack.lua164
-rw-r--r--src/luarocks/cmd/remove.lua124
-rw-r--r--src/luarocks/cmd/search.lua411
5 files changed, 36 insertions, 1086 deletions
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua
index f3b054d2..d050e6a3 100644
--- a/src/luarocks/cmd/build.lua
+++ b/src/luarocks/cmd/build.lua
@@ -1,23 +1,22 @@
1 1
2--- Module implementing the LuaRocks "build" command. 2--- Module implementing the LuaRocks "build" command.
3-- Builds a rock, compiling its C parts if any. 3-- Builds a rock, compiling its C parts if any.
4local build = {} 4local cmd_build = {}
5 5
6local pack = require("luarocks.pack") 6local pack = require("luarocks.pack")
7local path = require("luarocks.path") 7local path = require("luarocks.path")
8local util = require("luarocks.util") 8local util = require("luarocks.util")
9local repos = require("luarocks.repos")
10local fetch = require("luarocks.fetch") 9local fetch = require("luarocks.fetch")
11local fs = require("luarocks.fs") 10local fs = require("luarocks.fs")
12local dir = require("luarocks.dir") 11local dir = require("luarocks.dir")
13local deps = require("luarocks.deps") 12local deps = require("luarocks.deps")
14local writer = require("luarocks.manif.writer")
15local remove = require("luarocks.remove") 13local remove = require("luarocks.remove")
16local cfg = require("luarocks.core.cfg") 14local cfg = require("luarocks.core.cfg")
15local build = require("luarocks.build")
17 16
18build.help_summary = "Build/compile a rock." 17cmd_build.help_summary = "build/compile a rock."
19build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" 18cmd_build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}"
20build.help = [[ 19cmd_build.help = [[
21Build and install a rock, compiling its C parts if any. 20Build and install a rock, compiling its C parts if any.
22Argument may be a rockspec file, a source rock file 21Argument may be a rockspec file, a source rock file
23or the name of a rock to be fetched from a repository. 22or the name of a rock to be fetched from a repository.
@@ -39,328 +38,6 @@ or the name of a rock to be fetched from a repository.
39 38
40]]..util.deps_mode_help() 39]]..util.deps_mode_help()
41 40
42--- Install files to a given location.
43-- Takes a table where the array part is a list of filenames to be copied.
44-- In the hash part, other keys, if is_module_path is set, are identifiers
45-- in Lua module format, to indicate which subdirectory the file should be
46-- copied to. For example, install_files({["foo.bar"] = "src/bar.lua"}, "boo")
47-- will copy src/bar.lua to boo/foo.
48-- @param files table or nil: A table containing a list of files to copy in
49-- the format described above. If nil is passed, this function is a no-op.
50-- Directories should be delimited by forward slashes as in internet URLs.
51-- @param location string: The base directory files should be copied to.
52-- @param is_module_path boolean: True if string keys in files should be
53-- interpreted as dotted module paths.
54-- @param perms string: Permissions of the newly created files installed.
55-- Directories are always created with the default permissions.
56-- @return boolean or (nil, string): True if succeeded or
57-- nil and an error message.
58local function install_files(files, location, is_module_path, perms)
59 assert(type(files) == "table" or not files)
60 assert(type(location) == "string")
61 if files then
62 for k, file in pairs(files) do
63 local dest = location
64 local filename = dir.base_name(file)
65 if type(k) == "string" then
66 local modname = k
67 if is_module_path then
68 dest = dir.path(location, path.module_to_path(modname))
69 local ok, err = fs.make_dir(dest)
70 if not ok then return nil, err end
71 if filename:match("%.lua$") then
72 local basename = modname:match("([^.]+)$")
73 filename = basename..".lua"
74 end
75 else
76 dest = dir.path(location, dir.dir_name(modname))
77 local ok, err = fs.make_dir(dest)
78 if not ok then return nil, err end
79 filename = dir.base_name(modname)
80 end
81 else
82 local ok, err = fs.make_dir(dest)
83 if not ok then return nil, err end
84 end
85 local ok = fs.copy(dir.path(file), dir.path(dest, filename), perms)
86 if not ok then
87 return nil, "Failed copying "..file
88 end
89 end
90 end
91 return true
92end
93
94--- Write to the current directory the contents of a table,
95-- where each key is a file name and its value is the file content.
96-- @param files table: The table of files to be written.
97local function extract_from_rockspec(files)
98 for name, content in pairs(files) do
99 local fd = io.open(dir.path(fs.current_dir(), name), "w+")
100 fd:write(content)
101 fd:close()
102 end
103end
104
105--- Applies patches inlined in the build.patches section
106-- and extracts files inlined in the build.extra_files section
107-- of a rockspec.
108-- @param rockspec table: A rockspec table.
109-- @return boolean or (nil, string): True if succeeded or
110-- nil and an error message.
111function build.apply_patches(rockspec)
112 assert(type(rockspec) == "table")
113
114 local build_spec = rockspec.build
115 if build_spec.extra_files then
116 extract_from_rockspec(build_spec.extra_files)
117 end
118 if build_spec.patches then
119 extract_from_rockspec(build_spec.patches)
120 for patch, patchdata in util.sortedpairs(build_spec.patches) do
121 util.printout("Applying patch "..patch.."...")
122 local ok, err = fs.apply_patch(tostring(patch), patchdata)
123 if not ok then
124 return nil, "Failed applying patch "..patch
125 end
126 end
127 end
128 return true
129end
130
131local function install_default_docs(name, version)
132 local patterns = { "readme", "license", "copying", ".*%.md" }
133 local dest = dir.path(path.install_dir(name, version), "doc")
134 local has_dir = false
135 for file in fs.dir() do
136 for _, pattern in ipairs(patterns) do
137 if file:lower():match("^"..pattern) then
138 if not has_dir then
139 fs.make_dir(dest)
140 has_dir = true
141 end
142 fs.copy(file, dest, cfg.perm_read)
143 break
144 end
145 end
146 end
147end
148
149local function check_macosx_deployment_target(rockspec)
150 local target = rockspec.build.macosx_deployment_target
151 local function minor(version)
152 return tonumber(version and version:match("^[^.]+%.([^.]+)"))
153 end
154 local function patch_variable(var, target)
155 if rockspec.variables[var]:match("MACOSX_DEPLOYMENT_TARGET") then
156 rockspec.variables[var] = (rockspec.variables[var]):gsub("MACOSX_DEPLOYMENT_TARGET=[^ ]*", "MACOSX_DEPLOYMENT_TARGET="..target)
157 else
158 rockspec.variables[var] = "env MACOSX_DEPLOYMENT_TARGET="..target.." "..rockspec.variables[var]
159 end
160 end
161 if cfg.platforms.macosx and rockspec:format_is_at_least("3.0") and target then
162 local version = util.popen_read("sw_vers -productVersion")
163 local versionminor = minor(version)
164 local targetminor = minor(target)
165 if targetminor > versionminor then
166 return nil, ("This rock requires Mac OSX 10.%d, and you are running 10.%d."):format(targetminor, versionminor)
167 end
168 patch_variable("CC", target)
169 patch_variable("LD", target)
170 end
171 return true
172end
173
174--- Build and install a rock given a rockspec.
175-- @param rockspec_file string: local or remote filename of a rockspec.
176-- @param need_to_fetch boolean: true if sources need to be fetched,
177-- false if the rockspec was obtained from inside a source rock.
178-- @param minimal_mode boolean: true if there's no need to fetch,
179-- unpack or change dir (this is used by "luarocks make"). Implies
180-- need_to_fetch = false.
181-- @param deps_mode string: Dependency mode: "one" for the current default tree,
182-- "all" for all trees, "order" for all trees with priority >= the current default,
183-- "none" for no trees.
184-- @param build_only_deps boolean: true to build the listed dependencies only.
185-- @return (string, string) or (nil, string, [string]): Name and version of
186-- installed rock if succeeded or nil and an error message followed by an error code.
187function build.build_rockspec(rockspec_file, need_to_fetch, minimal_mode, deps_mode, build_only_deps)
188 assert(type(rockspec_file) == "string")
189 assert(type(need_to_fetch) == "boolean")
190
191 local rockspec, err, errcode = fetch.load_rockspec(rockspec_file)
192 if err then
193 return nil, err, errcode
194 elseif not rockspec.build then
195 return nil, "Rockspec error: build table not specified"
196 elseif not rockspec.build.type then
197 return nil, "Rockspec error: build type not specified"
198 end
199
200 local ok
201 if not build_only_deps then
202 ok, err, errcode = deps.check_external_deps(rockspec, "build")
203 if err then
204 return nil, err, errcode
205 end
206 end
207
208 if deps_mode == "none" then
209 util.printerr("Warning: skipping dependency checks.")
210 else
211 local ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode)
212 if err then
213 return nil, err, errcode
214 end
215 end
216
217 local name, version = rockspec.name, rockspec.version
218 if build_only_deps then
219 util.printout("Stopping after installing dependencies for " ..name.." "..version)
220 util.printout()
221 return name, version
222 end
223
224 if repos.is_installed(name, version) then
225 repos.delete_version(name, version, deps_mode)
226 end
227
228 if not minimal_mode then
229 local source_dir
230 if need_to_fetch then
231 ok, source_dir, errcode = fetch.fetch_sources(rockspec, true)
232 if not ok then
233 return nil, source_dir, errcode
234 end
235 local ok, err = fs.change_dir(source_dir)
236 if not ok then return nil, err end
237 elseif rockspec.source.file then
238 local ok, err = fs.unpack_archive(rockspec.source.file)
239 if not ok then
240 return nil, err
241 end
242 end
243 fs.change_dir(rockspec.source.dir)
244 end
245
246 local dirs = {
247 lua = { name = path.lua_dir(name, version), is_module_path = true, perms = cfg.perm_read },
248 lib = { name = path.lib_dir(name, version), is_module_path = true, perms = cfg.perm_exec },
249 conf = { name = path.conf_dir(name, version), is_module_path = false, perms = cfg.perm_read },
250 bin = { name = path.bin_dir(name, version), is_module_path = false, perms = cfg.perm_exec },
251 }
252
253 for _, d in pairs(dirs) do
254 local ok, err = fs.make_dir(d.name)
255 if not ok then return nil, err end
256 end
257 local rollback = util.schedule_function(function()
258 fs.delete(path.install_dir(name, version))
259 fs.remove_dir_if_empty(path.versions_dir(name))
260 end)
261
262 local build_spec = rockspec.build
263
264 if not minimal_mode then
265 ok, err = build.apply_patches(rockspec)
266 if err then
267 return nil, err
268 end
269 end
270
271 ok, err = check_macosx_deployment_target(rockspec)
272 if not ok then
273 return nil, err
274 end
275
276 if build_spec.type ~= "none" then
277
278 -- Temporary compatibility
279 if build_spec.type == "module" then
280 util.printout("Do not use 'module' as a build type. Use 'builtin' instead.")
281 build_spec.type = "builtin"
282 end
283
284 if cfg.accepted_build_types and util.array_contains(cfg.accepted_build_types, build_spec.type) then
285 return nil, "This rockspec uses the '"..build_spec.type.."' build type, which is blocked by the 'accepted_build_types' setting in your LuaRocks configuration."
286 end
287
288 local build_type
289 ok, build_type = pcall(require, "luarocks.build." .. build_spec.type)
290 if not ok or not type(build_type) == "table" then
291 return nil, "Failed initializing build back-end for build type '"..build_spec.type.."': "..build_type
292 end
293
294 ok, err = build_type.run(rockspec)
295 if not ok then
296 return nil, "Build error: " .. err
297 end
298 end
299
300 if build_spec.install then
301 for id, install_dir in pairs(dirs) do
302 ok, err = install_files(build_spec.install[id], install_dir.name, install_dir.is_module_path, install_dir.perms)
303 if not ok then
304 return nil, err
305 end
306 end
307 end
308
309 local copy_directories = build_spec.copy_directories
310 local copying_default = false
311 if not copy_directories then
312 copy_directories = {"doc"}
313 copying_default = true
314 end
315
316 local any_docs = false
317 for _, copy_dir in pairs(copy_directories) do
318 if fs.is_dir(copy_dir) then
319 local dest = dir.path(path.install_dir(name, version), copy_dir)
320 fs.make_dir(dest)
321 fs.copy_contents(copy_dir, dest)
322 any_docs = true
323 else
324 if not copying_default then
325 return nil, "Directory '"..copy_dir.."' not found"
326 end
327 end
328 end
329
330 if not any_docs then
331 install_default_docs(name, version)
332 end
333
334 for _, d in pairs(dirs) do
335 fs.remove_dir_if_empty(d.name)
336 end
337
338 fs.pop_dir()
339
340 fs.copy(rockspec.local_filename, path.rockspec_file(name, version), cfg.perm_read)
341 if need_to_fetch then
342 fs.pop_dir()
343 end
344
345 ok, err = writer.make_rock_manifest(name, version)
346 if err then return nil, err end
347
348 ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode)
349 if err then return nil, err end
350
351 util.remove_scheduled_function(rollback)
352 rollback = util.schedule_function(function()
353 repos.delete_version(name, version, deps_mode)
354 end)
355
356 ok, err = repos.run_hook(rockspec, "post_install")
357 if err then return nil, err end
358
359 util.announce_install(rockspec)
360 util.remove_scheduled_function(rollback)
361 return name, version
362end
363
364--- Build and install a rock. 41--- Build and install a rock.
365-- @param rock_file string: local or remote filename of a rock. 42-- @param rock_file string: local or remote filename of a rock.
366-- @param need_to_fetch boolean: true if sources need to be fetched, 43-- @param need_to_fetch boolean: true if sources need to be fetched,
@@ -371,7 +48,7 @@ end
371-- @param build_only_deps boolean: true to build the listed dependencies only. 48-- @param build_only_deps boolean: true to build the listed dependencies only.
372-- @return boolean or (nil, string, [string]): True if build was successful, 49-- @return boolean or (nil, string, [string]): True if build was successful,
373-- or false and an error message and an optional error code. 50-- or false and an error message and an optional error code.
374function build.build_rock(rock_file, need_to_fetch, deps_mode, build_only_deps) 51local function build_rock(rock_file, need_to_fetch, deps_mode, build_only_deps)
375 assert(type(rock_file) == "string") 52 assert(type(rock_file) == "string")
376 assert(type(need_to_fetch) == "boolean") 53 assert(type(need_to_fetch) == "boolean")
377 54
@@ -393,13 +70,11 @@ local function do_build(name, version, deps_mode, build_only_deps)
393 if name:match("%.rockspec$") then 70 if name:match("%.rockspec$") then
394 return build.build_rockspec(name, true, false, deps_mode, build_only_deps) 71 return build.build_rockspec(name, true, false, deps_mode, build_only_deps)
395 elseif name:match("%.src%.rock$") then 72 elseif name:match("%.src%.rock$") then
396 return build.build_rock(name, false, deps_mode, build_only_deps) 73 return build_rock(name, false, deps_mode, build_only_deps)
397 elseif name:match("%.all%.rock$") then 74 elseif name:match("%.all%.rock$") then
398 local install = require("luarocks.install") 75 return build_rock(name, true, deps_mode, build_only_deps)
399 local install_fun = build_only_deps and install.install_binary_rock_deps or install.install_binary_rock
400 return install_fun(name, deps_mode)
401 elseif name:match("%.rock$") then 76 elseif name:match("%.rock$") then
402 return build.build_rock(name, true, deps_mode, build_only_deps) 77 return build_rock(name, true, deps_mode, build_only_deps)
403 elseif not name:match(dir.separator) then 78 elseif not name:match(dir.separator) then
404 local search = require("luarocks.search") 79 local search = require("luarocks.search")
405 return search.act_on_src_or_rockspec(do_build, name:lower(), version, nil, deps_mode, build_only_deps) 80 return search.act_on_src_or_rockspec(do_build, name:lower(), version, nil, deps_mode, build_only_deps)
@@ -415,7 +90,7 @@ end
415-- also be given. 90-- also be given.
416-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an 91-- @return boolean or (nil, string, exitcode): True if build was successful; nil and an
417-- error message otherwise. exitcode is optionally returned. 92-- error message otherwise. exitcode is optionally returned.
418function build.command(flags, name, version) 93function cmd_build.command(flags, name, version)
419 if type(name) ~= "string" then 94 if type(name) ~= "string" then
420 return nil, "Argument missing. "..util.see_help("build") 95 return nil, "Argument missing. "..util.see_help("build")
421 end 96 end
@@ -440,4 +115,4 @@ function build.command(flags, name, version)
440 end 115 end
441end 116end
442 117
443return build 118return cmd_build
diff --git a/src/luarocks/cmd/download.lua b/src/luarocks/cmd/download.lua
index 557d1b65..9c119f6e 100644
--- a/src/luarocks/cmd/download.lua
+++ b/src/luarocks/cmd/download.lua
@@ -1,89 +1,27 @@
1 1
2--- Module implementing the luarocks "download" command. 2--- Module implementing the luarocks "download" command.
3-- Download a rock from the repository. 3-- Download a rock from the repository.
4local download = {} 4local cmd_download = {}
5 5
6local util = require("luarocks.util") 6local util = require("luarocks.util")
7local path = require("luarocks.path") 7local download = require("luarocks.download")
8local fetch = require("luarocks.fetch")
9local search = require("luarocks.search")
10local fs = require("luarocks.fs")
11local dir = require("luarocks.dir")
12local cfg = require("luarocks.core.cfg")
13 8
14download.help_summary = "Download a specific rock file from a rocks server." 9cmd_download.help_summary = "Download a specific rock file from a rocks server."
15download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" 10cmd_download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]"
16 11cmd_download.help = [[
17download.help = [[
18--all Download all files if there are multiple matches. 12--all Download all files if there are multiple matches.
19--source Download .src.rock if available. 13--source Download .src.rock if available.
20--rockspec Download .rockspec if available. 14--rockspec Download .rockspec if available.
21--arch=<arch> Download rock for a specific architecture. 15--arch=<arch> Download rock for a specific architecture.
22]] 16]]
23 17
24local function get_file(filename)
25 local protocol, pathname = dir.split_url(filename)
26 if protocol == "file" then
27 local ok, err = fs.copy(pathname, fs.current_dir(), cfg.perm_read)
28 if ok then
29 return pathname
30 else
31 return nil, err
32 end
33 else
34 return fetch.fetch_url(filename)
35 end
36end
37
38function download.download(arch, name, version, all)
39 local query = search.make_query(name, version)
40 if arch then query.arch = arch end
41 local search_err
42
43 if all then
44 if name == "" then query.exact_name = false end
45 local results = search.search_repos(query)
46 local has_result = false
47 local all_ok = true
48 local any_err = ""
49 for name, result in pairs(results) do
50 for version, items in pairs(result) do
51 for _, item in ipairs(items) do
52 -- Ignore provided rocks.
53 if item.arch ~= "installed" then
54 has_result = true
55 local filename = path.make_url(item.repo, name, version, item.arch)
56 local ok, err = get_file(filename)
57 if not ok then
58 all_ok = false
59 any_err = any_err .. "\n" .. err
60 end
61 end
62 end
63 end
64 end
65
66 if has_result then
67 return all_ok, any_err
68 end
69 else
70 local url
71 url, search_err = search.find_suitable_rock(query)
72 if url then
73 return get_file(url)
74 end
75 end
76 return nil, "Could not find a result named "..name..(version and " "..version or "")..
77 (search_err and ": "..search_err or ".")
78end
79
80--- Driver function for the "download" command. 18--- Driver function for the "download" command.
81-- @param name string: a rock name. 19-- @param name string: a rock name.
82-- @param version string or nil: if the name of a package is given, a 20-- @param version string or nil: if the name of a package is given, a
83-- version may also be passed. 21-- version may also be passed.
84-- @return boolean or (nil, string): true if successful or nil followed 22-- @return boolean or (nil, string): true if successful or nil followed
85-- by an error message. 23-- by an error message.
86function download.command(flags, name, version) 24function cmd_download.command(flags, name, version)
87 assert(type(version) == "string" or not version) 25 assert(type(version) == "string" or not version)
88 if type(name) ~= "string" and not flags["all"] then 26 if type(name) ~= "string" and not flags["all"] then
89 return nil, "Argument missing. "..util.see_help("download") 27 return nil, "Argument missing. "..util.see_help("download")
@@ -104,4 +42,4 @@ function download.command(flags, name, version)
104 return dl and true, err 42 return dl and true, err
105end 43end
106 44
107return download 45return cmd_download
diff --git a/src/luarocks/cmd/pack.lua b/src/luarocks/cmd/pack.lua
index 655cbf37..e43e5b3f 100644
--- a/src/luarocks/cmd/pack.lua
+++ b/src/luarocks/cmd/pack.lua
@@ -1,168 +1,20 @@
1 1
2--- Module implementing the LuaRocks "pack" command. 2--- Module implementing the LuaRocks "pack" command.
3-- Creates a rock, packing sources or binaries. 3-- Creates a rock, packing sources or binaries.
4local pack = {} 4local cmd_pack = {}
5 5
6local unpack = unpack or table.unpack
7
8local path = require("luarocks.path")
9local repos = require("luarocks.repos")
10local fetch = require("luarocks.fetch")
11local fs = require("luarocks.fs")
12local cfg = require("luarocks.core.cfg")
13local util = require("luarocks.util") 6local util = require("luarocks.util")
14local dir = require("luarocks.dir") 7local pack = require("luarocks.pack")
15local manif = require("luarocks.manif")
16local search = require("luarocks.search")
17 8
18pack.help_summary = "Create a rock, packing sources or binaries." 9cmd_pack.help_summary = "Create a rock, packing sources or binaries."
19pack.help_arguments = "{<rockspec>|<name> [<version>]}" 10cmd_pack.help_arguments = "{<rockspec>|<name> [<version>]}"
20pack.help = [[ 11cmd_pack.help = [[
21Argument may be a rockspec file, for creating a source rock, 12Argument may be a rockspec file, for creating a source rock,
22or the name of an installed package, for creating a binary rock. 13or the name of an installed package, for creating a binary rock.
23In the latter case, the app version may be given as a second 14In the latter case, the app version may be given as a second
24argument. 15argument.
25]] 16]]
26 17
27--- Create a source rock.
28-- Packages a rockspec and its required source files in a rock
29-- file with the .src.rock extension, which can later be built and
30-- installed with the "build" command.
31-- @param rockspec_file string: An URL or pathname for a rockspec file.
32-- @return string or (nil, string): The filename of the resulting
33-- .src.rock file; or nil and an error message.
34function pack.pack_source_rock(rockspec_file)
35 assert(type(rockspec_file) == "string")
36
37 local rockspec, err = fetch.load_rockspec(rockspec_file)
38 if err then
39 return nil, "Error loading rockspec: "..err
40 end
41 rockspec_file = rockspec.local_filename
42
43 local name_version = rockspec.name .. "-" .. rockspec.version
44 local rock_file = fs.absolute_name(name_version .. ".src.rock")
45
46 local source_file, source_dir = fetch.fetch_sources(rockspec, false)
47 if not source_file then
48 return nil, source_dir
49 end
50 local ok, err = fs.change_dir(source_dir)
51 if not ok then return nil, err end
52
53 fs.delete(rock_file)
54 fs.copy(rockspec_file, source_dir, cfg.perm_read)
55 if not fs.zip(rock_file, dir.base_name(rockspec_file), dir.base_name(source_file)) then
56 return nil, "Failed packing "..rock_file
57 end
58 fs.pop_dir()
59
60 return rock_file
61end
62
63local function copy_back_files(name, version, file_tree, deploy_dir, pack_dir, perms)
64 local ok, err = fs.make_dir(pack_dir)
65 if not ok then return nil, err end
66 for file, sub in pairs(file_tree) do
67 local source = dir.path(deploy_dir, file)
68 local target = dir.path(pack_dir, file)
69 if type(sub) == "table" then
70 local ok, err = copy_back_files(name, version, sub, source, target)
71 if not ok then return nil, err end
72 else
73 local versioned = path.versioned_name(source, deploy_dir, name, version)
74 if fs.exists(versioned) then
75 fs.copy(versioned, target, perms)
76 else
77 fs.copy(source, target, perms)
78 end
79 end
80 end
81 return true
82end
83
84-- @param name string: Name of package to pack.
85-- @param version string or nil: A version number may also be passed.
86-- @param tree string or nil: An optional tree to pick the package from.
87-- @return string or (nil, string): The filename of the resulting
88-- .src.rock file; or nil and an error message.
89local function do_pack_binary_rock(name, version, tree)
90 assert(type(name) == "string")
91 assert(type(version) == "string" or not version)
92
93 local repo, repo_url
94 name, version, repo, repo_url = search.pick_installed_rock(name, version, tree)
95 if not name then
96 return nil, version
97 end
98
99 local root = path.root_dir(repo_url)
100 local prefix = path.install_dir(name, version, root)
101 if not fs.exists(prefix) then
102 return nil, "'"..name.." "..version.."' does not seem to be an installed rock."
103 end
104
105 local rock_manifest, err = manif.load_rock_manifest(name, version, root)
106 if not rock_manifest then return nil, err end
107
108 local name_version = name .. "-" .. version
109 local rock_file = fs.absolute_name(name_version .. "."..cfg.arch..".rock")
110
111 local temp_dir = fs.make_temp_dir("pack")
112 fs.copy_contents(prefix, temp_dir)
113
114 local is_binary = false
115 if rock_manifest.lib then
116 local ok, err = copy_back_files(name, version, rock_manifest.lib, path.deploy_lib_dir(root), dir.path(temp_dir, "lib"), cfg.perm_exec)
117 if not ok then return nil, "Failed copying back files: " .. err end
118 is_binary = true
119 end
120 if rock_manifest.lua then
121 local ok, err = copy_back_files(name, version, rock_manifest.lua, path.deploy_lua_dir(root), dir.path(temp_dir, "lua"), cfg.perm_read)
122 if not ok then return nil, "Failed copying back files: " .. err end
123 end
124
125 local ok, err = fs.change_dir(temp_dir)
126 if not ok then return nil, err end
127 if not is_binary and not repos.has_binaries(name, version) then
128 rock_file = rock_file:gsub("%."..cfg.arch:gsub("%-","%%-").."%.", ".all.")
129 end
130 fs.delete(rock_file)
131 if not fs.zip(rock_file, unpack(fs.list_dir())) then
132 return nil, "Failed packing "..rock_file
133 end
134 fs.pop_dir()
135 fs.delete(temp_dir)
136 return rock_file
137end
138
139function pack.pack_binary_rock(name, version, cmd, ...)
140
141 -- The --pack-binary-rock option for "luarocks build" basically performs
142 -- "luarocks build" on a temporary tree and then "luarocks pack". The
143 -- alternative would require refactoring parts of luarocks.build and
144 -- luarocks.pack, which would save a few file operations: the idea would be
145 -- to shave off the final deploy steps from the build phase and the initial
146 -- collect steps from the pack phase.
147
148 local temp_dir, err = fs.make_temp_dir("luarocks-build-pack-"..dir.base_name(name))
149 if not temp_dir then
150 return nil, "Failed creating temporary directory: "..err
151 end
152 util.schedule_function(fs.delete, temp_dir)
153
154 path.use_tree(temp_dir)
155 local ok, err = cmd(...)
156 if not ok then
157 return nil, err
158 end
159 local rname, rversion = path.parse_name(name)
160 if not rname then
161 rname, rversion = name, version
162 end
163 return do_pack_binary_rock(rname, rversion, temp_dir)
164end
165
166--- Driver function for the "pack" command. 18--- Driver function for the "pack" command.
167-- @param arg string: may be a rockspec file, for creating a source rock, 19-- @param arg string: may be a rockspec file, for creating a source rock,
168-- or the name of an installed package, for creating a binary rock. 20-- or the name of an installed package, for creating a binary rock.
@@ -170,7 +22,7 @@ end
170-- version may also be passed. 22-- version may also be passed.
171-- @return boolean or (nil, string): true if successful or nil followed 23-- @return boolean or (nil, string): true if successful or nil followed
172-- by an error message. 24-- by an error message.
173function pack.command(flags, arg, version) 25function cmd_pack.command(flags, arg, version)
174 assert(type(version) == "string" or not version) 26 assert(type(version) == "string" or not version)
175 if type(arg) ~= "string" then 27 if type(arg) ~= "string" then
176 return nil, "Argument missing. "..util.see_help("pack") 28 return nil, "Argument missing. "..util.see_help("pack")
@@ -180,7 +32,7 @@ function pack.command(flags, arg, version)
180 if arg:match(".*%.rockspec") then 32 if arg:match(".*%.rockspec") then
181 file, err = pack.pack_source_rock(arg) 33 file, err = pack.pack_source_rock(arg)
182 else 34 else
183 file, err = do_pack_binary_rock(arg:lower(), version, flags["tree"]) 35 file, err = pack.pack_installed_rock(arg:lower(), version, flags["tree"])
184 end 36 end
185 if err then 37 if err then
186 return nil, err 38 return nil, err
@@ -190,4 +42,4 @@ function pack.command(flags, arg, version)
190 end 42 end
191end 43end
192 44
193return pack 45return cmd_pack
diff --git a/src/luarocks/cmd/remove.lua b/src/luarocks/cmd/remove.lua
index e7f37604..08d49058 100644
--- a/src/luarocks/cmd/remove.lua
+++ b/src/luarocks/cmd/remove.lua
@@ -1,20 +1,18 @@
1 1
2--- Module implementing the LuaRocks "remove" command. 2--- Module implementing the LuaRocks "remove" command.
3-- Uninstalls rocks. 3-- Uninstalls rocks.
4local remove = {} 4local cmd_remove = {}
5 5
6local search = require("luarocks.search") 6local remove = require("luarocks.remove")
7local deps = require("luarocks.deps")
8local fetch = require("luarocks.fetch")
9local repos = require("luarocks.repos")
10local path = require("luarocks.path")
11local util = require("luarocks.util") 7local util = require("luarocks.util")
12local cfg = require("luarocks.core.cfg") 8local cfg = require("luarocks.core.cfg")
13local fs = require("luarocks.fs") 9local fs = require("luarocks.fs")
10local search = require("luarocks.search")
11local path = require("luarocks.path")
14 12
15remove.help_summary = "Uninstall a rock." 13cmd_remove.help_summary = "Uninstall a rock."
16remove.help_arguments = "[--force|--force-fast] <name> [<version>]" 14cmd_remove.help_arguments = "[--force|--force-fast] <name> [<version>]"
17remove.help = [[ 15cmd_remove.help = [[
18Argument is the name of a rock to be uninstalled. 16Argument is the name of a rock to be uninstalled.
19If a version is not given, try to remove all versions at once. 17If a version is not given, try to remove all versions at once.
20Will only perform the removal if it does not break dependencies. 18Will only perform the removal if it does not break dependencies.
@@ -24,110 +22,6 @@ use --force-fast.
24 22
25]]..util.deps_mode_help() 23]]..util.deps_mode_help()
26 24
27--- Obtain a list of packages that depend on the given set of packages
28-- (where all packages of the set are versions of one program).
29-- @param name string: the name of a program
30-- @param versions array of string: the versions to be deleted.
31-- @return array of string: an empty table if no packages depend on any
32-- of the given list, or an array of strings in "name/version" format.
33local function check_dependents(name, versions, deps_mode)
34 local dependents = {}
35 local blacklist = {}
36 blacklist[name] = {}
37 for version, _ in pairs(versions) do
38 blacklist[name][version] = true
39 end
40 local local_rocks = {}
41 local query_all = search.make_query("")
42 query_all.exact_name = false
43 search.manifest_search(local_rocks, cfg.rocks_dir, query_all)
44 local_rocks[name] = nil
45 for rock_name, rock_versions in pairs(local_rocks) do
46 for rock_version, _ in pairs(rock_versions) do
47 local rockspec, err = fetch.load_rockspec(path.rockspec_file(rock_name, rock_version))
48 if rockspec then
49 local _, missing = deps.match_deps(rockspec, blacklist, deps_mode)
50 if missing[name] then
51 table.insert(dependents, { name = rock_name, version = rock_version })
52 end
53 end
54 end
55 end
56 return dependents
57end
58
59--- Delete given versions of a program.
60-- @param name string: the name of a program
61-- @param versions array of string: the versions to be deleted.
62-- @param deps_mode: string: Which trees to check dependencies for:
63-- "one" for the current default tree, "all" for all trees,
64-- "order" for all trees with priority >= the current default, "none" for no trees.
65-- @return boolean or (nil, string): true on success or nil and an error message.
66local function delete_versions(name, versions, deps_mode)
67
68 for version, _ in pairs(versions) do
69 util.printout("Removing "..name.." "..version.."...")
70 local ok, err = repos.delete_version(name, version, deps_mode)
71 if not ok then return nil, err end
72 end
73
74 return true
75end
76
77function remove.remove_search_results(results, name, deps_mode, force, fast)
78 local versions = results[name]
79
80 local version = next(versions)
81 local second = next(versions, version)
82
83 local dependents = {}
84 if not fast then
85 util.printout("Checking stability of dependencies in the absence of")
86 util.printout(name.." "..table.concat(util.keys(versions), ", ").."...")
87 util.printout()
88 dependents = check_dependents(name, versions, deps_mode)
89 end
90
91 if #dependents > 0 then
92 if force or fast then
93 util.printerr("The following packages may be broken by this forced removal:")
94 for _, dependent in ipairs(dependents) do
95 util.printerr(dependent.name.." "..dependent.version)
96 end
97 util.printerr()
98 else
99 if not second then
100 util.printerr("Will not remove "..name.." "..version..".")
101 util.printerr("Removing it would break dependencies for: ")
102 else
103 util.printerr("Will not remove installed versions of "..name..".")
104 util.printerr("Removing them would break dependencies for: ")
105 end
106 for _, dependent in ipairs(dependents) do
107 util.printerr(dependent.name.." "..dependent.version)
108 end
109 util.printerr()
110 util.printerr("Use --force to force removal (warning: this may break modules).")
111 return nil, "Failed removing."
112 end
113 end
114
115 local ok, err = delete_versions(name, versions, deps_mode)
116 if not ok then return nil, err end
117
118 util.printout("Removal successful.")
119 return true
120end
121
122function remove.remove_other_versions(name, version, force, fast)
123 local results = {}
124 search.manifest_search(results, cfg.rocks_dir, { name = name, exact_name = true, constraints = {{ op = "~=", version = version}} })
125 if results[name] then
126 return remove.remove_search_results(results, name, cfg.deps_mode, force, fast)
127 end
128 return true
129end
130
131--- Driver function for the "remove" command. 25--- Driver function for the "remove" command.
132-- @param name string: name of a rock. If a version is given, refer to 26-- @param name string: name of a rock. If a version is given, refer to
133-- a specific version; otherwise, try to remove all versions. 27-- a specific version; otherwise, try to remove all versions.
@@ -135,7 +29,7 @@ end
135-- may also be given. 29-- may also be given.
136-- @return boolean or (nil, string, exitcode): True if removal was 30-- @return boolean or (nil, string, exitcode): True if removal was
137-- successful, nil and an error message otherwise. exitcode is optionally returned. 31-- successful, nil and an error message otherwise. exitcode is optionally returned.
138function remove.command(flags, name, version) 32function cmd_remove.command(flags, name, version)
139 if type(name) ~= "string" then 33 if type(name) ~= "string" then
140 return nil, "Argument missing. "..util.see_help("remove") 34 return nil, "Argument missing. "..util.see_help("remove")
141 end 35 end
@@ -162,4 +56,4 @@ function remove.command(flags, name, version)
162 return remove.remove_search_results(results, name, deps_mode, flags["force"], flags["force-fast"]) 56 return remove.remove_search_results(results, name, deps_mode, flags["force"], flags["force-fast"])
163end 57end
164 58
165return remove 59return cmd_remove
diff --git a/src/luarocks/cmd/search.lua b/src/luarocks/cmd/search.lua
index 44eff694..109fe805 100644
--- a/src/luarocks/cmd/search.lua
+++ b/src/luarocks/cmd/search.lua
@@ -3,11 +3,6 @@
3-- Queries LuaRocks servers. 3-- Queries LuaRocks servers.
4local search = {} 4local search = {}
5 5
6
7local dir = require("luarocks.dir")
8local path = require("luarocks.path")
9local manif = require("luarocks.manif")
10local deps = require("luarocks.deps")
11local cfg = require("luarocks.core.cfg") 6local cfg = require("luarocks.core.cfg")
12local util = require("luarocks.util") 7local util = require("luarocks.util")
13 8
@@ -22,354 +17,6 @@ search.help = [[
22 this platform, do not filter by name. 17 this platform, do not filter by name.
23]] 18]]
24 19
25--- Convert the arch field of a query table to table format.
26-- @param query table: A query table.
27local function query_arch_as_table(query)
28 local format = type(query.arch)
29 if format == "table" then
30 return
31 elseif format == "nil" then
32 local accept = {}
33 accept["src"] = true
34 accept["all"] = true
35 accept["rockspec"] = true
36 accept["installed"] = true
37 accept[cfg.arch] = true
38 query.arch = accept
39 elseif format == "string" then
40 local accept = {}
41 for a in query.arch:gmatch("[%w_-]+") do
42 accept[a] = true
43 end
44 query.arch = accept
45 end
46end
47
48--- Store a search result (a rock or rockspec) in the results table.
49-- @param results table: The results table, where keys are package names and
50-- values are tables matching version strings to arrays of
51-- tables with fields "arch" and "repo".
52-- @param name string: Package name.
53-- @param version string: Package version.
54-- @param arch string: Architecture of rock ("all", "src" or platform
55-- identifier), "rockspec" or "installed"
56-- @param repo string: Pathname of a local repository of URL of
57-- rocks server.
58local function store_result(results, name, version, arch, repo)
59 assert(type(results) == "table")
60 assert(type(name) == "string")
61 assert(type(version) == "string")
62 assert(type(arch) == "string")
63 assert(type(repo) == "string")
64
65 if not results[name] then results[name] = {} end
66 if not results[name][version] then results[name][version] = {} end
67 table.insert(results[name][version], {
68 arch = arch,
69 repo = repo
70 })
71end
72
73--- Test the name field of a query.
74-- If query has a boolean field exact_name set to false,
75-- then substring match is performed; otherwise, exact string
76-- comparison is done.
77-- @param query table: A query in dependency table format.
78-- @param name string: A package name.
79-- @return boolean: True if names match, false otherwise.
80local function match_name(query, name)
81 assert(type(query) == "table")
82 assert(type(name) == "string")
83 if query.exact_name == false then
84 return name:find(query.name, 0, true) and true or false
85 else
86 return name == query.name
87 end
88end
89
90--- Store a match in a results table if version matches query.
91-- Name, version, arch and repository path are stored in a given
92-- table, optionally checking if version and arch (if given) match
93-- a query.
94-- @param results table: The results table, where keys are package names and
95-- values are tables matching version strings to arrays of
96-- tables with fields "arch" and "repo".
97-- @param repo string: URL or pathname of the repository.
98-- @param name string: The name of the package being tested.
99-- @param version string: The version of the package being tested.
100-- @param arch string: The arch of the package being tested.
101-- @param query table: A table describing the query in dependency
102-- format (for example, {name = "filesystem", exact_name = false,
103-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec").
104-- If the arch field is omitted, the local architecture (cfg.arch)
105-- is used. The special value "any" is also recognized, returning all
106-- matches regardless of architecture.
107local function store_if_match(results, repo, name, version, arch, query)
108 if match_name(query, name) then
109 if query.arch[arch] or query.arch["any"] then
110 if deps.match_constraints(deps.parse_version(version), query.constraints) then
111 store_result(results, name, version, arch, repo)
112 end
113 end
114 end
115end
116
117--- Perform search on a local repository.
118-- @param repo string: The pathname of the local repository.
119-- @param query table: A table describing the query in dependency
120-- format (for example, {name = "filesystem", exact_name = false,
121-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec").
122-- If the arch field is omitted, the local architecture (cfg.arch)
123-- is used. The special value "any" is also recognized, returning all
124-- matches regardless of architecture.
125-- @param results table or nil: If given, this table will store the
126-- results; if not given, a new table will be created.
127-- @return table: The results table, where keys are package names and
128-- values are tables matching version strings to arrays of
129-- tables with fields "arch" and "repo".
130-- If a table was given in the "results" parameter, that is the result value.
131function search.disk_search(repo, query, results)
132 assert(type(repo) == "string")
133 assert(type(query) == "table")
134 assert(type(results) == "table" or not results)
135
136 local fs = require("luarocks.fs")
137
138 if not results then
139 results = {}
140 end
141 query_arch_as_table(query)
142
143 for name in fs.dir(repo) do
144 local pathname = dir.path(repo, name)
145 local rname, rversion, rarch = path.parse_name(name)
146
147 if rname and (pathname:match(".rockspec$") or pathname:match(".rock$")) then
148 store_if_match(results, repo, rname, rversion, rarch, query)
149 elseif fs.is_dir(pathname) then
150 for version in fs.dir(pathname) do
151 if version:match("-%d+$") then
152 store_if_match(results, repo, name, version, "installed", query)
153 end
154 end
155 end
156 end
157 return results
158end
159
160--- Perform search on a rocks server or tree.
161-- @param results table: The results table, where keys are package names and
162-- values are tables matching version strings to arrays of
163-- tables with fields "arch" and "repo".
164-- @param repo string: The URL of a rocks server or
165-- the pathname of a rocks tree (as returned by path.rocks_dir()).
166-- @param query table: A table describing the query in dependency
167-- format (for example, {name = "filesystem", exact_name = false,
168-- constraints = {op = "~>", version = {1,0}}}, arch = "rockspec").
169-- If the arch field is omitted, the local architecture (cfg.arch)
170-- is used. The special value "any" is also recognized, returning all
171-- matches regardless of architecture.
172-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
173-- @return true or, in case of errors, nil, an error message and an optional error code.
174function search.manifest_search(results, repo, query, lua_version)
175 assert(type(results) == "table")
176 assert(type(repo) == "string")
177 assert(type(query) == "table")
178
179 query_arch_as_table(query)
180 local manifest, err, errcode = manif.load_manifest(repo, lua_version)
181 if not manifest then
182 return nil, err, errcode
183 end
184 for name, versions in pairs(manifest.repository) do
185 for version, items in pairs(versions) do
186 for _, item in ipairs(items) do
187 store_if_match(results, repo, name, version, item.arch, query)
188 end
189 end
190 end
191 return true
192end
193
194--- Search on all configured rocks servers.
195-- @param query table: A dependency query.
196-- @param lua_version string: Lua version in "5.x" format, defaults to installed version.
197-- @return table: A table where keys are package names
198-- and values are tables matching version strings to arrays of
199-- tables with fields "arch" and "repo".
200function search.search_repos(query, lua_version)
201 assert(type(query) == "table")
202
203 local results = {}
204 for _, repo in ipairs(cfg.rocks_servers) do
205 if not cfg.disabled_servers[repo] then
206 if type(repo) == "string" then
207 repo = { repo }
208 end
209 for _, mirror in ipairs(repo) do
210 local protocol, pathname = dir.split_url(mirror)
211 if protocol == "file" then
212 mirror = pathname
213 end
214 local ok, err, errcode = search.manifest_search(results, mirror, query, lua_version)
215 if errcode == "network" then
216 cfg.disabled_servers[repo] = true
217 end
218 if ok then
219 break
220 else
221 util.warning("Failed searching manifest: "..err)
222 end
223 end
224 end
225 end
226 -- search through rocks in cfg.rocks_provided
227 local provided_repo = "provided by VM or rocks_provided"
228 for name, versions in pairs(cfg.rocks_provided) do
229 store_if_match(results, provided_repo, name, versions, "installed", query)
230 end
231 return results
232end
233
234--- Prepare a query in dependency table format.
235-- @param name string: The query name.
236-- @param version string or nil:
237-- @return table: A query in table format
238function search.make_query(name, version)
239 assert(type(name) == "string")
240 assert(type(version) == "string" or not version)
241
242 local query = {
243 name = name,
244 constraints = {}
245 }
246 if version then
247 table.insert(query.constraints, { op = "==", version = deps.parse_version(version)})
248 end
249 return query
250end
251
252--- Get the URL for the latest in a set of versions.
253-- @param name string: The package name to be used in the URL.
254-- @param versions table: An array of version informations, as stored
255-- in search results tables.
256-- @return string or nil: the URL for the latest version if one could
257-- be picked, or nil.
258local function pick_latest_version(name, versions)
259 assert(type(name) == "string")
260 assert(type(versions) == "table")
261
262 local vtables = {}
263 for v, _ in pairs(versions) do
264 table.insert(vtables, deps.parse_version(v))
265 end
266 table.sort(vtables)
267 local version = vtables[#vtables].string
268 local items = versions[version]
269 if items then
270 local pick = 1
271 for i, item in ipairs(items) do
272 if (item.arch == 'src' and items[pick].arch == 'rockspec')
273 or (item.arch ~= 'src' and item.arch ~= 'rockspec') then
274 pick = i
275 end
276 end
277 return path.make_url(items[pick].repo, name, version, items[pick].arch)
278 end
279 return nil
280end
281
282-- Find out which other Lua versions provide rock versions matching a query,
283-- @param query table: A dependency query matching a single rock.
284-- @return table: array of Lua versions supported, in "5.x" format.
285local function supported_lua_versions(query)
286 local results = {}
287
288 for lua_version in util.lua_versions() do
289 if lua_version ~= cfg.lua_version then
290 if search.search_repos(query, lua_version)[query.name] then
291 table.insert(results, lua_version)
292 end
293 end
294 end
295
296 return results
297end
298
299--- Attempt to get a single URL for a given search for a rock.
300-- @param query table: A dependency query matching a single rock.
301-- @return string or (nil, string): URL for latest matching version
302-- of the rock if it was found, or nil followed by an error message.
303function search.find_suitable_rock(query)
304 assert(type(query) == "table")
305
306 local results = search.search_repos(query)
307 local first_rock = next(results)
308 if not first_rock then
309 if cfg.rocks_provided[query.name] == nil then
310 -- Check if constraints are satisfiable with other Lua versions.
311 local lua_versions = supported_lua_versions(query)
312
313 if #lua_versions ~= 0 then
314 -- Build a nice message in "only Lua 5.x and 5.y but not 5.z." format
315 for i, lua_version in ipairs(lua_versions) do
316 lua_versions[i] = "Lua "..lua_version
317 end
318
319 local versions_message = "only "..table.concat(lua_versions, " and ")..
320 " but not Lua "..cfg.lua_version.."."
321
322 if #query.constraints == 0 then
323 return nil, query.name.." supports "..versions_message
324 elseif #query.constraints == 1 and query.constraints[1].op == "==" then
325 return nil, query.name.." "..query.constraints[1].version.string.." supports "..versions_message
326 else
327 return nil, "Matching "..query.name.." versions support "..versions_message
328 end
329 end
330 end
331
332 return nil, "No results matching query were found."
333 elseif next(results, first_rock) then
334 -- Shouldn't happen as query must match only one package.
335 return nil, "Several rocks matched query."
336 elseif cfg.rocks_provided[query.name] ~= nil then
337 -- Do not install versions listed in cfg.rocks_provided.
338 return nil, "Rock "..query.name.." "..cfg.rocks_provided[query.name]..
339 " was found but it is provided by VM or 'rocks_provided' in the config file."
340 else
341 return pick_latest_version(query.name, results[first_rock])
342 end
343end
344
345--- Print a list of rocks/rockspecs on standard output.
346-- @param results table: A table where keys are package names and versions
347-- are tables matching version strings to an array of rocks servers.
348-- @param porcelain boolean or nil: A flag to force machine-friendly output.
349function search.print_results(results, porcelain)
350 assert(type(results) == "table")
351 assert(type(porcelain) == "boolean" or not porcelain)
352
353 for package, versions in util.sortedpairs(results) do
354 if not porcelain then
355 util.printout(package)
356 end
357 for version, repos in util.sortedpairs(versions, deps.compare_versions) do
358 for _, repo in ipairs(repos) do
359 repo.repo = dir.normalize(repo.repo)
360 if porcelain then
361 util.printout(package, version, repo.arch, repo.repo)
362 else
363 util.printout(" "..version.." ("..repo.arch..") - "..repo.repo)
364 end
365 end
366 end
367 if not porcelain then
368 util.printout()
369 end
370 end
371end
372
373--- Splits a list of search results into two lists, one for "source" results 20--- Splits a list of search results into two lists, one for "source" results
374-- to be used with the "build" command, and one for "binary" results to be 21-- to be used with the "build" command, and one for "binary" results to be
375-- used with the "install" command. 22-- used with the "install" command.
@@ -385,69 +32,13 @@ local function split_source_and_binary_results(results)
385 if repo.arch == "all" or repo.arch == cfg.arch then 32 if repo.arch == "all" or repo.arch == cfg.arch then
386 where = binaries 33 where = binaries
387 end 34 end
388 store_result(where, name, version, repo.arch, repo.repo) 35 search.store_result(where, name, version, repo.arch, repo.repo)
389 end 36 end
390 end 37 end
391 end 38 end
392 return sources, binaries 39 return sources, binaries
393end 40end
394 41
395--- Given a name and optionally a version, try to find in the rocks
396-- servers a single .src.rock or .rockspec file that satisfies
397-- the request, and run the given function on it; or display to the
398-- user possibilities if it couldn't narrow down a single match.
399-- @param action function: A function that takes a .src.rock or
400-- .rockspec URL as a parameter.
401-- @param name string: A rock name
402-- @param version string or nil: A version number may also be given.
403-- @return The result of the action function, or nil and an error message.
404function search.act_on_src_or_rockspec(action, name, version, ...)
405 assert(type(action) == "function")
406 assert(type(name) == "string")
407 assert(type(version) == "string" or not version)
408
409 local query = search.make_query(name, version)
410 query.arch = "src|rockspec"
411 local url, err = search.find_suitable_rock(query)
412 if not url then
413 return nil, "Could not find a result named "..name..(version and " "..version or "")..": "..err
414 end
415 return action(url, ...)
416end
417
418function search.pick_installed_rock(name, version, given_tree)
419 local results = {}
420 local query = search.make_query(name, version)
421 query.exact_name = true
422 local tree_map = {}
423 local trees = cfg.rocks_trees
424 if given_tree then
425 trees = { given_tree }
426 end
427 for _, tree in ipairs(trees) do
428 local rocks_dir = path.rocks_dir(tree)
429 tree_map[rocks_dir] = tree
430 search.manifest_search(results, rocks_dir, query)
431 end
432
433 if not next(results) then --
434 return nil,"cannot find package "..name.." "..(version or "").."\nUse 'list' to find installed rocks."
435 end
436
437 version = nil
438 local repo_url
439 local package, versions = util.sortedpairs(results)()
440 --question: what do we do about multiple versions? This should
441 --give us the latest version on the last repo (which is usually the global one)
442 for vs, repositories in util.sortedpairs(versions, deps.compare_versions) do
443 if not version then version = vs end
444 for _, rp in ipairs(repositories) do repo_url = rp.repo end
445 end
446
447 local repo = tree_map[repo_url]
448 return name, version, repo, repo_url
449end
450
451--- Driver function for "search" command. 42--- Driver function for "search" command.
452-- @param name string: A substring of a rock name to search. 43-- @param name string: A substring of a rock name to search.
453-- @param version string or nil: a version may also be passed. 44-- @param version string or nil: a version may also be passed.