diff options
author | Joris Vink <joris@cvs.openbsd.org> | 2007-01-28 02:04:46 +0000 |
---|---|---|
committer | Joris Vink <joris@cvs.openbsd.org> | 2007-01-28 02:04:46 +0000 |
commit | 36c64f8f20b0a2ff5a43fbf4f9a23b6aa3f65652 (patch) | |
tree | 967c1006924cdd47b4617230271dfaaa39498cf6 | |
parent | fbed64cc1fb56f9ce86017aab6f2a884eebf6472 (diff) |
add merging support in both local and remote sides.
tested by many, thanks.
-rw-r--r-- | usr.bin/cvs/checkout.c | 75 | ||||
-rw-r--r-- | usr.bin/cvs/client.c | 71 | ||||
-rw-r--r-- | usr.bin/cvs/diff.h | 4 | ||||
-rw-r--r-- | usr.bin/cvs/diff3.c | 94 | ||||
-rw-r--r-- | usr.bin/cvs/file.c | 3 | ||||
-rw-r--r-- | usr.bin/cvs/update.c | 7 |
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); |