=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/cvs/commit.c,v retrieving revision 1.54 retrieving revision 1.55 diff -u -r1.54 -r1.55 --- src/usr.bin/cvs/commit.c 2006/04/14 02:45:35 1.54 +++ src/usr.bin/cvs/commit.c 2006/05/27 03:30:30 1.55 @@ -1,271 +1,204 @@ -/* $OpenBSD: commit.c,v 1.54 2006/04/14 02:45:35 deraadt Exp $ */ +/* $OpenBSD: commit.c,v 1.55 2006/05/27 03:30:30 joris Exp $ */ /* - * Copyright (c) 2004 Jean-Francois Brousseau - * All rights reserved. + * Copyright (c) 2006 Joris Vink * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL - * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "includes.h" -#include "buf.h" #include "cvs.h" +#include "diff.h" #include "log.h" #include "proto.h" +int cvs_commit(int, char **); +void cvs_commit_local(struct cvs_file *); +void cvs_commit_check_conflicts(struct cvs_file *); -static int cvs_commit_init(struct cvs_cmd *, int, char **, int *); -static int cvs_commit_prepare(CVSFILE *, void *); -static int cvs_commit_remote(CVSFILE *, void *); -static int cvs_commit_local(CVSFILE *, void *); -static int cvs_commit_pre_exec(struct cvsroot *); +static char *commit_diff_file(struct cvs_file *); +struct cvs_flisthead files_affected; +int conflicts_found; +char *logmsg; + struct cvs_cmd cvs_cmd_commit = { CVS_OP_COMMIT, CVS_REQ_CI, "commit", - { "ci", "com" }, + { "ci", "com" }, "Check files into the repository", "[-flR] [-F logfile | -m msg] [-r rev] ...", "F:flm:Rr:", NULL, - CF_RECURSE | CF_IGNORE | CF_SORT, - cvs_commit_init, - cvs_commit_pre_exec, - cvs_commit_remote, - cvs_commit_local, - NULL, - NULL, - CVS_CMD_SENDDIR | CVS_CMD_ALLOWSPEC | CVS_CMD_SENDARGS2 + cvs_commit }; -static char *mfile = NULL; -static char *rev = NULL; -static char **commit_files = NULL; -static int commit_fcount = 0; -static int wantedstatus = 0; - -static int -cvs_commit_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) +int +cvs_commit(int argc, char **argv) { int ch; + char *arg = "."; + struct cvs_recursion cr; - while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { + while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) { switch (ch) { - case 'F': - mfile = optarg; - break; case 'f': - /* XXX half-implemented */ - cmd->file_flags &= ~CF_RECURSE; break; + case 'F': + break; case 'l': - cmd->file_flags &= ~CF_RECURSE; break; case 'm': - cvs_msg = xstrdup(optarg); + logmsg = xstrdup(optarg); break; - case 'R': - cmd->file_flags |= CF_RECURSE; - break; case 'r': - rev = optarg; break; + case 'R': + break; default: - return (CVS_EX_USAGE); + fatal("%s", cvs_cmd_commit.cmd_synopsis); } } - if (cvs_msg != NULL && mfile != NULL) { - cvs_log(LP_ERR, "the -F and -m flags are mutually exclusive"); - return (CVS_EX_USAGE); - } + argc -= optind; + argv += optind; - if (mfile != NULL) - cvs_msg = cvs_logmsg_open(mfile); + if (logmsg == NULL) + fatal("please use -m to specify a log message for now"); - *arg = optind; + TAILQ_INIT(&files_affected); + conflicts_found = 0; - commit_files = (argv + optind); - commit_fcount = (argc - optind); + cr.enterdir = NULL; + cr.leavedir = NULL; + cr.local = cvs_commit_check_conflicts; + cr.remote = NULL; + if (argc > 0) + cvs_file_run(argc, argv, &cr); + else + cvs_file_run(1, &arg, &cr); + + if (conflicts_found != 0) + fatal("%d conflicts found, please correct these first", + conflicts_found); + + cr.local = cvs_commit_local; + cvs_file_walklist(&files_affected, &cr); + cvs_file_freelist(&files_affected); + return (0); } -int -cvs_commit_pre_exec(struct cvsroot *root) +void +cvs_commit_check_conflicts(struct cvs_file *cf) { - CVSFILE *cfp; - CVSFILE *tmp; - int ret, i, flags = CF_RECURSE | CF_IGNORE | CF_SORT; - struct cvs_flist added, modified, removed, *cl[3]; - int stattype[] = { CVS_FST_ADDED, CVS_FST_MODIFIED, CVS_FST_REMOVED }; + cvs_log(LP_TRACE, "cvs_commit_check_conflicts(%s)", cf->file_path); - SIMPLEQ_INIT(&added); - SIMPLEQ_INIT(&modified); - SIMPLEQ_INIT(&removed); - - cl[0] = &added; - cl[1] = &modified; - cl[2] = &removed; - - if ((tmp = cvs_file_loadinfo(".", CF_NOFILES, NULL, NULL, 1)) == NULL) - return (CVS_EX_DATA); - /* - * Obtain the file lists for the logmessage. + * cvs_file_classify makes the noise for us + * XXX - we want that? */ - for (i = 0; i < 3; i++) { - wantedstatus = stattype[i]; - if (commit_fcount != 0) { - ret = cvs_file_getspec(commit_files, commit_fcount, - flags, cvs_commit_prepare, cl[i], NULL); - } else { - ret = cvs_file_get(".", flags, cvs_commit_prepare, - cl[i], NULL); - } + cvs_file_classify(cf); - if (ret != CVS_EX_OK) { - cvs_file_free(tmp); - return (CVS_EX_DATA); - } - } + if (cf->file_status == FILE_CONFLICT || + cf->file_status == FILE_LOST || + cf->file_status == FILE_UNLINK) + conflicts_found++; - /* - * If we didn't catch any file, don't call the editor. - */ - if (SIMPLEQ_EMPTY(&added) && SIMPLEQ_EMPTY(&modified) && - SIMPLEQ_EMPTY(&removed)) { - cvs_file_free(tmp); - return (0); - } + if (cf->file_status == FILE_ADDED || + cf->file_status == FILE_REMOVED || + cf->file_status == FILE_MODIFIED) + cvs_file_get(cf->file_path, &files_affected); +} - /* - * Fetch the log message for real, with all the files. - */ - if (cvs_msg == NULL) - cvs_msg = cvs_logmsg_get(tmp->cf_name, &added, &modified, - &removed); +void +cvs_commit_local(struct cvs_file *cf) +{ + BUF *b; + char *d, *f, rbuf[16]; - cvs_file_free(tmp); + cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path); + cvs_file_classify(cf); - /* free the file lists */ - for (i = 0; i < 3; i++) { - while (!SIMPLEQ_EMPTY(cl[i])) { - cfp = SIMPLEQ_FIRST(cl[i]); - SIMPLEQ_REMOVE_HEAD(cl[i], cf_list); - cvs_file_free(cfp); - } - } + rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); - if (cvs_msg == NULL) - return (CVS_EX_DATA); + cvs_printf("Checking in %s:\n", cf->file_path); + cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path); + cvs_printf("old revision: %s; ", rbuf); - if (root->cr_method != CVS_METHOD_LOCAL) { - cvs_logmsg_send(root, cvs_msg); + d = commit_diff_file(cf); - if (rev != NULL) { - cvs_sendarg(root, "-r", 0); - cvs_sendarg(root, rev, 0); - } - } + if ((b = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) + fatal("cvs_commit_local: failed to load file"); - return (0); -} + cvs_buf_putc(b, '\0'); + f = cvs_buf_release(b); -/* - * cvs_commit_prepare() - * - * Examine the file to see if it will be part of the commit, in which - * case it gets added to the list passed as second argument. - */ -int -cvs_commit_prepare(CVSFILE *cf, void *arg) -{ - CVSFILE *copy; - struct cvs_flist *clp = (struct cvs_flist *)arg; + if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, d) == -1) + fatal("cvs_commit_local: failed to set delta"); - if (cf->cf_type == DT_REG && cf->cf_cvstat == wantedstatus) { - copy = cvs_file_copy(cf); - if (copy == NULL) - return (CVS_EX_DATA); + if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, logmsg, -1, NULL) == -1) + fatal("cvs_commit_local: failed to add new revision"); - SIMPLEQ_INSERT_TAIL(clp, copy, cf_list); - } + if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, f) == -1) + fatal("cvs_commit_local: failed to set new HEAD delta"); - return (0); -} + xfree(f); + xfree(d); + rcs_write(cf->file_rcs); -/* - * cvs_commit_remote() - * - * Commit a single file. - */ -int -cvs_commit_remote(CVSFILE *cf, void *arg) -{ - char fpath[MAXPATHLEN]; - struct cvsroot *root; + rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); + cvs_printf("new revision: %s\n", rbuf); - root = CVS_DIR_ROOT(cf); + (void)unlink(cf->file_path); + (void)close(cf->fd); + cf->fd = -1; + cvs_checkout_file(cf, cf->file_rcs->rf_head, 0); - if (cf->cf_type == DT_DIR) { - if (cf->cf_cvstat != CVS_FST_UNKNOWN) - cvs_senddir(root, cf); - return (0); - } + cvs_printf("done\n"); - cvs_file_getpath(cf, fpath, sizeof(fpath)); +} - if (cf->cf_cvstat == CVS_FST_ADDED || - cf->cf_cvstat == CVS_FST_MODIFIED || - cf->cf_cvstat == CVS_FST_REMOVED) { - cvs_sendentry(root, cf); +static char * +commit_diff_file(struct cvs_file *cf) +{ + char*delta, *p1, *p2; + BUF *b1, *b2, *b3; - /* if it's removed, don't bother sending a - * Modified request together with the file its - * contents. - */ - if (cf->cf_cvstat == CVS_FST_REMOVED) - return (0); + if ((b1 = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) + fatal("commit_diff_file: failed to load '%s'", cf->file_path); - cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name); - cvs_sendfile(root, fpath); - } + if ((b2 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) + fatal("commit_diff_file: failed to load HEAD for '%s'", + cf->file_path); - return (0); -} + if ((b3 = cvs_buf_alloc(128, BUF_AUTOEXT)) == NULL) + fatal("commit_diff_file: failed to create diff buf"); -static int -cvs_commit_local(CVSFILE *cf, void *arg) -{ - char fpath[MAXPATHLEN], rcspath[MAXPATHLEN]; + (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); + cvs_buf_write_stmp(b1, p1, 0600, NULL); + cvs_buf_free(b1); - if (cf->cf_type == DT_DIR) { - if (verbosity > 1) - cvs_log(LP_NOTICE, "Examining %s", cf->cf_name); - return (0); - } + (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); + cvs_buf_write_stmp(b2, p2, 0600, NULL); + cvs_buf_free(b2); - cvs_file_getpath(cf, fpath, sizeof(fpath)); - cvs_rcs_getpath(cf, rcspath, sizeof(rcspath)); + diff_format = D_RCSDIFF; + if (cvs_diffreg(p1, p2, b3) == D_ERROR) + fatal("commit_diff_file: failed to get RCS patch"); - return (0); + cvs_buf_putc(b3, '\0'); + delta = cvs_buf_release(b3); + return (delta); }