diff options
author | Patrick Ohly <patrick.ohly@intel.com> | 2012-09-13 18:02:07 +0200 |
---|---|---|
committer | Patrick Ohly <patrick.ohly@intel.com> | 2012-10-25 16:43:46 +0200 |
commit | 849c5408e582189e92d920176109e97111ced043 (patch) | |
tree | f9e3423d6483f0e3fea1eec4d9a871e125b47d46 | |
parent | a4cc410b317c17b3c2060f8e487e3b65a5c506a4 (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.rst | 23 | ||||
-rw-r--r-- | src/syncevo/Cmdline.cpp | 100 | ||||
-rw-r--r-- | src/syncevo/Cmdline.h | 6 | ||||
-rwxr-xr-x | test/test-dbus.py | 6 |
4 files changed, 111 insertions, 24 deletions
@@ -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 ®istry(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() |