Skip to content

Commit f70f736

Browse files
committed
Merge branch 'svn-fe' of git://repo.or.cz/git/jrn
* 'svn-fe' of git://repo.or.cz/git/jrn: (31 commits) fast-import: make code "-Wpointer-arith" clean vcs-svn: teach line_buffer about temporary files vcs-svn: allow input from file descriptor vcs-svn: allow character-oriented input vcs-svn: add binary-safe read function t0081 (line-buffer): add buffering tests vcs-svn: tweak test-line-buffer to not assume line-oriented input tests: give vcs-svn/line_buffer its own test script vcs-svn: make test-line-buffer input format more flexible vcs-svn: teach line_buffer to handle multiple input files vcs-svn: collect line_buffer data in a struct vcs-svn: replace buffer_read_string memory pool with a strbuf vcs-svn: eliminate global byte_buffer fast-import: add 'ls' command vcs-svn: Allow change nodes for root of tree (/) vcs-svn: Implement Prop-delta handling vcs-svn: Sharpen parsing of property lines vcs-svn: Split off function for handling of individual properties vcs-svn: Make source easier to read on small screens vcs-svn: More dump format sanity checks ...
2 parents afb0b79 + 6288e3e commit f70f736

18 files changed

+1571
-233
lines changed

Documentation/git-fast-import.txt

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,8 @@ especially when a higher level language such as Perl, Python or
196196
Ruby is being used.
197197

198198
fast-import is very strict about its input. Where we say SP below we mean
199-
*exactly* one space. Likewise LF means one (and only one) linefeed.
199+
*exactly* one space. Likewise LF means one (and only one) linefeed
200+
and HT one (and only one) horizontal tab.
200201
Supplying additional whitespace characters will cause unexpected
201202
results, such as branch names or file names with leading or trailing
202203
spaces in their name, or early termination of fast-import when it encounters
@@ -334,6 +335,11 @@ and control the current import process. More detailed discussion
334335
format to the file descriptor set with `--cat-blob-fd` or
335336
`stdout` if unspecified.
336337

338+
`ls`::
339+
Causes fast-import to print a line describing a directory
340+
entry in 'ls-tree' format to the file descriptor set with
341+
`--cat-blob-fd` or `stdout` if unspecified.
342+
337343
`feature`::
338344
Require that fast-import supports the specified feature, or
339345
abort if it does not.
@@ -919,6 +925,55 @@ This command can be used anywhere in the stream that comments are
919925
accepted. In particular, the `cat-blob` command can be used in the
920926
middle of a commit but not in the middle of a `data` command.
921927

928+
`ls`
929+
~~~~
930+
Prints information about the object at a path to a file descriptor
931+
previously arranged with the `--cat-blob-fd` argument. This allows
932+
printing a blob from the active commit (with `cat-blob`) or copying a
933+
blob or tree from a previous commit for use in the current one (with
934+
`filemodify`).
935+
936+
The `ls` command can be used anywhere in the stream that comments are
937+
accepted, including the middle of a commit.
938+
939+
Reading from the active commit::
940+
This form can only be used in the middle of a `commit`.
941+
The path names a directory entry within fast-import's
942+
active commit. The path must be quoted in this case.
943+
+
944+
....
945+
'ls' SP <path> LF
946+
....
947+
948+
Reading from a named tree::
949+
The `<dataref>` can be a mark reference (`:<idnum>`) or the
950+
full 40-byte SHA-1 of a Git tag, commit, or tree object,
951+
preexisting or waiting to be written.
952+
The path is relative to the top level of the tree
953+
named by `<dataref>`.
954+
+
955+
....
956+
'ls' SP <dataref> SP <path> LF
957+
....
958+
959+
See `filemodify` above for a detailed description of `<path>`.
960+
961+
Output uses the same format as `git ls-tree <tree> {litdd} <path>`:
962+
963+
====
964+
<mode> SP ('blob' | 'tree' | 'commit') SP <dataref> HT <path> LF
965+
====
966+
967+
The <dataref> represents the blob, tree, or commit object at <path>
968+
and can be used in later 'cat-blob', 'filemodify', or 'ls' commands.
969+
970+
If there is no file or subtree at that path, 'git fast-import' will
971+
instead report
972+
973+
====
974+
missing SP <path> LF
975+
====
976+
922977
`feature`
923978
~~~~~~~~~
924979
Require that fast-import supports the specified feature, or abort if
@@ -946,8 +1001,10 @@ import-marks::
9461001
any "feature import-marks" command in the stream.
9471002

9481003
cat-blob::
949-
Ignored. Versions of fast-import not supporting the
950-
"cat-blob" command will exit with a message indicating so.
1004+
ls::
1005+
Require that the backend support the 'cat-blob' or 'ls' command.
1006+
Versions of fast-import not supporting the specified command
1007+
will exit with a message indicating so.
9511008
This lets the import error out early with a clear message,
9521009
rather than wasting time on the early part of an import
9531010
before the unsupported command is detected.

contrib/svn-fe/svn-fe.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88

99
int main(int argc, char **argv)
1010
{
11-
svndump_init(NULL);
11+
if (svndump_init(NULL))
12+
return 1;
1213
svndump_read((argc > 1) ? argv[1] : NULL);
1314
svndump_deinit();
1415
svndump_reset();

fast-import.c

Lines changed: 159 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,12 @@ Format of STDIN stream:
2424
commit_msg
2525
('from' sp committish lf)?
2626
('merge' sp committish lf)*
27-
file_change*
27+
(file_change | ls)*
2828
lf?;
2929
commit_msg ::= data;
3030
31+
ls ::= 'ls' sp '"' quoted(path) '"' lf;
32+
3133
file_change ::= file_clr
3234
| file_del
3335
| file_rnm
@@ -132,7 +134,7 @@ Format of STDIN stream:
132134
ts ::= # time since the epoch in seconds, ascii base10 notation;
133135
tz ::= # GIT style timezone;
134136
135-
# note: comments and cat requests may appear anywhere
137+
# note: comments, ls and cat requests may appear anywhere
136138
# in the input, except within a data command. Any form
137139
# of the data command always escapes the related input
138140
# from comment processing.
@@ -141,7 +143,9 @@ Format of STDIN stream:
141143
# must be the first character on that line (an lf
142144
# preceded it).
143145
#
146+
144147
cat_blob ::= 'cat-blob' sp (hexsha1 | idnum) lf;
148+
ls_tree ::= 'ls' sp (hexsha1 | idnum) sp path_str lf;
145149
146150
comment ::= '#' not_lf* lf;
147151
not_lf ::= # Any byte that is not ASCII newline (LF);
@@ -374,6 +378,7 @@ static int cat_blob_fd = STDOUT_FILENO;
374378

375379
static void parse_argv(void);
376380
static void parse_cat_blob(void);
381+
static void parse_ls(struct branch *b);
377382

378383
static void write_branch_report(FILE *rpt, struct branch *b)
379384
{
@@ -2614,6 +2619,8 @@ static void parse_new_commit(void)
26142619
note_change_n(b, prev_fanout);
26152620
else if (!strcmp("deleteall", command_buf.buf))
26162621
file_change_deleteall(b);
2622+
else if (!prefixcmp(command_buf.buf, "ls "))
2623+
parse_ls(b);
26172624
else {
26182625
unread_command_buf = 1;
26192626
break;
@@ -2837,6 +2844,153 @@ static void parse_cat_blob(void)
28372844
cat_blob(oe, sha1);
28382845
}
28392846

2847+
static struct object_entry *dereference(struct object_entry *oe,
2848+
unsigned char sha1[20])
2849+
{
2850+
unsigned long size;
2851+
char *buf = NULL;
2852+
if (!oe) {
2853+
enum object_type type = sha1_object_info(sha1, NULL);
2854+
if (type < 0)
2855+
die("object not found: %s", sha1_to_hex(sha1));
2856+
/* cache it! */
2857+
oe = insert_object(sha1);
2858+
oe->type = type;
2859+
oe->pack_id = MAX_PACK_ID;
2860+
oe->idx.offset = 1;
2861+
}
2862+
switch (oe->type) {
2863+
case OBJ_TREE: /* easy case. */
2864+
return oe;
2865+
case OBJ_COMMIT:
2866+
case OBJ_TAG:
2867+
break;
2868+
default:
2869+
die("Not a treeish: %s", command_buf.buf);
2870+
}
2871+
2872+
if (oe->pack_id != MAX_PACK_ID) { /* in a pack being written */
2873+
buf = gfi_unpack_entry(oe, &size);
2874+
} else {
2875+
enum object_type unused;
2876+
buf = read_sha1_file(sha1, &unused, &size);
2877+
}
2878+
if (!buf)
2879+
die("Can't load object %s", sha1_to_hex(sha1));
2880+
2881+
/* Peel one layer. */
2882+
switch (oe->type) {
2883+
case OBJ_TAG:
2884+
if (size < 40 + strlen("object ") ||
2885+
get_sha1_hex(buf + strlen("object "), sha1))
2886+
die("Invalid SHA1 in tag: %s", command_buf.buf);
2887+
break;
2888+
case OBJ_COMMIT:
2889+
if (size < 40 + strlen("tree ") ||
2890+
get_sha1_hex(buf + strlen("tree "), sha1))
2891+
die("Invalid SHA1 in commit: %s", command_buf.buf);
2892+
}
2893+
2894+
free(buf);
2895+
return find_object(sha1);
2896+
}
2897+
2898+
static struct object_entry *parse_treeish_dataref(const char **p)
2899+
{
2900+
unsigned char sha1[20];
2901+
struct object_entry *e;
2902+
2903+
if (**p == ':') { /* <mark> */
2904+
char *endptr;
2905+
e = find_mark(strtoumax(*p + 1, &endptr, 10));
2906+
if (endptr == *p + 1)
2907+
die("Invalid mark: %s", command_buf.buf);
2908+
if (!e)
2909+
die("Unknown mark: %s", command_buf.buf);
2910+
*p = endptr;
2911+
hashcpy(sha1, e->idx.sha1);
2912+
} else { /* <sha1> */
2913+
if (get_sha1_hex(*p, sha1))
2914+
die("Invalid SHA1: %s", command_buf.buf);
2915+
e = find_object(sha1);
2916+
*p += 40;
2917+
}
2918+
2919+
while (!e || e->type != OBJ_TREE)
2920+
e = dereference(e, sha1);
2921+
return e;
2922+
}
2923+
2924+
static void print_ls(int mode, const unsigned char *sha1, const char *path)
2925+
{
2926+
static struct strbuf line = STRBUF_INIT;
2927+
2928+
/* See show_tree(). */
2929+
const char *type =
2930+
S_ISGITLINK(mode) ? commit_type :
2931+
S_ISDIR(mode) ? tree_type :
2932+
blob_type;
2933+
2934+
if (!mode) {
2935+
/* missing SP path LF */
2936+
strbuf_reset(&line);
2937+
strbuf_addstr(&line, "missing ");
2938+
quote_c_style(path, &line, NULL, 0);
2939+
strbuf_addch(&line, '\n');
2940+
} else {
2941+
/* mode SP type SP object_name TAB path LF */
2942+
strbuf_reset(&line);
2943+
strbuf_addf(&line, "%06o %s %s\t",
2944+
mode, type, sha1_to_hex(sha1));
2945+
quote_c_style(path, &line, NULL, 0);
2946+
strbuf_addch(&line, '\n');
2947+
}
2948+
cat_blob_write(line.buf, line.len);
2949+
}
2950+
2951+
static void parse_ls(struct branch *b)
2952+
{
2953+
const char *p;
2954+
struct tree_entry *root = NULL;
2955+
struct tree_entry leaf = {0};
2956+
2957+
/* ls SP (<treeish> SP)? <path> */
2958+
p = command_buf.buf + strlen("ls ");
2959+
if (*p == '"') {
2960+
if (!b)
2961+
die("Not in a commit: %s", command_buf.buf);
2962+
root = &b->branch_tree;
2963+
} else {
2964+
struct object_entry *e = parse_treeish_dataref(&p);
2965+
root = new_tree_entry();
2966+
hashcpy(root->versions[1].sha1, e->idx.sha1);
2967+
load_tree(root);
2968+
if (*p++ != ' ')
2969+
die("Missing space after tree-ish: %s", command_buf.buf);
2970+
}
2971+
if (*p == '"') {
2972+
static struct strbuf uq = STRBUF_INIT;
2973+
const char *endp;
2974+
strbuf_reset(&uq);
2975+
if (unquote_c_style(&uq, p, &endp))
2976+
die("Invalid path: %s", command_buf.buf);
2977+
if (*endp)
2978+
die("Garbage after path in: %s", command_buf.buf);
2979+
p = uq.buf;
2980+
}
2981+
tree_content_get(root, p, &leaf);
2982+
/*
2983+
* A directory in preparation would have a sha1 of zero
2984+
* until it is saved. Save, for simplicity.
2985+
*/
2986+
if (S_ISDIR(leaf.versions[1].mode))
2987+
store_tree(&leaf);
2988+
2989+
print_ls(leaf.versions[1].mode, leaf.versions[1].sha1, p);
2990+
if (!b || root != &b->branch_tree)
2991+
release_tree_entry(root);
2992+
}
2993+
28402994
static void checkpoint(void)
28412995
{
28422996
checkpoint_requested = 0;
@@ -3001,7 +3155,7 @@ static int parse_one_feature(const char *feature, int from_stream)
30013155
relative_marks_paths = 0;
30023156
} else if (!prefixcmp(feature, "force")) {
30033157
force_update = 1;
3004-
} else if (!strcmp(feature, "notes")) {
3158+
} else if (!strcmp(feature, "notes") || !strcmp(feature, "ls")) {
30053159
; /* do nothing; we have the feature */
30063160
} else {
30073161
return 0;
@@ -3142,6 +3296,8 @@ int main(int argc, const char **argv)
31423296
while (read_next_command() != EOF) {
31433297
if (!strcmp("blob", command_buf.buf))
31443298
parse_new_blob();
3299+
else if (!prefixcmp(command_buf.buf, "ls "))
3300+
parse_ls(NULL);
31453301
else if (!prefixcmp(command_buf.buf, "commit "))
31463302
parse_new_commit();
31473303
else if (!prefixcmp(command_buf.buf, "tag "))

t/t0080-vcs-svn.sh

Lines changed: 0 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -76,60 +76,6 @@ test_expect_success 'obj pool: high-water mark' '
7676
test_cmp expected actual
7777
'
7878

79-
test_expect_success 'line buffer' '
80-
echo HELLO >expected1 &&
81-
printf "%s\n" "" HELLO >expected2 &&
82-
echo >expected3 &&
83-
printf "%s\n" "" Q | q_to_nul >expected4 &&
84-
printf "%s\n" foo "" >expected5 &&
85-
printf "%s\n" "" foo >expected6 &&
86-
87-
test-line-buffer <<-\EOF >actual1 &&
88-
5
89-
HELLO
90-
EOF
91-
92-
test-line-buffer <<-\EOF >actual2 &&
93-
0
94-
95-
5
96-
HELLO
97-
EOF
98-
99-
q_to_nul <<-\EOF |
100-
1
101-
Q
102-
EOF
103-
test-line-buffer >actual3 &&
104-
105-
q_to_nul <<-\EOF |
106-
0
107-
108-
1
109-
Q
110-
EOF
111-
test-line-buffer >actual4 &&
112-
113-
test-line-buffer <<-\EOF >actual5 &&
114-
5
115-
foo
116-
EOF
117-
118-
test-line-buffer <<-\EOF >actual6 &&
119-
0
120-
121-
5
122-
foo
123-
EOF
124-
125-
test_cmp expected1 actual1 &&
126-
test_cmp expected2 actual2 &&
127-
test_cmp expected3 actual3 &&
128-
test_cmp expected4 actual4 &&
129-
test_cmp expected5 actual5 &&
130-
test_cmp expected6 actual6
131-
'
132-
13379
test_expect_success 'string pool' '
13480
echo a does not equal b >expected.differ &&
13581
echo a equals a >expected.match &&

0 commit comments

Comments
 (0)