version 1.44, 2006/05/27 03:30:30 |
version 1.45, 2006/05/30 07:00:30 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* |
/* |
* Copyright (c) 2004 Joris Vink <joris@openbsd.org> |
* Copyright (c) 2006 Joris Vink <joris@openbsd.org> |
* All rights reserved. |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Permission to use, copy, modify, and distribute this software for any |
* modification, are permitted provided that the following conditions |
* purpose with or without fee is hereby granted, provided that the above |
* are met: |
* copyright notice and this permission notice appear in all copies. |
* |
* |
* 1. Redistributions of source code must retain the above copyright |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
* notice, this list of conditions and the following disclaimer. |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
* 2. The name of the author may not be used to endorse or promote products |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
* derived from this software without specific prior written permission. |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
* |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
* 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. |
|
*/ |
*/ |
|
|
#include "includes.h" |
#include "includes.h" |
|
|
#include "cvs.h" |
#include "cvs.h" |
|
#include "diff.h" |
#include "log.h" |
#include "log.h" |
#include "proto.h" |
#include "proto.h" |
|
|
|
int cvs_import(int, char **); |
|
void cvs_import_local(struct cvs_file *); |
|
|
#define CVS_IMPORT_DEFBRANCH "1.1.1" |
static void import_new(struct cvs_file *); |
|
static void import_update(struct cvs_file *); |
|
|
|
#define IMPORT_DEFAULT_BRANCH "1.1.1" |
|
|
static int cvs_import_init(struct cvs_cmd *, int, char **, int *); |
static char *import_branch = IMPORT_DEFAULT_BRANCH; |
static int cvs_import_pre_exec(struct cvsroot *); |
static char *logmsg = NULL; |
static int cvs_import_pre_exec(struct cvsroot *); |
static char *vendor_tag = NULL; |
static int cvs_import_post_exec(struct cvsroot *); |
static char *release_tag = NULL; |
static int cvs_import_remote(CVSFILE *, void *); |
|
static int cvs_import_local(CVSFILE *, void *); |
|
static int cvs_import_cleanup(void); |
|
|
|
static int dflag = 0; |
char *import_repository = NULL; |
static int conflicts = 0; |
|
static RCSNUM *imp_brnum; |
|
|
|
static char *module, *vendor, *release; |
|
|
|
struct cvs_cmd cvs_cmd_import = { |
struct cvs_cmd cvs_cmd_import = { |
CVS_OP_IMPORT, CVS_REQ_IMPORT, "import", |
CVS_OP_IMPORT, CVS_REQ_IMPORT, "import", |
{ "im", "imp" }, |
{ "im", "imp" }, |
"Import sources into CVS, using vendor branches", |
"Import sources into CVS, using vendor branches", |
"[-d] [-b branch] [-I ign] [-k mode] [-m msg] [-W spec] module " |
"[-b vendor branch id] [-m message] repository vendor-tag release-tags", |
"vendortag releasetag ...", |
"b:m:", |
"b:dI:k:m:W:", |
|
NULL, |
NULL, |
CF_RECURSE | CF_IGNORE | CF_NOSYMS, |
cvs_import |
cvs_import_init, |
|
cvs_import_pre_exec, |
|
cvs_import_remote, |
|
cvs_import_local, |
|
cvs_import_post_exec, |
|
cvs_import_cleanup, |
|
CVS_CMD_SENDDIR |
|
}; |
}; |
|
|
static int |
int |
cvs_import_init(struct cvs_cmd *cmd, int argc, char **argv, int *arg) |
cvs_import(int argc, char **argv) |
{ |
{ |
int ch; |
int ch, l; |
|
char repo[MAXPATHLEN], *arg = "."; |
|
struct cvs_recursion cr; |
|
|
while ((ch = getopt(argc, argv, cmd->cmd_opts)) != -1) { |
while ((ch = getopt(argc, argv, cvs_cmd_import.cmd_opts)) != -1) { |
switch (ch) { |
switch (ch) { |
case 'b': |
case 'b': |
if ((imp_brnum = rcsnum_parse(optarg)) == NULL) { |
import_branch = optarg; |
cvs_log(LP_ERR, "%s is not a numeric branch", |
|
optarg); |
|
return (CVS_EX_USAGE); |
|
} |
|
break; |
break; |
case 'd': |
|
dflag = 1; |
|
break; |
|
case 'I': |
|
if (cvs_file_ignore(optarg) < 0) { |
|
cvs_log(LP_ERR, "failed to add `%s' to list " |
|
"of ignore patterns", optarg); |
|
return (CVS_EX_USAGE); |
|
} |
|
break; |
|
case 'k': |
|
break; |
|
case 'm': |
case 'm': |
cvs_msg = xstrdup(optarg); |
logmsg = optarg; |
break; |
break; |
default: |
default: |
return (CVS_EX_USAGE); |
fatal("%s", cvs_cmd_import.cmd_synopsis); |
|
break; |
} |
} |
} |
} |
|
|
argc -= optind; |
argc -= optind; |
argv += optind; |
argv += optind; |
if (argc != 3) |
|
return (CVS_EX_USAGE); |
|
|
|
if (imp_brnum == NULL && |
if (argc < 3) |
(imp_brnum = rcsnum_parse(CVS_IMPORT_DEFBRANCH)) == NULL) |
fatal("%s", cvs_cmd_import.cmd_synopsis); |
fatal("cvs_import_init: rcsnum_parse failed"); |
|
|
|
module = argv[0]; |
if (logmsg == NULL) |
vendor = argv[1]; |
fatal("please specify a logmessage using -m for now"); |
release = argv[2]; |
|
|
|
*arg = optind + 3; |
import_repository = argv[0]; |
|
vendor_tag = argv[1]; |
|
release_tag = argv[2]; |
|
|
if (cvs_msg == NULL) |
l = snprintf(repo, sizeof(repo), "%s/%s", current_cvsroot->cr_dir, |
cvs_msg = cvs_logmsg_get(NULL, NULL, NULL, NULL); |
import_repository); |
|
if (l == -1 || l >= (int)sizeof(repo)) |
|
fatal("cvs_import: overflow"); |
|
|
return (0); |
if (mkdir(repo, 0755) == -1 && errno != EEXIST) |
} |
fatal("cvs_import: %s: %s", repo, strerror(errno)); |
|
|
static int |
cr.enterdir = NULL; |
cvs_import_pre_exec(struct cvsroot *root) |
cr.leavedir = NULL; |
{ |
cr.remote = NULL; |
char numbuf[64], repodir[MAXPATHLEN]; |
cr.local = cvs_import_local; |
|
cr.flags = CR_RECURSE_DIRS; |
|
cvs_file_run(1, &arg, &cr); |
|
|
if (root->cr_method == CVS_METHOD_LOCAL) { |
|
if (cvs_path_cat(root->cr_dir, module, repodir, |
|
sizeof(repodir)) >= sizeof(repodir)) |
|
fatal("cvs_import_pre_exec: cvs_path_cat overflow"); |
|
|
|
if (mkdir(repodir, 0775) == -1) |
|
fatal("cvs_import_pre_exec: mkdir `%s': %s", |
|
repodir, strerror(errno)); |
|
} else { |
|
rcsnum_tostr(imp_brnum, numbuf, sizeof(numbuf)); |
|
|
|
cvs_sendarg(root, "-b", 0); |
|
cvs_sendarg(root, numbuf, 0); |
|
cvs_logmsg_send(root, cvs_msg); |
|
cvs_sendarg(root, module, 0); |
|
cvs_sendarg(root, vendor, 0); |
|
cvs_sendarg(root, release, 0); |
|
} |
|
|
|
return (0); |
return (0); |
} |
} |
|
|
static int |
void |
cvs_import_post_exec(struct cvsroot *root) |
cvs_import_local(struct cvs_file *cf) |
{ |
{ |
char buf[8]; |
int l; |
|
int isnew; |
|
struct stat st; |
|
char repo[MAXPATHLEN]; |
|
|
if (root->cr_method == CVS_METHOD_LOCAL) { |
cvs_log(LP_TRACE, "cvs_import_local(%s)", cf->file_path); |
if (conflicts > 0) |
|
snprintf(buf, sizeof(buf), "%d", conflicts); |
|
|
|
if (verbosity > 0) |
cvs_file_classify(cf, 0); |
cvs_printf("\n%s conflicts created by this import\n\n", |
|
conflicts == 0 ? "No" : buf); |
|
} |
|
|
|
return (CVS_EX_OK); |
if (cf->file_type == CVS_DIR) { |
} |
if (!strcmp(cf->file_path, ".")) |
|
return; |
|
|
/* |
if (verbosity > 1) |
* cvs_import_remote() |
cvs_log(LP_NOTICE, "Importing %s", cf->file_path); |
* |
|
* Perform the import of a single file or directory. |
|
*/ |
|
static int |
|
cvs_import_remote(CVSFILE *cf, void *arg) |
|
{ |
|
size_t sz; |
|
struct cvsroot *root; |
|
char fpath[MAXPATHLEN], repodir[MAXPATHLEN]; |
|
char repo[MAXPATHLEN], date[32]; |
|
|
|
root = CVS_DIR_ROOT(cf); |
|
|
|
if (cvs_path_cat(root->cr_dir, module, repo, sizeof(repo)) >= |
if (mkdir(cf->file_rpath, 0755) == -1 && errno != EEXIST) |
sizeof(repo)) |
fatal("cvs_import_local: %s: %s", cf->file_rpath, |
fatal("cvs_import_remove: cvs_path_cat overflow"); |
strerror(errno)); |
|
|
cvs_file_getpath(cf, fpath, sizeof(fpath)); |
return; |
|
|
if (cf->cf_type == DT_DIR) { |
|
if (!strcmp(cf->cf_name, ".")) |
|
strlcpy(repodir, repo, sizeof(repodir)); |
|
else { |
|
if(cvs_path_cat(repo, fpath, repodir, |
|
sizeof(repodir)) >= sizeof(repodir)) |
|
fatal("cvs_import_remove: cvs_path_cat overflow"); |
|
} |
|
|
|
cvs_sendreq(root, CVS_REQ_DIRECTORY, fpath); |
|
cvs_sendln(root, repodir); |
|
return (0); |
|
} |
} |
|
|
if (dflag == 1) { |
isnew = 1; |
ctime_r(&(cf->cf_mtime), date); |
l = snprintf(repo, sizeof(repo), "%s/%s/%s/%s%s", |
sz = strlen(date); |
current_cvsroot->cr_dir, cf->file_wd, CVS_PATH_ATTIC, |
if (sz > 0 && date[sz - 1] == '\n') |
cf->file_name, RCS_FILE_EXT); |
date[--sz] = '\0'; |
if (l == -1 || l >= (int)sizeof(repo)) |
cvs_sendreq(root, CVS_REQ_CHECKINTIME, date); |
fatal("import_new: overflow"); |
} |
|
|
|
cvs_sendreq(root, CVS_REQ_MODIFIED, cf->cf_name); |
if (cf->file_rcs != NULL || stat(repo, &st) != -1) |
cvs_sendfile(root, fpath); |
isnew = 0; |
|
|
return (0); |
if (isnew == 1) |
|
import_new(cf); |
|
else |
|
import_update(cf); |
} |
} |
|
|
static int |
static void |
cvs_import_local(CVSFILE *cf, void *arg) |
import_new(struct cvs_file *cf) |
{ |
{ |
time_t stamp; |
|
char *fcont; |
|
char fpath[MAXPATHLEN], rpath[MAXPATHLEN], repo[MAXPATHLEN]; |
|
const char *comment; |
|
struct stat fst; |
|
struct timeval ts[2]; |
|
struct cvsroot *root; |
|
struct rcs_delta *rdp; |
|
struct rcs_branch *brp; |
|
RCSFILE *rf; |
|
RCSNUM *rev, *brev; |
|
BUF *bp; |
BUF *bp; |
|
char *content; |
|
struct rcs_branch *brp; |
|
struct rcs_delta *rdp; |
|
RCSNUM *branch, *brev; |
|
|
root = CVS_DIR_ROOT(cf); |
cvs_log(LP_TRACE, "import_new(%s)", cf->file_name); |
|
|
if (cvs_path_cat(root->cr_dir, module, repo, sizeof(repo)) >= |
if ((branch = rcsnum_parse(import_branch)) == NULL) |
sizeof(repo)) |
fatal("import_new: failed to parse branch"); |
fatal("cvs_import_local: cvs_path_cat overflow"); |
|
|
|
cvs_file_getpath(cf, fpath, sizeof(fpath)); |
if ((bp = cvs_buf_load(cf->file_path, BUF_AUTOEXT)) == NULL) |
|
fatal("import_new: failed to load %s", cf->file_path); |
|
|
if (cf->cf_type == DT_DIR) { |
cvs_buf_putc(bp, '\0'); |
if (!strcmp(cf->cf_name, ".")) |
content = cvs_buf_release(bp); |
strlcpy(rpath, repo, sizeof(rpath)); |
|
else { |
|
if (cvs_path_cat(repo, fpath, rpath, |
|
sizeof(rpath)) >= sizeof(rpath)) |
|
fatal("cvs_import_local: cvs_path_cat overflow"); |
|
|
|
cvs_printf("Importing %s\n", rpath); |
if ((brev = rcsnum_brtorev(branch)) == NULL) |
if (mkdir(rpath, 0755) == -1) { |
fatal("import_new: failed to get first branch revision"); |
cvs_log(LP_ERRNO, "failed to create %s", |
|
rpath); |
|
} |
|
} |
|
|
|
return (0); |
cf->repo_fd = open(cf->file_rpath, O_CREAT|O_TRUNC|O_WRONLY); |
} |
if (cf->repo_fd < 0) |
|
fatal("import_new: %s: %s", cf->file_rpath, strerror(errno)); |
|
|
/* |
cf->file_rcs = rcs_open(cf->file_rpath, cf->repo_fd, RCS_CREATE, 0444); |
* If -d was given, use the file's last modification time as the |
if (cf->file_rcs == NULL) |
* timestamps for the initial revisions. |
fatal("import_new: failed to create RCS file for %s", |
*/ |
cf->file_path); |
if (dflag == 1) { |
|
if (stat(fpath, &fst) == -1) |
|
fatal("cvs_import_local: stat failed on `%s': %s", |
|
fpath, strerror(errno)); |
|
|
|
stamp = (time_t)fst.st_mtime; |
rcs_branch_set(cf->file_rcs, branch); |
|
|
ts[0].tv_sec = stamp; |
if (rcs_sym_add(cf->file_rcs, vendor_tag, branch) == -1) |
ts[0].tv_usec = 0; |
fatal("import_new: failed to add release tag"); |
ts[1].tv_sec = stamp; |
|
ts[1].tv_usec = 0; |
|
} else |
|
stamp = -1; |
|
|
|
if (strlcpy(rpath, repo, sizeof(rpath)) >= sizeof(rpath) || |
if (rcs_sym_add(cf->file_rcs, release_tag, branch) == -1) |
strlcat(rpath, "/", sizeof(rpath)) >= sizeof(rpath) || |
fatal("import_new: failed to add vendor tag"); |
strlcat(rpath, fpath, sizeof(rpath)) >= sizeof(rpath) || |
|
strlcat(rpath, RCS_FILE_EXT, sizeof(rpath)) >= sizeof(rpath)) |
|
fatal("cvs_import_local: path truncation"); |
|
|
|
cvs_printf("N %s\n", fpath); |
if (rcs_rev_add(cf->file_rcs, brev, logmsg, -1, NULL) == -1) |
|
fatal("import_new: failed to create first branch revision"); |
|
|
if ((rf = rcs_open(rpath, RCS_RDWR|RCS_CREATE, 0444)) == NULL) |
if (rcs_rev_add(cf->file_rcs, RCS_HEAD_REV, logmsg, -1, NULL) == -1) |
fatal("cvs_import_local: rcs_open: `%s': %s", rpath, |
fatal("import_new: failed to create first revision"); |
rcs_errstr(rcs_errno)); |
|
|
|
comment = rcs_comment_lookup(cf->cf_name); |
if ((rdp = rcs_findrev(cf->file_rcs, cf->file_rcs->rf_head)) == NULL) |
if (comment != NULL) |
fatal("import_new: cannot find newly added revision"); |
rcs_comment_set(rf, comment); |
|
|
|
brev = rcsnum_brtorev(imp_brnum); |
|
if (rcs_rev_add(rf, brev, cvs_msg, stamp, NULL) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_rev_add failed: %s", |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
if (rcs_sym_add(rf, release, brev) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_sym_add failed: %s", |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
rev = rcsnum_alloc(); |
|
rcsnum_cpy(imp_brnum, rev, 2); |
|
if (rcs_rev_add(rf, rev, cvs_msg, stamp, NULL) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_rev_add failed: %s", |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
if (rcs_head_set(rf, rev) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_head_set failed: %s", |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
if (rcs_branch_set(rf, imp_brnum) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_branch_set failed: %s", |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
if (rcs_sym_add(rf, vendor, imp_brnum) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_sym_add failed: %s", |
|
rcs_errstr(rcs_errno)); |
|
} |
|
|
|
/* |
|
* Put the branch revision on the branches list for the first revision. |
|
*/ |
|
rdp = rcs_findrev(rf, rev); |
|
brp = xmalloc(sizeof(*brp)); |
brp = xmalloc(sizeof(*brp)); |
brp->rb_num = rcsnum_alloc(); |
brp->rb_num = rcsnum_alloc(); |
rcsnum_cpy(brev, brp->rb_num, 0); |
rcsnum_cpy(brev, brp->rb_num, 0); |
TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list); |
TAILQ_INSERT_TAIL(&(rdp->rd_branches), brp, rb_list); |
|
|
if ((bp = cvs_buf_load(fpath, BUF_AUTOEXT)) == NULL) { |
if (rcs_deltatext_set(cf->file_rcs, |
(void)unlink(rpath); |
cf->file_rcs->rf_head, content) == -1) |
fatal("cvs_import_local: cvs_buf_load failed"); |
fatal("import_new: failed to set deltatext"); |
} |
|
|
|
cvs_buf_putc(bp, '\0'); |
rcs_write(cf->file_rcs); |
|
cvs_printf("N %s\n", cf->file_path); |
|
|
fcont = cvs_buf_release(bp); |
rcsnum_free(branch); |
|
rcsnum_free(brev); |
if (rcs_deltatext_set(rf, rev, fcont) < 0) { |
|
(void)unlink(rpath); |
|
fatal("cvs_import_local: rcs_deltatext_set failed"); |
|
} |
|
|
|
/* add the vendor tag and release tag as symbols */ |
|
rcs_close(rf); |
|
|
|
if (dflag ==1 && utimes(rpath, ts) == -1) |
|
cvs_log(LP_ERRNO, "failed to timestamp RCS file"); |
|
|
|
return (0); |
|
} |
} |
|
|
static int |
static void |
cvs_import_cleanup(void) |
import_update(struct cvs_file *cf) |
{ |
{ |
if (imp_brnum != NULL) |
cvs_log(LP_TRACE, "import_update(%s)", cf->file_path); |
rcsnum_free(imp_brnum); |
|
return (0); |
|
} |
} |