diff options
author | peter <peter@FreeBSD.org> | 1998-01-26 03:09:57 +0000 |
---|---|---|
committer | peter <peter@FreeBSD.org> | 1998-01-26 03:09:57 +0000 |
commit | e6e45661e44f15cb8c5c6f063080509bd910b98d (patch) | |
tree | a9812ba7ade0fde6f62c1626b45d522ba104c314 /contrib/cvs/src/commit.c | |
parent | 571cfa0005d94d99d1341bf8ab02be04d4df5f9f (diff) | |
download | FreeBSD-src-e6e45661e44f15cb8c5c6f063080509bd910b98d.zip FreeBSD-src-e6e45661e44f15cb8c5c6f063080509bd910b98d.tar.gz |
Import cvs-1.9.23 as at 19980123. There are a number of really nice
things fixed in here, including the '-ko' vs. -A problem with
remote cvs which caused all files with -ko to be resent each time
(which is damn painful over a modem, I can tell you). It also found a
heap of stray empty directories that should have been pruned with the -P
flag to cvs update but were not for some reason.
It also has the fully integrated rcs and diff, so no more fork/exec
overheads for rcs,ci,patch,diff,etc. This means that it parses the control
data in the rcs files only once rather than twice or more.
If the 'cvs diff' vs. Index thing is going to be fixed for future patch
compatability, this is the place to do it.
Diffstat (limited to 'contrib/cvs/src/commit.c')
-rw-r--r-- | contrib/cvs/src/commit.c | 196 |
1 files changed, 158 insertions, 38 deletions
diff --git a/contrib/cvs/src/commit.c b/contrib/cvs/src/commit.c index c43e35f..a7fec5f 100644 --- a/contrib/cvs/src/commit.c +++ b/contrib/cvs/src/commit.c @@ -3,7 +3,7 @@ * Copyright (c) 1989-1992, Brian Berliner * * You may distribute under the terms of the GNU General Public License as - * specified in the README file that comes with the CVS 1.4 kit. + * specified in the README file that comes with the CVS source distribution. * * Commit Files * @@ -92,6 +92,7 @@ static const char *const commit_usage[] = "\t-F file\tRead the log message from file.\n", "\t-m msg\tLog message.\n", "\t-r rev\tCommit to this branch or trunk revision.\n", + "(Specify the --help global option for a list of other help options)\n", NULL }; @@ -144,8 +145,22 @@ find_dirent_proc (callerdat, dir, repository, update_dir, entries) { struct find_data *find_data = (struct find_data *)callerdat; + /* This check seems to slowly be creeping throughout CVS (update + and send_dirent_proc by CVS 1.5, diff in 31 Oct 1995. My guess + is that it (or some variant thereof) should go in all the + dirent procs. Unless someone has some better idea... */ + if (!isdir (dir)) + return (R_SKIP_ALL); + /* initialize the ignore list for this directory */ find_data->ignlist = getlist (); + + /* Print the same warm fuzzy as in check_direntproc, since that + code will never be run during client/server operation and we + want the messages to match. */ + if (!quiet) + error (0, 0, "Examining %s", update_dir); + return R_PROCESS; } @@ -232,7 +247,7 @@ find_fileproc (callerdat, finfo) xfinfo.repository = NULL; xfinfo.rcs = NULL; - vers = Version_TS (&xfinfo, NULL, NULL, NULL, 0, 0); + vers = Version_TS (&xfinfo, NULL, tag, NULL, 0, 0); if (vers->ts_user == NULL && vers->vn_user != NULL && vers->vn_user[0] == '-') @@ -246,8 +261,8 @@ find_fileproc (callerdat, finfo) if (vers->ts_user == NULL) error (0, 0, "nothing known about `%s'", finfo->fullname); else - error (0, 0, "use `cvs add' to create an entry for %s", - finfo->fullname); + error (0, 0, "use `%s add' to create an entry for %s", + program_name, finfo->fullname); return 1; } else if (vers->ts_user != NULL @@ -321,6 +336,9 @@ commit (argc, argv) * For log purposes, do not allow "root" to commit files. If you look * like root, but are really logged in as a non-root user, it's OK. */ + /* FIXME: Shouldn't this check be much more closely related to the + readonly user stuff (CVSROOT/readers, &c). That is, why should + root be able to "cvs init", "cvs import", &c, but not "cvs ci"? */ if (geteuid () == (uid_t) 0) { struct passwd *pw; @@ -342,9 +360,9 @@ commit (argc, argv) break; case 'm': #ifdef FORCE_USE_EDITOR - use_editor = TRUE; + use_editor = 1; #else - use_editor = FALSE; + use_editor = 0; #endif if (message) { @@ -371,9 +389,9 @@ commit (argc, argv) break; case 'F': #ifdef FORCE_USE_EDITOR - use_editor = TRUE; + use_editor = 1; #else - use_editor = FALSE; + use_editor = 0; #endif logfile = optarg; break; @@ -425,6 +443,7 @@ commit (argc, argv) #ifdef CLIENT_SUPPORT if (client_active) { + int err; struct find_data find_args; ign_setup (); @@ -489,6 +508,8 @@ commit (argc, argv) do_verify (message, (char *)NULL); /* We always send some sort of message, even if empty. */ + /* FIXME: is that true? There seems to be some code in do_editor + which can leave the message NULL. */ option_with_arg ("-m", message); /* OK, now process all the questionable files we have been saving @@ -553,14 +574,39 @@ commit (argc, argv) "cvs commit -r 2" across a whole bunch of files a very slow operation (and it isn't documented in cvsclient.texi). I haven't looked at the server code carefully enough to be - _sure_ why this is needed, but if it is because RCS_CI - wants the file to exist, then it would be relatively simple - (but not trivial) to fix in the server. */ + _sure_ why this is needed, but if it is because the "ci" + program, which we used to call, wanted the file to exist, + then it would be relatively simple to fix in the server. */ send_files (find_args.argc, find_args.argv, local, 0, find_args.force ? SEND_FORCE : 0); send_to_server ("ci\012", 0); - return get_responses_and_close (); + err = get_responses_and_close (); + if (err != 0 && use_editor && message != NULL) + { + /* If there was an error, don't nuke the user's carefully + constructed prose. This is something of a kludge; a better + solution is probably more along the lines of #150 in TODO + (doing a second up-to-date check before accepting the + log message has also been suggested, but that seems kind of + iffy because the real up-to-date check could still fail, + another error could occur, &c. Also, a second check would + slow things down). */ + + char *fname; + FILE *fp; + + fname = cvs_temp_name (); + fp = CVS_FOPEN (fname, "w+"); + if (fp == NULL) + error (1, 0, "cannot create temporary file %s", fname); + if (fwrite (message, 1, strlen (message), fp) != strlen (message)) + error (1, errno, "cannot write temporary file %s", fname); + if (fclose (fp) < 0) + error (0, errno, "cannot close temporary file %s", fname); + error (0, 0, "saving log message in %s", fname); + } + return err; } #endif @@ -633,7 +679,10 @@ classify_file_internal (finfo, vers) { int save_noexec, save_quiet, save_really_quiet; Ctype status; - + + /* FIXME: Do we need to save quiet as well as really_quiet? Last + time I glanced at Classify_File I only saw it looking at really_quiet + not quiet. */ save_noexec = noexec; save_quiet = quiet; save_really_quiet = really_quiet; @@ -817,16 +866,30 @@ check_fileproc (callerdat, finfo) if (file_has_markers (finfo)) { + /* Make this a warning, not an error, because we have + no way of knowing whether the "conflict indicators" + are really from a conflict or whether they are part + of the document itself (cvs.texinfo and sanity.sh in + CVS itself, for example, tend to want to have strings + like ">>>>>>>" at the start of a line). Making people + kludge this the way they need to kludge keyword + expansion seems undesirable. And it is worse than + keyword expansion, because there is no -ko + analogue. */ error (0, 0, - "file `%s' still contains conflict indicators", + "\ +warning: file `%s' seems to still contain conflict indicators", finfo->fullname); - freevers_ts (&vers); - return (1); } } if (status == T_REMOVED && vers->tag && isdigit (*vers->tag)) { + /* Remove also tries to forbid this, but we should check + here. I'm only _sure_ about somewhat obscure cases + (hacking the Entries file, using an old version of + CVS for the remove and a new one for the commit), but + there might be other cases. */ error (0, 0, "cannot remove file `%s' which has a numeric sticky tag of `%s'", finfo->fullname, vers->tag); @@ -946,7 +1009,8 @@ check_fileproc (callerdat, finfo) } /* - * Print warm fuzzies while examining the dirs + * By default, return the code that tells do_recursion to examine all + * directories */ /* ARGSUSED */ static Dtype @@ -957,6 +1021,9 @@ check_direntproc (callerdat, dir, repos, update_dir, entries) char *update_dir; List *entries; { + if (!isdir (dir)) + return (R_SKIP_ALL); + if (!quiet) error (0, 0, "Examining %s", update_dir); @@ -1013,7 +1080,8 @@ precommit_proc (repository, filter) free (s); } - run_setup ("%s %s", filter, repository); + run_setup (filter); + run_arg (repository); (void) walklist (ulist, precommit_list_proc, NULL); return (run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL|RUN_REALLY)); } @@ -1333,7 +1401,8 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries) if (line[line_length - 1] == '\n') line[--line_length] = '\0'; repository = Name_Repository ((char *) NULL, update_dir); - run_setup ("%s %s", line, repository); + run_setup (line); + run_arg (repository); cvs_output (program_name, 0); cvs_output (" ", 1); cvs_output (command_name, 0); @@ -1365,7 +1434,7 @@ commit_filesdoneproc (callerdat, err, repository, update_dir, entries) } /* - * Get the log message for a dir and print a warm fuzzy + * Get the log message for a dir */ /* ARGSUSED */ static Dtype @@ -1380,6 +1449,9 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries) List *ulist; char *real_repos; + if (!isdir (dir)) + return (R_SKIP_ALL); + /* find the update list for this dir */ p = findnode (mulist, update_dir); if (p != NULL) @@ -1391,10 +1463,6 @@ commit_direntproc (callerdat, dir, repos, update_dir, entries) if (ulist == NULL || ulist->list->next == ulist->list) return (R_SKIP_FILES); - /* print the warm fuzzy */ - if (!quiet) - error (0, 0, "Committing %s", update_dir); - /* get commit message */ real_repos = Name_Repository (dir, update_dir); got_message = 1; @@ -1489,10 +1557,10 @@ remove_file (finfo, tag, message) error (1, 0, "internal error: no parsed RCS file"); branch = 0; - if (tag && !(branch = RCS_isbranch (finfo->rcs, tag))) + if (tag && !(branch = RCS_nodeisbranch (finfo->rcs, tag))) { /* a symbolic tag is specified; just remove the tag from the file */ - if ((retcode = RCS_deltag (finfo->rcs, tag, 1)) != 0) + if ((retcode = RCS_deltag (finfo->rcs, tag)) != 0) { if (!quiet) error (0, retcode == -1 ? errno : 0, @@ -1500,6 +1568,7 @@ remove_file (finfo, tag, message) finfo->fullname); return (1); } + RCS_rewrite (finfo->rcs, NULL, NULL); Scratch_Entry (finfo->entries, finfo->file); return (0); } @@ -1556,6 +1625,7 @@ remove_file (finfo, tag, message) finfo->fullname); return (1); } + RCS_rewrite (finfo->rcs, NULL, NULL); } #ifdef SERVER_SUPPORT @@ -1584,12 +1654,15 @@ remove_file (finfo, tag, message) /* Except when we are creating a branch, lock the revision so that we can check in the new revision. */ if (lockflag) - RCS_lock (finfo->rcs, rev ? corev : NULL, 0); + { + if (RCS_lock (finfo->rcs, rev ? corev : NULL, 1) == 0) + RCS_rewrite (finfo->rcs, NULL, NULL); + } if (corev != NULL) free (corev); - retcode = RCS_checkin (finfo->rcs->path, finfo->file, message, rev, + retcode = RCS_checkin (finfo->rcs, finfo->file, message, rev, RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); if (retcode != 0) { @@ -1690,6 +1763,8 @@ unlockrcs (rcs) if ((retcode = RCS_unlock (rcs, NULL, 0)) != 0) error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, "could not unlock %s", rcs->path); + else + RCS_rewrite (rcs, NULL, NULL); } /* @@ -1730,6 +1805,7 @@ fixbranch (rcs, branch) if ((retcode = RCS_setbranch (rcs, branch)) != 0) error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, "cannot restore branch to %s for %s", branch, rcs->path); + RCS_rewrite (rcs, NULL, NULL); } } @@ -1841,29 +1917,63 @@ internal error: `%s' didn't move out of the attic", { /* this is the first time we have ever seen this file; create an rcs file. */ - run_setup ("%s%s -x,v/ -i", Rcsbin, RCS); + char *desc; + size_t descalloc; + size_t desclen; + + char *opt; + + desc = NULL; + descalloc = 0; + desclen = 0; fname = xmalloc (strlen (file) + sizeof (CVSADM) + sizeof (CVSEXT_LOG) + 10); (void) sprintf (fname, "%s/%s%s", CVSADM, file, CVSEXT_LOG); /* If the file does not exist, no big deal. In particular, the server does not (yet at least) create CVSEXT_LOG files. */ if (isfile (fname)) - run_args ("-t%s/%s%s", CVSADM, file, CVSEXT_LOG); + /* FIXME: Should be including update_dir in the appropriate + place here. */ + get_file (fname, fname, "r", &desc, &descalloc, &desclen); free (fname); + /* From reading the RCS 5.7 source, "rcs -i" adds a newline to the + end of the log message if the message is nonempty. + Do it. RCS also deletes certain whitespace, in cleanlogmsg, + which we don't try to do here. */ + if (desclen > 0) + { + expand_string (&desc, &descalloc, desclen + 1); + desc[desclen++] = '\012'; + } + /* Set RCS keyword expansion options. */ if (options && options[0] == '-' && options[1] == 'k') - run_arg (options); - run_arg (rcs); - if ((retcode = run_exec (RUN_TTY, RUN_TTY, RUN_TTY, RUN_NORMAL)) != 0) + opt = options + 2; + else + opt = NULL; + + /* This message is an artifact of the time when this + was implemented via "rcs -i". It should be revised at + some point (does the "initial revision" in the message from + RCS_checkin indicate that this is a new file? Or does the + "RCS file" message serve some function?). */ + cvs_output ("RCS file: ", 0); + cvs_output (rcs, 0); + cvs_output ("\ndone\n", 0); + + if (add_rcs_file (NULL, rcs, file, NULL, opt, + NULL, NULL, 0, NULL, + desc, desclen, NULL) != 0) { - error (retcode == -1 ? 1 : 0, retcode == -1 ? errno : 0, - "could not create %s", rcs); retval = 1; goto out; } + rcsfile = RCS_parsercsfile (rcs); newfile = 1; + if (desc != NULL) + free (desc); } /* when adding a file for the first time, and using a tag, we need @@ -1883,7 +1993,7 @@ internal error: `%s' didn't move out of the attic", /* commit a dead revision. */ (void) sprintf (tmp, "file %s was initially added on branch %s.", file, tag); - retcode = RCS_checkin (rcs, NULL, tmp, NULL, + retcode = RCS_checkin (rcsfile, NULL, tmp, NULL, RCS_FLAGS_DEAD | RCS_FLAGS_QUIET); free (tmp); if (retcode != 0) @@ -1898,7 +2008,8 @@ internal error: `%s' didn't move out of the attic", rename_file (fname, file); free (fname); - assert (rcsfile == NULL); + /* double-check that the file was written correctly */ + freercsnode (&rcsfile); rcsfile = RCS_parse (file, repository); if (rcsfile == NULL) { @@ -1952,6 +2063,7 @@ internal error: `%s' didn't move out of the attic", magicrev = RCS_magicrev (rcsfile, head); retcode = RCS_settag (rcsfile, tag, magicrev); + RCS_rewrite (rcsfile, NULL, NULL); free (head); free (magicrev); @@ -1984,7 +2096,14 @@ internal error: `%s' didn't move out of the attic", fileattr_newfile (file); + /* I don't think fix_rcs_modes is needed any more. In the + add_rcs_file case, the algorithms used by add_rcs_file and + fix_rcs_modes are the same, so there is no need to go through + it all twice. In the other cases, I think we want to just + preserve the mode that the file had before we started. That is + a behavior change, but I would think a desirable one. */ fix_rcs_modes (rcs, file); + retval = 0; out: @@ -2031,12 +2150,13 @@ lock_RCS (user, rcs, rev, repository) return (1); } } - err = RCS_lock(rcs, NULL, 0); + err = RCS_lock(rcs, NULL, 1); } else { (void) RCS_lock(rcs, rev, 1); } + RCS_rewrite (rcs, NULL, NULL); if (err == 0) { |