summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoris Vink <joris@cvs.openbsd.org>2007-01-28 02:04:46 +0000
committerJoris Vink <joris@cvs.openbsd.org>2007-01-28 02:04:46 +0000
commit36c64f8f20b0a2ff5a43fbf4f9a23b6aa3f65652 (patch)
tree967c1006924cdd47b4617230271dfaaa39498cf6
parentfbed64cc1fb56f9ce86017aab6f2a884eebf6472 (diff)
add merging support in both local and remote sides.
tested by many, thanks.
-rw-r--r--usr.bin/cvs/checkout.c75
-rw-r--r--usr.bin/cvs/client.c71
-rw-r--r--usr.bin/cvs/diff.h4
-rw-r--r--usr.bin/cvs/diff3.c94
-rw-r--r--usr.bin/cvs/file.c3
-rw-r--r--usr.bin/cvs/update.c7
6 files changed, 172 insertions, 82 deletions
diff --git a/usr.bin/cvs/checkout.c b/usr.bin/cvs/checkout.c
index 6d015699fe8..94553a4630c 100644
--- a/usr.bin/cvs/checkout.c
+++ b/usr.bin/cvs/checkout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: checkout.c,v 1.86 2007/01/26 21:59:11 otto Exp $ */
+/* $OpenBSD: checkout.c,v 1.87 2007/01/28 02:04:45 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
@@ -203,9 +203,12 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int co_flags)
time_t rcstime;
CVSENTRIES *ent;
struct timeval tv[2];
+ char *tosend;
char template[MAXPATHLEN], *p, entry[CVS_ENT_MAXLINELEN], rev[16];
char timebuf[64], kbuf[8], tbuf[32], stickytag[32];
+ exists = 0;
+ tosend = NULL;
rcsnum_tostr(rnum, rev, sizeof(rev));
cvs_log(LP_TRACE, "cvs_checkout_file(%s, %s, %d) -> %s",
@@ -223,26 +226,34 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int co_flags)
return;
}
+ if (co_flags & CO_MERGE)
+ printf("merge on %s\n", cf->file_path);
+
if (cvs_server_active == 0) {
- oflags = O_WRONLY | O_TRUNC;
- if (cf->fd != -1) {
- exists = 1;
- (void)close(cf->fd);
- } else {
- exists = 0;
- oflags |= O_CREAT;
+ if (!(co_flags & CO_MERGE)) {
+ oflags = O_WRONLY | O_TRUNC;
+ if (cf->fd != -1) {
+ exists = 1;
+ (void)close(cf->fd);
+ } else {
+ oflags |= O_CREAT;
+ }
+
+ cf->fd = open(cf->file_path, oflags);
+ if (cf->fd == -1)
+ fatal("cvs_checkout_file: open: %s",
+ strerror(errno));
+
+ rcs_rev_write_fd(cf->file_rcs, rnum, cf->fd, 1);
+ } else {
+ cvs_merge_file(cf, 1);
}
- cf->fd = open(cf->file_path, oflags);
- if (cf->fd == -1)
- fatal("cvs_checkout_file: open: %s", strerror(errno));
-
- rcs_rev_write_fd(cf->file_rcs, rnum, cf->fd, 1);
-
if (fchmod(cf->fd, 0644) == -1)
fatal("cvs_checkout_file: fchmod: %s", strerror(errno));
- if (exists == 0 && cf->file_ent == NULL)
+ if ((exists == 0) && (cf->file_ent == NULL) &&
+ !(co_flags & CO_MERGE))
rcstime = rcs_rev_getdate(cf->file_rcs, rnum);
else
time(&rcstime);
@@ -300,23 +311,39 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int co_flags)
if ((p = strrchr(cf->file_rpath, ',')) != NULL)
*p = '\0';
+ if (co_flags & CO_MERGE) {
+ cvs_merge_file(cf, 1);
+ tosend = cf->file_path;
+ }
+
if (co_flags & CO_COMMIT)
cvs_server_update_entry("Checked-in", cf);
+ else if (co_flags & CO_MERGE)
+ cvs_server_update_entry("Merged", cf);
else
cvs_server_update_entry("Updated", cf);
cvs_remote_output(entry);
if (!(co_flags & CO_COMMIT)) {
- l = snprintf(template, MAXPATHLEN,
- "%s/checkout.XXXXXXXXXX", cvs_tmpdir);
- if (l == -1 || l >= (int)sizeof(template))
- fatal("cvs_checkout_file: overflow");
-
- /* XXX - fd race below */
- rcs_rev_write_stmp(cf->file_rcs, rnum, template, 0);
- cvs_remote_send_file(template);
- cvs_worklist_run(&temp_files, cvs_worklist_unlink);
+ if (!(co_flags & CO_MERGE)) {
+ l = snprintf(template, MAXPATHLEN,
+ "%s/checkout.XXXXXXXXXX", cvs_tmpdir);
+ if (l == -1 || l >= MAXPATHLEN)
+ fatal("cvs_Checkout_file: overflow");
+ rcs_rev_write_stmp(cf->file_rcs, rnum,
+ template, 0);
+ tosend = template;
+ }
+
+ cvs_remote_send_file(tosend);
+
+ if (!(co_flags & CO_MERGE)) {
+ (void)unlink(template);
+ cvs_worklist_run(&temp_files,
+ cvs_worklist_unlink);
+ xfree(template);
+ }
}
if (p != NULL)
diff --git a/usr.bin/cvs/client.c b/usr.bin/cvs/client.c
index 0d105d25d46..d4618d1a678 100644
--- a/usr.bin/cvs/client.c
+++ b/usr.bin/cvs/client.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: client.c,v 1.55 2007/01/27 19:38:19 otto Exp $ */
+/* $OpenBSD: client.c,v 1.56 2007/01/28 02:04:45 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
@@ -457,6 +457,9 @@ cvs_client_sendfile(struct cvs_file *cf)
sizeof(timebuf));
if (len >= sizeof(timebuf))
fatal("cvs_client_sendfile: truncation");
+ len = strlcat(timebuf, "+", sizeof(timebuf));
+ if (len >= sizeof(timebuf))
+ fatal("cvs_client_sendfile: truncation");
}
sticky[0] = '\0';
@@ -682,6 +685,72 @@ cvs_client_updated(char *data)
void
cvs_client_merged(char *data)
{
+ int fd;
+ time_t now;
+ mode_t fmode;
+ size_t flen;
+ CVSENTRIES *ent;
+ const char *errstr;
+ struct timeval tv[2];
+ char timebuf[32], *repo, *rpath, *entry, *mode;
+ char *len, *fpath, *wdir;
+
+ client_check_directory(data);
+
+ rpath = cvs_remote_input();
+ entry = cvs_remote_input();
+ mode = cvs_remote_input();
+ len = cvs_remote_input();
+
+ repo = xmalloc(MAXPATHLEN);
+ cvs_get_repository_path(".", repo, MAXPATHLEN);
+
+ STRIP_SLASH(repo);
+
+ if (strlen(repo) + 1 > strlen(rpath))
+ fatal("received a repository path that is too short");
+
+ fpath = rpath + strlen(repo) + 1;
+ if ((wdir = dirname(fpath)) == NULL)
+ fatal("cvs_client_merged: dirname: %s", strerror(errno));
+ xfree(repo);
+
+ flen = strtonum(len, 0, INT_MAX, &errstr);
+ if (errstr != NULL)
+ fatal("cvs_client_merged: %s: %s", len, errstr);
+ xfree(len);
+
+ cvs_strtomode(mode, &fmode);
+ xfree(mode);
+
+ time(&now);
+ asctime_r(gmtime(&now), timebuf);
+ if (timebuf[strlen(timebuf) - 1] == '\n')
+ timebuf[strlen(timebuf) - 1] = '\0';
+
+ ent = cvs_ent_open(wdir);
+ cvs_ent_add(ent, entry);
+ cvs_ent_close(ent, ENT_SYNC);
+
+ if ((fd = open(fpath, O_CREAT | O_WRONLY | O_TRUNC)) == -1)
+ fatal("cvs_client_merged: open: %s: %s",
+ fpath, strerror(errno));
+
+ cvs_remote_receive_file(fd, flen);
+
+ tv[0].tv_sec = now;
+ tv[0].tv_usec = 0;
+ tv[1] = tv[0];
+
+ if (futimes(fd, tv) == -1)
+ fatal("cvs_client_merged: futimes: %s", strerror(errno));
+
+ if (fchmod(fd, fmode) == -1)
+ fatal("cvs_client_merged: fchmod: %s", strerror(errno));
+
+ (void)close(fd);
+
+ xfree(rpath);
}
void
diff --git a/usr.bin/cvs/diff.h b/usr.bin/cvs/diff.h
index 6f938614704..16d272fdef3 100644
--- a/usr.bin/cvs/diff.h
+++ b/usr.bin/cvs/diff.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: diff.h,v 1.13 2006/06/14 14:10:50 joris Exp $ */
+/* $OpenBSD: diff.h,v 1.14 2007/01/28 02:04:45 joris Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
* All rights reserved.
@@ -91,7 +91,7 @@
#define D_SKIPPED1 8 /* path1 was a special file */
#define D_SKIPPED2 9 /* path2 was a special file */
-BUF *cvs_diff3(RCSFILE *, char *, int, RCSNUM *, RCSNUM *, int);
+void cvs_merge_file(struct cvs_file *, int);
void diff_output(const char *, ...);
int cvs_diffreg(const char *, const char *, BUF *out);
int ed_patch_lines(struct cvs_lines *, struct cvs_lines *);
diff --git a/usr.bin/cvs/diff3.c b/usr.bin/cvs/diff3.c
index b7a43e097aa..9d2718a0a4b 100644
--- a/usr.bin/cvs/diff3.c
+++ b/usr.bin/cvs/diff3.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: diff3.c,v 1.32 2007/01/12 23:32:01 niallo Exp $ */
+/* $OpenBSD: diff3.c,v 1.33 2007/01/28 02:04:45 joris Exp $ */
/*
* Copyright (C) Caldera International Inc. 2001-2002.
@@ -72,7 +72,7 @@ static const char copyright[] =
#ifndef lint
static const char rcsid[] =
- "$OpenBSD: diff3.c,v 1.32 2007/01/12 23:32:01 niallo Exp $";
+ "$OpenBSD: diff3.c,v 1.33 2007/01/28 02:04:45 joris Exp $";
#endif /* not lint */
#include "includes.h"
@@ -133,7 +133,7 @@ static int last[4];
static int eflag;
static int oflag; /* indicates whether to mark overlaps (-E or -X)*/
static int debug = 0;
-static char f1mark[40], f3mark[40]; /* markers for -E and -X */
+static char f1mark[MAXPATHLEN], f3mark[MAXPATHLEN]; /* markers for -E and -X */
static int duplicate(struct range *, struct range *);
static int edit(struct diff *, int, int);
@@ -154,9 +154,8 @@ static int diff3_internal(int, char **, const char *, const char *);
int diff3_conflicts = 0;
-BUF *
-cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1,
- RCSNUM *rev2, int verbose)
+void
+cvs_merge_file(struct cvs_file *cf, int verbose)
{
int argc;
char *data, *patch;
@@ -164,19 +163,25 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1,
char *dp13, *dp23, *path1, *path2, *path3;
BUF *b1, *b2, *b3, *d1, *d2, *diffb;
size_t dlen, plen;
+ struct cvs_line *lp;
+ struct cvs_lines *dlines, *plines;
b1 = b2 = b3 = d1 = d2 = diffb = NULL;
+ rcsnum_tostr(cf->file_ent->ce_rev, r1, sizeof(r1));
+ rcsnum_tostr(cf->file_rcsrev, r2, sizeof(r2));
- rcsnum_tostr(rev1, r1, sizeof(r1));
- rcsnum_tostr(rev2, r2, sizeof(r2));
-
- if ((b1 = cvs_buf_load_fd(workfd, BUF_AUTOEXT)) == NULL)
- goto out;
-
+ b1 = cvs_buf_load_fd(cf->fd, BUF_AUTOEXT);
d1 = cvs_buf_alloc((size_t)128, BUF_AUTOEXT);
d2 = cvs_buf_alloc((size_t)128, BUF_AUTOEXT);
diffb = cvs_buf_alloc((size_t)128, BUF_AUTOEXT);
+ (void)close(cf->fd);
+ cf->fd = open(cf->file_path, O_WRONLY | O_TRUNC);
+ if (cf->fd == -1) {
+ fatal("cvs_merge_file: failed to reopen fd for writing: %s",
+ strerror(errno));
+ }
+
(void)xasprintf(&path1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
(void)xasprintf(&path2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
(void)xasprintf(&path3, "%s/diff3.XXXXXXXXXX", cvs_tmpdir);
@@ -184,25 +189,21 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1,
cvs_buf_write_stmp(b1, path1, NULL);
if (verbose == 1)
cvs_printf("Retrieving revision %s\n", r1);
- rcs_rev_write_stmp(rf, rev1, path2, 0);
+ rcs_rev_write_stmp(cf->file_rcs, cf->file_ent->ce_rev, path2, 0);
if (verbose == 1)
cvs_printf("Retrieving revision %s\n", r2);
- rcs_rev_write_stmp(rf, rev2, path3, 0);
+ rcs_rev_write_stmp(cf->file_rcs, cf->file_rcsrev, path3, 0);
cvs_diffreg(path1, path3, d1);
cvs_diffreg(path2, path3, d2);
(void)xasprintf(&dp13, "%s/d13.XXXXXXXXXX", cvs_tmpdir);
cvs_buf_write_stmp(d1, dp13, NULL);
-
cvs_buf_free(d1);
- d1 = NULL;
(void)xasprintf(&dp23, "%s/d23.XXXXXXXXXX", cvs_tmpdir);
cvs_buf_write_stmp(d2, dp23, NULL);
-
cvs_buf_free(d2);
- d2 = NULL;
argc = 0;
diffbuf = diffb;
@@ -212,21 +213,22 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1,
argv[argc++] = path2;
argv[argc++] = path3;
- diff3_conflicts = diff3_internal(argc, argv, workfile, r2);
- if (diff3_conflicts < 0) {
- cvs_buf_free(diffb);
- diffb = NULL;
- goto out;
- }
+ diff3_conflicts = diff3_internal(argc, argv, cf->file_path, r2);
+ if (diff3_conflicts < 0)
+ fatal("cvs_merge_file: merging failed for an unknown reason");
plen = cvs_buf_len(diffb);
patch = cvs_buf_release(diffb);
dlen = cvs_buf_len(b1);
data = cvs_buf_release(b1);
- diffb = b1 = NULL;
- if ((diffb = cvs_patchfile(data, dlen, patch, plen, ed_patch_lines)) == NULL)
- goto out;
+ cvs_printf("Merging differences between %s and %s into `%s'\n",
+ r1, r2, cf->file_path);
+
+ dlines = cvs_splitlines(data, dlen);
+ plines = cvs_splitlines(patch, plen);
+ ed_patch_lines(dlines, plines);
+ cvs_freelines(plines);
if (verbose == 1 && diff3_conflicts != 0) {
cvs_log(LP_ERR, "%d conflict%s found during merge, "
@@ -234,16 +236,19 @@ cvs_diff3(RCSFILE *rf, char *workfile, int workfd, RCSNUM *rev1,
(diff3_conflicts > 1) ? "s" : "");
}
- xfree(data);
- xfree(patch);
+ TAILQ_FOREACH(lp, &(dlines->l_lines), l_list) {
+ if (lp->l_line == NULL)
+ continue;
-out:
- if (b1 != NULL)
- cvs_buf_free(b1);
- if (d1 != NULL)
- cvs_buf_free(d1);
- if (d2 != NULL)
- cvs_buf_free(d2);
+ if (write(cf->fd, lp->l_line, lp->l_len) == -1)
+ fatal("cvs_merge_file: %s", strerror(errno));
+ }
+
+ cvs_freelines(dlines);
+
+ if (data != NULL)
+ xfree(data);
+ xfree(patch);
(void)unlink(path1);
(void)unlink(path2);
@@ -251,18 +256,11 @@ out:
(void)unlink(dp13);
(void)unlink(dp23);
- if (path1 != NULL)
- xfree(path1);
- if (path2 != NULL)
- xfree(path2);
- if (path3 != NULL)
- xfree(path3);
- if (dp13 != NULL)
- xfree(dp13);
- if (dp23 != NULL)
- xfree(dp23);
-
- return (diffb);
+ xfree(path1);
+ xfree(path2);
+ xfree(path3);
+ xfree(dp13);
+ xfree(dp23);
}
static int
diff --git a/usr.bin/cvs/file.c b/usr.bin/cvs/file.c
index 22174d3ca99..e6d99d5831e 100644
--- a/usr.bin/cvs/file.c
+++ b/usr.bin/cvs/file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.c,v 1.179 2007/01/27 20:21:25 joris Exp $ */
+/* $OpenBSD: file.c,v 1.180 2007/01/28 02:04:45 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
@@ -680,6 +680,7 @@ cvs_file_classify(struct cvs_file *cf, const char *tag, int loud)
}
if (ismodified == 1 && cf->fd != -1 && cf->file_rcs != NULL) {
+ printf("oh what on `%s'\n", cf->file_path);
b1 = rcs_rev_getbuf(cf->file_rcs, cf->file_rcsrev, 0);
if (b1 == NULL)
fatal("failed to get HEAD revision for comparison");
diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c
index c94d294d965..ba5f0c2d4c2 100644
--- a/usr.bin/cvs/update.c
+++ b/usr.bin/cvs/update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: update.c,v 1.89 2007/01/25 18:56:33 otto Exp $ */
+/* $OpenBSD: update.c,v 1.90 2007/01/28 02:04:45 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
@@ -339,10 +339,6 @@ cvs_update_local(struct cvs_file *cf)
cvs_printf("U %s\n", cf->file_path);
break;
case FILE_MERGE:
-#if 0
- cvs_diff3(cf->file_rcs, cf->file_path, cf->fd,
- cf->file_ent->ce_rev, cf->file_rcsrev, 1);
-
cvs_checkout_file(cf, cf->file_rcsrev, CO_MERGE);
if (diff3_conflicts != 0) {
@@ -351,7 +347,6 @@ cvs_update_local(struct cvs_file *cf)
update_clear_conflict(cf);
cvs_printf("M %s\n", cf->file_path);
}
-#endif
break;
case FILE_UNLINK:
(void)unlink(cf->file_path);