adds tag filter for dav-sync pull

Tue, 29 May 2018 20:15:09 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Tue, 29 May 2018 20:15:09 +0200
changeset 380
8a0c727aa409
parent 379
cdaf5a3d3a50
child 381
17ccf828a2f2

adds tag filter for dav-sync pull

dav/db.h file | annotate | diff | comparison | revisions
dav/main.c file | annotate | diff | comparison | revisions
dav/sopt.c file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
--- a/dav/db.h	Sun May 27 19:45:28 2018 +0200
+++ b/dav/db.h	Tue May 29 20:15:09 2018 +0200
@@ -54,6 +54,8 @@
     DavBool tags_updated;
     UcxBuffer *cached_tags;
     char *tags_hash;
+    
+    DavBool keep;
 };
 
 struct SyncDatabase {
--- a/dav/main.c	Sun May 27 19:45:28 2018 +0200
+++ b/dav/main.c	Tue May 29 20:15:09 2018 +0200
@@ -197,6 +197,9 @@
 }
 
 void print_usage(char *cmd) {
+    fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd);
+    
+    fprintf(stderr, "Commands:\n");
     for(int i=0;;i++) {
         char *str = cmdusageinfo[i];
         if(!str) {
@@ -226,7 +229,6 @@
     fprintf(stderr, "        -d         order by last modified date\n");
     fprintf(stderr, "        -e         show extended flags\n");
     fprintf(stderr, "        -O         override resources\n");
-    fprintf(stderr, "        -A         tar import/export\n");
     fprintf(stderr, "        -L <lock>  specificy lock token\n");
     fprintf(stderr, "        -T <sec>   timeout in seconds\n");
     fprintf(stderr, "        -n <uri>   specify namespace uri\n");
--- a/dav/sopt.c	Sun May 27 19:45:28 2018 +0200
+++ b/dav/sopt.c	Tue May 29 20:15:09 2018 +0200
@@ -49,7 +49,7 @@
     const char *NOARG = "";
     
     char *option = NULL;
-    //char optchar = 0;
+    char optchar = 0;
     for(int i=0;i<argc;i++) {
         char *arg = argv[i];
         size_t len = strlen(arg);
@@ -90,7 +90,7 @@
                         break;
                     }
                     case 'r': {
-                        ucx_map_cstr_put(a->options, "read", NOARG);
+                        ucx_map_cstr_put(a->options, "remove", NOARG);
                         break;
                     }
                     case 'v': {
@@ -101,6 +101,11 @@
                         ucx_map_cstr_put(a->options, "syncdir", NOARG);
                         break;
                     }
+                    case 't': {
+                        option = "tags";
+                        optchar = 't';
+                        break;
+                    }
                 }
             }
         } else if(option) {
--- a/dav/sync.c	Sun May 27 19:45:28 2018 +0200
+++ b/dav/sync.c	Tue May 29 20:15:09 2018 +0200
@@ -132,8 +132,8 @@
             ret = cmd_add_tag(args);
         } else if(!strcmp(cmd, "remove-tag")) {
             ret = cmd_remove_tag(args);
-        } else if(!strcmp(cmd, "update-tags")) {
-            ret = cmd_update_tags(args);
+        } else if(!strcmp(cmd, "set-tags")) {
+            ret = cmd_set_tags(args);
         } else if(!strcmp(cmd, "list-tags")) {
             ret = cmd_list_tags(args);
         } else if(!strcmp(cmd, "add-dir")
@@ -167,8 +167,8 @@
     fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd);
     
     fprintf(stderr, "Commands:\n");
-    fprintf(stderr, "        pull [-cld] <directory>\n");
-    fprintf(stderr, "        push [-cld] <directory>\n");
+    fprintf(stderr, "        pull [-cld] [-t <tags>] <directory>\n");
+    fprintf(stderr, "        push [-cld] [-t <tags>] <directory>\n");
     fprintf(stderr, "        archive [-cld] <directory>\n");
     fprintf(stderr, "        resolve-conflicts <directory>\n");
     fprintf(stderr, "        delete-conflicts <directory>\n");
@@ -176,14 +176,17 @@
     fprintf(stderr, "        empty-trash <directory>\n");
     fprintf(stderr, "        add-tag [-s <syncdir>] <file> <tag>\n");
     fprintf(stderr, "        remove-tag [-s <syncdir>] <file> <tag>\n");
-    fprintf(stderr, "        update-tags [-s <syncdir>] <file> [tags]\n");
+    fprintf(stderr, "        set-tags [-s <syncdir>] <file> [tags]\n");
     fprintf(stderr, "        list-tags [-s <syncdir>] <file>\n\n");
     
     fprintf(stderr, "Options:\n");
     fprintf(stderr, "        -c         Disable conflict detection\n");
     fprintf(stderr, "        -l         Lock the repository before access\n");
     fprintf(stderr, "        -d         Don't lock the repository\n");
-    //fprintf(stderr, "        -r         Read changes from stdin\n\n");
+    fprintf(stderr, "        -t <tags>  "
+                    "Only sync files which have the specified tags\n");
+    fprintf(stderr, "        -r         "
+                    "Remove resources not matching the tag filter\n");
     fprintf(stderr, "        -v         verbose output (all commands)\n\n");
     
     fprintf(stderr, "Config commands:\n");
@@ -252,6 +255,55 @@
     return 1;
 }
 
+static int matches_tags(UcxList *resource_tags, UcxList *tags) {
+    if(!tags) {
+        return 1;
+    }
+    if(!resource_tags) {
+        return 0;
+    }
+    
+    UcxMap *res_tagmap = ucx_map_new(32);
+    UCX_FOREACH(elm, resource_tags) {
+        DavTag *t = elm->data;
+        // the value actually doesn't matter
+        ucx_map_cstr_put(res_tagmap, t->name, t);
+    }
+    
+    int ret = 1;
+    
+    // TODO: replace FOREACH with new tag expression evaluation
+    UCX_FOREACH(elm, tags) {
+        DavTag *matches_tag = elm->data;
+        if(!ucx_map_cstr_get(res_tagmap, matches_tag->name)) {
+            ret = 0;
+            break;
+        }
+    }
+    
+    ucx_map_free(res_tagmap);
+    return ret;
+}
+
+static int res_matches_tags(DavResource *res, UcxList *tags) {
+    if(!tags) {
+        return 1;
+    }
+    
+    DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags");
+    UcxList *res_tags = parse_dav_xml_taglist(tagsprop);
+    
+    int ret = matches_tags(res_tags, tags);
+    // TODO: free list content
+    ucx_list_free(res_tags);
+    return ret;
+}
+
+static int localres_matches_tags(LocalResource *res, UcxList *tags) {
+    // TODO: implement
+    return 1;
+}
+
 static DavSession* create_session(DavContext *ctx, Repository *repo, char *url) {
     DavSession *sn = dav_session_new_auth(
             ctx,
@@ -289,6 +341,14 @@
     fprintf(stderr, "\n");
 }
 
+static void localres_keep(SyncDatabase *db, const char *path) {
+    LocalResource *local = ucx_map_cstr_remove(db->resources, path);
+    if(local) {
+        local->keep = TRUE;
+    }
+    
+}
+
 int cmd_pull(CmdArgs *a) {
     if(a->argc != 1) {
         fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many");
@@ -394,6 +454,13 @@
         return -1;
     }
     
+    UcxList *tags = NULL;
+    char *tags_str = cmd_getoption(a, "tags");
+    if(tags_str) {
+        tags = parse_csv_taglist(tags_str, strlen(tags_str));
+    }
+    DavBool rm_tagmismatch = cmd_getoption(a, "remove") ? 1 : 0;
+    
     int sync_success = 0;
     int sync_delete = 0;
     int sync_error = 0;
@@ -413,9 +480,18 @@
                 continue;
             }
             
+            if (!res_matches_tags(res, tags)) {
+                if(!rm_tagmismatch) {
+                    localres_keep(db, res->path);
+                }
+                res = res->next;
+                continue;
+            }
+            
             char *status = dav_get_string_property(res, "idav:status");
             if(status && !strcmp(status, "broken")) {
                 res = res->next;
+                localres_keep(db, res->path);
                 continue;
             }
             
@@ -466,7 +542,7 @@
             continue;
         }
         
-        if(sync_shutdown) {
+        if(sync_shutdown || local->keep) {
             ucx_map_cstr_put(svrres, local->path, local_resource_copy(local));
         } else {
             // sync_remove_resource does all necessary tests
@@ -1234,6 +1310,10 @@
     newres->size = res->size;
     newres->last_modified = res->last_modified;
     newres->isdirectory = res->isdirectory;
+    if(res->tags_hash) {
+       newres->tags_hash = strdup(res->tags_hash); 
+    }
+    newres->tags_updated = res->tags_updated;
     return newres;
 }
 
@@ -2121,7 +2201,7 @@
 
 #define CMD_TAG_ADD    0
 #define CMD_TAG_REMOVE 1
-#define CMD_TAG_UPDATE 2
+#define CMD_TAG_SET 2
 #define CMD_TAG_LIST   3
 int cmd_add_tag(CmdArgs *args) {
     if(args->argc != 2) {
@@ -2139,12 +2219,12 @@
     return cmd_tagopt(args, CMD_TAG_REMOVE);
 }
 
-int cmd_update_tags(CmdArgs *args) {
+int cmd_set_tags(CmdArgs *args) {
     if(args->argc < 1 || args->argc > 2) {
         fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many");
         return -1;
     }
-    return cmd_tagopt(args, CMD_TAG_UPDATE);
+    return cmd_tagopt(args, CMD_TAG_SET);
 }
 
 int cmd_list_tags(CmdArgs *args) {
@@ -2181,7 +2261,7 @@
     UcxList *tags = NULL;
     DavBool store_tags = FALSE;
     
-    if(cmd != CMD_TAG_UPDATE) {
+    if(cmd != CMD_TAG_SET) {
         char *tag = args->argv[1];
         char *tagcolor = NULL; // TODO: get color
 
--- a/dav/sync.h	Sun May 27 19:45:28 2018 +0200
+++ b/dav/sync.h	Tue May 29 20:15:09 2018 +0200
@@ -113,7 +113,7 @@
 
 int cmd_add_tag(CmdArgs *args);
 int cmd_remove_tag(CmdArgs *args);
-int cmd_update_tags(CmdArgs *args);
+int cmd_set_tags(CmdArgs *args);
 int cmd_list_tags(CmdArgs *args);
 int cmd_tagopt(CmdArgs *args, int cmd);
 

mercurial