From: Jonathan Nieder <jrnieder@gmail.com>
To: Junio C Hamano <gitster@pobox.com>
Cc: David Barr <davidbarr@google.com>,
Git Mailing List <git@vger.kernel.org>,
Andrew Sayers <andrew-git@pileofstuff.org>,
Dmitry Ivankov <divanorama@gmail.com>,
Sverre Rabbelier <srabbelier@gmail.com>
Subject: [NON-PATCH] vcs-svn: avoid 'ls' and filedelete with empty path
Date: Sat, 10 Mar 2012 01:00:16 -0600 [thread overview]
Message-ID: <20120310070016.GC1992@burratino> (raw)
In-Reply-To: <20120310031228.GA3008@burratino>
Jonathan Nieder wrote:
> svn-fe should probably also be tweaked to handle this case without
> demanding support for the (nice) 'ls empty path' extension in
> fast-import backends, and this could even happen before 1.7.10.
> I can't promise to get to that quickly enough, though.
On second thought, svn-fe will need the 'ls empty path' extension
before it can handle this case again. :(
-- >8 --
There is a pathological Subversion operation that svn-fe handles
incorrectly due to an unexpected response from fast-import:
svn cp $SVN_ROOT $SVN_ROOT/subdirectory
svn-fe tries to handle this as a copy from "" to "subdirectory", in
two steps: first, "ls :1 " to retrieve a <dataref> for the root, and
then "M 040000 <dataref> subdirectory" to use it in the active commit.
In git 1.7.9.3 and earlier, the fast-import "ls" command does not
understand that by the empty path we mean the root of the tree. The
unrecognized path is reported as "missing", so svn-fe emits "D
subdirectory" and continues unaware of the miscommunication that has
taken place.
This is a regression introduced by commit 723b7a27 (vcs-svn: eliminate
repo_tree structure, 2010-12-10).
A patch in flight teaches fast-import to error out, which is a little
better, but still does not win us a successful and accurate import.
Because the meaning of empty paths was not specified in the
fast-import manual until recently, other backends are likely to handle
this construct inconsistently, too.
svn-fe never actually needs to pass "" as an argument to 'ls',
'C', 'R', or 'D'. (*) There is always another way to spell what it is
trying to do:
. Making a 'ls <foo> ""' request and waiting for a response is a
complicated way to spell the identity operation. When <foo> is
a commit, <foo> can be used directly to name the root of the
corresponding tree. (*)
. Emitting 'ls ""' to get a name for the root of the current tree
would be useful in general and there is no other command that
does that. Svn-fe never does that: translating non-copy nodes from
the Subversion dump format does not involve retrieving current
directory listings to apply a delta to them, and for copies, the
copyfrom information refers to a specific previous revision.
. svn-fe does not use the filerename (R) and filecopy (C) commands.
. The intent of the command 'D ""' is more clearly written as
'deleteall'.
Reported-by: Andrew Sayers <andrew-git@pileofstuff.org>
Explained-by: David Barr <davidbarr@google.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Toy patch, not intended for application.
(*) Lies.
---
t/t9010-svn-fe.sh | 69 +++++++++++++++++++++++++++++++++++++++++++++++++
vcs-svn/fast_export.c | 25 +++++++++++++++++-
vcs-svn/fast_export.h | 2 +-
vcs-svn/repo_tree.c | 6 +++--
vcs-svn/repo_tree.h | 2 +-
vcs-svn/svndump.c | 3 ++-
6 files changed, 101 insertions(+), 6 deletions(-)
diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
index b7eed248..45706bde 100755
--- a/t/t9010-svn-fe.sh
+++ b/t/t9010-svn-fe.sh
@@ -271,6 +271,75 @@ test_expect_success PIPE 'directory with files' '
test_cmp hi directory/file2
'
+test_expect_success PIPE 'copy from root to directory' '
+ reinit_git &&
+ echo hello >hello &&
+ hello_blob=$(git hash-object -w -t blob hello) &&
+ subtree=$(
+ echo "100644 blob $hello_blob README.txt" |
+ git mktree
+ ) &&
+ expect=$(
+ git mktree <<-EOF
+ 100644 blob $hello_blob README.txt
+ 040000 tree $subtree trunk
+ EOF
+ ) &&
+
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "2012-10-10T00:01:003.000000Z" \
+ svn:log "created README.txt" &&
+ echo PROPS-END
+ } >r1.props &&
+ {
+ properties \
+ svn:author author@example.com \
+ svn:date "2012-10-10T00:02:005.000000Z" \
+ svn:log "created trunk" &&
+ echo PROPS-END
+ } >r2.props &&
+ {
+ cat <<-EOF &&
+ SVN-fs-dump-format-version: 3
+
+ Revision-number: 1
+ EOF
+ echo Prop-content-length: $(wc -c <r1.props) &&
+ echo Content-length: $(wc -c <r1.props) &&
+ echo &&
+ cat r1.props &&
+ cat <<-\EOF &&
+
+ Node-path: README.txt
+ Node-kind: file
+ Node-action: add
+ EOF
+ text_no_props hello &&
+ echo Revision-number: 2
+ echo Prop-content-length: $(wc -c <r2.props) &&
+ echo Content-length: $(wc -c <r2.props) &&
+ echo &&
+ cat r2.props &&
+ sed -e "s/X\$//" <<-\EOF
+
+ Node-path: trunk
+ Node-kind: dir
+ Node-action: add
+ Node-copyfrom-rev: 1
+ Node-copyfrom-path: X
+ Prop-content-length: 10
+ Content-length: 10
+
+ PROPS-END
+ EOF
+ } >copy-root.dump &&
+ try_dump copy-root.dump &&
+
+ git diff-tree --exit-code $expect HEAD
+'
+
test_expect_success PIPE 'branch name with backslash' '
reinit_git &&
sort <<-\EOF >expect.branch-files &&
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 19d7c34c..24232618 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -49,6 +49,12 @@ void fast_export_reset(void)
void fast_export_delete(const char *path)
{
+ /* delete("") means to return to a clean slate. */
+ if (!*path) {
+ printf("deleteall\n");
+ return;
+ }
+
putchar('D');
putchar(' ');
quote_c_style(path, NULL, stdout, 0);
@@ -113,6 +119,8 @@ void fast_export_end_commit(uint32_t revision)
static void ls_from_rev(uint32_t rev, const char *path)
{
+ assert(*path);
+
/* ls :5 path/to/old/file */
printf("ls :%"PRIu32" ", rev);
quote_c_style(path, NULL, stdout, 0);
@@ -122,6 +130,8 @@ static void ls_from_rev(uint32_t rev, const char *path)
static void ls_from_active_commit(const char *path)
{
+ assert(*path);
+
/* ls "path/to/file" */
printf("ls \"");
quote_c_style(path, NULL, stdout, 1);
@@ -285,12 +295,25 @@ static int parse_ls_response(const char *response, uint32_t *mode,
int fast_export_ls_rev(uint32_t rev, const char *path,
uint32_t *mode, struct strbuf *dataref)
{
+ if (!*path) {
+ /*
+ * The easy case: when path is "", the caller can use
+ * :<rev> directly to refer to the root of the tree. (*)
+ */
+ strbuf_addf(dataref, ":%"PRIu32, rev);
+ *mode = REPO_MODE_DIR;
+ return 0;
+ }
+
ls_from_rev(rev, path);
return parse_ls_response(get_response_line(), mode, dataref);
}
-int fast_export_ls(const char *path, uint32_t *mode, struct strbuf *dataref)
+int fast_export_ls_nonroot(const char *path, uint32_t *mode,
+ struct strbuf *dataref)
{
+ assert(*path);
+
ls_from_active_commit(path);
return parse_ls_response(get_response_line(), mode, dataref);
}
diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 43d05b65..53e208e2 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -22,7 +22,7 @@ void fast_export_blob_delta(uint32_t mode,
/* If there is no such file at that rev, returns -1, errno == ENOENT. */
int fast_export_ls_rev(uint32_t rev, const char *path,
uint32_t *mode_out, struct strbuf *dataref_out);
-int fast_export_ls(const char *path,
+int fast_export_ls_nonroot(const char *path,
uint32_t *mode_out, struct strbuf *dataref_out);
#endif
diff --git a/vcs-svn/repo_tree.c b/vcs-svn/repo_tree.c
index 67d27f0b..1547b8ce 100644
--- a/vcs-svn/repo_tree.c
+++ b/vcs-svn/repo_tree.c
@@ -8,13 +8,15 @@
#include "repo_tree.h"
#include "fast_export.h"
-const char *repo_read_path(const char *path, uint32_t *mode_out)
+const char *repo_read_nonroot_path(const char *path, uint32_t *mode_out)
{
int err;
static struct strbuf buf = STRBUF_INIT;
+ assert(*path);
+
strbuf_reset(&buf);
- err = fast_export_ls(path, mode_out, &buf);
+ err = fast_export_ls_nonroot(path, mode_out, &buf);
if (err) {
if (errno != ENOENT)
die_errno("BUG: unexpected fast_export_ls error");
diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h
index 889c6a3c..466d5a63 100644
--- a/vcs-svn/repo_tree.h
+++ b/vcs-svn/repo_tree.h
@@ -11,7 +11,7 @@ struct strbuf;
uint32_t next_blob_mark(void);
void repo_copy(uint32_t revision, const char *src, const char *dst);
void repo_add(const char *path, uint32_t mode, uint32_t blob_mark);
-const char *repo_read_path(const char *path, uint32_t *mode_out);
+const char *repo_read_nonroot_path(const char *path, uint32_t *mode_out);
void repo_delete(const char *path);
void repo_commit(uint32_t revision, const char *author,
const struct strbuf *log, const char *uuid, const char *url,
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index ca63760f..d610184d 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -248,7 +248,8 @@ static void handle_node(void)
old_data = NULL;
} else if (node_ctx.action == NODEACT_CHANGE) {
uint32_t mode;
- old_data = repo_read_path(node_ctx.dst.buf, &mode);
+ assert(*node_ctx.dst.buf);
+ old_data = repo_read_nonroot_path(node_ctx.dst.buf, &mode);
if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
die("invalid dump: cannot modify a directory into a file");
if (mode != REPO_MODE_DIR && type == REPO_MODE_DIR)
--
1.7.9.2
next prev parent reply other threads:[~2012-03-10 7:00 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-03-08 3:13 [BUG] fast-import: ls command on commit root returns missing (was: Bug in svn-fe: copying the root directory acts as if it's an empty directory) David Barr
2012-03-08 5:30 ` [PATCH] fast-import: fix ls command with empty path David Barr
2012-03-08 7:09 ` Jonathan Nieder
2012-03-08 15:29 ` Sverre Rabbelier
2012-03-08 16:39 ` Junio C Hamano
2012-03-08 17:33 ` Dmitry Ivankov
2012-03-08 19:32 ` Jonathan Nieder
2012-03-10 9:48 ` Jonathan Nieder
2012-03-08 18:15 ` Jonathan Nieder
2012-03-10 3:12 ` Jonathan Nieder
2012-03-10 3:20 ` [PATCH maint-1.7.6] fast-import: leakfix for 'ls' of dirty trees Jonathan Nieder
2012-03-10 4:00 ` [PATCH maint-1.7.6] fast-import: don't allow 'ls' of path with empty components Jonathan Nieder
2012-03-10 4:30 ` [PULL maint] two fast-import "ls" fixes Jonathan Nieder
2012-03-10 7:00 ` Jonathan Nieder [this message]
2013-06-21 16:33 ` [PATCH] fast-import: fix ls command with empty path Dave Abrahams
2012-03-08 20:27 ` [PATCH v2 0/2] " Jonathan Nieder
2012-03-08 20:31 ` [PATCH 1/2] fast-import: plug leak of dirty trees in 'ls' command Jonathan Nieder
2012-03-08 20:33 ` [PATCH 2/2] fast-import: teach ls command to accept empty path Jonathan Nieder
2012-03-09 4:28 ` David Barr
2012-03-09 9:29 ` Jonathan Nieder
2012-03-10 8:53 ` [PATCH v3] fast-import: allow 'ls' and filecopy to read the root Jonathan Nieder
2012-03-10 9:01 ` Jonathan Nieder
2012-03-10 9:18 ` [PATCH 2/1] fixup! " Jonathan Nieder
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=20120310070016.GC1992@burratino \
--to=jrnieder@gmail.com \
--cc=andrew-git@pileofstuff.org \
--cc=davidbarr@google.com \
--cc=divanorama@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=srabbelier@gmail.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).