diff options
| author | Hisham <hisham@gobolinux.org> | 2016-10-28 20:59:42 -0200 |
|---|---|---|
| committer | Hisham <hisham@gobolinux.org> | 2016-10-28 20:59:42 -0200 |
| commit | 5c140a5da73d304653621a0ac40f363d234928ed (patch) | |
| tree | 5bf34d6c10e8d4bb692feb9589477ac08f7f4863 /src | |
| parent | 5bd20308b881c63dd886b71395dbc9baaab25dfd (diff) | |
| download | luarocks-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.lua | 347 | ||||
| -rw-r--r-- | src/luarocks/cmd/download.lua | 76 | ||||
| -rw-r--r-- | src/luarocks/cmd/pack.lua | 164 | ||||
| -rw-r--r-- | src/luarocks/cmd/remove.lua | 124 | ||||
| -rw-r--r-- | src/luarocks/cmd/search.lua | 411 |
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. |
| 4 | local build = {} | 4 | local cmd_build = {} |
| 5 | 5 | ||
| 6 | local pack = require("luarocks.pack") | 6 | local pack = require("luarocks.pack") |
| 7 | local path = require("luarocks.path") | 7 | local path = require("luarocks.path") |
| 8 | local util = require("luarocks.util") | 8 | local util = require("luarocks.util") |
| 9 | local repos = require("luarocks.repos") | ||
| 10 | local fetch = require("luarocks.fetch") | 9 | local fetch = require("luarocks.fetch") |
| 11 | local fs = require("luarocks.fs") | 10 | local fs = require("luarocks.fs") |
| 12 | local dir = require("luarocks.dir") | 11 | local dir = require("luarocks.dir") |
| 13 | local deps = require("luarocks.deps") | 12 | local deps = require("luarocks.deps") |
| 14 | local writer = require("luarocks.manif.writer") | ||
| 15 | local remove = require("luarocks.remove") | 13 | local remove = require("luarocks.remove") |
| 16 | local cfg = require("luarocks.core.cfg") | 14 | local cfg = require("luarocks.core.cfg") |
| 15 | local build = require("luarocks.build") | ||
| 17 | 16 | ||
| 18 | build.help_summary = "Build/compile a rock." | 17 | cmd_build.help_summary = "build/compile a rock." |
| 19 | build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" | 18 | cmd_build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" |
| 20 | build.help = [[ | 19 | cmd_build.help = [[ |
| 21 | Build and install a rock, compiling its C parts if any. | 20 | Build and install a rock, compiling its C parts if any. |
| 22 | Argument may be a rockspec file, a source rock file | 21 | Argument may be a rockspec file, a source rock file |
| 23 | or the name of a rock to be fetched from a repository. | 22 | or 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. | ||
| 58 | local 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 | ||
| 92 | end | ||
| 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. | ||
| 97 | local 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 | ||
| 103 | end | ||
| 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. | ||
| 111 | function 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 | ||
| 129 | end | ||
| 130 | |||
| 131 | local 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 | ||
| 147 | end | ||
| 148 | |||
| 149 | local 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 | ||
| 172 | end | ||
| 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. | ||
| 187 | function 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 | ||
| 362 | end | ||
| 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. |
| 374 | function build.build_rock(rock_file, need_to_fetch, deps_mode, build_only_deps) | 51 | local 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. |
| 418 | function build.command(flags, name, version) | 93 | function 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 |
| 441 | end | 116 | end |
| 442 | 117 | ||
| 443 | return build | 118 | return 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. |
| 4 | local download = {} | 4 | local cmd_download = {} |
| 5 | 5 | ||
| 6 | local util = require("luarocks.util") | 6 | local util = require("luarocks.util") |
| 7 | local path = require("luarocks.path") | 7 | local download = require("luarocks.download") |
| 8 | local fetch = require("luarocks.fetch") | ||
| 9 | local search = require("luarocks.search") | ||
| 10 | local fs = require("luarocks.fs") | ||
| 11 | local dir = require("luarocks.dir") | ||
| 12 | local cfg = require("luarocks.core.cfg") | ||
| 13 | 8 | ||
| 14 | download.help_summary = "Download a specific rock file from a rocks server." | 9 | cmd_download.help_summary = "Download a specific rock file from a rocks server." |
| 15 | download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" | 10 | cmd_download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" |
| 16 | 11 | cmd_download.help = [[ | |
| 17 | download.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 | ||
| 24 | local 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 | ||
| 36 | end | ||
| 37 | |||
| 38 | function 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 ".") | ||
| 78 | end | ||
| 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. |
| 86 | function download.command(flags, name, version) | 24 | function 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 |
| 105 | end | 43 | end |
| 106 | 44 | ||
| 107 | return download | 45 | return 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. |
| 4 | local pack = {} | 4 | local cmd_pack = {} |
| 5 | 5 | ||
| 6 | local unpack = unpack or table.unpack | ||
| 7 | |||
| 8 | local path = require("luarocks.path") | ||
| 9 | local repos = require("luarocks.repos") | ||
| 10 | local fetch = require("luarocks.fetch") | ||
| 11 | local fs = require("luarocks.fs") | ||
| 12 | local cfg = require("luarocks.core.cfg") | ||
| 13 | local util = require("luarocks.util") | 6 | local util = require("luarocks.util") |
| 14 | local dir = require("luarocks.dir") | 7 | local pack = require("luarocks.pack") |
| 15 | local manif = require("luarocks.manif") | ||
| 16 | local search = require("luarocks.search") | ||
| 17 | 8 | ||
| 18 | pack.help_summary = "Create a rock, packing sources or binaries." | 9 | cmd_pack.help_summary = "Create a rock, packing sources or binaries." |
| 19 | pack.help_arguments = "{<rockspec>|<name> [<version>]}" | 10 | cmd_pack.help_arguments = "{<rockspec>|<name> [<version>]}" |
| 20 | pack.help = [[ | 11 | cmd_pack.help = [[ |
| 21 | Argument may be a rockspec file, for creating a source rock, | 12 | Argument may be a rockspec file, for creating a source rock, |
| 22 | or the name of an installed package, for creating a binary rock. | 13 | or the name of an installed package, for creating a binary rock. |
| 23 | In the latter case, the app version may be given as a second | 14 | In the latter case, the app version may be given as a second |
| 24 | argument. | 15 | argument. |
| 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. | ||
| 34 | function 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 | ||
| 61 | end | ||
| 62 | |||
| 63 | local 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 | ||
| 82 | end | ||
| 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. | ||
| 89 | local 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 | ||
| 137 | end | ||
| 138 | |||
| 139 | function 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) | ||
| 164 | end | ||
| 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. |
| 173 | function pack.command(flags, arg, version) | 25 | function 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 |
| 191 | end | 43 | end |
| 192 | 44 | ||
| 193 | return pack | 45 | return 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. |
| 4 | local remove = {} | 4 | local cmd_remove = {} |
| 5 | 5 | ||
| 6 | local search = require("luarocks.search") | 6 | local remove = require("luarocks.remove") |
| 7 | local deps = require("luarocks.deps") | ||
| 8 | local fetch = require("luarocks.fetch") | ||
| 9 | local repos = require("luarocks.repos") | ||
| 10 | local path = require("luarocks.path") | ||
| 11 | local util = require("luarocks.util") | 7 | local util = require("luarocks.util") |
| 12 | local cfg = require("luarocks.core.cfg") | 8 | local cfg = require("luarocks.core.cfg") |
| 13 | local fs = require("luarocks.fs") | 9 | local fs = require("luarocks.fs") |
| 10 | local search = require("luarocks.search") | ||
| 11 | local path = require("luarocks.path") | ||
| 14 | 12 | ||
| 15 | remove.help_summary = "Uninstall a rock." | 13 | cmd_remove.help_summary = "Uninstall a rock." |
| 16 | remove.help_arguments = "[--force|--force-fast] <name> [<version>]" | 14 | cmd_remove.help_arguments = "[--force|--force-fast] <name> [<version>]" |
| 17 | remove.help = [[ | 15 | cmd_remove.help = [[ |
| 18 | Argument is the name of a rock to be uninstalled. | 16 | Argument is the name of a rock to be uninstalled. |
| 19 | If a version is not given, try to remove all versions at once. | 17 | If a version is not given, try to remove all versions at once. |
| 20 | Will only perform the removal if it does not break dependencies. | 18 | Will 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. | ||
| 33 | local 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 | ||
| 57 | end | ||
| 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. | ||
| 66 | local 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 | ||
| 75 | end | ||
| 76 | |||
| 77 | function 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 | ||
| 120 | end | ||
| 121 | |||
| 122 | function 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 | ||
| 129 | end | ||
| 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. |
| 138 | function remove.command(flags, name, version) | 32 | function 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"]) |
| 163 | end | 57 | end |
| 164 | 58 | ||
| 165 | return remove | 59 | return 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. |
| 4 | local search = {} | 4 | local search = {} |
| 5 | 5 | ||
| 6 | |||
| 7 | local dir = require("luarocks.dir") | ||
| 8 | local path = require("luarocks.path") | ||
| 9 | local manif = require("luarocks.manif") | ||
| 10 | local deps = require("luarocks.deps") | ||
| 11 | local cfg = require("luarocks.core.cfg") | 6 | local cfg = require("luarocks.core.cfg") |
| 12 | local util = require("luarocks.util") | 7 | local 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. | ||
| 27 | local 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 | ||
| 46 | end | ||
| 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. | ||
| 58 | local 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 | }) | ||
| 71 | end | ||
| 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. | ||
| 80 | local 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 | ||
| 88 | end | ||
| 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. | ||
| 107 | local 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 | ||
| 115 | end | ||
| 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. | ||
| 131 | function 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 | ||
| 158 | end | ||
| 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. | ||
| 174 | function 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 | ||
| 192 | end | ||
| 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". | ||
| 200 | function 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 | ||
| 232 | end | ||
| 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 | ||
| 238 | function 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 | ||
| 250 | end | ||
| 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. | ||
| 258 | local 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 | ||
| 280 | end | ||
| 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. | ||
| 285 | local 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 | ||
| 297 | end | ||
| 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. | ||
| 303 | function 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 | ||
| 343 | end | ||
| 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. | ||
| 349 | function 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 | ||
| 371 | end | ||
| 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 |
| 393 | end | 40 | end |
| 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. | ||
| 404 | function 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, ...) | ||
| 416 | end | ||
| 417 | |||
| 418 | function 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 | ||
| 449 | end | ||
| 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. |
