[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: svn update select(2)

From: Larry McVoy <lm_at_bitmover.com>
Date: Sun, 21 Nov 2010 17:17:27 -0800

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

This is an archived mail posted to the Subversion Dev mailing list.