130 ret = cmd_empty_trash(args); |
130 ret = cmd_empty_trash(args); |
131 } else if(!strcmp(cmd, "add-tag")) { |
131 } else if(!strcmp(cmd, "add-tag")) { |
132 ret = cmd_add_tag(args); |
132 ret = cmd_add_tag(args); |
133 } else if(!strcmp(cmd, "remove-tag")) { |
133 } else if(!strcmp(cmd, "remove-tag")) { |
134 ret = cmd_remove_tag(args); |
134 ret = cmd_remove_tag(args); |
135 } else if(!strcmp(cmd, "update-tags")) { |
135 } else if(!strcmp(cmd, "set-tags")) { |
136 ret = cmd_update_tags(args); |
136 ret = cmd_set_tags(args); |
137 } else if(!strcmp(cmd, "list-tags")) { |
137 } else if(!strcmp(cmd, "list-tags")) { |
138 ret = cmd_list_tags(args); |
138 ret = cmd_list_tags(args); |
139 } else if(!strcmp(cmd, "add-dir") |
139 } else if(!strcmp(cmd, "add-dir") |
140 || !strcmp(cmd, "add-directory")) { |
140 || !strcmp(cmd, "add-directory")) { |
141 ret = cmd_add_directory(args); |
141 ret = cmd_add_directory(args); |
165 |
165 |
166 void print_usage(char *cmd) { |
166 void print_usage(char *cmd) { |
167 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd); |
167 fprintf(stderr, "Usage: %s command [options] arguments...\n\n", cmd); |
168 |
168 |
169 fprintf(stderr, "Commands:\n"); |
169 fprintf(stderr, "Commands:\n"); |
170 fprintf(stderr, " pull [-cld] <directory>\n"); |
170 fprintf(stderr, " pull [-cld] [-t <tags>] <directory>\n"); |
171 fprintf(stderr, " push [-cld] <directory>\n"); |
171 fprintf(stderr, " push [-cld] [-t <tags>] <directory>\n"); |
172 fprintf(stderr, " archive [-cld] <directory>\n"); |
172 fprintf(stderr, " archive [-cld] <directory>\n"); |
173 fprintf(stderr, " resolve-conflicts <directory>\n"); |
173 fprintf(stderr, " resolve-conflicts <directory>\n"); |
174 fprintf(stderr, " delete-conflicts <directory>\n"); |
174 fprintf(stderr, " delete-conflicts <directory>\n"); |
175 fprintf(stderr, " trash-info <directory>\n"); |
175 fprintf(stderr, " trash-info <directory>\n"); |
176 fprintf(stderr, " empty-trash <directory>\n"); |
176 fprintf(stderr, " empty-trash <directory>\n"); |
177 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n"); |
177 fprintf(stderr, " add-tag [-s <syncdir>] <file> <tag>\n"); |
178 fprintf(stderr, " remove-tag [-s <syncdir>] <file> <tag>\n"); |
178 fprintf(stderr, " remove-tag [-s <syncdir>] <file> <tag>\n"); |
179 fprintf(stderr, " update-tags [-s <syncdir>] <file> [tags]\n"); |
179 fprintf(stderr, " set-tags [-s <syncdir>] <file> [tags]\n"); |
180 fprintf(stderr, " list-tags [-s <syncdir>] <file>\n\n"); |
180 fprintf(stderr, " list-tags [-s <syncdir>] <file>\n\n"); |
181 |
181 |
182 fprintf(stderr, "Options:\n"); |
182 fprintf(stderr, "Options:\n"); |
183 fprintf(stderr, " -c Disable conflict detection\n"); |
183 fprintf(stderr, " -c Disable conflict detection\n"); |
184 fprintf(stderr, " -l Lock the repository before access\n"); |
184 fprintf(stderr, " -l Lock the repository before access\n"); |
185 fprintf(stderr, " -d Don't lock the repository\n"); |
185 fprintf(stderr, " -d Don't lock the repository\n"); |
186 //fprintf(stderr, " -r Read changes from stdin\n\n"); |
186 fprintf(stderr, " -t <tags> " |
|
187 "Only sync files which have the specified tags\n"); |
|
188 fprintf(stderr, " -r " |
|
189 "Remove resources not matching the tag filter\n"); |
187 fprintf(stderr, " -v verbose output (all commands)\n\n"); |
190 fprintf(stderr, " -v verbose output (all commands)\n\n"); |
188 |
191 |
189 fprintf(stderr, "Config commands:\n"); |
192 fprintf(stderr, "Config commands:\n"); |
190 fprintf(stderr, " add-directory\n"); |
193 fprintf(stderr, " add-directory\n"); |
191 fprintf(stderr, " list-directories\n"); |
194 fprintf(stderr, " list-directories\n"); |
247 } |
250 } |
248 } |
251 } |
249 return 0; |
252 return 0; |
250 } |
253 } |
251 } |
254 } |
|
255 return 1; |
|
256 } |
|
257 |
|
258 static int matches_tags(UcxList *resource_tags, UcxList *tags) { |
|
259 if(!tags) { |
|
260 return 1; |
|
261 } |
|
262 if(!resource_tags) { |
|
263 return 0; |
|
264 } |
|
265 |
|
266 UcxMap *res_tagmap = ucx_map_new(32); |
|
267 UCX_FOREACH(elm, resource_tags) { |
|
268 DavTag *t = elm->data; |
|
269 // the value actually doesn't matter |
|
270 ucx_map_cstr_put(res_tagmap, t->name, t); |
|
271 } |
|
272 |
|
273 int ret = 1; |
|
274 |
|
275 // TODO: replace FOREACH with new tag expression evaluation |
|
276 UCX_FOREACH(elm, tags) { |
|
277 DavTag *matches_tag = elm->data; |
|
278 if(!ucx_map_cstr_get(res_tagmap, matches_tag->name)) { |
|
279 ret = 0; |
|
280 break; |
|
281 } |
|
282 } |
|
283 |
|
284 ucx_map_free(res_tagmap); |
|
285 return ret; |
|
286 } |
|
287 |
|
288 static int res_matches_tags(DavResource *res, UcxList *tags) { |
|
289 if(!tags) { |
|
290 return 1; |
|
291 } |
|
292 |
|
293 DavXmlNode *tagsprop = dav_get_property_ns(res, DAV_NS, "tags"); |
|
294 UcxList *res_tags = parse_dav_xml_taglist(tagsprop); |
|
295 |
|
296 int ret = matches_tags(res_tags, tags); |
|
297 // TODO: free list content |
|
298 ucx_list_free(res_tags); |
|
299 return ret; |
|
300 } |
|
301 |
|
302 static int localres_matches_tags(LocalResource *res, UcxList *tags) { |
|
303 // TODO: implement |
252 return 1; |
304 return 1; |
253 } |
305 } |
254 |
306 |
255 static DavSession* create_session(DavContext *ctx, Repository *repo, char *url) { |
307 static DavSession* create_session(DavContext *ctx, Repository *repo, char *url) { |
256 DavSession *sn = dav_session_new_auth( |
308 DavSession *sn = dav_session_new_auth( |
287 fprintf(stderr, "%sarchive", sep); |
339 fprintf(stderr, "%sarchive", sep); |
288 } |
340 } |
289 fprintf(stderr, "\n"); |
341 fprintf(stderr, "\n"); |
290 } |
342 } |
291 |
343 |
|
344 static void localres_keep(SyncDatabase *db, const char *path) { |
|
345 LocalResource *local = ucx_map_cstr_remove(db->resources, path); |
|
346 if(local) { |
|
347 local->keep = TRUE; |
|
348 } |
|
349 |
|
350 } |
|
351 |
292 int cmd_pull(CmdArgs *a) { |
352 int cmd_pull(CmdArgs *a) { |
293 if(a->argc != 1) { |
353 if(a->argc != 1) { |
294 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); |
354 fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few" : "many"); |
295 return -1; |
355 return -1; |
296 } |
356 } |
411 if (res_matches_filter(dir, res->path)) { |
478 if (res_matches_filter(dir, res->path)) { |
412 res = res->next; |
479 res = res->next; |
413 continue; |
480 continue; |
414 } |
481 } |
415 |
482 |
|
483 if (!res_matches_tags(res, tags)) { |
|
484 if(!rm_tagmismatch) { |
|
485 localres_keep(db, res->path); |
|
486 } |
|
487 res = res->next; |
|
488 continue; |
|
489 } |
|
490 |
416 char *status = dav_get_string_property(res, "idav:status"); |
491 char *status = dav_get_string_property(res, "idav:status"); |
417 if(status && !strcmp(status, "broken")) { |
492 if(status && !strcmp(status, "broken")) { |
418 res = res->next; |
493 res = res->next; |
|
494 localres_keep(db, res->path); |
419 continue; |
495 continue; |
420 } |
496 } |
421 |
497 |
422 // download the resource |
498 // download the resource |
423 if(!sync_shutdown && sync_get_resource(a, dir, res, db, &sync_success)) { |
499 if(!sync_shutdown && sync_get_resource(a, dir, res, db, &sync_success)) { |
464 UCX_MAP_FOREACH(key, local, i) { |
540 UCX_MAP_FOREACH(key, local, i) { |
465 if (res_matches_filter(dir, local->path)) { |
541 if (res_matches_filter(dir, local->path)) { |
466 continue; |
542 continue; |
467 } |
543 } |
468 |
544 |
469 if(sync_shutdown) { |
545 if(sync_shutdown || local->keep) { |
470 ucx_map_cstr_put(svrres, local->path, local_resource_copy(local)); |
546 ucx_map_cstr_put(svrres, local->path, local_resource_copy(local)); |
471 } else { |
547 } else { |
472 // sync_remove_resource does all necessary tests |
548 // sync_remove_resource does all necessary tests |
473 int ret = sync_remove_local_resource(dir, local); |
549 int ret = sync_remove_local_resource(dir, local); |
474 if(ret == -1) { |
550 if(ret == -1) { |
1232 } |
1308 } |
1233 newres->skipped = res->skipped; |
1309 newres->skipped = res->skipped; |
1234 newres->size = res->size; |
1310 newres->size = res->size; |
1235 newres->last_modified = res->last_modified; |
1311 newres->last_modified = res->last_modified; |
1236 newres->isdirectory = res->isdirectory; |
1312 newres->isdirectory = res->isdirectory; |
|
1313 if(res->tags_hash) { |
|
1314 newres->tags_hash = strdup(res->tags_hash); |
|
1315 } |
|
1316 newres->tags_updated = res->tags_updated; |
1237 return newres; |
1317 return newres; |
1238 } |
1318 } |
1239 |
1319 |
1240 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
1320 int local_resource_is_changed(SyncDirectory *dir, SyncDatabase *db, LocalResource *res) { |
1241 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); |
1321 LocalResource *db_res = ucx_map_cstr_get(db->resources, res->path); |
2137 return -1; |
2217 return -1; |
2138 } |
2218 } |
2139 return cmd_tagopt(args, CMD_TAG_REMOVE); |
2219 return cmd_tagopt(args, CMD_TAG_REMOVE); |
2140 } |
2220 } |
2141 |
2221 |
2142 int cmd_update_tags(CmdArgs *args) { |
2222 int cmd_set_tags(CmdArgs *args) { |
2143 if(args->argc < 1 || args->argc > 2) { |
2223 if(args->argc < 1 || args->argc > 2) { |
2144 fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many"); |
2224 fprintf(stderr, "Too %s arguments\n", args->argc < 1 ? "few" : "many"); |
2145 return -1; |
2225 return -1; |
2146 } |
2226 } |
2147 return cmd_tagopt(args, CMD_TAG_UPDATE); |
2227 return cmd_tagopt(args, CMD_TAG_SET); |
2148 } |
2228 } |
2149 |
2229 |
2150 int cmd_list_tags(CmdArgs *args) { |
2230 int cmd_list_tags(CmdArgs *args) { |
2151 if(args->argc != 1) { |
2231 if(args->argc != 1) { |
2152 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2232 fprintf(stderr, "Too %s arguments\n", args->argc <= 1 ? "few" : "many"); |
2179 |
2259 |
2180 LocalResource *localres = ucx_map_cstr_get(db->resources, file.path); |
2260 LocalResource *localres = ucx_map_cstr_get(db->resources, file.path); |
2181 UcxList *tags = NULL; |
2261 UcxList *tags = NULL; |
2182 DavBool store_tags = FALSE; |
2262 DavBool store_tags = FALSE; |
2183 |
2263 |
2184 if(cmd != CMD_TAG_UPDATE) { |
2264 if(cmd != CMD_TAG_SET) { |
2185 char *tag = args->argv[1]; |
2265 char *tag = args->argv[1]; |
2186 char *tagcolor = NULL; // TODO: get color |
2266 char *tagcolor = NULL; // TODO: get color |
2187 |
2267 |
2188 tags = sync_get_file_tags(file.dir, localres, NULL); |
2268 tags = sync_get_file_tags(file.dir, localres, NULL); |
2189 UcxList *x = NULL; |
2269 UcxList *x = NULL; |