summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Melnichenko <mpeterval@gmail.com>2016-06-29 12:51:27 +0300
committerPeter Melnichenko <mpeterval@gmail.com>2016-06-29 12:51:27 +0300
commit3ec7bcfa595c22d55b564da9213affc9aee78b0e (patch)
tree58edc851a88a1227f34c52efaba5249abae41057
parent3739b93eeaffac3bb10235a789db30fe528a692d (diff)
downloadluacov-3ec7bcfa595c22d55b564da9213affc9aee78b0e.tar.gz
Improve config loading error handling
-rw-r--r--luacov-scm-1.rockspec1
-rw-r--r--src/luacov/runner.lua52
-rw-r--r--src/luacov/util.lua103
3 files changed, 136 insertions, 20 deletions
diff --git a/luacov-scm-1.rockspec b/luacov-scm-1.rockspec
index 5df14bc..3e4d79b 100644
--- a/luacov-scm-1.rockspec
+++ b/luacov-scm-1.rockspec
@@ -30,6 +30,7 @@ build = {
["luacov.stats"] = "src/luacov/stats.lua",
["luacov.tick"] = "src/luacov/tick.lua",
["luacov.hook"] = "src/luacov/hook.lua",
+ ["luacov.util"] = "src/luacov/util.lua"
},
install = {
bin = {
diff --git a/src/luacov/runner.lua b/src/luacov/runner.lua
index d7f150b..160cc95 100644
--- a/src/luacov/runner.lua
+++ b/src/luacov/runner.lua
@@ -9,9 +9,11 @@ local runner = {}
runner.version = "0.11.0"
local stats = require("luacov.stats")
+local util = require("luacov.util")
runner.defaults = require("luacov.defaults")
local debug = require("debug")
+local raw_os_exit = os.exit
local new_anchor = newproxy or function() return {} end -- luacheck: compat
@@ -146,16 +148,6 @@ local function on_exit()
end
end
--- Returns true if the given filename exists.
-local function file_exists(fname)
- local f = io.open(fname)
-
- if f then
- f:close()
- return true
- end
-end
-
local dir_sep = package.config:sub(1, 1)
local wildcard_expansion = "[^/]+"
@@ -315,6 +307,31 @@ local function set_config(configuration)
runner.tick = runner.tick or runner.configuration.tick
end
+local function die(error_msg)
+ io.stderr:write(("Error: %s\n"):format(error_msg))
+ raw_os_exit(1)
+end
+
+local function load_config_file(name, is_default)
+ local ok, conf, error_msg = util.load_config(name, _G)
+
+ if ok then
+ if type(conf) ~= "table" then
+ die("config is not a table")
+ end
+
+ return conf
+ end
+
+ local error_type = conf
+
+ if error_type == "read" and is_default then
+ return nil
+ end
+
+ die(("couldn't %s config file %s: %s"):format(error_type, name, error_msg))
+end
+
local default_config_file = ".luacov"
------------------------------------------------------
@@ -327,14 +344,10 @@ local default_config_file = ".luacov"
function runner.load_config(configuration)
if not runner.configuration then
if not configuration then
- -- nothing provided, load from default location if possible
- if file_exists(default_config_file) then
- set_config(dofile(default_config_file))
- else
- set_config(runner.defaults)
- end
+ -- Nothing provided, load from default location if possible.
+ set_config(load_config_file(default_config_file, true) or runner.defaults)
elseif type(configuration) == "string" then
- set_config(dofile(configuration))
+ set_config(load_config_file(configuration))
elseif type(configuration) == "table" then
set_config(configuration)
else
@@ -406,10 +419,9 @@ function runner.init(configuration)
-- metatable trick on filehandle won't work if Lua exits through
-- os.exit() hence wrap that with exit code as well
- local rawexit = os.exit
os.exit = function(...) -- luacheck: no global
on_exit()
- rawexit(...)
+ raw_os_exit(...)
end
debug.sethook(runner.debug_hook, "l")
@@ -518,7 +530,7 @@ local function getfilename(name)
error("Bad argument: " .. tostring(name))
end
- if file_exists(name) then
+ if util.file_exists(name) then
return name
end
diff --git a/src/luacov/util.lua b/src/luacov/util.lua
new file mode 100644
index 0000000..9f8e6f9
--- /dev/null
+++ b/src/luacov/util.lua
@@ -0,0 +1,103 @@
+---------------------------------------------------
+-- Utility module.
+-- @class module
+-- @name luacov.util
+local util = {}
+
+--- Removes a prefix from a string if it's present.
+-- @param str a string.
+-- @param prefix a prefix string.
+-- @return original string if does not start with prefix
+-- or string without prefix.
+function util.unprefix(str, prefix)
+ if str:sub(1, #prefix) == prefix then
+ return str:sub(#prefix + 1)
+ else
+ return str
+ end
+end
+
+-- Returns contents of a file or nil + error message.
+local function read_file(name)
+ local f, open_err = io.open(name, "rb")
+
+ if not f then
+ return nil, util.unprefix(open_err, name .. ": ")
+ end
+
+ local contents, read_err = f:read("*a")
+ f:close()
+
+ if contents then
+ return contents
+ else
+ return nil, read_err
+ end
+end
+
+--- Loads a string.
+-- @param str a string.
+-- @param[opt] env environment table.
+-- @param[opt] chunkname chunk name.
+function util.load_string(str, env, chunkname)
+ if _VERSION:find("5%.1") then
+ local func, err = loadstring(str, chunkname)
+
+ if not func then
+ return nil, err
+ end
+
+ if env then
+ setfenv(func, env)
+ end
+
+ return func
+ else
+ return load(str, chunkname, "bt", env or _ENV)
+ end
+end
+
+--- Load a config file.
+-- Reads, loads and runs a Lua file in an environment.
+-- @param name file name.
+-- @param env environment table.
+-- @return true and the first return value of config on success,
+-- nil + error type + error message on failure, where error type
+-- can be "read", "load" or "run".
+function util.load_config(name, env)
+ local src, read_err = read_file(name)
+
+ if not src then
+ return nil, "read", read_err
+ end
+
+ local func, load_err = util.load_string(src, env, "@config")
+
+ if not func then
+ return nil, "load", "line " .. util.unprefix(load_err, "config:")
+ end
+
+ local ok, ret = pcall(func)
+
+ if not ok then
+ return nil, "run", "line " .. util.unprefix(ret, "config:")
+ end
+
+ return true, ret
+end
+
+--- Checks if a file exists.
+-- @param name file name.
+-- @return true if file can be opened, false otherwise.
+function util.file_exists(name)
+ local f = io.open(name)
+
+ if f then
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+return util