aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHisham Muhammad <hisham@gobolinux.org>2019-03-14 23:18:53 -0300
committerHisham Muhammad <hisham@gobolinux.org>2019-04-03 10:44:51 -0300
commita21fcdc434f7135b3be215bbab5ad08f1873d300 (patch)
treefba8bd24af0e34804954455acb567467d8586b13
parent9c03508958522b2beeaa2aa289ad82e444d902d8 (diff)
downloadluarocks-a21fcdc434f7135b3be215bbab5ad08f1873d300.tar.gz
luarocks-a21fcdc434f7135b3be215bbab5ad08f1873d300.tar.bz2
luarocks-a21fcdc434f7135b3be215bbab5ad08f1873d300.zip
config: add modes for reading, writing and unsetting individual entries
Includes special config keys `lua_dir` and `lua_version`, which are essentially persistent versions of --lua-dir and --lua-version: * `lua_dir` writes a number of LUA_* variables and cfg.lua_interpreter in the current scope's config file. * `lua_version` writes default-lua-version.lua to the given scope. Also deprecates the "flag" versions for various getters: * `--lua-incdir`: use `luarocks config variables.LUA_INCDIR` * `--lua-libdir`: use `luarocks config variables.LUA_LIBDIR` * `--lua-ver`: use `luarocks config lua_version` * `--system-config`: use `luarocks config config_files.system.file` * `--user-config`: use `luarocks config config_files.user.file` * `--rock-trees`: use `luarocks config rocks_trees`
-rw-r--r--.gitignore1
-rw-r--r--spec/config_spec.lua241
-rw-r--r--src/luarocks/cmd.lua58
-rw-r--r--src/luarocks/cmd/config.lua330
-rw-r--r--src/luarocks/cmd/help.lua6
-rw-r--r--src/luarocks/cmd/init.lua9
-rw-r--r--src/luarocks/core/cfg.lua42
-rw-r--r--src/luarocks/fs/lua.lua2
-rw-r--r--src/luarocks/persist.lua35
-rw-r--r--src/luarocks/upload/api.lua5
-rw-r--r--src/luarocks/util.lua3
11 files changed, 534 insertions, 198 deletions
diff --git a/.gitignore b/.gitignore
index 628eab64..99850056 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,3 +14,4 @@
14/wiki 14/wiki
15/lua 15/lua
16/lua_modules 16/lua_modules
17/luarocks
diff --git a/spec/config_spec.lua b/spec/config_spec.lua
index defc1d2f..2e76ae0c 100644
--- a/spec/config_spec.lua
+++ b/spec/config_spec.lua
@@ -10,28 +10,58 @@ test_env.unload_luarocks()
10 10
11describe("LuaRocks config tests #integration", function() 11describe("LuaRocks config tests #integration", function()
12 12
13 before_each(function() 13 setup(function()
14 test_env.setup_specs() 14 test_env.setup_specs()
15 test_env.unload_luarocks() -- need to be required here, because hardcoded is created after first loading of specs 15 test_env.unload_luarocks() -- need to be required here, because hardcoded is created after first loading of specs
16 hardcoded = require("luarocks.core.hardcoded") 16 hardcoded = require("luarocks.core.hardcoded")
17 end) 17 end)
18 18
19 describe("LuaRocks config - basic tests", function() 19 describe("full configuration query", function()
20 it("LuaRocks config with no flags/arguments", function() 20 it("no flags/arguments", function()
21 assert.match("rocks_servers", run.luarocks("config")) 21 assert.match("rocks_servers = {", run.luarocks("config"))
22 end) 22 end)
23 23
24 it("LuaRocks config include dir returns a subdir of LUA_DIR", function() 24 it("--json", function()
25 assert.is_true(run.luarocks_nocov("install dkjson"))
26 finally(function()
27 assert.is_true(run.luarocks_nocov("remove dkjson"))
28 end)
29 assert.match('"rocks_servers":[', run.luarocks("config --json"), 1, true)
30 end)
31
32 it("--json fails without a json library", function()
33 assert.falsy(run.luarocks_bool("config --json"))
34 end)
35
36 it("with --tree respects custom config", function()
37 write_file("my_config.lua", [[
38 rocks_trees = {
39 {
40 name = "system",
41 root = "/example/tree",
42 lua_dir = "/example/luadir",
43 },
44 }
45 ]], finally)
46 local output = run.luarocks("config", {LUAROCKS_CONFIG = "my_config.lua"})
47 assert.match([[deploy_lua_dir = "/example/luadir"]], output)
48 output = run.luarocks("config --tree=system", {LUAROCKS_CONFIG = "my_config.lua"})
49 assert.match([[deploy_lua_dir = "/example/luadir"]], output)
50 end)
51 end)
52
53 describe("query flags", function()
54 it("--lua-incdir returns a subdir of LUA_DIR", function()
25 local output = run.luarocks("config --lua-incdir") 55 local output = run.luarocks("config --lua-incdir")
26 assert.match(hardcoded.LUA_DIR, output, 1, true) 56 assert.match(hardcoded.LUA_DIR, output, 1, true)
27 end) 57 end)
28 58
29 it("LuaRocks config library dir returns a subdir of LUA_DIR", function() 59 it("--lua-libdir returns a subdir of LUA_DIR", function()
30 local output = run.luarocks("config --lua-libdir") 60 local output = run.luarocks("config --lua-libdir")
31 assert.match(hardcoded.LUA_DIR, output, 1, true) 61 assert.match(hardcoded.LUA_DIR, output, 1, true)
32 end) 62 end)
33 63
34 it("LuaRocks config lua version", function() 64 it("--lua-ver returns the Lua version", function()
35 local output = run.luarocks("config --lua-ver") 65 local output = run.luarocks("config --lua-ver")
36 local lua_version = _VERSION:gsub("Lua ", "") 66 local lua_version = _VERSION:gsub("Lua ", "")
37 if test_env.LUAJIT_V then 67 if test_env.LUAJIT_V then
@@ -40,77 +70,158 @@ describe("LuaRocks config tests #integration", function()
40 assert.are.same(lua_version, output) 70 assert.are.same(lua_version, output)
41 end) 71 end)
42 72
43 it("LuaRocks config rock trees", function() 73 it("--rock-trees lists rock trees", function()
44 assert.is_true(run.luarocks_bool("config --rock-trees")) 74 assert.is_true(run.luarocks_bool("config --rock-trees"))
45 end) 75 end)
46 76
47 it("LuaRocks config user config", function() 77 describe("--user-config", function()
48 local user_config_path = run.luarocks("config --user-config") 78 it("returns user config dir", function()
49 assert.is.truthy(lfs.attributes(user_config_path)) 79 local user_config_path = run.luarocks("config --user-config")
50 end) 80 assert.is.truthy(lfs.attributes(user_config_path))
81 end)
51 82
52 it("LuaRocks config missing user config", function() 83 it("handles a missing user config", function()
53 local output = run.luarocks("config --user-config", {LUAROCKS_CONFIG = "missing_file.lua"}) 84 local output = run.luarocks("config --user-config", {LUAROCKS_CONFIG = "missing_file.lua"})
54 assert.truthy(output:match("Warning")) 85 assert.match("Warning", output)
86 end)
55 end) 87 end)
56 88
57 it("LuaRocks config with --tree respects custom config", function() 89 describe("--system-config", function()
58 write_file("my_config.lua", [[ 90 local scdir = testing_paths.testing_lrprefix .. "/etc/luarocks"
59 rocks_trees = { 91 local configfile = scdir .. "/config-" .. env_variables.LUA_VERSION .. ".lua"
60 { 92
61 name = "system", 93 it("fails if system config doesn't exist", function()
62 root = "/example/tree", 94 os.rename(configfile, configfile .. ".bak")
63 lua_dir = "/example/luadir", 95 finally(function()
64 }, 96 os.rename(configfile .. ".bak", configfile)
65 } 97 end)
66 ]], finally) 98 assert.is_false(run.luarocks_bool("config --system-config"))
67 local output = run.luarocks("config", {LUAROCKS_CONFIG = "my_config.lua"}) 99 end)
68 assert.match([[deploy_lua_dir = "/example/luadir"]], output) 100
69 output = run.luarocks("config --tree=system", {LUAROCKS_CONFIG = "my_config.lua"}) 101 it("outputs the path of the system config", function()
70 assert.match([[deploy_lua_dir = "/example/luadir"]], output) 102 lfs.mkdir(testing_paths.testing_lrprefix)
103 lfs.mkdir(testing_paths.testing_lrprefix .. "/etc/")
104 lfs.mkdir(scdir)
105
106 local sysconfig = io.open(configfile, "w+")
107 sysconfig:write(" ")
108 sysconfig:close()
109 finally(function()
110 os.remove(configfile)
111 end)
112
113 local output = run.luarocks("config --system-config")
114 assert.are.same(configfile, output)
115 end)
116
117 it("fails if system config is invalid", function()
118 lfs.mkdir(testing_paths.testing_lrprefix)
119 lfs.mkdir(testing_paths.testing_lrprefix .. "/etc/")
120 lfs.mkdir(scdir)
121
122 local sysconfig = io.open(configfile, "w+")
123 sysconfig:write("if if if")
124 sysconfig:close()
125 finally(function()
126 os.remove(configfile)
127 end)
128 assert.is_false(run.luarocks_bool("config --system-config"))
129 end)
71 end) 130 end)
72 end) 131 end)
73 132
74 describe("LuaRocks config - more complex tests", function() 133 describe("read config keys", function()
75 local scdir = testing_paths.testing_lrprefix .. "/etc/luarocks" 134 it("reads a simple config key", function()
76 local configfile = scdir .. "/config-" .. env_variables.LUA_VERSION .. ".lua" 135 local output = run.luarocks("config user_agent")
136 assert.match("LuaRocks/", output)
137 end)
77 138
78 it("LuaRocks fail system config", function() 139 it("reads an array config key", function()
79 os.rename(configfile, configfile .. ".bak") 140 local output = run.luarocks("config rocks_trees[2]")
80 finally(function() 141 assert.match("{%s*name", output)
81 os.rename(configfile .. ".bak", configfile)
82 end)
83 assert.is_false(run.luarocks_bool("config --system-config"))
84 end) 142 end)
85 143
86 it("LuaRocks system config", function() 144 it("can read as JSON", function()
87 lfs.mkdir(testing_paths.testing_lrprefix) 145 assert.is_true(run.luarocks_nocov("install dkjson"))
88 lfs.mkdir(testing_paths.testing_lrprefix .. "/etc/")
89 lfs.mkdir(scdir)
90
91 local sysconfig = io.open(configfile, "w+")
92 sysconfig:write(" ")
93 sysconfig:close()
94 finally(function() 146 finally(function()
95 os.remove(configfile) 147 assert.is_true(run.luarocks_nocov("remove dkjson"))
96 end) 148 end)
97 149 local output = run.luarocks("config rocks_trees --json")
98 local output = run.luarocks("config --system-config") 150 assert.match('^%["', output)
99 assert.are.same(configfile, output)
100 end) 151 end)
101 152
102 it("LuaRocks fail system config invalid", function() 153 it("--json does not work without a json library", function()
103 lfs.mkdir(testing_paths.testing_lrprefix) 154 assert.is_false(run.luarocks_bool("config rocks_trees --json"))
104 lfs.mkdir(testing_paths.testing_lrprefix .. "/etc/") 155 end)
105 lfs.mkdir(scdir) 156
106 157 it("reads an array -> hash config key", function()
107 local sysconfig = io.open(configfile, "w+") 158 local output = run.luarocks("config rocks_trees[2].name")
108 sysconfig:write("if if if") 159 assert.match("[a-z]+", output)
109 sysconfig:close()
110 finally(function()
111 os.remove(configfile)
112 end)
113 assert.is_false(run.luarocks_bool("config --system-config"))
114 end) 160 end)
161
162 it("reads a hash config key", function()
163 local output = run.luarocks("config variables.ICACLS")
164 assert.same("icacls", output)
165 end)
166
167 it("fails on invalid config key", function()
168 local output = run.luarocks("config xyz")
169 assert.match("Error: Unknown entry xyz", output)
170 end)
171 end)
172
173 describe("write config keys", function()
174 it("rejects invalid --scope", function()
175 assert.is_false(run.luarocks_bool("config web_browser foo --scope=foo"))
176 end)
177
178 it("reads an array config key", function()
179 local output = run.luarocks("config rocks_trees[2]")
180 assert.match("{%s*name", output)
181 end)
182
183 it("writes a simple config key", function()
184 test_env.run_in_tmp(function(tmpdir)
185 local myproject = tmpdir .. "/myproject"
186 lfs.mkdir(myproject)
187 lfs.chdir(myproject)
188
189 assert(run.luarocks("init"))
190 assert.truthy(run.luarocks_bool("config web_browser foo --scope=project"))
191
192 local output = run.luarocks("config web_browser")
193 assert.match("foo", output)
194 end, finally)
195 end)
196
197 it("writes a hash config key", function()
198 test_env.run_in_tmp(function(tmpdir)
199 local myproject = tmpdir .. "/myproject"
200 lfs.mkdir(myproject)
201 lfs.chdir(myproject)
202
203 assert(run.luarocks("init"))
204 assert.truthy(run.luarocks_bool("config variables.FOO_DIR /foo/bar --scope=project"))
205
206 local output = run.luarocks("config variables.FOO_DIR")
207 assert.match("/foo/bar", output)
208 end, finally)
209 end)
210
211 it("writes an array config key", function()
212 test_env.run_in_tmp(function(tmpdir)
213 local myproject = tmpdir .. "/myproject"
214 lfs.mkdir(myproject)
215 lfs.chdir(myproject)
216
217 assert(run.luarocks("init"))
218 assert.truthy(run.luarocks_bool("config external_deps_patterns.lib[1] testtest --scope=project"))
219
220 local output = run.luarocks("config external_deps_patterns.lib[1]")
221 assert.match("testtest", output)
222 end, finally)
223 end)
224
115 end) 225 end)
226
116end) 227end)
diff --git a/src/luarocks/cmd.lua b/src/luarocks/cmd.lua
index eb120c0b..d038852b 100644
--- a/src/luarocks/cmd.lua
+++ b/src/luarocks/cmd.lua
@@ -152,6 +152,33 @@ local function process_server_flags(flags)
152 return true 152 return true
153end 153end
154 154
155local function get_lua_version(flags)
156 if flags["lua-version"] then
157 return flags["lua-version"]
158 end
159 local dirs = {
160 cfg.home_tree,
161 cfg.sysconfdir,
162 }
163 if flags["project-tree"] then
164 table.insert(dirs, 1, dir.path(flags["project-tree"], ".."))
165 end
166 for _, d in ipairs(dirs) do
167 local f = dir.path(d, ".luarocks", "default-lua-version.lua")
168 local mod, err = loadfile(f, "t")
169 if mod then
170 local pok, ver = pcall(mod)
171 if pok and type(ver) == "string" and ver:match("%d+.%d+") then
172 if flags["verbose"] then
173 util.printout("Defaulting to Lua " .. ver .. " based on " .. f .. " ...")
174 end
175 return ver
176 end
177 end
178 end
179 return nil
180end
181
155--- Main command-line processor. 182--- Main command-line processor.
156-- Parses input arguments and calls the appropriate driver function 183-- Parses input arguments and calls the appropriate driver function
157-- to execute the action requested on the command-line, forwarding 184-- to execute the action requested on the command-line, forwarding
@@ -249,6 +276,16 @@ function cmd.run_command(description, commands, external_namespace, ...)
249 end 276 end
250 command = command:gsub("-", "_") 277 command = command:gsub("-", "_")
251 278
279 if command == "config" then
280 if nonflags[1] == "lua_version" and nonflags[2] then
281 flags["lua-version"] = nonflags[2]
282 elseif nonflags[1] == "lua_dir" and nonflags[2] then
283 flags["lua-dir"] = nonflags[2]
284 end
285 end
286
287 local lua_version = get_lua_version(flags)
288
252 if flags["deps-mode"] and not deps.check_deps_mode_flag(flags["deps-mode"]) then 289 if flags["deps-mode"] and not deps.check_deps_mode_flag(flags["deps-mode"]) then
253 die("Invalid entry for --deps-mode.") 290 die("Invalid entry for --deps-mode.")
254 end 291 end
@@ -256,47 +293,44 @@ function cmd.run_command(description, commands, external_namespace, ...)
256 local detected 293 local detected
257 if flags["lua-dir"] then 294 if flags["lua-dir"] then
258 local err 295 local err
259 detected, err = util.find_lua(flags["lua-dir"], flags["lua-version"]) 296 detected, err = util.find_lua(flags["lua-dir"], lua_version)
260 if not detected then 297 if not detected then
261 die(err) 298 die(err)
262 end 299 end
263 assert(detected.lua_version) 300 assert(detected.lua_version)
264 assert(detected.lua_dir) 301 assert(detected.lua_dir)
265 elseif flags["lua-version"] then 302 elseif lua_version then
266 local path_sep = (package.config:sub(1, 1) == "\\" and ";" or ":") 303 local path_sep = (package.config:sub(1, 1) == "\\" and ";" or ":")
267 for bindir in os.getenv("PATH"):gmatch("[^"..path_sep.."]+") do 304 for bindir in os.getenv("PATH"):gmatch("[^"..path_sep.."]+") do
268 local parentdir = bindir:gsub("[\\/][^\\/]+[\\/]?$", "") 305 local parentdir = bindir:gsub("[\\/][^\\/]+[\\/]?$", "")
269 detected = util.find_lua(dir.path(parentdir), flags["lua-version"]) 306 detected = util.find_lua(dir.path(parentdir), lua_version)
270 if detected then 307 if detected then
271 break 308 break
272 end 309 end
273 detected = util.find_lua(bindir, flags["lua-version"]) 310 detected = util.find_lua(bindir, lua_version)
274 if detected then 311 if detected then
275 break 312 break
276 end 313 end
277 end 314 end
278 if not detected then 315 if not detected then
279 util.warning("Could not find a Lua interpreter for version " .. 316 util.warning("Could not find a Lua interpreter for version " ..
280 flags["lua-version"] .. " in your PATH. " .. 317 lua_version .. " in your PATH. " ..
281 "Modules may not install with the correct configurations. " .. 318 "Modules may not install with the correct configurations. " ..
282 "You may want to specify to the path prefix to your build " .. 319 "You may want to specify to the path prefix to your build " ..
283 "of Lua " .. flags["lua-version"] .. " using --lua-dir") 320 "of Lua " .. lua_version .. " using --lua-dir")
284 detected = { 321 detected = {
285 lua_version = flags["lua-version"], 322 lua_version = lua_version,
286 } 323 }
287 end 324 end
288 end 325 end
289 326
290 if flags["project-tree"] then 327 if flags["project-tree"] then
291 local project_tree = flags["project-tree"]:gsub("[/\\][^/\\]+$", "") 328 local project_tree = flags["project-tree"]:gsub("[/\\][^/\\]+$", "")
292 detected = detected or { 329 detected = detected or {}
293 project_dir = project_tree 330 detected.project_dir = project_tree
294 }
295 local d = check_if_config_is_present(detected, project_tree) 331 local d = check_if_config_is_present(detected, project_tree)
296 if d then 332 if d then
297 detected = d 333 detected = d
298 else
299 detected.project_dir = nil
300 end 334 end
301 else 335 else
302 detected = detected or {} 336 detected = detected or {}
diff --git a/src/luarocks/cmd/config.lua b/src/luarocks/cmd/config.lua
index 794cc989..5c7cc6c9 100644
--- a/src/luarocks/cmd/config.lua
+++ b/src/luarocks/cmd/config.lua
@@ -2,26 +2,61 @@
2-- Queries information about the LuaRocks configuration. 2-- Queries information about the LuaRocks configuration.
3local config_cmd = {} 3local config_cmd = {}
4 4
5local persist = require("luarocks.persist")
5local cfg = require("luarocks.core.cfg") 6local cfg = require("luarocks.core.cfg")
6local util = require("luarocks.util") 7local util = require("luarocks.util")
7local deps = require("luarocks.deps") 8local deps = require("luarocks.deps")
8local dir = require("luarocks.dir") 9local dir = require("luarocks.dir")
9local fun = require("luarocks.fun") 10local fs = require("luarocks.fs")
10 11
11config_cmd.help_summary = "Query information about the LuaRocks configuration." 12config_cmd.help_summary = "Query information about the LuaRocks configuration."
12config_cmd.help_arguments = "<flag>" 13config_cmd.help_arguments = "(<key> | <key> <value> --scope=<scope> | <key> --unset --scope=<scope> | )"
13config_cmd.help = [[ 14config_cmd.help = [[
14--lua-incdir Path to Lua header files. 15* When given a configuration key, it prints the value of that key
16 according to the currently active configuration (taking into account
17 all config files and any command-line flags passed)
15 18
16--lua-libdir Path to Lua library files. 19 Examples:
20 luarocks config lua_interpreter
21 luarocks config variables.LUA_INCDIR
22 luarocks config lua_version
17 23
18--lua-ver Lua version (in major.minor format). e.g. 5.1 24* When given a configuration key and a value,
25 it overwrites the config file (see the --scope option below to determine which)
26 and replaces the value of the given key with the given value.
19 27
20--system-config Location of the system config file. 28 * `lua_dir` is a special key as it checks for a valid Lua installation
29 (equivalent to --lua-dir) and sets several keys at once.
30 * `lua_version` is a special key as it changes the default Lua version
31 used by LuaRocks commands (eqivalent to passing --lua-version).
21 32
22--user-config Location of the user config file. 33 Examples:
34 luarocks config variables.OPENSSL_DIR /usr/local/openssl
35 luarocks config lua_dir /usr/local
36 luarocks config lua_version 5.3
23 37
24--rock-trees Rocks trees in use. First the user tree, then the system tree. 38* When given a configuration key and --unset,
39 it overwrites the config file (see the --scope option below to determine which)
40 and deletes that key from the file.
41
42 Example: luarocks config variables.OPENSSL_DIR --unset
43
44* When given no arguments, it prints the entire currently active
45 configuration, resulting from reading the config files from
46 all scopes.
47
48 Example: luarocks config
49
50OPTIONS
51--scope=<scope> The scope indicates which config file should be rewritten.
52 Accepted values are "system", "user" or "project".
53 * Using a wrapper created with `luarocks init`,
54 the default is "project".
55 * Using --local (or when `local_by_default` is `true`),
56 the default is "user".
57 * Otherwise, the default is "system".
58
59--json Output as JSON
25]] 60]]
26config_cmd.help_see_also = [[ 61config_cmd.help_see_also = [[
27 https://github.com/luarocks/luarocks/wiki/Config-file-format 62 https://github.com/luarocks/luarocks/wiki/Config-file-format
@@ -30,35 +65,13 @@ config_cmd.help_see_also = [[
30 65
31local function config_file(conf) 66local function config_file(conf)
32 print(dir.normalize(conf.file)) 67 print(dir.normalize(conf.file))
33 if conf.ok then 68 if conf.found then
34 return true 69 return true
35 else 70 else
36 return nil, "file not found" 71 return nil, "file not found"
37 end 72 end
38end 73end
39 74
40local function printf(fmt, ...)
41 print((fmt):format(...))
42end
43
44local cfg_maps = {
45 external_deps_patterns = true,
46 external_deps_subdirs = true,
47 rocks_provided = true,
48 rocks_provided_3_0 = true,
49 runtime_external_deps_patterns = true,
50 runtime_external_deps_subdirs = true,
51 upload = true,
52 variables = true,
53}
54
55local cfg_arrays = {
56 disabled_servers = true,
57 external_deps_dirs = true,
58 rocks_trees = true,
59 rocks_servers = true,
60}
61
62local cfg_skip = { 75local cfg_skip = {
63 errorcodes = true, 76 errorcodes = true,
64 flags = true, 77 flags = true,
@@ -67,60 +80,163 @@ local cfg_skip = {
67 upload_servers = true, 80 upload_servers = true,
68} 81}
69 82
70local function print_config(cfg) 83local function should_skip(k, v)
71 for k, v in util.sortedpairs(cfg) do 84 return type(v) == "function" or cfg_skip[k]
72 k = tostring(k) 85end
73 if type(v) == "string" or type(v) == "number" then 86
74 printf("%s = %q", k, v) 87local function cleanup(tbl)
75 elseif type(v) == "boolean" then 88 local copy = {}
76 printf("%s = %s", k, tostring(v)) 89 for k, v in pairs(tbl) do
77 elseif type(v) == "function" or cfg_skip[k] then 90 if not should_skip(k, v) then
78 -- skip 91 copy[k] = v
79 elseif cfg_maps[k] then 92 end
80 printf("%s = {", k) 93 end
81 for kk, vv in util.sortedpairs(v) do 94 return copy
82 local keyfmt = kk:match("^[a-zA-Z_][a-zA-Z0-9_]*$") and "%s" or "[%q]" 95end
83 if type(vv) == "table" then 96
84 local qvs = fun.map(vv, function(e) return string.format("%q", e) end) 97local function traverse_varstring(var, tbl, fn, missing_parent)
85 printf(" "..keyfmt.." = {%s},", kk, table.concat(qvs, ", ")) 98 local k, r = var:match("^%[([0-9]+)%]%.(.*)$")
99 if k then
100 k = tonumber(k)
101 else
102 k, r = var:match("^([^.[]+)%.(.*)$")
103 if not k then
104 k, r = var:match("^([^[]+)(%[.*)$")
105 end
106 end
107
108 if k then
109 if not tbl[k] and missing_parent then
110 missing_parent(tbl, k)
111 end
112
113 if tbl[k] then
114 return traverse_varstring(r, tbl[k], fn, missing_parent)
115 else
116 return nil, "Unknown entry " .. k
117 end
118 end
119
120 local i = var:match("^%[([0-9]+)%]$")
121 if i then
122 var = tonumber(i)
123 end
124
125 return fn(tbl, var)
126end
127
128local function print_json(value)
129 local json_ok, json = util.require_json()
130 if not json_ok then
131 return nil, "A JSON library is required for this command. "..json
132 end
133
134 print(json.encode(value))
135 return true
136end
137
138local function print_entry(var, tbl, is_json)
139 return traverse_varstring(var, tbl, function(t, k)
140 if not t[k] then
141 return nil, "Unknown entry " .. k
142 end
143 local val = t[k]
144
145 if not should_skip(var, val) then
146 if is_json then
147 return print_json(val)
148 elseif type(val) == "string" then
149 print(val)
150 else
151 persist.write_value(io.stdout, val)
152 end
153 end
154 return true
155 end)
156end
157
158local function infer_type(var)
159 local typ
160 traverse_varstring(var, cfg, function(t, k)
161 if t[k] ~= nil then
162 typ = type(t[k])
163 end
164 end)
165 return typ
166end
167
168local function write_entries(keys, scope, do_unset)
169 if scope == "project" and not cfg.config_files.project then
170 return nil, "Current directory is not part of a project. You may want to run `luarocks init`."
171 end
172
173 local tbl, err = persist.load_config_file_if_basic(cfg.config_files[scope].file, cfg)
174 if not tbl then
175 return nil, err
176 end
177
178 for var, val in util.sortedpairs(keys) do
179 traverse_varstring(var, tbl, function(t, k)
180 if do_unset then
181 t[k] = nil
182 else
183 local typ = infer_type(var)
184 local v
185 if typ == "number" and tonumber(val) then
186 v = tonumber(val)
187 elseif typ == "boolean" and val == "true" then
188 v = true
189 elseif typ == "boolean" and val == "false" then
190 v = false
86 else 191 else
87 printf(" "..keyfmt.." = %q,", kk, vv) 192 v = val
88 end 193 end
194 t[k] = v
195 keys[var] = v
89 end 196 end
90 printf("}") 197 return true
91 elseif cfg_arrays[k] then 198 end, function(p, k)
92 if #v == 0 then 199 p[k] = {}
93 printf("%s = {}", k) 200 end)
201 end
202
203 local ok, err = persist.save_from_table(cfg.config_files[scope].file, tbl)
204 if ok then
205 print(do_unset and "Removed" or "Wrote")
206 for var, val in util.sortedpairs(keys) do
207 if do_unset then
208 print(("\t%s"):format(var))
94 else 209 else
95 printf("%s = {", k) 210 print(("\t%s = %q"):format(var, val))
96 for _, vv in ipairs(v) do
97 if type(vv) == "string" then
98 printf(" %q,", vv)
99 elseif type(vv) == "table" then
100 printf(" {")
101 if next(vv) == 1 then
102 for _, v3 in ipairs(vv) do
103 printf(" %q,", v3)
104 end
105 else
106 for k3, v3 in util.sortedpairs(vv) do
107 local keyfmt = tostring(k3):match("^[a-zA-Z_][a-zA-Z0-9_]*$") and "%s" or "[%q]"
108 printf(" "..keyfmt.." = %q,", k3, v3)
109 end
110 end
111 printf(" },")
112 end
113 end
114 printf("}")
115 end 211 end
116 end 212 end
213 print(do_unset and "from" or "to")
214 print("\t" .. cfg.config_files[scope].file)
215 return true
216 else
217 return nil, err
218 end
219end
220
221local function check_scope(flags)
222 local scope = flags["scope"]
223 or (flags["local"] and "user")
224 or (flags["project-tree"] and "project")
225 or (cfg.local_by_default and "user")
226 or "system"
227 if scope ~= "system" and scope ~= "user" and scope ~= "project" then
228 return nil, "Valid values for scope are: system, user, project"
117 end 229 end
230
231 return scope
118end 232end
119 233
120--- Driver function for "config" command. 234--- Driver function for "config" command.
121-- @return boolean: True if succeeded, nil on errors. 235-- @return boolean: True if succeeded, nil on errors.
122function config_cmd.command(flags) 236function config_cmd.command(flags, var, val)
123 deps.check_lua(cfg.variables) 237 deps.check_lua(cfg.variables)
238
239 -- deprecated flags
124 if flags["lua-incdir"] then 240 if flags["lua-incdir"] then
125 print(cfg.variables.LUA_INCDIR) 241 print(cfg.variables.LUA_INCDIR)
126 return true 242 return true
@@ -133,12 +249,11 @@ function config_cmd.command(flags)
133 print(cfg.lua_version) 249 print(cfg.lua_version)
134 return true 250 return true
135 end 251 end
136 local conf = cfg.which_config()
137 if flags["system-config"] then 252 if flags["system-config"] then
138 return config_file(conf.system) 253 return config_file(cfg.config_files.system)
139 end 254 end
140 if flags["user-config"] then 255 if flags["user-config"] then
141 return config_file(conf.user) 256 return config_file(cfg.config_files.user)
142 end 257 end
143 if flags["rock-trees"] then 258 if flags["rock-trees"] then
144 for _, tree in ipairs(cfg.rocks_trees) do 259 for _, tree in ipairs(cfg.rocks_trees) do
@@ -151,9 +266,68 @@ function config_cmd.command(flags)
151 end 266 end
152 return true 267 return true
153 end 268 end
269
270 if var == "lua_version" and val then
271 local scope, err = check_scope(flags)
272 if not scope then
273 return nil, err
274 end
275
276 if scope == "project" and not cfg.config_files.project then
277 return nil, "Current directory is not part of a project. You may want to run `luarocks init`."
278 end
279
280 local prefix = dir.dir_name(cfg.config_files[scope].file)
281 local ok, err = fs.make_dir(prefix)
282 if not ok then
283 return nil, "could not set default Lua version: " .. err
284 end
285 local fd, err = io.open(dir.path(prefix, "default-lua-version.lua"), "w")
286 if not fd then
287 return nil, "could not set default Lua version: " .. err
288 end
289
290 fd:write('return "' .. val .. '"\n')
291 fd:close()
292 print("Lua version will default to " .. val .. " in " .. prefix)
293 end
154 294
155 print_config(cfg) 295 if var == "lua_dir" and val then
156 return true 296 local scope, err = check_scope(flags)
297 if not scope then
298 return nil, err
299 end
300 local keys = {
301 ["variables.LUA_DIR"] = cfg.variables.LUA_DIR,
302 ["variables.LUA_BINDIR"] = cfg.variables.LUA_BINDIR,
303 ["variables.LUA_INCDIR"] = cfg.variables.LUA_INCDIR,
304 ["variables.LUA_LIBDIR"] = cfg.variables.LUA_LIBDIR,
305 ["lua_interpreter"] = cfg.lua_interpreter,
306 }
307 return write_entries(keys, scope, flags["unset"])
308 end
309
310 if var then
311 if val or flags["unset"] then
312 local scope, err = check_scope(flags)
313 if not scope then
314 return nil, err
315 end
316
317 return write_entries({ [var] = val }, scope, flags["unset"])
318 else
319 return print_entry(var, cfg, flags["json"])
320 end
321 end
322
323 local cleancfg = cleanup(cfg)
324
325 if flags["json"] then
326 return print_json(cleancfg)
327 else
328 print(persist.save_from_table_to_string(cleancfg))
329 return true
330 end
157end 331end
158 332
159return config_cmd 333return config_cmd
diff --git a/src/luarocks/cmd/help.lua b/src/luarocks/cmd/help.lua
index e5f1b799..dcc9e358 100644
--- a/src/luarocks/cmd/help.lua
+++ b/src/luarocks/cmd/help.lua
@@ -90,14 +90,14 @@ function help.command(description, commands, command)
90 util.printout() 90 util.printout()
91 util.printout("\tConfiguration files:") 91 util.printout("\tConfiguration files:")
92 local conf = cfg.config_files 92 local conf = cfg.config_files
93 util.printout("\t\tSystem : ".. dir.normalize(conf.system.file) .. " (" .. get_status(conf.system.ok) ..")") 93 util.printout("\t\tSystem : ".. dir.normalize(conf.system.file) .. " (" .. get_status(conf.system.found) ..")")
94 if conf.user.file then 94 if conf.user.file then
95 util.printout("\t\tUser : ".. dir.normalize(conf.user.file) .. " (" .. get_status(conf.user.ok) ..")") 95 util.printout("\t\tUser : ".. dir.normalize(conf.user.file) .. " (" .. get_status(conf.user.found) ..")")
96 else 96 else
97 util.printout("\t\tUser : disabled in this LuaRocks installation.") 97 util.printout("\t\tUser : disabled in this LuaRocks installation.")
98 end 98 end
99 if conf.project then 99 if conf.project then
100 util.printout("\t\tProject : ".. dir.normalize(conf.project.file) .. " (" .. get_status(conf.project.ok) ..")") 100 util.printout("\t\tProject : ".. dir.normalize(conf.project.file) .. " (" .. get_status(conf.project.found) ..")")
101 end 101 end
102 util.printout() 102 util.printout()
103 util.printout("\tRocks trees in use: ") 103 util.printout("\tRocks trees in use: ")
diff --git a/src/luarocks/cmd/init.lua b/src/luarocks/cmd/init.lua
index b1bb3b51..3b8c9fea 100644
--- a/src/luarocks/cmd/init.lua
+++ b/src/luarocks/cmd/init.lua
@@ -92,14 +92,7 @@ function init.command(flags, name, version)
92 92
93 if flags["reset"] then 93 if flags["reset"] then
94 fs.delete(lua_wrapper) 94 fs.delete(lua_wrapper)
95 for v in util.lua_versions() do 95 fs.delete(dir.path(".luarocks", "default_lua_version.lua"))
96 local config_file = dir.path(".luarocks", "config-"..v..".lua")
97 if v ~= cfg.lua_version then
98 fs.move(config_file, config_file .. "~")
99 else
100 fs.delete(config_file)
101 end
102 end
103 end 96 end
104 97
105 util.printout("Adding entries to .gitignore ...") 98 util.printout("Adding entries to .gitignore ...")
diff --git a/src/luarocks/core/cfg.lua b/src/luarocks/core/cfg.lua
index 0c2e3f67..af4327c6 100644
--- a/src/luarocks/core/cfg.lua
+++ b/src/luarocks/core/cfg.lua
@@ -728,33 +728,31 @@ function cfg.init(detected, warning)
728 cfg.variables.LUA = cfg.variables.LUA or (cfg.variables.LUA_BINDIR and (cfg.variables.LUA_BINDIR .. "/" .. cfg.lua_interpreter):gsub("//", "/")) 728 cfg.variables.LUA = cfg.variables.LUA or (cfg.variables.LUA_BINDIR and (cfg.variables.LUA_BINDIR .. "/" .. cfg.lua_interpreter):gsub("//", "/"))
729 cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch 729 cfg.user_agent = "LuaRocks/"..cfg.program_version.." "..cfg.arch
730 730
731 cfg.config_files = {
732 project = detected.project_dir and {
733 file = project_config_file,
734 found = not not project_config_ok,
735 },
736 system = {
737 file = sys_config_file,
738 found = not not sys_config_ok,
739 },
740 user = {
741 file = home_config_file,
742 found = not not home_config_ok,
743 },
744 nearest = project_config_ok
745 and project_config_file
746 or (home_config_ok
747 and home_config_file
748 or sys_config_file),
749 }
750
731 ---------------------------------------- 751 ----------------------------------------
732 -- Attributes of cfg are set. 752 -- Attributes of cfg are set.
733 -- Let's add some methods. 753 -- Let's add some methods.
734 ---------------------------------------- 754 ----------------------------------------
735 755
736 function cfg.which_config()
737 return {
738 project = detected.project_dir and {
739 file = project_config_file,
740 ok = project_config_ok,
741 },
742 system = {
743 file = sys_config_file,
744 ok = sys_config_ok,
745 },
746 user = {
747 file = home_config_file,
748 ok = home_config_ok,
749 },
750 nearest = project_config_ok
751 and project_config_file
752 or (home_config_ok
753 and home_config_file
754 or sys_config_file),
755 }
756 end
757
758 do 756 do
759 local function make_paths_from_tree(tree) 757 local function make_paths_from_tree(tree)
760 local lua_path, lib_path, bin_path 758 local lua_path, lib_path, bin_path
diff --git a/src/luarocks/fs/lua.lua b/src/luarocks/fs/lua.lua
index 0273cd53..71529cc0 100644
--- a/src/luarocks/fs/lua.lua
+++ b/src/luarocks/fs/lua.lua
@@ -114,7 +114,7 @@ function fs_lua.is_tool_available(tool_cmd, tool_name, arg)
114 if not fs.execute_quiet(tool_cmd, arg) then 114 if not fs.execute_quiet(tool_cmd, arg) then
115 local msg = "'%s' program not found. Make sure %s is installed and is available in your PATH " .. 115 local msg = "'%s' program not found. Make sure %s is installed and is available in your PATH " ..
116 "(or you may want to edit the 'variables.%s' value in file '%s')" 116 "(or you may want to edit the 'variables.%s' value in file '%s')"
117 return nil, msg:format(tool_cmd, tool_name, tool_name:upper(), cfg.which_config().nearest) 117 return nil, msg:format(tool_cmd, tool_name, tool_name:upper(), cfg.config_files.nearest)
118 else 118 else
119 return true 119 return true
120 end 120 end
diff --git a/src/luarocks/persist.lua b/src/luarocks/persist.lua
index 73f92bea..b8060ea0 100644
--- a/src/luarocks/persist.lua
+++ b/src/luarocks/persist.lua
@@ -20,8 +20,9 @@ local write_table
20-- @param level number: the indentation level 20-- @param level number: the indentation level
21-- @param sub_order table: optional prioritization table 21-- @param sub_order table: optional prioritization table
22-- @see write_table 22-- @see write_table
23local function write_value(out, v, level, sub_order) 23function persist.write_value(out, v, level, sub_order)
24 if type(v) == "table" then 24 if type(v) == "table" then
25 level = level or 0
25 write_table(out, v, level + 1, sub_order) 26 write_table(out, v, level + 1, sub_order)
26 elseif type(v) == "string" then 27 elseif type(v) == "string" then
27 if v:match("[\r\n]") then 28 if v:match("[\r\n]") then
@@ -80,7 +81,7 @@ local function write_table_key_assignment(out, k, level)
80 out:write(k) 81 out:write(k)
81 else 82 else
82 out:write("[") 83 out:write("[")
83 write_value(out, k, level) 84 persist.write_value(out, k, level)
84 out:write("]") 85 out:write("]")
85 end 86 end
86 87
@@ -112,7 +113,7 @@ write_table = function(out, tbl, level, field_order)
112 write_table_key_assignment(out, k, level) 113 write_table_key_assignment(out, k, level)
113 end 114 end
114 115
115 write_value(out, v, level, sub_order) 116 persist.write_value(out, v, level, sub_order)
116 if type(v) == "number" then 117 if type(v) == "number" then
117 sep = ", " 118 sep = ", "
118 indent = false 119 indent = false
@@ -139,13 +140,13 @@ local function write_table_as_assignments(out, tbl, field_order)
139 return nil, "cannot store '"..tostring(k).."' as a plain key." 140 return nil, "cannot store '"..tostring(k).."' as a plain key."
140 end 141 end
141 out:write(k.." = ") 142 out:write(k.." = ")
142 write_value(out, v, 0, sub_order) 143 persist.write_value(out, v, 0, sub_order)
143 out:write("\n") 144 out:write("\n")
144 end 145 end
145 return true 146 return true
146end 147end
147 148
148--- Write a table as series of assignments to a writer object. 149--- Write a table using Lua table syntax to a writer object.
149-- @param out table or userdata: a writer object supporting :write() method. 150-- @param out table or userdata: a writer object supporting :write() method.
150-- @param tbl table: the table to be written. 151-- @param tbl table: the table to be written.
151local function write_table_as_table(out, tbl) 152local function write_table_as_table(out, tbl)
@@ -153,7 +154,7 @@ local function write_table_as_table(out, tbl)
153 for k, v, sub_order in util.sortedpairs(tbl) do 154 for k, v, sub_order in util.sortedpairs(tbl) do
154 out:write(" ") 155 out:write(" ")
155 write_table_key_assignment(out, k, 1) 156 write_table_key_assignment(out, k, 1)
156 write_value(out, v, 1, sub_order) 157 persist.write_value(out, v, 1, sub_order)
157 out:write(",\n") 158 out:write(",\n")
158 end 159 end
159 out:write("}\n") 160 out:write("}\n")
@@ -216,4 +217,26 @@ function persist.save_as_module(filename, tbl)
216 return true 217 return true
217end 218end
218 219
220function persist.load_config_file_if_basic(filename, cfg)
221 local env = {
222 home = cfg.home
223 }
224 local result, err, errcode = persist.load_into_table(filename, env)
225 if errcode == "load" or errcode == "run" then
226 -- bad config file or depends on env, so error out
227 return nil, "Could not read existing config file " .. filename
228 end
229
230 local tbl
231 if errcode == "open" then
232 -- could not open, maybe file does not exist
233 tbl = {}
234 else
235 tbl = result
236 tbl.home = nil
237 end
238
239 return tbl
240end
241
219return persist 242return persist
diff --git a/src/luarocks/upload/api.lua b/src/luarocks/upload/api.lua
index bb2197ee..0e71432f 100644
--- a/src/luarocks/upload/api.lua
+++ b/src/luarocks/upload/api.lua
@@ -11,11 +11,10 @@ local multipart = require("luarocks.upload.multipart")
11local Api = {} 11local Api = {}
12 12
13local function upload_config_file() 13local function upload_config_file()
14 local conf = cfg.which_config() 14 if not cfg.config_files.user.file then
15 if not conf.user.file then
16 return nil 15 return nil
17 end 16 end
18 return (conf.user.file:gsub("/[^/]+$", "/upload_config.lua")) 17 return (cfg.config_files.user.file:gsub("/[^/]+$", "/upload_config.lua"))
19end 18end
20 19
21function Api:load_config() 20function Api:load_config()
diff --git a/src/luarocks/util.lua b/src/luarocks/util.lua
index aac52344..1714952e 100644
--- a/src/luarocks/util.lua
+++ b/src/luarocks/util.lua
@@ -106,6 +106,7 @@ local supported_flags = {
106 ["homepage"] = "\"<url>\"", 106 ["homepage"] = "\"<url>\"",
107 ["index"] = true, 107 ["index"] = true,
108 ["issues"] = true, 108 ["issues"] = true,
109 ["json"] = true,
109 ["keep"] = true, 110 ["keep"] = true,
110 ["labels"] = true, 111 ["labels"] = true,
111 ["lib"] = "<library>", 112 ["lib"] = "<library>",
@@ -149,6 +150,7 @@ local supported_flags = {
149 ["rock-trees"] = true, 150 ["rock-trees"] = true,
150 ["rockspec"] = true, 151 ["rockspec"] = true,
151 ["rockspec-format"] = "<ver>", 152 ["rockspec-format"] = "<ver>",
153 ["scope"] = "<system|user|project>",
152 ["server"] = "<server>", 154 ["server"] = "<server>",
153 ["sign"] = true, 155 ["sign"] = true,
154 ["skip-pack"] = true, 156 ["skip-pack"] = true,
@@ -161,6 +163,7 @@ local supported_flags = {
161 ["timeout"] = "<seconds>", 163 ["timeout"] = "<seconds>",
162 ["to"] = "<path>", 164 ["to"] = "<path>",
163 ["tree"] = "<path>", 165 ["tree"] = "<path>",
166 ["unset"] = true,
164 ["user-config"] = true, 167 ["user-config"] = true,
165 ["verbose"] = true, 168 ["verbose"] = true,
166 ["verify"] = true, 169 ["verify"] = true,