Annotation of src/usr.bin/cvs/import.c, Revision 1.98
1.98 ! canacar 1: /* $OpenBSD: import.c,v 1.97 2008/06/15 04:21:26 joris Exp $ */
1.1 krapht 2: /*
1.45 joris 3: * Copyright (c) 2006 Joris Vink <joris@openbsd.org>
1.1 krapht 4: *
1.45 joris 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.
1.1 krapht 8: *
1.45 joris 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.
1.1 krapht 16: */
17:
1.72 otto 18: #include <sys/stat.h>
19:
20: #include <errno.h>
21: #include <fcntl.h>
22: #include <string.h>
23: #include <unistd.h>
1.1 krapht 24:
1.23 xsa 25: #include "cvs.h"
1.45 joris 26: #include "diff.h"
1.64 joris 27: #include "remote.h"
1.1 krapht 28:
1.45 joris 29: void cvs_import_local(struct cvs_file *);
1.3 jfb 30:
1.93 joris 31: static void import_loginfo(char *);
1.45 joris 32: static void import_new(struct cvs_file *);
1.98 ! canacar 33: static void import_printf(const char *, ...)
! 34: __attribute__((format(printf, 1, 2)));
1.45 joris 35: static void import_update(struct cvs_file *);
1.47 joris 36: static void import_tag(struct cvs_file *, RCSNUM *, RCSNUM *);
1.62 joris 37: static BUF *import_get_rcsdiff(struct cvs_file *, RCSNUM *);
1.3 jfb 38:
1.45 joris 39: #define IMPORT_DEFAULT_BRANCH "1.1.1"
1.19 jfb 40:
1.93 joris 41: extern char *loginfo;
42: extern char *logmsg;
43:
1.45 joris 44: static char *import_branch = IMPORT_DEFAULT_BRANCH;
45: static char *vendor_tag = NULL;
1.91 joris 46: static char **release_tags;
1.68 xsa 47: static char *koptstr;
1.51 xsa 48: static int dflag = 0;
1.91 joris 49: static int tagcount = 0;
1.93 joris 50: static BUF *logbuf;
1.51 xsa 51:
1.45 joris 52: char *import_repository = NULL;
1.47 joris 53: int import_conflicts = 0;
1.3 jfb 54:
1.15 jfb 55: struct cvs_cmd cvs_cmd_import = {
1.80 tobias 56: CVS_OP_IMPORT, CVS_USE_WDIR, "import",
1.15 jfb 57: { "im", "imp" },
58: "Import sources into CVS, using vendor branches",
1.68 xsa 59: "[-b branch] [-d] [-k mode] [-m message] "
60: "repository vendor-tag release-tags",
61: "b:dk:m:",
1.15 jfb 62: NULL,
1.45 joris 63: cvs_import
1.7 joris 64: };
1.1 krapht 65:
1.45 joris 66: int
67: cvs_import(int argc, char **argv)
1.1 krapht 68: {
1.91 joris 69: int i, ch;
1.45 joris 70: char repo[MAXPATHLEN], *arg = ".";
71: struct cvs_recursion cr;
1.93 joris 72: struct trigger_list *line_list;
1.1 krapht 73:
1.45 joris 74: while ((ch = getopt(argc, argv, cvs_cmd_import.cmd_opts)) != -1) {
1.1 krapht 75: switch (ch) {
76: case 'b':
1.45 joris 77: import_branch = optarg;
1.1 krapht 78: break;
1.51 xsa 79: case 'd':
80: dflag = 1;
81: break;
1.68 xsa 82: case 'k':
83: koptstr = optarg;
84: kflag = rcs_kflag_get(koptstr);
85: if (RCS_KWEXP_INVAL(kflag)) {
86: cvs_log(LP_ERR,
1.89 tobias 87: "invalid RCS keyword expansion mode");
1.68 xsa 88: fatal("%s", cvs_cmd_import.cmd_synopsis);
89: }
90: break;
1.1 krapht 91: case 'm':
1.45 joris 92: logmsg = optarg;
1.1 krapht 93: break;
94: default:
1.45 joris 95: fatal("%s", cvs_cmd_import.cmd_synopsis);
96: break;
1.1 krapht 97: }
98: }
99:
100: argc -= optind;
101: argv += optind;
1.19 jfb 102:
1.45 joris 103: if (argc < 3)
104: fatal("%s", cvs_cmd_import.cmd_synopsis);
1.1 krapht 105:
1.90 joris 106: import_repository = argv[0];
107: vendor_tag = argv[1];
1.91 joris 108: argc -= 2;
109: argv += 2;
110:
111: release_tags = argv;
112: tagcount = argc;
1.90 joris 113:
114: if (!rcs_sym_check(vendor_tag))
115: fatal("invalid symbol: %s", vendor_tag);
1.91 joris 116:
117: for (i = 0; i < tagcount; i++) {
118: if (!rcs_sym_check(release_tags[i]))
119: fatal("invalid symbol: %s", release_tags[i]);
120: }
1.90 joris 121:
1.94 tobias 122: if (logmsg == NULL) {
123: if (cvs_server_active)
124: fatal("no log message specified");
125: else
126: logmsg = cvs_logmsg_create(NULL, NULL, NULL, NULL);
127: }
1.45 joris 128:
1.64 joris 129: if (current_cvsroot->cr_method != CVS_METHOD_LOCAL) {
130: cvs_client_connect_to_server();
131:
132: cvs_client_send_request("Argument -b%s", IMPORT_DEFAULT_BRANCH);
1.68 xsa 133:
1.82 tobias 134: if (kflag)
1.68 xsa 135: cvs_client_send_request("Argument -k%s", koptstr);
136:
1.75 joris 137: cvs_client_send_logmsg(logmsg);
1.64 joris 138: cvs_client_send_request("Argument %s", import_repository);
139: cvs_client_send_request("Argument %s", vendor_tag);
1.91 joris 140: for (i = 0; i < tagcount; i++)
141: cvs_client_send_request("Argument %s", release_tags[i]);
1.64 joris 142:
143: cr.enterdir = NULL;
144: cr.leavedir = NULL;
145: cr.fileproc = cvs_client_sendfile;
146: cr.flags = CR_RECURSE_DIRS;
147:
148: cvs_file_run(1, &arg, &cr);
149: cvs_client_senddir(".");
150: cvs_client_send_request("import");
151:
152: cvs_client_get_responses();
153: return (0);
154: }
155:
1.93 joris 156: if (cvs_logmsg_verify(logmsg))
157: return (0);
158:
1.70 xsa 159: (void)xsnprintf(repo, sizeof(repo), "%s/%s",
160: current_cvsroot->cr_dir, import_repository);
1.45 joris 161:
1.93 joris 162: import_loginfo(import_repository);
163:
1.48 joris 164: if (cvs_noexec != 1) {
165: if (mkdir(repo, 0755) == -1 && errno != EEXIST)
166: fatal("cvs_import: %s: %s", repo, strerror(errno));
167: }
1.45 joris 168:
169: cr.enterdir = NULL;
170: cr.leavedir = NULL;
1.53 joris 171: cr.fileproc = cvs_import_local;
1.45 joris 172: cr.flags = CR_RECURSE_DIRS;
173: cvs_file_run(1, &arg, &cr);
1.1 krapht 174:
1.47 joris 175: if (import_conflicts != 0) {
1.93 joris 176: import_printf("\n%d conflicts created by this import.\n\n",
1.47 joris 177: import_conflicts);
1.93 joris 178: import_printf("Use the following command to help the merge:\n");
179: import_printf("\topencvs checkout ");
180: import_printf("-j%s:yesterday -j%s %s\n\n", vendor_tag,
1.47 joris 181: vendor_tag, import_repository);
182: } else {
1.93 joris 183: import_printf("\nNo conflicts created by this import.\n\n");
1.47 joris 184: }
185:
1.93 joris 186: loginfo = cvs_buf_release(logbuf);
187: logbuf = NULL;
188:
189: line_list = cvs_trigger_getlines(CVS_PATH_LOGINFO, import_repository);
190: if (line_list != NULL) {
191: cvs_trigger_handle(CVS_TRIGGER_LOGINFO, import_repository,
192: loginfo, line_list, NULL);
193: cvs_trigger_freelist(line_list);
194: }
195:
196: xfree(loginfo);
1.7 joris 197: return (0);
198: }
1.1 krapht 199:
1.93 joris 200: static void
201: import_printf(const char *fmt, ...)
202: {
203: char *str;
204: va_list vap;
205:
206: va_start(vap, fmt);
207: if (vasprintf(&str, fmt, vap) == -1)
208: fatal("import_printf: could not allocate memory");
209: va_end(vap);
210:
211: cvs_printf("%s", str);
212: cvs_buf_puts(logbuf, str);
213: }
214:
1.45 joris 215: void
216: cvs_import_local(struct cvs_file *cf)
1.7 joris 217: {
1.45 joris 218: int isnew;
219: struct stat st;
220: char repo[MAXPATHLEN];
1.15 jfb 221:
1.45 joris 222: cvs_log(LP_TRACE, "cvs_import_local(%s)", cf->file_path);
1.1 krapht 223:
1.77 joris 224: cvs_file_classify(cf, cvs_directory_tag);
1.1 krapht 225:
1.45 joris 226: if (cf->file_type == CVS_DIR) {
227: if (!strcmp(cf->file_path, "."))
228: return;
1.19 jfb 229:
1.45 joris 230: if (verbosity > 1)
231: cvs_log(LP_NOTICE, "Importing %s", cf->file_path);
1.19 jfb 232:
1.48 joris 233: if (cvs_noexec == 1)
234: return;
1.19 jfb 235:
1.45 joris 236: if (mkdir(cf->file_rpath, 0755) == -1 && errno != EEXIST)
237: fatal("cvs_import_local: %s: %s", cf->file_rpath,
238: strerror(errno));
1.15 jfb 239:
1.45 joris 240: return;
1.15 jfb 241: }
242:
1.45 joris 243: isnew = 1;
1.67 xsa 244: (void)xsnprintf(repo, sizeof(repo), "%s/%s/%s/%s%s",
1.45 joris 245: current_cvsroot->cr_dir, cf->file_wd, CVS_PATH_ATTIC,
246: cf->file_name, RCS_FILE_EXT);
1.34 joris 247:
1.45 joris 248: if (cf->file_rcs != NULL || stat(repo, &st) != -1)
249: isnew = 0;
1.15 jfb 250:
1.45 joris 251: if (isnew == 1)
252: import_new(cf);
253: else
254: import_update(cf);
1.15 jfb 255: }
256:
1.45 joris 257: static void
1.93 joris 258: import_loginfo(char *repo)
259: {
260: int i;
261: char pwd[MAXPATHLEN];
262:
263: if (getcwd(pwd, sizeof(pwd)) == NULL)
264: fatal("Can't get working directory");
265:
266: logbuf = cvs_buf_alloc(1024);
267: cvs_trigger_loginfo_header(logbuf, repo);
268:
269: cvs_buf_puts(logbuf, "Log Message:\n");
270: cvs_buf_puts(logbuf, logmsg);
271: if (logmsg[0] != '\0' && logmsg[strlen(logmsg) - 1] != '\n')
272: cvs_buf_putc(logbuf, '\n');
273: cvs_buf_putc(logbuf, '\n');
274:
275: cvs_buf_puts(logbuf, "Status:\n\n");
276:
277: cvs_buf_puts(logbuf, "Vendor Tag:\t");
278: cvs_buf_puts(logbuf, vendor_tag);
279: cvs_buf_putc(logbuf, '\n');
280: cvs_buf_puts(logbuf, "Release Tags:\t");
281:
282: for (i = 0; i < tagcount ; i++) {
283: cvs_buf_puts(logbuf, "\t\t");
284: cvs_buf_puts(logbuf, release_tags[i]);
285: cvs_buf_putc(logbuf, '\n');
286: }
287: cvs_buf_putc(logbuf, '\n');
288: cvs_buf_putc(logbuf, '\n');
289: }
290:
291: static void
1.45 joris 292: import_new(struct cvs_file *cf)
1.15 jfb 293: {
1.91 joris 294: int i;
1.45 joris 295: BUF *bp;
1.95 joris 296: mode_t mode;
1.51 xsa 297: time_t tstamp;
298: struct stat st;
1.45 joris 299: struct rcs_branch *brp;
1.41 joris 300: struct rcs_delta *rdp;
1.45 joris 301: RCSNUM *branch, *brev;
302:
1.51 xsa 303: tstamp = -1;
304:
1.45 joris 305: cvs_log(LP_TRACE, "import_new(%s)", cf->file_name);
306:
1.48 joris 307: if (cvs_noexec == 1) {
1.93 joris 308: import_printf("N %s/%s\n", import_repository, cf->file_path);
1.48 joris 309: return;
310: }
311:
1.95 joris 312: if (fstat(cf->fd, &st) == -1)
313: fatal("import_new: %s", strerror(errno));
1.51 xsa 314:
1.95 joris 315: mode = st.st_mode;
316:
317: if (dflag == 1)
1.51 xsa 318: tstamp = st.st_mtime;
319:
1.45 joris 320: if ((branch = rcsnum_parse(import_branch)) == NULL)
321: fatal("import_new: failed to parse branch");
322:
1.83 tobias 323: bp = cvs_buf_load_fd(cf->fd);
1.45 joris 324:
325: if ((brev = rcsnum_brtorev(branch)) == NULL)
326: fatal("import_new: failed to get first branch revision");
1.24 xsa 327:
1.97 joris 328: cf->repo_fd = open(cf->file_rpath, O_CREAT | O_RDONLY);
1.45 joris 329: if (cf->repo_fd < 0)
330: fatal("import_new: %s: %s", cf->file_rpath, strerror(errno));
1.1 krapht 331:
1.95 joris 332: cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, RCS_CREATE,
333: (mode & ~(S_IWUSR | S_IWGRP | S_IWOTH)));
1.45 joris 334: if (cf->file_rcs == NULL)
335: fatal("import_new: failed to create RCS file for %s",
336: cf->file_path);
1.1 krapht 337:
1.45 joris 338: rcs_branch_set(cf->file_rcs, branch);
1.18 jfb 339:
1.45 joris 340: if (rcs_sym_add(cf->file_rcs, vendor_tag, branch) == -1)
1.88 xsa 341: fatal("import_new: failed to add vendor tag");
1.18 jfb 342:
1.91 joris 343: for (i = 0; i < tagcount; i++) {
344: if (rcs_sym_add(cf->file_rcs, release_tags[i], brev) == -1)
345: fatal("import_new: failed to add release tag");
346: }
1.17 jfb 347:
1.51 xsa 348: if (rcs_rev_add(cf->file_rcs, brev, logmsg, tstamp, NULL) == -1)
1.45 joris 349: fatal("import_new: failed to create first branch revision");
1.1 krapht 350:
1.76 tobias 351: if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, "Initial revision",
352: tstamp, NULL) == -1)
1.45 joris 353: fatal("import_new: failed to create first revision");
1.20 jfb 354:
1.45 joris 355: if ((rdp = rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL)
356: fatal("import_new: cannot find newly added revision");
1.41 joris 357:
1.42 ray 358: brp = xmalloc(sizeof(*brp));
1.41 joris 359: brp->rb_num = rcsnum_alloc();
360: rcsnum_cpy(brev, brp->rb_num, 0);
361: TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list);
1.30 joris 362:
1.45 joris 363: if (rcs_deltatext_set(cf->file_rcs,
1.60 joris 364: cf->file_rcs->rf_head, bp) == -1)
1.45 joris 365: fatal("import_new: failed to set deltatext");
1.30 joris 366:
1.82 tobias 367: if (kflag)
1.68 xsa 368: rcs_kwexp_set(cf->file_rcs, kflag);
369:
1.45 joris 370: rcs_write(cf->file_rcs);
1.93 joris 371: import_printf("N %s/%s\n", import_repository, cf->file_path);
1.30 joris 372:
1.45 joris 373: rcsnum_free(branch);
374: rcsnum_free(brev);
1.19 jfb 375: }
376:
1.45 joris 377: static void
378: import_update(struct cvs_file *cf)
1.19 jfb 379: {
1.64 joris 380: int ret;
1.62 joris 381: BUF *b1, *b2, *d;
1.74 xsa 382: char branch[CVS_REV_BUFSZ];
1.81 joris 383: RCSNUM *newrev, *rev, *brev;
1.47 joris 384:
1.45 joris 385: cvs_log(LP_TRACE, "import_update(%s)", cf->file_path);
1.96 tobias 386:
387: if (cf->file_rcs->rf_head == NULL)
388: fatal("no head revision in RCS file for `%s'", cf->file_path);
1.47 joris 389:
1.66 niallo 390: if ((rev = rcs_translate_tag(import_branch, cf->file_rcs)) == NULL)
1.84 tobias 391: fatal("import_update: could not translate tag `%s'",
392: import_branch);
1.47 joris 393:
394: if ((brev = rcsnum_parse(import_branch)) == NULL)
395: fatal("import_update: rcsnum_parse failed");
396:
1.84 tobias 397: b1 = rcs_rev_getbuf(cf->file_rcs, rev, RCS_KWEXP_NONE);
1.83 tobias 398: b2 = cvs_buf_load_fd(cf->fd);
1.81 joris 399:
400: ret = cvs_buf_differ(b1, b2);
401: cvs_buf_free(b1);
402: cvs_buf_free(b2);
403: if (ret == 0) {
404: import_tag(cf, brev, rev);
405: rcsnum_free(brev);
1.86 joris 406: if (cvs_noexec != 1)
407: rcs_write(cf->file_rcs);
1.93 joris 408: import_printf("U %s/%s\n", import_repository, cf->file_path);
1.81 joris 409: return;
1.47 joris 410: }
411:
412: if (cf->file_rcs->rf_branch != NULL)
413: rcsnum_tostr(cf->file_rcs->rf_branch, branch, sizeof(branch));
414:
1.86 joris 415: if (cf->file_rcs->rf_branch == NULL || cf->in_attic == 1 ||
416: strcmp(branch, import_branch)) {
417: import_conflicts++;
1.93 joris 418: import_printf("C %s/%s\n", import_repository, cf->file_path);
1.86 joris 419: } else {
1.93 joris 420: import_printf("U %s/%s\n", import_repository, cf->file_path);
1.86 joris 421: }
422:
423: if (cvs_noexec == 1)
424: return;
425:
1.81 joris 426: d = import_get_rcsdiff(cf, rev);
427: newrev = rcsnum_inc(rev);
1.47 joris 428:
429: if (rcs_rev_add(cf->file_rcs, newrev, logmsg, -1, NULL) == -1)
430: fatal("import_update: failed to add new revision");
431:
432: if (rcs_deltatext_set(cf->file_rcs, newrev, d) == -1)
433: fatal("import_update: failed to set deltatext");
1.48 joris 434:
1.47 joris 435: import_tag(cf, brev, newrev);
1.68 xsa 436:
1.82 tobias 437: if (kflag)
1.68 xsa 438: rcs_kwexp_set(cf->file_rcs, kflag);
1.47 joris 439:
440: rcsnum_free(brev);
441: rcs_write(cf->file_rcs);
442: }
443:
444: static void
445: import_tag(struct cvs_file *cf, RCSNUM *branch, RCSNUM *newrev)
446: {
1.91 joris 447: int i;
1.47 joris 448:
1.48 joris 449: if (cvs_noexec != 1) {
450: rcs_sym_add(cf->file_rcs, vendor_tag, branch);
1.47 joris 451:
1.91 joris 452: for (i = 0; i < tagcount; i++)
453: rcs_sym_add(cf->file_rcs, release_tags[i], newrev);
1.48 joris 454: }
1.47 joris 455: }
456:
1.62 joris 457: static BUF *
1.47 joris 458: import_get_rcsdiff(struct cvs_file *cf, RCSNUM *rev)
459: {
1.62 joris 460: char *p1, *p2;
1.61 niallo 461: BUF *b1, *b2;
1.85 joris 462: int fd1, fd2;
1.47 joris 463:
1.83 tobias 464: b2 = cvs_buf_alloc(128);
1.47 joris 465:
1.87 joris 466: b1 = cvs_buf_load_fd(cf->fd);
1.64 joris 467:
1.87 joris 468: (void)xasprintf(&p1, "%s/diff1.XXXXXXXXXX", cvs_tmpdir);
469: fd1 = cvs_buf_write_stmp(b1, p1, NULL);
470: cvs_buf_free(b1);
1.48 joris 471:
1.87 joris 472: (void)xasprintf(&p2, "%s/diff2.XXXXXXXXXX", cvs_tmpdir);
473: fd2 = rcs_rev_write_stmp(cf->file_rcs, rev, p2, RCS_KWEXP_NONE);
1.48 joris 474:
1.87 joris 475: diff_format = D_RCSDIFF;
476: if (cvs_diffreg(p2, p1, fd2, fd1, b2) == D_ERROR)
477: fatal("import_get_rcsdiff: failed to get RCS patch");
1.85 joris 478:
1.87 joris 479: close(fd1);
480: close(fd2);
1.59 xsa 481:
1.87 joris 482: (void)unlink(p1);
483: (void)unlink(p2);
1.55 xsa 484:
1.87 joris 485: xfree(p1);
486: xfree(p2);
1.55 xsa 487:
1.62 joris 488: return (b2);
1.1 krapht 489: }