summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Ohly <patrick.ohly@intel.com>2012-09-13 18:02:07 +0200
committerPatrick Ohly <patrick.ohly@intel.com>2012-10-25 16:43:46 +0200
commit849c5408e582189e92d920176109e97111ced043 (patch)
treef9e3423d6483f0e3fea1eec4d9a871e125b47d46
parenta4cc410b317c17b3c2060f8e487e3b65a5c506a4 (diff)
command line: implement --create/remove-database
Creating a database is only possible with a chosen name. The UID is chosen automatically by the storage. A new property would be needed to also specify the UID. There are no command line tests for the new functionality because support for it in backends is limited.
-rw-r--r--README.rst23
-rw-r--r--src/syncevo/Cmdline.cpp100
-rw-r--r--src/syncevo/Cmdline.h6
-rwxr-xr-xtest/test-dbus.py6
4 files changed, 111 insertions, 24 deletions
diff --git a/README.rst b/README.rst
index a3dedeb6..02585f4e 100644
--- a/README.rst
+++ b/README.rst
@@ -13,8 +13,8 @@ synchronize personal information management data
SYNOPSIS
========
-List databases:
- syncevolution --print-databases [<properties>] [<config> <source>]
+List and manipulate databases:
+ syncevolution --print-databases|--create-database|--remove-database [<properties>] [<config> <source>]
Show information about configuration(s):
syncevolution --print-servers|--print-configs|--print-peers
@@ -317,6 +317,25 @@ file backend synchronizes directories with one file per item and
always needs an explicit ``database`` property because it cannot guess
which directory it is meant to use. ::
+ syncevolution --create-database [<properties>] [<config> <source>]
+
+Creates a new database for the selected ``backend``, using the
+information given in the ``database`` property. As with
+``--print-databases``, it is possible to give the properties directly
+without configuring a source first.
+
+The interpretation of the ``database`` property depends on the
+backend. Not all backends support this operation.
+
+The EDS backend uses the value of the ``database`` as name of the new
+database and assigns a unique URI automatically. ::
+
+ syncevolution --remove-database [<properties>] [<config> <source>]
+
+Looks up the database based on the ``database`` property (depending
+on the backend, both name and a URI are valid), then deletes the data.
+Note that source configurations using the database are not removed. ::
+
syncevolution <config>
Without the optional list of sources, all sources which are enabled in
diff --git a/src/syncevo/Cmdline.cpp b/src/syncevo/Cmdline.cpp
index 6727647e..7a028a49 100644
--- a/src/syncevo/Cmdline.cpp
+++ b/src/syncevo/Cmdline.cpp
@@ -204,6 +204,12 @@ bool Cmdline::parse(vector<string> &parsed)
} else if(boost::iequals(m_argv[opt], "--print-databases")) {
operations.push_back(m_argv[opt]);
m_printDatabases = true;
+ } else if(boost::iequals(m_argv[opt], "--create-database")) {
+ operations.push_back(m_argv[opt]);
+ m_createDatabase = true;
+ } else if(boost::iequals(m_argv[opt], "--remove-database")) {
+ operations.push_back(m_argv[opt]);
+ m_removeDatabase = true;
} else if(boost::iequals(m_argv[opt], "--print-servers") ||
boost::iequals(m_argv[opt], "--print-peers") ||
boost::iequals(m_argv[opt], "--print-configs")) {
@@ -403,6 +409,8 @@ bool Cmdline::isSync()
m_printTemplates || m_dontrun ||
m_argc == 1 || (m_useDaemon.wasSet() && m_argc == 2) ||
m_printDatabases ||
+ m_createDatabase ||
+ m_removeDatabase ||
m_printConfig || m_remove ||
(m_server == "" && m_argc > 1) ||
m_configure || m_migrate ||
@@ -704,8 +712,8 @@ bool Cmdline::run() {
}
} else if (m_dontrun) {
// user asked for information
- } else if (m_printDatabases) {
- // list databases
+ } else if (m_printDatabases || m_createDatabase || m_removeDatabase) {
+ // manipulate databases
const SourceRegistry &registry(SyncSource::getSourceRegistry());
boost::shared_ptr<SyncSourceNodes> nodes;
std::string header;
@@ -714,6 +722,11 @@ bool Cmdline::run() {
std::string sourceName;
FilterConfigNode::ConfigFilter::const_iterator backend;
+ void (Cmdline::*operation)(SyncSource *, const std::string &) =
+ m_printDatabases ? &Cmdline::listDatabases :
+ m_createDatabase ? &Cmdline::createDatabase :
+ &Cmdline::removeDatabase;
+
if (!m_server.empty()) {
// list for specific backend chosen via config
if (m_sources.size() != 1) {
@@ -754,6 +767,7 @@ bool Cmdline::run() {
SyncSourceParams params("list", *nodes, context);
if (!m_server.empty() || backend != sourceFilter.end()) {
// list for specific backend
+ params.m_name = sourceName;
auto_ptr<SyncSource> source(SyncSource::createSource(params, false, NULL));
if (source.get() != NULL) {
if (!m_server.empty() && nodes) {
@@ -761,10 +775,9 @@ bool Cmdline::run() {
checkSyncPasswords(*context);
checkSourcePasswords(*context, sourceName, *nodes);
}
- listSources(*source, header);
- SE_LOG_SHOW(NULL, NULL, "\n");
+ (this->*operation)(source.get(), header);
} else {
- SE_LOG_SHOW(NULL, NULL, "%s:\n cannot list databases", header.c_str());
+ SE_LOG_SHOW(NULL, NULL, "%s:\n cannot access databases", header.c_str());
}
} else {
// list for all backends
@@ -775,16 +788,14 @@ bool Cmdline::run() {
nodes->getProperties()->setProperty("backend", type.m_backend);
std::string header = boost::join(alias, " = ");
try {
+ // The name is used in error messages. We
+ // don't have a source name, so let's fall
+ // back to the backend instead.
+ params.m_name = type.m_backend;
auto_ptr<SyncSource> source(SyncSource::createSource(params, false));
- if (!source.get()) {
- // silently skip backends like the "file" backend which do not support
- // listing databases and return NULL unless configured properly
- } else {
- listSources(*source, header);
- SE_LOG_SHOW(NULL, NULL, "\n");
- }
+ (this->*operation)(source.get(), header);
} catch (...) {
- SE_LOG_ERROR(NULL, NULL, "%s:\nlisting databases failed", header.c_str());
+ SE_LOG_ERROR(NULL, NULL, "%s:\nacessing databases failed", header.c_str());
Exception::handle();
}
}
@@ -1997,15 +2008,21 @@ void Cmdline::checkForPeerProps()
}
}
-void Cmdline::listSources(SyncSource &syncSource, const string &header)
+void Cmdline::listDatabases(SyncSource *source, const string &header)
{
+ if (!source) {
+ // silently skip backends like the "file" backend which do not support
+ // listing databases and return NULL unless configured properly
+ return;
+ }
+
ostringstream out;
out << header << ":\n";
- if (syncSource.isInactive()) {
- out << "not enabled during compilation or not usable in the current environment\n";
+ if (source->isInactive()) {
+ out << source->getBackend() << ": not enabled during compilation or not usable in the current environment\n";
} else {
- SyncSource::Databases databases = syncSource.getDatabases();
+ SyncSource::Databases databases = source->getDatabases();
BOOST_FOREACH(const SyncSource::Database &database, databases) {
out << " " << database.m_name << " (" << database.m_uri << ")";
@@ -2016,6 +2033,53 @@ void Cmdline::listSources(SyncSource &syncSource, const string &header)
}
}
SE_LOG_SHOW(NULL, NULL, "%s", out.str().c_str());
+ SE_LOG_SHOW(NULL, NULL, "\n");
+}
+
+void Cmdline::createDatabase(SyncSource *source, const string &header)
+{
+ if (!source) {
+ SE_THROW(StringPrintf("%s:\ncannot access databases", header.c_str()));
+ return;
+ }
+
+ // Only the name can be set via the command line. URI is chosen by backend.
+ InitStateString databaseID = source->getDatabaseID();
+ if (!databaseID.wasSet()) {
+ SE_THROW("The 'database' property must be set to the name of the new database");
+ }
+ SyncSource::Database database = source->createDatabase(SyncSource::Database(databaseID, ""));
+ SE_LOG_SHOW(NULL, NULL, "%s: database '%s' (%s) was created.",
+ header.c_str(),
+ database.m_name.c_str(),
+ database.m_uri.c_str());
+}
+
+void Cmdline::removeDatabase(SyncSource *source, const string &header)
+{
+ if (!source) {
+ SE_THROW(StringPrintf("%s:\ncannot access databases", header.c_str()));
+ return;
+ }
+
+ InitStateString databaseID = source->getDatabaseID();
+ if (!databaseID.wasSet()) {
+ SE_THROW("The 'database' property was not set. Cowardly refusing to remove the default database. Set it to the empty string and try again if that was the intention.");
+ }
+
+ // determine URI
+ source->open();
+ SyncSource::Database database = source->getDatabase();
+ if (database.m_uri.empty()) {
+ SE_THROW(StringPrintf("Cannot determine database from 'database' property value '%s'.",
+ databaseID.c_str()));
+ }
+
+ source->deleteDatabase(database.m_uri);
+ SE_LOG_SHOW(NULL, NULL, "%s: database '%s' (%s) was removed.",
+ header.c_str(),
+ database.m_name.c_str(),
+ database.m_uri.c_str());
}
void Cmdline::dumpConfigs(const string &preamble,
@@ -4373,7 +4437,7 @@ private:
std::string out = m_out.str();
std::string err = m_err.str();
std::string all = m_all.str();
- CPPUNIT_ASSERT(boost::starts_with(out, "List databases:\n"));
+ CPPUNIT_ASSERT(boost::starts_with(out, "List and manipulate databases:\n"));
CPPUNIT_ASSERT(out.find("\nOptions:\n") == std::string::npos);
CPPUNIT_ASSERT(boost::ends_with(out,
"Remove item(s):\n"
diff --git a/src/syncevo/Cmdline.h b/src/syncevo/Cmdline.h
index 9417b995..5067331b 100644
--- a/src/syncevo/Cmdline.h
+++ b/src/syncevo/Cmdline.h
@@ -142,6 +142,8 @@ protected:
Bool m_run;
Bool m_migrate;
Bool m_printDatabases;
+ Bool m_createDatabase;
+ Bool m_removeDatabase;
Bool m_printServers;
Bool m_printTemplates;
Bool m_printConfig;
@@ -244,7 +246,9 @@ protected:
/**
* list all known data sources of a certain type
*/
- void listSources(SyncSource &syncSource, const std::string &header);
+ void listDatabases(SyncSource *source, const std::string &header);
+ void createDatabase(SyncSource *source, const std::string &header);
+ void removeDatabase(SyncSource *source, const std::string &header);
void dumpConfigs(const std::string &preamble,
const SyncConfig::ConfigList &servers);
diff --git a/test/test-dbus.py b/test/test-dbus.py
index eb692b79..d895a4c8 100755
--- a/test/test-dbus.py
+++ b/test/test-dbus.py
@@ -5569,7 +5569,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
def expectUsageError(self, out, err, specific_error):
'''verify a short usage info was produced and specific error
message was printed'''
- self.assertTrue(out.startswith("List databases:\n"))
+ self.assertTrue(out.startswith("List and manipulate databases:\n"))
self.assertEqual(out.find("\nOptions:\n"), -1)
self.assertTrue(out.endswith("Remove item(s):\n" \
" syncevolution --delete-items [--] <config> <source> (<luid> ... | '*')\n\n"))
@@ -5703,7 +5703,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
sessionFlags=None,
expectSuccess=False)
self.assertEqualDiff('[ERROR] --foo-bar: unknown parameter\n', stripOutput(err))
- self.assertRegexpMatches(out, '^List databases:\n')
+ self.assertRegexpMatches(out, '^List and manipulate databases:\n')
self.assertEqual(1, code)
# Run command without talking to server, joined streams.
@@ -5712,7 +5712,7 @@ spds/sources/todo/config.txt:# evolutionpassword =
expectSuccess=False,
preserveOutputOrder=True)
self.assertEqual(err, None)
- self.assertRegexpMatches(stripOutput(out), r'^List databases:\n(.*\n)*\[ERROR\] --foo-bar: unknown parameter\n$')
+ self.assertRegexpMatches(stripOutput(out), r'^List and manipulate databases:\n(.*\n)*\[ERROR\] --foo-bar: unknown parameter\n$')
self.assertEqual(1, code)
peerMin = self.getPeerMinVersion()