import location
import version
import template
+import more_collections
# A warning or an error
class Message
private var messages = new Array[Message]
private var message_sorter: Comparator = default_comparator
- # Output all current stacked messages.
- # If some errors occurred, exits the program.
- fun check_errors
+ # Does an error prevent the program to stop at `check_errors`?
+ #
+ # Default to false.
+ # Set this value to `true` if you need to keep the program going in case of error.
+ var keep_going = false is writable
+
+ # List of tags per source-file whose warnings are not displayed.
+ #
+ # Initially empty, it is up to the toll to fill it.
+ # The tag "all" means all warnings and advices.
+ var warning_blacklist = new MultiHashMap[SourceFile, String]
+
+ # Is the source-file of `l` associated with `tag` in `warning_blacklist`?
+ #
+ # currently returns `false` if `l` is null or does not have a source-file.
+ fun is_warning_blacklisted(l: nullable Location, tag: String): Bool
+ do
+ if l == null then return false
+ var f = l.file
+ if f == null then return false
+ var tags = warning_blacklist.get_or_null(f)
+ if tags == null then return false
+ return tags.has("all") or tags.has(tag)
+ end
+
+ # Output all current stacked messages and display total error informations
+ #
+ # Return true if no errors occurred.
+ #
+ # If some errors occurred, the behavior depends on the value of `keep_going`.
+ # If `keep_going` is false, then the program exits.
+ # Else, the error count and the warning count are reset and false is returned.
+ fun check_errors: Bool
do
if messages.length > 0 then
message_sorter.sort(messages)
if error_count > 0 then
errors_info
- exit(1)
+ if not keep_going then exit(1)
+ return false
end
+ return true
end
- # Display total error informations
+ # Display (and reset) total error informations
fun errors_info
do
if error_count == 0 and warning_count == 0 then return
if opt_no_color.value then return
sys.stderr.write "Errors: {error_count}. Warnings: {warning_count}.\n"
+ error_count = 0
+ warning_count = 0
end
# Display an error
do
if opt_warning.value.has("no-{tag}") then return
if not opt_warning.value.has(tag) and opt_warn.value == 0 then return
+ if is_warning_blacklisted(l, tag) then return
messages.add(new Message(l, tag, text))
warning_count = warning_count + 1
if opt_stop_on_first_error.value then check_errors
do
if opt_warning.value.has("no-{tag}") then return
if not opt_warning.value.has(tag) and opt_warn.value <= 1 then return
+ if is_warning_blacklisted(l, tag) then return
messages.add(new Message(l, tag, text))
warning_count = warning_count + 1
if opt_stop_on_first_error.value then check_errors
# Option --log-dir
var opt_log_dir = new OptionString("Directory where to generate log files", "--log-dir")
+ # Option --nit-dir
+ var opt_nit_dir = new OptionString("Base directory of the Nit installation", "--nit-dir")
+
# Option --help
var opt_help = new OptionBool("Show Help (This screen)", "-h", "-?", "--help")
init
do
- option_context.add_option(opt_warn, opt_warning, opt_quiet, opt_stop_on_first_error, opt_no_color, opt_log, opt_log_dir, opt_help, opt_version, opt_set_dummy_tool, opt_verbose, opt_bash_completion, opt_stub_man)
+ option_context.add_option(opt_warn, opt_warning, opt_quiet, opt_stop_on_first_error, opt_no_color, opt_log, opt_log_dir, opt_nit_dir, opt_help, opt_version, opt_set_dummy_tool, opt_verbose, opt_bash_completion, opt_stub_man)
+
+ # Hide some internal options
+ opt_stub_man.hidden = true
+ opt_bash_completion.hidden = true
+ opt_set_dummy_tool.hidden = true
end
# Name, usage and synopsis of the tool.
exit 1
end
+ nit_dir = compute_nit_dir
+
if option_context.rest.is_empty and not accept_no_arguments then
print tooldescription
print "Use --help for help"
log_directory.mkdir
end
- nit_dir = compute_nit_dir
end
# Get the current `nit_version` or "DUMMY_VERSION" if `--set-dummy-tool` is set.
end
# The identified root directory of the Nit project
- var nit_dir: nullable String = null
+ var nit_dir: String is noinit
- private fun compute_nit_dir: nullable String
+ private fun compute_nit_dir: String
do
- # a environ variable has precedence
- var res = "NIT_DIR".environ
- if not res.is_empty then return res
+ # the option has precedence
+ var res = opt_nit_dir.value
+ if res != null then
+ if not check_nit_dir(res) then
+ fatal_error(null, "Fatal Error: the value of --nit-dir does not seem to be a valid base Nit directory: {res}")
+ end
+ return res
+ end
+
+ # then the environ variable has precedence
+ res = "NIT_DIR".environ
+ if not res.is_empty then
+ if not check_nit_dir(res) then
+ fatal_error(null, "Fatal Error: the value of NIT_DIR does not seem to be a valid base Nit directory: {res}")
+ end
+ return res
+ end
# find the runpath of the program from argv[0]
res = "{sys.program_name.dirname}/.."
- if res.file_exists and "{res}/src/nit.nit".file_exists then return res.simplify_path
+ if check_nit_dir(res) then return res.simplify_path
# find the runpath of the process from /proc
var exe = "/proc/self/exe"
if exe.file_exists then
res = exe.realpath
res = res.dirname.join_path("..")
- if res.file_exists and "{res}/src/nit.nit".file_exists then return res.simplify_path
+ if check_nit_dir(res) then return res.simplify_path
+ end
+
+ # search in the PATH
+ var ps = "PATH".environ.split(":")
+ for p in ps do
+ res = p/".."
+ if check_nit_dir(res) then return res.simplify_path
end
- return null
+ fatal_error(null, "Fatal Error: Cannot locate a valid base nit directory. It is quite unexpected. Try to set the environment variable `NIT_DIR` or to use the `--nit-dir` option.")
+ abort
+ end
+
+ private fun check_nit_dir(res: String): Bool
+ do
+ return res.file_exists and "{res}/src/nit.nit".file_exists
end
end