summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--usr.bin/cvs/checkout.c39
-rw-r--r--usr.bin/cvs/commit.c14
-rw-r--r--usr.bin/cvs/cvs.h7
-rw-r--r--usr.bin/cvs/rcs.h5
-rw-r--r--usr.bin/cvs/update.c117
5 files changed, 152 insertions, 30 deletions
diff --git a/usr.bin/cvs/checkout.c b/usr.bin/cvs/checkout.c
index 187eb933b78..f44664d686c 100644
--- a/usr.bin/cvs/checkout.c
+++ b/usr.bin/cvs/checkout.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: checkout.c,v 1.57 2006/05/27 16:10:01 joris Exp $ */
+/* $OpenBSD: checkout.c,v 1.58 2006/05/28 01:24:28 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
@@ -110,28 +110,22 @@ checkout_repository(const char *repobase, const char *wdbase)
cvs_file_freelist(&dl);
}
-int
-cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int flags)
+void
+cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, BUF *bp, int flags)
{
- BUF *bp;
+ BUF *nbp;
int l, oflags, exists;
time_t rcstime;
CVSENTRIES *ent;
struct timeval tv[2];
- char *entry, rev[16], timebuf[32];
+ char *entry, rev[16], timebuf[64], tbuf[32];
rcsnum_tostr(rnum, rev, sizeof(rev));
cvs_log(LP_TRACE, "cvs_checkout_file(%s, %s, %d)",
cf->file_path, rev, flags);
- if ((bp = rcs_getrev(cf->file_rcs, rnum)) == NULL) {
- cvs_log(LP_ERR, "%s: cannot find revision %s",
- cf->file_path, rev);
- return (0);
- }
-
- bp = rcs_kwexp_buf(bp, cf->file_rcs, rnum);
+ nbp = rcs_kwexp_buf(bp, cf->file_rcs, rnum);
oflags = O_WRONLY | O_TRUNC;
if (cf->fd != -1) {
@@ -146,10 +140,10 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int flags)
if (cf->fd == -1)
fatal("cvs_checkout_file: open: %s", strerror(errno));
- if (cvs_buf_write_fd(bp, cf->fd) == -1)
+ if (cvs_buf_write_fd(nbp, cf->fd) == -1)
fatal("cvs_checkout_file: %s", strerror(errno));
- cvs_buf_free(bp);
+ cvs_buf_free(nbp);
if (fchmod(cf->fd, 0644) == -1)
fatal("cvs_checkout_file: fchmod: %s", strerror(errno));
@@ -171,9 +165,18 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int flags)
if ((rcstime = cvs_hack_time(rcstime, 1)) == 0)
fatal("cvs_checkout_file: to gmt failed");
- ctime_r(&rcstime, timebuf);
- if (timebuf[strlen(timebuf) - 1] == '\n')
- timebuf[strlen(timebuf) - 1] = '\0';
+ ctime_r(&rcstime, tbuf);
+ if (tbuf[strlen(tbuf) - 1] == '\n')
+ tbuf[strlen(tbuf) - 1] = '\0';
+
+ if (flags & CO_MERGE) {
+ l = snprintf(timebuf, sizeof(timebuf), "Result of merge+%s",
+ tbuf);
+ if (l == -1 || l >= (int)sizeof(timebuf))
+ fatal("cvs_checkout_file: overflow");
+ } else {
+ strlcpy(timebuf, tbuf, sizeof(timebuf));
+ }
entry = xmalloc(CVS_ENT_MAXLINELEN);
l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/%s/%s//", cf->file_name,
@@ -184,6 +187,4 @@ cvs_checkout_file(struct cvs_file *cf, RCSNUM *rnum, int flags)
cvs_ent_close(ent, ENT_SYNC);
xfree(entry);
-
- return (1);
}
diff --git a/usr.bin/cvs/commit.c b/usr.bin/cvs/commit.c
index 1e6c0eac2dd..9e8cce9ca47 100644
--- a/usr.bin/cvs/commit.c
+++ b/usr.bin/cvs/commit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: commit.c,v 1.59 2006/05/27 15:17:42 joris Exp $ */
+/* $OpenBSD: commit.c,v 1.60 2006/05/28 01:24:28 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
@@ -126,6 +126,12 @@ cvs_commit_check_conflicts(struct cvs_file *cf)
cf->file_status == FILE_UNLINK)
conflicts_found++;
+ if (update_has_conflict_markers(cf)) {
+ cvs_log(LP_ERR, "conflict: unresolved conflicts in %s from "
+ "merging, please fix these first", cf->file_path);
+ conflicts_found++;
+ }
+
if (cf->file_status == FILE_MERGE ||
cf->file_status == FILE_PATCH) {
cvs_log(LP_ERR, "conflict: %s is not up-to-date",
@@ -204,7 +210,11 @@ cvs_commit_local(struct cvs_file *cf)
cf->fd = -1;
if (cf->file_status != FILE_REMOVED) {
- cvs_checkout_file(cf, cf->file_rcs->rf_head, 0);
+ b = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head);
+ if (b == NULL)
+ fatal("cvs_commit_local: failed to get HEAD");
+
+ cvs_checkout_file(cf, cf->file_rcs->rf_head, b, 0);
} else {
entlist = cvs_ent_open(cf->file_wd);
cvs_ent_remove(entlist, cf->file_name);
diff --git a/usr.bin/cvs/cvs.h b/usr.bin/cvs/cvs.h
index 19ad84c73c1..41429c40ee4 100644
--- a/usr.bin/cvs/cvs.h
+++ b/usr.bin/cvs/cvs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: cvs.h,v 1.108 2006/05/27 20:57:42 joris Exp $ */
+/* $OpenBSD: cvs.h,v 1.109 2006/05/28 01:24:28 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -347,6 +347,9 @@ void cvsroot_remove(struct cvsroot *);
void cvs_update_local(struct cvs_file *);
void cvs_update_enterdir(struct cvs_file *);
void cvs_update_leavedir(struct cvs_file *);
-int cvs_checkout_file(struct cvs_file *, RCSNUM *, int);
+void cvs_checkout_file(struct cvs_file *, RCSNUM *, BUF *, int);
+int update_has_conflict_markers(struct cvs_file *);
+
+#define CO_MERGE 0x01
#endif
diff --git a/usr.bin/cvs/rcs.h b/usr.bin/cvs/rcs.h
index 5024ed29485..a05961baaa2 100644
--- a/usr.bin/cvs/rcs.h
+++ b/usr.bin/cvs/rcs.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rcs.h,v 1.62 2006/05/27 03:30:31 joris Exp $ */
+/* $OpenBSD: rcs.h,v 1.63 2006/05/28 01:24:28 joris Exp $ */
/*
* Copyright (c) 2004 Jean-Francois Brousseau <jfb@openbsd.org>
* All rights reserved.
@@ -40,6 +40,9 @@
#define RCS_HEAD_INIT "1.1"
#define RCS_HEAD_REV ((RCSNUM *)(-1))
+#define RCS_CONFLICT_MARKER1 "<<<<<<< "
+#define RCS_CONFLICT_MARKER2 ">>>>>>> "
+#define RCS_CONFLICT_MARKER3 "=======\n"
#define RCS_SYM_INVALCHAR "$,.:;@"
diff --git a/usr.bin/cvs/update.c b/usr.bin/cvs/update.c
index df1722e9d06..324dac5ca41 100644
--- a/usr.bin/cvs/update.c
+++ b/usr.bin/cvs/update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: update.c,v 1.64 2006/05/27 21:20:52 joris Exp $ */
+/* $OpenBSD: update.c,v 1.65 2006/05/28 01:24:28 joris Exp $ */
/*
* Copyright (c) 2006 Joris Vink <joris@openbsd.org>
*
@@ -26,6 +26,8 @@ int cvs_update(int, char **);
int prune_dirs = 0;
int build_dirs = 0;
+static void update_clear_conflict(struct cvs_file *);
+
#define UPDATE_SKIP 100
struct cvs_cmd cvs_cmd_update = {
@@ -218,6 +220,8 @@ cvs_update_leavedir(struct cvs_file *cf)
void
cvs_update_local(struct cvs_file *cf)
{
+ int ret;
+ BUF *bp;
CVSENTRIES *entlist;
cvs_log(LP_TRACE, "cvs_update_local(%s)", cf->file_path);
@@ -232,6 +236,11 @@ cvs_update_local(struct cvs_file *cf)
return;
}
+ /*
+ * the bp buffer will be released inside rcs_kwexp_buf,
+ * which is called from cvs_checkout_file().
+ */
+ bp = NULL;
cvs_file_classify(cf);
switch (cf->file_status) {
@@ -239,10 +248,14 @@ cvs_update_local(struct cvs_file *cf)
cvs_printf("? %s\n", cf->file_path);
break;
case FILE_MODIFIED:
- if (cf->file_ent->ce_conflict != NULL)
+ ret = update_has_conflict_markers(cf);
+ if (cf->file_ent->ce_conflict != NULL && ret == 1) {
cvs_printf("C %s\n", cf->file_path);
- else
+ } else {
+ if (cf->file_ent->ce_conflict != NULL && ret == 0)
+ update_clear_conflict(cf);
cvs_printf("M %s\n", cf->file_path);
+ }
break;
case FILE_ADDED:
cvs_printf("A %s\n", cf->file_path);
@@ -256,11 +269,27 @@ cvs_update_local(struct cvs_file *cf)
case FILE_LOST:
case FILE_CHECKOUT:
case FILE_PATCH:
- if (cvs_checkout_file(cf, cf->file_rcs->rf_head, 0))
- cvs_printf("U %s\n", cf->file_path);
+ bp = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head);
+ if (bp == NULL)
+ fatal("cvs_update_local: failed to get HEAD");
+
+ cvs_checkout_file(cf, cf->file_rcs->rf_head, bp, 0);
+ cvs_printf("U %s\n", cf->file_path);
break;
case FILE_MERGE:
- cvs_printf("needs merge: %s\n", cf->file_path);
+ bp = cvs_diff3(cf->file_rcs, cf->file_path,
+ cf->file_ent->ce_rev, cf->file_rcs->rf_head, 1);
+ if (bp == NULL)
+ fatal("cvs_update_local: failed to merge");
+
+ cvs_checkout_file(cf, cf->file_rcs->rf_head, bp, CO_MERGE);
+
+ if (diff3_conflicts != 0) {
+ cvs_printf("C %s\n", cf->file_path);
+ } else {
+ update_clear_conflict(cf);
+ cvs_printf("M %s\n", cf->file_path);
+ }
break;
case FILE_UNLINK:
(void)unlink(cf->file_path);
@@ -273,3 +302,79 @@ cvs_update_local(struct cvs_file *cf)
break;
}
}
+
+static void
+update_clear_conflict(struct cvs_file *cf)
+{
+ int l;
+ time_t now;
+ CVSENTRIES *entlist;
+ char *entry, revbuf[16], timebuf[32];
+
+ cvs_log(LP_TRACE, "update_clear_conflict(%s)", cf->file_path);
+
+ time(&now);
+ ctime_r(&now, timebuf);
+ if (timebuf[strlen(timebuf) - 1] == '\n')
+ timebuf[strlen(timebuf) - 1] = '\0';
+
+ rcsnum_tostr(cf->file_ent->ce_rev, revbuf, sizeof(revbuf));
+
+ entry = xmalloc(CVS_ENT_MAXLINELEN);
+ l = snprintf(entry, CVS_ENT_MAXLINELEN, "/%s/%s/%s//",
+ cf->file_name, revbuf, timebuf);
+ if (l == -1 || l >= CVS_ENT_MAXLINELEN)
+ fatal("update_clear_conflict: overflow");
+
+ entlist = cvs_ent_open(cf->file_wd);
+ cvs_ent_add(entlist, entry);
+ cvs_ent_close(entlist, ENT_SYNC);
+ xfree(entry);
+}
+
+/*
+ * XXX - this is the way GNU cvs checks for outstanding conflicts
+ * in a file after a merge. It is a very very bad approach and
+ * should be looked at once opencvs is working decently.
+ */
+int
+update_has_conflict_markers(struct cvs_file *cf)
+{
+ BUF *bp;
+ int conflict;
+ char *content;
+ struct cvs_line *lp;
+ struct cvs_lines *lines;
+
+ cvs_log(LP_TRACE, "update_has_conflict_markers(%s)", cf->file_path);
+
+ if ((bp = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL)
+ fatal("update_has_conflict_markers: failed to load %s",
+ cf->file_path);
+
+ cvs_buf_putc(bp, '\0');
+ content = cvs_buf_release(bp);
+ if ((lines = cvs_splitlines(content)) == NULL)
+ fatal("update_has_conflict_markers: failed to split lines");
+
+ xfree(content);
+
+ conflict = 0;
+ TAILQ_FOREACH(lp, &(lines->l_lines), l_list) {
+ if (lp->l_line == NULL)
+ continue;
+
+ if (!strncmp(lp->l_line, RCS_CONFLICT_MARKER1,
+ strlen(RCS_CONFLICT_MARKER1)) ||
+ !strncmp(lp->l_line, RCS_CONFLICT_MARKER2,
+ strlen(RCS_CONFLICT_MARKER2)) ||
+ !strncmp(lp->l_line, RCS_CONFLICT_MARKER3,
+ strlen(RCS_CONFLICT_MARKER3))) {
+ conflict = 1;
+ break;
+ }
+ }
+
+ cvs_freelines(lines);
+ return (conflict);
+}