Hey Greg,
Thanks a lot for the reply, very cool of you.
On the long time no talk, I crawled under a rock after getting beat bloody
by the open source guys, something about helping people and getting
shit on for it wasn't working for me :) Slowly crawling back out.
Thanks for the variable, and the name rocks. BitKeeper has one like
that too, can't remember, but it is something like
I_KNOW_THIS_CORRUPTS_MY_TREE
We are trying to avoid parsing the dump format unless we have to. Just
want to keep it simple.
BTW, our importer is written in L which is a scripting language we did.
Open source though we haven't released it officially (if you want it
ask, we'll give you the source). It's sort of C + perl. Here's the
code for the svn2bk stuff. Feedback welcome.
Thanks again for the info - that helps.
--lm
/*
* This is a little SVN to BK importer written in L.
*
* It does not attempt to handle
* renames (other than copy/delete pretty much like SVN)
* multiple branches
*
* Usage:
* # Initial import:
* svn2bk [-hHOST] [-r<start>[..<stop]] <svn_url> <dir>
* # Incremental import in the top dir of the repo:
* svn2bk -i [-hHOST] [-r..<stop>]
*
* -hHOST set the hostname used for checkins
* -i incremental, import whatever has been added
* -rstart start at this commit in the svn repo
* -rstop stop at this one (default HEAD)
*/
typedef struct {
string user; // username who did the check in
string date; // 2007-05-13 03:21:54 -0700
string cmts[]; // array of comments for the commit
} delta;
delta log{int}; // cache of the entire log
int revs[]; // ordered list of revs for this branch
string q = "q"; // -v turns this off and makes bk noisy
void
main(int ac, string av[])
{
string c, host, url, dir;
int start, stop; // if set, do this range.
int i, incremental;
if (0) ac = 0; // lint
while (defined(c = getopt(av, "h:ir:v", undef))) {
switch (c) {
case "h": host = optarg; break;
case "i": incremental = 1; break;
case "r":
if (optarg =~ /(.+)\.\.(.+)/) {
start = (int)$1;
stop = (int)$2;
} else if (optarg =~ /^\.\.(.+)/) {
stop = (int)$1;
} else {
start = (int)optarg;
}
break;
case "v": q = ""; break;
default: usage(-1);
}
}
url = av[optind++];
dir = av[optind];
ifndef (start) start = 1;
ifdef (host) setenv("BK_HOST", host);
setenv("CLOCK_DRIFT", "1");
unless (defined(getenv("BK_HOST"))) usage(0);
unless ((defined(url) && defined(dir)) || defined(incremental)) {
usage(1);
}
ifdef (incremental) {
unless (isdir(".bk") && isdir(".svn")) {
fprintf(stderr, "Not at a BK/SVN root\n");
exit(1);
}
} else unless (defined(setup(start, url, dir))) {
usage(2);
}
ifndef (getlog(incremental, ++start, stop)) usage(3);
for (i = 0; defined(revs[i]); i++) {
assert(defined(cset(revs[i])));
}
}
/*
* Create an empty bk repo and the intial svn repo
* We want to end up with .bk next to .svn
*/
int
setup(int start, string url, string dir)
{
string bk = "${dir}/bk";
FILE f;
ifndef (system("svn co -q -r${start} ${url} ${dir}")) return (undef);
/*
* Set up a repo inside the svn repo
*/
f = fopen("${dir}/.bk_config", "w");
fprintf(f, "checkout:edit\n");
fprintf(f, "clockskew:on\n");
fprintf(f, "partial_check:on\n");
fclose(f);
ifndef (system("bk setup -f -c${dir}/.bk_config ${bk}")) return (undef);
system("tar -C${bk} -cf- . | tar -C${dir} -xf-");
unlink("${dir}/.bk_config");
system("rm -rf ${bk}");
if (isdir(bk)) die("rm failed\n");
chdir(dir);
if (isdir("bk")) die("rm failed2\n");
setenv("BK_CONFIG", "clockskew=1!;compression:off!");
mkdir("BitKeeper/tmp/dotbk");
setenv("BK_DOTBK", "BitKeeper/tmp/dotbk");
// Prune the top level one, we'll grep out the others
system("bk ignore '.svn -prune'");
system("bk -cxU | grep -v '/\.svn/ | bk ci -a${q}ly'SVN ${start}' -");
system("bk _eula -a");
system("bk commit -${q}y'SVN ${start}'");
return (0);
}
/*
* Import a SVN commit.
* We get the updates, then
* - for each file that is not checked out, svn deleted it so we delete it
* - for each modified/extra we check those in with the comment/user/date
* from the log message.
*/
int
cset(int rev)
{
FILE f;
string buf, tmp;
fprintf(stderr, "=== SVN ${rev} ===\n");
ifndef (system("svn update -q -r${rev}")) return (undef);
tmp = "BitKeeper/tmp/comments";
f = fopen(tmp, "w");
foreach (buf in log{rev}.cmts) {
fprintf(f, "%s\n", buf);
}
fclose(f);
setenv("BK_USER", log{rev}.user);
setenv("BK_DATE_TIME_ZONE", log{rev}.date);
system("bk -U^G rm -f");
system("bk -xcU | grep -v '/\.svn/' | bk ci -a${q}lY${tmp} -");
f = fopen(tmp, "a");
fprintf(f, "SVN: %d\n", rev);
fclose(f);
system("bk commit -${q}Y${tmp}");
return (0);
}
/*
* Load up the log, we'll use it for our commits.
* ------------------------------------------------------------------------
* r59 | mcccol | 2007-04-17 18:23:39 -0700 (Tue, 17 Apr 2007) | 4 lines
*
* removed logging, started using Debug.error
*
* ------------------------------------------------------------------------
* r60 | mcccol | 2007-04-17 18:25:08 -0700 (Tue, 17 Apr 2007) | 4 lines
*
* * Added fixbad to utf8 to repair damaged utf8
* * made regexps variables to preserver their regexp intrep
*
* etc.
*/
int
getlog(int incremental, int start, int stop)
{
FILE f;
int i, rev;
string cmts[];
string buf;
ifdef (incremental) {
start = (int)`svn info | grep Revision: | awk '{print $NF}'`;
start++;
}
ifdef (stop) {
if (stop <= start) {
fprintf(stderr, "Already up to or past %d\n", stop);
exit(1);
}
f = popen("svn log -r${start}:${stop} 2>@stderr", "r");
} else {
f = popen("svn log -r${start}:HEAD 2>@stderr", "r");
}
unless (defined(buf = <f>) && (buf =~ /^[-]+$/)) {
done: fprintf(stderr, "Seems like you are up to date.\n");
return (0);
}
while (!eof(f)) {
unless (defined(buf = <f>)) {
assert(eof(f));
break;
}
unless (buf =~ /^r(\d+) \| ([^|]+) \| ([^(]+)/) {
die("expected rev/date: ${buf}\n");
}
rev = (int)$1;
push(&revs, rev);
log{rev}.user = (string)$2;
log{rev}.date = (string)$3;
buf = <f>; // toss the blank line
undef(cmts); // toss previous comments
while (defined(buf = <f>)) {
if ((length(buf) == 72) && (buf =~ /^[-]+$/)) break;
push(&cmts, buf);
}
/*
* Lose trailing blank lines, they serve no purpose.
*/
for (i = length(cmts)-1; i >= 0; i--) {
unless (cmts[i] =~ /^\s*$/) break;
cmts[i] = undef;
}
log{rev}.cmts = cmts;
}
pclose(f);
pop(&revs); // we did this one in setup
unless (length(revs)) goto done;
return (0);
}
void
usage(int which)
{
fprintf(stderr, "Barfed on %d.\n", which);
exit(1);
}
Received on 2010-11-22 02:18:11 CET