diff --git a/cache.h b/cache.h
index 33decd9..33e69eb 100644
--- a/cache.h
+++ b/cache.h
@@ -678,6 +678,8 @@ static inline void hashclr(unsigned char *hash)
#define EMPTY_TREE_SHA1_BIN \
"\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
"\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
+#define EMPTY_BLOB_SHA1_HEX \
+ "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
int git_mkstemp(char *path, size_t n, const char *template);
diff --git a/fast-import.c b/fast-import.c
index 670f4f5..e62f34d 100644
--- a/fast-import.c
+++ b/fast-import.c
@@ -2862,12 +2862,20 @@ static struct object_entry *parse_treeish_dataref(const char **r)
static void print_ls(int mode, unsigned char *sha1, char *path)
{
- enum object_type type;
struct strbuf line = STRBUF_INIT;
- type = sha1_object_info(sha1, NULL);
+ const char *type;
+
+ /* See show_tree(). */
+ if (S_ISGITLINK(mode))
+ type = commit_type;
+ else if (S_ISDIR(mode))
+ type = tree_type;
+ else
+ type = blob_type;
+
/* mode SP type SP object_name TAB path LF */
- strbuf_addf(&line, "%o %s %s\t%s\n",
- mode, typename(type), sha1_to_hex(sha1), path);
+ strbuf_addf(&line, "%06o %s %s\t%s\n",
+ mode, type, sha1_to_hex(sha1), path);
cat_blob_write(line.buf, line.len);
strbuf_release(&line);
}@@ -2898,17 +2906,25 @@ static void parse_ls(struct branch *b)
if (*p)
die("Garbage after path: %s", command_buf.buf);
tree_content_get(root, uq.buf, &leaf);
- if (!leaf.versions[1].mode)
- die("Path %s not in branch", uq.buf);
+ if (!leaf.versions[1].mode) {
+ /*
+ * NEEDSWORK. Missing path? Must be an empty directory!
+ *
+ * Should find a nicer way to report this --- e.g.
+ * die("Path %s not in branch", uq.buf);
+ */
+ print_ls(S_IFDIR, (unsigned char *) EMPTY_TREE_SHA1_BIN, uq.buf);
+ } else {
+ /*
+ * A directory in preparation would have a sha1 of zero
+ * until it is saved. Save, for simplicity.
+ */
+ if (S_ISDIR(leaf.versions[1].mode))
+ store_tree(&leaf);
- /*
- * A directory in preparation would have a sha1 of zero
- * until it is saved. Save, for simplicity.
- */
- if (S_ISDIR(leaf.versions[1].mode))
- store_tree(&leaf);
+ print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, uq.buf);
+ }
- print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, uq.buf);
strbuf_release(&uq);
if (!b || root != &b->branch_tree)
release_tree_entry(root);diff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh
index 022e3e3..34bb9f6 100755
--- a/t/t9010-svn-fe.sh
+++ b/t/t9010-svn-fe.sh
@@ -53,8 +53,7 @@ test_expect_success 'empty dump' '
test_expect_success 'v4 dumps not supported' '
reinit_git &&
echo "SVN-fs-dump-format-version: 4" >v4.dump &&
- test_must_fail test-svn-fe v4.dump >stream &&
- test_cmp empty stream
+ test_must_fail test-svn-fe v4.dump
'
test_expect_failure 'empty revision' '
@@ -301,8 +300,9 @@ test_expect_success 'action: add node without text' '
test_must_fail test-svn-fe textless.dump
'
-test_expect_failure 'change file mode but keep old content' '
+test_expect_failure PIPE 'change file mode but keep old content' '
reinit_git &&
+ rm -f backflow &&
cat >expect <<-\EOF &&
OBJID
:120000 100644 OBJID OBJID T greeting
@@ -364,8 +364,9 @@ test_expect_failure 'change file mode but keep old content' '
PROPS-END
EOF
- test-svn-fe filemode.dump >stream &&
- git fast-import <stream &&
+ mkfifo backflow &&
+ test-svn-fe filemode.dump 3<backflow |
+ git fast-import --cat-blob-fd=3 3>backflow &&
{
git rev-list HEAD |
git diff-tree --root --stdin |@@ -378,8 +379,9 @@ test_expect_failure 'change file mode but keep old content' '
test_cmp hello actual.target
'
-test_expect_success 'change file mode and reiterate content' '
+test_expect_success PIPE 'change file mode and reiterate content' '
reinit_git &&
+ rm -f backflow &&
cat >expect <<-\EOF &&
OBJID
:120000 100644 OBJID OBJID T greeting
@@ -390,7 +392,7 @@ test_expect_success 'change file mode and reiterate content' '
EOF
echo "link hello" >expect.blob &&
echo hello >hello &&
- cat >filemode.dump <<-\EOF &&
+ cat >filemode2.dump <<-\EOF &&
SVN-fs-dump-format-version: 3
Revision-number: 1
@@ -445,8 +447,9 @@ test_expect_success 'change file mode and reiterate content' '
PROPS-END
link hello
EOF
- test-svn-fe filemode.dump >stream &&
- git fast-import <stream &&
+ mkfifo backflow &&
+ test-svn-fe filemode2.dump 3<backflow |
+ git fast-import --cat-blob-fd=3 3>backflow &&
{
git rev-list HEAD |
git diff-tree --root --stdin |@@ -522,12 +525,13 @@ test_expect_success PIPE 'deltas supported' '
cat delta
} >delta.dump &&
mkfifo backflow &&
- test_must_fail test-svn-fe delta.dump 3<backflow |
+ test-svn-fe delta.dump 3<backflow |
git fast-import --cat-blob-fd=3 3>backflow
'
-test_expect_success 'property deltas supported' '
+test_expect_success PIPE 'property deltas supported' '
reinit_git &&
+ rm -f backflow &&
cat >expect <<-\EOF &&
OBJID
:100755 100644 OBJID OBJID M script.sh
@@ -582,8 +586,9 @@ test_expect_success 'property deltas supported' '
PROPS-END
EOF
} >propdelta.dump &&
- test-svn-fe propdelta.dump >stream &&
- git fast-import <stream &&
+ mkfifo backflow &&
+ test-svn-fe propdelta.dump 3<backflow |
+ git fast-import --cat-blob-fd=3 3>backflow &&
{
git rev-list HEAD |
git diff-tree --stdin |@@ -592,8 +597,9 @@ test_expect_success 'property deltas supported' '
test_cmp expect actual
'
-test_expect_success 'properties on /' '
+test_expect_success PIPE 'properties on /' '
reinit_git &&
+ rm -f backflow &&
cat <<-\EOF >expect &&
OBJID
OBJID
@@ -637,8 +643,9 @@ test_expect_success 'properties on /' '
PROPS-END
EOF
- test-svn-fe changeroot.dump >stream &&
- git fast-import <stream &&
+ mkfifo backflow &&
+ test-svn-fe changeroot.dump 3<backflow |
+ git fast-import --cat-blob-fd=3 3>backflow &&
{
git rev-list HEAD |
git diff-tree --root --always --stdin |@@ -647,8 +654,9 @@ test_expect_success 'properties on /' '
test_cmp expect actual
'
-test_expect_success 'deltas for typechange' '
+test_expect_success PIPE 'deltas for typechange' '
reinit_git &&
+ rm -f backflow &&
cat >expect <<-\EOF &&
OBJID
:120000 100644 OBJID OBJID T test-file
@@ -723,8 +731,9 @@ test_expect_success 'deltas for typechange' '
PROPS-END
link testing 321
EOF
- test-svn-fe deleteprop.dump >stream &&
- git fast-import <stream &&
+ mkfifo backflow &&
+ test-svn-fe deleteprop.dump 3<backflow |
+ git fast-import --cat-blob-fd=3 3>backflow &&
{
git rev-list HEAD |
git diff-tree --root --stdin |@@ -841,15 +850,17 @@ test_expect_success PIPE 'deltas need not consume the whole preimage' '
test_cmp expect.3 actual.3
'
-test_expect_success 't9135/svn.dump' '
+test_expect_success PIPE 't9135/svn.dump' '
+ rm -f backflow &&
svnadmin create simple-svn &&
svnadmin load simple-svn <"$TEST_DIRECTORY/t9135/svn.dump" &&
svn_cmd export "file://$PWD/simple-svn" simple-svnco &&
git init simple-git &&
- test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" >simple.fe &&
+ mkfifo backflow &&
+ test-svn-fe "$TEST_DIRECTORY/t9135/svn.dump" 3<backflow |
(
cd simple-git &&
- git fast-import <../simple.fe
+ git fast-import --cat-blob-fd=3 3>../backflow
) &&
(
cd simple-svnco &&
diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c
index 6a4a689..96f6023 100644
--- a/vcs-svn/fast_export.c
+++ b/vcs-svn/fast_export.c
@@ -37,17 +37,17 @@ void fast_export_delete(uint32_t depth, uint32_t *path)
putchar('\n');
}
-void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
- uint32_t mark)
+void fast_export_modify(uint32_t depth, const uint32_t *path, uint32_t mode,
+ const char *dataref)
{
/* Mode must be 100644, 100755, 120000, or 160000. */
- printf("M %06"PRIo32" :%"PRIu32" ", mode, mark);
+ printf("M %06"PRIo32" %s ", mode, dataref);
pool_print_seq(depth, path, '/', stdout);
putchar('\n');
}
static char gitsvnline[MAX_GITSVN_LINE_LEN];
-void fast_export_commit(uint32_t revision, uint32_t author, char *log,
+void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,
uint32_t uuid, uint32_t url,
unsigned long timestamp)
{@@ -74,10 +74,20 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
printf("from refs/heads/master^0\n");
first_commit_done = 1;
}
- repo_diff(revision - 1, revision);
- fputc('\n', stdout);
+}
- printf("progress Imported commit %"PRIu32".\n\n", revision);
+void fast_export_end_commit(uint32_t revision)
+{
+ printf("\nprogress Imported commit %"PRIu32".\n\n", revision);
+}
+
+static struct strbuf response_line = STRBUF_INIT;
+static const char *get_response_line(void)
+{
+ strbuf_reset(&response_line);
+ if (fd_read_line(&response_line, REPORT_FILENO))
+ return NULL;
+ return response_line.buf;
}
static void ls_from_rev(uint32_t rev, const uint32_t *path)@@ -89,6 +99,56 @@ static void ls_from_rev(uint32_t rev, const uint32_t *path)
fflush(stdout);
}
+static void parse_ls_response(const char *response, uint32_t *mode,
+ struct strbuf *dataref)
+{
+ const char *tab;
+ const char *response_end;
+
+ if (!response)
+ die("cannot read ls response");
+ response_end = response + strlen(response);
+
+ /* Mode. */
+ if (response_end - response < strlen("100644") ||
+ response[strlen("100644")] != ' ')
+ die("invalid ls response: missing mode: %s", response);
+ *mode = 0;
+ for (; *response != ' '; response++) {
+ *mode *= 8;
+ *mode += (*response - '0');
+ }
+
+ /* ' blob ' or ' tree ' */
+ if (response_end - response < strlen(" blob "))
+ die("invalid ls response: missing type: %s", response);
+ response += strlen(" blob ");
+
+ /* Dataref. */
+ tab = memchr(response, '\t', response_end - response);
+ if (!tab)
+ die("invalid ls response: missing tab: %s", response);
+ strbuf_add(dataref, response, tab - response);
+}
+
+void fast_export_ls_rev(uint32_t rev, const uint32_t *path,
+ uint32_t *mode, struct strbuf *dataref)
+{
+ ls_from_rev(rev, path);
+ parse_ls_response(get_response_line(), mode, dataref);
+}
+
+/* Read directory entry from the active commit. */
+void fast_export_ls(const uint32_t *path,
+ uint32_t *mode, struct strbuf *dataref)
+{
+ printf("ls \"");
+ pool_print_seq(REPO_MAX_PATH_DEPTH, path, '/', stdout);
+ printf("\"\n");
+ fflush(stdout);
+ parse_ls_response(get_response_line(), mode, dataref);
+}
+
static int ends_with(const char *s, size_t len, const char *suffix)
{
const size_t suffixlen = strlen(suffix);@@ -97,27 +157,15 @@ static int ends_with(const char *s, size_t len, const char *suffix)
return !memcmp(s + len - suffixlen, suffix, suffixlen);
}
-static int parse_ls_response_line(const char *line, struct strbuf *objnam)
-{
- const char *end = line + strlen(line);
- const char *name, *tab;
-
- if (end - line < strlen("100644 blob "))
- return error("ls response too short: %s", line);
- name = line + strlen("100644 blob ");
- tab = memchr(name, '\t', end - name);
- if (!tab)
- return error("ls response does not contain tab: %s", line);
- strbuf_add(objnam, name, tab - name);
- return 0;
-}
-
static int parse_cat_response_line(const char *header, off_t *len)
{
- size_t headerlen = strlen(header);
+ size_t headerlen;
const char *type;
const char *end;
+ if (!header)
+ return error("missing cat-blob response");
+ headerlen = strlen(header);
if (ends_with(header, headerlen, " missing"))
return error("cat-blob reports missing blob: %s", header);
type = memmem(header, headerlen, " blob ", strlen(" blob "));@@ -131,49 +179,22 @@ static int parse_cat_response_line(const char *header, off_t *len)
return 0;
}
-static struct strbuf response_line = STRBUF_INIT;
-static const char *get_response_line(void)
+static off_t cat_dataref(const char *dataref)
{
- strbuf_reset(&response_line);
- if (fd_read_line(&response_line, REPORT_FILENO))
- return NULL;
- return response_line.buf;
-}
-
-static off_t cat_mark(uint32_t mark)
-{
- const char *response;
off_t length = length;
-
- printf("cat-blob :%"PRIu32"\n", mark);
- fflush(stdout);
- response = get_response_line();
- if (parse_cat_response_line(response, &length))
- die("invalid cat-blob response: %s", response);
- return length;
-}
-
-static off_t cat_from_rev(uint32_t rev, const uint32_t *path)
-{
const char *response;
- off_t length = length;
- struct strbuf blob_name = STRBUF_INIT;
-
- ls_from_rev(rev, path);
- response = get_response_line();
- if (parse_ls_response_line(response, &blob_name))
- die("invalid ls response: %s", response);
- printf("cat-blob %s\n", blob_name.buf);
+ if (!dataref)
+ die("BUG: null data reference");
+ printf("cat-blob %s\n", dataref);
fflush(stdout);
response = get_response_line();
if (parse_cat_response_line(response, &length))
- die("invalid cat-blob response: %s", response);
- strbuf_release(&blob_name);
+ die("invalid cat-blob response");
return length;
}
-static long delta_apply(uint32_t mark, off_t len, struct line_buffer *input,
+static long delta_apply(off_t len, struct line_buffer *input,
off_t preimage_len, uint32_t old_mode)
{
long ret;@@ -203,52 +224,50 @@ static long delta_apply(uint32_t mark, off_t len, struct line_buffer *input,
return ret;
}
-static void record_postimage(uint32_t mark, uint32_t mode,
- long postimage_len)
+static void record_postimage(uint32_t mode, long postimage_len)
{
if (mode == REPO_MODE_LNK) {
buffer_skip_bytes(&postimage, strlen("link "));
postimage_len -= strlen("link ");
}
- printf("blob\nmark :%"PRIu32"\ndata %ld\n", mark, postimage_len);
+ printf("data %ld\n", postimage_len);
buffer_copy_bytes(&postimage, postimage_len);
fputc('\n', stdout);
}
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
+void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input)
{
if (mode == REPO_MODE_LNK) {
/* svn symlink blobs start with "link " */
buffer_skip_bytes(input, 5);
len -= 5;
}
- printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
+ printf("data %"PRIu32"\n", len);
buffer_copy_bytes(input, len);
fputc('\n', stdout);
}
-void fast_export_blob_delta(uint32_t mode, uint32_t mark,
- uint32_t old_mode, uint32_t old_mark,
- uint32_t len, struct line_buffer *input)
+void fast_export_empty_blob(void)
{
- long postimage_len;
- if (len > maximum_signed_value_of_type(off_t))
- die("enormous delta");
- postimage_len = delta_apply(mark, (off_t) len, input,
- old_mark ? cat_mark(old_mark) : -1,
- old_mode);
- record_postimage(mark, mode, postimage_len);
+ printf("blob\ndata 0\n\n");
}
-void fast_export_blob_delta_rev(uint32_t mode, uint32_t mark, uint32_t old_mode,
- uint32_t old_rev, const uint32_t *old_path,
+void fast_export_delta(const uint32_t *path, uint32_t mode, uint32_t old_mode,
+ const char *dataref,
uint32_t len, struct line_buffer *input)
{
+ off_t preimage_len;
long postimage_len;
if (len > maximum_signed_value_of_type(off_t))
die("enormous delta");
- postimage_len = delta_apply(mark, (off_t) len, input,
- cat_from_rev(old_rev, old_path),
- old_mode);
- record_postimage(mark, mode, postimage_len);
+ preimage_len = cat_dataref(dataref);
+
+ /*
+ * NEEDSWORK: Will deadlock with very long paths.
+ */
+ fast_export_modify(REPO_MAX_PATH_DEPTH, path, mode, "inline");
+
+ postimage_len = delta_apply((off_t) len, input,
+ preimage_len, old_mode);
+ record_postimage(mode, postimage_len);
}diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h
index 487d3d4..8415d2c 100644
--- a/vcs-svn/fast_export.h
+++ b/vcs-svn/fast_export.h
@@ -3,18 +3,23 @@
#include "line_buffer.h"
+/* Output routines */
void fast_export_delete(uint32_t depth, uint32_t *path);
-void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
- uint32_t mark);
-void fast_export_commit(uint32_t revision, uint32_t author, char *log,
+void fast_export_modify(uint32_t depth, const uint32_t *path, uint32_t mode,
+ const char *dataref);
+void fast_export_begin_commit(uint32_t revision, uint32_t author, char *log,
uint32_t uuid, uint32_t url, unsigned long timestamp);
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
- struct line_buffer *input);
-void fast_export_blob_delta(uint32_t mode, uint32_t mark,
- uint32_t old_mode, uint32_t old_mark,
- uint32_t len, struct line_buffer *input);
-void fast_export_blob_delta_rev(uint32_t mode, uint32_t mark, uint32_t old_mode,
- uint32_t old_rev, const uint32_t *old_path,
+void fast_export_end_commit(uint32_t revision);
+void fast_export_empty_blob(void);
+void fast_export_data(uint32_t mode, uint32_t len, struct line_buffer *input);
+void fast_export_delta(const uint32_t *path, uint32_t mode, uint32_t old_mode,
+ const char *dataref,
uint32_t len, struct line_buffer *input);
+/* Input routines */
+void fast_export_ls_rev(uint32_t rev, const uint32_t *path,
+ uint32_t *mode_out, struct strbuf *dataref_out);
+void fast_export_ls(const uint32_t *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 4d98185..1283089 100644
--- a/vcs-svn/repo_tree.c
+++ b/vcs-svn/repo_tree.c
@@ -4,321 +4,49 @@
*/
#include "git-compat-util.h"
-
-#include "string_pool.h"
+#include "strbuf.h"
#include "repo_tree.h"
-#include "obj_pool.h"
#include "fast_export.h"
-#include "trp.h"
-
-struct repo_dirent {
- uint32_t name_offset;
- struct trp_node children;
- uint32_t mode;
- uint32_t content_offset;
-};
-
-struct repo_dir {
- struct trp_root entries;
-};
-
-struct repo_commit {
- uint32_t root_dir_offset;
-};
-
-/* Memory pools for commit, dir and dirent */
-obj_pool_gen(commit, struct repo_commit, 4096)
-obj_pool_gen(dir, struct repo_dir, 4096)
-obj_pool_gen(dent, struct repo_dirent, 4096)
-
-static uint32_t active_commit;
-static uint32_t mark;
-
-static int repo_dirent_name_cmp(const void *a, const void *b);
-
-/* Treap for directory entries */
-trp_gen(static, dent_, struct repo_dirent, children, dent, repo_dirent_name_cmp);
-
-uint32_t next_blob_mark(void)
-{
- return mark++;
-}
-
-static struct repo_dir *repo_commit_root_dir(struct repo_commit *commit)
-{
- return dir_pointer(commit->root_dir_offset);
-}
-
-static struct repo_dirent *repo_first_dirent(struct repo_dir *dir)
-{
- return dent_first(&dir->entries);
-}
-
-static int repo_dirent_name_cmp(const void *a, const void *b)
-{
- const struct repo_dirent *dent1 = a, *dent2 = b;
- uint32_t a_offset = dent1->name_offset;
- uint32_t b_offset = dent2->name_offset;
- return (a_offset > b_offset) - (a_offset < b_offset);
-}
-
-static int repo_dirent_is_dir(struct repo_dirent *dent)
-{
- return dent != NULL && dent->mode == REPO_MODE_DIR;
-}
-
-static struct repo_dir *repo_dir_from_dirent(struct repo_dirent *dent)
-{
- if (!repo_dirent_is_dir(dent))
- return NULL;
- return dir_pointer(dent->content_offset);
-}
-
-static struct repo_dir *repo_clone_dir(struct repo_dir *orig_dir)
-{
- uint32_t orig_o, new_o;
- orig_o = dir_offset(orig_dir);
- if (orig_o >= dir_pool.committed)
- return orig_dir;
- new_o = dir_alloc(1);
- orig_dir = dir_pointer(orig_o);
- *dir_pointer(new_o) = *orig_dir;
- return dir_pointer(new_o);
-}
-
-static struct repo_dirent *repo_read_dirent(uint32_t revision, uint32_t *path)
+static struct strbuf dataref_buf = STRBUF_INIT;
+const char *repo_read_path(uint32_t *path)
{
- uint32_t name = 0;
- struct repo_dirent *key = dent_pointer(dent_alloc(1));
- struct repo_dir *dir = NULL;
- struct repo_dirent *dent = NULL;
- dir = repo_commit_root_dir(commit_pointer(revision));
- while (~(name = *path++)) {
- key->name_offset = name;
- dent = dent_search(&dir->entries, key);
- if (dent == NULL || !repo_dirent_is_dir(dent))
- break;
- dir = repo_dir_from_dirent(dent);
- }
- dent_free(1);
- return dent;
-}
+ uint32_t unused;
-static void repo_write_dirent(uint32_t *path, uint32_t mode,
- uint32_t content_offset, uint32_t del)
-{
- uint32_t name, revision, dir_o = ~0, parent_dir_o = ~0;
- struct repo_dir *dir;
- struct repo_dirent *key;
- struct repo_dirent *dent = NULL;
- revision = active_commit;
- dir = repo_commit_root_dir(commit_pointer(revision));
- dir = repo_clone_dir(dir);
- commit_pointer(revision)->root_dir_offset = dir_offset(dir);
- while (~(name = *path++)) {
- parent_dir_o = dir_offset(dir);
-
- key = dent_pointer(dent_alloc(1));
- key->name_offset = name;
-
- dent = dent_search(&dir->entries, key);
- if (dent == NULL)
- dent = key;
- else
- dent_free(1);
-
- if (dent == key) {
- dent->mode = REPO_MODE_DIR;
- dent->content_offset = 0;
- dent_insert(&dir->entries, dent);
- }
-
- if (dent_offset(dent) < dent_pool.committed) {
- dir_o = repo_dirent_is_dir(dent) ?
- dent->content_offset : ~0;
- dent_remove(&dir->entries, dent);
- dent = dent_pointer(dent_alloc(1));
- dent->name_offset = name;
- dent->mode = REPO_MODE_DIR;
- dent->content_offset = dir_o;
- dent_insert(&dir->entries, dent);
- }
-
- dir = repo_dir_from_dirent(dent);
- dir = repo_clone_dir(dir);
- dent->content_offset = dir_offset(dir);
- }
- if (dent == NULL)
- return;
- dent->mode = mode;
- dent->content_offset = content_offset;
- if (del && ~parent_dir_o)
- dent_remove(&dir_pointer(parent_dir_o)->entries, dent);
-}
-
-uint32_t repo_read_path(uint32_t *path)
-{
- uint32_t content_offset = 0;
- struct repo_dirent *dent = repo_read_dirent(active_commit, path);
- if (dent != NULL)
- content_offset = dent->content_offset;
- return content_offset;
+ strbuf_reset(&dataref_buf);
+ fast_export_ls(path, &unused, &dataref_buf);
+ return dataref_buf.buf;
}
uint32_t repo_read_mode(const uint32_t *path)
{
- struct repo_dirent *dent = repo_read_dirent(active_commit, path);
- if (dent == NULL)
- die("invalid dump: path to be modified is missing");
- return dent->mode;
+ uint32_t result;
+ struct strbuf unused = STRBUF_INIT;
+
+ fast_export_ls(path, &result, &unused);
+ strbuf_release(&unused);
+ return result;
}
void repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst)
{
- uint32_t mode = 0, content_offset = 0;
- struct repo_dirent *src_dent;
- src_dent = repo_read_dirent(revision, src);
- if (src_dent != NULL) {
- mode = src_dent->mode;
- content_offset = src_dent->content_offset;
- repo_write_dirent(dst, mode, content_offset, 0);
- }
-}
+ uint32_t mode;
+ struct strbuf data = STRBUF_INIT;
-void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark)
-{
- repo_write_dirent(path, mode, blob_mark, 0);
+ fast_export_ls_rev(revision, src, &mode, &data);
+ fast_export_modify(REPO_MAX_PATH_DEPTH, dst, mode, data.buf);
+ strbuf_release(&data);
}
void repo_delete(uint32_t *path)
{
- repo_write_dirent(path, 0, 0, 1);
-}
-
-static void repo_git_add_r(uint32_t depth, uint32_t *path, struct repo_dir *dir);
-
-static void repo_git_add(uint32_t depth, uint32_t *path, struct repo_dirent *dent)
-{
- if (repo_dirent_is_dir(dent))
- repo_git_add_r(depth, path, repo_dir_from_dirent(dent));
- else
- fast_export_modify(depth, path,
- dent->mode, dent->content_offset);
-}
-
-static void repo_git_add_r(uint32_t depth, uint32_t *path, struct repo_dir *dir)
-{
- struct repo_dirent *de = repo_first_dirent(dir);
- while (de) {
- path[depth] = de->name_offset;
- repo_git_add(depth + 1, path, de);
- de = dent_next(&dir->entries, de);
- }
-}
-
-static void repo_diff_r(uint32_t depth, uint32_t *path, struct repo_dir *dir1,
- struct repo_dir *dir2)
-{
- struct repo_dirent *de1, *de2;
- de1 = repo_first_dirent(dir1);
- de2 = repo_first_dirent(dir2);
-
- while (de1 && de2) {
- if (de1->name_offset < de2->name_offset) {
- path[depth] = de1->name_offset;
- fast_export_delete(depth + 1, path);
- de1 = dent_next(&dir1->entries, de1);
- continue;
- }
- if (de1->name_offset > de2->name_offset) {
- path[depth] = de2->name_offset;
- repo_git_add(depth + 1, path, de2);
- de2 = dent_next(&dir2->entries, de2);
- continue;
- }
- path[depth] = de1->name_offset;
-
- if (de1->mode == de2->mode &&
- de1->content_offset == de2->content_offset) {
- ; /* No change. */
- } else if (repo_dirent_is_dir(de1) && repo_dirent_is_dir(de2)) {
- repo_diff_r(depth + 1, path,
- repo_dir_from_dirent(de1),
- repo_dir_from_dirent(de2));
- } else if (!repo_dirent_is_dir(de1) && !repo_dirent_is_dir(de2)) {
- repo_git_add(depth + 1, path, de2);
- } else {
- fast_export_delete(depth + 1, path);
- repo_git_add(depth + 1, path, de2);
- }
- de1 = dent_next(&dir1->entries, de1);
- de2 = dent_next(&dir2->entries, de2);
- }
- while (de1) {
- path[depth] = de1->name_offset;
- fast_export_delete(depth + 1, path);
- de1 = dent_next(&dir1->entries, de1);
- }
- while (de2) {
- path[depth] = de2->name_offset;
- repo_git_add(depth + 1, path, de2);
- de2 = dent_next(&dir2->entries, de2);
- }
-}
-
-static uint32_t path_stack[REPO_MAX_PATH_DEPTH];
-
-void repo_diff(uint32_t r1, uint32_t r2)
-{
- repo_diff_r(0,
- path_stack,
- repo_commit_root_dir(commit_pointer(r1)),
- repo_commit_root_dir(commit_pointer(r2)));
-}
-
-void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
- uint32_t url, unsigned long timestamp)
-{
- fast_export_commit(revision, author, log, uuid, url, timestamp);
- dent_commit();
- dir_commit();
- active_commit = commit_alloc(1);
- commit_pointer(active_commit)->root_dir_offset =
- commit_pointer(active_commit - 1)->root_dir_offset;
-}
-
-static void mark_init(void)
-{
- uint32_t i;
- mark = 1024 * 1024 * 1024;
- for (i = 0; i < dent_pool.size; i++)
- if (!repo_dirent_is_dir(dent_pointer(i)) &&
- dent_pointer(i)->content_offset > mark)
- mark = dent_pointer(i)->content_offset;
- mark++;
+ fast_export_delete(REPO_MAX_PATH_DEPTH, path);
}
void repo_init(void)
{
- mark_init();
- if (commit_pool.size == 0) {
- /* Create empty tree for commit 0. */
- commit_alloc(1);
- commit_pointer(0)->root_dir_offset = dir_alloc(1);
- dir_pointer(0)->entries.trp_root = ~0;
- dir_commit();
- }
- /* Preallocate next commit, ready for changes. */
- active_commit = commit_alloc(1);
- commit_pointer(active_commit)->root_dir_offset =
- commit_pointer(active_commit - 1)->root_dir_offset;
}
void repo_reset(void)
{
- pool_reset();
- commit_reset();
- dir_reset();
- dent_reset();
}diff --git a/vcs-svn/repo_tree.h b/vcs-svn/repo_tree.h
index 0499a19..559f99f 100644
--- a/vcs-svn/repo_tree.h
+++ b/vcs-svn/repo_tree.h
@@ -14,7 +14,7 @@
uint32_t next_blob_mark(void);
void repo_copy(uint32_t revision, uint32_t *src, uint32_t *dst);
void repo_add(uint32_t *path, uint32_t mode, uint32_t blob_mark);
-uint32_t repo_read_path(uint32_t *path);
+const char *repo_read_path(uint32_t *path);
uint32_t repo_read_mode(const uint32_t *path);
void repo_delete(uint32_t *path);
void repo_commit(uint32_t revision, uint32_t author, char *log, uint32_t uuid,
diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c
index 31c6056..68a8435 100644
--- a/vcs-svn/svndump.c
+++ b/vcs-svn/svndump.c
@@ -20,9 +20,11 @@
#define NODEACT_CHANGE 1
#define NODEACT_UNKNOWN 0
-#define DUMP_CTX 0
-#define REV_CTX 1
-#define NODE_CTX 2
+/* States: */
+#define DUMP_CTX 0 /* dump metadata */
+#define REV_CTX 1 /* revision metadata */
+#define NODE_CTX 2 /* node metadata */
+#define INTERNODE_CTX 3 /* between nodes */
#define LENGTH_UNKNOWN (~0)
#define DATE_RFC2822_LEN 31
@@ -198,13 +200,12 @@ static void read_props(void)
static void handle_node(void)
{
- uint32_t mark = 0, old_mode, old_mark;
+ uint32_t old_mode;
+ const char *old_data;
const uint32_t type = node_ctx.type;
const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
const int have_text = node_ctx.textLength != LENGTH_UNKNOWN;
- if (have_text)
- mark = next_blob_mark();
if (node_ctx.action == NODEACT_DELETE) {
if (have_text || have_props || node_ctx.srcRev)
die("invalid dump: deletion node has "@@ -224,18 +225,15 @@ static void handle_node(void)
die("invalid dump: directories cannot have text attached");
/*
- * Find old content (old_mark) and decide on the new content (mark)
- * and mode (node_ctx.type).
+ * Find old content (old_data) and decide on the new mode.
*/
if (node_ctx.action == NODEACT_CHANGE && !~*node_ctx.dst) {
if (type != REPO_MODE_DIR)
die("invalid dump: root of tree is not a regular file");
- old_mark = 0;
+ old_data = NULL;
} else if (node_ctx.action == NODEACT_CHANGE) {
uint32_t mode;
- old_mark = repo_read_path(node_ctx.dst);
- if (!have_text)
- mark = old_mark;
+ old_data = repo_read_path(node_ctx.dst);
mode = repo_read_mode(node_ctx.dst);
if (mode == REPO_MODE_DIR && type != REPO_MODE_DIR)
die("invalid dump: cannot modify a directory into a file");@@ -243,9 +241,12 @@ static void handle_node(void)
die("invalid dump: cannot modify a file into a directory");
node_ctx.type = mode;
} else if (node_ctx.action == NODEACT_ADD) {
- if (!have_text && type != REPO_MODE_DIR)
+ if (type == REPO_MODE_DIR)
+ old_data = NULL;
+ else if (have_text)
+ old_data = EMPTY_BLOB_SHA1_HEX;
+ else
die("invalid dump: adds node without text");
- old_mark = 0;
} else {
die("invalid dump: Node-path block lacks Node-action");
}@@ -264,28 +265,35 @@ static void handle_node(void)
/*
* Save the result.
*/
- repo_add(node_ctx.dst, node_ctx.type, mark);
- if (!have_text)
+ if (type == REPO_MODE_DIR) /* directories are not tracked. */
return;
+ if (!have_text) {
+ fast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst, node_ctx.type,
+ old_data);
+ return;
+ }
if (!node_ctx.text_delta) {
- fast_export_blob(node_ctx.type, mark, node_ctx.textLength, &input);
+ fast_export_modify(REPO_MAX_PATH_DEPTH, node_ctx.dst, node_ctx.type,
+ "inline");
+ fast_export_data(node_ctx.type, node_ctx.textLength, &input);
return;
}
- if (node_ctx.srcRev) {
- fast_export_blob_delta_rev(node_ctx.type, mark, old_mode,
- node_ctx.srcRev, node_ctx.src,
+ fast_export_delta(node_ctx.dst, node_ctx.type, old_mode, old_data,
node_ctx.textLength, &input);
+}
+
+static void begin_revision(void)
+{
+ if (!rev_ctx.revision) /* revision 0 gets no git commit. */
return;
- }
- fast_export_blob_delta(node_ctx.type, mark, old_mode, old_mark,
- node_ctx.textLength, &input);
+ fast_export_begin_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
+ dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
}
-static void handle_revision(void)
+static void end_revision(void)
{
if (rev_ctx.revision)
- repo_commit(rev_ctx.revision, rev_ctx.author, rev_ctx.log,
- dump_ctx.uuid, dump_ctx.url, rev_ctx.timestamp);
+ fast_export_end_commit(rev_ctx.revision);
}
void svndump_read(const char *url)@@ -315,13 +323,17 @@ void svndump_read(const char *url)
} else if (key == keys.revision_number) {
if (active_ctx == NODE_CTX)
handle_node();
+ if (active_ctx == REV_CTX)
+ begin_revision();
if (active_ctx != DUMP_CTX)
- handle_revision();
+ end_revision();
active_ctx = REV_CTX;
reset_rev_ctx(atoi(val));
} else if (key == keys.node_path) {
if (active_ctx == NODE_CTX)
handle_node();
+ if (active_ctx == REV_CTX)
+ begin_revision();
active_ctx = NODE_CTX;
reset_node_ctx(val);
} else if (key == keys.node_kind) {@@ -363,7 +375,7 @@ void svndump_read(const char *url)
read_props();
} else if (active_ctx == NODE_CTX) {
handle_node();
- active_ctx = REV_CTX;
+ active_ctx = INTERNODE_CTX;
} else {
fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
buffer_skip_bytes(&input, len);@@ -372,8 +384,10 @@ void svndump_read(const char *url)
}
if (active_ctx == NODE_CTX)
handle_node();
+ if (active_ctx == REV_CTX)
+ begin_revision();
if (active_ctx != DUMP_CTX)
- handle_revision();
+ end_revision();
}
int svndump_init(const char *filename)
@@ -385,6 +399,7 @@ int svndump_init(const char *filename)
reset_rev_ctx(0);
reset_node_ctx(NULL);
init_keys();
+ fast_export_empty_blob();
return 0;
}
--
1.7.2.4