diff options
Diffstat (limited to 'src/merge.c')
-rw-r--r-- | src/merge.c | 131 |
1 files changed, 80 insertions, 51 deletions
diff --git a/src/merge.c b/src/merge.c index c37cb53..b281b06 100644 --- a/src/merge.c +++ b/src/merge.c @@ -44,6 +44,7 @@ struct cb_info { static int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, void *p) { struct cb_info *cb_info = p; struct syrep_md md1, md2; + int writeback = 0; int f1, f2; char path[PATH_MAX+1]; @@ -62,18 +63,73 @@ static int conflict_phase(DB *ddb, struct syrep_name *name, struct diff_entry *d if (f1 && f2) { char d1[SYREP_DIGESTLENGTH*2+1], d2[SYREP_DIGESTLENGTH*2+1]; + int q; fhex(md1.digest, SYREP_DIGESTLENGTH, d1); fhex(md2.digest, SYREP_DIGESTLENGTH, d2); d1[SYREP_DIGESTLENGTH*2] = d2[SYREP_DIGESTLENGTH*2] = 0; - fprintf(stderr, "CONFLICT: New file '%s' apparead: %s in A vs. %s in B\n", path, d1, d2); + fprintf(stderr, "CONFLICT: New file '%s': %s in *local* vs. %s in *remote* repository.\n", path, d2, d1); + + if (!(q = question("Replace in local repository?", "ny"))) + return -1; + + if (q == 'y') { + de->action = DIFF_REPLACE; + de->repository = cb_info->c1; + writeback = 1; + } + } else if (f1 || f2) { char d[SYREP_DIGESTLENGTH*2+1]; + fhex(f1 ? md1.digest : md2.digest, SYREP_DIGESTLENGTH, d); d[SYREP_DIGESTLENGTH*2] = 0; - fprintf(stderr, "CONFLICT: File '%s' (%s) appeared in %c, removed in %c\n", path, d, f1 ? 'A' : 'B', f2 ? 'A' : 'B'); + fprintf(stderr, "CONFLICT: File '%s' (%s) appeared in *%s*, removed in *%s* repository.\n", path, d, f1 ? "remote" : "local", f2 ? "remote" : "local"); + + if (f1) { + int q; + + if (!(q = question("Add to local repository?", "yn"))) + return -1; + + if (q == 'y') { + de->action = DIFF_COPY; + de->repository = cb_info->c1; + writeback = 1; + } + } else { + int q; + + if (!(q = question("Remove from local repository?", "ny"))) + return -1; + + if (q == 'y') { + de->action = DIFF_DELETE; + de->repository = cb_info->c2; + writeback = 1; + } + } + } + + if (writeback) { + DBT key, data; + int ret; + + memset(&key, 0, sizeof(key)); + memset(&data, 0, sizeof(data)); + + key.data = (void*) name; + key.size = sizeof(struct syrep_name); + + data.data = (void*) de; + data.size = sizeof(struct diff_entry); + + if ((ret = ddb->put(ddb, NULL, &key, &data, 0))) { + ddb->err(ddb, ret, "ddb::put()"); + return -1; + } } return 0; @@ -112,7 +168,7 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v assert(ddb && name && de && p); - if (de->action != DIFF_COPY) + if (de->action != DIFF_COPY && de->action != DIFF_REPLACE) return 0; if (de->repository == cb_info->c2) @@ -153,7 +209,7 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v escape_path(name2.path, path2+l, sizeof(path2)-l); if (!access(path2, R_OK)) { - if (copy_or_link_file(path2, path, 0) < 0) + if (copy_or_link_file(path2, path, de->action == DIFF_REPLACE) < 0) return -1; } @@ -169,7 +225,7 @@ static int copy_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, v if (makeprefixpath(path, 0777) < 0) return -1; - if (copy_or_link_file(a, path, 0) < 0) + if (copy_or_link_file(a, path, de->action == DIFF_REPLACE) < 0) return -1; } else fprintf(stderr, "COPY: File <%s> is missing.\n", name->path); @@ -191,6 +247,19 @@ static int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, if (de->repository == cb_info->c1) return 0; + if (args.question_flag) { + char text[256]; + int q; + + snprintf(text, sizeof(text), "Delete %s?", name->path); + + if ((q = question(text, "yn")) < 0) + return -1; + + if (q != 'y') + return 0; + } + snprintf(path, sizeof(path), "%s/%s", cb_info->root, name->path); snprintf(target, sizeof(target), "%s/", cb_info->trash_dir); @@ -209,47 +278,6 @@ static int delete_phase(DB *ddb, struct syrep_name *name, struct diff_entry *de, return 0; } -static int empty_trash(const char *trash) { - DIR *dir = NULL; - int r = -1; - struct dirent *de; - - if (!(dir = opendir(trash))) { - fprintf(stderr, "opendir(\"%s\"): %s", trash, strerror(errno)); - goto finish; - } - - while ((de = readdir(dir))) { - char path[PATH_MAX]; - - if (!strcmp(de->d_name, ".")) - continue; - - if (!strcmp(de->d_name, "..")) - continue; - - snprintf(path, sizeof(path), "%s/%s", trash, de->d_name); - - if (unlink(path) < 0) { - fprintf(stderr, "unlink(\"%s\"): %s\n", path, strerror(errno)); - goto finish; - } - } - - if (rmdir(trash) < 0) { - fprintf(stderr, "rmdir(\"%s\"): %s\n", trash, strerror(errno)); - goto finish; - } - - r = 0; - -finish: - if (dir) - closedir(dir); - - return r; -} - /* Merges c1 into c2 in directory "root" */ int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* root) { struct cb_info cb_info; @@ -260,9 +288,9 @@ int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* cb_info.c1 = c1; cb_info.c2 = c2; cb_info.root = root; - - snprintf(cb_info.trash_dir, sizeof(cb_info.trash_dir), "%s/.syrep-trash", root); - mkdir(cb_info.trash_dir, 0777); + + snprintf(cb_info.trash_dir, sizeof(cb_info.trash_dir), "%s/.syrep/trash", root); + mkdir_p(cb_info.trash_dir, 0777); if (!(ddb = make_diff(c1, c2))) goto finish; @@ -276,8 +304,9 @@ int merge(struct syrep_db_context *c1, struct syrep_db_context *c2, const char* if (diff_foreach(ddb, copy_phase, &cb_info) < 0) goto finish; - if (empty_trash(cb_info.trash_dir) < 0) - goto finish; + if (!args.keep_trash_flag) + if (rm_rf(cb_info.trash_dir, 0) < 0) + goto finish; r = 0; |