summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2010-12-02 14:35:25 -0800
committerAn-Cheng Huang <ancheng@vyatta.com>2010-12-02 14:35:25 -0800
commit352a9e94534933aca7403e91d1dc55c26bf633ce (patch)
treedf413a5fbd1ab0e0b4776eff98149dd9cbc8006d /src
parent58005829f825c3e6843d0c2c36e1e343194ec3dd (diff)
downloadvyatta-cfg-352a9e94534933aca7403e91d1dc55c26bf633ce.tar.gz
vyatta-cfg-352a9e94534933aca7403e91d1dc55c26bf633ce.zip
implement load function in new config input/output infrastructure.
* add "commands diff" functionality to config input/output infrastructure. * consolidate similar logic in "commands diff" and "show diff". * add loadFile functionality to cstore using "commands diff". * export loadFile through shell API.
Diffstat (limited to 'src')
-rw-r--r--src/cli_shell_api.cpp31
-rw-r--r--src/cnode/cnode-algorithm.cpp487
-rw-r--r--src/cnode/cnode-algorithm.hpp15
-rw-r--r--src/cstore/cstore.cpp75
-rw-r--r--src/cstore/cstore.hpp8
5 files changed, 521 insertions, 95 deletions
diff --git a/src/cli_shell_api.cpp b/src/cli_shell_api.cpp
index af0a320..b9b8188 100644
--- a/src/cli_shell_api.cpp
+++ b/src/cli_shell_api.cpp
@@ -24,6 +24,7 @@
#include <cstore/unionfs/cstore-unionfs.hpp>
#include <cnode/cnode.hpp>
#include <cnode/cnode-algorithm.hpp>
+#include <cparse/cparse.hpp>
/* This program provides an API for shell scripts (e.g., snippets in
* templates, standalone scripts, etc.) to access the CLI cstore library.
@@ -405,18 +406,27 @@ showCfg(const vector<string>& args)
cnode::CfgNode aroot(cstore, nargs, true, true);
if (active_only) {
- // just show the active config
- cnode::show_diff(aroot, aroot, op_show_show_defaults,
- op_show_hide_secrets);
- } else if (working_only) {
- // just show the working config without diff markers
- cnode::CfgNode wroot(cstore, nargs, false, true);
- cnode::show_diff(wroot, wroot, op_show_show_defaults,
- op_show_hide_secrets);
+ // just show the active config (no diff)
+ cnode::show_cfg(aroot, op_show_show_defaults, op_show_hide_secrets);
} else {
cnode::CfgNode wroot(cstore, nargs, false, true);
- cnode::show_diff(aroot, wroot, op_show_show_defaults,
- op_show_hide_secrets);
+ if (working_only) {
+ // just show the working config (no diff)
+ cnode::show_cfg(wroot, op_show_show_defaults, op_show_hide_secrets);
+ } else {
+ cnode::show_cfg_diff(aroot, wroot, op_show_show_defaults,
+ op_show_hide_secrets);
+ }
+ }
+}
+
+static void
+loadFile(const vector<string>& args)
+{
+ UnionfsCstore cstore(true);
+ if (!cstore.loadFile(args[0].c_str())) {
+ // loadFile failed
+ exit(1);
}
}
@@ -463,6 +473,7 @@ static OpT ops[] = {
OP(validateTmplValPath, -1, NULL, 1, "Must specify config path"),
OP(showCfg, -1, NULL, -1, NULL),
+ OP(loadFile, 1, "Must specify config file", -1, NULL),
{NULL, -1, NULL, -1, NULL, NULL}
};
diff --git a/src/cnode/cnode-algorithm.cpp b/src/cnode/cnode-algorithm.cpp
index 4480352..3a7ccdd 100644
--- a/src/cnode/cnode-algorithm.cpp
+++ b/src/cnode/cnode-algorithm.cpp
@@ -40,6 +40,133 @@ _show_diff(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def,
bool hide_secret);
static void
+_get_cmds_diff(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path,
+ vector<vector<string> >& del_list,
+ vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list);
+
+/* compare the values of a "multi" node in the two configs. the values and
+ * the "prefix" of each value are returned in "values" and "pfxs",
+ * respectively.
+ *
+ * return value indicates whether the node is different in the two configs.
+ *
+ * comparison follows the original perl logic.
+ */
+static bool
+_cmp_multi_values(CfgNode *cfg1, CfgNode *cfg2, vector<string>& values,
+ vector<const char *>& pfxs)
+{
+ const vector<string>& ovec = cfg1->getValues();
+ const vector<string>& nvec = cfg2->getValues();
+ Cstore::MapT<string, bool> nmap;
+ bool changed = false;
+ for (size_t i = 0; i < nvec.size(); i++) {
+ nmap[nvec[i]] = true;
+ }
+ Cstore::MapT<string, bool> omap;
+ for (size_t i = 0; i < ovec.size(); i++) {
+ omap[ovec[i]] = true;
+ if (nmap.find(ovec[i]) == nmap.end()) {
+ values.push_back(ovec[i]);
+ pfxs.push_back(PFX_DIFF_DEL.c_str());
+ changed = true;
+ }
+ }
+
+ for (size_t i = 0; i < nvec.size(); i++) {
+ values.push_back(nvec[i]);
+ if (omap.find(nvec[i]) == omap.end()) {
+ pfxs.push_back(PFX_DIFF_ADD.c_str());
+ changed = true;
+ } else if (i < ovec.size() && nvec[i] == ovec[i]) {
+ pfxs.push_back(PFX_DIFF_NONE.c_str());
+ } else {
+ pfxs.push_back(PFX_DIFF_UPD.c_str());
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+static void
+_cmp_non_leaf_nodes(CfgNode *cfg1, CfgNode *cfg2, vector<CfgNode *>& rcnodes1,
+ vector<CfgNode *>& rcnodes2, bool& not_tag_node,
+ bool& is_value, bool& is_leaf_typeless,
+ string& name, string& value)
+{
+ CfgNode *cfg = (cfg1 ? cfg1 : cfg2);
+ is_value = cfg->isValue();
+ not_tag_node = (!cfg->isTag() || is_value);
+ is_leaf_typeless = cfg->isLeafTypeless();
+ bool is_tag_node = !not_tag_node;
+ name = cfg->getName();
+ if (is_value) {
+ value = cfg->getValue();
+ }
+
+ // handle child nodes
+ vector<CfgNode *> cnodes1, cnodes2;
+ if (cfg1) {
+ cnodes1 = cfg1->getChildNodes();
+ }
+ if (cfg2) {
+ cnodes2 = cfg2->getChildNodes();
+ }
+
+ Cstore::MapT<string, bool> map;
+ Cstore::MapT<string, CfgNode *> nmap1, nmap2;
+ for (size_t i = 0; i < cnodes1.size(); i++) {
+ string key = (is_tag_node
+ ? cnodes1[i]->getValue() : cnodes1[i]->getName());
+ map[key] = true;
+ nmap1[key] = cnodes1[i];
+ }
+ for (size_t i = 0; i < cnodes2.size(); i++) {
+ string key = (is_tag_node
+ ? cnodes2[i]->getValue() : cnodes2[i]->getName());
+ map[key] = true;
+ nmap2[key] = cnodes2[i];
+ }
+
+ vector<string> cnodes;
+ Cstore::MapT<string, bool>::iterator it = map.begin();
+ for (; it != map.end(); ++it) {
+ cnodes.push_back((*it).first);
+ }
+ Cstore::sortNodes(cnodes);
+
+ for (size_t i = 0; i < cnodes.size(); i++) {
+ bool in1 = (nmap1.find(cnodes[i]) != nmap1.end());
+ bool in2 = (nmap2.find(cnodes[i]) != nmap2.end());
+ CfgNode *c1 = (in1 ? nmap1[cnodes[i]] : NULL);
+ CfgNode *c2 = (in2 ? nmap2[cnodes[i]] : NULL);
+ rcnodes1.push_back(c1);
+ rcnodes2.push_back(c2);
+ }
+}
+
+static void
+_add_path_to_list(vector<vector<string> >& list, vector<string>& path,
+ const string *nptr, const string *vptr)
+{
+ if (nptr) {
+ path.push_back(*nptr);
+ }
+ if (vptr) {
+ path.push_back(*vptr);
+ }
+ list.push_back(path);
+ if (vptr) {
+ path.pop_back();
+ }
+ if (nptr) {
+ path.pop_back();
+ }
+}
+
+static void
_print_value_str(const string& name, const char *vstr, bool hide_secret)
{
// handle secret hiding first
@@ -161,35 +288,9 @@ _diff_check_and_show_leaf(CfgNode *cfg1, CfgNode *cfg2, int level,
}
} else {
// need to actually do a diff.
- // this follows the original perl logic.
- const vector<string>& ovec = cfg1->getValues();
- const vector<string>& nvec = cfg2->getValues();
vector<string> values;
vector<const char *> pfxs;
- Cstore::MapT<string, bool> nmap;
- for (size_t i = 0; i < nvec.size(); i++) {
- nmap[nvec[i]] = true;
- }
- Cstore::MapT<string, bool> omap;
- for (size_t i = 0; i < ovec.size(); i++) {
- omap[ovec[i]] = true;
- if (nmap.find(ovec[i]) == nmap.end()) {
- values.push_back(ovec[i]);
- pfxs.push_back(PFX_DIFF_DEL.c_str());
- }
- }
-
- for (size_t i = 0; i < nvec.size(); i++) {
- values.push_back(nvec[i]);
- if (omap.find(nvec[i]) == omap.end()) {
- pfxs.push_back(PFX_DIFF_ADD.c_str());
- } else if (i < ovec.size() && nvec[i] == ovec[i]) {
- pfxs.push_back(PFX_DIFF_NONE.c_str());
- } else {
- pfxs.push_back(PFX_DIFF_UPD.c_str());
- }
- }
-
+ _cmp_multi_values(cfg1, cfg2, values, pfxs);
for (size_t i = 0; i < values.size(); i++) {
_diff_print_indent(cfg1, cfg2, level, pfxs[i]);
printf("%s ", cfg->getName().c_str());
@@ -224,13 +325,10 @@ static void
_diff_show_other(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def,
bool hide_secret)
{
- CfgNode *cfg = NULL;
const char *pfx_diff = PFX_DIFF_NONE.c_str();
if (!cfg1) {
- cfg = cfg2;
pfx_diff = PFX_DIFF_ADD.c_str();
} else {
- cfg = cfg1;
if (!cfg2) {
pfx_diff = PFX_DIFF_DEL.c_str();
} else if (cfg1 == cfg2) {
@@ -238,76 +336,41 @@ _diff_show_other(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def,
}
}
+ string name, value;
+ bool not_tag_node, is_value, is_leaf_typeless;
+ vector<CfgNode *> rcnodes1, rcnodes2;
+ _cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value,
+ is_leaf_typeless, name, value);
+
/* only print "this" node if it
* (1) is a tag value or an intermediate node,
* (2) is not "root", and
* (3) has a "name".
*/
- const string& name = cfg->getName();
- bool print_this = (((cfg1 && (!cfg1->isTag() || cfg1->isValue()))
- || (cfg2 && (!cfg2->isTag() || cfg2->isValue())))
- && level >= 0 && name.size() > 0);
+ bool print_this = (not_tag_node && level >= 0 && name.size() > 0);
if (print_this) {
_diff_print_comment(cfg1, cfg2, level);
_diff_print_indent(cfg1, cfg2, level, pfx_diff);
- if (cfg->isValue()) {
+ if (is_value) {
// at tag value
- printf("%s %s", name.c_str(), cfg->getValue().c_str());
+ printf("%s %s", name.c_str(), value.c_str());
} else {
// at intermediate node
printf("%s", name.c_str());
}
- printf("%s\n", (cfg->isLeafTypeless() ? "" : " {"));
+ printf("%s\n", (is_leaf_typeless ? "" : " {"));
}
- // handle child nodes
- vector<CfgNode *> cnodes1, cnodes2;
- if (cfg1) {
- cnodes1 = cfg1->getChildNodes();
- }
- if (cfg2) {
- cnodes2 = cfg2->getChildNodes();
- }
-
- Cstore::MapT<string, bool> map;
- Cstore::MapT<string, CfgNode *> nmap1, nmap2;
- for (size_t i = 0; i < cnodes1.size(); i++) {
- string key
- = ((cfg->isTag() && !cfg->isValue())
- ? cnodes1[i]->getValue() : cnodes1[i]->getName());
- map[key] = true;
- nmap1[key] = cnodes1[i];
- }
- for (size_t i = 0; i < cnodes2.size(); i++) {
- string key
- = ((cfg->isTag() && !cfg->isValue())
- ? cnodes2[i]->getValue() : cnodes2[i]->getName());
- map[key] = true;
- nmap2[key] = cnodes2[i];
- }
-
- vector<string> cnodes;
- Cstore::MapT<string, bool>::iterator it = map.begin();
- for (; it != map.end(); ++it) {
- cnodes.push_back((*it).first);
- }
- Cstore::sortNodes(cnodes);
-
- for (size_t i = 0; i < cnodes.size(); i++) {
- bool in1 = (nmap1.find(cnodes[i]) != nmap1.end());
- bool in2 = (nmap2.find(cnodes[i]) != nmap2.end());
- CfgNode *c1 = (in1 ? nmap1[cnodes[i]] : NULL);
- CfgNode *c2 = (in2 ? nmap2[cnodes[i]] : NULL);
-
+ for (size_t i = 0; i < rcnodes1.size(); i++) {
int next_level = level + 1;
if (!print_this) {
next_level = (level >= 0 ? level : 0);
}
- _show_diff(c1, c2, next_level, show_def, hide_secret);
+ _show_diff(rcnodes1[i], rcnodes2[i], next_level, show_def, hide_secret);
}
// finish printing "this" node if necessary
- if (print_this && !cfg->isLeafTypeless()) {
+ if (print_this && !is_leaf_typeless) {
_diff_print_indent(cfg1, cfg2, level, pfx_diff);
printf("}\n");
}
@@ -353,11 +416,227 @@ _show_diff(CfgNode *cfg1, CfgNode *cfg2, int level, bool show_def,
}
}
+static void
+_get_comment_diff_cmd(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path,
+ vector<vector<string> >& com_list, const string *val)
+{
+ const string *comment = NULL;
+ const string *name = NULL;
+ string empty = "";
+ string c1, c2;
+ if (cfg1 != cfg2) {
+ c1 = (cfg1 ? cfg1->getComment() : "");
+ c2 = (cfg2 ? cfg2->getComment() : "");
+ if (c1 != "") {
+ name = &(cfg1->getName());
+ if (c2 != "") {
+ // in both
+ if (c1 != c2) {
+ // updated
+ comment = &c2;
+ }
+ } else {
+ // only in cfg1 => deleted
+ comment = &empty;
+ }
+ } else {
+ if (c2 != "") {
+ // only in cfg2 => added
+ name = &(cfg2->getName());
+ comment = &c2;
+ }
+ }
+ } else {
+ // cfg1 == cfg2 => just getting all commands
+ c1 = cfg1->getComment();
+ if (c1 != "") {
+ name = &(cfg1->getName());
+ comment = &c1;
+ }
+ }
+ if (comment) {
+ if (val) {
+ cur_path.push_back(*name);
+ name = val;
+ }
+ _add_path_to_list(com_list, cur_path, name, comment);
+ if (val) {
+ cur_path.pop_back();
+ }
+ }
+}
+
+static bool
+_get_cmds_diff_leaf(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path,
+ vector<vector<string> >& del_list,
+ vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list)
+{
+ if ((cfg1 && !cfg1->isLeaf()) || (cfg2 && !cfg2->isLeaf())) {
+ // not a leaf node
+ return false;
+ }
+
+ CfgNode *cfg = NULL;
+ vector<vector<string> > *list = NULL;
+ if (cfg1) {
+ cfg = cfg1;
+ if (!cfg2) {
+ // exists in cfg1 but not in cfg2 => delete and stop recursion
+ _add_path_to_list(del_list, cur_path, &(cfg1->getName()), NULL);
+ return true;
+ } else if (cfg1 == cfg2) {
+ // same config => just translating config to set commands
+ list = &set_list;
+ }
+ } else {
+ // !cfg1 => cfg2 must not be NULL
+ cfg = cfg2;
+ list = &set_list;
+ }
+
+ _get_comment_diff_cmd(cfg1, cfg2, cur_path, com_list, NULL);
+ if (cfg->isMulti()) {
+ // multi-value node
+ if (list) {
+ const vector<string>& vvec = cfg->getValues();
+ for (size_t i = 0; i < vvec.size(); i++) {
+ _add_path_to_list(*list, cur_path, &(cfg->getName()), &(vvec[i]));
+ }
+ } else {
+ // need to actually do a diff.
+ vector<string> dummy_vals;
+ vector<const char *> dummy_pfxs;
+ if (_cmp_multi_values(cfg1, cfg2, dummy_vals, dummy_pfxs)) {
+ /* something changed. to get the correct ordering for multi-node
+ * values, need to delete the node and then set the new values.
+ */
+ const vector<string>& nvec = cfg2->getValues();
+ _add_path_to_list(del_list, cur_path, &(cfg->getName()), NULL);
+ for (size_t i = 0; i < nvec.size(); i++) {
+ _add_path_to_list(set_list, cur_path, &(cfg->getName()), &(nvec[i]));
+ }
+ }
+ }
+ } else {
+ // single-value node
+ string val = cfg->getValue();
+ if (!list) {
+ const string& val1 = cfg1->getValue();
+ val = cfg2->getValue();
+ if (val != val1) {
+ // changed => need to set it
+ list = &set_list;
+ }
+ }
+ if (list) {
+ _add_path_to_list(*list, cur_path, &(cfg->getName()), &val);
+ }
+ }
+
+ return true;
+}
+
+static void
+_get_cmds_diff_other(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path,
+ vector<vector<string> >& del_list,
+ vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list)
+{
+ vector<vector<string> > *list = NULL;
+ if (cfg1) {
+ if (!cfg2) {
+ // exists in cfg1 but not in cfg2 => delete and stop recursion
+ _add_path_to_list(del_list, cur_path, &(cfg1->getName()),
+ (cfg1->isValue() ? &(cfg1->getValue()) : NULL));
+ return;
+ } else if (cfg1 == cfg2) {
+ // same config => just translating config to set commands
+ list = &set_list;
+ }
+ } else {
+ // !cfg1 => cfg2 must not be NULL
+ list = &set_list;
+ }
+
+ string name, value;
+ bool not_tag_node, is_value, is_leaf_typeless;
+ vector<CfgNode *> rcnodes1, rcnodes2;
+ _cmp_non_leaf_nodes(cfg1, cfg2, rcnodes1, rcnodes2, not_tag_node, is_value,
+ is_leaf_typeless, name, value);
+ if (rcnodes1.size() < 1 && list) {
+ // subtree is empty
+ _add_path_to_list(*list, cur_path, &name, (is_value ? &value : NULL));
+ return;
+ }
+
+ bool add_this = (not_tag_node && name.size() > 0);
+ if (add_this) {
+ const string *val = (is_value ? &value : NULL);
+ _get_comment_diff_cmd(cfg1, cfg2, cur_path, com_list, val);
+
+ cur_path.push_back(name);
+ if (is_value) {
+ cur_path.push_back(value);
+ }
+ }
+ for (size_t i = 0; i < rcnodes1.size(); i++) {
+ _get_cmds_diff(rcnodes1[i], rcnodes2[i], cur_path, del_list, set_list,
+ com_list);
+ }
+ if (add_this) {
+ if (is_value) {
+ cur_path.pop_back();
+ }
+ cur_path.pop_back();
+ }
+}
+
+static void
+_get_cmds_diff(CfgNode *cfg1, CfgNode *cfg2, vector<string>& cur_path,
+ vector<vector<string> >& del_list,
+ vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list)
+{
+ // if doesn't exist, treat as NULL
+ if (cfg1 && !cfg1->exists()) {
+ cfg1 = NULL;
+ }
+ if (cfg2 && !cfg2->exists()) {
+ cfg2 = NULL;
+ }
+
+ if (!cfg1 && !cfg2) {
+ fprintf(stderr, "_get_cmds_diff error (both config NULL)\n");
+ exit(1);
+ }
+
+ if (_get_cmds_diff_leaf(cfg1, cfg2, cur_path, del_list, set_list,
+ com_list)) {
+ // leaf node has been shown. done.
+ return;
+ } else {
+ // intermediate node, tag node, or tag value
+ _get_cmds_diff_other(cfg1, cfg2, cur_path, del_list, set_list, com_list);
+ }
+}
+
+static void
+_print_cmds_list(const char *op, vector<vector<string> >& list)
+{
+ for (size_t i = 0; i < list.size(); i++) {
+ printf("%s", op);
+ for (size_t j = 0; j < list[i].size(); j++) {
+ printf(" '%s'", list[i][j].c_str());
+ }
+ printf("\n");
+ }
+}
////// algorithms
void
-cnode::show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def,
- bool hide_secret)
+cnode::show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def,
+ bool hide_secret)
{
if (cfg1.isInvalid() || cfg2.isInvalid()) {
printf("Specified configuration path is not valid\n");
@@ -372,3 +651,51 @@ cnode::show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def,
show_def, hide_secret);
}
+void
+cnode::show_cfg(const CfgNode& cfg, bool show_def, bool hide_secret)
+{
+ show_cfg_diff(cfg, cfg, show_def, hide_secret);
+}
+
+void
+cnode::show_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2)
+{
+ vector<string> cur_path;
+ vector<vector<string> > del_list;
+ vector<vector<string> > set_list;
+ vector<vector<string> > com_list;
+ _get_cmds_diff(const_cast<CfgNode *>(&cfg1), const_cast<CfgNode *>(&cfg2),
+ cur_path, del_list, set_list, com_list);
+
+ _print_cmds_list("delete", del_list);
+ _print_cmds_list("set", set_list);
+ _print_cmds_list("comment", com_list);
+}
+
+void
+cnode::show_cmds(const CfgNode& cfg)
+{
+ show_cmds_diff(cfg, cfg);
+}
+
+void
+cnode::get_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2,
+ vector<vector<string> >& del_list,
+ vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list)
+{
+ vector<string> cur_path;
+ _get_cmds_diff(const_cast<CfgNode *>(&cfg1), const_cast<CfgNode *>(&cfg2),
+ cur_path, del_list, set_list, com_list);
+}
+
+void
+cnode::get_cmds(const CfgNode& cfg, vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list)
+{
+ vector<string> cur_path;
+ vector<vector<string> > del_list;
+ _get_cmds_diff(const_cast<CfgNode *>(&cfg), const_cast<CfgNode *>(&cfg),
+ cur_path, del_list, set_list, com_list);
+}
+
diff --git a/src/cnode/cnode-algorithm.hpp b/src/cnode/cnode-algorithm.hpp
index 86bce81..07faf07 100644
--- a/src/cnode/cnode-algorithm.hpp
+++ b/src/cnode/cnode-algorithm.hpp
@@ -21,8 +21,19 @@
namespace cnode {
-void show_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def,
- bool hide_secret);
+void show_cfg_diff(const CfgNode& cfg1, const CfgNode& cfg2, bool show_def,
+ bool hide_secret);
+void show_cfg(const CfgNode& cfg, bool show_def, bool hide_secret);
+
+void show_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2);
+void show_cmds(const CfgNode& cfg);
+
+void get_cmds_diff(const CfgNode& cfg1, const CfgNode& cfg2,
+ vector<vector<string> >& del_list,
+ vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list);
+void get_cmds(const CfgNode& cfg, vector<vector<string> >& set_list,
+ vector<vector<string> >& com_list);
} // namespace cnode
diff --git a/src/cstore/cstore.cpp b/src/cstore/cstore.cpp
index ed18c9e..0ff8ba2 100644
--- a/src/cstore/cstore.cpp
+++ b/src/cstore/cstore.cpp
@@ -31,6 +31,9 @@
#include <cli_cstore.h>
#include <cstore/cstore.hpp>
#include <cstore/cstore-varref.hpp>
+#include <cnode/cnode.hpp>
+#include <cnode/cnode-algorithm.hpp>
+#include <cparse/cparse.hpp>
////// constants
@@ -1803,6 +1806,63 @@ Cstore::unmarkCfgPathDeactivated(const vector<string>& path_comps)
return ret;
}
+// load specified config file
+bool
+Cstore::loadFile(const char *filename)
+{
+ if (!inSession()) {
+ output_user("Cannot load config outside configuration session\n");
+ // exit handled by assert below
+ }
+ ASSERT_IN_SESSION;
+
+ FILE *fin = fopen(filename, "r");
+ if (!fin) {
+ output_user("Failed to open specified config file\n");
+ return false;
+ }
+
+ // get the config tree from the file
+ cnode::CfgNode *froot = cparse::parse_file(fin, *this);
+ if (!froot) {
+ output_user("Failed to parse specified config file\n");
+ return false;
+ }
+
+ // get the config tree from the active config
+ vector<string> args;
+ cnode::CfgNode aroot(*this, args, true, true);
+
+ // get the "commands diff" between the two
+ vector<vector<string> > del_list;
+ vector<vector<string> > set_list;
+ vector<vector<string> > com_list;
+ cnode::get_cmds_diff(aroot, *froot, del_list, set_list, com_list);
+
+ // "apply" the changes to the working config
+ for (size_t i = 0; i < del_list.size(); i++) {
+ vtw_def def;
+ if (!validateDeletePath(del_list[i], def)
+ || !deleteCfgPath(del_list[i], def)) {
+ print_str_vec("Delete [", "] failed\n", del_list[i], "'");
+ }
+ }
+ for (size_t i = 0; i < set_list.size(); i++) {
+ if (!validateSetPath(set_list[i]) || !setCfgPath(set_list[i])) {
+ print_str_vec("Set [", "] failed\n", set_list[i], "'");
+ }
+ }
+ for (size_t i = 0; i < com_list.size(); i++) {
+ vtw_def def;
+ if (!validateCommentArgs(com_list[i], def)
+ || !commentCfgPath(com_list[i], def)) {
+ print_str_vec("Comment [", "] failed\n", com_list[i], "'");
+ }
+ }
+
+ return true;
+}
+
/* "changed" status handling.
* the "changed" status is used during commit to check if a node has been
* changed. note that if a node is "changed", all of its ancestors are also
@@ -2797,3 +2857,18 @@ Cstore::shell_escape_squotes(string& str)
}
}
+// print a vector of strings
+void
+Cstore::print_str_vec(const char *pre, const char *post,
+ const vector<string>& vec, const char *quote)
+{
+ output_user("%s", pre);
+ for (size_t i = 0; i < vec.size(); i++) {
+ if (i > 0) {
+ output_user(" ");
+ }
+ output_user("%s%s%s", quote, vec[i].c_str(), quote);
+ }
+ output_user("%s", post);
+}
+
diff --git a/src/cstore/cstore.hpp b/src/cstore/cstore.hpp
index 267dabe..d1d01fa 100644
--- a/src/cstore/cstore.hpp
+++ b/src/cstore/cstore.hpp
@@ -112,7 +112,7 @@ public:
* edit-related commands (invoked from shell functions)
* completion-related (for completion script)
* session-related (setup, teardown, etc.)
- * load (XXX currently still implemented in perl)
+ * load
*
* these operate on the "working config" and the session and MUST NOT
* be used by anything other than the listed operations.
@@ -165,8 +165,8 @@ public:
virtual bool inSession() = 0;
// commit
bool unmarkCfgPathChanged(const vector<string>& path_comps);
- // XXX load
- //bool unmarkCfgPathDeactivatedDescendants(const vector<string>& path_comps);
+ // load
+ bool loadFile(const char *filename);
/******
* these functions are observers of the current "working config" or
@@ -476,6 +476,8 @@ private:
// util functions
string get_shell_prompt(const string& level);
void shell_escape_squotes(string& str);
+ void print_str_vec(const char *pre, const char *post,
+ const vector<string>& vec, const char *quote);
};
#endif /* _CSTORE_H_ */