Fossil SCM

Fix a problem that can occasionally occur with repeated syncs to/from a git repository, where a fossil-generated mark clashes with a mark previously generated by git, causing the sync to fail.

nick.lloyd 2016-09-21 19:05 nick.lloyd-git-interop
Commit 69668f8c57a081b40ab195295326e42bd845a5fb
2 files changed +75 -34 +4 -4
+75 -34
--- src/export.c
+++ src/export.c
@@ -132,23 +132,28 @@
132132
133133
/*
134134
** create_mark()
135135
** Create a new (mark,rid,uuid) entry for the given rid in the 'xmark' table,
136136
** and return that information as a struct mark_t in *mark.
137
+** *unused_mark is a value representing a mark that is free for use--that is,
138
+** it does not appear in the marks file, and has not been used during this
139
+** export run. Specifically, it is the supremum of the set of used marks
140
+** plus one.
137141
** This function returns -1 in the case where 'rid' does not exist, otherwise
138142
** it returns 0.
139143
** mark->name is dynamically allocated and is owned by the caller upon return.
140144
*/
141
-int create_mark(int rid, struct mark_t *mark){
145
+int create_mark(int rid, struct mark_t *mark, unsigned int *unused_mark){
142146
char sid[13];
143147
char *zUuid = rid_to_uuid(rid);
144148
if(!zUuid){
145149
fossil_trace("Undefined rid=%d\n", rid);
146150
return -1;
147151
}
148152
mark->rid = rid;
149
- sqlite3_snprintf(sizeof(sid), sid, ":%d", COMMITMARK(rid));
153
+ sqlite3_snprintf(sizeof(sid), sid, ":%d", *unused_mark);
154
+ *unused_mark += 1;
150155
mark->name = fossil_strdup(sid);
151156
sqlite3_snprintf(sizeof(mark->uuid), mark->uuid, "%s", zUuid);
152157
free(zUuid);
153158
insert_commit_xref(mark->rid, mark->name, mark->uuid);
154159
return 0;
@@ -156,19 +161,22 @@
156161
157162
/*
158163
** mark_name_from_rid()
159164
** Find the mark associated with the given rid. Mark names always start
160165
** with ':', and are pulled from the 'xmark' temporary table.
161
-** This function returns NULL if the rid does not exist in the 'xmark' table.
162
-** Otherwise, it returns the name of the mark, which is dynamically allocated
163
-** and is owned by the caller of this function.
166
+** If the given rid doesn't have a mark associated with it yet, one is
167
+** created with a value of *unused_mark.
168
+** *unused_mark functions exactly as in create_mark().
169
+** This function returns NULL if the rid does not have an associated UUID,
170
+** (i.e. is not valid). Otherwise, it returns the name of the mark, which is
171
+** dynamically allocated and is owned by the caller of this function.
164172
*/
165
-char * mark_name_from_rid(int rid){
173
+char * mark_name_from_rid(int rid, unsigned int *unused_mark){
166174
char *zMark = db_text(0, "SELECT tname FROM xmark WHERE trid=%d", rid);
167175
if(zMark==NULL){
168176
struct mark_t mark;
169
- if(create_mark(rid, &mark)==0){
177
+ if(create_mark(rid, &mark, unused_mark)==0){
170178
zMark = mark.name;
171179
}else{
172180
return NULL;
173181
}
174182
}
@@ -185,16 +193,18 @@
185193
** database. Otherwise, 0 is returned.
186194
** mark->name is dynamically allocated, and owned by the caller.
187195
*/
188196
int parse_mark(char *line, struct mark_t *mark){
189197
char *cur_tok;
198
+ char type_;
190199
cur_tok = strtok(line, " \t");
191200
if(!cur_tok||strlen(cur_tok)<2){
192201
return -1;
193202
}
194203
mark->rid = atoi(&cur_tok[1]);
195
- if(cur_tok[0]!='c'){
204
+ type_ = cur_tok[0];
205
+ if(type_!='c'&&type_!='b'){
196206
/* This is probably a blob mark */
197207
mark->name = NULL;
198208
return 0;
199209
}
200210
@@ -202,11 +212,18 @@
202212
if(!cur_tok){
203213
/* This mark was generated by an older version of Fossil and doesn't
204214
** include the mark name and uuid. create_mark() will name the new mark
205215
** exactly as it was when exported to git, so that we should have a
206216
** valid mapping from git sha1<->mark name<->fossil sha1. */
207
- return create_mark(mark->rid, mark);
217
+ unsigned int mid;
218
+ if( type_=='c' ){
219
+ mid = COMMITMARK(mark->rid);
220
+ }
221
+ else{
222
+ mid = BLOBMARK(mark->rid);
223
+ }
224
+ return create_mark(mark->rid, mark, &mid);
208225
}else{
209226
mark->name = fossil_strdup(cur_tok);
210227
}
211228
212229
cur_tok = strtok(NULL, "\n");
@@ -233,18 +250,21 @@
233250
/*
234251
** import_marks()
235252
** Import the marks specified in file 'f' into the 'xmark' table.
236253
** If 'blobs' is non-null, insert all blob marks into it.
237254
** If 'vers' is non-null, insert all commit marks into it.
255
+** If 'unused_marks' is non-null, upon return of this function, all values
256
+** x >= *unused_marks are free to use as marks, i.e. they do not clash with
257
+** any marks appearing in the marks file.
238258
** Each line in the file must be at most 100 characters in length. This
239259
** seems like a reasonable maximum for a 40-character uuid, and 1-13
240260
** character rid.
241261
** The function returns -1 if any of the lines in file 'f' are malformed,
242262
** or the rid/uuid information doesn't match what is in the repository
243263
** database. Otherwise, 0 is returned.
244264
*/
245
-int import_marks(FILE* f, Bag *blobs, Bag *vers){
265
+int import_marks(FILE* f, Bag *blobs, Bag *vers, unsigned int *unused_mark){
246266
char line[101];
247267
while(fgets(line, sizeof(line), f)){
248268
struct mark_t mark;
249269
if(strlen(line)==100&&line[99]!='\n'){
250270
/* line too long */
@@ -251,22 +271,45 @@
251271
return -1;
252272
}
253273
if( parse_mark(line, &mark)<0 ){
254274
return -1;
255275
}else if( line[0]=='b' ){
256
- /* Don't import blob marks into 'xmark' table--git doesn't use them,
257
- ** so they need to be left free for git to reuse. */
258276
if(blobs!=NULL){
259277
bag_insert(blobs, mark.rid);
260278
}
261
- }else if( vers!=NULL ){
262
- bag_insert(vers, mark.rid);
279
+ }else{
280
+ if( vers!=NULL ){
281
+ bag_insert(vers, mark.rid);
282
+ }
283
+ }
284
+ if( unused_mark!=NULL ){
285
+ unsigned int mid = atoi(mark.name + 1);
286
+ if( mid>=*unused_mark ){
287
+ *unused_mark = mid + 1;
288
+ }
263289
}
264290
free(mark.name);
265291
}
266292
return 0;
267293
}
294
+
295
+void export_mark(FILE* f, int rid, char obj_type)
296
+{
297
+ unsigned int z = 0;
298
+ char *zUuid = rid_to_uuid(rid);
299
+ char *zMark;
300
+ if(zUuid==NULL){
301
+ fossil_trace("No uuid matching rid=%d when exporting marks\n", rid);
302
+ return;
303
+ }
304
+ /* Since rid is already in the 'xmark' table, the value of z won't be
305
+ ** used, but pass in a valid pointer just to be safe. */
306
+ zMark = mark_name_from_rid(rid, &z);
307
+ fprintf(f, "%c%d %s %s\n", obj_type, rid, zMark, zUuid);
308
+ free(zMark);
309
+ free(zUuid);
310
+}
268311
269312
/*
270313
** If 'blobs' is non-null, it must point to a Bag of blob rids to be
271314
** written to disk. Blob rids are written as 'b<rid>'.
272315
** If 'vers' is non-null, it must point to a Bag of commit rids to be
@@ -275,32 +318,24 @@
275318
** This function does not fail, but may produce errors if a uuid cannot
276319
** be found for an rid in 'vers'.
277320
*/
278321
void export_marks(FILE* f, Bag *blobs, Bag *vers){
279322
int rid;
280
- if( blobs!=NULL ){
323
+
324
+ if( blobs!=NULL ) {
281325
rid = bag_first(blobs);
282
- if(rid!=0){
326
+ if( rid!=0 ){
283327
do{
284
- fprintf(f, "b%d\n", rid);
285
- }while((rid = bag_next(blobs, rid))!=0);
328
+ export_mark(f, rid, 'b');
329
+ }while( (rid = bag_next(blobs, rid))!=0 );
286330
}
287331
}
288332
if( vers!=NULL ){
289333
rid = bag_first(vers);
290334
if( rid!=0 ){
291335
do{
292
- char *zUuid = rid_to_uuid(rid);
293
- char *zMark;
294
- if(zUuid==NULL){
295
- fossil_trace("No uuid matching rid=%d when exporting marks\n", rid);
296
- continue;
297
- }
298
- zMark = mark_name_from_rid(rid);
299
- fprintf(f, "c%d %s %s\n", rid, zMark, zUuid);
300
- free(zMark);
301
- free(zUuid);
336
+ export_mark(f, rid, 'c');
302337
}while( (rid = bag_next(vers, rid))!=0 );
303338
}
304339
}
305340
}
306341
@@ -336,10 +371,11 @@
336371
*/
337372
void export_cmd(void){
338373
Stmt q, q2, q3;
339374
int i;
340375
Bag blobs, vers;
376
+ unsigned int unused_mark = 1;
341377
const char *markfile_in;
342378
const char *markfile_out;
343379
344380
bag_init(&blobs);
345381
bag_init(&vers);
@@ -362,11 +398,11 @@
362398
363399
f = fossil_fopen(markfile_in, "r");
364400
if( f==0 ){
365401
fossil_fatal("cannot open %s for reading", markfile_in);
366402
}
367
- if(import_marks(f, &blobs, &vers)<0){
403
+ if(import_marks(f, &blobs, &vers, &unused_mark)<0){
368404
fossil_fatal("error importing marks from file: %s\n", markfile_in);
369405
}
370406
db_prepare(&qb, "INSERT OR IGNORE INTO oldblob VALUES (:rid)");
371407
db_prepare(&qc, "INSERT OR IGNORE INTO oldcommit VALUES (:rid)");
372408
rid = bag_first(&blobs);
@@ -416,15 +452,18 @@
416452
while( db_step(&q)==SQLITE_ROW ){
417453
int rid = db_column_int(&q, 0);
418454
Blob content;
419455
420456
while( !bag_find(&blobs, rid) ){
457
+ char *zMark;
421458
content_get(rid, &content);
422459
db_bind_int(&q2, ":rid", rid);
423460
db_step(&q2);
424461
db_reset(&q2);
425
- printf("blob\nmark :%d\ndata %d\n", BLOBMARK(rid), blob_size(&content));
462
+ zMark = mark_name_from_rid(rid, &unused_mark);
463
+ printf("blob\nmark %s\ndata %d\n", zMark, blob_size(&content));
464
+ free(zMark);
426465
bag_insert(&blobs, rid);
427466
fwrite(blob_buffer(&content), 1, blob_size(&content), stdout);
428467
printf("\n");
429468
blob_reset(&content);
430469
@@ -470,11 +509,11 @@
470509
if( zBranch==0 ) zBranch = "trunk";
471510
zBr = mprintf("%s", zBranch);
472511
for(i=0; zBr[i]; i++){
473512
if( !fossil_isalnum(zBr[i]) ) zBr[i] = '_';
474513
}
475
- zMark = mark_name_from_rid(ckinId);
514
+ zMark = mark_name_from_rid(ckinId, &unused_mark);
476515
printf("commit refs/heads/%s\nmark %s\n", zBr, zMark);
477516
free(zMark);
478517
free(zBr);
479518
printf("committer");
480519
print_person(zUser);
@@ -487,21 +526,21 @@
487526
" AND pid IN (SELECT objid FROM event)",
488527
ckinId
489528
);
490529
if( db_step(&q3) == SQLITE_ROW ){
491530
int pid = db_column_int(&q3, 0);
492
- zMark = mark_name_from_rid(pid);
531
+ zMark = mark_name_from_rid(pid, &unused_mark);
493532
printf("from %s\n", zMark);
494533
free(zMark);
495534
db_prepare(&q4,
496535
"SELECT pid FROM plink"
497536
" WHERE cid=%d AND NOT isprim"
498537
" AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)"
499538
" ORDER BY pid",
500539
ckinId);
501540
while( db_step(&q4)==SQLITE_ROW ){
502
- zMark = mark_name_from_rid(db_column_int(&q4, 0));
541
+ zMark = mark_name_from_rid(db_column_int(&q4, 0), &unused_mark);
503542
printf("merge %s\n", zMark);
504543
free(zMark);
505544
}
506545
db_finalize(&q4);
507546
}else{
@@ -519,17 +558,19 @@
519558
int zNew = db_column_int(&q4,1);
520559
int mPerm = db_column_int(&q4,2);
521560
if( zNew==0)
522561
printf("D %s\n", zName);
523562
else if( bag_find(&blobs, zNew) ) {
563
+ zMark = mark_name_from_rid(zNew, &unused_mark);
524564
const char *zPerm;
525565
switch( mPerm ){
526566
case PERM_LNK: zPerm = "120000"; break;
527567
case PERM_EXE: zPerm = "100755"; break;
528568
default: zPerm = "100644"; break;
529569
}
530
- printf("M %s :%d %s\n", zPerm, BLOBMARK(zNew), zName);
570
+ printf("M %s %s %s\n", zPerm, zMark, zName);
571
+ free(zMark);
531572
}
532573
}
533574
db_finalize(&q4);
534575
db_finalize(&q3);
535576
printf("\n");
536577
--- src/export.c
+++ src/export.c
@@ -132,23 +132,28 @@
132
133 /*
134 ** create_mark()
135 ** Create a new (mark,rid,uuid) entry for the given rid in the 'xmark' table,
136 ** and return that information as a struct mark_t in *mark.
 
 
 
 
137 ** This function returns -1 in the case where 'rid' does not exist, otherwise
138 ** it returns 0.
139 ** mark->name is dynamically allocated and is owned by the caller upon return.
140 */
141 int create_mark(int rid, struct mark_t *mark){
142 char sid[13];
143 char *zUuid = rid_to_uuid(rid);
144 if(!zUuid){
145 fossil_trace("Undefined rid=%d\n", rid);
146 return -1;
147 }
148 mark->rid = rid;
149 sqlite3_snprintf(sizeof(sid), sid, ":%d", COMMITMARK(rid));
 
150 mark->name = fossil_strdup(sid);
151 sqlite3_snprintf(sizeof(mark->uuid), mark->uuid, "%s", zUuid);
152 free(zUuid);
153 insert_commit_xref(mark->rid, mark->name, mark->uuid);
154 return 0;
@@ -156,19 +161,22 @@
156
157 /*
158 ** mark_name_from_rid()
159 ** Find the mark associated with the given rid. Mark names always start
160 ** with ':', and are pulled from the 'xmark' temporary table.
161 ** This function returns NULL if the rid does not exist in the 'xmark' table.
162 ** Otherwise, it returns the name of the mark, which is dynamically allocated
163 ** and is owned by the caller of this function.
 
 
 
164 */
165 char * mark_name_from_rid(int rid){
166 char *zMark = db_text(0, "SELECT tname FROM xmark WHERE trid=%d", rid);
167 if(zMark==NULL){
168 struct mark_t mark;
169 if(create_mark(rid, &mark)==0){
170 zMark = mark.name;
171 }else{
172 return NULL;
173 }
174 }
@@ -185,16 +193,18 @@
185 ** database. Otherwise, 0 is returned.
186 ** mark->name is dynamically allocated, and owned by the caller.
187 */
188 int parse_mark(char *line, struct mark_t *mark){
189 char *cur_tok;
 
190 cur_tok = strtok(line, " \t");
191 if(!cur_tok||strlen(cur_tok)<2){
192 return -1;
193 }
194 mark->rid = atoi(&cur_tok[1]);
195 if(cur_tok[0]!='c'){
 
196 /* This is probably a blob mark */
197 mark->name = NULL;
198 return 0;
199 }
200
@@ -202,11 +212,18 @@
202 if(!cur_tok){
203 /* This mark was generated by an older version of Fossil and doesn't
204 ** include the mark name and uuid. create_mark() will name the new mark
205 ** exactly as it was when exported to git, so that we should have a
206 ** valid mapping from git sha1<->mark name<->fossil sha1. */
207 return create_mark(mark->rid, mark);
 
 
 
 
 
 
 
208 }else{
209 mark->name = fossil_strdup(cur_tok);
210 }
211
212 cur_tok = strtok(NULL, "\n");
@@ -233,18 +250,21 @@
233 /*
234 ** import_marks()
235 ** Import the marks specified in file 'f' into the 'xmark' table.
236 ** If 'blobs' is non-null, insert all blob marks into it.
237 ** If 'vers' is non-null, insert all commit marks into it.
 
 
 
238 ** Each line in the file must be at most 100 characters in length. This
239 ** seems like a reasonable maximum for a 40-character uuid, and 1-13
240 ** character rid.
241 ** The function returns -1 if any of the lines in file 'f' are malformed,
242 ** or the rid/uuid information doesn't match what is in the repository
243 ** database. Otherwise, 0 is returned.
244 */
245 int import_marks(FILE* f, Bag *blobs, Bag *vers){
246 char line[101];
247 while(fgets(line, sizeof(line), f)){
248 struct mark_t mark;
249 if(strlen(line)==100&&line[99]!='\n'){
250 /* line too long */
@@ -251,22 +271,45 @@
251 return -1;
252 }
253 if( parse_mark(line, &mark)<0 ){
254 return -1;
255 }else if( line[0]=='b' ){
256 /* Don't import blob marks into 'xmark' table--git doesn't use them,
257 ** so they need to be left free for git to reuse. */
258 if(blobs!=NULL){
259 bag_insert(blobs, mark.rid);
260 }
261 }else if( vers!=NULL ){
262 bag_insert(vers, mark.rid);
 
 
 
 
 
 
 
 
263 }
264 free(mark.name);
265 }
266 return 0;
267 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
268
269 /*
270 ** If 'blobs' is non-null, it must point to a Bag of blob rids to be
271 ** written to disk. Blob rids are written as 'b<rid>'.
272 ** If 'vers' is non-null, it must point to a Bag of commit rids to be
@@ -275,32 +318,24 @@
275 ** This function does not fail, but may produce errors if a uuid cannot
276 ** be found for an rid in 'vers'.
277 */
278 void export_marks(FILE* f, Bag *blobs, Bag *vers){
279 int rid;
280 if( blobs!=NULL ){
 
281 rid = bag_first(blobs);
282 if(rid!=0){
283 do{
284 fprintf(f, "b%d\n", rid);
285 }while((rid = bag_next(blobs, rid))!=0);
286 }
287 }
288 if( vers!=NULL ){
289 rid = bag_first(vers);
290 if( rid!=0 ){
291 do{
292 char *zUuid = rid_to_uuid(rid);
293 char *zMark;
294 if(zUuid==NULL){
295 fossil_trace("No uuid matching rid=%d when exporting marks\n", rid);
296 continue;
297 }
298 zMark = mark_name_from_rid(rid);
299 fprintf(f, "c%d %s %s\n", rid, zMark, zUuid);
300 free(zMark);
301 free(zUuid);
302 }while( (rid = bag_next(vers, rid))!=0 );
303 }
304 }
305 }
306
@@ -336,10 +371,11 @@
336 */
337 void export_cmd(void){
338 Stmt q, q2, q3;
339 int i;
340 Bag blobs, vers;
 
341 const char *markfile_in;
342 const char *markfile_out;
343
344 bag_init(&blobs);
345 bag_init(&vers);
@@ -362,11 +398,11 @@
362
363 f = fossil_fopen(markfile_in, "r");
364 if( f==0 ){
365 fossil_fatal("cannot open %s for reading", markfile_in);
366 }
367 if(import_marks(f, &blobs, &vers)<0){
368 fossil_fatal("error importing marks from file: %s\n", markfile_in);
369 }
370 db_prepare(&qb, "INSERT OR IGNORE INTO oldblob VALUES (:rid)");
371 db_prepare(&qc, "INSERT OR IGNORE INTO oldcommit VALUES (:rid)");
372 rid = bag_first(&blobs);
@@ -416,15 +452,18 @@
416 while( db_step(&q)==SQLITE_ROW ){
417 int rid = db_column_int(&q, 0);
418 Blob content;
419
420 while( !bag_find(&blobs, rid) ){
 
421 content_get(rid, &content);
422 db_bind_int(&q2, ":rid", rid);
423 db_step(&q2);
424 db_reset(&q2);
425 printf("blob\nmark :%d\ndata %d\n", BLOBMARK(rid), blob_size(&content));
 
 
426 bag_insert(&blobs, rid);
427 fwrite(blob_buffer(&content), 1, blob_size(&content), stdout);
428 printf("\n");
429 blob_reset(&content);
430
@@ -470,11 +509,11 @@
470 if( zBranch==0 ) zBranch = "trunk";
471 zBr = mprintf("%s", zBranch);
472 for(i=0; zBr[i]; i++){
473 if( !fossil_isalnum(zBr[i]) ) zBr[i] = '_';
474 }
475 zMark = mark_name_from_rid(ckinId);
476 printf("commit refs/heads/%s\nmark %s\n", zBr, zMark);
477 free(zMark);
478 free(zBr);
479 printf("committer");
480 print_person(zUser);
@@ -487,21 +526,21 @@
487 " AND pid IN (SELECT objid FROM event)",
488 ckinId
489 );
490 if( db_step(&q3) == SQLITE_ROW ){
491 int pid = db_column_int(&q3, 0);
492 zMark = mark_name_from_rid(pid);
493 printf("from %s\n", zMark);
494 free(zMark);
495 db_prepare(&q4,
496 "SELECT pid FROM plink"
497 " WHERE cid=%d AND NOT isprim"
498 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)"
499 " ORDER BY pid",
500 ckinId);
501 while( db_step(&q4)==SQLITE_ROW ){
502 zMark = mark_name_from_rid(db_column_int(&q4, 0));
503 printf("merge %s\n", zMark);
504 free(zMark);
505 }
506 db_finalize(&q4);
507 }else{
@@ -519,17 +558,19 @@
519 int zNew = db_column_int(&q4,1);
520 int mPerm = db_column_int(&q4,2);
521 if( zNew==0)
522 printf("D %s\n", zName);
523 else if( bag_find(&blobs, zNew) ) {
 
524 const char *zPerm;
525 switch( mPerm ){
526 case PERM_LNK: zPerm = "120000"; break;
527 case PERM_EXE: zPerm = "100755"; break;
528 default: zPerm = "100644"; break;
529 }
530 printf("M %s :%d %s\n", zPerm, BLOBMARK(zNew), zName);
 
531 }
532 }
533 db_finalize(&q4);
534 db_finalize(&q3);
535 printf("\n");
536
--- src/export.c
+++ src/export.c
@@ -132,23 +132,28 @@
132
133 /*
134 ** create_mark()
135 ** Create a new (mark,rid,uuid) entry for the given rid in the 'xmark' table,
136 ** and return that information as a struct mark_t in *mark.
137 ** *unused_mark is a value representing a mark that is free for use--that is,
138 ** it does not appear in the marks file, and has not been used during this
139 ** export run. Specifically, it is the supremum of the set of used marks
140 ** plus one.
141 ** This function returns -1 in the case where 'rid' does not exist, otherwise
142 ** it returns 0.
143 ** mark->name is dynamically allocated and is owned by the caller upon return.
144 */
145 int create_mark(int rid, struct mark_t *mark, unsigned int *unused_mark){
146 char sid[13];
147 char *zUuid = rid_to_uuid(rid);
148 if(!zUuid){
149 fossil_trace("Undefined rid=%d\n", rid);
150 return -1;
151 }
152 mark->rid = rid;
153 sqlite3_snprintf(sizeof(sid), sid, ":%d", *unused_mark);
154 *unused_mark += 1;
155 mark->name = fossil_strdup(sid);
156 sqlite3_snprintf(sizeof(mark->uuid), mark->uuid, "%s", zUuid);
157 free(zUuid);
158 insert_commit_xref(mark->rid, mark->name, mark->uuid);
159 return 0;
@@ -156,19 +161,22 @@
161
162 /*
163 ** mark_name_from_rid()
164 ** Find the mark associated with the given rid. Mark names always start
165 ** with ':', and are pulled from the 'xmark' temporary table.
166 ** If the given rid doesn't have a mark associated with it yet, one is
167 ** created with a value of *unused_mark.
168 ** *unused_mark functions exactly as in create_mark().
169 ** This function returns NULL if the rid does not have an associated UUID,
170 ** (i.e. is not valid). Otherwise, it returns the name of the mark, which is
171 ** dynamically allocated and is owned by the caller of this function.
172 */
173 char * mark_name_from_rid(int rid, unsigned int *unused_mark){
174 char *zMark = db_text(0, "SELECT tname FROM xmark WHERE trid=%d", rid);
175 if(zMark==NULL){
176 struct mark_t mark;
177 if(create_mark(rid, &mark, unused_mark)==0){
178 zMark = mark.name;
179 }else{
180 return NULL;
181 }
182 }
@@ -185,16 +193,18 @@
193 ** database. Otherwise, 0 is returned.
194 ** mark->name is dynamically allocated, and owned by the caller.
195 */
196 int parse_mark(char *line, struct mark_t *mark){
197 char *cur_tok;
198 char type_;
199 cur_tok = strtok(line, " \t");
200 if(!cur_tok||strlen(cur_tok)<2){
201 return -1;
202 }
203 mark->rid = atoi(&cur_tok[1]);
204 type_ = cur_tok[0];
205 if(type_!='c'&&type_!='b'){
206 /* This is probably a blob mark */
207 mark->name = NULL;
208 return 0;
209 }
210
@@ -202,11 +212,18 @@
212 if(!cur_tok){
213 /* This mark was generated by an older version of Fossil and doesn't
214 ** include the mark name and uuid. create_mark() will name the new mark
215 ** exactly as it was when exported to git, so that we should have a
216 ** valid mapping from git sha1<->mark name<->fossil sha1. */
217 unsigned int mid;
218 if( type_=='c' ){
219 mid = COMMITMARK(mark->rid);
220 }
221 else{
222 mid = BLOBMARK(mark->rid);
223 }
224 return create_mark(mark->rid, mark, &mid);
225 }else{
226 mark->name = fossil_strdup(cur_tok);
227 }
228
229 cur_tok = strtok(NULL, "\n");
@@ -233,18 +250,21 @@
250 /*
251 ** import_marks()
252 ** Import the marks specified in file 'f' into the 'xmark' table.
253 ** If 'blobs' is non-null, insert all blob marks into it.
254 ** If 'vers' is non-null, insert all commit marks into it.
255 ** If 'unused_marks' is non-null, upon return of this function, all values
256 ** x >= *unused_marks are free to use as marks, i.e. they do not clash with
257 ** any marks appearing in the marks file.
258 ** Each line in the file must be at most 100 characters in length. This
259 ** seems like a reasonable maximum for a 40-character uuid, and 1-13
260 ** character rid.
261 ** The function returns -1 if any of the lines in file 'f' are malformed,
262 ** or the rid/uuid information doesn't match what is in the repository
263 ** database. Otherwise, 0 is returned.
264 */
265 int import_marks(FILE* f, Bag *blobs, Bag *vers, unsigned int *unused_mark){
266 char line[101];
267 while(fgets(line, sizeof(line), f)){
268 struct mark_t mark;
269 if(strlen(line)==100&&line[99]!='\n'){
270 /* line too long */
@@ -251,22 +271,45 @@
271 return -1;
272 }
273 if( parse_mark(line, &mark)<0 ){
274 return -1;
275 }else if( line[0]=='b' ){
 
 
276 if(blobs!=NULL){
277 bag_insert(blobs, mark.rid);
278 }
279 }else{
280 if( vers!=NULL ){
281 bag_insert(vers, mark.rid);
282 }
283 }
284 if( unused_mark!=NULL ){
285 unsigned int mid = atoi(mark.name + 1);
286 if( mid>=*unused_mark ){
287 *unused_mark = mid + 1;
288 }
289 }
290 free(mark.name);
291 }
292 return 0;
293 }
294
295 void export_mark(FILE* f, int rid, char obj_type)
296 {
297 unsigned int z = 0;
298 char *zUuid = rid_to_uuid(rid);
299 char *zMark;
300 if(zUuid==NULL){
301 fossil_trace("No uuid matching rid=%d when exporting marks\n", rid);
302 return;
303 }
304 /* Since rid is already in the 'xmark' table, the value of z won't be
305 ** used, but pass in a valid pointer just to be safe. */
306 zMark = mark_name_from_rid(rid, &z);
307 fprintf(f, "%c%d %s %s\n", obj_type, rid, zMark, zUuid);
308 free(zMark);
309 free(zUuid);
310 }
311
312 /*
313 ** If 'blobs' is non-null, it must point to a Bag of blob rids to be
314 ** written to disk. Blob rids are written as 'b<rid>'.
315 ** If 'vers' is non-null, it must point to a Bag of commit rids to be
@@ -275,32 +318,24 @@
318 ** This function does not fail, but may produce errors if a uuid cannot
319 ** be found for an rid in 'vers'.
320 */
321 void export_marks(FILE* f, Bag *blobs, Bag *vers){
322 int rid;
323
324 if( blobs!=NULL ) {
325 rid = bag_first(blobs);
326 if( rid!=0 ){
327 do{
328 export_mark(f, rid, 'b');
329 }while( (rid = bag_next(blobs, rid))!=0 );
330 }
331 }
332 if( vers!=NULL ){
333 rid = bag_first(vers);
334 if( rid!=0 ){
335 do{
336 export_mark(f, rid, 'c');
 
 
 
 
 
 
 
 
 
337 }while( (rid = bag_next(vers, rid))!=0 );
338 }
339 }
340 }
341
@@ -336,10 +371,11 @@
371 */
372 void export_cmd(void){
373 Stmt q, q2, q3;
374 int i;
375 Bag blobs, vers;
376 unsigned int unused_mark = 1;
377 const char *markfile_in;
378 const char *markfile_out;
379
380 bag_init(&blobs);
381 bag_init(&vers);
@@ -362,11 +398,11 @@
398
399 f = fossil_fopen(markfile_in, "r");
400 if( f==0 ){
401 fossil_fatal("cannot open %s for reading", markfile_in);
402 }
403 if(import_marks(f, &blobs, &vers, &unused_mark)<0){
404 fossil_fatal("error importing marks from file: %s\n", markfile_in);
405 }
406 db_prepare(&qb, "INSERT OR IGNORE INTO oldblob VALUES (:rid)");
407 db_prepare(&qc, "INSERT OR IGNORE INTO oldcommit VALUES (:rid)");
408 rid = bag_first(&blobs);
@@ -416,15 +452,18 @@
452 while( db_step(&q)==SQLITE_ROW ){
453 int rid = db_column_int(&q, 0);
454 Blob content;
455
456 while( !bag_find(&blobs, rid) ){
457 char *zMark;
458 content_get(rid, &content);
459 db_bind_int(&q2, ":rid", rid);
460 db_step(&q2);
461 db_reset(&q2);
462 zMark = mark_name_from_rid(rid, &unused_mark);
463 printf("blob\nmark %s\ndata %d\n", zMark, blob_size(&content));
464 free(zMark);
465 bag_insert(&blobs, rid);
466 fwrite(blob_buffer(&content), 1, blob_size(&content), stdout);
467 printf("\n");
468 blob_reset(&content);
469
@@ -470,11 +509,11 @@
509 if( zBranch==0 ) zBranch = "trunk";
510 zBr = mprintf("%s", zBranch);
511 for(i=0; zBr[i]; i++){
512 if( !fossil_isalnum(zBr[i]) ) zBr[i] = '_';
513 }
514 zMark = mark_name_from_rid(ckinId, &unused_mark);
515 printf("commit refs/heads/%s\nmark %s\n", zBr, zMark);
516 free(zMark);
517 free(zBr);
518 printf("committer");
519 print_person(zUser);
@@ -487,21 +526,21 @@
526 " AND pid IN (SELECT objid FROM event)",
527 ckinId
528 );
529 if( db_step(&q3) == SQLITE_ROW ){
530 int pid = db_column_int(&q3, 0);
531 zMark = mark_name_from_rid(pid, &unused_mark);
532 printf("from %s\n", zMark);
533 free(zMark);
534 db_prepare(&q4,
535 "SELECT pid FROM plink"
536 " WHERE cid=%d AND NOT isprim"
537 " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)"
538 " ORDER BY pid",
539 ckinId);
540 while( db_step(&q4)==SQLITE_ROW ){
541 zMark = mark_name_from_rid(db_column_int(&q4, 0), &unused_mark);
542 printf("merge %s\n", zMark);
543 free(zMark);
544 }
545 db_finalize(&q4);
546 }else{
@@ -519,17 +558,19 @@
558 int zNew = db_column_int(&q4,1);
559 int mPerm = db_column_int(&q4,2);
560 if( zNew==0)
561 printf("D %s\n", zName);
562 else if( bag_find(&blobs, zNew) ) {
563 zMark = mark_name_from_rid(zNew, &unused_mark);
564 const char *zPerm;
565 switch( mPerm ){
566 case PERM_LNK: zPerm = "120000"; break;
567 case PERM_EXE: zPerm = "100755"; break;
568 default: zPerm = "100644"; break;
569 }
570 printf("M %s %s %s\n", zPerm, zMark, zName);
571 free(zMark);
572 }
573 }
574 db_finalize(&q4);
575 db_finalize(&q3);
576 printf("\n");
577
+4 -4
--- src/import.c
+++ src/import.c
@@ -1770,11 +1770,11 @@
17701770
if( markfile_in ){
17711771
FILE *f = fossil_fopen(markfile_in, "r");
17721772
if( !f ){
17731773
fossil_fatal("cannot open %s for reading\n", markfile_in);
17741774
}
1775
- if(import_marks(f, &blobs, NULL)<0){
1775
+ if(import_marks(f, &blobs, NULL, NULL)<0){
17761776
fossil_fatal("error importing marks from file: %s\n", markfile_in);
17771777
}
17781778
fclose(f);
17791779
}
17801780
@@ -1795,13 +1795,13 @@
17951795
db_prepare(&q_marks, "SELECT DISTINCT trid FROM xmark");
17961796
while( db_step(&q_marks)==SQLITE_ROW ){
17971797
rid = db_column_int(&q_marks, 0);
17981798
if( db_int(0, "SELECT count(objid) FROM event"
17991799
" WHERE objid=%d AND type='ci'", rid)==0 ){
1800
- if( bag_find(&blobs, rid)==0 ){
1801
- bag_insert(&blobs, rid);
1802
- }
1800
+ /* Blob marks exported by git aren't saved between runs, so they need
1801
+ ** to be left free for git to re-use in the future.
1802
+ */
18031803
}else{
18041804
bag_insert(&vers, rid);
18051805
}
18061806
}
18071807
db_finalize(&q_marks);
18081808
--- src/import.c
+++ src/import.c
@@ -1770,11 +1770,11 @@
1770 if( markfile_in ){
1771 FILE *f = fossil_fopen(markfile_in, "r");
1772 if( !f ){
1773 fossil_fatal("cannot open %s for reading\n", markfile_in);
1774 }
1775 if(import_marks(f, &blobs, NULL)<0){
1776 fossil_fatal("error importing marks from file: %s\n", markfile_in);
1777 }
1778 fclose(f);
1779 }
1780
@@ -1795,13 +1795,13 @@
1795 db_prepare(&q_marks, "SELECT DISTINCT trid FROM xmark");
1796 while( db_step(&q_marks)==SQLITE_ROW ){
1797 rid = db_column_int(&q_marks, 0);
1798 if( db_int(0, "SELECT count(objid) FROM event"
1799 " WHERE objid=%d AND type='ci'", rid)==0 ){
1800 if( bag_find(&blobs, rid)==0 ){
1801 bag_insert(&blobs, rid);
1802 }
1803 }else{
1804 bag_insert(&vers, rid);
1805 }
1806 }
1807 db_finalize(&q_marks);
1808
--- src/import.c
+++ src/import.c
@@ -1770,11 +1770,11 @@
1770 if( markfile_in ){
1771 FILE *f = fossil_fopen(markfile_in, "r");
1772 if( !f ){
1773 fossil_fatal("cannot open %s for reading\n", markfile_in);
1774 }
1775 if(import_marks(f, &blobs, NULL, NULL)<0){
1776 fossil_fatal("error importing marks from file: %s\n", markfile_in);
1777 }
1778 fclose(f);
1779 }
1780
@@ -1795,13 +1795,13 @@
1795 db_prepare(&q_marks, "SELECT DISTINCT trid FROM xmark");
1796 while( db_step(&q_marks)==SQLITE_ROW ){
1797 rid = db_column_int(&q_marks, 0);
1798 if( db_int(0, "SELECT count(objid) FROM event"
1799 " WHERE objid=%d AND type='ci'", rid)==0 ){
1800 /* Blob marks exported by git aren't saved between runs, so they need
1801 ** to be left free for git to re-use in the future.
1802 */
1803 }else{
1804 bag_insert(&vers, rid);
1805 }
1806 }
1807 db_finalize(&q_marks);
1808

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button