commit.c revision 1.63
1/* $OpenBSD: commit.c,v 1.63 2006/05/28 10:15:35 joris Exp $ */ 2/* 3 * Copyright (c) 2006 Joris Vink <joris@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18#include "includes.h" 19 20#include "cvs.h" 21#include "diff.h" 22#include "log.h" 23#include "proto.h" 24 25int cvs_commit(int, char **); 26void cvs_commit_local(struct cvs_file *); 27void cvs_commit_check_conflicts(struct cvs_file *); 28 29static char *commit_diff_file(struct cvs_file *); 30 31struct cvs_flisthead files_affected; 32int conflicts_found; 33char *logmsg; 34 35struct cvs_cmd cvs_cmd_commit = { 36 CVS_OP_COMMIT, CVS_REQ_CI, "commit", 37 { "ci", "com" }, 38 "Check files into the repository", 39 "[-flR] [-F logfile | -m msg] [-r rev] ...", 40 "F:flm:Rr:", 41 NULL, 42 cvs_commit 43}; 44 45int 46cvs_commit(int argc, char **argv) 47{ 48 int ch; 49 char *arg = "."; 50 int flags; 51 struct cvs_recursion cr; 52 53 flags = CR_RECURSE_DIRS; 54 55 while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) { 56 switch (ch) { 57 case 'f': 58 break; 59 case 'F': 60 break; 61 case 'l': 62 flags &= ~CR_RECURSE_DIRS; 63 break; 64 case 'm': 65 logmsg = xstrdup(optarg); 66 break; 67 case 'r': 68 break; 69 case 'R': 70 break; 71 default: 72 fatal("%s", cvs_cmd_commit.cmd_synopsis); 73 } 74 } 75 76 argc -= optind; 77 argv += optind; 78 79 if (logmsg == NULL) 80 fatal("please use -m to specify a log message for now"); 81 82 TAILQ_INIT(&files_affected); 83 conflicts_found = 0; 84 85 cr.enterdir = NULL; 86 cr.leavedir = NULL; 87 cr.local = cvs_commit_check_conflicts; 88 cr.remote = NULL; 89 cr.flags = flags; 90 91 if (argc > 0) 92 cvs_file_run(argc, argv, &cr); 93 else 94 cvs_file_run(1, &arg, &cr); 95 96 if (conflicts_found != 0) 97 fatal("%d conflicts found, please correct these first", 98 conflicts_found); 99 100 cr.local = cvs_commit_local; 101 cvs_file_walklist(&files_affected, &cr); 102 cvs_file_freelist(&files_affected); 103 104 return (0); 105} 106 107void 108cvs_commit_check_conflicts(struct cvs_file *cf) 109{ 110 cvs_log(LP_TRACE, "cvs_commit_check_conflicts(%s)", cf->file_path); 111 112 /* 113 * cvs_file_classify makes the noise for us 114 * XXX - we want that? 115 */ 116 cvs_file_classify(cf, 1); 117 118 if (cf->file_type == CVS_DIR) { 119 if (verbosity > 1) 120 cvs_log(LP_NOTICE, "Examining %s", cf->file_path); 121 return; 122 } 123 124 if (cf->file_status == FILE_CONFLICT || 125 cf->file_status == FILE_LOST || 126 cf->file_status == FILE_UNLINK) 127 conflicts_found++; 128 129 if (cf->file_status != FILE_REMOVED && 130 update_has_conflict_markers(cf)) { 131 cvs_log(LP_ERR, "conflict: unresolved conflicts in %s from " 132 "merging, please fix these first", cf->file_path); 133 conflicts_found++; 134 } 135 136 if (cf->file_status == FILE_MERGE || 137 cf->file_status == FILE_PATCH) { 138 cvs_log(LP_ERR, "conflict: %s is not up-to-date", 139 cf->file_path); 140 conflicts_found++; 141 } 142 143 if (cf->file_status == FILE_ADDED || 144 cf->file_status == FILE_REMOVED || 145 cf->file_status == FILE_MODIFIED) 146 cvs_file_get(cf->file_path, &files_affected); 147} 148 149void 150cvs_commit_local(struct cvs_file *cf) 151{ 152 BUF *b; 153 int isadded; 154 char *d, *f, rbuf[24]; 155 CVSENTRIES *entlist; 156 157 cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path); 158 cvs_file_classify(cf, 0); 159 160 if (cf->file_status == FILE_MODIFIED || 161 cf->file_status == FILE_REMOVED) 162 rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 163 else 164 strlcpy(rbuf, "Non-existent", sizeof(rbuf)); 165 166 isadded = (cf->file_status == FILE_ADDED && cf->file_rcs == NULL); 167 if (isadded) { 168 cf->repo_fd = open(cf->file_rpath, O_CREAT|O_TRUNC|O_WRONLY); 169 if (cf->repo_fd < 0) 170 fatal("cvs_commit_local: %s", strerror(errno)); 171 172 cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, 173 RCS_CREATE, 0600); 174 if (cf->file_rcs == NULL) 175 fatal("cvs_commit_local: failed to create RCS file " 176 "for %s", cf->file_path); 177 } 178 179 cvs_printf("Checking in %s:\n", cf->file_path); 180 cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path); 181 cvs_printf("old revision: %s; ", rbuf); 182 183 if (isadded == 0) 184 d = commit_diff_file(cf); 185 186 if (cf->file_status == FILE_REMOVED) { 187 b = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); 188 if (b == NULL) 189 fatal("cvs_commit_local: failed to get HEAD"); 190 } else { 191 if ((b = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) 192 fatal("cvs_commit_local: failed to load file"); 193 } 194 195 cvs_buf_putc(b, '\0'); 196 f = cvs_buf_release(b); 197 198 if (isadded == 0) { 199 if (rcs_deltatext_set(cf->file_rcs, 200 cf->file_rcs->rf_head, d) == -1) 201 fatal("cvs_commit_local: failed to set delta"); 202 } 203 204 if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, logmsg, -1, NULL) == -1) 205 fatal("cvs_commit_local: failed to add new revision"); 206 207 if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, f) == -1) 208 fatal("cvs_commit_local: failed to set new HEAD delta"); 209 210 xfree(f); 211 212 if (isadded == 0) 213 xfree(d); 214 215 if (cf->file_status == FILE_REMOVED) { 216 if (rcs_state_set(cf->file_rcs, 217 cf->file_rcs->rf_head, RCS_STATE_DEAD) == -1) 218 fatal("cvs_commit_local: failed to set state"); 219 } 220 221 rcs_write(cf->file_rcs); 222 223 if (cf->file_status == FILE_REMOVED) { 224 strlcpy(rbuf, "Removed", sizeof(rbuf)); 225 } else if (cf->file_status == FILE_ADDED) { 226 if (cf->file_rcs->rf_dead == 0) 227 strlcpy(rbuf, "Initial Revision", sizeof(rbuf)); 228 else 229 rcsnum_tostr(cf->file_rcs->rf_head, 230 rbuf, sizeof(rbuf)); 231 } else if (cf->file_status == FILE_MODIFIED) { 232 rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 233 } 234 235 cvs_printf("new revision: %s\n", rbuf); 236 237 (void)unlink(cf->file_path); 238 (void)close(cf->fd); 239 cf->fd = -1; 240 241 if (cf->file_status != FILE_REMOVED) { 242 b = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); 243 if (b == NULL) 244 fatal("cvs_commit_local: failed to get HEAD"); 245 246 cvs_checkout_file(cf, cf->file_rcs->rf_head, b, 0); 247 } else { 248 entlist = cvs_ent_open(cf->file_wd); 249 cvs_ent_remove(entlist, cf->file_name); 250 cvs_ent_close(entlist, ENT_SYNC); 251 } 252 253 cvs_printf("done\n"); 254 255} 256 257static char * 258commit_diff_file(struct cvs_file *cf) 259{ 260 char*delta, *p1, *p2; 261 BUF *b1, *b2, *b3; 262 263 if (cf->file_status == FILE_MODIFIED || 264 cf->file_status == FILE_ADDED) { 265 if ((b1 = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) 266 fatal("commit_diff_file: failed to load '%s'", 267 cf->file_path); 268 } else { 269 b1 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); 270 if (b1 == NULL) 271 fatal("commit_diff_file: failed to load HEAD"); 272 b1 = rcs_kwexp_buf(b1, cf->file_rcs, cf->file_rcs->rf_head); 273 } 274 275 if ((b2 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) 276 fatal("commit_diff_file: failed to load HEAD for '%s'", 277 cf->file_path); 278 279 if ((b3 = cvs_buf_alloc(128, BUF_AUTOEXT)) == NULL) 280 fatal("commit_diff_file: failed to create diff buf"); 281 282 (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 283 cvs_buf_write_stmp(b1, p1, 0600, NULL); 284 cvs_buf_free(b1); 285 286 (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 287 cvs_buf_write_stmp(b2, p2, 0600, NULL); 288 cvs_buf_free(b2); 289 290 diff_format = D_RCSDIFF; 291 if (cvs_diffreg(p1, p2, b3) == D_ERROR) 292 fatal("commit_diff_file: failed to get RCS patch"); 293 294 cvs_buf_putc(b3, '\0'); 295 delta = cvs_buf_release(b3); 296 return (delta); 297} 298