Skip to content

Commit 6b01b67

Browse files
barrbraingitster
authored andcommitted
vcs-svn: Implement Prop-delta handling
The rules for what file is used as delta source for each file are not documented in dump-load-format.txt. Luckily, the Apache Software Foundation repository has rich enough examples to figure out most of the rules: Node-action: replace implies the empty property set and empty text as preimage for deltas. Otherwise, if a copyfrom source is given, that node is the preimage for deltas. Lastly, if none of the above applies and the node path exists in the current revision, then that version forms the basis. [jn: refactored, with tests] Signed-off-by: David Barr <[email protected]> Signed-off-by: Jonathan Nieder <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 6263c06 commit 6b01b67

File tree

2 files changed

+144
-12
lines changed

2 files changed

+144
-12
lines changed

t/t9010-svn-fe.sh

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,12 @@ test_expect_success 'deltas not supported' '
514514
test_must_fail test-svn-fe delta.dump
515515
'
516516

517-
test_expect_success 'property deltas not supported' '
517+
test_expect_success 'property deltas supported' '
518+
reinit_git &&
519+
cat >expect <<-\EOF &&
520+
OBJID
521+
:100755 100644 OBJID OBJID M script.sh
522+
EOF
518523
{
519524
properties \
520525
svn:author [email protected] \
@@ -565,7 +570,100 @@ test_expect_success 'property deltas not supported' '
565570
PROPS-END
566571
EOF
567572
} >propdelta.dump &&
568-
test_must_fail test-svn-fe propdelta.dump
573+
test-svn-fe propdelta.dump >stream &&
574+
git fast-import <stream &&
575+
{
576+
git rev-list HEAD |
577+
git diff-tree --stdin |
578+
sed "s/$_x40/OBJID/g"
579+
} >actual &&
580+
test_cmp expect actual
581+
'
582+
583+
test_expect_success 'deltas for typechange' '
584+
reinit_git &&
585+
cat >expect <<-\EOF &&
586+
OBJID
587+
:120000 100644 OBJID OBJID T test-file
588+
OBJID
589+
:100755 120000 OBJID OBJID T test-file
590+
OBJID
591+
:000000 100755 OBJID OBJID A test-file
592+
EOF
593+
cat >deleteprop.dump <<-\EOF &&
594+
SVN-fs-dump-format-version: 3
595+
596+
Revision-number: 1
597+
Prop-content-length: 10
598+
Content-length: 10
599+
600+
PROPS-END
601+
602+
Node-path: test-file
603+
Node-kind: file
604+
Node-action: add
605+
Prop-delta: true
606+
Prop-content-length: 35
607+
Text-content-length: 17
608+
Content-length: 52
609+
610+
K 14
611+
svn:executable
612+
V 0
613+
614+
PROPS-END
615+
link testing 123
616+
617+
Revision-number: 2
618+
Prop-content-length: 10
619+
Content-length: 10
620+
621+
PROPS-END
622+
623+
Node-path: test-file
624+
Node-kind: file
625+
Node-action: change
626+
Prop-delta: true
627+
Prop-content-length: 53
628+
Text-content-length: 17
629+
Content-length: 70
630+
631+
K 11
632+
svn:special
633+
V 1
634+
*
635+
D 14
636+
svn:executable
637+
PROPS-END
638+
link testing 231
639+
640+
Revision-number: 3
641+
Prop-content-length: 10
642+
Content-length: 10
643+
644+
PROPS-END
645+
646+
Node-path: test-file
647+
Node-kind: file
648+
Node-action: change
649+
Prop-delta: true
650+
Prop-content-length: 27
651+
Text-content-length: 17
652+
Content-length: 44
653+
654+
D 11
655+
svn:special
656+
PROPS-END
657+
link testing 321
658+
EOF
659+
test-svn-fe deleteprop.dump >stream &&
660+
git fast-import <stream &&
661+
{
662+
git rev-list HEAD |
663+
git diff-tree --root --stdin |
664+
sed "s/$_x40/OBJID/g"
665+
} >actual &&
666+
test_cmp expect actual
569667
'
570668

571669
test_expect_success 't9135/svn.dump' '

vcs-svn/svndump.c

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -115,27 +115,55 @@ static void init_keys(void)
115115
keys.prop_delta = pool_intern("Prop-delta");
116116
}
117117

118-
static void handle_property(uint32_t key, const char *val, uint32_t len)
118+
static void handle_property(uint32_t key, const char *val, uint32_t len,
119+
uint32_t *type_set)
119120
{
120121
if (key == keys.svn_log) {
122+
if (!val)
123+
die("invalid dump: unsets svn:log");
121124
/* Value length excludes terminating nul. */
122125
rev_ctx.log = log_copy(len + 1, val);
123126
} else if (key == keys.svn_author) {
124127
rev_ctx.author = pool_intern(val);
125128
} else if (key == keys.svn_date) {
129+
if (!val)
130+
die("invalid dump: unsets svn:date");
126131
if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
127-
fprintf(stderr, "Invalid timestamp: %s\n", val);
128-
} else if (key == keys.svn_executable) {
129-
node_ctx.type = REPO_MODE_EXE;
130-
} else if (key == keys.svn_special) {
131-
node_ctx.type = REPO_MODE_LNK;
132+
warning("invalid timestamp: %s", val);
133+
} else if (key == keys.svn_executable || key == keys.svn_special) {
134+
if (*type_set) {
135+
if (!val)
136+
return;
137+
die("invalid dump: sets type twice");
138+
}
139+
if (!val) {
140+
node_ctx.type = REPO_MODE_BLB;
141+
return;
142+
}
143+
*type_set = 1;
144+
node_ctx.type = key == keys.svn_executable ?
145+
REPO_MODE_EXE :
146+
REPO_MODE_LNK;
132147
}
133148
}
134149

135150
static void read_props(void)
136151
{
137152
uint32_t key = ~0;
138153
const char *t;
154+
/*
155+
* NEEDSWORK: to support simple mode changes like
156+
* K 11
157+
* svn:special
158+
* V 1
159+
* *
160+
* D 14
161+
* svn:executable
162+
* we keep track of whether a mode has been set and reset to
163+
* plain file only if not. We should be keeping track of the
164+
* symlink and executable bits separately instead.
165+
*/
166+
uint32_t type_set = 0;
139167
while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
140168
uint32_t len;
141169
const char *val;
@@ -151,8 +179,13 @@ static void read_props(void)
151179
case 'K':
152180
key = pool_intern(val);
153181
continue;
182+
case 'D':
183+
key = pool_intern(val);
184+
val = NULL;
185+
len = 0;
186+
/* fall through */
154187
case 'V':
155-
handle_property(key, val, len);
188+
handle_property(key, val, len, &type_set);
156189
key = ~0;
157190
continue;
158191
default:
@@ -167,8 +200,8 @@ static void handle_node(void)
167200
const uint32_t type = node_ctx.type;
168201
const int have_props = node_ctx.propLength != LENGTH_UNKNOWN;
169202

170-
if (node_ctx.text_delta || node_ctx.prop_delta)
171-
die("text and property deltas not supported");
203+
if (node_ctx.text_delta)
204+
die("text deltas not supported");
172205
if (node_ctx.textLength != LENGTH_UNKNOWN)
173206
mark = next_blob_mark();
174207
if (node_ctx.action == NODEACT_DELETE) {
@@ -206,7 +239,8 @@ static void handle_node(void)
206239
}
207240
if (have_props) {
208241
const uint32_t old_mode = node_ctx.type;
209-
node_ctx.type = type;
242+
if (!node_ctx.prop_delta)
243+
node_ctx.type = type;
210244
if (node_ctx.propLength)
211245
read_props();
212246
if (node_ctx.type != old_mode)

0 commit comments

Comments
 (0)