opts="${COMP_WORDS[*]}"
cur="${COMP_WORDS[COMP_CWORD]}"
COMPREPLY=($(icinga2 --autocomplete $COMP_CWORD ${COMP_WORDS[*]} < /dev/null))
+ [[ $COMPREPLY = */ ]] && compopt -o nospace
return 0
}
const RunAsUser = "@ICINGA2_USER@"
const RunAsGroup = "@ICINGA2_GROUP@"
+
+library "cli"
SERVICE_STATUS_HANDLE l_SvcStatusHandle;
#endif /* _WIN32 */
+static std::vector<String> LogLevelCompletion(const String& arg)
+{
+ std::vector<String> result;
+
+ String debugLevel = "debug";
+ if (debugLevel.Find(arg) == 0)
+ result.push_back(debugLevel);
+
+ String noticeLevel = "notice";
+ if (noticeLevel.Find(arg) == 0)
+ result.push_back(noticeLevel);
+
+ String informationLevel = "information";
+ if (informationLevel.Find(arg) == 0)
+ result.push_back(informationLevel);
+
+ String warningLevel = "warning";
+ if (warningLevel.Find(arg) == 0)
+ result.push_back(warningLevel);
+
+ String criticalLevel = "critical";
+ if (criticalLevel.Find(arg) == 0)
+ result.push_back(criticalLevel);
+
+ return result;
+}
+
int Main(void)
{
int argc = Application::GetArgC();
po::positional_options_description positionalDesc;
positionalDesc.add("arg", -1);
+ ArgumentCompletionDescription argDesc;
+ argDesc["include"] = BashArgumentCompletion("directory");
+ argDesc["log-level"] = LogLevelCompletion;
+
String cmdname;
CLICommand::Ptr command;
po::variables_map vm;
try {
- CLICommand::ParseCommand(argc, argv, visibleDesc, hiddenDesc, positionalDesc, vm, cmdname, command, autocomplete);
+ CLICommand::ParseCommand(argc, argv, visibleDesc, hiddenDesc, positionalDesc, argDesc, vm, cmdname, command, autocomplete);
} catch (const std::exception& ex) {
std::ostringstream msgbuf;
msgbuf << "Error while parsing command-line options: " << ex.what();
int rc = 1;
if (autocomplete) {
- CLICommand::ShowCommands(argc, argv, &visibleDesc, &hiddenDesc, true, autoindex);
+ CLICommand::ShowCommands(argc, argv, &visibleDesc, &hiddenDesc, &argDesc, true, autoindex);
rc = 0;
} else if (command) {
std::vector<std::string> args;
#include "base/logger_fwd.hpp"
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
boost::mutex l_RegistryMutex;
std::map<std::vector<String>, CLICommand::Ptr> l_Registry;
+static std::vector<String> BashArgumentCompletionHelper(const String& type, const String& arg)
+{
+ std::vector<String> result;
+
+#ifndef _WIN32
+ String bashArg = "compgen -A " + Utility::EscapeShellArg(type) + " " + Utility::EscapeShellArg(arg);
+ String cmd = "bash -c " + Utility::EscapeShellArg(bashArg);
+
+ FILE *fp = popen(cmd.CStr(), "r");
+
+ char line[4096];
+ while (fgets(line, sizeof(line), fp)) {
+ String wline = line;
+ boost::algorithm::trim_right_if(wline, boost::is_any_of("\r\n"));
+ result.push_back(wline);
+ }
+ fclose(fp);
+
+ /* Append a slash if there's only one suggestion and it's a directory */
+ if ((type == "file" || type == "directory") && result.size() == 1) {
+ String path = result[0];
+
+ struct stat statbuf;
+ if (lstat(path.CStr(), &statbuf) >= 0) {
+ if (S_ISDIR(statbuf.st_mode)) {
+ result.clear(),
+ result.push_back(path + "/");
+ }
+ }
+ }
+#endif /* _WIN32 */
+
+ return result;
+}
+
+ArgumentCompletionCallback icinga::BashArgumentCompletion(const String& type)
+{
+ return boost::bind(BashArgumentCompletionHelper, type, _1);
+}
+
CLICommand::Ptr CLICommand::GetByName(const std::vector<String>& name)
{
boost::mutex::scoped_lock lock(l_RegistryMutex);
}
bool CLICommand::ParseCommand(int argc, char **argv, po::options_description& visibleDesc,
- po::options_description& hiddenDesc, po::positional_options_description& positionalDesc, po::variables_map& vm,
- String& cmdname, CLICommand::Ptr& command, bool autocomplete)
+ po::options_description& hiddenDesc,
+ po::positional_options_description& positionalDesc,
+ ArgumentCompletionDescription& argCompletionDesc,
+ po::variables_map& vm, String& cmdname, CLICommand::Ptr& command, bool autocomplete)
{
boost::mutex::scoped_lock lock(l_RegistryMutex);
po::options_description vdesc("Command options");
if (command)
- command->InitParameters(vdesc, hiddenDesc);
+ command->InitParameters(vdesc, hiddenDesc, argCompletionDesc);
visibleDesc.add(vdesc);
}
void CLICommand::ShowCommands(int argc, char **argv, po::options_description *visibleDesc,
- po::options_description *hiddenDesc, bool autocomplete, int autoindex)
+ po::options_description *hiddenDesc, ArgumentCompletionDescription *argCompletionDesc,
+ bool autocomplete, int autoindex)
{
boost::mutex::scoped_lock lock(l_RegistryMutex);
}
if (command && autocomplete) {
- po::options_description vdesc("Command options");
-
- if (command)
- command->InitParameters(vdesc, *hiddenDesc);
+ String aname, prefix, pword;
+ ArgumentCompletionDescription::const_iterator it;
+ const po::option_description *odesc;
+
+ if (autoindex - 2 >= 0 && strcmp(argv[autoindex - 1], "=") == 0 && strstr(argv[autoindex - 2], "--") == argv[autoindex - 2]) {
+ aname = argv[autoindex - 2] + 2;
+ pword = aword;
+ } else if (autoindex - 1 >= 0 && argv[autoindex - 1][0] == '-' && argv[autoindex - 1][1] == '-') {
+ aname = argv[autoindex - 1] + 2;
+ pword = aword;
+
+ if (pword == "=")
+ pword = "";
+ } else if (aword.GetLength() > 1 && aword[0] == '-' && aword[1] != '-') {
+ aname = aword.SubStr(1, 1);
+ prefix = aword.SubStr(0, 2);
+ pword = aword.SubStr(2);
+ } else {
+ goto complete_option;
+ }
- visibleDesc->add(vdesc);
+ odesc = visibleDesc->find_nothrow(aname, false);
+
+ if (!odesc)
+ return;
+
+ if (odesc->semantic()->min_tokens() == 0)
+ goto complete_option;
+
+ it = argCompletionDesc->find(odesc->long_name());
+
+ if (it == argCompletionDesc->end())
+ return;
+
+ BOOST_FOREACH(const String& suggestion, it->second(pword)) {
+ std::cout << prefix << suggestion << "\n";
+ }
+
+ return;
+complete_option:
BOOST_FOREACH(const shared_ptr<po::option_description>& odesc, visibleDesc->options()) {
String cname = "--" + odesc->long_name();
namespace icinga
{
+typedef boost::function<std::vector<String> (const String&)> ArgumentCompletionCallback;
+typedef std::map<String, ArgumentCompletionCallback> ArgumentCompletionDescription;
+
+I2_BASE_API ArgumentCompletionCallback BashArgumentCompletion(const String& type);
+
/**
* A CLI command.
*
virtual String GetDescription(void) const = 0;
virtual String GetShortDescription(void) const = 0;
- virtual void InitParameters(boost::program_options::options_description& visibleDesc, boost::program_options::options_description& hiddenDesc) const = 0;
+ virtual void InitParameters(boost::program_options::options_description& visibleDesc,
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const = 0;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const = 0;
static CLICommand::Ptr GetByName(const std::vector<String>& name);
static bool ParseCommand(int argc, char **argv, boost::program_options::options_description& visibleDesc,
boost::program_options::options_description& hiddenDesc,
boost::program_options::positional_options_description& positionalDesc,
+ ArgumentCompletionDescription& argCompletionDesc,
boost::program_options::variables_map& vm, String& cmdname,
CLICommand::Ptr& command, bool autocomplete);
- static void ShowCommands(int argc, char **argv, boost::program_options::options_description *visibleDesc = NULL,
- boost::program_options::options_description *hiddenDesc = NULL, bool autocomplete = false, int autoindex = -1);
+
+ static void ShowCommands(int argc, char **argv,
+ boost::program_options::options_description *visibleDesc = NULL,
+ boost::program_options::options_description *hiddenDesc = NULL,
+ ArgumentCompletionDescription *argCompletionDesc = NULL,
+ bool autocomplete = false, int autoindex = -1);
};
/**
}
void DaemonCommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const
{
visibleDesc.add_options()
("config,c", po::value<std::vector<std::string> >(), "parse a configuration file")
hiddenDesc.add_options()
("reload-internal", po::value<int>(), "used internally to implement config reload: do not call manually, send SIGHUP instead");
#endif /* _WIN32 */
+
+ argCompletionDesc["config"] = BashArgumentCompletion("file");
+ argCompletionDesc["errorlog"] = BashArgumentCompletion("file");
}
/**
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const;
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
};
}
void FeatureDisableCommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const
{
/* Command doesn't support any parameters. */
}
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const;
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
};
}
void FeatureEnableCommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const
{
/* Command doesn't support any parameters. */
}
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const;
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
};
}
void FeatureListCommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const
{
/* Command doesn't support any parameters. */
}
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const;
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
private:
}
void PKINewCACommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const
{
/* Command doesn't support any parameters. */
}
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const;
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
};
}
void PKINewCertCommand::InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const
{
visibleDesc.add_options()
("cn", po::value<std::string>(), "Common Name")
virtual String GetDescription(void) const;
virtual String GetShortDescription(void) const;
virtual void InitParameters(boost::program_options::options_description& visibleDesc,
- boost::program_options::options_description& hiddenDesc) const;
+ boost::program_options::options_description& hiddenDesc,
+ ArgumentCompletionDescription& argCompletionDesc) const;
virtual int Run(const boost::program_options::variables_map& vm, const std::vector<std::string>& ap) const;
};