From: Ramkumar Ramachandra <artagnon@gmail.com>
To: Jonathan Nieder <jrnieder@gmail.com>, Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, David Barr <david.barr@cordelta.com>,
Sverre Rabbelier <srabbelier@gmail.com>,
Tomas Carnecky <tom@dbservice.com>
Subject: Re: Plans for the vcs-svn-pu branch
Date: Fri, 11 Feb 2011 21:19:15 +0530 [thread overview]
Message-ID: <20110211154910.GB7335@kytes> (raw)
In-Reply-To: <20110211090931.GA27410@elie>
Hi,
Jonathan Nieder writes:
> Jonathan Nieder wrote:
>
> > Here are the topics that are cooking in vcs-svn-pu.
Thanks for the elaborate email. Some updates from my side:
- I've rewritten most of the svnload parser to resemble fast-import,
and I'd like some preliminary feedback on the design.
- Although most of the dependent infrastructure is in place now, the
remote-helper branch is still lagging. I'll shortly look into this.
Signed-off-by: Ramkumar Ramachandra <artagnon@gmail.com>
--8<--
/*
* Produce a dumpfile v3 from a fast-import stream.
* Load the dump into the SVN repository with:
* svnrdump load <URL> <dumpfile
*
* Licensed under a two-clause BSD-style license.
* See LICENSE for details.
*/
#include "cache.h"
#include "quote.h"
#include "git-compat-util.h"
#include "dump_export.h"
#include "dir_cache.h"
#define SVN_DATE_FORMAT "%Y-%m-%dT%H:%M:%S.000000Z"
#define SVN_DATE_LEN 27
struct ident
{
struct strbuf name, email;
char date[SVN_DATE_LEN + 1];
};
static FILE *infile;
static struct strbuf command_buf = STRBUF_INIT;
static struct strbuf log_buf = STRBUF_INIT;
static struct strbuf path_s = STRBUF_INIT;
static struct strbuf path_d = STRBUF_INIT;
static struct strbuf svn_author = STRBUF_INIT;
static struct ident author = {STRBUF_INIT, STRBUF_INIT, ""};
static struct ident committer = {STRBUF_INIT, STRBUF_INIT, ""};
static int read_next_command(void)
{
return strbuf_getline(&command_buf, infile, '\n');
}
static void populate_revprops(struct strbuf *props, size_t author_len,
const char *author, size_t log_len, const char *log,
size_t date_len, const char *date)
{
strbuf_reset(props);
strbuf_addf(props, "K 10\nsvn:author\nV %lu\n%s\n", author_len, author);
strbuf_addf(props, "K 7\nsvn:log\nV %lu\n%s\n", log_len, log);
if (date_len)
/* SVN doesn't like an empty svn:date value */
strbuf_addf(props, "K 8\nsvn:date\nV %lu\n%s\n", date_len, date);
strbuf_add(props, "PROPS-END\n", 10);
}
static void parse_ident(const char *buf, struct ident *identp)
{
char *t, *tz_off;
int tz_off_buf;
const struct tm *tm_time;
/* John Doe <johndoe@email.com> 1170199019 +0530 */
strbuf_reset(&(identp->name));
strbuf_reset(&(identp->email));
if (!buf)
goto error;
if (!(tz_off = strrchr(buf, ' ')))
goto error;
*tz_off++ = '\0';
if (!(t = strrchr(buf, ' ')))
goto error;
*(t - 1) = '\0'; /* Ignore '>' from email */
t++;
tz_off_buf = atoi(tz_off);
if (tz_off_buf > 1200 || tz_off_buf < -1200)
goto error;
tm_time = time_to_tm(strtoul(t, NULL, 10), tz_off_buf);
strftime(identp->date, SVN_DATE_LEN + 1, SVN_DATE_FORMAT, tm_time);
if (!(t = strchr(buf, '<')))
goto error;
*(t - 1) = '\0'; /* Ignore ' <' from email */
t++;
strbuf_add(&(identp->email), t, strlen(t));
strbuf_add(&(identp->name), buf, strlen(buf));
return;
error:
die("Malformed ident line: %s", buf);
}
static void skip_optional_lf(void)
{
int term_char = fgetc(stdin);
if (term_char != '\n' && term_char != EOF)
ungetc(term_char, stdin);
}
static void parse_data(struct strbuf *dst)
{
if (prefixcmp(command_buf.buf, "data "))
die("Expected 'data n' command, found: %s", command_buf.buf);
if (!prefixcmp(command_buf.buf + 5, "<<")) {
char *term = xstrdup(command_buf.buf + 5 + 2);
size_t term_len = command_buf.len - 5 - 2;
strbuf_reset(&command_buf);
for (;;) {
if (read_next_command() == EOF)
die("EOF in data (terminator '%s' not found)", term);
if (term_len == command_buf.len
&& !memcmp(term, command_buf.buf, term_len))
break;
if (dst) {
strbuf_addbuf(dst, &command_buf);
strbuf_addch(dst, '\n');
} else
printf("%s\n", command_buf.buf);
}
free(term);
} else {
uintmax_t length;
length = strtoumax(command_buf.buf + 5, NULL, 10);
if ((size_t)length < length)
die("Data is too large to use in this context");
if (!dst) {
strbuf_reset(&command_buf);
/* buffer_copy_bytes(&command_buf, (size_t)length); */
} else
strbuf_fread(dst, (size_t)length, stdin);
}
skip_optional_lf();
}
static const char *get_mode(const char *str, uint16_t *modep)
{
unsigned char c;
uint16_t mode = 0;
while ((c = *str++) != ' ') {
if (c < '0' || c > '7')
return NULL;
mode = (mode << 3) + (c - '0');
}
*modep = mode;
return str;
}
static void file_change_m(void)
{
const char *p;
const char *endp;
uint16_t mode;
enum node_kind kind;
p = get_mode(command_buf.buf + 2, &mode);
if (!p)
die("Corrupt mode: %s", command_buf.buf);
switch (mode) {
case 0644:
case 0755:
mode |= S_IFREG;
case S_IFREG | 0644:
kind = NODE_KIND_NORMAL;
break;
case S_IFREG | 0755:
kind = NODE_KIND_EXECUTABLE;
break;
case S_IFLNK:
kind = NODE_KIND_SYMLINK;
break;
case S_IFGITLINK:
die("Gitlinks unsupported"); /* TODO */
case S_IFDIR:
die("Subdirectories unsupported"); /* TODO */
default:
die("Corrupt mode: %s", command_buf.buf);
}
if (!prefixcmp(p, "inline"))
p += 6;
else
die ("Non-inlined data unsupported");
if (*p++ != ' ')
die("Missing space after dataref: %s", command_buf.buf);
/* parse out path into path_d */
strbuf_reset(&path_d);
if (!unquote_c_style(&path_d, p, &endp)) {
if (*endp)
die("Garbage after path in: %s", command_buf.buf);
} else
strbuf_addstr(&path_d, p);
dump_export_m(path_d.buf, kind);
read_next_command();
parse_data(NULL); /* parse data and write it to stdout */
}
static void file_change_d(void)
{
const char *p;
const char *endp;
p = command_buf.buf + 2;
/* parse out path into path_d */
strbuf_reset(&path_d);
if (!unquote_c_style(&path_d, p, &endp)) {
if (*endp)
die("Garbage after path in: %s", command_buf.buf);
} else
strbuf_addstr(&path_d, p);
dump_export_d(path_d.buf);
}
static void file_change_cr(int rename)
{
const char *p;
const char *endp;
p = command_buf.buf + 2;
strbuf_reset(&path_s);
if (!unquote_c_style(&path_s, p, &endp)) {
if (*endp != ' ')
die("Missing space after source: %s", command_buf.buf);
} else {
endp = strchr(p, ' ');
if (!endp)
die("Missing space after source: %s", command_buf.buf);
strbuf_add(&path_s, p, endp - p);
}
endp++;
if (!*endp)
die("Missing destination: %s", command_buf.buf);
p = endp;
strbuf_reset(&path_d);
if (!unquote_c_style(&path_d, p, &endp)) {
if (*endp)
die("Garbage after destination in: %s", command_buf.buf);
} else
strbuf_addstr(&path_d, p);
/* TODO: Check C "path/to/subdir" "" */
if (rename)
dump_export_d(path_s.buf);
dump_export_c(path_d.buf, path_s.buf, 0);
}
static void parse_new_commit()
{
char *branch;
/* parse and ignore branch name */
branch = strchr(command_buf.buf, ' ') + 1;
read_next_command();
if (!prefixcmp(command_buf.buf, "mark :"))
/* parse and ignore mark line */
read_next_command();
if (!prefixcmp(command_buf.buf, "author ")) {
parse_ident(command_buf.buf + 7, &author);
read_next_command();
}
if (!prefixcmp(command_buf.buf, "committer ")) {
parse_ident(command_buf.buf + 10, &committer);
read_next_command();
}
if (!committer.name.len)
die("Missing committer line in stream");
parse_data(&log_buf);
read_next_command();
if (!prefixcmp(command_buf.buf, "from "))
/* TODO: Support copyfrom */
read_next_command();
while (!prefixcmp(command_buf.buf, "merge "))
/* TODO: Support merges */
read_next_command();
/* file_change_* */
while (command_buf.len > 0) {
if (!prefixcmp(command_buf.buf, "M "))
file_change_m();
else if (!prefixcmp(command_buf.buf, "D "))
file_change_d();
else if (!prefixcmp(command_buf.buf, "R "))
file_change_cr(1);
else if (!prefixcmp(command_buf.buf, "C "))
file_change_cr(0);
else if (!prefixcmp(command_buf.buf, "N "))
; /* ignored */
else if (!prefixcmp(command_buf.buf, "ls "))
goto error; /* TODO */
else if (!strcmp("deleteall", command_buf.buf))
goto error; /* TODO */
else
break;
if (read_next_command() == EOF)
break;
}
return;
error:
die("Unsupported command: %s", command_buf.buf);
}
void parse_new_tag()
{
/* TODO: Support tags */
return;
}
void parse_reset_branch()
{
/* TODO */
return;
}
void build_svn_author(struct ident *author, struct ident *committer)
{
char *t, *email;
strbuf_reset(&svn_author);
email = author->email.len ? author->email.buf : committer->email.buf;
if ((t = strchr(email, '@')))
strbuf_add(&svn_author, email, t - email);
else
strbuf_addstr(&svn_author, t);
}
void svnload_read(void)
{
char *val;
while (read_next_command() != EOF) {
if ((val = strchr(command_buf.buf, ' ')))
*val++ = '\0';
if (!strcmp("blob", command_buf.buf))
die("Non-inlined blobs unsupported");
else if (!prefixcmp(command_buf.buf, "ls "))
goto error; /* TODO */
else if (!prefixcmp(command_buf.buf, "cat-blob "))
goto error; /* TODO */
else if (!prefixcmp(command_buf.buf, "commit "))
parse_new_commit(val);
else if (!prefixcmp(command_buf.buf, "tag "))
parse_new_tag(val);
else if (!prefixcmp(command_buf.buf, "reset "))
parse_reset_branch(val);
else if (!strcmp(command_buf.buf, "checkpoint")
|| !prefixcmp(command_buf.buf, "progress ")
|| !prefixcmp(command_buf.buf, "feature ")
|| !prefixcmp(command_buf.buf, "option "))
; /* ignored */
else
goto error;
}
error:
die("Unsupported command: %s", command_buf.buf);
}
int svnload_init(const char *filename)
{
if (!(infile = filename ? fopen(filename, "r") : stdin))
die("Cannot open %s: %s", filename, strerror(errno));
dump_export_init();
return 0;
}
prev parent reply other threads:[~2011-02-11 15:48 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-11-07 11:21 Status of the svn remote helper project (Nov, 2010) Jonathan Nieder
2010-11-07 12:06 ` David Michael Barr
2010-11-08 3:56 ` David Barr
2010-11-08 6:11 ` Jonathan Nieder
2010-11-08 6:20 ` David Barr
2010-11-07 12:50 ` Ramkumar Ramachandra
2010-11-07 17:42 ` Jonathan Nieder
2010-11-21 6:31 ` Status of the svn remote helper project (Nov 2010, #2) Jonathan Nieder
2010-11-21 9:38 ` David Michael Barr
2010-11-21 23:06 ` Jonathan Nieder
2010-11-22 2:06 ` David Barr
2010-12-05 11:37 ` Status of the svn remote helper project (Dec 2010, #1) Jonathan Nieder
2010-12-08 18:26 ` Tomas Carnecky
2010-12-12 6:14 ` fast-import tweaks for remote helpers (Re: Status of the svn remote helper project (Dec 2010, #1)) Jonathan Nieder
2010-12-12 9:53 ` Sam Vilain
2010-12-12 17:16 ` fast-import tweaks for remote helpers Jonathan Nieder
2011-01-05 21:20 ` fast-import --report-fd (Re: fast-import tweaks for remote helpers) Jonathan Nieder
2011-01-05 23:39 ` Status of the svn remote helper project (Jan 2011, #1) Jonathan Nieder
2011-01-07 14:00 ` David Michael Barr
2011-02-11 9:09 ` Plans for the vcs-svn-pu branch Jonathan Nieder
2011-02-11 10:36 ` [PATCH] svn-fe: warn about experimental status Jonathan Nieder
2011-02-11 15:49 ` Ramkumar Ramachandra [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20110211154910.GB7335@kytes \
--to=artagnon@gmail.com \
--cc=david.barr@cordelta.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=jrnieder@gmail.com \
--cc=srabbelier@gmail.com \
--cc=tom@dbservice.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).