config: refactor root path handling

The previous approach made FileConfigTree more complex than necessary.
Having an abstract ConfigTree::getRootPath() with undefined behavior
is bad design.

The code was had undesiredable side effects: inside a peer config,
another "peers" directory was created because FileConfigTree didn't
know whether creating that dir was required or not.

Now all of the complexity is in SyncConfig, which arguably knows
better what the tree stands for and how to use
it.
This commit is contained in:
Patrick Ohly 2013-09-06 10:30:30 +02:00
parent 37b03d5e8d
commit ba5eaccef9
8 changed files with 42 additions and 36 deletions

View file

@ -81,9 +81,6 @@ class ConfigTree {
*/
virtual void remove(const std::string &path) = 0;
/** a string identifying the root of the configuration - exact meaning varies */
virtual std::string getRootPath() const = 0;
/**
* Selects which node attached to a path name is to be used.
* This is similar in concept to multiple data forks in a file.

View file

@ -38,31 +38,18 @@ using namespace std;
SE_BEGIN_CXX
FileConfigTree::FileConfigTree(const string &root,
const string &peer,
SyncConfig::Layout layout) :
m_root(root),
m_peer(peer),
m_layout(layout),
m_readonly(false)
{
}
string FileConfigTree::getRootPath() const
{
return normalizePath(m_root + "/" + m_peer);
}
void FileConfigTree::flush()
{
BOOST_FOREACH(const NodeCache_t::value_type &node, m_nodes) {
node.second->flush();
}
if (m_layout == SyncConfig::SHARED_LAYOUT) {
// ensure that "peers" directory exists for new-style configs,
// not created by flushing nodes for pure context configs but
// needed to detect new-syle configs
mkdir_p(getRootPath() + "/peers");
}
}
void FileConfigTree::reload()

View file

@ -40,21 +40,18 @@ class FileConfigTree : public ConfigTree {
/**
* @param root absolute filesystem path for
* .syncj4/evolution or .config/syncevolution
* @param peer the relative path to the peer configuration
* @param layout determines file names to be used;
* HTTP_SERVER_LAYOUT and SHARED_LAYOUT are the same except
* that SHARED_LAYOUT creates the "peers" directory during
* flushing
* HTTP_SERVER_LAYOUT and SHARED_LAYOUT are the same,
* whereas SYNC4J_LAYOUT activates some backward-compatibility code
*/
FileConfigTree(const std::string &root,
const std::string &peer,
SyncConfig::Layout layout);
void setReadOnly(bool readonly) { m_readonly = readonly; }
bool getReadOnly() const { return m_readonly; }
std::string getRoot() const { return m_root; }
/* ConfigTree API */
virtual std::string getRootPath() const;
virtual void flush();
virtual void reload();
virtual void remove(const std::string &path);
@ -75,7 +72,6 @@ class FileConfigTree : public ConfigTree {
private:
const std::string m_root;
const std::string m_peer;
SyncConfig::Layout m_layout;
bool m_readonly;

View file

@ -52,7 +52,7 @@ boost::shared_ptr<ConfigNode> SingleFileConfigTree::open(const string &filename)
return entry;
}
string name = getRootPath() + " - " + normalized;
string name = m_data->getName() + " - " + normalized;
boost::shared_ptr<DataBlob> data;
BOOST_FOREACH(const FileContent_t::value_type &file, m_content) {

View file

@ -62,7 +62,6 @@ class SingleFileConfigTree : public ConfigTree {
boost::shared_ptr<ConfigNode> open(const std::string &filename);
/* ConfigTree API */
virtual std::string getRootPath() const { return m_data->getName(); }
virtual void flush();
virtual void reload();
virtual void remove(const std::string &path);

View file

@ -330,6 +330,7 @@ SyncConfig::SyncConfig() :
void SyncConfig::makeVolatile()
{
m_tree.reset(new VolatileConfigTree());
m_fileTree.reset();
m_peerNode.reset(new VolatileConfigNode());
m_hiddenPeerNode = m_peerNode;
m_globalNode = m_peerNode;
@ -381,6 +382,7 @@ SyncConfig::SyncConfig(const string &peer,
if (!access((path + "/spds/syncml/config.txt").c_str(), F_OK)) {
m_layout = SYNC4J_LAYOUT;
} else {
m_layout = SHARED_LAYOUT;
root = getNewRoot();
path = root + "/" + m_peerPath;
if (!access((path + "/config.ini").c_str(), F_OK) &&
@ -396,9 +398,8 @@ SyncConfig::SyncConfig(const string &peer,
}
}
}
m_tree.reset(new FileConfigTree(root,
m_peerPath.empty() ? m_contextPath : m_peerPath,
m_layout));
m_fileTree.reset(new FileConfigTree(root, m_layout));
m_tree = m_fileTree;
}
string path;
@ -656,13 +657,16 @@ void SyncConfig::migrate(const std::string &config)
string SyncConfig::getRootPath() const
{
return m_tree->getRootPath();
return m_fileTree ?
normalizePath(m_fileTree->getRoot() + "/" +
((m_layout == SYNC4J_LAYOUT || hasPeerProperties()) ? m_peerPath : m_contextPath)) :
"";
}
void SyncConfig::addPeers(const string &root,
const std::string &configname,
SyncConfig::ConfigList &res) {
FileConfigTree tree(root, "", SyncConfig::HTTP_SERVER_LAYOUT);
FileConfigTree tree(root, SyncConfig::HTTP_SERVER_LAYOUT);
list<string> servers = tree.getChildren("");
BOOST_FOREACH(const string &server, servers) {
// sanity check: only list server directories which actually
@ -930,8 +934,11 @@ list<string> SyncConfig::getPeers() const
list<string> res;
if (!hasPeerProperties()) {
FileConfigTree tree(getRootPath(), "", SHARED_LAYOUT);
res = tree.getChildren("peers");
std::string rootPath = getRootPath();
if (!rootPath.empty()) {
FileConfigTree tree(getRootPath(), SHARED_LAYOUT);
res = tree.getChildren("peers");
}
}
return res;
@ -964,6 +971,13 @@ void SyncConfig::preFlush(UserInterface &ui)
void SyncConfig::flush()
{
if (!isEphemeral()) {
if (m_fileTree && m_layout == SHARED_LAYOUT && !hasPeerProperties()) {
// Ensure that "peers" directory exists for new-style
// configs. It would not get created when flushing nodes
// for pure context configs otherwise (it's empty), and we
// need it to detect new-syle configs.
mkdir_p(m_fileTree->getRoot() + "/" + m_contextPath + "/peers");
}
m_tree->flush();
}
}
@ -1098,8 +1112,14 @@ SyncSourceNodes SyncConfig::getSyncSourceNodes(const string &name,
serverNode = node;
} else {
// Here we assume that m_tree is a FileConfigTree. Otherwise getRootPath()
// will not point into a normal file system.
cacheDir = m_tree->getRootPath() + "/" + peerPath + "/.cache";
// will not point into a normal file system. We fall back to not allowing
// the usage of a cache dir by using /dev/null in that case.
std::string rootPath = getRootPath();
if (rootPath.empty()) {
cacheDir = "/dev/null";
} else {
cacheDir = rootPath + "/" + peerPath + "/.cache";
}
node = m_tree->open(peerPath, ConfigTree::visible);
if (compatMode) {

View file

@ -39,6 +39,8 @@
#include <syncevo/declarations.h>
SE_BEGIN_CXX
class FileConfigTree;
/**
* @defgroup ConfigHandling Configuration Handling
* @{
@ -973,7 +975,7 @@ class SyncConfig {
*/
void prepareConfigForWrite();
/** absolute directory name of the configuration root */
/** absolute directory name of the configuration root, empty if unknown or not available */
std::string getRootPath() const;
typedef std::list< std::pair<std::string, std::string> > ConfigList;
@ -1653,6 +1655,11 @@ private:
/** holds all config nodes relative to the root that we found */
boost::shared_ptr<ConfigTree> m_tree;
/**
* Same instance as m_tree, except that we know that it is a FileConfigTree.
*/
boost::shared_ptr<FileConfigTree> m_fileTree;
/** access to global sync properties, independent of
the context (for example, "defaultPeer") */
boost::shared_ptr<FilterConfigNode> m_globalNode;

View file

@ -33,7 +33,7 @@ SE_BEGIN_CXX
class VolatileConfigTree : public FileConfigTree {
public:
VolatileConfigTree() :
FileConfigTree("/dev/null", "", SyncConfig::SHARED_LAYOUT)
FileConfigTree("/dev/null", SyncConfig::SHARED_LAYOUT)
{}
virtual void flush() {}