From 95882ea60d61fe9cfb0be8d92b4abaaa46f42c25 Mon Sep 17 00:00:00 2001 From: "David E. O'Brien" Date: Wed, 19 Mar 2008 15:07:28 +0000 Subject: [PATCH] Merge rev 1.9 (update "-T" Template support) and rev 1.2 (-D'date' option with -r'branch' on update) into version 1.11-20080310. --- contrib/cvs/src/update.c | 147 +++++++++++++++++++++++++-------------- 1 file changed, 95 insertions(+), 52 deletions(-) diff --git a/contrib/cvs/src/update.c b/contrib/cvs/src/update.c index 3d82ee49c076..f2c80874345a 100644 --- a/contrib/cvs/src/update.c +++ b/contrib/cvs/src/update.c @@ -1448,8 +1448,10 @@ VERS: ", 0); /* fix up the vers structure, in case it is used by join */ if (join_rev1) { - /* FIXME: Throwing away the original revision info is almost - certainly wrong -- what if join_rev1 is "BASE"? */ + /* FIXME: It seems like we should be preserving ts_user + * & ts_rcs here, but setting them causes problems in + * join_file(). + */ if (vers_ts->vn_user != NULL) free (vers_ts->vn_user); if (vers_ts->vn_rcs != NULL) @@ -1658,21 +1660,11 @@ patch_file (finfo, vers_ts, docheckout, file_info, checksum) data.final_nl = 0; data.compute_checksum = 0; - /* FIXME - Passing vers_ts->tag here is wrong in the least number - * of cases. Since we don't know whether vn_user was checked out - * using a tag, we pass vers_ts->tag, which, assuming the user did - * not specify a new TAG to -r, will be the branch we are on. - * - * The only thing it is used for is to substitute in for the Name - * RCS keyword, so in the error case, the patch fails to apply on - * the client end and we end up resending the whole file. - * - * At least, if we are keeping track of the tag vn_user came from, - * I don't know where yet. -DRP + /* Duplicating the client working file, so use the original sticky options. */ retcode = RCS_checkout (vers_ts->srcfile, (char *) NULL, - vers_ts->vn_user, vers_ts->tag, - vers_ts->options, RUN_TTY, + vers_ts->vn_user, vers_ts->entdata->tag, + vers_ts->entdata->options, RUN_TTY, patch_file_write, (void *) &data); if (fclose (e) < 0) @@ -2230,6 +2222,7 @@ join_file (finfo, vers) if (rev2 == NULL || RCS_isdead (vers->srcfile, rev2)) { char *mrev; + short conflict = 0; if (rev2 != NULL) free (rev2); @@ -2280,8 +2273,7 @@ join_file (finfo, vers) || vers->vn_user[0] == '-' || RCS_isdead (vers->srcfile, vers->vn_user)) { - if (rev1 != NULL) - free (rev1); + free (rev1); return; } @@ -2290,56 +2282,107 @@ join_file (finfo, vers) resolve. No_Difference will already have been called in this case, so comparing the timestamps is sufficient to determine whether the file is locally modified. */ - if (strcmp (vers->vn_user, "0") == 0 - || (vers->ts_user != NULL - && strcmp (vers->ts_user, vers->ts_rcs) != 0)) + if (/* may have changed on destination branch */ + /* file added locally */ + !strcmp (vers->vn_user, "0") + || /* destination branch modified in repository */ + strcmp (rev1, vers->vn_user) + || /* locally modified */ + vers->ts_user && strcmp (vers->ts_user, vers->ts_rcs)) { - if (jdate2 != NULL) + /* The removal should happen if either the file has never changed + * on the destination or the file has changed to be identical to + * the first join revision. + * + * ------R-----------D + * | + * \----J1---J2-----S + * + * So: + * + * J2 is dead. + * D is destination. + * R is source branch root/GCA. + * if J1 == D removal should happen + * if D == R removal should happen + * otherwise, fail. + * + * (In the source, J2 = REV2, D = user file (potentially VN_USER), + * R = GCA computed below) + */ + char *gca_rev1 = gca (rev1, vers->vn_user); +#ifdef SERVER_SUPPORT + if (server_active && !isreadable (finfo->file)) + { + int retcode; + /* The file is up to date. Need to check out the current + * contents. + */ + /* FIXME - see the FIXME comment above the call to RCS_checkout + * in the patch_file function. + */ + retcode = RCS_checkout (vers->srcfile, finfo->file, + vers->vn_user, vers->tag, + NULL, RUN_TTY, NULL, NULL); + if (retcode) + error (1, 0, + "failed to check out %s file", finfo->fullname); + } +#endif + if (/* genuinely changed on destination branch */ + RCS_cmp_file (vers->srcfile, gca_rev1, NULL, + NULL, vers->options, finfo->file) + && /* genuinely different from REV1 */ + RCS_cmp_file (vers->srcfile, rev1, NULL, + NULL, vers->options, finfo->file)) + conflict = 1; + } + + free (rev1); + + if (conflict) + { + char *cp; + + if (jdate2) error (0, 0, - "file %s is locally modified, but has been removed in revision %s as of %s", + "file %s has been removed in revision %s as of %s, but the destination is incompatibly modified", finfo->fullname, jrev2, jdate2); else error (0, 0, - "file %s is locally modified, but has been removed in revision %s", + "file %s has been removed in revision %s, but the destination is incompatibly modified", finfo->fullname, jrev2); - /* FIXME: Should we arrange to return a non-zero exit - status? */ + /* Register the conflict with the client. */ - if (rev1 != NULL) - free (rev1); - - return; - } - - /* If only one join tag was specified, and the user file has - been changed since the greatest common ancestor (rev1), - then there is a conflict we can not resolve. See above for - the rationale. */ - if (join_rev2 == NULL - && strcmp (rev1, vers->vn_user) != 0) - { - if (jdate2 != NULL) - error (0, 0, - "file %s has been modified, but has been removed in revision %s as of %s", - finfo->fullname, jrev2, jdate2); + /* FIXME: vers->ts_user should always be set here but sometimes + * isn't, namely when checkout_file() has just created the file, + * but simply setting it in checkout_file() appears to cause other + * problems. + */ + if (isfile (finfo->file)) + cp = time_stamp (finfo->file); else - error (0, 0, - "file %s has been modified, but has been removed in revision %s", - finfo->fullname, jrev2); + cp = xstrdup (vers->ts_user); - /* FIXME: Should we arrange to return a non-zero exit - status? */ + Register (finfo->entries, finfo->file, vers->vn_user, + "Result of merge", vers->options, vers->tag, vers->date, + cp); + write_letter (finfo, 'C'); + free (cp); - if (rev1 != NULL) - free (rev1); +#ifdef SERVER_SUPPORT + /* Abuse server_checked_in() to send the updated entry without + * needing to update the file. + */ + if (server_active) + server_checked_in (finfo->file, finfo->update_dir, + finfo->repository); +#endif return; } - if (rev1 != NULL) - free (rev1); - /* The user file exists and has not been modified. Mark it for removal. FIXME: If we are doing a checkout, this has the effect of first checking out the file, and then