Rework datastores

DatastoreAccess now has "targets". The target determines what datastores
are used for writing and reading data. There are three targets:
  Operational:
  - reads from operational, writes to running
  Startup:
  - reads from startup, writes to startup
  Running:
  - reads from running, writes to running

(the datastores types above correspond to the NMDA datastore types)

The need to define targets instead of just calling them "datastores" is
that the operational target doesn't actually use the operational
datastore for both writing and reading.

Change-Id: Iffb7034c27aba42d10d715e23a2c970031b9bd1b
diff --git a/src/cli.cpp b/src/cli.cpp
index 3805dbc..0635c28 100644
--- a/src/cli.cpp
+++ b/src/cli.cpp
@@ -22,12 +22,12 @@
 static const auto usage = R"(CLI interface to sysrepo
 
 Usage:
-  sysrepo-cli [-d <datastore>]
+  sysrepo-cli [-d <datastore_target>]
   sysrepo-cli (-h | --help)
   sysrepo-cli --version
 
 Options:
-  -d <datastore>   can be "running" or "startup" [default: running])";
+  -d <datastore_target>   can be "running", "startup" or "operational" [default: operational])";
 #elif defined(YANG_CLI)
 #include <boost/spirit/home/x3.hpp>
 #include <filesystem>
@@ -54,15 +54,15 @@
 static const auto usage = R"(CLI interface for NETCONF
 
 Usage:
-  netconf-cli [-v] [-p <port>] <host>
-  netconf-cli [-v] --socket <path>
+  netconf-cli [-v] [-d <datastore_target>] [-p <port>] <host>
+  netconf-cli [-v] [-d <datastore_target>] --socket <path>
   netconf-cli (-h | --help)
   netconf-cli --version
 
 Options:
   -v         enable verbose mode
   -p <port>  port number [default: 830]
-)";
+  -d <datastore_target>   can be "running", "startup" or "operational" [default: operational])";
 #include "cli-netconf.hpp"
 #include "netconf_access.hpp"
 #define PROGRAM_NAME "netconf-cli"
@@ -95,20 +95,26 @@
     Replxx lineEditor;
     std::atomic<int> backendReturnCode = 0;
 
-#if defined(SYSREPO_CLI)
-    auto datastoreType = Datastore::Running;
+    // For some reason, GCC10 still needs [[maybe_unused]] because of conditional compilation...
+    [[maybe_unused]] auto datastoreTarget = DatastoreTarget::Operational;
     if (const auto& ds = args["-d"]) {
         if (ds.asString() == "startup") {
-            datastoreType = Datastore::Startup;
+            datastoreTarget = DatastoreTarget::Startup;
         } else if (ds.asString() == "running") {
-            datastoreType = Datastore::Running;
+            datastoreTarget = DatastoreTarget::Running;
+        } else if (ds.asString() == "operational") {
+            datastoreTarget = DatastoreTarget::Operational;
         } else {
-            std::cerr << PROGRAM_NAME << ": unknown datastore: " << ds.asString() << "\n";
+            std::cerr << PROGRAM_NAME << ": unknown datastore target: " << ds.asString() << "\n";
             return 1;
         }
     }
-    auto datastore = std::make_shared<SysrepoAccess>(datastoreType);
-    std::cout << "Connected to sysrepo [datastore: " << (datastoreType == Datastore::Startup ? "startup" : "running") << "]" << std::endl;
+
+    auto datastoreTargetString = args["-d"] ? args["-d"].asString() : std::string("operational");
+
+#if defined(SYSREPO_CLI)
+    auto datastore = std::make_shared<SysrepoAccess>();
+    std::cout << "Connected to sysrepo [datastore target: " << datastoreTargetString << "]" << std::endl;
 #elif defined(YANG_CLI)
     auto datastore = std::make_shared<YangAccess>();
     if (args["--configonly"].asBool()) {
@@ -189,10 +195,13 @@
             return 1;
         }
     }
+    std::cout << "Connected via NETCONF [datastore target: " << datastoreTargetString << "]" << std::endl;
 #else
 #error "Unknown CLI backend"
 #endif
 
+    datastore->setTarget(datastoreTarget);
+
 #if defined(SYSREPO_CLI) || defined(NETCONF_CLI)
     auto createTemporaryDatastore = [](const std::shared_ptr<DatastoreAccess>& datastore) {
         return std::make_shared<YangAccess>(std::static_pointer_cast<YangSchema>(datastore->schema()));