blob: 3019d36792319905e4cbb6c8767f744c23e493bc [file] [log] [blame]
Jan Kundrátdc2b0722018-03-02 14:13:37 +01001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
Jan Kundráta2740442018-03-22 16:56:43 +01003 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
Jan Kundrátdc2b0722018-03-02 14:13:37 +01004 *
Václav Kubernát624a8872018-03-02 17:28:47 +01005 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
Jan Kundrátdc2b0722018-03-02 14:13:37 +01006 *
7*/
Jan Kundrátdc2b0722018-03-02 14:13:37 +01008#include <docopt.h>
Václav Kubernát2b684612018-08-09 18:55:24 +02009#include <experimental/filesystem>
Václav Kubernát624a8872018-03-02 17:28:47 +010010#include <iostream>
Václav Kubernát435706e2019-02-20 18:05:59 +010011#include <optional>
Václav Kubernáta395d332019-02-13 16:49:20 +010012#include <replxx.hxx>
Jan Kundrátdc2b0722018-03-02 14:13:37 +010013#include "NETCONF_CLI_VERSION.h"
Václav Kubernát96344a12018-05-28 16:33:39 +020014#include "interpreter.hpp"
Václav Kubernát6415b822018-08-22 17:40:01 +020015#include "sysrepo_access.hpp"
Václav Kubernát2b684612018-08-09 18:55:24 +020016#include "yang_schema.hpp"
Jan Kundrátdc2b0722018-03-02 14:13:37 +010017
Václav Kubernát435706e2019-02-20 18:05:59 +010018const auto HISTORY_FILE_NAME = "netconf-cli_history";
Václav Kubernát624a8872018-03-02 17:28:47 +010019
Jan Kundrátdc2b0722018-03-02 14:13:37 +010020static const char usage[] =
Václav Kubernát624a8872018-03-02 17:28:47 +010021 R"(CLI interface to remote NETCONF hosts
Jan Kundrátdc2b0722018-03-02 14:13:37 +010022
23Usage:
Václav Kubernáta6c5fff2018-09-07 15:16:25 +020024 netconf-cli
Jan Kundrátdc2b0722018-03-02 14:13:37 +010025 netconf-cli (-h | --help)
26 netconf-cli --version
27)";
28
Václav Kubernát624a8872018-03-02 17:28:47 +010029
Jan Kundrátdc2b0722018-03-02 14:13:37 +010030int main(int argc, char* argv[])
31{
32 auto args = docopt::docopt(usage,
33 {argv + 1, argv + argc},
34 true,
35 "netconf-cli " NETCONF_CLI_VERSION,
36 true);
Václav Kubernát624a8872018-03-02 17:28:47 +010037 std::cout << "Welcome to netconf-cli" << std::endl;
Václav Kubernátff2c9f62018-05-16 20:26:31 +020038
Václav Kubernát6415b822018-08-22 17:40:01 +020039 SysrepoAccess datastore("netconf-cli");
Václav Kubernáta6c5fff2018-09-07 15:16:25 +020040 Parser parser(datastore.schema());
Václav Kubernáta395d332019-02-13 16:49:20 +010041 replxx::Replxx lineEditor;
42 lineEditor.set_completion_callback([&parser](const std::string& input, int&) {
43 std::stringstream stream;
44 auto completionsSet = parser.completeCommand(input, stream);
45
46 std::vector<std::string> res;
47 std::transform(completionsSet.begin(), completionsSet.end(), std::back_inserter(res),
48 [input](auto it) { return it; });
49 return res;
50 });
51 lineEditor.set_word_break_characters(" '/[");
Václav Kubernát2b684612018-08-09 18:55:24 +020052
Václav Kubernát435706e2019-02-20 18:05:59 +010053 std::optional<std::string> historyFile;
54 if (auto xdgHome = getenv("XDG_DATA_HOME")) {
55 historyFile = std::string(xdgHome) + "/" + HISTORY_FILE_NAME;
56 } else if (auto home = getenv("HOME")) {
57 historyFile = std::string(home) + "/.local/share/" + HISTORY_FILE_NAME;
58 }
59
60 if (historyFile)
61 lineEditor.history_load(historyFile.value());
62
Václav Kubernátff2c9f62018-05-16 20:26:31 +020063 while (true) {
Václav Kubernáta395d332019-02-13 16:49:20 +010064 auto line = lineEditor.input(parser.currentNode() + "> ");
65 if (!line) {
Václav Kubernátff2c9f62018-05-16 20:26:31 +020066 break;
Václav Kubernát5b80e522019-01-25 12:17:03 +010067 }
Václav Kubernátff2c9f62018-05-16 20:26:31 +020068
Jan Kundráte3877022018-09-05 15:32:09 +020069 std::locale C_locale("C");
Václav Kubernáta395d332019-02-13 16:49:20 +010070 std::string_view view{line};
71 if (std::all_of(view.begin(), view.end(),
Jan Kundráte3877022018-09-05 15:32:09 +020072 [C_locale](const auto c) { return std::isspace(c, C_locale);})) {
73 continue;
74 }
75
Václav Kubernátff2c9f62018-05-16 20:26:31 +020076 try {
Václav Kubernát5b80e522019-01-25 12:17:03 +010077 command_ cmd = parser.parseCommand(line, std::cout);
Václav Kubernát6415b822018-08-22 17:40:01 +020078 boost::apply_visitor(Interpreter(parser, datastore), cmd);
Václav Kubernátff2c9f62018-05-16 20:26:31 +020079 } catch (InvalidCommandException& ex) {
80 std::cerr << ex.what() << std::endl;
Václav Kubernátc58e4aa2019-04-03 18:37:32 +020081 } catch (DatastoreException& ex) {
82 std::cerr << ex.what() << std::endl;
Václav Kubernátff2c9f62018-05-16 20:26:31 +020083 }
Václav Kubernát5b80e522019-01-25 12:17:03 +010084
Václav Kubernáta395d332019-02-13 16:49:20 +010085 lineEditor.history_add(line);
Václav Kubernátff2c9f62018-05-16 20:26:31 +020086 }
87
Václav Kubernát435706e2019-02-20 18:05:59 +010088 if (historyFile)
89 lineEditor.history_save(historyFile.value());
90
Jan Kundrátdc2b0722018-03-02 14:13:37 +010091 return 0;
92}