# Copyright 2006-2008 Floréal Morandat <morandat@lirmm.fr>
# Copyright 2008-2012 Jean Privat <jean@pryen.org>
# Copyright 2009 Jean-Sebastien Gelinas <calestar@gmail.com>
+# Copyright 2014 Alexandre Terrasa <alexandre@moz-code.org>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
import opts
import location
import version
+import template
class Message
super Comparable
for m in messages do
if opt_no_color.value then
- stderr.write("{m}\n")
+ sys.stderr.write("{m}\n")
else
- stderr.write("{m.to_color_string}\n")
+ sys.stderr.write("{m.to_color_string}\n")
end
end
end
end
+ # Executes a program while checking if it's available and if the execution ended correctly
+ #
+ # Stops execution and prints errors if the program isn't available or didn't end correctly
+ fun exec_and_check(args: Array[String], error: String)
+ do
+ var prog = args.first
+ args.remove_at 0
+
+ # Is the wanted program available?
+ var proc_which = new IProcess.from_a("which", [prog])
+ proc_which.wait
+ var res = proc_which.status
+ if res != 0 then
+ print "{error}: executable \"{prog}\" not found"
+ exit 1
+ end
+
+ # Execute the wanted program
+ var proc = new Process.from_a(prog, args)
+ proc.wait
+ res = proc.status
+ if res != 0 then
+ print "{error}: execution of \"{prog} {args.join(" ")}\" failed"
+ exit 1
+ end
+ end
+
# Global OptionContext
var option_context: OptionContext = new OptionContext
# Option --version
var opt_version: OptionBool = new OptionBool("Show version and exit", "--version")
+ # Option --set-dummy-tool
+ var opt_set_dummy_tool: OptionBool = new OptionBool("Set toolname and version to DUMMY. Useful for testing", "--set-dummy-tool")
+
# Option --verbose
var opt_verbose: OptionCount = new OptionCount("Verbose", "-v", "--verbose")
# Option --no-color
var opt_no_color: OptionBool = new OptionBool("Do not use color to display errors and warnings", "--no-color")
+ # Option --bash-completion
+ var opt_bash_completion: OptionBool = new OptionBool("Generate bash_completion file for this program", "--bash-completion")
+
# Verbose level
var verbose_level: Int = 0
init
do
- option_context.add_option(opt_warn, opt_quiet, opt_stop_on_first_error, opt_no_color, opt_log, opt_log_dir, opt_help, opt_version, opt_verbose)
+ option_context.add_option(opt_warn, 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)
end
# Name, usage and synopsis of the tool.
# A multi-line string is recommmended.
#
# eg. `"Usage: tool [OPTION]... [FILE]...\nDo some things."`
- var tooldescription: String writable = "Usage: [OPTION]... [ARG]..."
+ var tooldescription: String = "Usage: [OPTION]... [ARG]..." is writable
# Does `process_options` should accept an empty sequence of arguments.
# ie. nothing except options.
# Is `false` by default.
#
# If required, if should be set by the client before calling `process_options`
- var accept_no_arguments writable = false
+ var accept_no_arguments = false is writable
# print the full usage of the tool.
# Is called by `process_option` on `--help`.
end
# Parse and process the options given on the command line
- fun process_options
+ fun process_options(args: Sequence[String])
do
self.opt_warn.value = 1
end
if opt_version.value then
- print nit_version
+ print version
+ exit 0
+ end
+
+ if opt_bash_completion.value then
+ var bash_completion = new BashCompletion(self)
+ bash_completion.write_to(sys.stdout)
exit 0
end
# Make sure the output directory exists
log_directory.mkdir
end
+
+ nit_dir = compute_nit_dir
+ end
+
+ # Get the current `nit_version` or "DUMMY_VERSION" if `--set-dummy-tool` is set.
+ fun version: String do
+ if opt_set_dummy_tool.value then
+ return "DUMMY_VERSION"
+ end
+ return nit_version
+ end
+
+ # Get the name of the tool or "DUMMY_TOOL" id `--set-dummy-tool` is set.
+ fun toolname: String do
+ if opt_set_dummy_tool.value then
+ return "DUMMY_TOOL"
+ end
+ return sys.program_name.basename("")
+ end
+
+ # The identified root directory of the Nit project
+ var nit_dir: nullable String = null
+
+ private fun compute_nit_dir: nullable String
+ do
+ # a environ variable has precedence
+ var res = "NIT_DIR".environ
+ if not res.is_empty then return res
+
+ # 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
+
+ # 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
+ end
+
+ return null
+ end
+end
+
+# This class generates a compatible `bash_completion` script file.
+#
+# On some Linux systems `bash_completion` allow the program to control command line behaviour.
+#
+# $ nitls [TAB][TAB]
+# file1.nit file2.nit file3.nit
+#
+# $ nitls --[TAB][TAB]
+# --bash-toolname --keep --path --tree
+# --depends --log --project --verbose
+# --disable-phase --log-dir --quiet --version
+# --gen-bash-completion --no-color --recursive --warn
+# --help --only-metamodel --source
+# --ignore-visibility --only-parse --stop-on-first-error
+#
+# Generated file can be placed in system bash_completion directory `/etc/bash_completion.d/`
+# or source it in `~/.bash_completion`.
+class BashCompletion
+ super Template
+
+ var toolcontext: ToolContext
+
+ init(toolcontext: ToolContext) do
+ self.toolcontext = toolcontext
+ end
+
+ private fun extract_options_names: Array[String] do
+ var names = new Array[String]
+ for option in toolcontext.option_context.options do
+ for name in option.names do
+ if name.has_prefix("--") then names.add name
+ end
+ end
+ return names
+ end
+
+ redef fun rendering do
+ var name = toolcontext.toolname
+ var option_names = extract_options_names
+ addn "# generated bash completion file for {name} {toolcontext.version}"
+ addn "_{name}()"
+ addn "\{"
+ addn " local cur prev opts"
+ addn " COMPREPLY=()"
+ addn " cur=\"$\{COMP_WORDS[COMP_CWORD]\}\""
+ addn " prev=\"$\{COMP_WORDS[COMP_CWORD-1]\}\""
+ if option_names != null then
+ addn " opts=\"{option_names.join(" ")}\""
+ addn " if [[ $\{cur\} == -* ]] ; then"
+ addn " COMPREPLY=( $(compgen -W \"$\{opts\}\" -- $\{cur\}) )"
+ addn " return 0"
+ addn " fi"
+ end
+ addn "\} &&"
+ addn "complete -o default -F _{name} {name}"
end
end