2008-03-19 12:29:14 +01:00
/*
2009-03-25 15:21:04 +01:00
* Copyright ( C ) 2008 - 2009 Patrick Ohly < patrick . ohly @ gmx . de >
* Copyright ( C ) 2009 Intel Corporation
2009-04-30 18:14:03 +02:00
*
* This library is free software ; you can redistribute it and / or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
* version 2.1 of the License , or ( at your option ) version 3.
*
* This library is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the GNU
* Lesser General Public License for more details .
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA
* 02110 - 1301 USA
2008-03-19 12:29:14 +01:00
*/
2009-10-05 14:49:32 +02:00
# include <syncevo/Cmdline.h>
# include <syncevo/FilterConfigNode.h>
# include <syncevo/VolatileConfigNode.h>
# include <syncevo/SyncSource.h>
# include <syncevo/SyncContext.h>
# include <syncevo/util.h>
2009-10-02 17:23:53 +02:00
# include "test.h"
2008-03-19 12:29:14 +01:00
2008-03-19 17:43:31 +01:00
# include <unistd.h>
# include <errno.h>
2010-06-11 15:44:57 +02:00
# include <fstream>
2008-03-19 12:29:14 +01:00
# include <iostream>
2009-04-15 21:03:26 +02:00
# include <iomanip>
2008-03-28 23:32:00 +01:00
# include <sstream>
2008-03-19 12:29:14 +01:00
# include <memory>
# include <set>
2010-03-03 16:20:53 +01:00
# include <list>
2008-03-19 15:35:22 +01:00
# include <algorithm>
2008-03-19 12:29:14 +01:00
using namespace std ;
# include <boost/shared_ptr.hpp>
2009-06-10 17:28:45 +02:00
# include <boost/algorithm/string/join.hpp>
2010-06-11 15:44:57 +02:00
# include <boost/algorithm/string/split.hpp>
2008-03-29 16:41:11 +01:00
# include <boost/algorithm/string.hpp>
2008-03-30 15:11:45 +02:00
# include <boost/foreach.hpp>
2010-06-11 15:44:57 +02:00
# include <fstream>
2009-10-05 14:49:32 +02:00
# include <syncevo/declarations.h>
2009-10-02 17:23:53 +02:00
SE_BEGIN_CXX
2009-10-05 14:49:32 +02:00
Cmdline : : Cmdline ( int argc , const char * const * argv , ostream & out , ostream & err ) :
2008-03-19 12:29:14 +01:00
m_argc ( argc ) ,
m_argv ( argv ) ,
m_out ( out ) ,
m_err ( err ) ,
2009-10-06 17:22:47 +02:00
m_validSyncProps ( SyncConfig : : getRegistry ( ) ) ,
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
m_validSourceProps ( SyncSourceConfig : : getRegistry ( ) )
2008-03-19 12:29:14 +01:00
{ }
2010-03-15 02:33:43 +01:00
Cmdline : : Cmdline ( const vector < string > & args , ostream & out , ostream & err ) :
m_args ( args ) ,
m_out ( out ) ,
m_err ( err ) ,
m_validSyncProps ( SyncConfig : : getRegistry ( ) ) ,
m_validSourceProps ( SyncSourceConfig : : getRegistry ( ) )
{
m_argc = args . size ( ) ;
m_argvArray . reset ( new const char * [ args . size ( ) ] ) ;
for ( int i = 0 ; i < m_argc ; i + + ) {
m_argvArray [ i ] = m_args [ i ] . c_str ( ) ;
}
m_argv = m_argvArray . get ( ) ;
}
2009-10-05 14:49:32 +02:00
bool Cmdline : : parse ( )
2008-03-19 12:29:14 +01:00
{
2010-04-06 10:38:24 +02:00
vector < string > parsed ;
return parse ( parsed ) ;
}
bool Cmdline : : parse ( vector < string > & parsed )
{
parsed . clear ( ) ;
2010-04-07 18:21:54 +02:00
if ( m_argc ) {
parsed . push_back ( m_argv [ 0 ] ) ;
}
2010-06-11 15:44:57 +02:00
m_delimiter = " \n \n " ;
2010-04-07 18:21:54 +02:00
2010-06-11 12:52:35 +02:00
// All command line options which ask for a specific operation,
// like --restore, --print-config, ... Used to detect conflicting
// operations.
vector < string > operations ;
2008-03-19 12:29:14 +01:00
int opt = 1 ;
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
bool ok ;
2008-03-19 12:29:14 +01:00
while ( opt < m_argc ) {
2010-04-06 10:38:24 +02:00
parsed . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
if ( m_argv [ opt ] [ 0 ] ! = ' - ' ) {
break ;
}
2008-03-29 16:41:11 +01:00
if ( boost : : iequals ( m_argv [ opt ] , " --sync " ) | |
boost : : iequals ( m_argv [ opt ] , " -s " ) ) {
2008-03-19 12:29:14 +01:00
opt + + ;
string param ;
string cmdopt ( m_argv [ opt - 1 ] ) ;
2008-03-19 13:11:39 +01:00
if ( ! parseProp ( m_validSourceProps , m_sourceProps ,
2008-03-19 12:29:14 +01:00
m_argv [ opt - 1 ] , opt = = m_argc ? NULL : m_argv [ opt ] ,
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSourceConfig : : m_sourcePropSync . getName ( ) . c_str ( ) ) ) {
2008-03-19 12:29:14 +01:00
return false ;
}
2010-04-09 05:24:03 +02:00
parsed . push_back ( m_argv [ opt ] ) ;
2008-08-03 22:48:45 +02:00
// disable requirement to add --run explicitly in order to
// be compatible with traditional command lines
m_run = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --sync-property " ) | |
boost : : iequals ( m_argv [ opt ] , " -y " ) ) {
2008-03-19 12:29:14 +01:00
opt + + ;
if ( ! parseProp ( m_validSyncProps , m_syncProps ,
m_argv [ opt - 1 ] , opt = = m_argc ? NULL : m_argv [ opt ] ) ) {
return false ;
}
2010-04-09 05:24:03 +02:00
parsed . push_back ( m_argv [ opt ] ) ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --source-property " ) | |
boost : : iequals ( m_argv [ opt ] , " -z " ) ) {
2008-03-19 12:29:14 +01:00
opt + + ;
if ( ! parseProp ( m_validSourceProps , m_sourceProps ,
m_argv [ opt - 1 ] , opt = = m_argc ? NULL : m_argv [ opt ] ) ) {
return false ;
}
2010-04-09 05:24:03 +02:00
parsed . push_back ( m_argv [ opt ] ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --template " ) | |
2008-03-29 16:41:11 +01:00
boost : : iequals ( m_argv [ opt ] , " -l " ) ) {
2008-03-19 12:29:14 +01:00
opt + + ;
if ( opt > = m_argc ) {
usage ( true , string ( " missing parameter for " ) + cmdOpt ( m_argv [ opt - 1 ] ) ) ;
return false ;
}
2010-04-09 05:24:03 +02:00
parsed . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_template = m_argv [ opt ] ;
2008-03-30 23:50:51 +02:00
m_configure = true ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
string temp = boost : : trim_copy ( m_template ) ;
if ( temp . find ( " ? " ) = = 0 ) {
m_printTemplates = true ;
2008-03-19 17:43:31 +01:00
m_dontrun = true ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
m_template = temp . substr ( 1 ) ;
2008-03-19 17:43:31 +01:00
}
2010-01-20 11:36:19 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --print-servers " ) | |
boost : : iequals ( m_argv [ opt ] , " --print-peers " ) | |
boost : : iequals ( m_argv [ opt ] , " --print-configs " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_printServers = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --print-config " ) | |
boost : : iequals ( m_argv [ opt ] , " -p " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_printConfig = true ;
2009-04-15 15:58:05 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --print-sessions " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2009-04-15 15:58:05 +02:00
m_printSessions = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --configure " ) | |
boost : : iequals ( m_argv [ opt ] , " -c " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_configure = true ;
2009-04-15 14:02:09 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --remove " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2009-04-15 14:02:09 +02:00
m_remove = true ;
2008-08-03 15:00:51 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --run " ) | |
boost : : iequals ( m_argv [ opt ] , " -r " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-08-03 15:00:51 +02:00
m_run = true ;
2009-04-23 16:47:07 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --restore " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2009-04-23 16:47:07 +02:00
opt + + ;
if ( opt > = m_argc ) {
usage ( true , string ( " missing parameter for " ) + cmdOpt ( m_argv [ opt - 1 ] ) ) ;
return false ;
}
m_restore = m_argv [ opt ] ;
if ( m_restore . empty ( ) ) {
usage ( true , string ( " missing parameter for " ) + cmdOpt ( m_argv [ opt - 1 ] ) ) ;
return false ;
}
2010-04-06 10:38:24 +02:00
//if can't convert it successfully, it's an invalid path
if ( ! relToAbs ( m_restore ) ) {
2009-04-23 16:47:07 +02:00
usage ( true , string ( " parameter ' " ) + m_restore + " ' for " + cmdOpt ( m_argv [ opt - 1 ] ) + " must be log directory " ) ;
return false ;
}
2010-04-06 10:38:24 +02:00
parsed . push_back ( m_restore ) ;
2009-04-23 16:47:07 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --before " ) ) {
m_before = true ;
} else if ( boost : : iequals ( m_argv [ opt ] , " --after " ) ) {
m_after = true ;
2010-06-11 15:44:57 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --print-items " ) ) {
operations . push_back ( m_argv [ opt ] ) ;
m_printItems = m_accessItems = true ;
} else if ( ( boost : : iequals ( m_argv [ opt ] , " --export " ) & & ( m_export = true ) ) | |
( boost : : iequals ( m_argv [ opt ] , " --import " ) & & ( m_import = true ) ) | |
( boost : : iequals ( m_argv [ opt ] , " --update " ) & & ( m_update = true ) ) ) {
operations . push_back ( m_argv [ opt ] ) ;
m_accessItems = true ;
opt + + ;
if ( opt > = m_argc | | ! m_argv [ opt ] [ 0 ] ) {
usage ( true , string ( " missing parameter for " ) + cmdOpt ( m_argv [ opt - 1 ] ) ) ;
return false ;
}
m_itemPath = m_argv [ opt ] ;
if ( m_itemPath ! = " - " ) {
string dir , file ;
splitPath ( m_itemPath , dir , file ) ;
if ( dir . empty ( ) ) {
dir = " . " ;
}
if ( ! relToAbs ( dir ) ) {
SyncContext : : throwError ( dir , errno ) ;
}
m_itemPath = dir + " / " + file ;
}
parsed . push_back ( m_itemPath ) ;
} else if ( boost : : iequals ( m_argv [ opt ] , " --delimiter " ) ) {
opt + + ;
if ( opt > = m_argc ) {
usage ( true , string ( " missing parameter for " ) + cmdOpt ( m_argv [ opt - 1 ] ) ) ;
return false ;
}
m_delimiter = m_argv [ opt ] ;
parsed . push_back ( m_delimiter ) ;
2010-06-11 18:43:01 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --delete-items " ) ) {
operations . push_back ( m_argv [ opt ] ) ;
m_deleteItems = m_accessItems = true ;
2009-04-23 16:47:07 +02:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --dry-run " ) ) {
m_dryrun = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --migrate " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_migrate = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --status " ) | |
boost : : iequals ( m_argv [ opt ] , " -t " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_status = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --quiet " ) | |
boost : : iequals ( m_argv [ opt ] , " -q " ) ) {
2008-03-19 12:29:14 +01:00
m_quiet = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --help " ) | |
boost : : iequals ( m_argv [ opt ] , " -h " ) ) {
2008-03-19 12:29:14 +01:00
m_usage = true ;
2008-03-29 16:41:11 +01:00
} else if ( boost : : iequals ( m_argv [ opt ] , " --version " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2008-03-19 12:29:14 +01:00
m_version = true ;
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
} else if ( parseBool ( opt , " --keyring " , " -k " , true , m_keyring , ok ) ) {
if ( ! ok ) {
2010-03-15 02:33:43 +01:00
return false ;
}
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
} else if ( parseBool ( opt , " --daemon " , NULL , true , m_useDaemon , ok ) ) {
if ( ! ok ) {
return false ;
2010-03-15 02:33:43 +01:00
}
} else if ( boost : : iequals ( m_argv [ opt ] , " --monitor " ) | |
boost : : iequals ( m_argv [ opt ] , " -m " ) ) {
2010-06-11 12:52:35 +02:00
operations . push_back ( m_argv [ opt ] ) ;
2010-03-15 02:33:43 +01:00
m_monitor = true ;
2008-03-19 13:11:39 +01:00
} else {
usage ( false , string ( m_argv [ opt ] ) + " : unknown parameter " ) ;
return false ;
2008-03-19 12:29:14 +01:00
}
opt + + ;
}
if ( opt < m_argc ) {
m_server = m_argv [ opt + + ] ;
while ( opt < m_argc ) {
2010-04-06 10:38:24 +02:00
parsed . push_back ( m_argv [ opt ] ) ;
2010-06-11 15:44:57 +02:00
if ( m_sources . empty ( ) | |
! m_accessItems ) {
m_sources . insert ( m_argv [ opt + + ] ) ;
} else {
// first additional parameter was source, rest are luids
m_luids . push_back ( m_argv [ opt + + ] ) ;
}
2008-03-19 12:29:14 +01:00
}
}
2010-06-11 12:52:35 +02:00
// check whether we have conflicting operations requested by user
if ( operations . size ( ) > 1 ) {
usage ( false , boost : : join ( operations , " " ) + " : mutually exclusive operations " ) ;
return false ;
}
2010-06-11 15:44:57 +02:00
// common sanity checking for item listing/import/export/update
if ( m_accessItems ) {
if ( m_server . empty ( ) ) {
usage ( false , operations [ 0 ] + " : needs configuration name " ) ;
return false ;
}
if ( m_sources . size ( ) = = 0 ) {
usage ( false , operations [ 0 ] + " : needs source name " ) ;
return false ;
}
if ( ( m_import | | m_update ) & & m_dryrun ) {
usage ( false , operations [ 0 ] + " : --dry-run not supported " ) ;
return false ;
}
}
2008-03-19 12:29:14 +01:00
return true ;
}
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
bool Cmdline : : parseBool ( int opt , const char * longName , const char * shortName ,
bool def , Bool & value ,
bool & ok )
{
string option = m_argv [ opt ] ;
string param ;
size_t pos = option . find ( ' = ' ) ;
if ( pos ! = option . npos ) {
param = option . substr ( pos + 1 ) ;
option . resize ( pos ) ;
}
if ( ( longName & & boost : : iequals ( option , longName ) ) | |
( shortName & & boost : : iequals ( option , shortName ) ) ) {
ok = true ;
if ( param . empty ( ) ) {
value = def ;
} else if ( boost : : iequals ( param , " t " ) | |
boost : : iequals ( param , " 1 " ) | |
boost : : iequals ( param , " true " ) | |
boost : : iequals ( param , " yes " ) ) {
value = true ;
} else if ( boost : : iequals ( param , " f " ) | |
boost : : iequals ( param , " 0 " ) | |
boost : : iequals ( param , " false " ) | |
boost : : iequals ( param , " no " ) ) {
value = false ;
} else {
usage ( true , string ( " parameter in ' " ) + m_argv [ opt ] + " ' must be 1/t/true/yes or 0/f/false/no " ) ;
ok = false ;
}
// was our option
return true ;
} else {
// keep searching for match
return false ;
}
}
2010-03-15 02:33:43 +01:00
bool Cmdline : : isSync ( )
{
2010-06-11 13:00:05 +02:00
// make sure command line arguments really try to run sync
if ( m_usage | | m_version | |
m_printServers | | boost : : trim_copy ( m_server ) = = " ? " | |
m_printTemplates | | m_dontrun | |
m_argc = = 1 | | ( m_useDaemon . wasSet ( ) & & m_argc = = 2 ) | |
m_printConfig | | m_remove | |
( m_server = = " " & & m_argc > 1 ) | |
m_configure | | m_migrate | |
m_status | | m_printSessions | |
! m_restore . empty ( ) | |
2010-06-11 15:44:57 +02:00
m_accessItems | |
2010-06-11 13:00:05 +02:00
m_dryrun | |
( ! m_run & & ( m_syncProps . size ( ) | | m_sourceProps . size ( ) ) ) ) {
2010-03-15 02:33:43 +01:00
return false ;
2010-06-11 13:00:05 +02:00
} else {
return true ;
2010-03-15 02:33:43 +01:00
}
}
2010-04-07 18:23:33 +02:00
bool Cmdline : : dontRun ( ) const
{
// this mimics the if() checks in run()
if ( m_usage | | m_version | |
m_printServers | | boost : : trim_copy ( m_server ) = = " ? " | |
m_printTemplates ) {
return false ;
} else {
return m_dontrun ;
}
}
2009-10-05 14:49:32 +02:00
bool Cmdline : : run ( ) {
2009-04-23 16:47:07 +02:00
// --dry-run is only supported by some operations.
// Be very strict about it and make sure it is off in all
// potentially harmful operations, otherwise users might
// expect it to have an effect when it doesn't.
2008-03-19 12:29:14 +01:00
if ( m_usage ) {
usage ( true ) ;
} else if ( m_version ) {
printf ( " SyncEvolution %s \n " , VERSION ) ;
2008-10-10 23:57:55 +02:00
printf ( " %s " , EDSAbiWrapperInfo ( ) ) ;
2009-09-27 22:18:24 +02:00
printf ( " %s " , SyncSource : : backendsInfo ( ) . c_str ( ) ) ;
2008-03-30 15:11:45 +02:00
} else if ( m_printServers | | boost : : trim_copy ( m_server ) = = " ? " ) {
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
dumpConfigs ( " Configured servers: " ,
SyncConfig : : getConfigs ( ) ) ;
} else if ( m_printTemplates ) {
SyncConfig : : DeviceList devices ;
if ( m_template . empty ( ) ) {
dumpConfigTemplates ( " Available configuration templates: " ,
SyncConfig : : getPeerTemplates ( devices ) , false ) ;
} else {
//limiting at templates for syncml clients only.
2010-02-23 05:06:05 +01:00
devices . push_back ( SyncConfig : : DeviceDescription ( " " , m_template , SyncConfig : : MATCH_FOR_SERVER_MODE ) ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
dumpConfigTemplates ( " Available configuration templates: " ,
SyncConfig : : matchPeerTemplates ( devices ) , true ) ;
}
2008-03-19 12:29:14 +01:00
} else if ( m_dontrun ) {
// user asked for information
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
} else if ( m_argc = = 1 | | ( m_useDaemon . wasSet ( ) & & m_argc = = 2 ) ) {
2009-04-23 16:47:07 +02:00
// no parameters: list databases and short usage
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
const SourceRegistry & registry ( SyncSource : : getSourceRegistry ( ) ) ;
2009-11-13 14:52:00 +01:00
boost : : shared_ptr < FilterConfigNode > sharedNode ( new VolatileConfigNode ( ) ) ;
2008-03-19 12:29:14 +01:00
boost : : shared_ptr < FilterConfigNode > configNode ( new VolatileConfigNode ( ) ) ;
boost : : shared_ptr < FilterConfigNode > hiddenNode ( new VolatileConfigNode ( ) ) ;
boost : : shared_ptr < FilterConfigNode > trackingNode ( new VolatileConfigNode ( ) ) ;
2009-09-29 22:41:06 +02:00
boost : : shared_ptr < FilterConfigNode > serverNode ( new VolatileConfigNode ( ) ) ;
2010-03-04 17:50:01 +01:00
SyncSourceNodes nodes ( true , sharedNode , configNode , hiddenNode , trackingNode , serverNode , " " ) ;
2009-11-13 14:52:00 +01:00
SyncSourceParams params ( " list " , nodes ) ;
2008-03-19 12:29:14 +01:00
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const RegisterSyncSource * source , registry ) {
BOOST_FOREACH ( const Values : : value_type & alias , source - > m_typeValues ) {
if ( ! alias . empty ( ) & & source - > m_enabled ) {
configNode - > setProperty ( " type " , * alias . begin ( ) ) ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
auto_ptr < SyncSource > source ( SyncSource : : createSource ( params , false ) ) ;
2008-03-19 12:29:14 +01:00
if ( source . get ( ) ! = NULL ) {
2008-07-11 22:25:02 +02:00
listSources ( * source , boost : : join ( alias , " = " ) ) ;
2008-03-30 17:15:00 +02:00
m_out < < " \n " ;
2008-03-19 12:29:14 +01:00
}
}
}
}
usage ( false ) ;
} else if ( m_printConfig ) {
2009-10-06 17:22:47 +02:00
boost : : shared_ptr < SyncConfig > config ;
2009-11-24 19:26:58 +01:00
ConfigProps syncFilter ;
SourceFilters_t sourceFilters ;
2008-03-19 15:35:22 +01:00
if ( m_template . empty ( ) ) {
2008-03-30 13:43:36 +02:00
if ( m_server . empty ( ) ) {
m_err < < " ERROR: --print-config requires either a --template or a server name. " < < endl ;
return false ;
}
2009-10-06 17:22:47 +02:00
config . reset ( new SyncConfig ( m_server ) ) ;
2008-03-19 15:35:22 +01:00
if ( ! config - > exists ( ) ) {
2008-03-30 13:43:36 +02:00
m_err < < " ERROR: server ' " < < m_server < < " ' has not been configured yet. " < < endl ;
2008-03-19 15:35:22 +01:00
return false ;
}
2009-11-24 19:26:58 +01:00
syncFilter = m_syncProps ;
sourceFilters [ " " ] = m_sourceProps ;
2008-03-19 15:35:22 +01:00
} else {
2009-11-24 19:26:58 +01:00
string peer , context ;
SyncConfig : : splitConfigString ( SyncConfig : : normalizeConfigString ( m_template ) , peer , context ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
config = SyncConfig : : createPeerTemplate ( peer ) ;
2008-03-19 15:35:22 +01:00
if ( ! config . get ( ) ) {
2008-03-30 13:43:36 +02:00
m_err < < " ERROR: no configuration template for ' " < < m_template < < " ' available. " < < endl ;
2008-03-19 15:35:22 +01:00
return false ;
}
2009-11-24 19:26:58 +01:00
getFilters ( context , syncFilter , sourceFilters ) ;
2008-03-19 15:35:22 +01:00
}
2010-03-02 16:27:22 +01:00
// determine whether we dump a peer or a context
int flags = DUMP_PROPS_NORMAL ;
string peer , context ;
SyncConfig : : splitConfigString ( config - > getConfigName ( ) , peer , context ) ;
if ( peer . empty ( ) ) {
flags | = HIDE_PER_PEER ;
2010-03-03 16:20:53 +01:00
checkForPeerProps ( ) ;
2010-03-02 16:27:22 +01:00
}
2008-08-03 15:00:51 +02:00
if ( m_sources . empty ( ) | |
m_sources . find ( " main " ) ! = m_sources . end ( ) ) {
2008-03-19 15:35:22 +01:00
boost : : shared_ptr < FilterConfigNode > syncProps ( config - > getProperties ( ) ) ;
2009-11-24 19:26:58 +01:00
syncProps - > setFilter ( syncFilter ) ;
2010-03-02 16:27:22 +01:00
dumpProperties ( * syncProps , config - > getRegistry ( ) , flags ) ;
2008-03-19 12:29:14 +01:00
}
2008-07-06 22:49:19 +02:00
list < string > sources = config - > getSyncSources ( ) ;
sources . sort ( ) ;
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const string & name , sources ) {
2008-03-19 12:29:14 +01:00
if ( m_sources . empty ( ) | |
2008-07-11 22:25:02 +02:00
m_sources . find ( name ) ! = m_sources . end ( ) ) {
m_out < < endl < < " [ " < < name < < " ] " < < endl ;
2009-11-13 14:52:00 +01:00
SyncSourceNodes nodes = config - > getSyncSourceNodes ( name ) ;
boost : : shared_ptr < FilterConfigNode > sourceProps = nodes . getProperties ( ) ;
2009-11-24 19:26:58 +01:00
SourceFilters_t : : const_iterator it = sourceFilters . find ( name ) ;
if ( it ! = sourceFilters . end ( ) ) {
sourceProps - > setFilter ( it - > second ) ;
} else {
sourceProps - > setFilter ( sourceFilters [ " " ] ) ;
}
2010-01-20 11:36:19 +01:00
dumpProperties ( * sourceProps , SyncSourceConfig : : getRegistry ( ) ,
2010-03-02 16:27:22 +01:00
flags | ( ( name ! = * ( - - sources . end ( ) ) ) ? HIDE_LEGEND : DUMP_PROPS_NORMAL ) ) ;
2008-03-19 12:29:14 +01:00
}
}
2008-03-19 15:35:22 +01:00
} else if ( m_server = = " " & & m_argc > 1 ) {
// Options given, but no server - not sure what the user wanted?!
usage ( true , " server name missing " ) ;
return false ;
2008-03-19 12:29:14 +01:00
} else if ( m_configure | | m_migrate ) {
2009-04-23 16:47:07 +02:00
if ( m_dryrun ) {
2009-10-05 14:49:32 +02:00
SyncContext : : throwError ( " --dry-run not supported for configuration changes " ) ;
2009-04-23 16:47:07 +02:00
}
2009-09-21 10:07:05 +02:00
if ( m_keyring ) {
# ifndef USE_GNOME_KEYRING
m_err < < " Error: this syncevolution binary was compiled without support for storing "
" passwords in a keyring. Either store passwords in your configuration "
" files or enter them interactively on each program run. " < < endl ;
return false ;
# endif
}
2009-04-23 16:47:07 +02:00
2008-03-30 15:11:45 +02:00
bool fromScratch = false ;
2009-11-24 19:26:58 +01:00
string peer , context ;
SyncConfig : : splitConfigString ( SyncConfig : : normalizeConfigString ( m_server ) , peer , context ) ;
2010-03-03 16:20:53 +01:00
if ( peer . empty ( ) ) {
checkForPeerProps ( ) ;
}
2008-03-30 15:11:45 +02:00
2008-03-19 17:43:31 +01:00
// Both config changes and migration are implemented as copying from
// another config (template resp. old one). Migration also moves
// the old config.
2009-10-06 17:22:47 +02:00
boost : : shared_ptr < SyncConfig > from ;
2008-03-19 17:43:31 +01:00
if ( m_migrate ) {
2009-11-25 16:10:44 +01:00
string oldContext = context ;
2009-10-06 17:22:47 +02:00
from . reset ( new SyncConfig ( m_server ) ) ;
2008-03-19 17:43:31 +01:00
if ( ! from - > exists ( ) ) {
2009-11-25 16:10:44 +01:00
// for migration into a different context, search for config without context
oldContext = " " ;
from . reset ( new SyncConfig ( peer ) ) ;
if ( ! from - > exists ( ) ) {
m_err < < " ERROR: server ' " < < m_server < < " ' has not been configured yet. " < < endl ;
return false ;
}
2008-03-19 17:43:31 +01:00
}
int counter = 0 ;
string oldRoot = from - > getRootPath ( ) ;
string suffix ;
while ( true ) {
string newname ;
ostringstream newsuffix ;
newsuffix < < " .old " ;
if ( counter ) {
newsuffix < < " . " < < counter ;
}
suffix = newsuffix . str ( ) ;
newname = oldRoot + suffix ;
if ( ! rename ( oldRoot . c_str ( ) ,
newname . c_str ( ) ) ) {
break ;
} else if ( errno ! = EEXIST & & errno ! = ENOTEMPTY ) {
m_err < < " ERROR: renaming " < < oldRoot < < " to " < <
newname < < " : " < < strerror ( errno ) < < endl ;
return false ;
}
counter + + ;
}
2009-11-25 16:10:44 +01:00
from . reset ( new SyncConfig ( peer + suffix +
( oldContext . empty ( ) ? " " : " @ " ) +
oldContext ) ) ;
2008-03-19 17:43:31 +01:00
} else {
2009-10-06 17:22:47 +02:00
from . reset ( new SyncConfig ( m_server ) ) ;
2008-03-19 17:43:31 +01:00
if ( ! from - > exists ( ) ) {
// creating from scratch, look for template
2008-03-30 15:11:45 +02:00
fromScratch = true ;
2010-03-02 21:28:28 +01:00
string configTemplate ;
if ( m_template . empty ( ) ) {
// template is the peer name
configTemplate = m_server ;
SyncConfig : : splitConfigString ( SyncConfig : : normalizeConfigString ( configTemplate ) , peer , context ) ;
} else {
// Template is specified explicitly. It must not contain a context,
// because the context comes from the config name.
configTemplate = m_template ;
if ( SyncConfig : : splitConfigString ( SyncConfig : : normalizeConfigString ( configTemplate ) , peer , context ) ) {
m_err < < " ERROR: template " < < configTemplate < < " must not specify a context. " < < endl ;
return false ;
}
string tmp ;
SyncConfig : : splitConfigString ( SyncConfig : : normalizeConfigString ( m_server ) , tmp , context ) ;
}
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
from = SyncConfig : : createPeerTemplate ( peer ) ;
2008-03-19 17:43:31 +01:00
if ( ! from . get ( ) ) {
2008-03-30 13:43:36 +02:00
m_err < < " ERROR: no configuration template for ' " < < configTemplate < < " ' available. " < < endl ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
dumpConfigTemplates ( " Available configuration templates: " ,
SyncConfig : : getPeerTemplates ( SyncConfig : : DeviceList ( ) ) ) ;
2008-03-19 17:43:31 +01:00
return false ;
}
2009-11-19 16:30:46 +01:00
2010-03-02 21:30:13 +01:00
if ( ! from - > getPeerIsClient ( ) ) {
// Templates no longer contain these strings, because
// GUIs would have to localize them. For configs created
// via the command line, the extra hint that these
// properties need to be set is useful, so set these
// strings here. They'll get copied into the new
// config only if no other value was given on the
// command line.
if ( ! from - > getUsername ( ) [ 0 ] ) {
from - > setUsername ( " your SyncML server account name " ) ;
}
if ( ! from - > getPassword ( ) [ 0 ] ) {
from - > setPassword ( " your SyncML server password " ) ;
}
2010-03-04 03:54:54 +01:00
} else {
// uncomment SyncURL, so that it can be shown by
// sync-ui
if ( from - > getSyncURL ( ) . size ( ) = = 0 ) {
from - > setSyncURL ( " input your peer address here " ) ;
}
2009-11-19 16:30:46 +01:00
}
2008-03-19 17:43:31 +01:00
}
}
2009-11-24 19:26:58 +01:00
// Apply config changes on-the-fly. Regardless what we do
// (changing an existing config, migrating, creating from
// a template), existing shared properties in the desired
// context must be preserved unless explicitly overwritten.
// Therefore read those, update with command line properties,
// then set as filter.
ConfigProps syncFilter ;
SourceFilters_t sourceFilters ;
getFilters ( context , syncFilter , sourceFilters ) ;
from - > setConfigFilter ( true , " " , syncFilter ) ;
BOOST_FOREACH ( const SourceFilters_t : : value_type & entry , sourceFilters ) {
from - > setConfigFilter ( false , entry . first , entry . second ) ;
}
2008-03-19 17:43:31 +01:00
// write into the requested configuration, creating it if necessary
2009-10-05 14:49:32 +02:00
boost : : shared_ptr < SyncContext > to ( createSyncClient ( ) ) ;
2008-03-30 15:41:56 +02:00
to - > copy ( * from , ! fromScratch & & ! m_sources . empty ( ) ? & m_sources : NULL ) ;
2008-03-30 15:11:45 +02:00
2008-07-02 21:36:02 +02:00
// Sources are active now according to the server default.
// Disable all sources not selected by user (if any selected)
// and those which have no database.
if ( fromScratch ) {
2008-03-30 15:11:45 +02:00
list < string > configuredSources = to - > getSyncSources ( ) ;
2008-07-02 21:36:02 +02:00
set < string > sources = m_sources ;
2008-03-30 15:11:45 +02:00
BOOST_FOREACH ( const string & source , configuredSources ) {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
boost : : shared_ptr < PersistentSyncSourceConfig > sourceConfig ( to - > getSyncSourceConfig ( source ) ) ;
2008-07-02 21:36:02 +02:00
string disable = " " ;
set < string > : : iterator entry = sources . find ( source ) ;
bool selected = entry ! = sources . end ( ) ;
if ( ! m_sources . empty ( ) & &
! selected ) {
disable = " not selected " ;
} else {
if ( entry ! = sources . end ( ) ) {
// The command line parameter matched a valid source.
// All entries left afterwards must have been typos.
sources . erase ( entry ) ;
}
// check whether the sync source works
2009-11-13 14:52:00 +01:00
SyncSourceParams params ( " list " , to - > getSyncSourceNodes ( source ) ) ;
2010-03-17 10:03:59 +01:00
auto_ptr < SyncSource > syncSource ( SyncSource : : createSource ( params , false , to . get ( ) ) ) ;
2008-07-02 21:36:02 +02:00
if ( syncSource . get ( ) = = NULL ) {
disable = " no backend available " ;
} else {
try {
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSource : : Databases databases = syncSource - > getDatabases ( ) ;
2008-07-10 21:17:42 +02:00
if ( databases . empty ( ) ) {
2008-07-02 21:36:02 +02:00
disable = " no database to synchronize " ;
}
} catch ( . . . ) {
disable = " backend failed " ;
}
}
}
if ( ! disable . empty ( ) ) {
// abort if the user explicitly asked for the sync source
// and it cannot be enabled, otherwise disable it silently
if ( selected ) {
2009-10-05 14:49:32 +02:00
SyncContext : : throwError ( source + " : " + disable ) ;
2008-07-02 21:36:02 +02:00
}
sourceConfig - > setSync ( " disabled " ) ;
} else if ( selected ) {
// user absolutely wants it: enable even if off by default
FilterConfigNode : : ConfigFilter : : const_iterator sync =
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
m_sourceProps . find ( SyncSourceConfig : : m_sourcePropSync . getName ( ) ) ;
2008-07-02 21:36:02 +02:00
sourceConfig - > setSync ( sync = = m_sourceProps . end ( ) ? " two-way " : sync - > second ) ;
}
}
if ( ! sources . empty ( ) ) {
2009-10-05 14:49:32 +02:00
SyncContext : : throwError ( string ( " no such source(s): " ) + boost : : join ( sources , " " ) ) ;
2008-03-30 15:11:45 +02:00
}
}
2009-09-21 10:07:05 +02:00
// give a change to do something before flushing configs to files
to - > preFlush ( * to ) ;
2008-03-19 17:43:31 +01:00
// done, now write it
to - > flush ( ) ;
2009-11-25 15:30:07 +01:00
// also copy .synthesis dir?
if ( m_migrate ) {
string fromDir , toDir ;
fromDir = from - > getRootPath ( ) + " /.synthesis " ;
toDir = to - > getRootPath ( ) + " /.synthesis " ;
if ( isDir ( fromDir ) ) {
cp_r ( fromDir , toDir ) ;
}
}
2009-04-15 14:02:09 +02:00
} else if ( m_remove ) {
2009-04-23 16:47:07 +02:00
if ( m_dryrun ) {
2009-10-05 14:49:32 +02:00
SyncContext : : throwError ( " --dry-run not supported for removing configurations " ) ;
2009-04-23 16:47:07 +02:00
}
2009-04-15 14:02:09 +02:00
// extra sanity check
if ( ! m_sources . empty ( ) | |
! m_syncProps . empty ( ) | |
! m_sourceProps . empty ( ) ) {
usage ( true , " too many parameters for --remove " ) ;
return false ;
} else {
2009-10-06 17:22:47 +02:00
boost : : shared_ptr < SyncConfig > config ;
config . reset ( new SyncConfig ( m_server ) ) ;
2009-10-13 22:08:33 +02:00
if ( ! config - > exists ( ) ) {
SyncContext : : throwError ( string ( " no such configuration: " ) + m_server ) ;
}
2009-04-15 14:02:09 +02:00
config - > remove ( ) ;
return true ;
}
2010-06-11 15:44:57 +02:00
} else if ( m_accessItems ) {
// need access to specific source
boost : : shared_ptr < SyncContext > context ;
context . reset ( createSyncClient ( ) ) ;
context - > setOutput ( & m_out ) ;
string sourceName = * m_sources . begin ( ) ;
2010-06-16 13:51:50 +02:00
SyncSourceNodes sourceNodes = context - > getSyncSourceNodesNoTracking ( sourceName ) ;
2010-06-11 15:44:57 +02:00
SyncSourceParams params ( sourceName , sourceNodes ) ;
cxxptr < SyncSource > source ( SyncSource : : createSource ( params , true ) ) ;
sysync : : TSyError err ;
# define CHECK_ERROR(_op) if (err) { SE_THROW_EXCEPTION_STATUS(StatusException, string(source->getName()) + ": " + (_op), SyncMLStatus(err)); }
source - > open ( ) ;
const SyncSource : : Operations & ops = source - > getOperations ( ) ;
if ( m_printItems ) {
SyncSourceLogging * logging = dynamic_cast < SyncSourceLogging * > ( source . get ( ) ) ;
if ( ! ops . m_startDataRead | |
! ops . m_readNextItem ) {
source - > throwError ( " reading items not supported " ) ;
}
err = ops . m_startDataRead ( " " , " " ) ;
CHECK_ERROR ( " reading items " ) ;
list < string > luids ;
readLUIDs ( source , luids ) ;
BOOST_FOREACH ( string & luid , luids ) {
string description ;
2010-06-11 18:50:03 +02:00
if ( logging ) {
description = logging - > getDescription ( luid ) ;
if ( ! description . empty ( ) ) {
description . insert ( 0 , " : " ) ;
}
2010-06-11 15:44:57 +02:00
}
m_out < < luid < < description < < std : : endl ;
}
2010-06-11 18:43:01 +02:00
} else if ( m_deleteItems ) {
if ( ! ops . m_deleteItem ) {
source - > throwError ( " deleting items not supported " ) ;
}
err = ops . m_startDataRead ( " " , " " ) ;
CHECK_ERROR ( " reading items " ) ;
if ( ops . m_endDataRead ) {
err = ops . m_endDataRead ( ) ;
CHECK_ERROR ( " stop reading items " ) ;
}
if ( ops . m_startDataWrite ) {
err = ops . m_startDataWrite ( ) ;
CHECK_ERROR ( " writing items " ) ;
}
BOOST_FOREACH ( const string & luid , m_luids ) {
sysync : : ItemIDType id ;
2010-06-21 17:14:25 +02:00
string tmp = SafeConfigNode : : unescape ( luid ) ;
id . item = ( char * ) tmp . c_str ( ) ;
2010-06-11 18:43:01 +02:00
err = ops . m_deleteItem ( & id ) ;
CHECK_ERROR ( " deleting item " ) ;
}
// NO err = ops.m_endDataWrite(), see import/update below.
2010-06-11 15:44:57 +02:00
} else {
SyncSourceRaw * raw = dynamic_cast < SyncSourceRaw * > ( source . get ( ) ) ;
if ( ! raw ) {
source - > throwError ( " reading/writing items directly not supported " ) ;
}
if ( m_import | | m_update ) {
err = ops . m_startDataRead ( " " , " " ) ;
CHECK_ERROR ( " reading items " ) ;
if ( ops . m_endDataRead ) {
err = ops . m_endDataRead ( ) ;
CHECK_ERROR ( " stop reading items " ) ;
}
if ( ops . m_startDataWrite ) {
err = ops . m_startDataWrite ( ) ;
CHECK_ERROR ( " writing items " ) ;
}
cxxptr < ifstream > inFile ;
if ( m_itemPath = = " - " | |
! isDir ( m_itemPath ) ) {
string content ;
string luid ;
if ( m_itemPath = = " - " ) {
context - > readStdin ( content ) ;
} else if ( ! ReadFile ( m_itemPath , content ) ) {
SyncContext : : throwError ( m_itemPath , errno ) ;
}
if ( m_delimiter = = " none " ) {
if ( m_update ) {
if ( m_luids . size ( ) ! = 1 ) {
SyncContext : : throwError ( " need exactly one LUID parameter " ) ;
} else {
luid = * m_luids . begin ( ) ;
}
}
m_out < < " #0: "
< < insertItem ( raw , luid , content )
< < endl ;
} else {
typedef boost : : split_iterator < string : : iterator > string_split_iterator ;
int count = 0 ;
// when updating, check number of luids in advance
if ( m_update ) {
unsigned long total = 0 ;
for ( string_split_iterator it =
boost : : make_split_iterator ( content ,
boost : : first_finder ( m_delimiter , boost : : is_iequal ( ) ) ) ;
it ! = string_split_iterator ( ) ;
+ + it ) {
total + + ;
}
if ( total ! = m_luids . size ( ) ) {
SyncContext : : throwError ( StringPrintf ( " %lu items != %lu luids, must match => aborting " ,
total , ( unsigned long ) m_luids . size ( ) ) ) ;
}
}
list < string > : : const_iterator luidit = m_luids . begin ( ) ;
for ( string_split_iterator it =
boost : : make_split_iterator ( content ,
boost : : first_finder ( m_delimiter , boost : : is_iequal ( ) ) ) ;
it ! = string_split_iterator ( ) ;
+ + it ) {
m_out < < " # " < < count < < " : " ;
string luid ;
if ( m_update ) {
if ( luidit = = m_luids . end ( ) ) {
// was checked above
SyncContext : : throwError ( " internal error, not enough luids " ) ;
}
luid = * luidit ;
+ + luidit ;
}
m_out < < insertItem ( raw ,
luid ,
string ( it - > begin ( ) , it - > end ( ) ) )
< < endl ;
count + + ;
}
}
} else {
ReadDir dir ( m_itemPath ) ;
int count = 0 ;
BOOST_FOREACH ( const string & entry , dir ) {
string content ;
string path = m_itemPath + " / " + entry ;
m_out < < count < < " : " < < entry < < " : " ;
if ( ! ReadFile ( path , content ) ) {
SyncContext : : throwError ( path , errno ) ;
}
m_out < < insertItem ( raw , " " , content ) < < endl ;
}
}
// NO err = ops.m_endDataWrite()! That's
// intentional. It ensures that for most (all?!)
// backends the change tracking isn't updated and thus
// future syncs see the imports/updates as changes
// made by the user.
} else if ( m_export ) {
err = ops . m_startDataRead ( " " , " " ) ;
CHECK_ERROR ( " reading items " ) ;
ostream * out = NULL ;
cxxptr < ofstream > outFile ;
if ( m_itemPath = = " - " ) {
out = & m_out ;
} else if ( ! isDir ( m_itemPath ) ) {
outFile . set ( new ofstream ( m_itemPath . c_str ( ) ) ) ;
out = outFile ;
}
if ( m_luids . empty ( ) ) {
readLUIDs ( source , m_luids ) ;
}
bool haveItem = false ; // have written one item
bool haveNewline = false ; // that item had a newline at the end
try {
BOOST_FOREACH ( const string & luid , m_luids ) {
string item ;
raw - > readItemRaw ( SafeConfigNode : : unescape ( luid ) , item ) ;
if ( ! out ) {
// write into directory
string fullPath = m_itemPath + " / " + luid ;
ofstream file ( ( m_itemPath + " / " + luid ) . c_str ( ) ) ;
file < < item ;
file . close ( ) ;
if ( file . bad ( ) ) {
SyncContext : : throwError ( fullPath , errno ) ;
}
} else {
if ( haveItem ) {
if ( m_delimiter . size ( ) > 1 & &
haveNewline & &
m_delimiter [ 0 ] = = ' \n ' ) {
// already wrote initial newline, skip it
* out < < m_delimiter . substr ( 1 ) ;
} else {
* out < < m_delimiter ;
}
}
* out < < item ;
haveNewline = ! item . empty ( ) & & item [ item . size ( ) - 1 ] = = ' \n ' ;
haveItem = true ;
}
}
} catch ( . . . ) {
// ensure that we start following output on new line
if ( m_itemPath = = " - " & & haveItem & & ! haveNewline ) {
m_out < < endl ;
}
throw ;
}
if ( outFile ) {
outFile - > close ( ) ;
if ( outFile - > bad ( ) ) {
SyncContext : : throwError ( m_itemPath , errno ) ;
}
}
}
}
source - > close ( ) ;
2008-03-19 12:29:14 +01:00
} else {
2009-09-14 21:54:43 +02:00
std : : set < std : : string > unmatchedSources ;
boost : : shared_ptr < SyncContext > context ;
context . reset ( createSyncClient ( ) ) ;
context - > setQuiet ( m_quiet ) ;
context - > setDryRun ( m_dryrun ) ;
context - > setConfigFilter ( true , " " , m_syncProps ) ;
2010-03-26 10:17:32 +01:00
context - > setOutput ( & m_out ) ;
2009-09-14 21:54:43 +02:00
if ( m_sources . empty ( ) ) {
if ( m_sourceProps . empty ( ) ) {
// empty source list, empty source filter => run with
// existing configuration without filtering it
} else {
// Special semantic of 'no source selected': apply
// filter only to sources which are
// *active*. Configuration of inactive sources is left
// unchanged. This way we don't activate sync sources
// accidentally when the sync mode is modified
// temporarily.
BOOST_FOREACH ( const std : : string & source ,
context - > getSyncSources ( ) ) {
boost : : shared_ptr < PersistentSyncSourceConfig > source_config =
context - > getSyncSourceConfig ( source ) ;
if ( strcmp ( source_config - > getSync ( ) , " disabled " ) ) {
context - > setConfigFilter ( false , source , m_sourceProps ) ;
}
}
}
} else {
// apply (possibly empty) source filter to selected sources
BOOST_FOREACH ( const std : : string & source ,
m_sources ) {
boost : : shared_ptr < PersistentSyncSourceConfig > source_config =
context - > getSyncSourceConfig ( source ) ;
if ( ! source_config | | ! source_config - > exists ( ) ) {
// invalid source name in m_sources, remember and
// report this below
unmatchedSources . insert ( source ) ;
} else if ( m_sourceProps . find ( SyncSourceConfig : : m_sourcePropSync . getName ( ) ) = =
m_sourceProps . end ( ) ) {
// Sync mode is not set, must override the
// "sync=disabled" set below with the original
// sync mode for the source or (if that is also
// "disabled") with "two-way". The latter is part
// of the command line semantic that listing a
// source activates it.
FilterConfigNode : : ConfigFilter filter = m_sourceProps ;
string sync = source_config - > getSync ( ) ;
filter [ SyncSourceConfig : : m_sourcePropSync . getName ( ) ] =
sync = = " disabled " ? " two-way " : sync ;
context - > setConfigFilter ( false , source , filter ) ;
} else {
// sync mode is set, can use m_sourceProps
// directly to apply it
context - > setConfigFilter ( false , source , m_sourceProps ) ;
}
}
// temporarily disable the rest
FilterConfigNode : : ConfigFilter disabled ;
disabled [ SyncSourceConfig : : m_sourcePropSync . getName ( ) ] = " disabled " ;
context - > setConfigFilter ( false , " " , disabled ) ;
}
// check whether there were any sources specified which do not exist
if ( unmatchedSources . size ( ) ) {
context - > throwError ( string ( " no such source(s): " ) + boost : : join ( unmatchedSources , " " ) ) ;
}
2008-03-19 12:29:14 +01:00
if ( m_status ) {
2009-09-14 21:54:43 +02:00
context - > status ( ) ;
2009-04-15 15:58:05 +02:00
} else if ( m_printSessions ) {
vector < string > dirs ;
2009-09-14 21:54:43 +02:00
context - > getSessions ( dirs ) ;
2009-04-16 12:07:49 +02:00
bool first = true ;
2009-04-15 15:58:05 +02:00
BOOST_FOREACH ( const string & dir , dirs ) {
2009-04-16 12:07:49 +02:00
if ( first ) {
first = false ;
} else if ( ! m_quiet ) {
2010-03-26 09:53:27 +01:00
m_out < < endl ;
2009-04-16 12:07:49 +02:00
}
2010-03-26 09:53:27 +01:00
m_out < < dir < < endl ;
2009-04-16 12:07:49 +02:00
if ( ! m_quiet ) {
SyncReport report ;
2009-09-14 21:54:43 +02:00
context - > readSessionInfo ( dir , report ) ;
2010-03-26 09:53:27 +01:00
m_out < < report ;
2009-04-16 12:07:49 +02:00
}
2009-04-15 15:58:05 +02:00
}
2009-04-23 16:47:07 +02:00
} else if ( ! m_restore . empty ( ) ) {
// sanity checks: either --after or --before must be given, sources must be selected
if ( ( ! m_after & & ! m_before ) | |
( m_after & & m_before ) ) {
usage ( false , " --restore <log dir> must be used with either --after (restore database as it was after that sync) or --before (restore data from before sync) " ) ;
return false ;
}
if ( m_sources . empty ( ) ) {
usage ( false , " Sources must be selected explicitly for --restore to prevent accidental restore. " ) ;
return false ;
}
2009-09-14 21:54:43 +02:00
context - > restore ( m_restore ,
m_after ?
SyncContext : : DATABASE_AFTER_SYNC :
SyncContext : : DATABASE_BEFORE_SYNC ) ;
2008-03-19 12:29:14 +01:00
} else {
2009-04-23 16:47:07 +02:00
if ( m_dryrun ) {
2009-10-05 14:49:32 +02:00
SyncContext : : throwError ( " --dry-run not supported for running a synchronization " ) ;
2009-04-23 16:47:07 +02:00
}
2008-08-03 15:00:51 +02:00
// safety catch: if props are given, then --run
// is required
if ( ! m_run & &
( m_syncProps . size ( ) | | m_sourceProps . size ( ) ) ) {
usage ( false , " Properties specified, but neither '--configure' nor '--run' - what did you want? " ) ;
return false ;
}
2009-09-14 21:54:43 +02:00
return ( context - > sync ( ) = = STATUS_OK ) ;
2008-03-19 12:29:14 +01:00
}
}
return true ;
}
2010-06-11 15:44:57 +02:00
void Cmdline : : readLUIDs ( SyncSource * source , list < string > & luids )
{
const SyncSource : : Operations & ops = source - > getOperations ( ) ;
sysync : : ItemIDType id ;
sysync : : sInt32 status ;
sysync : : TSyError err = ops . m_readNextItem ( & id , & status , true ) ;
CHECK_ERROR ( " next item " ) ;
while ( status ! = sysync : : ReadNextItem_EOF ) {
luids . push_back ( SafeConfigNode : : escape ( id . item , true , true ) ) ;
err = ops . m_readNextItem ( & id , & status , false ) ;
CHECK_ERROR ( " next item " ) ;
}
}
string Cmdline : : insertItem ( SyncSourceRaw * source , const string & luid , const string & data )
{
2010-06-21 17:14:25 +02:00
SyncSourceRaw : : InsertItemResult res = source - > insertItemRaw ( SafeConfigNode : : unescape ( luid ) , data ) ;
2010-06-11 15:44:57 +02:00
return res . m_luid ;
}
2009-10-05 14:49:32 +02:00
string Cmdline : : cmdOpt ( const char * opt , const char * param )
2008-03-19 12:29:14 +01:00
{
string res = " ' " ;
res + = opt ;
if ( param ) {
res + = " " ;
res + = param ;
}
res + = " ' " ;
return res ;
}
2009-10-05 14:49:32 +02:00
bool Cmdline : : parseProp ( const ConfigPropertyRegistry & validProps ,
2008-03-19 12:29:14 +01:00
FilterConfigNode : : ConfigFilter & props ,
const char * opt ,
const char * param ,
const char * propname )
{
if ( ! param ) {
usage ( true , string ( " missing parameter for " ) + cmdOpt ( opt , param ) ) ;
return false ;
2008-03-30 15:11:45 +02:00
} else if ( boost : : trim_copy ( string ( param ) ) = = " ? " ) {
2008-03-19 12:29:14 +01:00
m_dontrun = true ;
if ( propname ) {
return listPropValues ( validProps , propname , opt ) ;
} else {
return listProperties ( validProps , opt ) ;
}
} else {
string propstr ;
string paramstr ;
if ( propname ) {
propstr = propname ;
paramstr = param ;
} else {
const char * equal = strchr ( param , ' = ' ) ;
if ( ! equal ) {
usage ( true , string ( " the '=<value>' part is missing in: " ) + cmdOpt ( opt , param ) ) ;
return false ;
}
propstr . assign ( param , equal - param ) ;
paramstr . assign ( equal + 1 ) ;
}
2008-03-30 15:11:45 +02:00
boost : : trim ( propstr ) ;
boost : : trim_left ( paramstr ) ;
if ( boost : : trim_copy ( paramstr ) = = " ? " ) {
2008-03-19 12:29:14 +01:00
m_dontrun = true ;
return listPropValues ( validProps , propstr , cmdOpt ( opt , param ) ) ;
} else {
const ConfigProperty * prop = validProps . find ( propstr ) ;
if ( ! prop ) {
2008-03-19 13:11:39 +01:00
m_err < < " ERROR: " < < cmdOpt ( opt , param ) < < " : no such property " < < endl ;
2008-03-19 12:29:14 +01:00
return false ;
} else {
string error ;
if ( ! prop - > checkValue ( paramstr , error ) ) {
m_err < < " ERROR: " < < cmdOpt ( opt , param ) < < " : " < < error < < endl ;
return false ;
} else {
2008-07-06 22:26:23 +02:00
props [ propstr ] = paramstr ;
2008-03-19 12:29:14 +01:00
return true ;
}
}
}
}
}
2009-10-05 14:49:32 +02:00
bool Cmdline : : listPropValues ( const ConfigPropertyRegistry & validProps ,
2008-03-19 12:29:14 +01:00
const string & propName ,
const string & opt )
{
const ConfigProperty * prop = validProps . find ( propName ) ;
if ( ! prop ) {
2008-03-19 13:11:39 +01:00
m_err < < " ERROR: " < < opt < < " : no such property " < < endl ;
2008-03-19 12:29:14 +01:00
return false ;
} else {
m_out < < opt < < endl ;
string comment = prop - > getComment ( ) ;
if ( comment ! = " " ) {
list < string > commentLines ;
ConfigProperty : : splitComment ( comment , commentLines ) ;
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const string & line , commentLines ) {
m_out < < " " < < line < < endl ;
2008-03-19 12:29:14 +01:00
}
} else {
2008-04-01 21:44:12 +02:00
m_out < < " no documentation available " < < endl ;
2008-03-19 12:29:14 +01:00
}
return true ;
}
}
2009-10-05 14:49:32 +02:00
bool Cmdline : : listProperties ( const ConfigPropertyRegistry & validProps ,
2008-03-19 12:29:14 +01:00
const string & opt )
{
// The first of several related properties has a comment.
// Remember that comment and print it as late as possible,
// that way related properties preceed their comment.
string comment ;
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const ConfigProperty * prop , validProps ) {
if ( ! prop - > isHidden ( ) ) {
string newComment = prop - > getComment ( ) ;
2008-03-19 12:29:14 +01:00
if ( newComment ! = " " ) {
2008-03-30 17:15:00 +02:00
if ( ! comment . empty ( ) ) {
dumpComment ( m_out , " " , comment ) ;
m_out < < endl ;
}
2008-03-19 12:29:14 +01:00
comment = newComment ;
}
2008-07-11 22:25:02 +02:00
m_out < < prop - > getName ( ) < < " : " < < endl ;
2008-03-19 12:29:14 +01:00
}
}
dumpComment ( m_out , " " , comment ) ;
return true ;
}
2009-11-24 19:26:58 +01:00
void Cmdline : : getFilters ( const string & context ,
ConfigProps & syncFilter ,
map < string , ConfigProps > & sourceFilters )
{
2009-12-01 18:03:39 +01:00
// Read from context. If it does not exist, we simply set no properties
// as filter. Previously there was a check for existance, but that was
// flawed because it ignored the global property "defaultPeer".
2009-11-24 19:26:58 +01:00
boost : : shared_ptr < SyncConfig > shared ( new SyncConfig ( string ( " @ " ) + context ) ) ;
2009-12-01 18:03:39 +01:00
shared - > getProperties ( ) - > readProperties ( syncFilter ) ;
BOOST_FOREACH ( StringPair entry , m_syncProps ) {
syncFilter [ entry . first ] = entry . second ;
}
2009-11-24 19:26:58 +01:00
2009-12-01 18:03:39 +01:00
BOOST_FOREACH ( std : : string source , shared - > getSyncSources ( ) ) {
SyncSourceNodes nodes = shared - > getSyncSourceNodes ( source , " " ) ;
ConfigProps & props = sourceFilters [ source ] ;
nodes . getProperties ( ) - > readProperties ( props ) ;
2009-11-24 19:26:58 +01:00
2009-12-01 18:03:39 +01:00
// Special case "type" property: the value in the context
// is not preserved. Every new peer must ensure that
// its own value is compatible (= same backend) with
// the other peers.
props . erase ( " type " ) ;
2009-11-24 19:26:58 +01:00
2009-12-01 18:03:39 +01:00
BOOST_FOREACH ( StringPair entry , m_sourceProps ) {
props [ entry . first ] = entry . second ;
2009-11-24 19:26:58 +01:00
}
}
2009-12-01 18:03:39 +01:00
sourceFilters [ " " ] = m_sourceProps ;
2009-11-24 19:26:58 +01:00
}
2010-03-03 16:20:53 +01:00
static void findPeerProps ( FilterConfigNode : : ConfigFilter & filter ,
ConfigPropertyRegistry & registry ,
list < string > & peerProps )
{
BOOST_FOREACH ( StringPair entry , filter ) {
const ConfigProperty * prop = registry . find ( entry . first ) ;
if ( prop & &
prop - > getSharing ( ) = = ConfigProperty : : NO_SHARING & &
! ( prop - > getFlags ( ) & ConfigProperty : : SHARED_AND_UNSHARED ) ) {
peerProps . push_back ( entry . first ) ;
}
}
}
void Cmdline : : checkForPeerProps ( )
{
list < string > peerProps ;
findPeerProps ( m_syncProps , SyncConfig : : getRegistry ( ) , peerProps ) ;
findPeerProps ( m_sourceProps , SyncSourceConfig : : getRegistry ( ) , peerProps ) ;
if ( ! peerProps . empty ( ) ) {
SyncContext : : throwError ( string ( " per-peer (unshared) properties not allowed: " ) +
boost : : join ( peerProps , " , " ) ) ;
}
}
2009-10-05 14:49:32 +02:00
void Cmdline : : listSources ( SyncSource & syncSource , const string & header )
2008-03-19 12:29:14 +01:00
{
m_out < < header < < " : \n " ;
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
SyncSource : : Databases databases = syncSource . getDatabases ( ) ;
2008-03-19 12:29:14 +01:00
redesigned SyncSource base class + API
The main motivation for this change is that it allows the implementor
of a backend to choose the implementations for the different aspects
of a datasource (change tracking, item import/export, logging, ...)
independently of each other. For example, change tracking via revision
strings can now be combined with exchanging data with the Synthesis
engine via a single string (the traditional method in SyncEvolution)
and with direct access to the Synthesis field list (now possible for
the first time).
The new backend API is based on the concept of providing
implementations for certain functionality via function objects instead
of implementing certain virtual methods. The advantage is that
implementors can define their own, custom interfaces and mix and match
implementations of the different groups of functionality.
Logging (see SyncSourceLogging in a later commit) can be done by
wrapping some arbitrary other item import/export function objects
(decorator design pattern).
The class hierarchy is now this:
- SyncSourceBase: interface for common utility code, all other
classes are derived from it and thus can use that code
- SyncSource: base class which implements SyncSourceBase and
hooks a datasource into the SyncEvolution core;
its "struct Operations" holds the function objects which
can be implemented in different ways
- TestingSyncSource: combines some of the following classes
into an interface that is expected by the client-test
program; backends only have to derive from (and implement this)
if they want to use the automated testing
- TrackingSyncSource: provides the same functionality as
before (change tracking via revision strings, item import/export
as string) in a single interface; the description of the pure
virtual methods are duplicated so that developers can go through
this class and find everything they need to know to implement
it
The following classes contain the code that was previously
found in the EvolutionSyncSource base class. Implementors
can derive from them and call the init() methods to inherit
and activate the functionality:
- SyncSourceSession: binds Synthesis session callbacks to
virtual methods beginSync(), endSync()
- SyncSourceChanges: implements Synthesis item tracking callbacks
with set of LUIDs that the user of the class has to fill
- SyncSourceDelete: binds Synthesis delete callback to
virtual method
- SyncSourceRaw: read and write items in the backends format,
used for testing and backup/restore
- SyncSourceSerialize: exchanges items with Synthesis engine
using a string representation of the data; this is how
EvolutionSyncSource has traditionally worked, so much of the
same virtual methods are now in this class
- SyncSourceRevisions: utility class which does change tracking
via some kind of "revision" string which changes each time
an item is modified; this code was previously in the
TrackingSyncSource
2009-08-25 09:27:46 +02:00
BOOST_FOREACH ( const SyncSource : : Database & database , databases ) {
2008-07-10 21:17:42 +02:00
m_out < < " " < < database . m_name < < " ( " < < database . m_uri < < " ) " ;
if ( database . m_isDefault ) {
2008-03-30 21:08:19 +02:00
m_out < < " <default> " ;
}
m_out < < endl ;
2008-03-19 12:29:14 +01:00
}
}
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
void Cmdline : : dumpConfigs ( const string & preamble ,
const SyncConfig : : ConfigList & servers )
2008-03-19 17:43:31 +01:00
{
m_out < < preamble < < endl ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
BOOST_FOREACH ( const SyncConfig : : ConfigList : : value_type & server , servers ) {
m_out < < " " < < server . first < < " = " < < server . second < < endl ;
2008-03-19 17:43:31 +01:00
}
if ( ! servers . size ( ) ) {
m_out < < " none " < < endl ;
}
}
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
void Cmdline : : dumpConfigTemplates ( const string & preamble ,
const SyncConfig : : TemplateList & templates ,
bool printRank )
{
m_out < < preamble < < endl ;
2010-03-03 09:24:58 +01:00
m_out < < " " < < " template name " < < " = " < < " template description " ;
if ( printRank ) {
2010-03-04 03:26:03 +01:00
m_out < < " " < < " matching score in percent (100% = exact match) " ;
2010-03-03 09:24:58 +01:00
}
m_out < < endl ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
BOOST_FOREACH ( const SyncConfig : : TemplateList : : value_type server , templates ) {
2010-03-25 04:26:13 +01:00
m_out < < " " < < server - > m_templateId < < " = " < < server - > m_description ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
if ( printRank ) {
2010-03-04 03:26:03 +01:00
m_out < < " " < < server - > m_rank * 20 < < " % " ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
}
m_out < < endl ;
}
if ( ! templates . size ( ) ) {
m_out < < " none " < < endl ;
}
}
2009-10-05 14:49:32 +02:00
void Cmdline : : dumpProperties ( const ConfigNode & configuredProps ,
2010-01-20 11:36:19 +01:00
const ConfigPropertyRegistry & allProps ,
2010-03-02 16:27:22 +01:00
int flags )
2008-03-19 12:29:14 +01:00
{
2010-01-20 11:36:19 +01:00
list < string > perPeer , perContext , global ;
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const ConfigProperty * prop , allProps ) {
2010-03-02 16:27:22 +01:00
if ( prop - > isHidden ( ) | |
( ( flags & HIDE_PER_PEER ) & &
prop - > getSharing ( ) = = ConfigProperty : : NO_SHARING & &
! ( prop - > getFlags ( ) & ConfigProperty : : SHARED_AND_UNSHARED ) ) ) {
2008-03-19 17:43:31 +01:00
continue ;
}
2008-03-19 12:29:14 +01:00
if ( ! m_quiet ) {
2008-07-11 22:25:02 +02:00
string comment = prop - > getComment ( ) ;
2008-03-19 15:38:19 +01:00
if ( ! comment . empty ( ) ) {
m_out < < endl ;
dumpComment ( m_out , " # " , comment ) ;
}
2008-03-19 12:29:14 +01:00
}
2008-03-30 23:50:51 +02:00
bool isDefault ;
2008-07-11 22:25:02 +02:00
prop - > getProperty ( configuredProps , & isDefault ) ;
2008-03-30 23:50:51 +02:00
if ( isDefault ) {
m_out < < " # " ;
}
2008-07-11 22:25:02 +02:00
m_out < < prop - > getName ( ) < < " = " < < prop - > getProperty ( configuredProps ) < < endl ;
2010-01-20 11:36:19 +01:00
list < string > * type = NULL ;
switch ( prop - > getSharing ( ) ) {
case ConfigProperty : : GLOBAL_SHARING :
type = & global ;
break ;
case ConfigProperty : : SOURCE_SET_SHARING :
type = & perContext ;
break ;
case ConfigProperty : : NO_SHARING :
type = & perPeer ;
break ;
}
if ( type ) {
type - > push_back ( prop - > getName ( ) ) ;
}
}
2010-03-02 16:27:22 +01:00
if ( ! m_quiet & & ! ( flags & HIDE_LEGEND ) ) {
2010-01-20 11:36:19 +01:00
if ( ! perPeer . empty ( ) | |
! perContext . empty ( ) | |
! global . empty ( ) ) {
m_out < < endl ;
}
if ( ! perPeer . empty ( ) ) {
m_out < < " # per-peer (unshared) properties: " < < boost : : join ( perPeer , " , " ) < < endl ;
}
if ( ! perContext . empty ( ) ) {
m_out < < " # shared by peers in same context: " < < boost : : join ( perContext , " , " ) < < endl ;
}
if ( ! global . empty ( ) ) {
m_out < < " # global properties: " < < boost : : join ( global , " , " ) < < endl ;
}
2008-03-19 12:29:14 +01:00
}
}
2009-10-05 14:49:32 +02:00
void Cmdline : : dumpComment ( ostream & stream ,
2008-03-19 12:29:14 +01:00
const string & prefix ,
const string & comment )
{
list < string > commentLines ;
ConfigProperty : : splitComment ( comment , commentLines ) ;
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const string & line , commentLines ) {
stream < < prefix < < line < < endl ;
2008-03-19 12:29:14 +01:00
}
}
2009-10-05 14:49:32 +02:00
void Cmdline : : usage ( bool full , const string & error , const string & param )
2008-03-19 12:29:14 +01:00
{
2008-03-29 18:04:26 +01:00
ostream & out ( error . empty ( ) ? m_out : m_err ) ;
2008-08-03 15:00:51 +02:00
out < < " Show available sources: " < < endl ;
out < < " " < < m_argv [ 0 ] < < endl ;
2009-04-15 15:58:05 +02:00
out < < " Show information about configuration(s) and sync sessions: " < < endl ;
2010-01-20 11:36:19 +01:00
out < < " " < < m_argv [ 0 ] < < " --print-servers|--print-configs|--print-peers " < < endl ;
out < < " " < < m_argv [ 0 ] < < " --print-config [--quiet] <config> [main|<source ...] " < < endl ;
out < < " " < < m_argv [ 0 ] < < " --print-sessions [--quiet] <config> " < < endl ;
2008-08-03 15:00:51 +02:00
out < < " Show information about SyncEvolution: " < < endl ;
out < < " " < < m_argv [ 0 ] < < " --help|-h " < < endl ;
out < < " " < < m_argv [ 0 ] < < " --version " < < endl ;
out < < " Run a synchronization: " < < endl ;
2010-01-20 11:36:19 +01:00
out < < " " < < m_argv [ 0 ] < < " <config> [<source> ...] " < < endl ;
out < < " " < < m_argv [ 0 ] < < " --run <options for run> <config> [<source> ...] " < < endl ;
2009-04-23 16:47:07 +02:00
out < < " Restore data from the automatic backups: " < < endl ;
2010-01-20 11:36:19 +01:00
out < < " " < < m_argv [ 0 ] < < " --restore <session directory> --before|--after [--dry-run] <config> <source> ... " < < endl ;
2009-04-15 14:02:09 +02:00
out < < " Remove a configuration: " < < endl ;
2010-01-20 11:36:19 +01:00
out < < " " < < m_argv [ 0 ] < < " --remove <config> " < < endl ;
2008-08-03 15:00:51 +02:00
out < < " Modify configuration: " < < endl ;
2010-01-20 11:36:19 +01:00
out < < " " < < m_argv [ 0 ] < < " --configure <options for configuration> <config> [<source> ...] " < < endl ;
out < < " " < < m_argv [ 0 ] < < " --migrate <config> " < < endl ;
2008-03-19 12:29:14 +01:00
if ( full ) {
2008-03-29 18:04:26 +01:00
out < < endl < <
2008-03-19 12:29:14 +01:00
" Options: " < < endl < <
2008-04-10 21:36:57 +02:00
" --sync|-s <mode> " < < endl < <
" --sync|-s ? " < < endl < <
" Temporarily synchronize the active sources in that mode. Useful " < < endl < <
" for a \" refresh-from-server \" or \" refresh-from-client \" sync which " < < endl < <
" clears all data at one end and copies all items from the other. " < < endl < <
" " < < endl < <
2010-01-20 11:36:19 +01:00
" --print-servers|--print-configs|--print-peers " < < endl < <
" Prints the names of all configured peers to stdout. " < < endl < <
2008-04-10 21:36:57 +02:00
" " < < endl < <
" --print-config|-p " < < endl < <
2010-01-20 11:36:19 +01:00
" Prints the complete configuration for the selected peer " < < endl < <
2008-04-10 21:36:57 +02:00
" to stdout, including up-to-date comments for all properties. The " < < endl < <
" format is the normal .ini format with source configurations in " < < endl < <
" different sections introduced with [<source>] lines. Can be combined " < < endl < <
" with --sync-property and --source-property to modify the configuration " < < endl < <
2010-01-20 11:36:19 +01:00
" on-the-fly. When one or more sources are listed after the <config> " < < endl < <
2008-04-10 21:36:57 +02:00
" name on the command line, then only the configs of those sources are " < < endl < <
" printed. Using --quiet suppresses the comments for each property. " < < endl < <
" When setting a --template, then the reference configuration for " < < endl < <
2010-01-20 11:36:19 +01:00
" that peer is printed instead of an existing configuration. " < < endl < <
2008-04-10 21:36:57 +02:00
" " < < endl < <
2009-04-15 15:58:05 +02:00
" --print-sessions " < < endl < <
2009-04-16 12:07:49 +02:00
" Prints a list of all previous log directories. Unless --quiet is used, each " < < endl < <
" file name is followed by the original sync report. " < < endl < <
2009-04-15 15:58:05 +02:00
" " < < endl < <
2009-09-28 11:55:24 +02:00
" --configure|-c " < < endl < <
2010-01-20 11:36:19 +01:00
" Modify the configuration files for the selected peer. If no such " < < endl < <
2008-04-10 21:36:57 +02:00
" configuration exists, then a new one is created using one of the " < < endl < <
" template configurations (see --template option). When creating " < < endl < <
" a new configuration only the active sources will be set to active " < < endl < <
" in the new configuration, i.e. \" syncevolution -c scheduleworld addressbook \" " < < endl < <
" followed by \" syncevolution scheduleworld \" will only synchronize the " < < endl < <
" address book. The other sources are created in a disabled state. " < < endl < <
" When modifying an existing configuration and sources are specified, " < < endl < <
" then the source properties of only those sources are modified. " < < endl < <
" " < < endl < <
" --migrate " < < endl < <
2010-01-20 11:36:19 +01:00
" In older SyncEvolution releases a different layout of configuration files " < < endl < <
2008-04-10 21:36:57 +02:00
" was used. Using --migrate will automatically migrate to the new " < < endl < <
2010-01-20 11:36:19 +01:00
" layout and rename the <config> into <config>.old to prevent accidental use " < < endl < <
2008-04-10 21:36:57 +02:00
" of the old configuration. WARNING: old SyncEvolution releases cannot " < < endl < <
" use the new configuration! " < < endl < <
2010-01-20 11:36:19 +01:00
" " < < endl < <
2008-04-10 21:36:57 +02:00
" The switch can also be used to migrate a configuration in the current " < < endl < <
" configuration directory: this preserves all property values, discards " < < endl < <
" obsolete properties and sets all comments exactly as if the configuration " < < endl < <
" had been created from scratch. WARNING: custom comments in the " < < endl < <
" configuration are not preserved. " < < endl < <
" " < < endl < <
2009-04-23 16:47:07 +02:00
" --restore " < < endl < <
" Restores the data of the selected sources to the state from before or after the " < < endl < <
" selected synchronization. The synchronization is selected via its log directory " < < endl < <
" (see --print-sessions). Other directories can also be given as long as " < < endl < <
" they contain database dumps in the format created by SyncEvolution. " < < endl < <
" The output includes information about the changes made during the " < < endl < <
" restore, both in terms of item changes and content changes (which is " < < endl < <
" not always the same, see manual for details). This output can be suppressed " < < endl < <
" with --quiet. " < < endl < <
" In combination with --dry-run, the changes to local data are only simulated. " < < endl < <
" This can be used to check that --restore will not remove valuable information. " < < endl < <
" " < < endl < <
2009-04-16 08:42:11 +02:00
" --remove " < < endl < <
2010-01-20 11:36:19 +01:00
" Deletes the configuration. If the <config> refers to a specific " < < endl < <
" peer, only that peer's configuration is removed. If it refers to " < < endl < <
" a context, that context and all peers inside it are removed. " < < endl < <
" Note that there is no confirmation question. Neither local data " < < endl < <
" referenced by the configuration nor the content of log dirs are " < < endl < <
" deleted. " < < endl < <
2009-04-16 08:42:11 +02:00
" " < < endl < <
2008-04-10 21:36:57 +02:00
" --sync-property|-y <property>=<value> " < < endl < <
" --sync-property|-y ? " < < endl < <
" --sync-property|-y <property>=? " < < endl < <
2010-01-20 11:36:19 +01:00
" Overrides a source-independent configuration property for the " < < endl < <
" current synchronization run or permanently when --configure is used " < < endl < <
" to update the configuration. Can be used multiple times. Specifying " < < endl < <
" an unused property will trigger an error message. " < < endl < <
" " < < endl < <
" When using the configuration layout introduced with 1.0, some of the " < < endl < <
" sync properties are shared between peers, for example the directory " < < endl < <
" where sessions are logged. Permanently changing such a shared " < < endl < <
" property for one peer will automatically update the property for all " < < endl < <
" other peers in the same context because the property is stored in a " < < endl < <
" shared config file. " < < endl < <
2008-04-10 21:36:57 +02:00
" " < < endl < <
" --source-property|-z <property>=<value> " < < endl < <
" --source-property|-z ? " < < endl < <
" --source-property|-z <property>=? " < < endl < <
2009-09-28 11:55:24 +02:00
" Same as --sync-property, but applies to the configuration of all active " < < endl < <
2009-10-01 15:59:48 +02:00
" sources. \" --sync <mode> \" is a shortcut for \" --source-property sync=<mode> \" . " < < endl < <
2008-04-10 21:36:57 +02:00
" " < < endl < <
2010-01-20 11:36:19 +01:00
" --template|-l <peer name>|default|?|?<device> " < < endl < <
2008-04-10 21:36:57 +02:00
" Can be used to select from one of the built-in default configurations " < < endl < <
2010-01-20 11:36:19 +01:00
" for known SyncML peers. Defaults to the <config> name, so --template " < < endl < <
2008-04-10 21:36:57 +02:00
" only has to be specified when creating multiple different configurations " < < endl < <
2010-01-20 11:36:19 +01:00
" for the same peer, or when using a template that is named differently " < < endl < <
" than the peer. \" default \" is an alias for \" scheduleworld \" and can be " < < endl < <
2008-04-10 21:36:57 +02:00
" used as the starting point for servers which do not have a built-in " < < endl < <
2010-01-20 11:36:19 +01:00
" template. " < < endl < <
" " < < endl < <
2008-04-10 21:36:57 +02:00
" Each template contains a pseudo-random device ID. Therefore setting the " < < endl < <
" \" deviceId \" sync property is only necessary when manually recreating a " < < endl < <
" configuration or when a more descriptive name is desired. " < < endl < <
" " < < endl < <
2010-01-20 11:36:19 +01:00
" The available templates for different known SyncML servers are listed when " < < endl < <
" using a single question mark instead of template name. When using the " < < endl < <
" ?<device> format, a fuzzy search for a template that might be " < < endl < <
" suitable for talking to such a device is done. The matching works best " < < endl < <
" when using <device> = <Manufacturer>_<Model>. If you don't know the " < < endl < <
" manufacturer, you can just keep it as empty. The output in this mode " < < endl < <
" gives the template name followed by a short description and a rating how well " < < endl < <
" the template matches the device (higher is better). " < < endl < <
" " < < endl < <
2008-04-10 21:36:57 +02:00
" --status|-t " < < endl < <
" The changes made to local data since the last synchronization are " < < endl < <
" shown without starting a new one. This can be used to see in advance " < < endl < <
2010-01-20 11:36:19 +01:00
" whether the local data needs to be synchronized with the peer. " < < endl < <
2008-04-10 21:36:57 +02:00
" " < < endl < <
2010-03-29 10:58:31 +02:00
" When used without configuration name, it shows the status of the background " < < endl < <
" sync daemon or an error if no such daemon exists. " < < endl < <
" " < < endl < <
2008-04-10 21:36:57 +02:00
" --quiet|-q " < < endl < <
" Suppresses most of the normal output during a synchronization. The " < < endl < <
" log file still contains all the information. " < < endl < <
" " < < endl < <
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
" --keyring|-k[=yes/no/...] " < < endl < <
2009-09-21 10:07:05 +02:00
" Save or retrieve passwords from the GNOME keyring when modifying the " < < endl < <
" configuration or running a synchronization. Note that using this option " < < endl < <
" applies to *all* passwords in a configuration, so setting a single " < < endl < <
" password as follows moves the other passwords into the keyring, if " < < endl < <
" they were not stored there already: " < < endl < <
" --keyring --configure --sync-property proxyPassword=foo " < < endl < <
" " < < endl < <
" When passwords were stored in the keyring, their value is set to '-' " < < endl < <
" in the configuration. This means that when running a synchronization " < < endl < <
" without the --keyring argument, the password has to be entered " < < endl < <
2009-09-23 07:25:28 +02:00
" interactively. The --print-config output always shows '-' instead of " < < endl < <
" retrieving the password from the keyring. " < < endl < <
2009-09-21 10:07:05 +02:00
" " < < endl < <
command line + daemon: usability improvements (MB #5043)
This patch changes what is shown to the user and how the user
interacts with the command line. Details below.
"--use-daemon [yes/no]" implies that yes/no is optional (square
brackets!), with "yes" being the option that could be expected for a
plain "--use-daemon" parameter. But the implementation always expects
a "yes" or "no" parameter. The original format suggested was
"--use-daemon[=yes/no]"
This patch switches to that format, changes --use-daemon into --daemon
(to be consistent with --keyring) and enables the same format for
--keyring. Although not documented, 0/f/false and 1/t/true are also
accepted. Because the value becomes part of the parameter, m_argc checks
had to be adapted.
The documentation for "--use-daemon" was inserted in the middle of the
"--keyring documentation".
"Parameter not set" has to be available to the Cmdline caller in the
command line too, in addition to true/false. This was done originally
with a string which is empty, "yes" or "no". Using a tri-state
Cmdline::Bool class makes this a bit more explicit and removes the
ambiguity around what useDaemon() returns (values weren't documented).
When running without --daemon and no daemon available, the
first lines of output were:
ERROR: org.<cryptic error>
[INFO] itodo20: inactive
....
=> The command line should fall back *silently* to running in-process.
=> Error messages should be formatted and logged as such, using SE_LOG_ERROR().
Old code might not have done that and we need to preserve that for compatibility
with frontends, but new code should use [ERROR] as output.
=> D-Bus error messages (as in the case above) must have some user (and developer!)
comprehensible explanation what went wrong. The D-Bus error class itself
is no enough.
Although I haven't tested it, I suspect that the code also would have
re-run the operation in-process after the D-Bus server already
executed it and failed.
I rewrote this so that a check for "daemon available" without error messages
is done first before committing to using the daemon. Once that decision is made,
the command line will not fall back to in-process execution.
Rewrote several error messages. Telling a user of a distro's binary to
"re-configure" is misleading (he didn't configure himself).
"can't" => "cannot", punctuation changes. Not sure whether is always an
improvement, comments welcome.
Comment on coding style: I've used "if ()" instead of "if()" because that is
the GNU recommendation.
2010-03-26 18:47:41 +01:00
" --daemon[=yes/no/...] " < < endl < <
" Run operations in cooperation with the background sync daemon; " < < endl < <
" enabled by default if it is installed. " < < endl < <
" " < < endl < <
2008-04-10 21:36:57 +02:00
" --help|-h " < < endl < <
" Prints usage information. " < < endl < <
" " < < endl < <
" --version " < < endl < <
" Prints the SyncEvolution version. " < < endl ;
2008-03-19 12:29:14 +01:00
}
if ( error ! = " " ) {
2008-03-29 18:04:26 +01:00
out < < endl < < " ERROR: " < < error < < endl ;
2008-03-19 12:29:14 +01:00
}
if ( param ! = " " ) {
2008-03-29 18:04:26 +01:00
out < < " INFO: use ' " < < param < < ( param [ param . size ( ) - 1 ] = = ' = ' ? " " : " " ) < <
2008-03-19 12:29:14 +01:00
" ?' to get a list of valid parameters " < < endl ;
}
}
2008-03-28 23:32:00 +01:00
2009-10-05 14:49:32 +02:00
SyncContext * Cmdline : : createSyncClient ( ) {
2009-09-14 21:54:43 +02:00
return new SyncContext ( m_server , true ) ;
2009-09-21 10:07:05 +02:00
}
2008-04-17 20:27:53 +02:00
# ifdef ENABLE_UNIT_TESTS
2008-03-28 23:32:00 +01:00
2008-03-29 18:04:26 +01:00
/** simple line-by-line diff */
static string diffStrings ( const string & lhs , const string & rhs )
{
ostringstream res ;
typedef boost : : split_iterator < string : : const_iterator > string_split_iterator ;
string_split_iterator lit =
boost : : make_split_iterator ( lhs , boost : : first_finder ( " \n " , boost : : is_iequal ( ) ) ) ;
string_split_iterator rit =
boost : : make_split_iterator ( rhs , boost : : first_finder ( " \n " , boost : : is_iequal ( ) ) ) ;
while ( lit ! = string_split_iterator ( ) & &
rit ! = string_split_iterator ( ) ) {
if ( * lit ! = * rit ) {
res < < " < " < < * lit < < endl ;
res < < " > " < < * rit < < endl ;
}
+ + lit ;
+ + rit ;
}
while ( lit ! = string_split_iterator ( ) ) {
res < < " < " < < * lit < < endl ;
+ + lit ;
}
2008-03-29 18:26:23 +01:00
while ( rit ! = string_split_iterator ( ) ) {
2008-03-29 18:04:26 +01:00
res < < " > " < < * rit < < endl ;
+ + rit ;
}
return res . str ( ) ;
}
# define CPPUNIT_ASSERT_EQUAL_DIFF( expected, actual ) \
do { \
2008-03-30 11:02:07 +02:00
string expected_ = ( expected ) ; \
string actual_ = ( actual ) ; \
if ( expected_ ! = actual_ ) { \
2008-03-29 18:04:26 +01:00
CPPUNIT_NS : : Message cpputMsg_ ( string ( " expected: \n " ) + \
2008-03-30 11:02:07 +02:00
expected_ ) ; \
2008-03-29 18:04:26 +01:00
cpputMsg_ . addDetail ( string ( " actual: \n " ) + \
2008-03-30 11:02:07 +02:00
actual_ ) ; \
2008-03-29 18:04:26 +01:00
cpputMsg_ . addDetail ( string ( " diff: \n " ) + \
2008-03-30 11:02:07 +02:00
diffStrings ( expected_ , actual_ ) ) ; \
2008-03-29 18:04:26 +01:00
CPPUNIT_NS : : Asserter : : fail ( cpputMsg_ , \
CPPUNIT_SOURCELINE ( ) ) ; \
} \
} while ( false )
2008-03-30 13:43:36 +02:00
// returns last line, including trailing line break, empty if input is empty
static string lastLine ( const string & buffer )
{
if ( buffer . size ( ) < 2 ) {
return buffer ;
}
size_t line = buffer . rfind ( " \n " , buffer . size ( ) - 2 ) ;
if ( line = = buffer . npos ) {
return buffer ;
}
return buffer . substr ( line + 1 ) ;
}
2008-03-30 23:50:51 +02:00
// true if <word> =
static bool isPropAssignment ( const string & buffer ) {
size_t start = 0 ;
while ( start < buffer . size ( ) & &
! isspace ( buffer [ start ] ) ) {
start + + ;
}
if ( start + 3 < = buffer . size ( ) & &
buffer . substr ( start , 3 ) = = " = " ) {
return true ;
} else {
return false ;
}
}
// remove pure comment lines from buffer,
2009-11-24 15:02:21 +01:00
// also empty lines,
// also defaultPeer (because reference properties do not include global props)
2008-03-30 13:43:36 +02:00
static string filterConfig ( const string & buffer )
{
ostringstream res ;
typedef boost : : split_iterator < string : : const_iterator > string_split_iterator ;
for ( string_split_iterator it =
boost : : make_split_iterator ( buffer , boost : : first_finder ( " \n " , boost : : is_iequal ( ) ) ) ;
it ! = string_split_iterator ( ) ;
+ + it ) {
2008-03-30 23:50:51 +02:00
string line = boost : : copy_range < string > ( * it ) ;
if ( ! line . empty ( ) & &
2009-11-24 15:02:21 +01:00
line . find ( " defaultPeer = " ) = = line . npos & &
2008-03-30 23:50:51 +02:00
( ! boost : : starts_with ( line , " # " ) | |
isPropAssignment ( line . substr ( 2 ) ) ) ) {
res < < line < < endl ;
2008-03-30 13:43:36 +02:00
}
}
return res . str ( ) ;
}
2009-11-19 16:30:46 +01:00
static string injectValues ( const string & buffer )
{
string res = buffer ;
// username/password not set in templates, only in configs created via
// the command line
boost : : replace_first ( res ,
" # username = " ,
" username = your SyncML server account name " ) ;
boost : : replace_first ( res ,
" # password = " ,
" password = your SyncML server password " ) ;
return res ;
}
2008-03-30 17:15:00 +02:00
// remove lines indented with spaces
static string filterIndented ( const string & buffer )
{
ostringstream res ;
bool first = true ;
typedef boost : : split_iterator < string : : const_iterator > string_split_iterator ;
for ( string_split_iterator it =
boost : : make_split_iterator ( buffer , boost : : first_finder ( " \n " , boost : : is_iequal ( ) ) ) ;
it ! = string_split_iterator ( ) ;
+ + it ) {
if ( ! boost : : starts_with ( * it , " " ) ) {
if ( ! first ) {
res < < endl ;
} else {
first = false ;
}
res < < * it ;
}
}
return res . str ( ) ;
}
2009-11-24 15:02:21 +01:00
// sort lines by file, preserving order inside each line
static void sortConfig ( string & config )
{
// file name, line number, property
typedef pair < string , pair < int , string > > line_t ;
vector < line_t > lines ;
typedef boost : : split_iterator < string : : iterator > string_split_iterator ;
int linenr = 0 ;
for ( string_split_iterator it =
boost : : make_split_iterator ( config , boost : : first_finder ( " \n " , boost : : is_iequal ( ) ) ) ;
it ! = string_split_iterator ( ) ;
+ + it , + + linenr ) {
string line ( it - > begin ( ) , it - > end ( ) ) ;
if ( line . empty ( ) ) {
continue ;
}
size_t colon = line . find ( ' : ' ) ;
string prefix = line . substr ( 0 , colon ) ;
lines . push_back ( make_pair ( prefix , make_pair ( linenr , line . substr ( colon ) ) ) ) ;
}
// stable sort because of line number
sort ( lines . begin ( ) , lines . end ( ) ) ;
size_t len = config . size ( ) ;
config . resize ( 0 ) ;
config . reserve ( len ) ;
BOOST_FOREACH ( const line_t & line , lines ) {
config + = line . first ;
config + = line . second . second ;
config + = " \n " ;
}
}
// convert the internal config dump to .ini style (--print-config)
2008-03-30 13:43:36 +02:00
static string internalToIni ( const string & config )
{
ostringstream res ;
string section ;
typedef boost : : split_iterator < string : : const_iterator > string_split_iterator ;
for ( string_split_iterator it =
boost : : make_split_iterator ( config , boost : : first_finder ( " \n " , boost : : is_iequal ( ) ) ) ;
it ! = string_split_iterator ( ) ;
+ + it ) {
string line ( it - > begin ( ) , it - > end ( ) ) ;
if ( line . empty ( ) ) {
continue ;
}
size_t colon = line . find ( ' : ' ) ;
string prefix = line . substr ( 0 , colon ) ;
2009-11-24 15:02:21 +01:00
// internal values are not part of the --print-config output
2008-03-30 18:13:08 +02:00
if ( boost : : contains ( prefix , " .internal.ini " ) | |
boost : : contains ( line , " = internal value " ) ) {
2008-03-30 13:43:36 +02:00
continue ;
}
2009-11-24 15:02:21 +01:00
// --print-config also doesn't duplicate the "type" property
// => remove the shared property
if ( boost : : contains ( line , " :type = " ) & &
boost : : starts_with ( line , " sources/ " ) ) {
continue ;
}
2008-03-30 18:13:08 +02:00
// sources/<name>/config.ini or
// spds/sources/<name>/config.ini
2008-03-30 17:15:00 +02:00
size_t endslash = prefix . rfind ( ' / ' ) ;
2008-03-30 18:13:08 +02:00
if ( endslash ! = line . npos & & endslash > 1 ) {
size_t slash = prefix . rfind ( ' / ' , endslash - 1 ) ;
if ( slash ! = line . npos ) {
string newsource = prefix . substr ( slash + 1 , endslash - slash - 1 ) ;
if ( newsource ! = section & &
2009-11-24 15:02:21 +01:00
prefix . find ( " /sources/ " ) ! = prefix . npos & &
2008-03-30 18:13:08 +02:00
newsource ! = " syncml " ) {
2009-11-24 15:02:21 +01:00
res < < " [ " < < newsource < < " ] " < < endl ;
2008-03-30 18:13:08 +02:00
section = newsource ;
}
2008-03-30 13:43:36 +02:00
}
}
string assignment = line . substr ( colon + 1 ) ;
// substitude aliases with generic values
boost : : replace_first ( assignment , " = F " , " = 0 " ) ;
boost : : replace_first ( assignment , " = T " , " = 1 " ) ;
2009-06-10 14:27:16 +02:00
boost : : replace_first ( assignment , " = syncml:auth-md5 " , " = md5 " ) ;
boost : : replace_first ( assignment , " = syncml:auth-basix " , " = basic " ) ;
2008-03-30 13:43:36 +02:00
res < < assignment < < endl ;
}
return res . str ( ) ;
}
2008-03-29 18:04:26 +01:00
2008-03-28 23:32:00 +01:00
/**
* Testing is based on a text representation of a directory
* hierarchy where each line is of the format
* < file path > : < line in file >
*
* The order of files is alphabetical , of lines in the file as
* in the file . Lines in the file without line break cannot
* be represented .
*
* The root of the hierarchy is not part of the representation
* itself .
*/
2009-10-05 14:49:32 +02:00
class CmdlineTest : public CppUnit : : TestFixture {
CPPUNIT_TEST_SUITE ( CmdlineTest ) ;
2008-03-28 23:32:00 +01:00
CPPUNIT_TEST ( testFramework ) ;
2008-03-29 15:16:34 +01:00
CPPUNIT_TEST ( testSetupScheduleWorld ) ;
2008-03-29 18:26:23 +01:00
CPPUNIT_TEST ( testSetupDefault ) ;
CPPUNIT_TEST ( testSetupRenamed ) ;
2008-03-29 18:04:26 +01:00
CPPUNIT_TEST ( testSetupFunambol ) ;
CPPUNIT_TEST ( testSetupSynthesis ) ;
2008-03-29 18:26:23 +01:00
CPPUNIT_TEST ( testPrintServers ) ;
2008-03-30 13:43:36 +02:00
CPPUNIT_TEST ( testPrintConfig ) ;
2009-12-01 16:36:33 +01:00
CPPUNIT_TEST ( testPrintFileTemplates ) ;
2010-05-03 21:41:36 +02:00
CPPUNIT_TEST ( testPrintFileTemplatesConfig ) ;
2008-03-29 18:04:26 +01:00
CPPUNIT_TEST ( testTemplate ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
CPPUNIT_TEST ( testMatchTemplate ) ;
2009-12-03 16:01:32 +01:00
CPPUNIT_TEST ( testAddSource ) ;
2008-03-30 11:02:07 +02:00
CPPUNIT_TEST ( testSync ) ;
2008-03-30 15:41:56 +02:00
CPPUNIT_TEST ( testConfigure ) ;
2008-03-30 18:13:08 +02:00
CPPUNIT_TEST ( testOldConfigure ) ;
2008-03-30 17:15:00 +02:00
CPPUNIT_TEST ( testListSources ) ;
CPPUNIT_TEST ( testMigrate ) ;
2008-03-28 23:32:00 +01:00
CPPUNIT_TEST_SUITE_END ( ) ;
2008-03-29 15:16:34 +01:00
public :
2009-10-05 14:49:32 +02:00
CmdlineTest ( ) :
m_testDir ( " CmdlineTest " ) ,
2009-11-24 15:02:21 +01:00
// properties sorted by the order in which they are defined
// in the sync and sync source property registry
m_scheduleWorldConfig ( " peers/scheduleworld/.internal.ini:# HashCode = 0 \n "
" peers/scheduleworld/.internal.ini:# ConfigDate = \n "
" peers/scheduleworld/.internal.ini:# lastNonce = \n "
" peers/scheduleworld/.internal.ini:# deviceData = \n "
" peers/scheduleworld/config.ini:syncURL = http://sync.scheduleworld.com/funambol/ds \n "
" peers/scheduleworld/config.ini:username = your SyncML server account name \n "
" peers/scheduleworld/config.ini:password = your SyncML server password \n "
2008-03-30 23:50:51 +02:00
" config.ini:# logdir = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/config.ini:# loglevel = 0 \n "
" peers/scheduleworld/config.ini:# printChanges = 1 \n "
2009-04-16 17:22:31 +02:00
" config.ini:# maxlogdirs = 10 \n "
2010-03-02 06:34:42 +01:00
" peers/scheduleworld/config.ini:# autoSync = 0 \n "
2010-03-22 17:45:03 +01:00
" peers/scheduleworld/config.ini:# autoSyncInterval = 30M \n "
" peers/scheduleworld/config.ini:# autoSyncDelay = 5M \n "
2010-02-25 17:59:51 +01:00
" peers/scheduleworld/config.ini:# preventSlowSync = 1 \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/config.ini:# useProxy = 0 \n "
" peers/scheduleworld/config.ini:# proxyHost = \n "
" peers/scheduleworld/config.ini:# proxyUsername = \n "
" peers/scheduleworld/config.ini:# proxyPassword = \n "
" peers/scheduleworld/config.ini:# clientAuthType = md5 \n "
2010-03-22 17:45:03 +01:00
" peers/scheduleworld/config.ini:# RetryDuration = 5M \n "
2010-04-19 13:56:07 +02:00
" peers/scheduleworld/config.ini:# RetryInterval = 2M \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/config.ini:# remoteIdentifier = \n "
" peers/scheduleworld/config.ini:# PeerIsClient = 0 \n "
2010-02-26 11:20:52 +01:00
" peers/scheduleworld/config.ini:# SyncMLVersion = \n "
2010-01-13 18:05:45 +01:00
" peers/scheduleworld/config.ini:# PeerName = \n "
2008-03-30 20:39:15 +02:00
" config.ini:deviceId = fixed-devid \n " /* this is not the default! */
2009-11-27 19:47:47 +01:00
" peers/scheduleworld/config.ini:# remoteDeviceId = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/config.ini:# enableWBXML = 1 \n "
2010-02-25 17:59:51 +01:00
" peers/scheduleworld/config.ini:# maxMsgSize = 150000 \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/config.ini:# maxObjSize = 4000000 \n "
" peers/scheduleworld/config.ini:# enableCompression = 0 \n "
" peers/scheduleworld/config.ini:# SSLServerCertificates = \n "
" peers/scheduleworld/config.ini:# SSLVerifyServer = 1 \n "
" peers/scheduleworld/config.ini:# SSLVerifyHost = 1 \n "
2010-01-19 16:01:10 +01:00
" peers/scheduleworld/config.ini:WebURL = http://www.scheduleworld.com \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/config.ini:# IconURI = \n "
" peers/scheduleworld/config.ini:ConsumerReady = 1 \n "
" peers/scheduleworld/sources/addressbook/.internal.ini:# adminData = \n "
2010-02-15 16:50:06 +01:00
" peers/scheduleworld/sources/addressbook/.internal.ini:# synthesisID = 0 \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/addressbook/config.ini:sync = two-way \n "
2008-07-12 21:45:50 +02:00
" sources/addressbook/config.ini:type = addressbook:text/vcard \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/addressbook/config.ini:type = addressbook:text/vcard \n "
2008-03-30 23:50:51 +02:00
" sources/addressbook/config.ini:# evolutionsource = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/addressbook/config.ini:uri = card3 \n "
2008-03-30 23:50:51 +02:00
" sources/addressbook/config.ini:# evolutionuser = \n "
" sources/addressbook/config.ini:# evolutionpassword = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/calendar/.internal.ini:# adminData = \n "
2010-02-15 16:50:06 +01:00
" peers/scheduleworld/sources/calendar/.internal.ini:# synthesisID = 0 \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/calendar/config.ini:sync = two-way \n "
2008-03-30 17:15:00 +02:00
" sources/calendar/config.ini:type = calendar \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/calendar/config.ini:type = calendar \n "
2008-03-30 23:50:51 +02:00
" sources/calendar/config.ini:# evolutionsource = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/calendar/config.ini:uri = cal2 \n "
2008-03-30 23:50:51 +02:00
" sources/calendar/config.ini:# evolutionuser = \n "
" sources/calendar/config.ini:# evolutionpassword = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/memo/.internal.ini:# adminData = \n "
2010-02-15 16:50:06 +01:00
" peers/scheduleworld/sources/memo/.internal.ini:# synthesisID = 0 \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/memo/config.ini:sync = two-way \n "
2008-03-30 17:15:00 +02:00
" sources/memo/config.ini:type = memo \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/memo/config.ini:type = memo \n "
2008-03-30 23:50:51 +02:00
" sources/memo/config.ini:# evolutionsource = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/memo/config.ini:uri = note \n "
2008-03-30 23:50:51 +02:00
" sources/memo/config.ini:# evolutionuser = \n "
" sources/memo/config.ini:# evolutionpassword = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/todo/.internal.ini:# adminData = \n "
2010-02-15 16:50:06 +01:00
" peers/scheduleworld/sources/todo/.internal.ini:# synthesisID = 0 \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/todo/config.ini:sync = two-way \n "
2008-03-30 17:15:00 +02:00
" sources/todo/config.ini:type = todo \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/todo/config.ini:type = todo \n "
2008-03-30 23:50:51 +02:00
" sources/todo/config.ini:# evolutionsource = \n "
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/todo/config.ini:uri = task2 \n "
2008-03-30 23:50:51 +02:00
" sources/todo/config.ini:# evolutionuser = \n "
2009-11-24 15:02:21 +01:00
" sources/todo/config.ini:# evolutionpassword = " )
2009-07-17 16:21:25 +02:00
{
# ifdef ENABLE_LIBSOUP
// path to SSL certificates has to be set only for libsoup
boost : : replace_first ( m_scheduleWorldConfig ,
" SSLServerCertificates = " ,
" SSLServerCertificates = /etc/ssl/certs/ca-certificates.crt:/etc/pki/tls/certs/ca-bundle.crt:/usr/share/ssl/certs/ca-bundle.crt " ) ;
# endif
}
2008-03-28 23:32:00 +01:00
protected :
2008-03-29 15:16:34 +01:00
/** verify that createFiles/scanFiles themselves work */
2008-03-28 23:32:00 +01:00
void testFramework ( ) {
2008-03-29 15:16:34 +01:00
const string root ( m_testDir ) ;
2008-03-28 23:32:00 +01:00
const string content ( " baz:line \n "
2008-03-29 15:16:34 +01:00
" caz/subdir:booh \n "
2008-03-30 23:50:51 +02:00
" caz/subdir2/sub:# comment \n "
" caz/subdir2/sub:# foo = bar \n "
" caz/subdir2/sub:# empty = \n "
" caz/subdir2/sub:# another comment \n "
2008-03-28 23:32:00 +01:00
" foo:bar1 \n "
2008-03-30 23:50:51 +02:00
" foo: \n "
" foo: \n "
2008-03-28 23:32:00 +01:00
" foo:bar2 \n " ) ;
2008-03-30 23:50:51 +02:00
const string filtered ( " baz:line \n "
" caz/subdir:booh \n "
" caz/subdir2/sub:# foo = bar \n "
" caz/subdir2/sub:# empty = \n "
" foo:bar1 \n "
" foo: \n "
" foo:bar2 \n " ) ;
2008-03-28 23:32:00 +01:00
createFiles ( root , content ) ;
string res = scanFiles ( root ) ;
2008-03-30 23:50:51 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( filtered , res ) ;
2008-03-28 23:32:00 +01:00
}
2008-03-30 20:02:32 +02:00
void removeRandomUUID ( string & buffer ) {
2010-02-25 17:59:51 +01:00
string uuidstr = " deviceId = syncevolution- " ;
2008-03-30 20:02:32 +02:00
size_t uuid = buffer . find ( uuidstr ) ;
CPPUNIT_ASSERT ( uuid ! = buffer . npos ) ;
size_t end = buffer . find ( " \n " , uuid + uuidstr . size ( ) ) ;
CPPUNIT_ASSERT ( end ! = buffer . npos ) ;
buffer . replace ( uuid , end - uuid , " deviceId = fixed-devid " ) ;
}
2008-03-29 18:04:26 +01:00
/** create new configurations */
2009-11-24 15:02:21 +01:00
void testSetupScheduleWorld ( ) { doSetupScheduleWorld ( false ) ; }
void doSetupScheduleWorld ( bool shared ) {
2008-03-29 18:04:26 +01:00
string root ;
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-29 15:16:34 +01:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
2008-03-29 18:04:26 +01:00
root = m_testDir ;
2009-11-24 15:02:21 +01:00
root + = " /syncevolution/default " ;
string peer ;
if ( shared ) {
peer = root + " /peers/scheduleworld " ;
} else {
peer = root ;
}
2008-03-30 15:11:45 +02:00
{
2009-11-24 15:02:21 +01:00
rm_r ( peer ) ;
2008-03-30 15:11:45 +02:00
TestCmdline cmdline ( " --configure " ,
" --sync-property " , " proxyHost = proxy " ,
" scheduleworld " ,
" addressbook " ,
NULL ) ;
cmdline . doit ( ) ;
string res = scanFiles ( root ) ;
2008-03-30 20:02:32 +02:00
removeRandomUUID ( res ) ;
2009-04-07 20:33:18 +02:00
string expected = ScheduleWorldConfig ( ) ;
2009-11-24 15:02:21 +01:00
sortConfig ( expected ) ;
2008-03-30 15:11:45 +02:00
boost : : replace_first ( expected ,
2008-03-30 23:50:51 +02:00
" # proxyHost = " ,
2008-03-30 15:11:45 +02:00
" proxyHost = proxy " ) ;
boost : : replace_all ( expected ,
" sync = two-way " ,
" sync = disabled " ) ;
boost : : replace_first ( expected ,
" addressbook/config.ini:sync = disabled " ,
" addressbook/config.ini:sync = two-way " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
}
{
2009-11-24 15:02:21 +01:00
rm_r ( peer ) ;
2008-03-30 15:11:45 +02:00
TestCmdline cmdline ( " --configure " ,
2008-03-30 20:02:32 +02:00
" --sync-property " , " deviceID = fixed-devid " ,
2008-03-30 15:11:45 +02:00
" scheduleworld " ,
NULL ) ;
cmdline . doit ( ) ;
string res = scanFiles ( root ) ;
2009-11-24 15:02:21 +01:00
string expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
2008-03-30 15:11:45 +02:00
}
2008-03-29 15:16:34 +01:00
}
2008-03-30 23:50:51 +02:00
2008-03-29 18:26:23 +01:00
void testSetupDefault ( ) {
string root ;
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-29 18:26:23 +01:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
root = m_testDir ;
2009-11-24 15:02:21 +01:00
root + = " /syncevolution/default " ;
2008-03-29 18:26:23 +01:00
rm_r ( root ) ;
TestCmdline cmdline ( " --configure " ,
" --template " , " default " ,
2008-03-30 20:02:32 +02:00
" --sync-property " , " deviceID = fixed-devid " ,
2008-03-29 18:26:23 +01:00
" some-other-server " ,
NULL ) ;
cmdline . doit ( ) ;
2009-11-24 15:02:21 +01:00
string res = scanFiles ( root , " some-other-server " ) ;
string expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
boost : : replace_all ( expected , " /scheduleworld/ " , " /some-other-server/ " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
2008-03-29 18:26:23 +01:00
}
void testSetupRenamed ( ) {
string root ;
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-29 18:26:23 +01:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
root = m_testDir ;
2009-11-24 15:02:21 +01:00
root + = " /syncevolution/default " ;
2008-03-29 18:26:23 +01:00
rm_r ( root ) ;
TestCmdline cmdline ( " --configure " ,
" --template " , " scheduleworld " ,
2008-03-30 20:02:32 +02:00
" --sync-property " , " deviceID = fixed-devid " ,
2008-03-29 18:26:23 +01:00
" scheduleworld2 " ,
NULL ) ;
cmdline . doit ( ) ;
2009-11-24 15:02:21 +01:00
string res = scanFiles ( root , " scheduleworld2 " ) ;
string expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
boost : : replace_all ( expected , " /scheduleworld/ " , " /scheduleworld2/ " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
2008-03-29 18:26:23 +01:00
}
2009-11-24 15:02:21 +01:00
void testSetupFunambol ( ) { doSetupFunambol ( false ) ; }
void doSetupFunambol ( bool shared ) {
2008-03-29 18:04:26 +01:00
string root ;
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-29 18:04:26 +01:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
root = m_testDir ;
2009-11-24 15:02:21 +01:00
root + = " /syncevolution/default " ;
string peer ;
if ( shared ) {
peer = root + " /peers/funambol " ;
} else {
peer = root ;
}
rm_r ( peer ) ;
2009-11-24 19:26:58 +01:00
const char * const argv_fixed [ ] = {
" --configure " ,
" --sync-property " , " deviceID = fixed-devid " ,
// templates are case-insensitive
" FunamBOL " ,
NULL
} , * const argv_shared [ ] = {
" --configure " ,
" FunamBOL " ,
NULL
} ;
TestCmdline cmdline ( shared ? argv_shared : argv_fixed ) ;
2008-03-29 18:04:26 +01:00
cmdline . doit ( ) ;
2009-11-24 15:02:21 +01:00
string res = scanFiles ( root , " funambol " ) ;
string expected = FunambolConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
2008-03-29 18:04:26 +01:00
}
2009-11-24 15:02:21 +01:00
void testSetupSynthesis ( ) { doSetupSynthesis ( false ) ; }
void doSetupSynthesis ( bool shared ) {
2008-03-29 18:04:26 +01:00
string root ;
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-29 18:04:26 +01:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
root = m_testDir ;
2009-11-24 15:02:21 +01:00
root + = " /syncevolution/default " ;
string peer ;
if ( shared ) {
peer = root + " /peers/synthesis " ;
} else {
peer = root ;
}
rm_r ( peer ) ;
2009-11-24 19:26:58 +01:00
const char * const argv_fixed [ ] = {
" --configure " ,
" --sync-property " , " deviceID = fixed-devid " ,
" synthesis " ,
NULL
} , * const argv_shared [ ] = {
" --configure " ,
" synthesis " ,
NULL
} ;
TestCmdline cmdline ( shared ? argv_shared : argv_fixed ) ;
2008-03-29 18:04:26 +01:00
cmdline . doit ( ) ;
2009-11-24 15:02:21 +01:00
string res = scanFiles ( root , " synthesis " ) ;
string expected = SynthesisConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
2008-03-29 18:04:26 +01:00
}
void testTemplate ( ) {
TestCmdline failure ( " --template " , NULL ) ;
CPPUNIT_ASSERT ( ! failure . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , failure . m_out . str ( ) ) ;
2008-03-30 13:43:36 +02:00
CPPUNIT_ASSERT_EQUAL ( string ( " ERROR: missing parameter for '--template' \n " ) , lastLine ( failure . m_err . str ( ) ) ) ;
2008-03-29 18:04:26 +01:00
2008-03-30 15:11:45 +02:00
TestCmdline help ( " --template " , " ? " , NULL ) ;
2008-03-29 18:04:26 +01:00
help . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " Available configuration templates: \n "
2010-03-03 09:24:58 +01:00
" template name = template description \n "
2009-04-08 16:32:05 +02:00
" Funambol = http://my.funambol.com \n "
2009-06-18 15:25:53 +02:00
" Google = http://m.google.com/sync \n "
2010-01-18 10:07:18 +01:00
" Goosync = http://www.goosync.com/ \n "
2009-04-08 16:32:05 +02:00
" Memotoo = http://www.memotoo.com \n "
2009-08-07 09:11:43 +02:00
" Mobical = http://www.mobical.net \n "
2009-10-29 16:13:31 +01:00
" Oracle = http://www.oracle.com/technology/products/beehive/index.html \n "
2010-02-09 04:03:20 +01:00
" Ovi = http://www.ovi.com \n "
2010-01-18 21:58:31 +01:00
" ScheduleWorld = http://www.scheduleworld.com \n "
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
" SyncEvolution = http://www.syncevolution.org \n "
2009-07-18 16:40:29 +02:00
" Synthesis = http://www.synthesis.ch \n "
" ZYB = http://www.zyb.com \n " ,
2008-03-29 18:04:26 +01:00
help . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , help . m_err . str ( ) ) ;
}
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
void testMatchTemplate ( ) {
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " testcases/templates " ) ;
2010-05-03 21:41:36 +02:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , " /dev/null " ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
2010-03-19 06:19:53 +01:00
TestCmdline help1 ( " --template " , " ?nokia 7210c " , NULL ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
help1 . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " Available configuration templates: \n "
2010-03-04 03:26:03 +01:00
" template name = template description matching score in percent (100% = exact match) \n "
2010-03-24 10:23:20 +01:00
" Nokia 7210c = Template for Nokia S40 series Phone 100% \n "
2010-03-19 06:19:53 +01:00
" SyncEvolution Client = SyncEvolution server side template 40% \n " ,
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
help1 . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , help1 . m_err . str ( ) ) ;
TestCmdline help2 ( " --template " , " ?nokia " , NULL ) ;
help2 . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " Available configuration templates: \n "
2010-03-04 03:26:03 +01:00
" template name = template description matching score in percent (100% = exact match) \n "
2010-03-24 10:23:20 +01:00
" Nokia 7210c = Template for Nokia S40 series Phone 100% \n "
2010-03-19 06:19:53 +01:00
" SyncEvolution Client = SyncEvolution server side template 40% \n " ,
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
help2 . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , help2 . m_err . str ( ) ) ;
TestCmdline help3 ( " --template " , " ?7210c " , NULL ) ;
help3 . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " Available configuration templates: \n "
2010-03-04 03:26:03 +01:00
" template name = template description matching score in percent (100% = exact match) \n "
2010-03-24 10:23:20 +01:00
" Nokia 7210c = Template for Nokia S40 series Phone 60% \n "
2010-03-19 06:19:53 +01:00
" SyncEvolution Client = SyncEvolution server side template 20% \n " ,
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
help3 . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , help3 . m_err . str ( ) ) ;
2010-03-19 06:19:53 +01:00
TestCmdline help4 ( " --template " , " ?syncevolution client " , NULL ) ;
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
help4 . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " Available configuration templates: \n "
2010-03-04 03:26:03 +01:00
" template name = template description matching score in percent (100% = exact match) \n "
2010-03-19 06:19:53 +01:00
" SyncEvolution Client = SyncEvolution server side template 100% \n "
2010-03-24 10:23:20 +01:00
" Nokia 7210c = Template for Nokia S40 series Phone 40% \n " ,
Configuration templates matching: match templates based on metadata
Introduced TemplateConfig to abstracting the template configuration structure,
the template metadata used for matching is also parsed here.
The fields introduced in the metadata are:
PeerIsClient: identify whether this is a server side configuration or a client
side configuration.
Fingerprint: the matching string for this template, it is a comma separated string
with each string modeled as: "Manufacture_Model". The first substring is also
used as the name to identify this template so that user can select the template
by this name.
eg:
Nokia 7210c: Nokia_7210c
SyncEvolution server: SyncEvolutionServer, SyncEvolution
ScheduleWorld: ScheduleWorld,default
SyncEvolution client: SyncEvolutionClient, SyncEvolution
Description: this is a just a descriptive string not used for matching.
GetServerTemplates is changed to add another "devices" parameter to identify
it is asking for templates for a list of "devices". Each device is a tuple
<matchstring (devicename), matchMode (server/client/all)>.
TemplateList as the return type, which is a list of class TemplateDescription
so that we can also return enough information for corresponding templates. This
list is sorted by the 3-tuple <finger, rank, name>.
Add MatchServerTemplates method which will iterating all templates inside the
folder and match against the input parameter and finally return a sorted
list of matched templates.
The atcually fuzzy match algorithm is based on a LCS (added in the following
commit).
Cmdline interface is changed accordingly:
--template ? is changed to --template ?[string], so that user use the former
case to match all templates for a tradiontial SyncML client and the latter case
to match templates related to an input string.
SyncConfig API is also renamed (Server -> Peer) because both server/client
configuration/template are handled.
The original configuration template (Funambol and ScheduleWorld) has been moved
to the new template structure (under servers), they also have a .template.ini
file added so that they can be matched and picked up. All templates for
supported servers still have built-in template support in the code as before.
Templates for SyncEvolution based server is also added.
Server side templates are added (Nokia default, Nokia_7210c and SyncEvolutionServer).
Add unit test for the new template match use case.
2010-01-19 08:01:05 +01:00
help4 . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , help4 . m_err . str ( ) ) ;
}
2008-03-29 18:26:23 +01:00
void testPrintServers ( ) {
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-29 18:26:23 +01:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
rm_r ( m_testDir ) ;
2009-11-24 15:02:21 +01:00
doSetupScheduleWorld ( false ) ;
doSetupSynthesis ( true ) ;
doSetupFunambol ( true ) ;
2008-03-29 18:26:23 +01:00
TestCmdline cmdline ( " --print-servers " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " Configured servers: \n "
2009-11-24 15:02:21 +01:00
" funambol = CmdlineTest/syncevolution/default/peers/funambol \n "
" scheduleworld = CmdlineTest/syncevolution/default/peers/scheduleworld \n "
" synthesis = CmdlineTest/syncevolution/default/peers/synthesis \n " ,
2008-03-29 18:26:23 +01:00
cmdline . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
}
2008-03-30 13:43:36 +02:00
void testPrintConfig ( ) {
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-30 13:43:36 +02:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
rm_r ( m_testDir ) ;
testSetupFunambol ( ) ;
{
TestCmdline failure ( " --print-config " , NULL ) ;
CPPUNIT_ASSERT ( failure . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT ( ! failure . m_cmdline - > run ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , failure . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL ( string ( " ERROR: --print-config requires either a --template or a server name. \n " ) ,
lastLine ( failure . m_err . str ( ) ) ) ;
}
{
TestCmdline failure ( " --print-config " , " foo " , NULL ) ;
CPPUNIT_ASSERT ( failure . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT ( ! failure . m_cmdline - > run ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , failure . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL ( string ( " ERROR: server 'foo' has not been configured yet. \n " ) ,
lastLine ( failure . m_err . str ( ) ) ) ;
}
{
TestCmdline failure ( " --print-config " , " --template " , " foo " , NULL ) ;
CPPUNIT_ASSERT ( failure . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT ( ! failure . m_cmdline - > run ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , failure . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL ( string ( " ERROR: no configuration template for 'foo' available. \n " ) ,
lastLine ( failure . m_err . str ( ) ) ) ;
}
{
TestCmdline cmdline ( " --print-config " , " --template " , " scheduleworld " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
string actual = cmdline . m_out . str ( ) ;
2009-11-24 19:26:58 +01:00
// deviceId must be the one from Funambol
CPPUNIT_ASSERT ( boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
2009-11-19 16:30:46 +01:00
string filtered = injectValues ( filterConfig ( actual ) ) ;
2009-04-07 20:33:18 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ,
2008-03-30 13:43:36 +02:00
filtered ) ;
// there should have been comments
CPPUNIT_ASSERT ( actual . size ( ) > filtered . size ( ) ) ;
}
2010-03-02 21:28:28 +01:00
{
TestCmdline cmdline ( " --print-config " , " --template " , " scheduleworld@nosuchcontext " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
string actual = cmdline . m_out . str ( ) ;
// deviceId must *not* be the one from Funambol because of the new context
CPPUNIT_ASSERT ( ! boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
}
2008-03-30 13:43:36 +02:00
{
2009-04-08 16:32:05 +02:00
TestCmdline cmdline ( " --print-config " , " --template " , " Default " , NULL ) ;
2008-03-30 13:43:36 +02:00
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
2009-11-19 16:30:46 +01:00
string actual = injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ;
2009-11-24 19:26:58 +01:00
CPPUNIT_ASSERT ( boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
2009-04-07 20:33:18 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ,
2008-03-30 20:02:32 +02:00
actual ) ;
2008-03-30 13:43:36 +02:00
}
{
TestCmdline cmdline ( " --print-config " , " funambol " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( filterConfig ( internalToIni ( FunambolConfig ( ) ) ) ,
2009-11-19 16:30:46 +01:00
injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ) ;
2008-03-30 13:43:36 +02:00
}
{
2009-11-24 19:26:58 +01:00
// override context and template properties
2008-03-30 13:43:36 +02:00
TestCmdline cmdline ( " --print-config " , " --template " , " scheduleworld " ,
" --sync-property " , " syncURL=foo " ,
2009-11-24 19:26:58 +01:00
" --source-property " , " evolutionsource=Personal " ,
2008-03-30 13:43:36 +02:00
" --source-property " , " sync=disabled " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
2009-04-07 20:33:18 +02:00
string expected = filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( expected ,
2008-06-28 15:27:07 +02:00
" syncURL = http://sync.scheduleworld.com/funambol/ds " ,
2008-03-30 13:43:36 +02:00
" syncURL = foo " ) ;
2009-11-24 19:26:58 +01:00
boost : : replace_all ( expected ,
" # evolutionsource = " ,
" evolutionsource = Personal " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_all ( expected ,
" sync = two-way " ,
" sync = disabled " ) ;
2009-11-19 16:30:46 +01:00
string actual = injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ;
2009-11-24 19:26:58 +01:00
CPPUNIT_ASSERT ( boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
2008-03-30 13:43:36 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
2008-03-30 20:02:32 +02:00
actual ) ;
2008-03-30 13:43:36 +02:00
}
{
TestCmdline cmdline ( " --print-config " , " --quiet " ,
" --template " , " scheduleworld " ,
" funambol " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
2008-03-30 20:02:32 +02:00
string actual = cmdline . m_out . str ( ) ;
2009-11-24 19:26:58 +01:00
CPPUNIT_ASSERT ( boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
2009-04-07 20:33:18 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( internalToIni ( ScheduleWorldConfig ( ) ) ,
2009-11-24 15:02:21 +01:00
injectValues ( filterConfig ( actual ) ) ) ;
2008-03-30 13:43:36 +02:00
}
2009-11-24 19:26:58 +01:00
{
// change shared source properties, then check template again
TestCmdline cmdline ( " --configure " ,
" --source-property " , " evolutionsource=Personal " ,
" funambol " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
}
{
TestCmdline cmdline ( " --print-config " , " --quiet " ,
" --template " , " scheduleworld " ,
" funambol " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
string expected = filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ;
// from modified Funambol config
boost : : replace_all ( expected ,
" # evolutionsource = " ,
" evolutionsource = Personal " ) ;
string actual = injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ;
CPPUNIT_ASSERT ( boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
actual ) ;
}
2010-03-02 21:28:28 +01:00
{
// print config => must not use settings from default context
TestCmdline cmdline ( " --print-config " , " --template " , " scheduleworld@nosuchcontext " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
// source settings *not* from modified Funambol config
string expected = filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ;
string actual = injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ;
CPPUNIT_ASSERT ( ! boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
removeRandomUUID ( actual ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
actual ) ;
}
{
// create config => again, must not use settings from default context
TestCmdline cmdline ( " --configure " , " --template " , " scheduleworld " , " other@other " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
}
{
TestCmdline cmdline ( " --print-config " , " other@other " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
// source settings *not* from modified Funambol config
string expected = filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ;
string actual = injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ;
CPPUNIT_ASSERT ( ! boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
removeRandomUUID ( actual ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
actual ) ;
}
2008-03-30 13:43:36 +02:00
}
2009-12-01 16:36:33 +01:00
void testPrintFileTemplates ( ) {
2010-05-03 21:41:36 +02:00
rm_r ( m_testDir ) ;
2009-12-01 16:36:33 +01:00
// use local copy of templates in build dir (no need to install)
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " ./templates " ) ;
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
2010-05-03 21:41:36 +02:00
doPrintFileTemplates ( ) ;
}
void testPrintFileTemplatesConfig ( ) {
2009-12-01 16:36:33 +01:00
rm_r ( m_testDir ) ;
2010-05-03 21:41:36 +02:00
mkdir_p ( m_testDir ) ;
symlink ( " ../templates " , ( m_testDir + " /syncevolution-templates " ) . c_str ( ) ) ;
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
doPrintFileTemplates ( ) ;
}
void doPrintFileTemplates ( ) {
2009-12-01 16:36:33 +01:00
testSetupFunambol ( ) ;
{
TestCmdline cmdline ( " --print-config " , " --template " , " scheduleworld " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
string actual = cmdline . m_out . str ( ) ;
// deviceId must be the one from Funambol
CPPUNIT_ASSERT ( boost : : contains ( actual , " deviceId = fixed-devid " ) ) ;
string filtered = injectValues ( filterConfig ( actual ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( filterConfig ( internalToIni ( ScheduleWorldConfig ( ) ) ) ,
filtered ) ;
// there should have been comments
CPPUNIT_ASSERT ( actual . size ( ) > filtered . size ( ) ) ;
}
{
TestCmdline cmdline ( " --print-config " , " funambol " , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( filterConfig ( internalToIni ( FunambolConfig ( ) ) ) ,
injectValues ( filterConfig ( cmdline . m_out . str ( ) ) ) ) ;
}
}
2009-12-03 16:01:32 +01:00
void testAddSource ( ) {
string root ;
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
testSetupScheduleWorld ( ) ;
root = m_testDir ;
root + = " /syncevolution/default " ;
{
TestCmdline cmdline ( " --configure " ,
" --source-property " , " uri = dummy " ,
" scheduleworld " ,
" xyz " ,
NULL ) ;
cmdline . doit ( ) ;
string res = scanFiles ( root ) ;
string expected = ScheduleWorldConfig ( ) ;
expected + = " \n "
" peers/scheduleworld/sources/xyz/.internal.ini:# adminData = \n "
2010-02-15 16:50:06 +01:00
" peers/scheduleworld/sources/xyz/.internal.ini:# synthesisID = 0 \n "
2010-01-29 21:16:00 +01:00
" peers/scheduleworld/sources/xyz/config.ini:# sync = disabled \n "
2009-12-03 16:01:32 +01:00
" peers/scheduleworld/sources/xyz/config.ini:# type = select backend \n "
" peers/scheduleworld/sources/xyz/config.ini:uri = dummy \n "
" sources/xyz/config.ini:# type = select backend \n "
" sources/xyz/config.ini:# evolutionsource = \n "
" sources/xyz/config.ini:# evolutionuser = \n "
" sources/xyz/config.ini:# evolutionpassword = " ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , res ) ;
}
}
2009-12-01 16:36:33 +01:00
2008-03-30 11:02:07 +02:00
void testSync ( ) {
TestCmdline failure ( " --sync " , NULL ) ;
CPPUNIT_ASSERT ( ! failure . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , failure . m_out . str ( ) ) ;
2008-03-30 13:43:36 +02:00
CPPUNIT_ASSERT_EQUAL ( string ( " ERROR: missing parameter for '--sync' \n " ) , lastLine ( failure . m_err . str ( ) ) ) ;
2008-03-30 11:02:07 +02:00
TestCmdline failure2 ( " --sync " , " foo " , NULL ) ;
CPPUNIT_ASSERT ( ! failure2 . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , failure2 . m_out . str ( ) ) ;
2008-03-30 13:43:36 +02:00
CPPUNIT_ASSERT_EQUAL ( string ( " ERROR: '--sync foo': not one of the valid values (two-way, slow, refresh-from-client = refresh-client, refresh-from-server = refresh-server = refresh, one-way-from-client = one-way-client, one-way-from-server = one-way-server = one-way, disabled = none) \n " ) , lastLine ( failure2 . m_err . str ( ) ) ) ;
2008-03-30 11:02:07 +02:00
2008-03-30 15:11:45 +02:00
TestCmdline help ( " --sync " , " ? " , NULL ) ;
2008-03-30 11:02:07 +02:00
help . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " --sync \n "
" requests a certain synchronization mode: \n "
" two-way = only send/receive changes since last sync \n "
" slow = exchange all items \n "
" refresh-from-client = discard all remote items and replace with \n "
" the items on the client \n "
" refresh-from-server = discard all local items and replace with \n "
" the items on the server \n "
" one-way-from-client = transmit changes from client \n "
" one-way-from-server = transmit changes from server \n "
2008-03-30 20:39:15 +02:00
" none (or disabled) = synchronization disabled \n " ,
2008-03-30 11:02:07 +02:00
help . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , help . m_err . str ( ) ) ;
TestCmdline filter ( " --sync " , " refresh-from-server " , NULL ) ;
CPPUNIT_ASSERT ( filter . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT ( ! filter . m_cmdline - > run ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , filter . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " sync = refresh-from-server " ,
string ( filter . m_cmdline - > m_sourceProps ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " ,
string ( filter . m_cmdline - > m_syncProps ) ) ;
TestCmdline filter2 ( " --source-property " , " sync=refresh " , NULL ) ;
CPPUNIT_ASSERT ( filter2 . m_cmdline - > parse ( ) ) ;
CPPUNIT_ASSERT ( ! filter2 . m_cmdline - > run ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , filter2 . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " sync = refresh " ,
string ( filter2 . m_cmdline - > m_sourceProps ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " ,
string ( filter2 . m_cmdline - > m_syncProps ) ) ;
}
2008-03-30 15:41:56 +02:00
void testConfigure ( ) {
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-30 15:41:56 +02:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
2008-03-30 17:15:00 +02:00
rm_r ( m_testDir ) ;
2008-03-30 15:41:56 +02:00
testSetupScheduleWorld ( ) ;
2010-03-02 16:30:10 +01:00
string expected = doConfigure ( ScheduleWorldConfig ( ) , " sources/addressbook/config.ini: " ) ;
{
// updating type for peer must also update type for context
TestCmdline cmdline ( " --configure " ,
" --source-property " , " type=file:text/vcard:3.0 " ,
" scheduleworld " , " addressbook " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
boost : : replace_all ( expected ,
" type = addressbook:text/vcard " ,
" type = file:text/vcard:3.0 " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
filterConfig ( printConfig ( " scheduleworld " ) ) ) ;
string shared = filterConfig ( printConfig ( " @default " ) ) ;
CPPUNIT_ASSERT ( shared . find ( " type = file:text/vcard:3.0 " ) ! = shared . npos ) ;
}
{
// updating type for context must not affect peer
TestCmdline cmdline ( " --configure " ,
" --source-property " , " type=file:text/vcard:2.1 " ,
" @default " , " addressbook " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
filterConfig ( printConfig ( " scheduleworld " ) ) ) ;
string shared = filterConfig ( printConfig ( " @default " ) ) ;
CPPUNIT_ASSERT ( shared . find ( " type = file:text/vcard:2.1 " ) ! = shared . npos ) ;
}
2008-03-30 15:41:56 +02:00
2008-03-30 17:15:00 +02:00
string syncProperties ( " syncURL: \n "
" \n "
" username: \n "
2008-04-03 22:01:56 +02:00
" \n "
2008-03-30 17:15:00 +02:00
" password: \n "
" \n "
" logdir: \n "
" \n "
" loglevel: \n "
" \n "
2009-04-21 11:22:32 +02:00
" printChanges: \n "
" \n "
2008-03-30 17:15:00 +02:00
" maxlogdirs: \n "
" \n "
2010-03-02 06:34:42 +01:00
" autoSync: \n "
" \n "
" autoSyncInterval: \n "
" \n "
" autoSyncDelay: \n "
" \n "
2010-01-26 17:56:02 +01:00
" preventSlowSync: \n "
" \n "
2008-03-30 17:15:00 +02:00
" useProxy: \n "
" \n "
" proxyHost: \n "
" \n "
" proxyUsername: \n "
2008-04-03 22:01:56 +02:00
" \n "
2008-03-30 17:15:00 +02:00
" proxyPassword: \n "
" \n "
" clientAuthType: \n "
" \n "
2009-09-23 15:16:42 +02:00
" RetryDuration: \n "
" \n "
" RetryInterval: \n "
" \n "
2009-11-19 16:33:33 +01:00
" remoteIdentifier: \n "
" \n "
" PeerIsClient: \n "
" \n "
2010-02-26 11:20:52 +01:00
" SyncMLVersion: \n "
" \n "
2010-01-13 18:05:45 +01:00
" PeerName: \n "
" \n "
2008-03-30 20:39:15 +02:00
" deviceId: \n "
" \n "
2009-11-27 19:47:47 +01:00
" remoteDeviceId: \n "
" \n "
2009-03-17 14:16:49 +01:00
" enableWBXML: \n "
" \n "
2008-03-30 17:15:00 +02:00
" maxMsgSize: \n "
" maxObjSize: \n "
" \n "
2008-04-16 22:33:38 +02:00
" enableCompression: \n "
" \n "
" SSLServerCertificates: \n "
" \n "
" SSLVerifyServer: \n "
" \n "
2009-04-07 20:33:18 +02:00
" SSLVerifyHost: \n "
" \n "
" WebURL: \n "
" \n "
2009-06-29 20:32:26 +02:00
" IconURI: \n "
" \n "
2009-11-13 17:25:30 +01:00
" ConsumerReady: \n "
" \n "
" defaultPeer: \n " ) ;
2008-03-30 17:15:00 +02:00
string sourceProperties ( " sync: \n "
" \n "
" type: \n "
" \n "
" evolutionsource: \n "
" \n "
" uri: \n "
" \n "
" evolutionuser: \n "
2009-03-17 14:16:49 +01:00
" evolutionpassword: \n " ) ;
2008-03-30 17:15:00 +02:00
{
TestCmdline cmdline ( " --sync-property " , " ? " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( syncProperties ,
filterIndented ( cmdline . m_out . str ( ) ) ) ;
}
{
TestCmdline cmdline ( " --source-property " , " ? " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( sourceProperties ,
filterIndented ( cmdline . m_out . str ( ) ) ) ;
}
{
TestCmdline cmdline ( " --source-property " , " ? " ,
" --sync-property " , " ? " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( sourceProperties + syncProperties ,
filterIndented ( cmdline . m_out . str ( ) ) ) ;
}
{
TestCmdline cmdline ( " --sync-property " , " ? " ,
" --source-property " , " ? " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( syncProperties + sourceProperties ,
filterIndented ( cmdline . m_out . str ( ) ) ) ;
}
2008-03-30 18:13:08 +02:00
}
void testOldConfigure ( ) {
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-30 18:13:08 +02:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
string oldConfig = OldScheduleWorldConfig ( ) ;
InitList < string > props = InitList < string > ( " serverNonce " ) +
" clientNonce " +
" devInfoHash " +
2009-06-25 10:55:22 +02:00
" HashCode " +
" ConfigDate " +
2009-11-12 21:19:03 +01:00
" deviceData " +
" adminData " +
2010-02-15 16:50:06 +01:00
" synthesisID " +
2009-11-12 21:19:03 +01:00
" lastNonce " +
2008-03-30 18:13:08 +02:00
" last " ;
BOOST_FOREACH ( string & prop , props ) {
boost : : replace_all ( oldConfig ,
prop + " = " ,
prop + " = internal value " ) ;
}
rm_r ( m_testDir ) ;
createFiles ( m_testDir + " /.sync4j/evolution/scheduleworld " , oldConfig ) ;
doConfigure ( oldConfig , " spds/sources/addressbook/config.txt: " ) ;
}
2008-03-30 17:15:00 +02:00
2010-03-02 16:30:10 +01:00
string doConfigure ( const string & SWConfig , const string & addressbookPrefix ) {
2008-03-30 15:41:56 +02:00
string expected ;
{
TestCmdline cmdline ( " --configure " ,
" --source-property " , " sync = disabled " ,
" scheduleworld " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
2008-03-30 18:13:08 +02:00
expected = filterConfig ( internalToIni ( SWConfig ) ) ;
2008-03-30 15:41:56 +02:00
boost : : replace_all ( expected ,
" sync = two-way " ,
" sync = disabled " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
filterConfig ( printConfig ( " scheduleworld " ) ) ) ;
}
{
TestCmdline cmdline ( " --configure " ,
" --source-property " , " sync = one-way-from-server " ,
" scheduleworld " ,
" addressbook " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
2008-03-30 18:13:08 +02:00
expected = SWConfig ;
2008-03-30 15:41:56 +02:00
boost : : replace_all ( expected ,
" sync = two-way " ,
" sync = disabled " ) ;
boost : : replace_first ( expected ,
2008-03-30 18:13:08 +02:00
addressbookPrefix + " sync = disabled " ,
addressbookPrefix + " sync = one-way-from-server " ) ;
2008-03-30 15:41:56 +02:00
expected = filterConfig ( internalToIni ( expected ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
filterConfig ( printConfig ( " scheduleworld " ) ) ) ;
}
{
TestCmdline cmdline ( " --configure " ,
" --sync " , " two-way " ,
2008-03-30 17:15:00 +02:00
" -z " , " evolutionsource=source " ,
2009-04-16 17:22:31 +02:00
" --sync-property " , " maxlogdirs=20 " ,
2008-03-30 17:15:00 +02:00
" -y " , " LOGDIR=logdir " ,
2008-03-30 15:41:56 +02:00
" scheduleworld " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
boost : : replace_all ( expected ,
" sync = one-way-from-server " ,
" sync = two-way " ) ;
boost : : replace_all ( expected ,
" sync = disabled " ,
" sync = two-way " ) ;
boost : : replace_all ( expected ,
2008-03-30 23:50:51 +02:00
" # evolutionsource = " ,
2008-03-30 15:41:56 +02:00
" evolutionsource = source " ) ;
boost : : replace_all ( expected ,
2009-04-16 17:22:31 +02:00
" # maxlogdirs = 10 " ,
" maxlogdirs = 20 " ) ;
2008-03-30 15:41:56 +02:00
boost : : replace_all ( expected ,
2008-03-30 23:50:51 +02:00
" # logdir = " ,
2008-03-30 15:41:56 +02:00
" logdir = logdir " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected ,
filterConfig ( printConfig ( " scheduleworld " ) ) ) ;
}
2010-03-02 16:30:10 +01:00
return expected ;
2008-03-30 15:41:56 +02:00
}
2008-03-30 17:15:00 +02:00
void testListSources ( ) {
2009-11-24 19:26:58 +01:00
// pick the varargs constructor; NULL alone is ambiguous
TestCmdline cmdline ( NULL , NULL ) ;
2008-03-30 17:15:00 +02:00
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
// exact output varies, do not test
}
void testMigrate ( ) {
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-30 17:15:00 +02:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
rm_r ( m_testDir ) ;
string oldRoot = m_testDir + " /.sync4j/evolution/scheduleworld " ;
2009-11-24 15:02:21 +01:00
string newRoot = m_testDir + " /syncevolution/default " ;
2008-03-30 17:15:00 +02:00
2008-03-30 18:13:08 +02:00
string oldConfig = OldScheduleWorldConfig ( ) ;
2008-03-30 17:15:00 +02:00
{
// migrate old config
createFiles ( oldRoot , oldConfig ) ;
string createdConfig = scanFiles ( oldRoot ) ;
TestCmdline cmdline ( " --migrate " ,
" scheduleworld " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
string migratedConfig = scanFiles ( newRoot ) ;
2009-11-24 15:02:21 +01:00
string expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , migratedConfig ) ;
2008-03-30 17:15:00 +02:00
string renamedConfig = scanFiles ( oldRoot + " .old " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( createdConfig , renamedConfig ) ;
}
{
2009-11-24 15:02:21 +01:00
// rewrite existing config with obsolete properties
// => these properties should get removed
//
// There is one limitation: shared nodes are not rewritten.
// This is acceptable.
createFiles ( newRoot + " /peers/scheduleworld " ,
2008-03-30 17:15:00 +02:00
" config.ini:# obsolete comment \n "
" config.ini:obsoleteprop = foo \n " ,
true ) ;
2009-11-24 15:02:21 +01:00
string createdConfig = scanFiles ( newRoot , " scheduleworld " ) ;
2008-03-30 17:15:00 +02:00
TestCmdline cmdline ( " --migrate " ,
" scheduleworld " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
2009-11-24 15:02:21 +01:00
string migratedConfig = scanFiles ( newRoot , " scheduleworld " ) ;
string expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , migratedConfig ) ;
string renamedConfig = scanFiles ( newRoot , " scheduleworld.old " ) ;
boost : : replace_all ( createdConfig , " /scheduleworld/ " , " /scheduleworld.old/ " ) ;
2008-03-30 17:15:00 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( createdConfig , renamedConfig ) ;
}
{
2009-11-25 15:30:07 +01:00
// migrate old config with changes and .synthesis directory, a second time
2008-03-30 17:15:00 +02:00
createFiles ( oldRoot , oldConfig ) ;
createFiles ( oldRoot ,
2009-11-25 15:30:07 +01:00
" .synthesis/dummy-file.bfi:dummy = foobar \n "
2008-03-30 17:15:00 +02:00
" spds/sources/addressbook/changes/config.txt:foo = bar \n "
" spds/sources/addressbook/changes/config.txt:foo2 = bar2 \n " ,
true ) ;
string createdConfig = scanFiles ( oldRoot ) ;
rm_r ( newRoot ) ;
TestCmdline cmdline ( " --migrate " ,
" scheduleworld " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
string migratedConfig = scanFiles ( newRoot ) ;
string expected = m_scheduleWorldConfig ;
2009-11-24 15:02:21 +01:00
sortConfig ( expected ) ;
2008-03-30 17:15:00 +02:00
boost : : replace_first ( expected ,
2009-11-24 15:02:21 +01:00
" peers/scheduleworld/sources/addressbook/config.ini " ,
" peers/scheduleworld/sources/addressbook/.other.ini:foo = bar \n "
" peers/scheduleworld/sources/addressbook/.other.ini:foo2 = bar2 \n "
" peers/scheduleworld/sources/addressbook/config.ini " ) ;
2009-11-25 15:30:07 +01:00
boost : : replace_first ( expected ,
" peers/scheduleworld/config.ini " ,
" peers/scheduleworld/.synthesis/dummy-file.bfi:dummy = foobar \n "
" peers/scheduleworld/config.ini " ) ;
2008-03-30 17:15:00 +02:00
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , migratedConfig ) ;
string renamedConfig = scanFiles ( oldRoot + " .old.1 " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( createdConfig , renamedConfig ) ;
}
2009-11-25 16:10:44 +01:00
{
string otherRoot = m_testDir + " /syncevolution/other " ;
rm_r ( otherRoot ) ;
// migrate old config into non-default context
createFiles ( oldRoot , oldConfig ) ;
string createdConfig = scanFiles ( oldRoot ) ;
{
TestCmdline cmdline ( " --migrate " ,
" scheduleworld@other " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
}
string migratedConfig = scanFiles ( otherRoot ) ;
string expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , migratedConfig ) ;
string renamedConfig = scanFiles ( oldRoot + " .old " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( createdConfig , renamedConfig ) ;
// migrate the migrated config again inside the "other" context
{
TestCmdline cmdline ( " --migrate " ,
" scheduleworld@other " ,
NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_out . str ( ) ) ;
}
migratedConfig = scanFiles ( otherRoot , " scheduleworld " ) ;
expected = ScheduleWorldConfig ( ) ;
sortConfig ( expected ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , migratedConfig ) ;
renamedConfig = scanFiles ( otherRoot , " scheduleworld.old " ) ;
boost : : replace_all ( expected , " /scheduleworld/ " , " /scheduleworld.old/ " ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( expected , renamedConfig ) ;
}
2008-03-30 17:15:00 +02:00
}
2008-03-29 15:16:34 +01:00
const string m_testDir ;
2009-07-17 16:21:25 +02:00
string m_scheduleWorldConfig ;
2008-03-29 15:16:34 +01:00
2008-03-28 23:32:00 +01:00
private :
2008-03-29 15:16:34 +01:00
/**
* vararg constructor with NULL termination ,
* out and error stream into stringstream members
*/
class TestCmdline {
2009-11-24 19:26:58 +01:00
void init ( ) {
m_argv . reset ( new const char * [ m_argvstr . size ( ) + 1 ] ) ;
m_argv [ 0 ] = " client-test " ;
for ( size_t index = 0 ;
index < m_argvstr . size ( ) ;
+ + index ) {
m_argv [ index + 1 ] = m_argvstr [ index ] . c_str ( ) ;
}
m_cmdline . set ( new Cmdline ( m_argvstr . size ( ) + 1 , m_argv . get ( ) , m_out , m_err ) , " cmdline " ) ;
}
2008-03-29 15:16:34 +01:00
public :
TestCmdline ( const char * arg , . . . ) {
va_list argList ;
va_start ( argList , arg ) ;
for ( const char * curr = arg ;
curr ;
curr = va_arg ( argList , const char * ) ) {
m_argvstr . push_back ( curr ) ;
}
va_end ( argList ) ;
2009-11-24 19:26:58 +01:00
init ( ) ;
}
2008-03-29 15:16:34 +01:00
2009-11-24 19:26:58 +01:00
TestCmdline ( const char * const argv [ ] ) {
for ( int i = 0 ; argv [ i ] ; i + + ) {
m_argvstr . push_back ( argv [ i ] ) ;
2008-03-29 15:16:34 +01:00
}
2009-11-24 19:26:58 +01:00
init ( ) ;
2008-03-29 15:16:34 +01:00
}
void doit ( ) {
bool success ;
success = m_cmdline - > parse ( ) & &
m_cmdline - > run ( ) ;
if ( m_err . str ( ) . size ( ) ) {
2010-03-26 09:53:27 +01:00
m_out < < endl < < m_err . str ( ) ;
2008-03-29 15:16:34 +01:00
}
CPPUNIT_ASSERT ( success ) ;
}
ostringstream m_out , m_err ;
2009-10-05 14:49:32 +02:00
cxxptr < Cmdline > m_cmdline ;
2008-03-29 15:16:34 +01:00
private :
vector < string > m_argvstr ;
boost : : scoped_array < const char * > m_argv ;
} ;
2008-03-30 18:13:08 +02:00
string ScheduleWorldConfig ( ) {
2009-04-07 20:33:18 +02:00
string config = m_scheduleWorldConfig ;
2009-12-01 16:36:33 +01:00
#if 0
// Currently we don't have an icon for ScheduleWorld. If we
// had (MB #2062) one, then this code would ensure that the
// reference config also has the right path for it.
const char * templateDir = getenv ( " SYNCEVOLUTION_TEMPLATE_DIR " ) ;
if ( ! templateDir ) {
templateDir = TEMPLATE_DIR ;
}
if ( isDir ( string ( templateDir ) + " /ScheduleWorld " ) ) {
2009-04-07 20:33:18 +02:00
boost : : replace_all ( config ,
" # IconURI = " ,
2009-12-01 16:36:33 +01:00
string ( " IconURI = file:// " ) + templateDir + " /ScheduleWorld/icon.png " ) ;
2009-04-07 20:33:18 +02:00
}
2009-12-01 16:36:33 +01:00
# endif
2009-04-07 20:33:18 +02:00
return config ;
2008-03-30 18:13:08 +02:00
}
string OldScheduleWorldConfig ( ) {
2009-11-24 15:02:21 +01:00
// old style paths
string oldConfig =
" spds/syncml/config.txt:syncURL = http://sync.scheduleworld.com/funambol/ds \n "
" spds/syncml/config.txt:username = your SyncML server account name \n "
" spds/syncml/config.txt:password = your SyncML server password \n "
" spds/syncml/config.txt:# logdir = \n "
" spds/syncml/config.txt:# loglevel = 0 \n "
" spds/syncml/config.txt:# printChanges = 1 \n "
" spds/syncml/config.txt:# maxlogdirs = 10 \n "
2010-03-02 06:34:42 +01:00
" spds/syncml/config.txt:# autoSync = 0 \n "
2010-03-22 17:45:03 +01:00
" spds/syncml/config.txt:# autoSyncInterval = 30M \n "
" spds/syncml/config.txt:# autoSyncDelay = 5M \n "
2010-02-25 17:59:51 +01:00
" spds/syncml/config.txt:# preventSlowSync = 1 \n "
2009-11-24 15:02:21 +01:00
" spds/syncml/config.txt:# useProxy = 0 \n "
" spds/syncml/config.txt:# proxyHost = \n "
" spds/syncml/config.txt:# proxyUsername = \n "
" spds/syncml/config.txt:# proxyPassword = \n "
" spds/syncml/config.txt:# clientAuthType = md5 \n "
2010-03-22 17:45:03 +01:00
" spds/syncml/config.txt:# RetryDuration = 5M \n "
2010-04-19 13:56:07 +02:00
" spds/syncml/config.txt:# RetryInterval = 2M \n "
2009-11-24 15:02:21 +01:00
" spds/syncml/config.txt:# remoteIdentifier = \n "
" spds/syncml/config.txt:# PeerIsClient = 0 \n "
2010-02-26 11:20:52 +01:00
" spds/syncml/config.txt:# SyncMLVersion = \n "
2010-01-13 18:05:45 +01:00
" spds/syncml/config.txt:# PeerName = \n "
2009-11-24 15:02:21 +01:00
" spds/syncml/config.txt:deviceId = fixed-devid \n " /* this is not the default! */
2009-11-27 19:47:47 +01:00
" spds/syncml/config.txt:# remoteDeviceId = \n "
2009-11-24 15:02:21 +01:00
" spds/syncml/config.txt:# enableWBXML = 1 \n "
2010-02-25 17:59:51 +01:00
" spds/syncml/config.txt:# maxMsgSize = 150000 \n "
2009-11-24 15:02:21 +01:00
" spds/syncml/config.txt:# maxObjSize = 4000000 \n "
" spds/syncml/config.txt:# enableCompression = 0 \n "
# ifdef ENABLE_LIBSOUP
// path to SSL certificates is only set for libsoup
" spds/syncml/config.txt:# SSLServerCertificates = /etc/ssl/certs/ca-certificates.crt:/etc/pki/tls/certs/ca-bundle.crt:/usr/share/ssl/certs/ca-bundle.crt \n "
# else
" spds/syncml/config.txt:# SSLServerCertificates = \n "
# endif
" spds/syncml/config.txt:# SSLVerifyServer = 1 \n "
" spds/syncml/config.txt:# SSLVerifyHost = 1 \n "
2010-01-19 19:17:31 +01:00
" spds/syncml/config.txt:WebURL = http://www.scheduleworld.com \n "
2009-11-24 15:02:21 +01:00
" spds/syncml/config.txt:# IconURI = \n "
" spds/syncml/config.txt:ConsumerReady = 1 \n "
" spds/sources/addressbook/config.txt:sync = two-way \n "
" spds/sources/addressbook/config.txt:type = addressbook:text/vcard \n "
" spds/sources/addressbook/config.txt:# evolutionsource = \n "
" spds/sources/addressbook/config.txt:uri = card3 \n "
" spds/sources/addressbook/config.txt:# evolutionuser = \n "
" spds/sources/addressbook/config.txt:# evolutionpassword = \n "
" spds/sources/calendar/config.txt:sync = two-way \n "
" spds/sources/calendar/config.txt:type = calendar \n "
" spds/sources/calendar/config.txt:# evolutionsource = \n "
" spds/sources/calendar/config.txt:uri = cal2 \n "
" spds/sources/calendar/config.txt:# evolutionuser = \n "
" spds/sources/calendar/config.txt:# evolutionpassword = \n "
" spds/sources/memo/config.txt:sync = two-way \n "
" spds/sources/memo/config.txt:type = memo \n "
" spds/sources/memo/config.txt:# evolutionsource = \n "
" spds/sources/memo/config.txt:uri = note \n "
" spds/sources/memo/config.txt:# evolutionuser = \n "
" spds/sources/memo/config.txt:# evolutionpassword = \n "
" spds/sources/todo/config.txt:sync = two-way \n "
" spds/sources/todo/config.txt:type = todo \n "
" spds/sources/todo/config.txt:# evolutionsource = \n "
" spds/sources/todo/config.txt:uri = task2 \n "
" spds/sources/todo/config.txt:# evolutionuser = \n "
" spds/sources/todo/config.txt:# evolutionpassword = \n " ;
2008-03-30 18:13:08 +02:00
return oldConfig ;
}
2008-03-30 13:43:36 +02:00
string FunambolConfig ( ) {
string config = m_scheduleWorldConfig ;
2009-11-24 15:02:21 +01:00
boost : : replace_all ( config , " /scheduleworld/ " , " /funambol/ " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
2008-06-28 15:27:07 +02:00
" syncURL = http://sync.scheduleworld.com/funambol/ds " ,
2008-06-28 23:32:16 +02:00
" syncURL = http://my.funambol.com/sync " ) ;
2008-03-30 13:43:36 +02:00
2009-04-07 20:33:18 +02:00
boost : : replace_first ( config ,
2010-01-18 21:58:31 +01:00
" WebURL = http://www.scheduleworld.com " ,
2009-04-07 20:33:18 +02:00
" WebURL = http://my.funambol.com " ) ;
2009-06-25 11:06:07 +02:00
boost : : replace_first ( config ,
" # enableWBXML = 1 " ,
" enableWBXML = 0 " ) ;
2010-04-19 13:56:07 +02:00
boost : : replace_first ( config ,
" # RetryInterval = 2M " ,
" RetryInterval = 0 " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
" addressbook/config.ini:uri = card3 " ,
" addressbook/config.ini:uri = card " ) ;
2009-11-24 15:02:21 +01:00
boost : : replace_all ( config ,
" addressbook/config.ini:type = addressbook:text/vcard " ,
" addressbook/config.ini:type = addressbook " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
2008-06-12 20:55:01 +02:00
" calendar/config.ini:uri = cal2 " ,
2008-03-30 13:43:36 +02:00
" calendar/config.ini:uri = event " ) ;
2009-11-24 15:02:21 +01:00
boost : : replace_all ( config ,
" calendar/config.ini:type = calendar " ,
" calendar/config.ini:type = calendar:text/calendar! " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
" todo/config.ini:uri = task2 " ,
" todo/config.ini:uri = task " ) ;
2009-11-24 15:02:21 +01:00
boost : : replace_all ( config ,
" todo/config.ini:type = todo " ,
" todo/config.ini:type = todo:text/calendar! " ) ;
2008-03-30 13:43:36 +02:00
return config ;
}
string SynthesisConfig ( ) {
string config = m_scheduleWorldConfig ;
2009-11-24 15:02:21 +01:00
boost : : replace_all ( config , " /scheduleworld/ " , " /synthesis/ " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
2008-06-28 15:27:07 +02:00
" syncURL = http://sync.scheduleworld.com/funambol/ds " ,
2008-03-30 13:43:36 +02:00
" syncURL = http://www.synthesis.ch/sync " ) ;
2009-04-07 20:33:18 +02:00
boost : : replace_first ( config ,
2010-01-18 21:58:31 +01:00
" WebURL = http://www.scheduleworld.com " ,
2009-04-07 20:33:18 +02:00
" WebURL = http://www.synthesis.ch " ) ;
2009-06-29 20:32:26 +02:00
boost : : replace_first ( config ,
" ConsumerReady = 1 " ,
" # ConsumerReady = 0 " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
" addressbook/config.ini:uri = card3 " ,
" addressbook/config.ini:uri = contacts " ) ;
2009-11-24 15:02:21 +01:00
boost : : replace_all ( config ,
" addressbook/config.ini:type = addressbook:text/vcard " ,
" addressbook/config.ini:type = addressbook " ) ;
2008-03-30 13:43:36 +02:00
boost : : replace_first ( config ,
2008-06-12 20:55:01 +02:00
" calendar/config.ini:uri = cal2 " ,
2008-03-30 13:43:36 +02:00
" calendar/config.ini:uri = events " ) ;
boost : : replace_first ( config ,
" calendar/config.ini:sync = two-way " ,
" calendar/config.ini:sync = disabled " ) ;
boost : : replace_first ( config ,
" memo/config.ini:uri = note " ,
" memo/config.ini:uri = notes " ) ;
boost : : replace_first ( config ,
" todo/config.ini:uri = task2 " ,
" todo/config.ini:uri = tasks " ) ;
boost : : replace_first ( config ,
" todo/config.ini:sync = two-way " ,
" todo/config.ini:sync = disabled " ) ;
return config ;
2010-01-29 20:28:24 +01:00
}
2008-03-29 15:16:34 +01:00
2008-03-28 23:32:00 +01:00
/** create directory hierarchy, overwriting previous content */
2008-03-30 17:15:00 +02:00
void createFiles ( const string & root , const string & content , bool append = false ) {
if ( ! append ) {
rm_r ( root ) ;
}
2008-03-28 23:32:00 +01:00
size_t start = 0 ;
ofstream out ;
string outname ;
out . exceptions ( ios_base : : badbit | ios_base : : failbit ) ;
while ( start < content . size ( ) ) {
size_t delim = content . find ( ' : ' , start ) ;
size_t end = content . find ( ' \n ' , start ) ;
if ( delim = = content . npos | |
end = = content . npos ) {
// invalid content ?!
break ;
}
string newname = content . substr ( start , delim - start ) ;
string line = content . substr ( delim + 1 , end - delim - 1 ) ;
if ( newname ! = outname ) {
if ( out . is_open ( ) ) {
out . close ( ) ;
}
string fullpath = root + " / " + newname ;
size_t fileoff = fullpath . rfind ( ' / ' ) ;
mkdir_p ( fullpath . substr ( 0 , fileoff ) ) ;
2008-03-30 17:15:00 +02:00
out . open ( fullpath . c_str ( ) ,
append ? ios_base : : out : ( ios_base : : out | ios_base : : trunc ) ) ;
2008-03-28 23:32:00 +01:00
outname = newname ;
}
out < < line < < endl ;
start = end + 1 ;
}
}
2009-11-24 15:02:21 +01:00
/** turn directory hierarchy into string
*
* @ param root root path in file system
* @ param peer if non - empty , then ignore all < root > / peers / < foo > directories
* where < foo > ! = peer
* @ param onlyProps ignore lines which are comments
*/
string scanFiles ( const string & root , const string & peer = " " , bool onlyProps = true ) {
2008-03-28 23:32:00 +01:00
ostringstream out ;
2009-11-24 15:02:21 +01:00
scanFiles ( root , " " , peer , out , onlyProps ) ;
2008-03-28 23:32:00 +01:00
return out . str ( ) ;
}
2008-03-30 23:50:51 +02:00
2009-11-24 15:02:21 +01:00
void scanFiles ( const string & root , const string & dir , const string & peer , ostringstream & out , bool onlyProps ) {
2008-03-29 15:16:34 +01:00
string newroot = root ;
newroot + = " / " ;
newroot + = dir ;
ReadDir readDir ( newroot ) ;
2008-03-28 23:32:00 +01:00
sort ( readDir . begin ( ) , readDir . end ( ) ) ;
2008-07-11 22:25:02 +02:00
BOOST_FOREACH ( const string & entry , readDir ) {
if ( isDir ( newroot + " / " + entry ) ) {
2009-11-24 15:02:21 +01:00
if ( boost : : ends_with ( newroot , " /peers " ) & &
! peer . empty ( ) & &
entry ! = peer ) {
// skip different peer directory
continue ;
} else {
scanFiles ( root , dir + ( dir . empty ( ) ? " " : " / " ) + entry , peer , out , onlyProps ) ;
}
2008-03-29 15:16:34 +01:00
} else {
ifstream in ;
in . exceptions ( ios_base : : badbit /* failbit must not trigger exception because is set when reaching eof ?! */ ) ;
2008-07-11 22:25:02 +02:00
in . open ( ( newroot + " / " + entry ) . c_str ( ) ) ;
2008-03-29 15:16:34 +01:00
string line ;
while ( ! in . eof ( ) ) {
getline ( in , line ) ;
if ( ( line . size ( ) | | ! in . eof ( ) ) & &
( ! onlyProps | |
2008-03-30 23:50:51 +02:00
( boost : : starts_with ( line , " # " ) ?
isPropAssignment ( line . substr ( 2 ) ) :
! line . empty ( ) ) ) ) {
2008-03-29 15:16:34 +01:00
if ( dir . size ( ) ) {
out < < dir < < " / " ;
}
2008-07-11 22:25:02 +02:00
out < < entry < < " : " ;
2008-03-29 15:16:34 +01:00
out < < line < < ' \n ' ;
2008-03-28 23:32:00 +01:00
}
}
}
}
}
2008-03-30 15:41:56 +02:00
string printConfig ( const string & server ) {
2009-12-01 16:36:33 +01:00
ScopedEnvChange templates ( " SYNCEVOLUTION_TEMPLATE_DIR " , " /dev/null " ) ;
2008-03-30 15:41:56 +02:00
ScopedEnvChange xdg ( " XDG_CONFIG_HOME " , m_testDir ) ;
ScopedEnvChange home ( " HOME " , m_testDir ) ;
TestCmdline cmdline ( " --print-config " , server . c_str ( ) , NULL ) ;
cmdline . doit ( ) ;
CPPUNIT_ASSERT_EQUAL_DIFF ( " " , cmdline . m_err . str ( ) ) ;
return cmdline . m_out . str ( ) ;
}
2008-03-28 23:32:00 +01:00
} ;
2009-10-05 14:49:32 +02:00
SYNCEVOLUTION_TEST_SUITE_REGISTRATION ( CmdlineTest ) ;
2008-03-28 23:32:00 +01:00
# endif // ENABLE_UNIT_TESTS
2009-10-02 17:23:53 +02:00
SE_END_CXX