adds tag management commands to dav-sync

Sun, 01 Apr 2018 12:40:48 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 01 Apr 2018 12:40:48 +0200
changeset 372
2e15ff88a0ab
parent 371
604e7e335b3b
child 373
dcc03142eb5f

adds tag management commands to dav-sync

dav/sopt.c file | annotate | diff | comparison | revisions
dav/sync.c file | annotate | diff | comparison | revisions
dav/sync.h file | annotate | diff | comparison | revisions
libidav/utils.c file | annotate | diff | comparison | revisions
libidav/utils.h file | annotate | diff | comparison | revisions
--- a/dav/sopt.c	Sun Feb 04 15:58:07 2018 +0100
+++ b/dav/sopt.c	Sun Apr 01 12:40:48 2018 +0200
@@ -97,6 +97,10 @@
                         ucx_map_cstr_put(a->options, "verbose", NOARG);
                         break;
                     }
+                    case 's': {
+                        ucx_map_cstr_put(a->options, "syncdir", NOARG);
+                        break;
+                    }
                 }
             }
         } else if(option) {
--- a/dav/sync.c	Sun Feb 04 15:58:07 2018 +0100
+++ b/dav/sync.c	Sun Apr 01 12:40:48 2018 +0200
@@ -128,6 +128,12 @@
             ret = cmd_trash_info(args);
         } else if(!strcmp(cmd, "empty-trash")) {
             ret = cmd_empty_trash(args);
+        } else if(!strcmp(cmd, "add-tag")) {
+            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, "add-dir")
                 || !strcmp(cmd, "add-directory")) {
             ret = cmd_add_directory(args);
@@ -165,7 +171,10 @@
     fprintf(stderr, "        resolve-conflicts <directory>\n");
     fprintf(stderr, "        delete-conflicts <directory>\n");
     fprintf(stderr, "        trash-info <directory>\n");
-    fprintf(stderr, "        empty-trash <directory>\n\n");
+    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\n");
     
     fprintf(stderr, "Options:\n");
     fprintf(stderr, "        -c         Disable conflict detection\n");
@@ -1386,6 +1395,14 @@
         return 0;
     }
     
+    int ret = sync_store_tags_local(dir, local, path, tags);
+    
+    // TODO: free stuff
+    
+    return ret;
+}
+
+int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, UcxList *tags) {
     int ret = 0;
     if(dir->tagconfig->store == TAG_STORE_XATTR) {
         UcxBuffer *data = NULL;
@@ -1408,8 +1425,16 @@
             
             if(data) {
                 char *data_hash = dav_create_hash(data->space, data->size);
-                if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) {
-                    printf("update: %s\n", local->path);
+                int update = 1;
+                if(local) {
+                    if(!local->tags_hash || strcmp(data_hash, local->tags_hash)) {
+                        printf("update: %s\n", local->path);
+                        // TODO: update hash in localres??
+                    } else {
+                        update = 0;
+                    }
+                }
+                if(update) {
                     ret = xattr_set(path, dir->tagconfig->xattr_name, data->space, data->pos);
                 }
                 ucx_buffer_free(data);
@@ -1422,8 +1447,6 @@
         }
     }
     
-    // TODO: free stuff
-    
     return ret;
 }
 
@@ -1458,6 +1481,10 @@
     
     UcxList *tags = NULL;
     
+    if(!res) {
+        return NULL;
+    }
+    
     if(!dir->tagconfig) {
         return NULL;
     }
@@ -2042,6 +2069,195 @@
     return 0;
 }
 
+#define CMD_TAG_ADD    0
+#define CMD_TAG_REMOVE 1
+#define CMD_TAG_UPDATE 2
+int cmd_add_tag(CmdArgs *args) {
+    if(args->argc != 2) {
+        fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many");
+        return -1;
+    }
+    return cmd_tagopt(args, CMD_TAG_ADD);
+}
+
+int cmd_remove_tag(CmdArgs *args) {
+    if(args->argc != 2) {
+        fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many");
+        return -1;
+    }
+    return cmd_tagopt(args, CMD_TAG_REMOVE);
+}
+
+int cmd_update_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);
+}
+
+int cmd_tagopt(CmdArgs *args, int cmd) {
+    SyncFile file;
+    int ret = 0;
+    char *path = args->argv[0];
+    
+    int err = sync_get_file(args, path, NULL, &file);
+    if(err) {
+        fprintf(stderr, "err: %d\n", err); // TODO: print nice err msg
+        return -1;
+    }
+    
+    if(!file.dir->tagconfig) {
+        fprintf(stderr, "Tags are not supported for this sync directory\n");
+        return -1;
+    }
+    
+    SyncDatabase *db = load_db(file.dir->database);
+    if(!db) {
+        fprintf(stderr, "Cannot load sync directory database\n");
+        return -1;
+    }
+    
+    LocalResource *localres = ucx_map_cstr_get(db->resources, file.path);
+    UcxList *tags = NULL;
+    DavBool store_tags = FALSE;
+    
+    if(cmd == CMD_TAG_ADD || cmd == CMD_TAG_REMOVE) {
+        char *tag = args->argv[1];
+        char *tagcolor = NULL; // TODO: get color
+
+        tags = sync_get_file_tags(file.dir, localres, NULL);
+        UcxList *x = NULL;
+        UCX_FOREACH(elm, tags) {
+            DavTag *t = elm->data;
+            if(!strcmp(t->name, tag)) {
+                x = elm;
+                break;
+            }
+        }
+
+        if(cmd == CMD_TAG_ADD) {
+            if(!x) {
+                DavTag *newtag = malloc(sizeof(DavTag));
+                newtag->name = tag;
+                newtag->color = tagcolor;
+                tags = ucx_list_append(tags, newtag);
+                store_tags = TRUE;
+            }
+        } else {
+            if(tags) {
+                tags = ucx_list_remove(tags, x);
+            }
+            store_tags = TRUE;
+        }
+    } else {
+        if(args->argc == 2) {
+            char *tags_str = args->argv[1];
+            tags = parse_csv_taglist(tags_str, strlen(tags_str));
+            // TODO: read from stdin if tags_str is "-"
+        }
+    }
+    
+    if(store_tags) {
+        if(sync_store_tags_local(file.dir, NULL, path, tags)) {
+            fprintf(stderr, "Cannot store tags\n");
+        }
+        if(localres) {
+            localres->tags_updated = TRUE;
+        }
+    }
+    
+    // store db
+    if(store_db(db, file.dir->database)) {
+        fprintf(stderr, "Cannot store sync db\n");
+        ret = -2;
+    }
+    
+    free(file.path);
+    return ret;
+}
+
+static int isfileindir(SyncDirectory *dir, const char *path, SyncFile *f) {
+    char *fullpath;
+    if(path[0] != '/') {
+        size_t wdlen = 1024;
+        char *wd = malloc(1024);
+        while(!getcwd(wd, wdlen)) {
+            if(errno == ERANGE) {
+                wdlen *= 2;
+                wd = realloc(wd, wdlen);
+            } else {
+                free(wd);
+                return 0;
+            }
+        }
+        
+        fullpath = util_concat_path(wd, path);
+    } else {
+        fullpath = strdup(path);
+    }
+    
+    // TODO: normalize path
+    
+    if(!sstrprefix(sstr((char*)fullpath), sstr(dir->path))) {
+        free(fullpath);
+        return 0;
+    }
+    
+    // TODO: check filter
+    
+    f->dir = dir;
+    f->path = util_concat_path("/", fullpath + strlen(dir->path));
+    
+    free(fullpath);
+    return 1;
+}
+
+int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f) {
+    struct stat s;
+    if(stat(path, &s)) {
+        switch(errno) {
+            case EACCES: return 2;
+            case ENOENT: return 1;
+            default: return 3;
+        }
+    }
+    
+    char *sdir = cmd_getoption(args, "syncdir");
+    
+    if(sdir) {
+        SyncDirectory *dir = scfg_get_dir(sdir);
+        if(!dir) {
+            return 6;
+        }
+        if(!isfileindir(dir, path, f)) {
+            return 4;
+        }
+    } else {
+        SyncDirectory *target = NULL;
+        
+        UcxMapIterator i = scfg_directory_iterator();
+        UcxKey k;
+        SyncDirectory *dir;
+        UCX_MAP_FOREACH(key, dir, i) {
+            if(isfileindir(dir, path, f)) {
+                if(target) {
+                    return 5;
+                } else {
+                    target = dir;
+                }
+            }
+        }
+        
+        if(!target) {
+            return 4;
+        }
+    }
+    
+    return 0;
+}
+
+
 int cmd_add_directory(CmdArgs *args) {
     if(!get_repositories()) {
         fprintf(stderr, "No repositories available. Run 'dav add-repository' first.\n");
--- a/dav/sync.h	Sun Feb 04 15:58:07 2018 +0100
+++ b/dav/sync.h	Sun Apr 01 12:40:48 2018 +0200
@@ -51,6 +51,11 @@
 
 #define STDIN_BUF_SIZE 2048
 
+typedef struct SyncFile {
+    SyncDirectory *dir;
+    char *path;
+} SyncFile;
+    
 void print_usage(char *cmd);
 
 pthread_t start_sighandler(pthread_mutex_t *mutex) ;
@@ -87,6 +92,7 @@
 UcxList* sync_get_file_tags(SyncDirectory *dir, LocalResource *res, DavBool *changed);
 UcxList* sync_merge_tags(UcxList *tags1, UcxList *tags2);
 int sync_store_tags(SyncDirectory *dir, const char *path, LocalResource *local, DavResource *res);
+int sync_store_tags_local(SyncDirectory *dir, LocalResource *local, const char *path, UcxList *tags);
 int sync_put_resource(
         SyncDirectory *dir,
         DavResource *res,
@@ -103,6 +109,25 @@
 
 int cmd_trash_info(CmdArgs *args);
 int cmd_empty_trash(CmdArgs *args);
+
+int cmd_add_tag(CmdArgs *args);
+int cmd_remove_tag(CmdArgs *args);
+int cmd_update_tags(CmdArgs *args);
+int cmd_tagopt(CmdArgs *args, int cmd);
+
+/*
+ * gets the syncdir and resource path for a given file path
+ * 
+ * returns 0 or error code:
+ * 1: file not found
+ * 2: file permission error
+ * 3: stat error
+ * 4: file is not in any syncdir
+ * 5: file is in multiple syncdirs
+ * 6: syncdir not found
+ */
+int sync_get_file(CmdArgs *args, const char *path, const char *dir, SyncFile *f);
+
 int cmd_add_directory(CmdArgs *args);
 int cmd_list_dirs();
 int cmd_check_repositories();
--- a/libidav/utils.c	Sun Feb 04 15:58:07 2018 +0100
+++ b/libidav/utils.c	Sun Apr 01 12:40:48 2018 +0200
@@ -357,11 +357,11 @@
 #endif
 }
 
-char* util_concat_path(char *url_base, char *p) {
-    sstr_t base = sstr(url_base);
+char* util_concat_path(const char *url_base, const char *p) {
+    sstr_t base = sstr((char*)url_base);
     sstr_t path;
     if(p) {
-        path = sstr(p);
+        path = sstr((char*)p);
     } else {
         path = sstrn("", 0);
     }
--- a/libidav/utils.h	Sun Feb 04 15:58:07 2018 +0100
+++ b/libidav/utils.h	Sun Apr 01 12:40:48 2018 +0200
@@ -68,7 +68,7 @@
 char* util_url_path(char *url);
 char* util_url_decode(DavSession *sn, char *url);
 char* util_resource_name(char *url);
-char* util_concat_path(char *url_base, char *path);
+char* util_concat_path(const char *url_base, const char *path);
 char* util_get_url(DavSession *sn, char *href);
 void util_set_url(DavSession *sn, char *href);
 

mercurial