diff options
| author | Hisham <hisham@gobolinux.org> | 2016-10-28 20:15:15 -0200 |
|---|---|---|
| committer | Hisham <hisham@gobolinux.org> | 2016-10-28 20:15:15 -0200 |
| commit | 75902ff48a5bdc2cd00b492deb9f8aaa1d35bd3d (patch) | |
| tree | def839023a6520ad1c721d4ab955e29196770240 /src | |
| parent | 825e722029fbc93976c2d882dd21f444f9bffda0 (diff) | |
| download | luarocks-75902ff48a5bdc2cd00b492deb9f8aaa1d35bd3d.tar.gz luarocks-75902ff48a5bdc2cd00b492deb9f8aaa1d35bd3d.tar.bz2 luarocks-75902ff48a5bdc2cd00b492deb9f8aaa1d35bd3d.zip | |
Duplicate files to preserve git-blame
Diffstat (limited to 'src')
| -rw-r--r-- | src/luarocks/base/build.lua (renamed from src/luarocks/build.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/config_cmd.lua (renamed from src/luarocks/config_cmd.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/doc.lua (renamed from src/luarocks/doc.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/download.lua (renamed from src/luarocks/download.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/help.lua (renamed from src/luarocks/help.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/install.lua (renamed from src/luarocks/install.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/lint.lua (renamed from src/luarocks/lint.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/list.lua (renamed from src/luarocks/list.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/make.lua (renamed from src/luarocks/make.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/new_version.lua (renamed from src/luarocks/new_version.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/pack.lua (renamed from src/luarocks/pack.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/path_cmd.lua (renamed from src/luarocks/path_cmd.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/purge.lua (renamed from src/luarocks/purge.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/remove.lua (renamed from src/luarocks/remove.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/search.lua (renamed from src/luarocks/search.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/show.lua (renamed from src/luarocks/show.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/unpack.lua (renamed from src/luarocks/unpack.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/upload.lua (renamed from src/luarocks/upload.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/base/write_rockspec.lua (renamed from src/luarocks/write_rockspec.lua) | 0 | ||||
| -rw-r--r-- | src/luarocks/cmd/build.lua | 443 | ||||
| -rw-r--r-- | src/luarocks/cmd/config_cmd.lua | 71 | ||||
| -rw-r--r-- | src/luarocks/cmd/doc.lua | 155 | ||||
| -rw-r--r-- | src/luarocks/cmd/download.lua | 107 | ||||
| -rw-r--r-- | src/luarocks/cmd/help.lua | 117 | ||||
| -rw-r--r-- | src/luarocks/cmd/install.lua | 183 | ||||
| -rw-r--r-- | src/luarocks/cmd/lint.lua | 53 | ||||
| -rw-r--r-- | src/luarocks/cmd/list.lua | 95 | ||||
| -rw-r--r-- | src/luarocks/cmd/make.lua | 86 | ||||
| -rw-r--r-- | src/luarocks/cmd/new_version.lua | 199 | ||||
| -rw-r--r-- | src/luarocks/cmd/pack.lua | 193 | ||||
| -rw-r--r-- | src/luarocks/cmd/path_cmd.lua | 68 | ||||
| -rw-r--r-- | src/luarocks/cmd/purge.lua | 77 | ||||
| -rw-r--r-- | src/luarocks/cmd/remove.lua | 165 | ||||
| -rw-r--r-- | src/luarocks/cmd/search.lua | 482 | ||||
| -rw-r--r-- | src/luarocks/cmd/show.lua | 158 | ||||
| -rw-r--r-- | src/luarocks/cmd/unpack.lua | 164 | ||||
| -rw-r--r-- | src/luarocks/cmd/upload.lua | 94 | ||||
| -rw-r--r-- | src/luarocks/cmd/write_rockspec.lua | 376 |
38 files changed, 3286 insertions, 0 deletions
diff --git a/src/luarocks/build.lua b/src/luarocks/base/build.lua index f3b054d2..f3b054d2 100644 --- a/src/luarocks/build.lua +++ b/src/luarocks/base/build.lua | |||
diff --git a/src/luarocks/config_cmd.lua b/src/luarocks/base/config_cmd.lua index b68f7898..b68f7898 100644 --- a/src/luarocks/config_cmd.lua +++ b/src/luarocks/base/config_cmd.lua | |||
diff --git a/src/luarocks/doc.lua b/src/luarocks/base/doc.lua index 5d521276..5d521276 100644 --- a/src/luarocks/doc.lua +++ b/src/luarocks/base/doc.lua | |||
diff --git a/src/luarocks/download.lua b/src/luarocks/base/download.lua index 557d1b65..557d1b65 100644 --- a/src/luarocks/download.lua +++ b/src/luarocks/base/download.lua | |||
diff --git a/src/luarocks/help.lua b/src/luarocks/base/help.lua index d27c3a50..d27c3a50 100644 --- a/src/luarocks/help.lua +++ b/src/luarocks/base/help.lua | |||
diff --git a/src/luarocks/install.lua b/src/luarocks/base/install.lua index c9b085f5..c9b085f5 100644 --- a/src/luarocks/install.lua +++ b/src/luarocks/base/install.lua | |||
diff --git a/src/luarocks/lint.lua b/src/luarocks/base/lint.lua index c9ea45ea..c9ea45ea 100644 --- a/src/luarocks/lint.lua +++ b/src/luarocks/base/lint.lua | |||
diff --git a/src/luarocks/list.lua b/src/luarocks/base/list.lua index 45f1a26f..45f1a26f 100644 --- a/src/luarocks/list.lua +++ b/src/luarocks/base/list.lua | |||
diff --git a/src/luarocks/make.lua b/src/luarocks/base/make.lua index eb38bff0..eb38bff0 100644 --- a/src/luarocks/make.lua +++ b/src/luarocks/base/make.lua | |||
diff --git a/src/luarocks/new_version.lua b/src/luarocks/base/new_version.lua index b13dbb97..b13dbb97 100644 --- a/src/luarocks/new_version.lua +++ b/src/luarocks/base/new_version.lua | |||
diff --git a/src/luarocks/pack.lua b/src/luarocks/base/pack.lua index 655cbf37..655cbf37 100644 --- a/src/luarocks/pack.lua +++ b/src/luarocks/base/pack.lua | |||
diff --git a/src/luarocks/path_cmd.lua b/src/luarocks/base/path_cmd.lua index 516a0c47..516a0c47 100644 --- a/src/luarocks/path_cmd.lua +++ b/src/luarocks/base/path_cmd.lua | |||
diff --git a/src/luarocks/purge.lua b/src/luarocks/base/purge.lua index 50f290c8..50f290c8 100644 --- a/src/luarocks/purge.lua +++ b/src/luarocks/base/purge.lua | |||
diff --git a/src/luarocks/remove.lua b/src/luarocks/base/remove.lua index e7f37604..e7f37604 100644 --- a/src/luarocks/remove.lua +++ b/src/luarocks/base/remove.lua | |||
diff --git a/src/luarocks/search.lua b/src/luarocks/base/search.lua index 44eff694..44eff694 100644 --- a/src/luarocks/search.lua +++ b/src/luarocks/base/search.lua | |||
diff --git a/src/luarocks/show.lua b/src/luarocks/base/show.lua index 1ff81e08..1ff81e08 100644 --- a/src/luarocks/show.lua +++ b/src/luarocks/base/show.lua | |||
diff --git a/src/luarocks/unpack.lua b/src/luarocks/base/unpack.lua index c50701b0..c50701b0 100644 --- a/src/luarocks/unpack.lua +++ b/src/luarocks/base/unpack.lua | |||
diff --git a/src/luarocks/upload.lua b/src/luarocks/base/upload.lua index baee47ab..baee47ab 100644 --- a/src/luarocks/upload.lua +++ b/src/luarocks/base/upload.lua | |||
diff --git a/src/luarocks/write_rockspec.lua b/src/luarocks/base/write_rockspec.lua index be563eaa..be563eaa 100644 --- a/src/luarocks/write_rockspec.lua +++ b/src/luarocks/base/write_rockspec.lua | |||
diff --git a/src/luarocks/cmd/build.lua b/src/luarocks/cmd/build.lua new file mode 100644 index 00000000..f3b054d2 --- /dev/null +++ b/src/luarocks/cmd/build.lua | |||
| @@ -0,0 +1,443 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "build" command. | ||
| 3 | -- Builds a rock, compiling its C parts if any. | ||
| 4 | local build = {} | ||
| 5 | |||
| 6 | local pack = require("luarocks.pack") | ||
| 7 | local path = require("luarocks.path") | ||
| 8 | local util = require("luarocks.util") | ||
| 9 | local repos = require("luarocks.repos") | ||
| 10 | local fetch = require("luarocks.fetch") | ||
| 11 | local fs = require("luarocks.fs") | ||
| 12 | local dir = require("luarocks.dir") | ||
| 13 | local deps = require("luarocks.deps") | ||
| 14 | local writer = require("luarocks.manif.writer") | ||
| 15 | local remove = require("luarocks.remove") | ||
| 16 | local cfg = require("luarocks.core.cfg") | ||
| 17 | |||
| 18 | build.help_summary = "Build/compile a rock." | ||
| 19 | build.help_arguments = "[--pack-binary-rock] [--keep] {<rockspec>|<rock>|<name> [<version>]}" | ||
| 20 | build.help = [[ | ||
| 21 | Build and install a rock, compiling its C parts if any. | ||
| 22 | Argument may be a rockspec file, a source rock file | ||
| 23 | or the name of a rock to be fetched from a repository. | ||
| 24 | |||
| 25 | --pack-binary-rock Do not install rock. Instead, produce a .rock file | ||
| 26 | with the contents of compilation in the current | ||
| 27 | directory. | ||
| 28 | |||
| 29 | --keep Do not remove previously installed versions of the | ||
| 30 | rock after building a new one. This behavior can | ||
| 31 | be made permanent by setting keep_other_versions=true | ||
| 32 | in the configuration file. | ||
| 33 | |||
| 34 | --branch=<name> Override the `source.branch` field in the loaded | ||
| 35 | rockspec. Allows to specify a different branch to | ||
| 36 | fetch. Particularly for SCM rocks. | ||
| 37 | |||
| 38 | --only-deps Installs only the dependencies of the rock. | ||
| 39 | |||
| 40 | ]]..util.deps_mode_help() | ||
| 41 | |||
| 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. | ||
| 365 | -- @param rock_file string: local or remote filename of a rock. | ||
| 366 | -- @param need_to_fetch boolean: true if sources need to be fetched, | ||
| 367 | -- false if the rockspec was obtained from inside a source rock. | ||
| 368 | -- @param deps_mode: string: Which trees to check dependencies for: | ||
| 369 | -- "one" for the current default tree, "all" for all trees, | ||
| 370 | -- "order" for all trees with priority >= the current default, "none" for no trees. | ||
| 371 | -- @param build_only_deps boolean: true to build the listed dependencies only. | ||
| 372 | -- @return boolean or (nil, string, [string]): True if build was successful, | ||
| 373 | -- 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) | ||
| 375 | assert(type(rock_file) == "string") | ||
| 376 | assert(type(need_to_fetch) == "boolean") | ||
| 377 | |||
| 378 | local ok, err, errcode | ||
| 379 | local unpack_dir | ||
| 380 | unpack_dir, err, errcode = fetch.fetch_and_unpack_rock(rock_file) | ||
| 381 | if not unpack_dir then | ||
| 382 | return nil, err, errcode | ||
| 383 | end | ||
| 384 | local rockspec_file = path.rockspec_name_from_rock(rock_file) | ||
| 385 | ok, err = fs.change_dir(unpack_dir) | ||
| 386 | if not ok then return nil, err end | ||
| 387 | ok, err, errcode = build.build_rockspec(rockspec_file, need_to_fetch, false, deps_mode, build_only_deps) | ||
| 388 | fs.pop_dir() | ||
| 389 | return ok, err, errcode | ||
| 390 | end | ||
| 391 | |||
| 392 | local function do_build(name, version, deps_mode, build_only_deps) | ||
| 393 | if name:match("%.rockspec$") then | ||
| 394 | return build.build_rockspec(name, true, false, deps_mode, build_only_deps) | ||
| 395 | elseif name:match("%.src%.rock$") then | ||
| 396 | return build.build_rock(name, false, deps_mode, build_only_deps) | ||
| 397 | elseif name:match("%.all%.rock$") then | ||
| 398 | local install = require("luarocks.install") | ||
| 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 | ||
| 402 | return build.build_rock(name, true, deps_mode, build_only_deps) | ||
| 403 | elseif not name:match(dir.separator) then | ||
| 404 | local search = require("luarocks.search") | ||
| 405 | return search.act_on_src_or_rockspec(do_build, name:lower(), version, nil, deps_mode, build_only_deps) | ||
| 406 | end | ||
| 407 | return nil, "Don't know what to do with "..name | ||
| 408 | end | ||
| 409 | |||
| 410 | --- Driver function for "build" command. | ||
| 411 | -- @param name string: A local or remote rockspec or rock file. | ||
| 412 | -- If a package name is given, forwards the request to "search" and, | ||
| 413 | -- if returned a result, installs the matching rock. | ||
| 414 | -- @param version string: When passing a package name, a version number may | ||
| 415 | -- also be given. | ||
| 416 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an | ||
| 417 | -- error message otherwise. exitcode is optionally returned. | ||
| 418 | function build.command(flags, name, version) | ||
| 419 | if type(name) ~= "string" then | ||
| 420 | return nil, "Argument missing. "..util.see_help("build") | ||
| 421 | end | ||
| 422 | assert(type(version) == "string" or not version) | ||
| 423 | |||
| 424 | if flags["pack-binary-rock"] then | ||
| 425 | return pack.pack_binary_rock(name, version, do_build, name, version, deps.get_deps_mode(flags)) | ||
| 426 | else | ||
| 427 | local ok, err = fs.check_command_permissions(flags) | ||
| 428 | if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end | ||
| 429 | ok, err = do_build(name, version, deps.get_deps_mode(flags), flags["only-deps"]) | ||
| 430 | if not ok then return nil, err end | ||
| 431 | name, version = ok, err | ||
| 432 | if flags["only-deps"] then | ||
| 433 | return name, version | ||
| 434 | end | ||
| 435 | if (not flags["keep"]) and not cfg.keep_other_versions then | ||
| 436 | local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) | ||
| 437 | if not ok then util.printerr(err) end | ||
| 438 | end | ||
| 439 | return name, version | ||
| 440 | end | ||
| 441 | end | ||
| 442 | |||
| 443 | return build | ||
diff --git a/src/luarocks/cmd/config_cmd.lua b/src/luarocks/cmd/config_cmd.lua new file mode 100644 index 00000000..b68f7898 --- /dev/null +++ b/src/luarocks/cmd/config_cmd.lua | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | --- Module implementing the LuaRocks "config" command. | ||
| 2 | -- Queries information about the LuaRocks configuration. | ||
| 3 | local config_cmd = {} | ||
| 4 | |||
| 5 | local cfg = require("luarocks.core.cfg") | ||
| 6 | local util = require("luarocks.util") | ||
| 7 | local dir = require("luarocks.dir") | ||
| 8 | |||
| 9 | config_cmd.help_summary = "Query information about the LuaRocks configuration." | ||
| 10 | config_cmd.help_arguments = "<flag>" | ||
| 11 | config_cmd.help = [[ | ||
| 12 | --lua-incdir Path to Lua header files. | ||
| 13 | |||
| 14 | --lua-libdir Path to Lua library files. | ||
| 15 | |||
| 16 | --lua-ver Lua version (in major.minor format). e.g. 5.1 | ||
| 17 | |||
| 18 | --system-config Location of the system config file. | ||
| 19 | |||
| 20 | --user-config Location of the user config file. | ||
| 21 | |||
| 22 | --rock-trees Rocks trees in use. First the user tree, then the system tree. | ||
| 23 | ]] | ||
| 24 | |||
| 25 | local function config_file(conf) | ||
| 26 | print(dir.normalize(conf.file)) | ||
| 27 | if conf.ok then | ||
| 28 | return true | ||
| 29 | else | ||
| 30 | return nil, "file not found" | ||
| 31 | end | ||
| 32 | end | ||
| 33 | |||
| 34 | --- Driver function for "config" command. | ||
| 35 | -- @return boolean: True if succeeded, nil on errors. | ||
| 36 | function config_cmd.command(flags) | ||
| 37 | if flags["lua-incdir"] then | ||
| 38 | print(cfg.variables.LUA_INCDIR) | ||
| 39 | return true | ||
| 40 | end | ||
| 41 | if flags["lua-libdir"] then | ||
| 42 | print(cfg.variables.LUA_LIBDIR) | ||
| 43 | return true | ||
| 44 | end | ||
| 45 | if flags["lua-ver"] then | ||
| 46 | print(cfg.lua_version) | ||
| 47 | return true | ||
| 48 | end | ||
| 49 | local conf = cfg.which_config() | ||
| 50 | if flags["system-config"] then | ||
| 51 | return config_file(conf.system) | ||
| 52 | end | ||
| 53 | if flags["user-config"] then | ||
| 54 | return config_file(conf.user) | ||
| 55 | end | ||
| 56 | if flags["rock-trees"] then | ||
| 57 | for _, tree in ipairs(cfg.rocks_trees) do | ||
| 58 | if type(tree) == "string" then | ||
| 59 | util.printout(dir.normalize(tree)) | ||
| 60 | else | ||
| 61 | local name = tree.name and "\t"..tree.name or "" | ||
| 62 | util.printout(dir.normalize(tree.root)..name) | ||
| 63 | end | ||
| 64 | end | ||
| 65 | return true | ||
| 66 | end | ||
| 67 | |||
| 68 | return nil, "Please provide a flag for querying configuration values. "..util.see_help("config") | ||
| 69 | end | ||
| 70 | |||
| 71 | return config_cmd | ||
diff --git a/src/luarocks/cmd/doc.lua b/src/luarocks/cmd/doc.lua new file mode 100644 index 00000000..5d521276 --- /dev/null +++ b/src/luarocks/cmd/doc.lua | |||
| @@ -0,0 +1,155 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "doc" command. | ||
| 3 | -- Shows documentation for an installed rock. | ||
| 4 | local doc = {} | ||
| 5 | |||
| 6 | local util = require("luarocks.util") | ||
| 7 | local search = require("luarocks.search") | ||
| 8 | local path = require("luarocks.path") | ||
| 9 | local dir = require("luarocks.dir") | ||
| 10 | local fetch = require("luarocks.fetch") | ||
| 11 | local fs = require("luarocks.fs") | ||
| 12 | local download = require("luarocks.download") | ||
| 13 | |||
| 14 | doc.help_summary = "Show documentation for an installed rock." | ||
| 15 | |||
| 16 | doc.help = [[ | ||
| 17 | <argument> is an existing package name. | ||
| 18 | Without any flags, tries to load the documentation | ||
| 19 | using a series of heuristics. | ||
| 20 | With these flags, return only the desired information: | ||
| 21 | |||
| 22 | --home Open the home page of project. | ||
| 23 | --list List documentation files only. | ||
| 24 | |||
| 25 | For more information about a rock, see the 'show' command. | ||
| 26 | ]] | ||
| 27 | |||
| 28 | local function show_homepage(homepage, name, version) | ||
| 29 | if not homepage then | ||
| 30 | return nil, "No 'homepage' field in rockspec for "..name.." "..version | ||
| 31 | end | ||
| 32 | util.printout("Opening "..homepage.." ...") | ||
| 33 | fs.browser(homepage) | ||
| 34 | return true | ||
| 35 | end | ||
| 36 | |||
| 37 | local function try_to_open_homepage(name, version) | ||
| 38 | local temp_dir, err = fs.make_temp_dir("doc-"..name.."-"..(version or "")) | ||
| 39 | if not temp_dir then | ||
| 40 | return nil, "Failed creating temporary directory: "..err | ||
| 41 | end | ||
| 42 | util.schedule_function(fs.delete, temp_dir) | ||
| 43 | local ok, err = fs.change_dir(temp_dir) | ||
| 44 | if not ok then return nil, err end | ||
| 45 | local filename, err = download.download("rockspec", name, version) | ||
| 46 | if not filename then return nil, err end | ||
| 47 | local rockspec, err = fetch.load_local_rockspec(filename) | ||
| 48 | if not rockspec then return nil, err end | ||
| 49 | fs.pop_dir() | ||
| 50 | local descript = rockspec.description or {} | ||
| 51 | if not descript.homepage then return nil, "No homepage defined for "..name end | ||
| 52 | return show_homepage(descript.homepage, name, version) | ||
| 53 | end | ||
| 54 | |||
| 55 | --- Driver function for "doc" command. | ||
| 56 | -- @param name or nil: an existing package name. | ||
| 57 | -- @param version string or nil: a version may also be passed. | ||
| 58 | -- @return boolean: True if succeeded, nil on errors. | ||
| 59 | function doc.command(flags, name, version) | ||
| 60 | if not name then | ||
| 61 | return nil, "Argument missing. "..util.see_help("doc") | ||
| 62 | end | ||
| 63 | |||
| 64 | name = name:lower() | ||
| 65 | |||
| 66 | local iname, iversion, repo = search.pick_installed_rock(name, version, flags["tree"]) | ||
| 67 | if not iname then | ||
| 68 | util.printout(name..(version and " "..version or "").." is not installed. Looking for it in the rocks servers...") | ||
| 69 | return try_to_open_homepage(name, version) | ||
| 70 | end | ||
| 71 | name, version = iname, iversion | ||
| 72 | |||
| 73 | local rockspec, err = fetch.load_local_rockspec(path.rockspec_file(name, version, repo)) | ||
| 74 | if not rockspec then return nil,err end | ||
| 75 | local descript = rockspec.description or {} | ||
| 76 | |||
| 77 | if flags["home"] then | ||
| 78 | return show_homepage(descript.homepage, name, version) | ||
| 79 | end | ||
| 80 | |||
| 81 | local directory = path.install_dir(name,version,repo) | ||
| 82 | |||
| 83 | local docdir | ||
| 84 | local directories = { "doc", "docs" } | ||
| 85 | for _, d in ipairs(directories) do | ||
| 86 | local dirname = dir.path(directory, d) | ||
| 87 | if fs.is_dir(dirname) then | ||
| 88 | docdir = dirname | ||
| 89 | break | ||
| 90 | end | ||
| 91 | end | ||
| 92 | if not docdir then | ||
| 93 | if descript.homepage and not flags["list"] then | ||
| 94 | util.printout("Local documentation directory not found -- opening "..descript.homepage.." ...") | ||
| 95 | fs.browser(descript.homepage) | ||
| 96 | return true | ||
| 97 | end | ||
| 98 | return nil, "Documentation directory not found for "..name.." "..version | ||
| 99 | end | ||
| 100 | |||
| 101 | docdir = dir.normalize(docdir):gsub("/+", "/") | ||
| 102 | local files = fs.find(docdir) | ||
| 103 | local htmlpatt = "%.html?$" | ||
| 104 | local extensions = { htmlpatt, "%.md$", "%.txt$", "%.textile$", "" } | ||
| 105 | local basenames = { "index", "readme", "manual" } | ||
| 106 | |||
| 107 | local porcelain = flags["porcelain"] | ||
| 108 | if #files > 0 then | ||
| 109 | util.title("Documentation files for "..name.." "..version, porcelain) | ||
| 110 | if porcelain then | ||
| 111 | for _, file in ipairs(files) do | ||
| 112 | util.printout(docdir.."/"..file) | ||
| 113 | end | ||
| 114 | else | ||
| 115 | util.printout(docdir.."/") | ||
| 116 | for _, file in ipairs(files) do | ||
| 117 | util.printout("\t"..file) | ||
| 118 | end | ||
| 119 | end | ||
| 120 | end | ||
| 121 | |||
| 122 | if flags["list"] then | ||
| 123 | return true | ||
| 124 | end | ||
| 125 | |||
| 126 | for _, extension in ipairs(extensions) do | ||
| 127 | for _, basename in ipairs(basenames) do | ||
| 128 | local filename = basename..extension | ||
| 129 | local found | ||
| 130 | for _, file in ipairs(files) do | ||
| 131 | if file:lower():match(filename) and ((not found) or #file < #found) then | ||
| 132 | found = file | ||
| 133 | end | ||
| 134 | end | ||
| 135 | if found then | ||
| 136 | local pathname = dir.path(docdir, found) | ||
| 137 | util.printout() | ||
| 138 | util.printout("Opening "..pathname.." ...") | ||
| 139 | util.printout() | ||
| 140 | local ok = fs.browser(pathname) | ||
| 141 | if not ok and not pathname:match(htmlpatt) then | ||
| 142 | local fd = io.open(pathname, "r") | ||
| 143 | util.printout(fd:read("*a")) | ||
| 144 | fd:close() | ||
| 145 | end | ||
| 146 | return true | ||
| 147 | end | ||
| 148 | end | ||
| 149 | end | ||
| 150 | |||
| 151 | return true | ||
| 152 | end | ||
| 153 | |||
| 154 | |||
| 155 | return doc | ||
diff --git a/src/luarocks/cmd/download.lua b/src/luarocks/cmd/download.lua new file mode 100644 index 00000000..557d1b65 --- /dev/null +++ b/src/luarocks/cmd/download.lua | |||
| @@ -0,0 +1,107 @@ | |||
| 1 | |||
| 2 | --- Module implementing the luarocks "download" command. | ||
| 3 | -- Download a rock from the repository. | ||
| 4 | local download = {} | ||
| 5 | |||
| 6 | local util = require("luarocks.util") | ||
| 7 | local path = require("luarocks.path") | ||
| 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 | |||
| 14 | download.help_summary = "Download a specific rock file from a rocks server." | ||
| 15 | download.help_arguments = "[--all] [--arch=<arch> | --source | --rockspec] [<name> [<version>]]" | ||
| 16 | |||
| 17 | download.help = [[ | ||
| 18 | --all Download all files if there are multiple matches. | ||
| 19 | --source Download .src.rock if available. | ||
| 20 | --rockspec Download .rockspec if available. | ||
| 21 | --arch=<arch> Download rock for a specific architecture. | ||
| 22 | ]] | ||
| 23 | |||
| 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. | ||
| 81 | -- @param name string: a rock name. | ||
| 82 | -- @param version string or nil: if the name of a package is given, a | ||
| 83 | -- version may also be passed. | ||
| 84 | -- @return boolean or (nil, string): true if successful or nil followed | ||
| 85 | -- by an error message. | ||
| 86 | function download.command(flags, name, version) | ||
| 87 | assert(type(version) == "string" or not version) | ||
| 88 | if type(name) ~= "string" and not flags["all"] then | ||
| 89 | return nil, "Argument missing. "..util.see_help("download") | ||
| 90 | end | ||
| 91 | if not name then name, version = "", "" end | ||
| 92 | |||
| 93 | local arch | ||
| 94 | |||
| 95 | if flags["source"] then | ||
| 96 | arch = "src" | ||
| 97 | elseif flags["rockspec"] then | ||
| 98 | arch = "rockspec" | ||
| 99 | elseif flags["arch"] then | ||
| 100 | arch = flags["arch"] | ||
| 101 | end | ||
| 102 | |||
| 103 | local dl, err = download.download(arch, name:lower(), version, flags["all"]) | ||
| 104 | return dl and true, err | ||
| 105 | end | ||
| 106 | |||
| 107 | return download | ||
diff --git a/src/luarocks/cmd/help.lua b/src/luarocks/cmd/help.lua new file mode 100644 index 00000000..d27c3a50 --- /dev/null +++ b/src/luarocks/cmd/help.lua | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "help" command. | ||
| 3 | -- This is a generic help display module, which | ||
| 4 | -- uses a global table called "commands" to find commands | ||
| 5 | -- to show help for; each command should be represented by a | ||
| 6 | -- table containing "help" and "help_summary" fields. | ||
| 7 | local help = {} | ||
| 8 | |||
| 9 | local util = require("luarocks.util") | ||
| 10 | local cfg = require("luarocks.core.cfg") | ||
| 11 | local dir = require("luarocks.dir") | ||
| 12 | |||
| 13 | local program = util.this_program("luarocks") | ||
| 14 | |||
| 15 | help.help_summary = "Help on commands. Type '"..program.." help <command>' for more." | ||
| 16 | |||
| 17 | help.help_arguments = "[<command>]" | ||
| 18 | help.help = [[ | ||
| 19 | <command> is the command to show help for. | ||
| 20 | ]] | ||
| 21 | |||
| 22 | local function print_banner() | ||
| 23 | util.printout("\nLuaRocks "..cfg.program_version..", a module deployment system for Lua") | ||
| 24 | end | ||
| 25 | |||
| 26 | local function print_section(section) | ||
| 27 | util.printout("\n"..section) | ||
| 28 | end | ||
| 29 | |||
| 30 | local function get_status(status) | ||
| 31 | if status then | ||
| 32 | return "ok" | ||
| 33 | else | ||
| 34 | return "not found" | ||
| 35 | end | ||
| 36 | end | ||
| 37 | |||
| 38 | --- Driver function for the "help" command. | ||
| 39 | -- @param command string or nil: command to show help for; if not | ||
| 40 | -- given, help summaries for all commands are shown. | ||
| 41 | -- @return boolean or (nil, string): true if there were no errors | ||
| 42 | -- or nil and an error message if an invalid command was requested. | ||
| 43 | function help.command(flags, command) | ||
| 44 | if not command then | ||
| 45 | local conf = cfg.which_config() | ||
| 46 | print_banner() | ||
| 47 | print_section("NAME") | ||
| 48 | util.printout("\t"..program..[[ - ]]..program_description) | ||
| 49 | print_section("SYNOPSIS") | ||
| 50 | util.printout("\t"..program..[[ [--from=<server> | --only-from=<server>] [--to=<tree>] [VAR=VALUE]... <command> [<argument>] ]]) | ||
| 51 | print_section("GENERAL OPTIONS") | ||
| 52 | util.printout([[ | ||
| 53 | These apply to all commands, as appropriate: | ||
| 54 | |||
| 55 | --server=<server> Fetch rocks/rockspecs from this server | ||
| 56 | (takes priority over config file) | ||
| 57 | --only-server=<server> Fetch rocks/rockspecs from this server only | ||
| 58 | (overrides any entries in the config file) | ||
| 59 | --only-sources=<url> Restrict downloads to paths matching the | ||
| 60 | given URL. | ||
| 61 | --tree=<tree> Which tree to operate on. | ||
| 62 | --local Use the tree in the user's home directory. | ||
| 63 | To enable it, see ']]..program..[[ help path'. | ||
| 64 | --verbose Display verbose output of commands executed. | ||
| 65 | --timeout=<seconds> Timeout on network operations, in seconds. | ||
| 66 | 0 means no timeout (wait forever). | ||
| 67 | Default is ]]..tostring(cfg.connection_timeout)..[[.]]) | ||
| 68 | print_section("VARIABLES") | ||
| 69 | util.printout([[ | ||
| 70 | Variables from the "variables" table of the configuration file | ||
| 71 | can be overriden with VAR=VALUE assignments.]]) | ||
| 72 | print_section("COMMANDS") | ||
| 73 | for name, command in util.sortedpairs(commands) do | ||
| 74 | local cmd = require(command) | ||
| 75 | util.printout("", name) | ||
| 76 | util.printout("\t", cmd.help_summary) | ||
| 77 | end | ||
| 78 | print_section("CONFIGURATION") | ||
| 79 | util.printout("\tLua version: " .. cfg.lua_version) | ||
| 80 | util.printout("\tConfiguration files:") | ||
| 81 | util.printout("\t\tSystem: ".. dir.normalize(conf.system.file) .. " (" .. get_status(conf.system.ok) ..")") | ||
| 82 | if conf.user.file then | ||
| 83 | util.printout("\t\tUser : ".. dir.normalize(conf.user.file) .. " (" .. get_status(conf.user.ok) ..")\n") | ||
| 84 | else | ||
| 85 | util.printout("\t\tUser : disabled in this LuaRocks installation.\n") | ||
| 86 | end | ||
| 87 | util.printout("\tRocks trees in use: ") | ||
| 88 | for _, tree in ipairs(cfg.rocks_trees) do | ||
| 89 | if type(tree) == "string" then | ||
| 90 | util.printout("\t\t"..dir.normalize(tree)) | ||
| 91 | else | ||
| 92 | local name = tree.name and " (\""..tree.name.."\")" or "" | ||
| 93 | util.printout("\t\t"..dir.normalize(tree.root)..name) | ||
| 94 | end | ||
| 95 | end | ||
| 96 | else | ||
| 97 | command = command:gsub("-", "_") | ||
| 98 | local cmd = commands[command] and require(commands[command]) | ||
| 99 | if cmd then | ||
| 100 | local arguments = cmd.help_arguments or "<argument>" | ||
| 101 | print_banner() | ||
| 102 | print_section("NAME") | ||
| 103 | util.printout("\t"..program.." "..command.." - "..cmd.help_summary) | ||
| 104 | print_section("SYNOPSIS") | ||
| 105 | util.printout("\t"..program.." "..command.." "..arguments) | ||
| 106 | print_section("DESCRIPTION") | ||
| 107 | util.printout("",(cmd.help:gsub("\n","\n\t"):gsub("\n\t$",""))) | ||
| 108 | print_section("SEE ALSO") | ||
| 109 | util.printout("","'"..program.." help' for general options and configuration.\n") | ||
| 110 | else | ||
| 111 | return nil, "Unknown command: "..command | ||
| 112 | end | ||
| 113 | end | ||
| 114 | return true | ||
| 115 | end | ||
| 116 | |||
| 117 | return help | ||
diff --git a/src/luarocks/cmd/install.lua b/src/luarocks/cmd/install.lua new file mode 100644 index 00000000..c9b085f5 --- /dev/null +++ b/src/luarocks/cmd/install.lua | |||
| @@ -0,0 +1,183 @@ | |||
| 1 | --- Module implementing the LuaRocks "install" command. | ||
| 2 | -- Installs binary rocks. | ||
| 3 | local install = {} | ||
| 4 | |||
| 5 | local path = require("luarocks.path") | ||
| 6 | local repos = require("luarocks.repos") | ||
| 7 | local fetch = require("luarocks.fetch") | ||
| 8 | local util = require("luarocks.util") | ||
| 9 | local fs = require("luarocks.fs") | ||
| 10 | local deps = require("luarocks.deps") | ||
| 11 | local writer = require("luarocks.manif.writer") | ||
| 12 | local remove = require("luarocks.remove") | ||
| 13 | local cfg = require("luarocks.core.cfg") | ||
| 14 | |||
| 15 | install.help_summary = "Install a rock." | ||
| 16 | |||
| 17 | install.help_arguments = "{<rock>|<name> [<version>]}" | ||
| 18 | |||
| 19 | install.help = [[ | ||
| 20 | Argument may be the name of a rock to be fetched from a repository | ||
| 21 | or a filename of a locally available rock. | ||
| 22 | |||
| 23 | --keep Do not remove previously installed versions of the | ||
| 24 | rock after installing a new one. This behavior can | ||
| 25 | be made permanent by setting keep_other_versions=true | ||
| 26 | in the configuration file. | ||
| 27 | |||
| 28 | --only-deps Installs only the dependencies of the rock. | ||
| 29 | ]]..util.deps_mode_help() | ||
| 30 | |||
| 31 | |||
| 32 | --- Install a binary rock. | ||
| 33 | -- @param rock_file string: local or remote filename of a rock. | ||
| 34 | -- @param deps_mode: string: Which trees to check dependencies for: | ||
| 35 | -- "one" for the current default tree, "all" for all trees, | ||
| 36 | -- "order" for all trees with priority >= the current default, "none" for no trees. | ||
| 37 | -- @return (string, string) or (nil, string, [string]): Name and version of | ||
| 38 | -- installed rock if succeeded or nil and an error message followed by an error code. | ||
| 39 | function install.install_binary_rock(rock_file, deps_mode) | ||
| 40 | assert(type(rock_file) == "string") | ||
| 41 | |||
| 42 | local name, version, arch = path.parse_name(rock_file) | ||
| 43 | if not name then | ||
| 44 | return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." | ||
| 45 | end | ||
| 46 | |||
| 47 | if arch ~= "all" and arch ~= cfg.arch then | ||
| 48 | return nil, "Incompatible architecture "..arch, "arch" | ||
| 49 | end | ||
| 50 | if repos.is_installed(name, version) then | ||
| 51 | repos.delete_version(name, version, deps_mode) | ||
| 52 | end | ||
| 53 | |||
| 54 | local rollback = util.schedule_function(function() | ||
| 55 | fs.delete(path.install_dir(name, version)) | ||
| 56 | fs.remove_dir_if_empty(path.versions_dir(name)) | ||
| 57 | end) | ||
| 58 | |||
| 59 | local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) | ||
| 60 | if not ok then return nil, err, errcode end | ||
| 61 | |||
| 62 | local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) | ||
| 63 | if err then | ||
| 64 | return nil, "Failed loading rockspec for installed package: "..err, errcode | ||
| 65 | end | ||
| 66 | |||
| 67 | if deps_mode == "none" then | ||
| 68 | util.printerr("Warning: skipping dependency checks.") | ||
| 69 | else | ||
| 70 | ok, err, errcode = deps.check_external_deps(rockspec, "install") | ||
| 71 | if err then return nil, err, errcode end | ||
| 72 | end | ||
| 73 | |||
| 74 | -- For compatibility with .rock files built with LuaRocks 1 | ||
| 75 | if not fs.exists(path.rock_manifest_file(name, version)) then | ||
| 76 | ok, err = writer.make_rock_manifest(name, version) | ||
| 77 | if err then return nil, err end | ||
| 78 | end | ||
| 79 | |||
| 80 | if deps_mode ~= "none" then | ||
| 81 | ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) | ||
| 82 | if err then return nil, err, errcode end | ||
| 83 | end | ||
| 84 | |||
| 85 | ok, err = repos.deploy_files(name, version, repos.should_wrap_bin_scripts(rockspec), deps_mode) | ||
| 86 | if err then return nil, err end | ||
| 87 | |||
| 88 | util.remove_scheduled_function(rollback) | ||
| 89 | rollback = util.schedule_function(function() | ||
| 90 | repos.delete_version(name, version, deps_mode) | ||
| 91 | end) | ||
| 92 | |||
| 93 | ok, err = repos.run_hook(rockspec, "post_install") | ||
| 94 | if err then return nil, err end | ||
| 95 | |||
| 96 | util.announce_install(rockspec) | ||
| 97 | util.remove_scheduled_function(rollback) | ||
| 98 | return name, version | ||
| 99 | end | ||
| 100 | |||
| 101 | --- Installs the dependencies of a binary rock. | ||
| 102 | -- @param rock_file string: local or remote filename of a rock. | ||
| 103 | -- @param deps_mode: string: Which trees to check dependencies for: | ||
| 104 | -- "one" for the current default tree, "all" for all trees, | ||
| 105 | -- "order" for all trees with priority >= the current default, "none" for no trees. | ||
| 106 | -- @return (string, string) or (nil, string, [string]): Name and version of | ||
| 107 | -- the rock whose dependencies were installed if succeeded or nil and an error message | ||
| 108 | -- followed by an error code. | ||
| 109 | function install.install_binary_rock_deps(rock_file, deps_mode) | ||
| 110 | assert(type(rock_file) == "string") | ||
| 111 | |||
| 112 | local name, version, arch = path.parse_name(rock_file) | ||
| 113 | if not name then | ||
| 114 | return nil, "Filename "..rock_file.." does not match format 'name-version-revision.arch.rock'." | ||
| 115 | end | ||
| 116 | |||
| 117 | if arch ~= "all" and arch ~= cfg.arch then | ||
| 118 | return nil, "Incompatible architecture "..arch, "arch" | ||
| 119 | end | ||
| 120 | |||
| 121 | local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, path.install_dir(name, version)) | ||
| 122 | if not ok then return nil, err, errcode end | ||
| 123 | |||
| 124 | local rockspec, err, errcode = fetch.load_rockspec(path.rockspec_file(name, version)) | ||
| 125 | if err then | ||
| 126 | return nil, "Failed loading rockspec for installed package: "..err, errcode | ||
| 127 | end | ||
| 128 | |||
| 129 | ok, err, errcode = deps.fulfill_dependencies(rockspec, deps_mode) | ||
| 130 | if err then return nil, err, errcode end | ||
| 131 | |||
| 132 | util.printout() | ||
| 133 | util.printout("Successfully installed dependencies for " ..name.." "..version) | ||
| 134 | |||
| 135 | return name, version | ||
| 136 | end | ||
| 137 | |||
| 138 | --- Driver function for the "install" command. | ||
| 139 | -- @param name string: name of a binary rock. If an URL or pathname | ||
| 140 | -- to a binary rock is given, fetches and installs it. If a rockspec or a | ||
| 141 | -- source rock is given, forwards the request to the "build" command. | ||
| 142 | -- If a package name is given, forwards the request to "search" and, | ||
| 143 | -- if returned a result, installs the matching rock. | ||
| 144 | -- @param version string: When passing a package name, a version number | ||
| 145 | -- may also be given. | ||
| 146 | -- @return boolean or (nil, string, exitcode): True if installation was | ||
| 147 | -- successful, nil and an error message otherwise. exitcode is optionally returned. | ||
| 148 | function install.command(flags, name, version) | ||
| 149 | if type(name) ~= "string" then | ||
| 150 | return nil, "Argument missing. "..util.see_help("install") | ||
| 151 | end | ||
| 152 | |||
| 153 | local ok, err = fs.check_command_permissions(flags) | ||
| 154 | if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end | ||
| 155 | |||
| 156 | if name:match("%.rockspec$") or name:match("%.src%.rock$") then | ||
| 157 | local build = require("luarocks.build") | ||
| 158 | return build.command(flags, name) | ||
| 159 | elseif name:match("%.rock$") then | ||
| 160 | if flags["only-deps"] then | ||
| 161 | ok, err = install.install_binary_rock_deps(name, deps.get_deps_mode(flags)) | ||
| 162 | else | ||
| 163 | ok, err = install.install_binary_rock(name, deps.get_deps_mode(flags)) | ||
| 164 | end | ||
| 165 | if not ok then return nil, err end | ||
| 166 | name, version = ok, err | ||
| 167 | if (not flags["only-deps"]) and (not flags["keep"]) and not cfg.keep_other_versions then | ||
| 168 | local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) | ||
| 169 | if not ok then util.printerr(err) end | ||
| 170 | end | ||
| 171 | return name, version | ||
| 172 | else | ||
| 173 | local search = require("luarocks.search") | ||
| 174 | local url, err = search.find_suitable_rock(search.make_query(name:lower(), version)) | ||
| 175 | if not url then | ||
| 176 | return nil, err | ||
| 177 | end | ||
| 178 | util.printout("Installing "..url) | ||
| 179 | return install.command(flags, url) | ||
| 180 | end | ||
| 181 | end | ||
| 182 | |||
| 183 | return install | ||
diff --git a/src/luarocks/cmd/lint.lua b/src/luarocks/cmd/lint.lua new file mode 100644 index 00000000..c9ea45ea --- /dev/null +++ b/src/luarocks/cmd/lint.lua | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "lint" command. | ||
| 3 | -- Utility function that checks syntax of the rockspec. | ||
| 4 | local lint = {} | ||
| 5 | |||
| 6 | local util = require("luarocks.util") | ||
| 7 | local download = require("luarocks.download") | ||
| 8 | local fetch = require("luarocks.fetch") | ||
| 9 | |||
| 10 | lint.help_summary = "Check syntax of a rockspec." | ||
| 11 | lint.help_arguments = "<rockspec>" | ||
| 12 | lint.help = [[ | ||
| 13 | This is a utility function that checks the syntax of a rockspec. | ||
| 14 | |||
| 15 | It returns success or failure if the text of a rockspec is | ||
| 16 | syntactically correct. | ||
| 17 | ]] | ||
| 18 | |||
| 19 | function lint.command(flags, input) | ||
| 20 | if not input then | ||
| 21 | return nil, "Argument missing. "..util.see_help("lint") | ||
| 22 | end | ||
| 23 | |||
| 24 | local filename = input | ||
| 25 | if not input:match(".rockspec$") then | ||
| 26 | local err | ||
| 27 | filename, err = download.download("rockspec", input:lower()) | ||
| 28 | if not filename then | ||
| 29 | return nil, err | ||
| 30 | end | ||
| 31 | end | ||
| 32 | |||
| 33 | local rs, err = fetch.load_local_rockspec(filename) | ||
| 34 | if not rs then | ||
| 35 | return nil, "Failed loading rockspec: "..err | ||
| 36 | end | ||
| 37 | |||
| 38 | local ok = true | ||
| 39 | |||
| 40 | -- This should have been done in the type checker, | ||
| 41 | -- but it would break compatibility of other commands. | ||
| 42 | -- Making 'lint' alone be stricter shouldn't be a problem, | ||
| 43 | -- because extra-strict checks is what lint-type commands | ||
| 44 | -- are all about. | ||
| 45 | if not rs.description.license then | ||
| 46 | util.printerr("Rockspec has no license field.") | ||
| 47 | ok = false | ||
| 48 | end | ||
| 49 | |||
| 50 | return ok, ok or filename.." failed consistency checks." | ||
| 51 | end | ||
| 52 | |||
| 53 | return lint | ||
diff --git a/src/luarocks/cmd/list.lua b/src/luarocks/cmd/list.lua new file mode 100644 index 00000000..45f1a26f --- /dev/null +++ b/src/luarocks/cmd/list.lua | |||
| @@ -0,0 +1,95 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "list" command. | ||
| 3 | -- Lists currently installed rocks. | ||
| 4 | local list = {} | ||
| 5 | |||
| 6 | local search = require("luarocks.search") | ||
| 7 | local deps = require("luarocks.deps") | ||
| 8 | local cfg = require("luarocks.core.cfg") | ||
| 9 | local util = require("luarocks.util") | ||
| 10 | local path = require("luarocks.path") | ||
| 11 | |||
| 12 | list.help_summary = "List currently installed rocks." | ||
| 13 | list.help_arguments = "[--porcelain] <filter>" | ||
| 14 | list.help = [[ | ||
| 15 | <filter> is a substring of a rock name to filter by. | ||
| 16 | |||
| 17 | --outdated List only rocks for which there is a | ||
| 18 | higher version available in the rocks server. | ||
| 19 | |||
| 20 | --porcelain Produce machine-friendly output. | ||
| 21 | ]] | ||
| 22 | |||
| 23 | local function check_outdated(trees, query) | ||
| 24 | local results_installed = {} | ||
| 25 | for _, tree in ipairs(trees) do | ||
| 26 | search.manifest_search(results_installed, path.rocks_dir(tree), query) | ||
| 27 | end | ||
| 28 | local outdated = {} | ||
| 29 | for name, versions in util.sortedpairs(results_installed) do | ||
| 30 | versions = util.keys(versions) | ||
| 31 | table.sort(versions, deps.compare_versions) | ||
| 32 | local latest_installed = versions[1] | ||
| 33 | |||
| 34 | local query_available = search.make_query(name:lower()) | ||
| 35 | query.exact_name = true | ||
| 36 | local results_available, err = search.search_repos(query_available) | ||
| 37 | |||
| 38 | if results_available[name] then | ||
| 39 | local available_versions = util.keys(results_available[name]) | ||
| 40 | table.sort(available_versions, deps.compare_versions) | ||
| 41 | local latest_available = available_versions[1] | ||
| 42 | local latest_available_repo = results_available[name][latest_available][1].repo | ||
| 43 | |||
| 44 | if deps.compare_versions(latest_available, latest_installed) then | ||
| 45 | table.insert(outdated, { name = name, installed = latest_installed, available = latest_available, repo = latest_available_repo }) | ||
| 46 | end | ||
| 47 | end | ||
| 48 | end | ||
| 49 | return outdated | ||
| 50 | end | ||
| 51 | |||
| 52 | local function list_outdated(trees, query, porcelain) | ||
| 53 | util.title("Outdated rocks:", porcelain) | ||
| 54 | local outdated = check_outdated(trees, query) | ||
| 55 | for _, item in ipairs(outdated) do | ||
| 56 | if porcelain then | ||
| 57 | util.printout(item.name, item.installed, item.available, item.repo) | ||
| 58 | else | ||
| 59 | util.printout(item.name) | ||
| 60 | util.printout(" "..item.installed.." < "..item.available.." at "..item.repo) | ||
| 61 | util.printout() | ||
| 62 | end | ||
| 63 | end | ||
| 64 | return true | ||
| 65 | end | ||
| 66 | |||
| 67 | --- Driver function for "list" command. | ||
| 68 | -- @param filter string or nil: A substring of a rock name to filter by. | ||
| 69 | -- @param version string or nil: a version may also be passed. | ||
| 70 | -- @return boolean: True if succeeded, nil on errors. | ||
| 71 | function list.command(flags, filter, version) | ||
| 72 | local query = search.make_query(filter and filter:lower() or "", version) | ||
| 73 | query.exact_name = false | ||
| 74 | local trees = cfg.rocks_trees | ||
| 75 | if flags["tree"] then | ||
| 76 | trees = { flags["tree"] } | ||
| 77 | end | ||
| 78 | |||
| 79 | if flags["outdated"] then | ||
| 80 | return list_outdated(trees, query, flags["porcelain"]) | ||
| 81 | end | ||
| 82 | |||
| 83 | local results = {} | ||
| 84 | for _, tree in ipairs(trees) do | ||
| 85 | local ok, err, errcode = search.manifest_search(results, path.rocks_dir(tree), query) | ||
| 86 | if not ok and errcode ~= "open" then | ||
| 87 | util.warning(err) | ||
| 88 | end | ||
| 89 | end | ||
| 90 | util.title("Installed rocks:", flags["porcelain"]) | ||
| 91 | search.print_results(results, flags["porcelain"]) | ||
| 92 | return true | ||
| 93 | end | ||
| 94 | |||
| 95 | return list | ||
diff --git a/src/luarocks/cmd/make.lua b/src/luarocks/cmd/make.lua new file mode 100644 index 00000000..eb38bff0 --- /dev/null +++ b/src/luarocks/cmd/make.lua | |||
| @@ -0,0 +1,86 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "make" command. | ||
| 3 | -- Builds sources in the current directory, but unlike "build", | ||
| 4 | -- it does not fetch sources, etc., assuming everything is | ||
| 5 | -- available in the current directory. | ||
| 6 | local make = {} | ||
| 7 | |||
| 8 | local build = require("luarocks.build") | ||
| 9 | local fs = require("luarocks.fs") | ||
| 10 | local util = require("luarocks.util") | ||
| 11 | local cfg = require("luarocks.core.cfg") | ||
| 12 | local fetch = require("luarocks.fetch") | ||
| 13 | local pack = require("luarocks.pack") | ||
| 14 | local remove = require("luarocks.remove") | ||
| 15 | local deps = require("luarocks.deps") | ||
| 16 | |||
| 17 | make.help_summary = "Compile package in current directory using a rockspec." | ||
| 18 | make.help_arguments = "[--pack-binary-rock] [<rockspec>]" | ||
| 19 | make.help = [[ | ||
| 20 | Builds sources in the current directory, but unlike "build", | ||
| 21 | it does not fetch sources, etc., assuming everything is | ||
| 22 | available in the current directory. If no argument is given, | ||
| 23 | it looks for a rockspec in the current directory and in "rockspec/" | ||
| 24 | and "rockspecs/" subdirectories, picking the rockspec with newest version | ||
| 25 | or without version name. If rockspecs for different rocks are found | ||
| 26 | or there are several rockspecs without version, you must specify which to use, | ||
| 27 | through the command-line. | ||
| 28 | |||
| 29 | This command is useful as a tool for debugging rockspecs. | ||
| 30 | To install rocks, you'll normally want to use the "install" and | ||
| 31 | "build" commands. See the help on those for details. | ||
| 32 | |||
| 33 | --pack-binary-rock Do not install rock. Instead, produce a .rock file | ||
| 34 | with the contents of compilation in the current | ||
| 35 | directory. | ||
| 36 | |||
| 37 | --keep Do not remove previously installed versions of the | ||
| 38 | rock after installing a new one. This behavior can | ||
| 39 | be made permanent by setting keep_other_versions=true | ||
| 40 | in the configuration file. | ||
| 41 | |||
| 42 | --branch=<name> Override the `source.branch` field in the loaded | ||
| 43 | rockspec. Allows to specify a different branch to | ||
| 44 | fetch. Particularly for SCM rocks. | ||
| 45 | |||
| 46 | ]] | ||
| 47 | |||
| 48 | --- Driver function for "make" command. | ||
| 49 | -- @param name string: A local rockspec. | ||
| 50 | -- @return boolean or (nil, string, exitcode): True if build was successful; nil and an | ||
| 51 | -- error message otherwise. exitcode is optionally returned. | ||
| 52 | function make.command(flags, rockspec) | ||
| 53 | assert(type(rockspec) == "string" or not rockspec) | ||
| 54 | |||
| 55 | if not rockspec then | ||
| 56 | local err | ||
| 57 | rockspec, err = util.get_default_rockspec() | ||
| 58 | if not rockspec then | ||
| 59 | return nil, err | ||
| 60 | end | ||
| 61 | end | ||
| 62 | if not rockspec:match("rockspec$") then | ||
| 63 | return nil, "Invalid argument: 'make' takes a rockspec as a parameter. "..util.see_help("make") | ||
| 64 | end | ||
| 65 | |||
| 66 | if flags["pack-binary-rock"] then | ||
| 67 | local rspec, err, errcode = fetch.load_rockspec(rockspec) | ||
| 68 | if not rspec then | ||
| 69 | return nil, err | ||
| 70 | end | ||
| 71 | return pack.pack_binary_rock(rspec.name, rspec.version, build.build_rockspec, rockspec, false, true, deps.get_deps_mode(flags)) | ||
| 72 | else | ||
| 73 | local ok, err = fs.check_command_permissions(flags) | ||
| 74 | if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end | ||
| 75 | ok, err = build.build_rockspec(rockspec, false, true, deps.get_deps_mode(flags)) | ||
| 76 | if not ok then return nil, err end | ||
| 77 | local name, version = ok, err | ||
| 78 | if (not flags["keep"]) and not cfg.keep_other_versions then | ||
| 79 | local ok, err = remove.remove_other_versions(name, version, flags["force"], flags["force-fast"]) | ||
| 80 | if not ok then util.printerr(err) end | ||
| 81 | end | ||
| 82 | return name, version | ||
| 83 | end | ||
| 84 | end | ||
| 85 | |||
| 86 | return make | ||
diff --git a/src/luarocks/cmd/new_version.lua b/src/luarocks/cmd/new_version.lua new file mode 100644 index 00000000..b13dbb97 --- /dev/null +++ b/src/luarocks/cmd/new_version.lua | |||
| @@ -0,0 +1,199 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "new_version" command. | ||
| 3 | -- Utility function that writes a new rockspec, updating data from a previous one. | ||
| 4 | local new_version = {} | ||
| 5 | |||
| 6 | local util = require("luarocks.util") | ||
| 7 | local download = require("luarocks.download") | ||
| 8 | local fetch = require("luarocks.fetch") | ||
| 9 | local persist = require("luarocks.persist") | ||
| 10 | local fs = require("luarocks.fs") | ||
| 11 | local type_check = require("luarocks.type_check") | ||
| 12 | |||
| 13 | new_version.help_summary = "Auto-write a rockspec for a new version of a rock." | ||
| 14 | new_version.help_arguments = "[--tag=<tag>] [<package>|<rockspec>] [<new_version>] [<new_url>]" | ||
| 15 | new_version.help = [[ | ||
| 16 | This is a utility function that writes a new rockspec, updating data | ||
| 17 | from a previous one. | ||
| 18 | |||
| 19 | If a package name is given, it downloads the latest rockspec from the | ||
| 20 | default server. If a rockspec is given, it uses it instead. If no argument | ||
| 21 | is given, it looks for a rockspec same way 'luarocks make' does. | ||
| 22 | |||
| 23 | If the version number is not given and tag is passed using --tag, | ||
| 24 | it is used as the version, with 'v' removed from beginning. | ||
| 25 | Otherwise, it only increments the revision number of the given | ||
| 26 | (or downloaded) rockspec. | ||
| 27 | |||
| 28 | If a URL is given, it replaces the one from the old rockspec with the | ||
| 29 | given URL. If a URL is not given and a new version is given, it tries | ||
| 30 | to guess the new URL by replacing occurrences of the version number | ||
| 31 | in the URL or tag. It also tries to download the new URL to determine | ||
| 32 | the new MD5 checksum. | ||
| 33 | |||
| 34 | If a tag is given, it replaces the one from the old rockspec. If there is | ||
| 35 | an old tag but no new one passed, it is guessed in the same way URL is. | ||
| 36 | |||
| 37 | WARNING: it writes the new rockspec to the current directory, | ||
| 38 | overwriting the file if it already exists. | ||
| 39 | ]] | ||
| 40 | |||
| 41 | local function try_replace(tbl, field, old, new) | ||
| 42 | if not tbl[field] then | ||
| 43 | return false | ||
| 44 | end | ||
| 45 | local old_field = tbl[field] | ||
| 46 | local new_field = tbl[field]:gsub(old, new) | ||
| 47 | if new_field ~= old_field then | ||
| 48 | util.printout("Guessing new '"..field.."' field as "..new_field) | ||
| 49 | tbl[field] = new_field | ||
| 50 | return true | ||
| 51 | end | ||
| 52 | return false | ||
| 53 | end | ||
| 54 | |||
| 55 | -- Try to download source file using URL from a rockspec. | ||
| 56 | -- If it specified MD5, update it. | ||
| 57 | -- @return (true, false) if MD5 was not specified or it stayed same, | ||
| 58 | -- (true, true) if MD5 changed, (nil, string) on error. | ||
| 59 | local function check_url_and_update_md5(out_rs) | ||
| 60 | local file, temp_dir = fetch.fetch_url_at_temp_dir(out_rs.source.url, "luarocks-new-version-"..out_rs.package) | ||
| 61 | if not file then | ||
| 62 | util.printerr("Warning: invalid URL - "..temp_dir) | ||
| 63 | return true, false | ||
| 64 | end | ||
| 65 | |||
| 66 | local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, out_rs.source.url, out_rs.source.dir) | ||
| 67 | if not inferred_dir then | ||
| 68 | return nil, found_dir | ||
| 69 | end | ||
| 70 | |||
| 71 | if found_dir and found_dir ~= inferred_dir then | ||
| 72 | out_rs.source.dir = found_dir | ||
| 73 | end | ||
| 74 | |||
| 75 | if file then | ||
| 76 | if out_rs.source.md5 then | ||
| 77 | util.printout("File successfully downloaded. Updating MD5 checksum...") | ||
| 78 | local new_md5, err = fs.get_md5(file) | ||
| 79 | if not new_md5 then | ||
| 80 | return nil, err | ||
| 81 | end | ||
| 82 | local old_md5 = out_rs.source.md5 | ||
| 83 | out_rs.source.md5 = new_md5 | ||
| 84 | return true, new_md5 ~= old_md5 | ||
| 85 | else | ||
| 86 | util.printout("File successfully downloaded.") | ||
| 87 | return true, false | ||
| 88 | end | ||
| 89 | end | ||
| 90 | end | ||
| 91 | |||
| 92 | local function update_source_section(out_rs, url, tag, old_ver, new_ver) | ||
| 93 | if tag then | ||
| 94 | out_rs.source.tag = tag | ||
| 95 | end | ||
| 96 | if url then | ||
| 97 | out_rs.source.url = url | ||
| 98 | return check_url_and_update_md5(out_rs) | ||
| 99 | end | ||
| 100 | if new_ver == old_ver then | ||
| 101 | return true | ||
| 102 | end | ||
| 103 | if out_rs.source.dir then | ||
| 104 | try_replace(out_rs.source, "dir", old_ver, new_ver) | ||
| 105 | end | ||
| 106 | if out_rs.source.file then | ||
| 107 | try_replace(out_rs.source, "file", old_ver, new_ver) | ||
| 108 | end | ||
| 109 | if try_replace(out_rs.source, "url", old_ver, new_ver) then | ||
| 110 | return check_url_and_update_md5(out_rs) | ||
| 111 | end | ||
| 112 | if tag or try_replace(out_rs.source, "tag", old_ver, new_ver) then | ||
| 113 | return true | ||
| 114 | end | ||
| 115 | -- Couldn't replace anything significant, use the old URL. | ||
| 116 | local ok, md5_changed = check_url_and_update_md5(out_rs) | ||
| 117 | if not ok then | ||
| 118 | return nil, md5_changed | ||
| 119 | end | ||
| 120 | if md5_changed then | ||
| 121 | util.printerr("Warning: URL is the same, but MD5 has changed. Old rockspec is broken.") | ||
| 122 | end | ||
| 123 | return true | ||
| 124 | end | ||
| 125 | |||
| 126 | function new_version.command(flags, input, version, url) | ||
| 127 | if not input then | ||
| 128 | local err | ||
| 129 | input, err = util.get_default_rockspec() | ||
| 130 | if not input then | ||
| 131 | return nil, err | ||
| 132 | end | ||
| 133 | end | ||
| 134 | assert(type(input) == "string") | ||
| 135 | |||
| 136 | local filename, err | ||
| 137 | if input:match("rockspec$") then | ||
| 138 | filename, err = fetch.fetch_url(input) | ||
| 139 | if not filename then | ||
| 140 | return nil, err | ||
| 141 | end | ||
| 142 | else | ||
| 143 | filename, err = download.download("rockspec", input:lower()) | ||
| 144 | if not filename then | ||
| 145 | return nil, err | ||
| 146 | end | ||
| 147 | end | ||
| 148 | |||
| 149 | local valid_rs, err = fetch.load_rockspec(filename) | ||
| 150 | if not valid_rs then | ||
| 151 | return nil, err | ||
| 152 | end | ||
| 153 | |||
| 154 | local old_ver, old_rev = valid_rs.version:match("(.*)%-(%d+)$") | ||
| 155 | local new_ver, new_rev | ||
| 156 | |||
| 157 | if flags.tag and not version then | ||
| 158 | version = flags.tag:gsub("^v", "") | ||
| 159 | end | ||
| 160 | |||
| 161 | if version then | ||
| 162 | new_ver, new_rev = version:match("(.*)%-(%d+)$") | ||
| 163 | new_rev = tonumber(new_rev) | ||
| 164 | if not new_rev then | ||
| 165 | new_ver = version | ||
| 166 | new_rev = 1 | ||
| 167 | end | ||
| 168 | else | ||
| 169 | new_ver = old_ver | ||
| 170 | new_rev = tonumber(old_rev) + 1 | ||
| 171 | end | ||
| 172 | local new_rockver = new_ver:gsub("-", "") | ||
| 173 | |||
| 174 | local out_rs, err = persist.load_into_table(filename) | ||
| 175 | local out_name = out_rs.package:lower() | ||
| 176 | out_rs.version = new_rockver.."-"..new_rev | ||
| 177 | |||
| 178 | local ok, err = update_source_section(out_rs, url, flags.tag, old_ver, new_ver) | ||
| 179 | if not ok then return nil, err end | ||
| 180 | |||
| 181 | if out_rs.build and out_rs.build.type == "module" then | ||
| 182 | out_rs.build.type = "builtin" | ||
| 183 | end | ||
| 184 | |||
| 185 | local out_filename = out_name.."-"..new_rockver.."-"..new_rev..".rockspec" | ||
| 186 | |||
| 187 | persist.save_from_table(out_filename, out_rs, type_check.rockspec_order) | ||
| 188 | |||
| 189 | util.printout("Wrote "..out_filename) | ||
| 190 | |||
| 191 | local valid_out_rs, err = fetch.load_local_rockspec(out_filename) | ||
| 192 | if not valid_out_rs then | ||
| 193 | return nil, "Failed loading generated rockspec: "..err | ||
| 194 | end | ||
| 195 | |||
| 196 | return true | ||
| 197 | end | ||
| 198 | |||
| 199 | return new_version | ||
diff --git a/src/luarocks/cmd/pack.lua b/src/luarocks/cmd/pack.lua new file mode 100644 index 00000000..655cbf37 --- /dev/null +++ b/src/luarocks/cmd/pack.lua | |||
| @@ -0,0 +1,193 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "pack" command. | ||
| 3 | -- Creates a rock, packing sources or binaries. | ||
| 4 | local pack = {} | ||
| 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") | ||
| 14 | local dir = require("luarocks.dir") | ||
| 15 | local manif = require("luarocks.manif") | ||
| 16 | local search = require("luarocks.search") | ||
| 17 | |||
| 18 | pack.help_summary = "Create a rock, packing sources or binaries." | ||
| 19 | pack.help_arguments = "{<rockspec>|<name> [<version>]}" | ||
| 20 | pack.help = [[ | ||
| 21 | Argument may be a rockspec file, for creating a source rock, | ||
| 22 | 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 | ||
| 24 | argument. | ||
| 25 | ]] | ||
| 26 | |||
| 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. | ||
| 167 | -- @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. | ||
| 169 | -- @param version string or nil: if the name of a package is given, a | ||
| 170 | -- version may also be passed. | ||
| 171 | -- @return boolean or (nil, string): true if successful or nil followed | ||
| 172 | -- by an error message. | ||
| 173 | function pack.command(flags, arg, version) | ||
| 174 | assert(type(version) == "string" or not version) | ||
| 175 | if type(arg) ~= "string" then | ||
| 176 | return nil, "Argument missing. "..util.see_help("pack") | ||
| 177 | end | ||
| 178 | |||
| 179 | local file, err | ||
| 180 | if arg:match(".*%.rockspec") then | ||
| 181 | file, err = pack.pack_source_rock(arg) | ||
| 182 | else | ||
| 183 | file, err = do_pack_binary_rock(arg:lower(), version, flags["tree"]) | ||
| 184 | end | ||
| 185 | if err then | ||
| 186 | return nil, err | ||
| 187 | else | ||
| 188 | util.printout("Packed: "..file) | ||
| 189 | return true | ||
| 190 | end | ||
| 191 | end | ||
| 192 | |||
| 193 | return pack | ||
diff --git a/src/luarocks/cmd/path_cmd.lua b/src/luarocks/cmd/path_cmd.lua new file mode 100644 index 00000000..516a0c47 --- /dev/null +++ b/src/luarocks/cmd/path_cmd.lua | |||
| @@ -0,0 +1,68 @@ | |||
| 1 | |||
| 2 | --- @module luarocks.path_cmd | ||
| 3 | -- Driver for the `luarocks path` command. | ||
| 4 | local path_cmd = {} | ||
| 5 | |||
| 6 | local util = require("luarocks.util") | ||
| 7 | local cfg = require("luarocks.core.cfg") | ||
| 8 | |||
| 9 | path_cmd.help_summary = "Return the currently configured package path." | ||
| 10 | path_cmd.help_arguments = "" | ||
| 11 | path_cmd.help = [[ | ||
| 12 | Returns the package path currently configured for this installation | ||
| 13 | of LuaRocks, formatted as shell commands to update LUA_PATH and LUA_CPATH. | ||
| 14 | |||
| 15 | --bin Adds the system path to the output | ||
| 16 | |||
| 17 | --append Appends the paths to the existing paths. Default is to prefix | ||
| 18 | the LR paths to the existing paths. | ||
| 19 | |||
| 20 | --lr-path Exports the Lua path (not formatted as shell command) | ||
| 21 | |||
| 22 | --lr-cpath Exports the Lua cpath (not formatted as shell command) | ||
| 23 | |||
| 24 | --lr-bin Exports the system path (not formatted as shell command) | ||
| 25 | |||
| 26 | |||
| 27 | On Unix systems, you may run: | ||
| 28 | eval `luarocks path` | ||
| 29 | And on Windows: | ||
| 30 | luarocks path > "%temp%\_lrp.bat" && call "%temp%\_lrp.bat" && del "%temp%\_lrp.bat" | ||
| 31 | ]] | ||
| 32 | |||
| 33 | --- Driver function for "path" command. | ||
| 34 | -- @return boolean This function always succeeds. | ||
| 35 | function path_cmd.command(flags) | ||
| 36 | local lr_path, lr_cpath, lr_bin = cfg.package_paths(flags["tree"]) | ||
| 37 | local path_sep = cfg.export_path_separator | ||
| 38 | |||
| 39 | if flags["lr-path"] then | ||
| 40 | util.printout(util.remove_path_dupes(lr_path, ';')) | ||
| 41 | return true | ||
| 42 | elseif flags["lr-cpath"] then | ||
| 43 | util.printout(util.remove_path_dupes(lr_cpath, ';')) | ||
| 44 | return true | ||
| 45 | elseif flags["lr-bin"] then | ||
| 46 | util.printout(util.remove_path_dupes(lr_bin, path_sep)) | ||
| 47 | return true | ||
| 48 | end | ||
| 49 | |||
| 50 | if flags["append"] then | ||
| 51 | lr_path = package.path .. ";" .. lr_path | ||
| 52 | lr_cpath = package.cpath .. ";" .. lr_cpath | ||
| 53 | lr_bin = os.getenv("PATH") .. path_sep .. lr_bin | ||
| 54 | else | ||
| 55 | lr_path = lr_path.. ";" .. package.path | ||
| 56 | lr_cpath = lr_cpath .. ";" .. package.cpath | ||
| 57 | lr_bin = lr_bin .. path_sep .. os.getenv("PATH") | ||
| 58 | end | ||
| 59 | |||
| 60 | util.printout(cfg.export_lua_path:format(util.remove_path_dupes(lr_path, ';'))) | ||
| 61 | util.printout(cfg.export_lua_cpath:format(util.remove_path_dupes(lr_cpath, ';'))) | ||
| 62 | if flags["bin"] then | ||
| 63 | util.printout(cfg.export_path:format(util.remove_path_dupes(lr_bin, path_sep))) | ||
| 64 | end | ||
| 65 | return true | ||
| 66 | end | ||
| 67 | |||
| 68 | return path_cmd | ||
diff --git a/src/luarocks/cmd/purge.lua b/src/luarocks/cmd/purge.lua new file mode 100644 index 00000000..50f290c8 --- /dev/null +++ b/src/luarocks/cmd/purge.lua | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "purge" command. | ||
| 3 | -- Remove all rocks from a given tree. | ||
| 4 | local purge = {} | ||
| 5 | |||
| 6 | local util = require("luarocks.util") | ||
| 7 | local fs = require("luarocks.fs") | ||
| 8 | local path = require("luarocks.path") | ||
| 9 | local search = require("luarocks.search") | ||
| 10 | local deps = require("luarocks.deps") | ||
| 11 | local repos = require("luarocks.repos") | ||
| 12 | local writer = require("luarocks.manif.writer") | ||
| 13 | local cfg = require("luarocks.core.cfg") | ||
| 14 | local remove = require("luarocks.remove") | ||
| 15 | |||
| 16 | purge.help_summary = "Remove all installed rocks from a tree." | ||
| 17 | purge.help_arguments = "--tree=<tree> [--old-versions]" | ||
| 18 | purge.help = [[ | ||
| 19 | This command removes rocks en masse from a given tree. | ||
| 20 | By default, it removes all rocks from a tree. | ||
| 21 | |||
| 22 | The --tree argument is mandatory: luarocks purge does not | ||
| 23 | assume a default tree. | ||
| 24 | |||
| 25 | --old-versions Keep the highest-numbered version of each | ||
| 26 | rock and remove the other ones. By default | ||
| 27 | it only removes old versions if they are | ||
| 28 | not needed as dependencies. This can be | ||
| 29 | overridden with the flag --force. | ||
| 30 | ]] | ||
| 31 | |||
| 32 | function purge.command(flags) | ||
| 33 | local tree = flags["tree"] | ||
| 34 | |||
| 35 | if type(tree) ~= "string" then | ||
| 36 | return nil, "The --tree argument is mandatory. "..util.see_help("purge") | ||
| 37 | end | ||
| 38 | |||
| 39 | local results = {} | ||
| 40 | local query = search.make_query("") | ||
| 41 | query.exact_name = false | ||
| 42 | if not fs.is_dir(tree) then | ||
| 43 | return nil, "Directory not found: "..tree | ||
| 44 | end | ||
| 45 | |||
| 46 | local ok, err = fs.check_command_permissions(flags) | ||
| 47 | if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end | ||
| 48 | |||
| 49 | search.manifest_search(results, path.rocks_dir(tree), query) | ||
| 50 | |||
| 51 | local sort = function(a,b) return deps.compare_versions(b,a) end | ||
| 52 | if flags["old-versions"] then | ||
| 53 | sort = deps.compare_versions | ||
| 54 | end | ||
| 55 | |||
| 56 | for package, versions in util.sortedpairs(results) do | ||
| 57 | for version, _ in util.sortedpairs(versions, sort) do | ||
| 58 | if flags["old-versions"] then | ||
| 59 | util.printout("Keeping "..package.." "..version.."...") | ||
| 60 | local ok, err = remove.remove_other_versions(package, version, flags["force"], flags["force-fast"]) | ||
| 61 | if not ok then | ||
| 62 | util.printerr(err) | ||
| 63 | end | ||
| 64 | break | ||
| 65 | else | ||
| 66 | util.printout("Removing "..package.." "..version.."...") | ||
| 67 | local ok, err = repos.delete_version(package, version, "none", true) | ||
| 68 | if not ok then | ||
| 69 | util.printerr(err) | ||
| 70 | end | ||
| 71 | end | ||
| 72 | end | ||
| 73 | end | ||
| 74 | return writer.make_manifest(cfg.rocks_dir, "one") | ||
| 75 | end | ||
| 76 | |||
| 77 | return purge | ||
diff --git a/src/luarocks/cmd/remove.lua b/src/luarocks/cmd/remove.lua new file mode 100644 index 00000000..e7f37604 --- /dev/null +++ b/src/luarocks/cmd/remove.lua | |||
| @@ -0,0 +1,165 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "remove" command. | ||
| 3 | -- Uninstalls rocks. | ||
| 4 | local remove = {} | ||
| 5 | |||
| 6 | local search = require("luarocks.search") | ||
| 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") | ||
| 12 | local cfg = require("luarocks.core.cfg") | ||
| 13 | local fs = require("luarocks.fs") | ||
| 14 | |||
| 15 | remove.help_summary = "Uninstall a rock." | ||
| 16 | remove.help_arguments = "[--force|--force-fast] <name> [<version>]" | ||
| 17 | remove.help = [[ | ||
| 18 | Argument is the name of a rock to be uninstalled. | ||
| 19 | 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. | ||
| 21 | To override this check and force the removal, use --force. | ||
| 22 | To perform a forced removal without reporting dependency issues, | ||
| 23 | use --force-fast. | ||
| 24 | |||
| 25 | ]]..util.deps_mode_help() | ||
| 26 | |||
| 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. | ||
| 132 | -- @param name string: name of a rock. If a version is given, refer to | ||
| 133 | -- a specific version; otherwise, try to remove all versions. | ||
| 134 | -- @param version string: When passing a package name, a version number | ||
| 135 | -- may also be given. | ||
| 136 | -- @return boolean or (nil, string, exitcode): True if removal was | ||
| 137 | -- successful, nil and an error message otherwise. exitcode is optionally returned. | ||
| 138 | function remove.command(flags, name, version) | ||
| 139 | if type(name) ~= "string" then | ||
| 140 | return nil, "Argument missing. "..util.see_help("remove") | ||
| 141 | end | ||
| 142 | |||
| 143 | local deps_mode = flags["deps-mode"] or cfg.deps_mode | ||
| 144 | |||
| 145 | local ok, err = fs.check_command_permissions(flags) | ||
| 146 | if not ok then return nil, err, cfg.errorcodes.PERMISSIONDENIED end | ||
| 147 | |||
| 148 | local rock_type = name:match("%.(rock)$") or name:match("%.(rockspec)$") | ||
| 149 | local filename = name | ||
| 150 | if rock_type then | ||
| 151 | name, version = path.parse_name(filename) | ||
| 152 | if not name then return nil, "Invalid "..rock_type.." filename: "..filename end | ||
| 153 | end | ||
| 154 | |||
| 155 | local results = {} | ||
| 156 | name = name:lower() | ||
| 157 | search.manifest_search(results, cfg.rocks_dir, search.make_query(name, version)) | ||
| 158 | if not results[name] then | ||
| 159 | return nil, "Could not find rock '"..name..(version and " "..version or "").."' in "..path.rocks_tree_to_string(cfg.root_dir) | ||
| 160 | end | ||
| 161 | |||
| 162 | return remove.remove_search_results(results, name, deps_mode, flags["force"], flags["force-fast"]) | ||
| 163 | end | ||
| 164 | |||
| 165 | return remove | ||
diff --git a/src/luarocks/cmd/search.lua b/src/luarocks/cmd/search.lua new file mode 100644 index 00000000..44eff694 --- /dev/null +++ b/src/luarocks/cmd/search.lua | |||
| @@ -0,0 +1,482 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "search" command. | ||
| 3 | -- Queries LuaRocks servers. | ||
| 4 | local search = {} | ||
| 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") | ||
| 12 | local util = require("luarocks.util") | ||
| 13 | |||
| 14 | search.help_summary = "Query the LuaRocks servers." | ||
| 15 | search.help_arguments = "[--source] [--binary] { <name> [<version>] | --all }" | ||
| 16 | search.help = [[ | ||
| 17 | --source Return only rockspecs and source rocks, | ||
| 18 | to be used with the "build" command. | ||
| 19 | --binary Return only pure Lua and binary rocks (rocks that can be used | ||
| 20 | with the "install" command without requiring a C toolchain). | ||
| 21 | --all List all contents of the server that are suitable to | ||
| 22 | this platform, do not filter by name. | ||
| 23 | ]] | ||
| 24 | |||
| 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 | ||
| 374 | -- to be used with the "build" command, and one for "binary" results to be | ||
| 375 | -- used with the "install" command. | ||
| 376 | -- @param results table: A search results table. | ||
| 377 | -- @return (table, table): Two tables, one for source and one for binary | ||
| 378 | -- results. | ||
| 379 | local function split_source_and_binary_results(results) | ||
| 380 | local sources, binaries = {}, {} | ||
| 381 | for name, versions in pairs(results) do | ||
| 382 | for version, repositories in pairs(versions) do | ||
| 383 | for _, repo in ipairs(repositories) do | ||
| 384 | local where = sources | ||
| 385 | if repo.arch == "all" or repo.arch == cfg.arch then | ||
| 386 | where = binaries | ||
| 387 | end | ||
| 388 | store_result(where, name, version, repo.arch, repo.repo) | ||
| 389 | end | ||
| 390 | end | ||
| 391 | end | ||
| 392 | return sources, binaries | ||
| 393 | end | ||
| 394 | |||
| 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. | ||
| 452 | -- @param name string: A substring of a rock name to search. | ||
| 453 | -- @param version string or nil: a version may also be passed. | ||
| 454 | -- @return boolean or (nil, string): True if build was successful; nil and an | ||
| 455 | -- error message otherwise. | ||
| 456 | function search.command(flags, name, version) | ||
| 457 | if flags["all"] then | ||
| 458 | name, version = "", nil | ||
| 459 | end | ||
| 460 | |||
| 461 | if type(name) ~= "string" and not flags["all"] then | ||
| 462 | return nil, "Enter name and version or use --all. "..util.see_help("search") | ||
| 463 | end | ||
| 464 | |||
| 465 | local query = search.make_query(name:lower(), version) | ||
| 466 | query.exact_name = false | ||
| 467 | local results, err = search.search_repos(query) | ||
| 468 | local porcelain = flags["porcelain"] | ||
| 469 | util.title("Search results:", porcelain, "=") | ||
| 470 | local sources, binaries = split_source_and_binary_results(results) | ||
| 471 | if next(sources) and not flags["binary"] then | ||
| 472 | util.title("Rockspecs and source rocks:", porcelain) | ||
| 473 | search.print_results(sources, porcelain) | ||
| 474 | end | ||
| 475 | if next(binaries) and not flags["source"] then | ||
| 476 | util.title("Binary and pure-Lua rocks:", porcelain) | ||
| 477 | search.print_results(binaries, porcelain) | ||
| 478 | end | ||
| 479 | return true | ||
| 480 | end | ||
| 481 | |||
| 482 | return search | ||
diff --git a/src/luarocks/cmd/show.lua b/src/luarocks/cmd/show.lua new file mode 100644 index 00000000..1ff81e08 --- /dev/null +++ b/src/luarocks/cmd/show.lua | |||
| @@ -0,0 +1,158 @@ | |||
| 1 | --- Module implementing the LuaRocks "show" command. | ||
| 2 | -- Shows information about an installed rock. | ||
| 3 | local show = {} | ||
| 4 | |||
| 5 | local search = require("luarocks.search") | ||
| 6 | local cfg = require("luarocks.core.cfg") | ||
| 7 | local util = require("luarocks.util") | ||
| 8 | local path = require("luarocks.path") | ||
| 9 | local deps = require("luarocks.deps") | ||
| 10 | local fetch = require("luarocks.fetch") | ||
| 11 | local manif = require("luarocks.manif") | ||
| 12 | |||
| 13 | show.help_summary = "Show information about an installed rock." | ||
| 14 | |||
| 15 | show.help = [[ | ||
| 16 | <argument> is an existing package name. | ||
| 17 | Without any flags, show all module information. | ||
| 18 | With these flags, return only the desired information: | ||
| 19 | |||
| 20 | --home home page of project | ||
| 21 | --modules all modules provided by this package as used by require() | ||
| 22 | --deps packages this package depends on | ||
| 23 | --rockspec the full path of the rockspec file | ||
| 24 | --mversion the package version | ||
| 25 | --rock-tree local tree where rock is installed | ||
| 26 | --rock-dir data directory of the installed rock | ||
| 27 | ]] | ||
| 28 | |||
| 29 | local function keys_as_string(t, sep) | ||
| 30 | local keys = util.keys(t) | ||
| 31 | table.sort(keys) | ||
| 32 | return table.concat(keys, sep or " ") | ||
| 33 | end | ||
| 34 | |||
| 35 | local function word_wrap(line) | ||
| 36 | local width = tonumber(os.getenv("COLUMNS")) or 80 | ||
| 37 | if width > 80 then width = 80 end | ||
| 38 | if #line > width then | ||
| 39 | local brk = width | ||
| 40 | while brk > 0 and line:sub(brk, brk) ~= " " do | ||
| 41 | brk = brk - 1 | ||
| 42 | end | ||
| 43 | if brk > 0 then | ||
| 44 | return line:sub(1, brk-1) .. "\n" .. word_wrap(line:sub(brk+1)) | ||
| 45 | end | ||
| 46 | end | ||
| 47 | return line | ||
| 48 | end | ||
| 49 | |||
| 50 | local function format_text(text) | ||
| 51 | text = text:gsub("^%s*",""):gsub("%s$", ""):gsub("\n[ \t]+","\n"):gsub("([^\n])\n([^\n])","%1 %2") | ||
| 52 | local paragraphs = util.split_string(text, "\n\n") | ||
| 53 | for n, line in ipairs(paragraphs) do | ||
| 54 | paragraphs[n] = word_wrap(line) | ||
| 55 | end | ||
| 56 | return (table.concat(paragraphs, "\n\n"):gsub("%s$", "")) | ||
| 57 | end | ||
| 58 | |||
| 59 | local function installed_rock_label(name, tree) | ||
| 60 | local installed, version | ||
| 61 | if cfg.rocks_provided[name] then | ||
| 62 | installed, version = true, cfg.rocks_provided[name] | ||
| 63 | else | ||
| 64 | installed, version = search.pick_installed_rock(name, nil, tree) | ||
| 65 | end | ||
| 66 | return installed and "(using "..version..")" or "(missing)" | ||
| 67 | end | ||
| 68 | |||
| 69 | --- Driver function for "show" command. | ||
| 70 | -- @param name or nil: an existing package name. | ||
| 71 | -- @param version string or nil: a version may also be passed. | ||
| 72 | -- @return boolean: True if succeeded, nil on errors. | ||
| 73 | function show.command(flags, name, version) | ||
| 74 | if not name then | ||
| 75 | return nil, "Argument missing. "..util.see_help("show") | ||
| 76 | end | ||
| 77 | |||
| 78 | local repo, repo_url | ||
| 79 | name, version, repo, repo_url = search.pick_installed_rock(name:lower(), version, flags["tree"]) | ||
| 80 | if not name then | ||
| 81 | return nil, version | ||
| 82 | end | ||
| 83 | |||
| 84 | local directory = path.install_dir(name,version,repo) | ||
| 85 | local rockspec_file = path.rockspec_file(name, version, repo) | ||
| 86 | local rockspec, err = fetch.load_local_rockspec(rockspec_file) | ||
| 87 | if not rockspec then return nil,err end | ||
| 88 | |||
| 89 | local descript = rockspec.description or {} | ||
| 90 | local manifest, err = manif.load_manifest(repo_url) | ||
| 91 | if not manifest then return nil,err end | ||
| 92 | local minfo = manifest.repository[name][version][1] | ||
| 93 | |||
| 94 | if flags["rock-tree"] then util.printout(path.rocks_tree_to_string(repo)) | ||
| 95 | elseif flags["rock-dir"] then util.printout(directory) | ||
| 96 | elseif flags["home"] then util.printout(descript.homepage) | ||
| 97 | elseif flags["issues"] then util.printout(descript.issues_url) | ||
| 98 | elseif flags["labels"] then util.printout(descript.labels and table.concat(descript.labels, "\n")) | ||
| 99 | elseif flags["modules"] then util.printout(keys_as_string(minfo.modules, "\n")) | ||
| 100 | elseif flags["deps"] then util.printout(keys_as_string(minfo.dependencies)) | ||
| 101 | elseif flags["rockspec"] then util.printout(rockspec_file) | ||
| 102 | elseif flags["mversion"] then util.printout(version) | ||
| 103 | else | ||
| 104 | util.printout() | ||
| 105 | util.printout(rockspec.package.." "..rockspec.version.." - "..(descript.summary or "")) | ||
| 106 | util.printout() | ||
| 107 | if descript.detailed then | ||
| 108 | util.printout(format_text(descript.detailed)) | ||
| 109 | util.printout() | ||
| 110 | end | ||
| 111 | if descript.license then | ||
| 112 | util.printout("License: ", descript.license) | ||
| 113 | end | ||
| 114 | if descript.homepage then | ||
| 115 | util.printout("Homepage: ", descript.homepage) | ||
| 116 | end | ||
| 117 | if descript.issues_url then | ||
| 118 | util.printout("Issues: ", descript.issues_url) | ||
| 119 | end | ||
| 120 | if descript.labels then | ||
| 121 | util.printout("Labels: ", table.concat(descript.labels, ", ")) | ||
| 122 | end | ||
| 123 | util.printout("Installed in: ", path.rocks_tree_to_string(repo)) | ||
| 124 | if next(minfo.modules) then | ||
| 125 | util.printout() | ||
| 126 | util.printout("Modules:") | ||
| 127 | for mod, filename in util.sortedpairs(minfo.modules) do | ||
| 128 | util.printout("\t"..mod.." ("..path.which(mod, filename, name, version, repo, manifest)..")") | ||
| 129 | end | ||
| 130 | end | ||
| 131 | local direct_deps = {} | ||
| 132 | if #rockspec.dependencies > 0 then | ||
| 133 | util.printout() | ||
| 134 | util.printout("Depends on:") | ||
| 135 | for _, dep in ipairs(rockspec.dependencies) do | ||
| 136 | direct_deps[dep.name] = true | ||
| 137 | util.printout("\t"..deps.show_dep(dep).." "..installed_rock_label(dep.name, flags["tree"])) | ||
| 138 | end | ||
| 139 | end | ||
| 140 | local has_indirect_deps | ||
| 141 | for dep_name in util.sortedpairs(minfo.dependencies) do | ||
| 142 | if not direct_deps[dep_name] then | ||
| 143 | if not has_indirect_deps then | ||
| 144 | util.printout() | ||
| 145 | util.printout("Indirectly pulling:") | ||
| 146 | has_indirect_deps = true | ||
| 147 | end | ||
| 148 | |||
| 149 | util.printout("\t"..dep_name.." "..installed_rock_label(dep_name, flags["tree"])) | ||
| 150 | end | ||
| 151 | end | ||
| 152 | util.printout() | ||
| 153 | end | ||
| 154 | return true | ||
| 155 | end | ||
| 156 | |||
| 157 | |||
| 158 | return show | ||
diff --git a/src/luarocks/cmd/unpack.lua b/src/luarocks/cmd/unpack.lua new file mode 100644 index 00000000..c50701b0 --- /dev/null +++ b/src/luarocks/cmd/unpack.lua | |||
| @@ -0,0 +1,164 @@ | |||
| 1 | |||
| 2 | --- Module implementing the LuaRocks "unpack" command. | ||
| 3 | -- Unpack the contents of a rock. | ||
| 4 | local unpack = {} | ||
| 5 | |||
| 6 | local fetch = require("luarocks.fetch") | ||
| 7 | local fs = require("luarocks.fs") | ||
| 8 | local util = require("luarocks.util") | ||
| 9 | local build = require("luarocks.build") | ||
| 10 | local dir = require("luarocks.dir") | ||
| 11 | local cfg = require("luarocks.core.cfg") | ||
| 12 | |||
| 13 | unpack.help_summary = "Unpack the contents of a rock." | ||
| 14 | unpack.help_arguments = "[--force] {<rock>|<name> [<version>]}" | ||
| 15 | unpack.help = [[ | ||
| 16 | Unpacks the contents of a rock in a newly created directory. | ||
| 17 | Argument may be a rock file, or the name of a rock in a rocks server. | ||
| 18 | In the latter case, the app version may be given as a second argument. | ||
| 19 | |||
| 20 | --force Unpack files even if the output directory already exists. | ||
| 21 | ]] | ||
| 22 | |||
| 23 | --- Load a rockspec file to the given directory, fetches the source | ||
| 24 | -- files specified in the rockspec, and unpack them inside the directory. | ||
| 25 | -- @param rockspec_file string: The URL for a rockspec file. | ||
| 26 | -- @param dir_name string: The directory where to store and unpack files. | ||
| 27 | -- @return table or (nil, string): the loaded rockspec table or | ||
| 28 | -- nil and an error message. | ||
| 29 | local function unpack_rockspec(rockspec_file, dir_name) | ||
| 30 | assert(type(rockspec_file) == "string") | ||
| 31 | assert(type(dir_name) == "string") | ||
| 32 | |||
| 33 | local rockspec, err = fetch.load_rockspec(rockspec_file) | ||
| 34 | if not rockspec then | ||
| 35 | return nil, "Failed loading rockspec "..rockspec_file..": "..err | ||
| 36 | end | ||
| 37 | local ok, err = fs.change_dir(dir_name) | ||
| 38 | if not ok then return nil, err end | ||
| 39 | local ok, sources_dir = fetch.fetch_sources(rockspec, true, ".") | ||
| 40 | if not ok then | ||
| 41 | return nil, sources_dir | ||
| 42 | end | ||
| 43 | ok, err = fs.change_dir(sources_dir) | ||
| 44 | if not ok then return nil, err end | ||
| 45 | ok, err = build.apply_patches(rockspec) | ||
| 46 | fs.pop_dir() | ||
| 47 | if not ok then return nil, err end | ||
| 48 | return rockspec | ||
| 49 | end | ||
| 50 | |||
| 51 | --- Load a .rock file to the given directory and unpack it inside it. | ||
| 52 | -- @param rock_file string: The URL for a .rock file. | ||
| 53 | -- @param dir_name string: The directory where to unpack. | ||
| 54 | -- @param kind string: the kind of rock file, as in the second-level | ||
| 55 | -- extension in the rock filename (eg. "src", "all", "linux-x86") | ||
| 56 | -- @return table or (nil, string): the loaded rockspec table or | ||
| 57 | -- nil and an error message. | ||
| 58 | local function unpack_rock(rock_file, dir_name, kind) | ||
| 59 | assert(type(rock_file) == "string") | ||
| 60 | assert(type(dir_name) == "string") | ||
| 61 | |||
| 62 | local ok, err, errcode = fetch.fetch_and_unpack_rock(rock_file, dir_name) | ||
| 63 | if not ok then | ||
| 64 | return nil, "Failed unzipping rock "..rock_file, errcode | ||
| 65 | end | ||
| 66 | ok, err = fs.change_dir(dir_name) | ||
| 67 | if not ok then return nil, err end | ||
| 68 | local rockspec_file = dir_name..".rockspec" | ||
| 69 | local rockspec, err = fetch.load_rockspec(rockspec_file) | ||
| 70 | if not rockspec then | ||
| 71 | return nil, "Failed loading rockspec "..rockspec_file..": "..err | ||
| 72 | end | ||
| 73 | if kind == "src" then | ||
| 74 | if rockspec.source.file then | ||
| 75 | local ok, err = fs.unpack_archive(rockspec.source.file) | ||
| 76 | if not ok then | ||
| 77 | return nil, err | ||
| 78 | end | ||
| 79 | ok, err = fs.change_dir(rockspec.source.dir) | ||
| 80 | if not ok then return nil, err end | ||
| 81 | ok, err = build.apply_patches(rockspec) | ||
| 82 | fs.pop_dir() | ||
| 83 | if not ok then return nil, err end | ||
| 84 | end | ||
| 85 | end | ||
| 86 | return rockspec | ||
| 87 | end | ||
| 88 | |||
| 89 | --- Create a directory and perform the necessary actions so that | ||
| 90 | -- the sources for the rock and its rockspec are unpacked inside it, | ||
| 91 | -- laid out properly so that the 'make' command is able to build the module. | ||
| 92 | -- @param file string: A rockspec or .rock URL. | ||
| 93 | -- @return boolean or (nil, string): true if successful or nil followed | ||
| 94 | -- by an error message. | ||
| 95 | local function run_unpacker(file, force) | ||
| 96 | assert(type(file) == "string") | ||
| 97 | |||
| 98 | local base_name = dir.base_name(file) | ||
| 99 | local dir_name, kind, extension = base_name:match("(.*)%.([^.]+)%.(rock)$") | ||
| 100 | if not extension then | ||
| 101 | dir_name, extension = base_name:match("(.*)%.(rockspec)$") | ||
| 102 | kind = "rockspec" | ||
| 103 | end | ||
| 104 | if not extension then | ||
| 105 | return nil, file.." does not seem to be a valid filename." | ||
| 106 | end | ||
| 107 | |||
| 108 | local exists = fs.exists(dir_name) | ||
| 109 | if exists and not force then | ||
| 110 | return nil, "Directory "..dir_name.." already exists." | ||
| 111 | end | ||
| 112 | if not exists then | ||
| 113 | local ok, err = fs.make_dir(dir_name) | ||
| 114 | if not ok then return nil, err end | ||
| 115 | end | ||
| 116 | local rollback = util.schedule_function(fs.delete, fs.absolute_name(dir_name)) | ||
| 117 | |||
| 118 | local rockspec, err | ||
| 119 | if extension == "rock" then | ||
| 120 | rockspec, err = unpack_rock(file, dir_name, kind) | ||
| 121 | elseif extension == "rockspec" then | ||
| 122 | rockspec, err = unpack_rockspec(file, dir_name) | ||
| 123 | end | ||
| 124 | if not rockspec then | ||
| 125 | return nil, err | ||
| 126 | end | ||
| 127 | if kind == "src" or kind == "rockspec" then | ||
| 128 | if rockspec.source.dir ~= "." then | ||
| 129 | local ok = fs.copy(rockspec.local_filename, rockspec.source.dir, cfg.perm_read) | ||
| 130 | if not ok then | ||
| 131 | return nil, "Failed copying unpacked rockspec into unpacked source directory." | ||
| 132 | end | ||
| 133 | end | ||
| 134 | util.printout() | ||
| 135 | util.printout("Done. You may now enter directory ") | ||
| 136 | util.printout(dir.path(dir_name, rockspec.source.dir)) | ||
| 137 | util.printout("and type 'luarocks make' to build.") | ||
| 138 | end | ||
| 139 | util.remove_scheduled_function(rollback) | ||
| 140 | return true | ||
| 141 | end | ||
| 142 | |||
| 143 | --- Driver function for the "unpack" command. | ||
| 144 | -- @param name string: may be a rock filename, for unpacking a | ||
| 145 | -- rock file or the name of a rock to be fetched and unpacked. | ||
| 146 | -- @param version string or nil: if the name of a package is given, a | ||
| 147 | -- version may also be passed. | ||
| 148 | -- @return boolean or (nil, string): true if successful or nil followed | ||
| 149 | -- by an error message. | ||
| 150 | function unpack.command(flags, name, version) | ||
| 151 | assert(type(version) == "string" or not version) | ||
| 152 | if type(name) ~= "string" then | ||
| 153 | return nil, "Argument missing. "..util.see_help("unpack") | ||
| 154 | end | ||
| 155 | |||
| 156 | if name:match(".*%.rock") or name:match(".*%.rockspec") then | ||
| 157 | return run_unpacker(name, flags["force"]) | ||
| 158 | else | ||
| 159 | local search = require("luarocks.search") | ||
| 160 | return search.act_on_src_or_rockspec(run_unpacker, name:lower(), version) | ||
| 161 | end | ||
| 162 | end | ||
| 163 | |||
| 164 | return unpack | ||
diff --git a/src/luarocks/cmd/upload.lua b/src/luarocks/cmd/upload.lua new file mode 100644 index 00000000..baee47ab --- /dev/null +++ b/src/luarocks/cmd/upload.lua | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | |||
| 2 | local upload = {} | ||
| 3 | |||
| 4 | local util = require("luarocks.util") | ||
| 5 | local fetch = require("luarocks.fetch") | ||
| 6 | local pack = require("luarocks.pack") | ||
| 7 | local cfg = require("luarocks.core.cfg") | ||
| 8 | local Api = require("luarocks.upload.api") | ||
| 9 | |||
| 10 | upload.help_summary = "Upload a rockspec to the public rocks repository." | ||
| 11 | upload.help_arguments = "[--skip-pack] [--api-key=<key>] [--force] <rockspec>" | ||
| 12 | upload.help = [[ | ||
| 13 | <rockspec> Pack a source rock file (.src.rock extension), | ||
| 14 | upload rockspec and source rock to server. | ||
| 15 | --skip-pack Do not pack and send source rock. | ||
| 16 | --api-key=<key> Give it an API key. It will be stored for subsequent uses. | ||
| 17 | --force Replace existing rockspec if the same revision of | ||
| 18 | a module already exists. This should be used only | ||
| 19 | in case of upload mistakes: when updating a rockspec, | ||
| 20 | increment the revision number instead. | ||
| 21 | ]] | ||
| 22 | |||
| 23 | function upload.command(flags, fname) | ||
| 24 | if not fname then | ||
| 25 | return nil, "Missing rockspec. "..util.see_help("upload") | ||
| 26 | end | ||
| 27 | |||
| 28 | local api, err = Api.new(flags) | ||
| 29 | if not api then | ||
| 30 | return nil, err | ||
| 31 | end | ||
| 32 | if cfg.verbose then | ||
| 33 | api.debug = true | ||
| 34 | end | ||
| 35 | |||
| 36 | local rockspec, err, errcode = fetch.load_rockspec(fname) | ||
| 37 | if err then | ||
| 38 | return nil, err, errcode | ||
| 39 | end | ||
| 40 | |||
| 41 | util.printout("Sending " .. tostring(fname) .. " ...") | ||
| 42 | local res, err = api:method("check_rockspec", { | ||
| 43 | package = rockspec.package, | ||
| 44 | version = rockspec.version | ||
| 45 | }) | ||
| 46 | if not res then return nil, err end | ||
| 47 | |||
| 48 | if not res.module then | ||
| 49 | util.printout("Will create new module (" .. tostring(rockspec.package) .. ")") | ||
| 50 | end | ||
| 51 | if res.version and not flags["force"] then | ||
| 52 | return nil, "Revision "..rockspec.version.." already exists on the server. "..util.see_help("upload") | ||
| 53 | end | ||
| 54 | |||
| 55 | local rock_fname | ||
| 56 | if not flags["skip-pack"] and not rockspec.version:match("^scm") then | ||
| 57 | util.printout("Packing " .. tostring(rockspec.package)) | ||
| 58 | rock_fname, err = pack.pack_source_rock(fname) | ||
| 59 | if not rock_fname then | ||
| 60 | return nil, err | ||
| 61 | end | ||
| 62 | end | ||
| 63 | |||
| 64 | local multipart = require("luarocks.upload.multipart") | ||
| 65 | |||
| 66 | res, err = api:method("upload", nil, { | ||
| 67 | rockspec_file = multipart.new_file(fname) | ||
| 68 | }) | ||
| 69 | if not res then return nil, err end | ||
| 70 | |||
| 71 | if res.is_new and #res.manifests == 0 then | ||
| 72 | util.printerr("Warning: module not added to root manifest due to name taken.") | ||
| 73 | end | ||
| 74 | |||
| 75 | local module_url = res.module_url | ||
| 76 | |||
| 77 | if rock_fname then | ||
| 78 | if (not res.version) or (not res.version.id) then | ||
| 79 | return nil, "Invalid response from server." | ||
| 80 | end | ||
| 81 | util.printout(("Sending " .. tostring(rock_fname) .. " ...")) | ||
| 82 | res, err = api:method("upload_rock/" .. ("%d"):format(res.version.id), nil, { | ||
| 83 | rock_file = multipart.new_file(rock_fname) | ||
| 84 | }) | ||
| 85 | if not res then return nil, err end | ||
| 86 | end | ||
| 87 | |||
| 88 | util.printout() | ||
| 89 | util.printout("Done: " .. tostring(module_url)) | ||
| 90 | util.printout() | ||
| 91 | return true | ||
| 92 | end | ||
| 93 | |||
| 94 | return upload | ||
diff --git a/src/luarocks/cmd/write_rockspec.lua b/src/luarocks/cmd/write_rockspec.lua new file mode 100644 index 00000000..be563eaa --- /dev/null +++ b/src/luarocks/cmd/write_rockspec.lua | |||
| @@ -0,0 +1,376 @@ | |||
| 1 | |||
| 2 | local write_rockspec = {} | ||
| 3 | |||
| 4 | local cfg = require("luarocks.core.cfg") | ||
| 5 | local dir = require("luarocks.dir") | ||
| 6 | local fetch = require("luarocks.fetch") | ||
| 7 | local fs = require("luarocks.fs") | ||
| 8 | local path = require("luarocks.path") | ||
| 9 | local persist = require("luarocks.persist") | ||
| 10 | local type_check = require("luarocks.type_check") | ||
| 11 | local util = require("luarocks.util") | ||
| 12 | local deps = require("luarocks.deps") | ||
| 13 | |||
| 14 | write_rockspec.help_summary = "Write a template for a rockspec file." | ||
| 15 | write_rockspec.help_arguments = "[--output=<file> ...] [<name>] [<version>] [<url>|<path>]" | ||
| 16 | write_rockspec.help = [[ | ||
| 17 | This command writes an initial version of a rockspec file, | ||
| 18 | based on a name, a version, and a location (an URL or a local path). | ||
| 19 | If only two arguments are given, the first one is considered the name and the | ||
| 20 | second one is the location. | ||
| 21 | If only one argument is given, it must be the location. | ||
| 22 | If no arguments are given, current directory is used as location. | ||
| 23 | LuaRocks will attempt to infer name and version if not given, | ||
| 24 | using 'scm' as default version. | ||
| 25 | |||
| 26 | Note that the generated file is a _starting point_ for writing a | ||
| 27 | rockspec, and is not guaranteed to be complete or correct. | ||
| 28 | |||
| 29 | --output=<file> Write the rockspec with the given filename. | ||
| 30 | If not given, a file is written in the current | ||
| 31 | directory with a filename based on given name and version. | ||
| 32 | --license="<string>" A license string, such as "MIT/X11" or "GNU GPL v3". | ||
| 33 | --summary="<txt>" A short one-line description summary. | ||
| 34 | --detailed="<txt>" A longer description string. | ||
| 35 | --homepage=<url> Project homepage. | ||
| 36 | --lua-version=<ver> Supported Lua versions. Accepted values are "5.1", "5.2", | ||
| 37 | "5.3", "5.1,5.2", "5.2,5.3", or "5.1,5.2,5.3". | ||
| 38 | --rockspec-format=<ver> Rockspec format version, such as "1.0" or "1.1". | ||
| 39 | --tag=<tag> Tag to use. Will attempt to extract version number from it. | ||
| 40 | --lib=<lib>[,<lib>] A comma-separated list of libraries that C files need to | ||
| 41 | link to. | ||
| 42 | ]] | ||
| 43 | |||
| 44 | local function open_file(name) | ||
| 45 | return io.open(dir.path(fs.current_dir(), name), "r") | ||
| 46 | end | ||
| 47 | |||
| 48 | local function get_url(rockspec) | ||
| 49 | local file, temp_dir, err_code, err_file, err_temp_dir = fetch.fetch_sources(rockspec, false) | ||
| 50 | if err_code == "source.dir" then | ||
| 51 | file, temp_dir = err_file, err_temp_dir | ||
| 52 | elseif not file then | ||
| 53 | util.warning("Could not fetch sources - "..temp_dir) | ||
| 54 | return false | ||
| 55 | end | ||
| 56 | util.printout("File successfully downloaded. Making checksum and checking base dir...") | ||
| 57 | if fetch.is_basic_protocol(rockspec.source.protocol) then | ||
| 58 | rockspec.source.md5 = fs.get_md5(file) | ||
| 59 | end | ||
| 60 | local inferred_dir, found_dir = fetch.find_base_dir(file, temp_dir, rockspec.source.url) | ||
| 61 | return true, found_dir or inferred_dir, temp_dir | ||
| 62 | end | ||
| 63 | |||
| 64 | local function configure_lua_version(rockspec, luaver) | ||
| 65 | if luaver == "5.1" then | ||
| 66 | table.insert(rockspec.dependencies, "lua ~> 5.1") | ||
| 67 | elseif luaver == "5.2" then | ||
| 68 | table.insert(rockspec.dependencies, "lua ~> 5.2") | ||
| 69 | elseif luaver == "5.3" then | ||
| 70 | table.insert(rockspec.dependencies, "lua ~> 5.3") | ||
| 71 | elseif luaver == "5.1,5.2" then | ||
| 72 | table.insert(rockspec.dependencies, "lua >= 5.1, < 5.3") | ||
| 73 | elseif luaver == "5.2,5.3" then | ||
| 74 | table.insert(rockspec.dependencies, "lua >= 5.2, < 5.4") | ||
| 75 | elseif luaver == "5.1,5.2,5.3" then | ||
| 76 | table.insert(rockspec.dependencies, "lua >= 5.1, < 5.4") | ||
| 77 | else | ||
| 78 | util.warning("Please specify supported Lua version with --lua-version=<ver>. "..util.see_help("write_rockspec")) | ||
| 79 | end | ||
| 80 | end | ||
| 81 | |||
| 82 | local function detect_description() | ||
| 83 | local fd = open_file("README.md") or open_file("README") | ||
| 84 | if not fd then return end | ||
| 85 | local data = fd:read("*a") | ||
| 86 | fd:close() | ||
| 87 | local paragraph = data:match("\n\n([^%[].-)\n\n") | ||
| 88 | if not paragraph then paragraph = data:match("\n\n(.*)") end | ||
| 89 | local summary, detailed | ||
| 90 | if paragraph then | ||
| 91 | detailed = paragraph | ||
| 92 | |||
| 93 | if #paragraph < 80 then | ||
| 94 | summary = paragraph:gsub("\n", "") | ||
| 95 | else | ||
| 96 | summary = paragraph:gsub("\n", " "):match("([^.]*%.) ") | ||
| 97 | end | ||
| 98 | end | ||
| 99 | return summary, detailed | ||
| 100 | end | ||
| 101 | |||
| 102 | local function detect_mit_license(data) | ||
| 103 | local strip_copyright = (data:gsub("Copyright [^\n]*\n", "")) | ||
| 104 | local sum = 0 | ||
| 105 | for i = 1, #strip_copyright do | ||
| 106 | local num = string.byte(strip_copyright:sub(i,i)) | ||
| 107 | if num > 32 and num <= 128 then | ||
| 108 | sum = sum + num | ||
| 109 | end | ||
| 110 | end | ||
| 111 | return sum == 78656 | ||
| 112 | end | ||
| 113 | |||
| 114 | local simple_scm_protocols = { | ||
| 115 | git = true, ["git+http"] = true, ["git+https"] = true, | ||
| 116 | hg = true, ["hg+http"] = true, ["hg+https"] = true | ||
| 117 | } | ||
| 118 | |||
| 119 | local function detect_url_from_command(program, args, directory) | ||
| 120 | local command = fs.Q(cfg.variables[program:upper()]).. " "..args | ||
| 121 | local pipe = io.popen(fs.command_at(directory, fs.quiet_stderr(command))) | ||
| 122 | if not pipe then return nil end | ||
| 123 | local url = pipe:read("*a"):match("^([^\r\n]+)") | ||
| 124 | pipe:close() | ||
| 125 | if not url then return nil end | ||
| 126 | if not util.starts_with(url, program.."://") then | ||
| 127 | url = program.."+"..url | ||
| 128 | end | ||
| 129 | |||
| 130 | if simple_scm_protocols[dir.split_url(url)] then | ||
| 131 | return url | ||
| 132 | end | ||
| 133 | end | ||
| 134 | |||
| 135 | local function detect_scm_url(directory) | ||
| 136 | return detect_url_from_command("git", "config --get remote.origin.url", directory) or | ||
| 137 | detect_url_from_command("hg", "paths default", directory) | ||
| 138 | end | ||
| 139 | |||
| 140 | local function show_license(rockspec) | ||
| 141 | local fd = open_file("COPYING") or open_file("LICENSE") or open_file("MIT-LICENSE.txt") | ||
| 142 | if not fd then return nil end | ||
| 143 | local data = fd:read("*a") | ||
| 144 | fd:close() | ||
| 145 | local is_mit = detect_mit_license(data) | ||
| 146 | util.title("License for "..rockspec.package..":") | ||
| 147 | util.printout(data) | ||
| 148 | util.printout() | ||
| 149 | return is_mit | ||
| 150 | end | ||
| 151 | |||
| 152 | local function get_cmod_name(file) | ||
| 153 | local fd = open_file(file) | ||
| 154 | if not fd then return nil end | ||
| 155 | local data = fd:read("*a") | ||
| 156 | fd:close() | ||
| 157 | return (data:match("int%s+luaopen_([a-zA-Z0-9_]+)")) | ||
| 158 | end | ||
| 159 | |||
| 160 | local luamod_blacklist = { | ||
| 161 | test = true, | ||
| 162 | tests = true, | ||
| 163 | } | ||
| 164 | |||
| 165 | local function fill_as_builtin(rockspec, libs) | ||
| 166 | rockspec.build.type = "builtin" | ||
| 167 | rockspec.build.modules = {} | ||
| 168 | local prefix = "" | ||
| 169 | |||
| 170 | for _, parent in ipairs({"src", "lua"}) do | ||
| 171 | if fs.is_dir(parent) then | ||
| 172 | fs.change_dir(parent) | ||
| 173 | prefix = parent.."/" | ||
| 174 | break | ||
| 175 | end | ||
| 176 | end | ||
| 177 | |||
| 178 | local incdirs, libdirs | ||
| 179 | if libs then | ||
| 180 | incdirs, libdirs = {}, {} | ||
| 181 | for _, lib in ipairs(libs) do | ||
| 182 | local upper = lib:upper() | ||
| 183 | incdirs[#incdirs+1] = "$("..upper.."_INCDIR)" | ||
| 184 | libdirs[#libdirs+1] = "$("..upper.."_LIBDIR)" | ||
| 185 | end | ||
| 186 | end | ||
| 187 | |||
| 188 | for _, file in ipairs(fs.find()) do | ||
| 189 | local luamod = file:match("(.*)%.lua$") | ||
| 190 | if luamod and not luamod_blacklist[luamod] then | ||
| 191 | rockspec.build.modules[path.path_to_module(file)] = prefix..file | ||
| 192 | else | ||
| 193 | local cmod = file:match("(.*)%.c$") | ||
| 194 | if cmod then | ||
| 195 | local modname = get_cmod_name(file) or path.path_to_module(file:gsub("%.c$", ".lua")) | ||
| 196 | rockspec.build.modules[modname] = { | ||
| 197 | sources = prefix..file, | ||
| 198 | libraries = libs, | ||
| 199 | incdirs = incdirs, | ||
| 200 | libdirs = libdirs, | ||
| 201 | } | ||
| 202 | end | ||
| 203 | end | ||
| 204 | end | ||
| 205 | |||
| 206 | for _, directory in ipairs({ "doc", "docs", "samples", "tests" }) do | ||
| 207 | if fs.is_dir(directory) then | ||
| 208 | if not rockspec.build.copy_directories then | ||
| 209 | rockspec.build.copy_directories = {} | ||
| 210 | end | ||
| 211 | table.insert(rockspec.build.copy_directories, directory) | ||
| 212 | end | ||
| 213 | end | ||
| 214 | |||
| 215 | if prefix ~= "" then | ||
| 216 | fs.pop_dir() | ||
| 217 | end | ||
| 218 | end | ||
| 219 | |||
| 220 | local function rockspec_cleanup(rockspec) | ||
| 221 | rockspec.source.file = nil | ||
| 222 | rockspec.source.protocol = nil | ||
| 223 | rockspec.variables = nil | ||
| 224 | rockspec.name = nil | ||
| 225 | rockspec.format_is_at_least = nil | ||
| 226 | end | ||
| 227 | |||
| 228 | function write_rockspec.command(flags, name, version, url_or_dir) | ||
| 229 | if not name then | ||
| 230 | url_or_dir = "." | ||
| 231 | elseif not version then | ||
| 232 | url_or_dir = name | ||
| 233 | name = nil | ||
| 234 | elseif not url_or_dir then | ||
| 235 | url_or_dir = version | ||
| 236 | version = nil | ||
| 237 | end | ||
| 238 | |||
| 239 | if flags["tag"] then | ||
| 240 | if not version then | ||
| 241 | version = flags["tag"]:gsub("^v", "") | ||
| 242 | end | ||
| 243 | end | ||
| 244 | |||
| 245 | local protocol, pathname = dir.split_url(url_or_dir) | ||
| 246 | if protocol == "file" then | ||
| 247 | if pathname == "." then | ||
| 248 | name = name or dir.base_name(fs.current_dir()) | ||
| 249 | end | ||
| 250 | elseif fetch.is_basic_protocol(protocol) then | ||
| 251 | local filename = dir.base_name(url_or_dir) | ||
| 252 | local newname, newversion = filename:match("(.*)-([^-]+)") | ||
| 253 | if newname then | ||
| 254 | name = name or newname | ||
| 255 | version = version or newversion:gsub("%.[a-z]+$", ""):gsub("%.tar$", "") | ||
| 256 | end | ||
| 257 | else | ||
| 258 | name = name or dir.base_name(url_or_dir):gsub("%.[^.]+$", "") | ||
| 259 | end | ||
| 260 | |||
| 261 | if not name then | ||
| 262 | return nil, "Could not infer rock name. "..util.see_help("write_rockspec") | ||
| 263 | end | ||
| 264 | version = version or "scm" | ||
| 265 | |||
| 266 | local filename = flags["output"] or dir.path(fs.current_dir(), name:lower().."-"..version.."-1.rockspec") | ||
| 267 | |||
| 268 | local rockspec = { | ||
| 269 | rockspec_format = flags["rockspec-format"], | ||
| 270 | package = name, | ||
| 271 | name = name:lower(), | ||
| 272 | version = version.."-1", | ||
| 273 | source = { | ||
| 274 | url = "*** please add URL for source tarball, zip or repository here ***", | ||
| 275 | tag = flags["tag"], | ||
| 276 | }, | ||
| 277 | description = { | ||
| 278 | summary = flags["summary"] or "*** please specify description summary ***", | ||
| 279 | detailed = flags["detailed"] or "*** please enter a detailed description ***", | ||
| 280 | homepage = flags["homepage"] or "*** please enter a project homepage ***", | ||
| 281 | license = flags["license"] or "*** please specify a license ***", | ||
| 282 | }, | ||
| 283 | dependencies = {}, | ||
| 284 | build = {}, | ||
| 285 | } | ||
| 286 | path.configure_paths(rockspec) | ||
| 287 | rockspec.source.protocol = protocol | ||
| 288 | rockspec.format_is_at_least = deps.format_is_at_least | ||
| 289 | |||
| 290 | configure_lua_version(rockspec, flags["lua-version"]) | ||
| 291 | |||
| 292 | local local_dir = url_or_dir | ||
| 293 | |||
| 294 | if url_or_dir:match("://") then | ||
| 295 | rockspec.source.url = url_or_dir | ||
| 296 | rockspec.source.file = dir.base_name(url_or_dir) | ||
| 297 | rockspec.source.dir = "dummy" | ||
| 298 | if not fetch.is_basic_protocol(rockspec.source.protocol) then | ||
| 299 | if version ~= "scm" then | ||
| 300 | rockspec.source.tag = flags["tag"] or "v" .. version | ||
| 301 | end | ||
| 302 | end | ||
| 303 | rockspec.source.dir = nil | ||
| 304 | local ok, base_dir, temp_dir = get_url(rockspec) | ||
| 305 | if ok then | ||
| 306 | if base_dir ~= dir.base_name(url_or_dir) then | ||
| 307 | rockspec.source.dir = base_dir | ||
| 308 | end | ||
| 309 | end | ||
| 310 | if base_dir then | ||
| 311 | local_dir = dir.path(temp_dir, base_dir) | ||
| 312 | else | ||
| 313 | local_dir = nil | ||
| 314 | end | ||
| 315 | else | ||
| 316 | rockspec.source.url = detect_scm_url(local_dir) or rockspec.source.url | ||
| 317 | end | ||
| 318 | |||
| 319 | if not local_dir then | ||
| 320 | local_dir = "." | ||
| 321 | end | ||
| 322 | |||
| 323 | if not flags["homepage"] then | ||
| 324 | local url_protocol, url_path = dir.split_url(rockspec.source.url) | ||
| 325 | |||
| 326 | if simple_scm_protocols[url_protocol] then | ||
| 327 | for _, domain in ipairs({"github.com", "bitbucket.org", "gitlab.com"}) do | ||
| 328 | if util.starts_with(url_path, domain) then | ||
| 329 | rockspec.description.homepage = "https://"..url_path:gsub("%.git$", "") | ||
| 330 | break | ||
| 331 | end | ||
| 332 | end | ||
| 333 | end | ||
| 334 | end | ||
| 335 | |||
| 336 | local libs = nil | ||
| 337 | if flags["lib"] then | ||
| 338 | libs = {} | ||
| 339 | rockspec.external_dependencies = {} | ||
| 340 | for lib in flags["lib"]:gmatch("([^,]+)") do | ||
| 341 | table.insert(libs, lib) | ||
| 342 | rockspec.external_dependencies[lib:upper()] = { | ||
| 343 | library = lib | ||
| 344 | } | ||
| 345 | end | ||
| 346 | end | ||
| 347 | |||
| 348 | local ok, err = fs.change_dir(local_dir) | ||
| 349 | if not ok then return nil, "Failed reaching files from project - error entering directory "..local_dir end | ||
| 350 | |||
| 351 | if (not flags["summary"]) or (not flags["detailed"]) then | ||
| 352 | local summary, detailed = detect_description() | ||
| 353 | rockspec.description.summary = flags["summary"] or summary | ||
| 354 | rockspec.description.detailed = flags["detailed"] or detailed | ||
| 355 | end | ||
| 356 | |||
| 357 | local is_mit = show_license(rockspec) | ||
| 358 | |||
| 359 | if is_mit and not flags["license"] then | ||
| 360 | rockspec.description.license = "MIT" | ||
| 361 | end | ||
| 362 | |||
| 363 | fill_as_builtin(rockspec, libs) | ||
| 364 | |||
| 365 | rockspec_cleanup(rockspec) | ||
| 366 | |||
| 367 | persist.save_from_table(filename, rockspec, type_check.rockspec_order) | ||
| 368 | |||
| 369 | util.printout() | ||
| 370 | util.printout("Wrote template at "..filename.." -- you should now edit and finish it.") | ||
| 371 | util.printout() | ||
| 372 | |||
| 373 | return true | ||
| 374 | end | ||
| 375 | |||
| 376 | return write_rockspec | ||
