1 /* $OpenBSD: import.c,v 1.66 2007/01/20 01:07:51 niallo 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 "remote.h" 24 25 void cvs_import_local(struct cvs_file *); 26 27 static void import_new(struct cvs_file *); 28 static void import_update(struct cvs_file *); 29 static void import_tag(struct cvs_file *, RCSNUM *, RCSNUM *); 30 static BUF *import_get_rcsdiff(struct cvs_file *, RCSNUM *); 31 32 #define IMPORT_DEFAULT_BRANCH "1.1.1" 33 34 static char *import_branch = IMPORT_DEFAULT_BRANCH; 35 static char *logmsg = NULL; 36 static char *vendor_tag = NULL; 37 static char *release_tag = NULL; 38 39 static int dflag = 0; 40 41 char *import_repository = NULL; 42 int import_conflicts = 0; 43 44 struct cvs_cmd cvs_cmd_import = { 45 CVS_OP_IMPORT, 0, "import", 46 { "im", "imp" }, 47 "Import sources into CVS, using vendor branches", 48 "[-d] [-b branch] [-m message] repository vendor-tag release-tags", 49 "b:dm:", 50 NULL, 51 cvs_import 52 }; 53 54 int 55 cvs_import(int argc, char **argv) 56 { 57 int ch; 58 char repo[MAXPATHLEN], *arg = "."; 59 struct cvs_recursion cr; 60 61 while ((ch = getopt(argc, argv, cvs_cmd_import.cmd_opts)) != -1) { 62 switch (ch) { 63 case 'b': 64 import_branch = optarg; 65 break; 66 case 'd': 67 dflag = 1; 68 break; 69 case 'm': 70 logmsg = optarg; 71 break; 72 default: 73 fatal("%s", cvs_cmd_import.cmd_synopsis); 74 break; 75 } 76 } 77 78 argc -= optind; 79 argv += optind; 80 81 if (argc < 3) 82 fatal("%s", cvs_cmd_import.cmd_synopsis); 83 84 if (logmsg == NULL) 85 logmsg = cvs_logmsg_create(NULL, NULL, NULL); 86 87 if (logmsg == NULL) 88 fatal("This shouldnt happen, honestly!"); 89 90 import_repository = argv[0]; 91 vendor_tag = argv[1]; 92 release_tag = argv[2]; 93 94 if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) { 95 cvs_client_connect_to_server(); 96 97 cvs_client_send_request("Argument -b%s", IMPORT_DEFAULT_BRANCH); 98 cvs_client_send_request("Argument -m%s", logmsg); 99 cvs_client_send_request("Argument %s", import_repository); 100 cvs_client_send_request("Argument %s", vendor_tag); 101 cvs_client_send_request("Argument %s", release_tag); 102 103 cr.enterdir = NULL; 104 cr.leavedir = NULL; 105 cr.fileproc = cvs_client_sendfile; 106 cr.flags = CR_RECURSE_DIRS; 107 108 cvs_file_run(1, &arg, &cr); 109 cvs_client_senddir("."); 110 cvs_client_send_request("import"); 111 112 cvs_client_get_responses(); 113 return (0); 114 } 115 116 if (cvs_path_cat(current_cvsroot->cr_dir, import_repository, 117 repo, sizeof(repo)) >= sizeof(repo)) 118 fatal("cvs_import: truncation"); 119 120 if (cvs_noexec != 1) { 121 if (mkdir(repo, 0755) == -1 && errno != EEXIST) 122 fatal("cvs_import: %s: %s", repo, strerror(errno)); 123 } 124 125 cr.enterdir = NULL; 126 cr.leavedir = NULL; 127 cr.fileproc = cvs_import_local; 128 cr.flags = CR_RECURSE_DIRS; 129 cvs_file_run(1, &arg, &cr); 130 131 if (import_conflicts != 0) { 132 cvs_printf("\n%d conflicts created by this import.\n\n", 133 import_conflicts); 134 cvs_printf("Use the following command to help the merge:\n"); 135 cvs_printf("\topencvs checkout "); 136 cvs_printf("-j%s:yesterday -j%s %s\n\n", vendor_tag, 137 vendor_tag, import_repository); 138 } else { 139 cvs_printf("\nNo conflicts created by this import.\n\n"); 140 } 141 142 return (0); 143 } 144 145 void 146 cvs_import_local(struct cvs_file *cf) 147 { 148 int l; 149 int isnew; 150 struct stat st; 151 char repo[MAXPATHLEN]; 152 153 cvs_log(LP_TRACE, "cvs_import_local(%s)", cf->file_path); 154 155 cvs_file_classify(cf, NULL, 0); 156 157 if (cf->file_type == CVS_DIR) { 158 if (!strcmp(cf->file_path, ".")) 159 return; 160 161 if (verbosity > 1) 162 cvs_log(LP_NOTICE, "Importing %s", cf->file_path); 163 164 if (cvs_noexec == 1) 165 return; 166 167 if (mkdir(cf->file_rpath, 0755) == -1 && errno != EEXIST) 168 fatal("cvs_import_local: %s: %s", cf->file_rpath, 169 strerror(errno)); 170 171 return; 172 } 173 174 isnew = 1; 175 l = snprintf(repo, sizeof(repo), "%s/%s/%s/%s%s", 176 current_cvsroot->cr_dir, cf->file_wd, CVS_PATH_ATTIC, 177 cf->file_name, RCS_FILE_EXT); 178 if (l == -1 || l >= (int)sizeof(repo)) 179 fatal("import_new: overflow"); 180 181 if (cf->file_rcs != NULL || stat(repo, &st) != -1) 182 isnew = 0; 183 184 if (isnew == 1) 185 import_new(cf); 186 else 187 import_update(cf); 188 } 189 190 static void 191 import_new(struct cvs_file *cf) 192 { 193 BUF *bp; 194 time_t tstamp; 195 struct stat st; 196 struct rcs_branch *brp; 197 struct rcs_delta *rdp; 198 RCSNUM *branch, *brev; 199 200 tstamp = -1; 201 202 cvs_log(LP_TRACE, "import_new(%s)", cf->file_name); 203 204 if (cvs_noexec == 1) { 205 cvs_printf("N %s/%s\n", import_repository, cf->file_path); 206 return; 207 } 208 209 if (dflag == 1) { 210 if (fstat(cf->fd, &st) == -1) 211 fatal("import_new: %s", strerror(errno)); 212 213 tstamp = st.st_mtime; 214 } 215 216 if ((branch = rcsnum_parse(import_branch)) == NULL) 217 fatal("import_new: failed to parse branch"); 218 219 if ((bp = cvs_buf_load_fd(cf->fd, BUF_AUTOEXT)) == NULL) 220 fatal("import_new: failed to load %s", cf->file_path); 221 222 if ((brev = rcsnum_brtorev(branch)) == NULL) 223 fatal("import_new: failed to get first branch revision"); 224 225 cf->repo_fd = open(cf->file_rpath, O_CREAT|O_TRUNC|O_WRONLY); 226 if (cf->repo_fd < 0) 227 fatal("import_new: %s: %s", cf->file_rpath, strerror(errno)); 228 229 cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, RCS_CREATE, 0444); 230 if (cf->file_rcs == NULL) 231 fatal("import_new: failed to create RCS file for %s", 232 cf->file_path); 233 234 rcs_branch_set(cf->file_rcs, branch); 235 236 if (rcs_sym_add(cf->file_rcs, vendor_tag, branch) == -1) 237 fatal("import_new: failed to add release tag"); 238 239 if (rcs_sym_add(cf->file_rcs, release_tag, brev) == -1) 240 fatal("import_new: failed to add vendor tag"); 241 242 if (rcs_rev_add(cf->file_rcs, brev, logmsg, tstamp, NULL) == -1) 243 fatal("import_new: failed to create first branch revision"); 244 245 if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, logmsg, tstamp, NULL) == -1) 246 fatal("import_new: failed to create first revision"); 247 248 if ((rdp = rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) 249 fatal("import_new: cannot find newly added revision"); 250 251 brp = xmalloc(sizeof(*brp)); 252 brp->rb_num = rcsnum_alloc(); 253 rcsnum_cpy(brev, brp->rb_num, 0); 254 TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list); 255 256 if (rcs_deltatext_set(cf->file_rcs, 257 cf->file_rcs->rf_head, bp) == -1) 258 fatal("import_new: failed to set deltatext"); 259 260 rcs_write(cf->file_rcs); 261 cvs_printf("N %s/%s\n", import_repository, cf->file_path); 262 263 rcsnum_free(branch); 264 rcsnum_free(brev); 265 } 266 267 static void 268 import_update(struct cvs_file *cf) 269 { 270 int ret; 271 BUF *b1, *b2, *d; 272 char branch[16]; 273 RCSNUM *newrev, *rev, *brev, *hrev; 274 275 cvs_log(LP_TRACE, "import_update(%s)", cf->file_path); 276 277 if ((rev = rcs_translate_tag(import_branch, cf->file_rcs)) == NULL) 278 fatal("import_update: could not translate tag `%s'", import_branch); 279 280 if ((brev = rcsnum_parse(import_branch)) == NULL) 281 fatal("import_update: rcsnum_parse failed"); 282 283 if (rev != NULL) { 284 if ((b1 = rcs_rev_getbuf(cf->file_rcs, rev, 0)) == NULL) 285 fatal("import_update: failed to grab revision"); 286 287 if ((b2 = cvs_buf_load_fd(cf->fd, BUF_AUTOEXT)) == NULL) 288 fatal("import_update: failed to load %s", 289 cf->file_path); 290 291 ret = cvs_buf_differ(b1, b2); 292 if (ret == 0) { 293 import_tag(cf, brev, rev); 294 rcsnum_free(brev); 295 rcs_write(cf->file_rcs); 296 return; 297 } 298 } 299 300 if (cf->file_rcs->rf_branch != NULL) 301 rcsnum_tostr(cf->file_rcs->rf_branch, branch, sizeof(branch)); 302 303 if (rev != NULL) { 304 d = import_get_rcsdiff(cf, rev); 305 newrev = rcsnum_inc(rev); 306 } else { 307 hrev = rcs_head_get(cf->file_rcs); 308 d = import_get_rcsdiff(cf, hrev); 309 rcsnum_free(hrev); 310 newrev = rcsnum_brtorev(brev); 311 } 312 313 if (rcs_rev_add(cf->file_rcs, newrev, logmsg, -1, NULL) == -1) 314 fatal("import_update: failed to add new revision"); 315 316 if (rcs_deltatext_set(cf->file_rcs, newrev, d) == -1) 317 fatal("import_update: failed to set deltatext"); 318 319 import_tag(cf, brev, newrev); 320 321 if (cf->file_rcs->rf_branch == NULL || cf->file_rcs->rf_inattic == 1 || 322 strcmp(branch, import_branch)) { 323 import_conflicts++; 324 cvs_printf("C %s/%s\n", import_repository, cf->file_path); 325 } else { 326 cvs_printf("U %s/%s\n", import_repository, cf->file_path); 327 } 328 329 rcsnum_free(brev); 330 rcs_write(cf->file_rcs); 331 } 332 333 static void 334 import_tag(struct cvs_file *cf, RCSNUM *branch, RCSNUM *newrev) 335 { 336 char b[16]; 337 338 if (cvs_noexec != 1) { 339 rcsnum_tostr(branch, b, sizeof(b)); 340 rcs_sym_add(cf->file_rcs, vendor_tag, branch); 341 342 rcsnum_tostr(newrev, b, sizeof(b)); 343 rcs_sym_add(cf->file_rcs, release_tag, newrev); 344 } 345 } 346 347 static BUF * 348 import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev) 349 { 350 char *p1, *p2; 351 BUF *b1, *b2; 352 353 b2 = cvs_buf_alloc(128, BUF_AUTOEXT); 354 355 if (cvs_noexec != 1) { 356 if ((b1 = cvs_buf_load_fd(cf->fd, BUF_AUTOEXT)) == NULL) 357 fatal("import_get_rcsdiff: failed loading %s", 358 cf->file_path); 359 360 (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir); 361 cvs_buf_write_stmp(b1, p1, NULL); 362 cvs_buf_free(b1); 363 364 (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir); 365 rcs_rev_write_stmp(cf->file_rcs, rev, p2, 0); 366 367 diff_format = D_RCSDIFF; 368 if (cvs_diffreg(p2, p1, b2) == D_ERROR) 369 fatal("import_get_rcsdiff: failed to get RCS patch"); 370 371 (void)unlink(p1); 372 (void)unlink(p2); 373 374 xfree(p1); 375 xfree(p2); 376 } 377 378 return (b2); 379 } 380