1 /* $OpenBSD: commit.c,v 1.56 2006/05/27 06:16:14 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 25 int cvs_commit(int, char **); 26 void cvs_commit_local(struct cvs_file *); 27 void cvs_commit_check_conflicts(struct cvs_file *); 28 29 static char *commit_diff_file(struct cvs_file *); 30 31 struct cvs_flisthead files_affected; 32 int conflicts_found; 33 char *logmsg; 34 35 struct 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 45 int 46 cvs_commit(int argc, char **argv) 47 { 48 int ch; 49 char *arg = "."; 50 struct cvs_recursion cr; 51 52 while ((ch = getopt(argc, argv, cvs_cmd_commit.cmd_opts)) != -1) { 53 switch (ch) { 54 case 'f': 55 break; 56 case 'F': 57 break; 58 case 'l': 59 break; 60 case 'm': 61 logmsg = xstrdup(optarg); 62 break; 63 case 'r': 64 break; 65 case 'R': 66 break; 67 default: 68 fatal("%s", cvs_cmd_commit.cmd_synopsis); 69 } 70 } 71 72 argc -= optind; 73 argv += optind; 74 75 if (logmsg == NULL) 76 fatal("please use -m to specify a log message for now"); 77 78 TAILQ_INIT(&files_affected); 79 conflicts_found = 0; 80 81 cr.enterdir = NULL; 82 cr.leavedir = NULL; 83 cr.local = cvs_commit_check_conflicts; 84 cr.remote = NULL; 85 86 if (argc > 0) 87 cvs_file_run(argc, argv, &cr); 88 else 89 cvs_file_run(1, &arg, &cr); 90 91 if (conflicts_found != 0) 92 fatal("%d conflicts found, please correct these first", 93 conflicts_found); 94 95 cr.local = cvs_commit_local; 96 cvs_file_walklist(&files_affected, &cr); 97 cvs_file_freelist(&files_affected); 98 99 return (0); 100 } 101 102 void 103 cvs_commit_check_conflicts(struct cvs_file *cf) 104 { 105 cvs_log(LP_TRACE, "cvs_commit_check_conflicts(%s)", cf->file_path); 106 107 /* 108 * cvs_file_classify makes the noise for us 109 * XXX - we want that? 110 */ 111 cvs_file_classify(cf); 112 113 if (cf->file_status == FILE_CONFLICT || 114 cf->file_status == FILE_LOST || 115 cf->file_status == FILE_UNLINK) 116 conflicts_found++; 117 118 if (cf->file_status == FILE_ADDED || 119 cf->file_status == FILE_REMOVED || 120 cf->file_status == FILE_MODIFIED) 121 cvs_file_get(cf->file_path, &files_affected); 122 } 123 124 void 125 cvs_commit_local(struct cvs_file *cf) 126 { 127 BUF *b; 128 char *d, *f, rbuf[16]; 129 CVSENTRIES *entlist; 130 131 cvs_log(LP_TRACE, "cvs_commit_local(%s)", cf->file_path); 132 cvs_file_classify(cf); 133 134 if (cf->file_status == FILE_MODIFIED || 135 cf->file_status == FILE_REMOVED) 136 rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 137 138 cvs_printf("Checking in %s:\n", cf->file_path); 139 cvs_printf("%s <- %s\n", cf->file_rpath, cf->file_path); 140 cvs_printf("old revision: %s; ", rbuf); 141 142 d = commit_diff_file(cf); 143 144 if (cf->file_status == FILE_REMOVED) { 145 b = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); 146 if (b == NULL) 147 fatal("cvs_commit_local: failed to get HEAD"); 148 } else if (cf->file_status == FILE_MODIFIED) { 149 if ((b = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) 150 fatal("cvs_commit_local: failed to load file"); 151 } 152 153 cvs_buf_putc(b, '\0'); 154 f = cvs_buf_release(b); 155 156 if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, d) == -1) 157 fatal("cvs_commit_local: failed to set delta"); 158 159 if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, logmsg, -1, NULL) == -1) 160 fatal("cvs_commit_local: failed to add new revision"); 161 162 if (rcs_deltatext_set(cf->file_rcs, cf->file_rcs->rf_head, f) == -1) 163 fatal("cvs_commit_local: failed to set new HEAD delta"); 164 165 xfree(f); 166 xfree(d); 167 168 if (cf->file_status == FILE_REMOVED) { 169 if (rcs_state_set(cf->file_rcs, 170 cf->file_rcs->rf_head, RCS_STATE_DEAD) == -1) 171 fatal("cvs_commit_local: failed to set state"); 172 } 173 174 rcs_write(cf->file_rcs); 175 176 if (cf->file_status == FILE_REMOVED) { 177 strlcpy(rbuf, "Removed", sizeof(rbuf)); 178 } else if (cf->file_status == FILE_MODIFIED) { 179 rcsnum_tostr(cf->file_rcs->rf_head, rbuf, sizeof(rbuf)); 180 } 181 182 cvs_printf("new revision: %s\n", rbuf); 183 184 (void)unlink(cf->file_path); 185 (void)close(cf->fd); 186 cf->fd = -1; 187 188 if (cf->file_status != FILE_REMOVED) { 189 cvs_checkout_file(cf, cf->file_rcs->rf_head, 0); 190 } else { 191 entlist = cvs_ent_open(cf->file_wd); 192 cvs_ent_remove(entlist, cf->file_name); 193 cvs_ent_close(entlist, ENT_SYNC); 194 } 195 196 cvs_printf("done\n"); 197 198 } 199 200 static char * 201 commit_diff_file(struct cvs_file *cf) 202 { 203 char*delta, *p1, *p2; 204 BUF *b1, *b2, *b3; 205 206 if (cf->file_status == FILE_MODIFIED) { 207 if ((b1 = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) 208 fatal("commit_diff_file: failed to load '%s'", 209 cf->file_path); 210 } else if (cf->file_status == FILE_REMOVED) { 211 b1 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head); 212 if (b1 == NULL) 213 fatal("commit_diff_file: failed to load HEAD"); 214 b1 = rcs_kwexp_buf(b1, cf->file_rcs, cf->file_rcs->rf_head); 215 } 216 217 if ((b2 = rcs_getrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) 218 fatal("commit_diff_file: failed to load HEAD for '%s'", 219 cf->file_path); 220 221 if ((b3 = cvs_buf_alloc(128, BUF_AUTOEXT)) == NULL) 222 fatal("commit_diff_file: failed to create diff buf"); 223 224 (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 225 cvs_buf_write_stmp(b1, p1, 0600, NULL); 226 cvs_buf_free(b1); 227 228 (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 229 cvs_buf_write_stmp(b2, p2, 0600, NULL); 230 cvs_buf_free(b2); 231 232 diff_format = D_RCSDIFF; 233 if (cvs_diffreg(p1, p2, b3) == D_ERROR) 234 fatal("commit_diff_file: failed to get RCS patch"); 235 236 cvs_buf_putc(b3, '\0'); 237 delta = cvs_buf_release(b3); 238 return (delta); 239 } 240