int _repos_pull_data (XML * repository, const char * list_id, const char * remote_id, int mode, XML * changelist);
WFTK_EXPORT int repos_pull (XML * repository, const char *list_id, const char *remote_id, XML * changelist)
{
return _repos_pull_data (repository, list_id, remote_id, 0, changelist);
}
WFTK_EXPORT int repos_pull_all (XML * repository, const char *list_id, const char *remote_id, XML * changelist)
{
XML * info;
XML * last;
struct tm * timeptr;
time_t julian;
char now[32];
int ret = _repos_pull_data (repository, list_id, remote_id, 1, changelist);
if (ret > 0) {
info = xml_load ("_log/%s.info", list_id);
if (xml_is (info, "xml-error")) {
xml_free (info);
info = NULL;
}
if (!info) {
info = xml_create ("synchinfo");
}
last = NULL;
last = xml_search (info, "field", "id", remote_id);
if (!last) {
last = xml_create ("field");
xml_set (last, "id", remote_id);
xml_append (info, last);
}
repos_mark_time (repository, "now");
xml_set (last, "push", xml_attrval (repository, "now"));
xml_save (info, "_log/%s.info", list_id);
xml_free (info);
}
return ret;
}
int _repos_pull_data (XML * repository, const char *list_id, const char *remote_id, int mode, XML * changelist)
{
XML * list;
XML * remote;
XML * info;
XML * last;
XML * changes;
XML * cur;
int count = 0;
XML * obj;
list = xml_search (repository, "list", "id", list_id);
if (!list) {
return -1;
}
if (!remote_id) {
remote_id = xml_attrval (list, "pull");
if (!*remote_id) {
remote_id = xml_attrval (list, "mirror");
}
if (!*remote_id) {
return -1;
}
}
/* Only remote lists are supported right now. */
remote = xml_search (repository, "remote", "host", remote_id);
if (!remote) {
remote = xml_create ("remote");
xml_set (remote, "host", remote_id);
xml_append (repository, remote);
}
repos_open (remote, NULL, "--remote--");
if (*xml_attrval (remote, "error-state")) {
xml_delete (remote);
return -1;
}
/* OK. Let's get a list of changes since our last pull. */
info = xml_load ("_log/%s.info", list_id);
if (xml_is (info, "xml-error")) {
xml_free (info);
info = NULL;
}
if (!info) {
info = xml_create ("synchinfo");
}
last = NULL;
last = xml_search (info, "field", "id", remote_id);
if (!last) {
last = xml_create ("field");
xml_set (last, "id", remote_id);
xml_set (last, "pull", "0000-00-00");
xml_append (info, last);
}
if (changelist) changes = changelist;
else changes = xml_create ("list");
if (!mode) {
repos_changes (remote, changes, xml_attrval (last, "pull"), list_id);
} else {
xml_set (changes, "id", list_id);
repos_list (remote, changes);
}
cur = xml_firstelem (changes);
if (!cur) {
if (!changelist) xml_free (changes);
xml_free (info);
return 0;
}
/* Now we write our current data into the info file. */
repos_mark_time (remote, "now");
repos_mark_time (repository, "now");
xml_set (last, "pull", xml_attrval (remote, "now"));
xml_set (last, "push", xml_attrval (repository, "now")); /* This is necessary in the case of a pull-fixup-synch process */
xml_save (info, "_log/%s.info", list_id);
/* Now we iterate along our change list and do the Right Thing for each change. */
while (cur) {
count++;
if (!*xml_attrval (cur, "action") || !strcmp ("add", xml_attrval (cur, "action"))) {
obj = repos_get (remote, list_id, xml_attrval (cur, "id"));
repos_add (repository, list_id, obj);
xml_free (obj);
} else if (!strcmp ("del", xml_attrval (cur, "action"))) {
repos_del (repository, list_id, xml_attrval (cur, "id"));
} else if (!strcmp ("mod", xml_attrval (cur, "action"))) {
obj = repos_get (remote, list_id, xml_attrval (cur, "id"));
repos_merge (repository, list_id, obj, NULL); /* TODO: consider a list mode "synch-raw" which can force "mod" */
xml_free (obj);
}
/* Note we can log other things without confusing our mirrors. Might come in handy. */
cur = xml_nextelem (cur);
}
if (!changelist) xml_free (changes);
xml_free (info);
return count;
}
|
int _repos_push_data (XML * repository, const char * list_id, const char * remote_id, int mode);
WFTK_EXPORT int repos_push (XML * repository, const char *list_id, const char *remote_id)
{
return _repos_push_data (repository, list_id, remote_id, 0);
}
WFTK_EXPORT int repos_push_all (XML * repository, const char *list_id, const char *remote_id)
{
XML * info;
XML * last;
int ret = _repos_push_data (repository, list_id, remote_id, 1);
if (ret > 0) {
info = xml_load ("_log/%s.info", list_id);
if (xml_is (info, "xml-error")) {
xml_free (info);
info = NULL;
}
if (!info) {
info = xml_create ("synchinfo");
}
last = NULL;
last = xml_search (info, "field", "id", remote_id);
if (!last) {
last = xml_create ("field");
xml_set (last, "id", remote_id);
xml_append (info, last);
}
xml_set (last, "pull", xml_attrval (repository, "remote-time"));
xml_save (info, "_log/%s.info", list_id);
xml_free (info);
}
return ret;
}
int _repos_push_data (XML * repository, const char *list_id, const char *remote_id, int mode)
{
XML * list;
XML * remote;
XML * info;
XML * last;
XML * changes;
XML * cur;
int count = 0;
XML * obj;
list = xml_search (repository, "list", "id", list_id);
if (!list) {
return -1;
}
if (!remote_id) {
remote_id = xml_attrval (list, "push");
if (!*remote_id) {
remote_id = xml_attrval (list, "mirror");
}
if (!*remote_id) {
return -1;
}
}
/* Only remote lists are supported right now. */
remote = xml_search (repository, "remote", "host", remote_id);
if (!remote) {
remote = xml_create ("remote");
xml_set (remote, "host", remote_id);
xml_append (repository, remote);
}
repos_open (remote, NULL, "--remote--");
if (*xml_attrval (remote, "error-state")) {
xml_delete (remote);
return -1;
}
/* OK. Let's get a list of changes since our last pull. */
info = xml_load ("_log/%s.info", list_id);
if (xml_is (info, "xml-error")) {
xml_free (info);
info = NULL;
}
if (!info) {
info = xml_create ("synchinfo");
}
last = NULL;
last = xml_search (info, "field", "id", remote_id);
if (!last) {
last = xml_create ("field");
xml_set (last, "id", remote_id);
xml_set (last, "push", "0000-00-00");
xml_append (info, last);
}
changes = xml_create ("list");
if (!mode) {
repos_changes (repository, changes, xml_attrval (last, "push"), list_id);
} else {
xml_set (changes, "id", list_id);
repos_list (repository, changes);
}
cur = xml_firstelem (changes);
if (!cur) {
xml_free (changes);
xml_free (info);
return 0;
}
/* Now we write our current data into the info file. */
repos_mark_time (repository, "now");
repos_mark_time (remote, "now");
xml_set (repository, "remote-time", xml_attrval (remote, "now"));
xml_set (last, "push", xml_attrval (repository, "now"));
xml_save (info, "_log/%s.info", list_id);
/* Now we iterate along our change list and do the Right Thing for each change. */
while (cur) {
count++;
if (!*xml_attrval (cur, "action") || !strcmp ("add", xml_attrval (cur, "action"))) {
obj = repos_get (repository, list_id, xml_attrval (cur, "id"));
repos_add (remote, list_id, obj);
xml_free (obj);
} else if (!strcmp ("del", xml_attrval (cur, "action"))) {
repos_del (remote, list_id, xml_attrval (cur, "id"));
} else if (!strcmp ("mod", xml_attrval (cur, "action"))) {
obj = repos_get (repository, list_id, xml_attrval (cur, "id"));
repos_merge (remote, list_id, obj, NULL); /* TODO: consider a list mode "synch-raw" which can force "mod" */
xml_free (obj);
}
/* Note we can log other things without confusing our mirrors. Might come in handy. */
cur = xml_nextelem (cur);
}
xml_free (changes);
xml_free (info);
return count;
}
|
WFTK_EXPORT int repos_synch (XML * repository, const char *list_id, const char *remote_id, XML * changelist)
{
XML * list;
XML * remote;
XML * info;
XML * last;
XML * localchanges;
XML * remotechanges;
XML * cur;
int count = 0;
XML * obj;
list = xml_search (repository, "list", "id", list_id);
if (!list) {
return -1;
}
if (!remote_id) {
remote_id = xml_attrval (list, "mirror");
if (!*remote_id) {
if (*xml_attrval (list, "push")) return repos_push (repository, list_id, remote_id);
if (*xml_attrval (list, "pull")) return repos_pull (repository, list_id, remote_id, NULL);
return -1;
}
}
/* Only remote lists are supported right now. */
remote = xml_search (repository, "remote", "host", remote_id);
if (!remote) {
remote = xml_create ("remote");
xml_set (remote, "host", remote_id);
xml_append (repository, remote);
}
repos_open (remote, NULL, "--remote--");
if (*xml_attrval (remote, "error-state")) {
xml_delete (remote);
return -1;
}
/* OK. Let's get a list of changes since our last pull. */
info = xml_load ("_log/%s.info", list_id);
if (xml_is (info, "xml-error")) {
xml_free (info);
info = NULL;
}
if (!info) {
info = xml_create ("synchinfo");
}
last = NULL;
last = xml_search (info, "field", "id", remote_id);
if (!last) {
last = xml_create ("field");
xml_set (last, "id", remote_id);
xml_append (info, last);
}
if (!*xml_attrval (last, "push")) xml_set (last, "push", "0000-00-00");
if (!*xml_attrval (last, "pull")) xml_set (last, "pull", "0000-00-00");
if (changelist) remotechanges = changelist;
else remotechanges = xml_create ("list");
repos_changes (remote, remotechanges, xml_attrval (last, "pull"), list_id);
localchanges = xml_create ("list");
repos_changes (repository, localchanges, xml_attrval (last, "push"), list_id);
if (!xml_firstelem (remotechanges) && !xml_firstelem (localchanges)) {
if (!changelist) xml_free (remotechanges);
xml_free (localchanges);
xml_free (info);
return 0;
}
/* Now we iterate along our change lists and do the Right Thing for each change. */
/* We first pull all changes from the remote list, then we push all changes from the local list. */
cur = xml_firstelem (remotechanges);
while (cur) {
count++;
if (!strcmp ("add", xml_attrval (cur, "action"))) {
obj = repos_get (remote, list_id, xml_attrval (cur, "id"));
repos_add (repository, list_id, obj);
xml_free (obj);
} else if (!strcmp ("del", xml_attrval (cur, "action"))) {
repos_del (repository, list_id, xml_attrval (cur, "id"));
} else if (!strcmp ("mod", xml_attrval (cur, "action"))) {
obj = repos_get (remote, list_id, xml_attrval (cur, "id"));
repos_merge (repository, list_id, obj, NULL); /* TODO: consider a list mode "synch-raw" which can force "mod" */
xml_free (obj);
}
cur = xml_nextelem (cur);
}
cur = xml_firstelem (localchanges);
while (cur) {
count++;
if (!strcmp ("add", xml_attrval (cur, "action"))) {
obj = repos_get (repository, list_id, xml_attrval (cur, "id"));
repos_add (remote, list_id, obj);
xml_free (obj);
} else if (!strcmp ("del", xml_attrval (cur, "action"))) {
repos_del (remote, list_id, xml_attrval (cur, "id"));
} else if (!strcmp ("mod", xml_attrval (cur, "action"))) {
obj = repos_get (repository, list_id, xml_attrval (cur, "id"));
repos_merge (remote, list_id, obj, NULL); /* TODO: consider a list mode "synch-raw" which can force "mod" */
xml_free (obj);
}
cur = xml_nextelem (cur);
}
/* Now we write our current data into the info file. Note that this allows us to avoid noticing
our own changes next time we synch -- but without locking, it exposes us to missing some changes
if somebody else synchs while we're busy. That's why we need locking! */
repos_mark_time (remote, "now");
repos_mark_time (repository, "now");
xml_set (last, "push", xml_attrval (repository, "now"));
xml_set (last, "pull", xml_attrval (remote, "now"));
xml_save (info, "_log/%s.info", list_id);
xml_free (localchanges);
if (!changelist) xml_free (remotechanges);
xml_free (info);
return count;
}
|
WFTK_EXPORT int repos_mark_time (XML * repository, const char *attr)
{
struct tm * timeptr;
time_t julian;
char now[32];
const char * recv;
char * mark;
struct _repos_remote * sock = (struct _repos_remote *) xml_getbin (repository);
if (sock) { /* Remote. */
xml_set (sock->parms, "outgoing", "time\n");
_repos_send (sock);
xml_set (repository, attr, "");
recv = _repos_receive (sock);
if (*recv == '-') return 1;
mark = strchr (recv + 6, '+');
if (!mark) return 1;
xml_attrncat (repository, attr, recv + 6, mark - recv - 7);
return 0;
}
time (&julian);
timeptr = localtime (&julian);
sprintf (now, "%04d-%02d-%02d %02d:%02d:%02d",
timeptr->tm_year + 1900, timeptr->tm_mon + 1, timeptr->tm_mday,
timeptr->tm_hour, timeptr->tm_min, timeptr->tm_sec);
xml_set (repository, attr, now);
}
|
| This code and documentation are released under the terms of the GNU license. They are copyright (c) 2001-2005, Vivtek. All rights reserved except those explicitly granted under the terms of the GNU license. |