summaryrefslogtreecommitdiffstats
path: root/src/merge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/merge.c')
-rw-r--r--src/merge.c131
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;