| | @@ -132,23 +132,28 @@ |
| 132 | 132 | |
| 133 | 133 | /* |
| 134 | 134 | ** create_mark() |
| 135 | 135 | ** Create a new (mark,rid,uuid) entry for the given rid in the 'xmark' table, |
| 136 | 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. |
| 137 | 141 | ** This function returns -1 in the case where 'rid' does not exist, otherwise |
| 138 | 142 | ** it returns 0. |
| 139 | 143 | ** mark->name is dynamically allocated and is owned by the caller upon return. |
| 140 | 144 | */ |
| 141 | | -int create_mark(int rid, struct mark_t *mark){ |
| 145 | +int create_mark(int rid, struct mark_t *mark, unsigned int *unused_mark){ |
| 142 | 146 | char sid[13]; |
| 143 | 147 | char *zUuid = rid_to_uuid(rid); |
| 144 | | - if(!zUuid){ |
| 148 | + if( !zUuid ){ |
| 145 | 149 | fossil_trace("Undefined rid=%d\n", rid); |
| 146 | 150 | return -1; |
| 147 | 151 | } |
| 148 | 152 | 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; |
| 150 | 155 | mark->name = fossil_strdup(sid); |
| 151 | 156 | sqlite3_snprintf(sizeof(mark->uuid), mark->uuid, "%s", zUuid); |
| 152 | 157 | free(zUuid); |
| 153 | 158 | insert_commit_xref(mark->rid, mark->name, mark->uuid); |
| 154 | 159 | return 0; |
| | @@ -156,19 +161,22 @@ |
| 156 | 161 | |
| 157 | 162 | /* |
| 158 | 163 | ** mark_name_from_rid() |
| 159 | 164 | ** Find the mark associated with the given rid. Mark names always start |
| 160 | 165 | ** 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. |
| 164 | 172 | */ |
| 165 | | -char * mark_name_from_rid(int rid){ |
| 173 | +char * mark_name_from_rid(int rid, unsigned int *unused_mark){ |
| 166 | 174 | char *zMark = db_text(0, "SELECT tname FROM xmark WHERE trid=%d", rid); |
| 167 | | - if(zMark==NULL){ |
| 175 | + if( zMark==NULL ){ |
| 168 | 176 | struct mark_t mark; |
| 169 | | - if(create_mark(rid, &mark)==0){ |
| 177 | + if( create_mark(rid, &mark, unused_mark)==0 ){ |
| 170 | 178 | zMark = mark.name; |
| 171 | 179 | }else{ |
| 172 | 180 | return NULL; |
| 173 | 181 | } |
| 174 | 182 | } |
| | @@ -185,43 +193,52 @@ |
| 185 | 193 | ** database. Otherwise, 0 is returned. |
| 186 | 194 | ** mark->name is dynamically allocated, and owned by the caller. |
| 187 | 195 | */ |
| 188 | 196 | int parse_mark(char *line, struct mark_t *mark){ |
| 189 | 197 | char *cur_tok; |
| 198 | + char type_; |
| 190 | 199 | cur_tok = strtok(line, " \t"); |
| 191 | | - if(!cur_tok||strlen(cur_tok)<2){ |
| 200 | + if( !cur_tok || strlen(cur_tok)<2 ){ |
| 192 | 201 | return -1; |
| 193 | 202 | } |
| 194 | 203 | mark->rid = atoi(&cur_tok[1]); |
| 195 | | - if(cur_tok[0]!='c'){ |
| 204 | + type_ = cur_tok[0]; |
| 205 | + if( type_!='c' && type_!='b' ){ |
| 196 | 206 | /* This is probably a blob mark */ |
| 197 | 207 | mark->name = NULL; |
| 198 | 208 | return 0; |
| 199 | 209 | } |
| 200 | 210 | |
| 201 | 211 | cur_tok = strtok(NULL, " \t"); |
| 202 | | - if(!cur_tok){ |
| 212 | + if( !cur_tok ){ |
| 203 | 213 | /* This mark was generated by an older version of Fossil and doesn't |
| 204 | 214 | ** include the mark name and uuid. create_mark() will name the new mark |
| 205 | 215 | ** exactly as it was when exported to git, so that we should have a |
| 206 | 216 | ** 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); |
| 208 | 225 | }else{ |
| 209 | 226 | mark->name = fossil_strdup(cur_tok); |
| 210 | 227 | } |
| 211 | 228 | |
| 212 | 229 | cur_tok = strtok(NULL, "\n"); |
| 213 | | - if(!cur_tok||strlen(cur_tok)!=40){ |
| 230 | + if( !cur_tok || strlen(cur_tok)!=40 ){ |
| 214 | 231 | free(mark->name); |
| 215 | 232 | fossil_trace("Invalid SHA-1 in marks file: %s\n", cur_tok); |
| 216 | 233 | return -1; |
| 217 | 234 | }else{ |
| 218 | 235 | sqlite3_snprintf(sizeof(mark->uuid), mark->uuid, "%s", cur_tok); |
| 219 | 236 | } |
| 220 | 237 | |
| 221 | 238 | /* make sure that rid corresponds to UUID */ |
| 222 | | - if(fast_uuid_to_rid(mark->uuid)!=mark->rid){ |
| 239 | + if( fast_uuid_to_rid(mark->uuid)!=mark->rid ){ |
| 223 | 240 | free(mark->name); |
| 224 | 241 | fossil_trace("Non-existent SHA-1 in marks file: %s\n", mark->uuid); |
| 225 | 242 | return -1; |
| 226 | 243 | } |
| 227 | 244 | |
| | @@ -233,40 +250,66 @@ |
| 233 | 250 | /* |
| 234 | 251 | ** import_marks() |
| 235 | 252 | ** Import the marks specified in file 'f' into the 'xmark' table. |
| 236 | 253 | ** If 'blobs' is non-null, insert all blob marks into it. |
| 237 | 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. |
| 238 | 258 | ** Each line in the file must be at most 100 characters in length. This |
| 239 | 259 | ** seems like a reasonable maximum for a 40-character uuid, and 1-13 |
| 240 | 260 | ** character rid. |
| 241 | 261 | ** The function returns -1 if any of the lines in file 'f' are malformed, |
| 242 | 262 | ** or the rid/uuid information doesn't match what is in the repository |
| 243 | 263 | ** database. Otherwise, 0 is returned. |
| 244 | 264 | */ |
| 245 | | -int import_marks(FILE* f, Bag *blobs, Bag *vers){ |
| 265 | +int import_marks(FILE* f, Bag *blobs, Bag *vers, unsigned int *unused_mark){ |
| 246 | 266 | char line[101]; |
| 247 | 267 | while(fgets(line, sizeof(line), f)){ |
| 248 | 268 | struct mark_t mark; |
| 249 | | - if(strlen(line)==100&&line[99]!='\n'){ |
| 269 | + if( strlen(line)==100 && line[99]!='\n' ){ |
| 250 | 270 | /* line too long */ |
| 251 | 271 | return -1; |
| 252 | 272 | } |
| 253 | 273 | if( parse_mark(line, &mark)<0 ){ |
| 254 | 274 | return -1; |
| 255 | 275 | }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){ |
| 276 | + if( blobs!=NULL ){ |
| 259 | 277 | bag_insert(blobs, mark.rid); |
| 260 | 278 | } |
| 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 | + } |
| 263 | 289 | } |
| 264 | 290 | free(mark.name); |
| 265 | 291 | } |
| 266 | 292 | return 0; |
| 267 | 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 | +} |
| 268 | 311 | |
| 269 | 312 | /* |
| 270 | 313 | ** If 'blobs' is non-null, it must point to a Bag of blob rids to be |
| 271 | 314 | ** written to disk. Blob rids are written as 'b<rid>'. |
| 272 | 315 | ** If 'vers' is non-null, it must point to a Bag of commit rids to be |
| | @@ -275,32 +318,24 @@ |
| 275 | 318 | ** This function does not fail, but may produce errors if a uuid cannot |
| 276 | 319 | ** be found for an rid in 'vers'. |
| 277 | 320 | */ |
| 278 | 321 | void export_marks(FILE* f, Bag *blobs, Bag *vers){ |
| 279 | 322 | int rid; |
| 323 | + |
| 280 | 324 | if( blobs!=NULL ){ |
| 281 | 325 | rid = bag_first(blobs); |
| 282 | | - if(rid!=0){ |
| 326 | + if( rid!=0 ){ |
| 283 | 327 | 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 ); |
| 286 | 330 | } |
| 287 | 331 | } |
| 288 | 332 | if( vers!=NULL ){ |
| 289 | 333 | rid = bag_first(vers); |
| 290 | 334 | if( rid!=0 ){ |
| 291 | 335 | 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'); |
| 302 | 337 | }while( (rid = bag_next(vers, rid))!=0 ); |
| 303 | 338 | } |
| 304 | 339 | } |
| 305 | 340 | } |
| 306 | 341 | |
| | @@ -336,10 +371,11 @@ |
| 336 | 371 | */ |
| 337 | 372 | void export_cmd(void){ |
| 338 | 373 | Stmt q, q2, q3; |
| 339 | 374 | int i; |
| 340 | 375 | Bag blobs, vers; |
| 376 | + unsigned int unused_mark = 1; |
| 341 | 377 | const char *markfile_in; |
| 342 | 378 | const char *markfile_out; |
| 343 | 379 | |
| 344 | 380 | bag_init(&blobs); |
| 345 | 381 | bag_init(&vers); |
| | @@ -362,25 +398,25 @@ |
| 362 | 398 | |
| 363 | 399 | f = fossil_fopen(markfile_in, "r"); |
| 364 | 400 | if( f==0 ){ |
| 365 | 401 | fossil_fatal("cannot open %s for reading", markfile_in); |
| 366 | 402 | } |
| 367 | | - if(import_marks(f, &blobs, &vers)<0){ |
| 403 | + if( import_marks(f, &blobs, &vers, &unused_mark)<0 ){ |
| 368 | 404 | fossil_fatal("error importing marks from file: %s", markfile_in); |
| 369 | 405 | } |
| 370 | 406 | db_prepare(&qb, "INSERT OR IGNORE INTO oldblob VALUES (:rid)"); |
| 371 | 407 | db_prepare(&qc, "INSERT OR IGNORE INTO oldcommit VALUES (:rid)"); |
| 372 | 408 | rid = bag_first(&blobs); |
| 373 | | - if(rid!=0){ |
| 409 | + if( rid!=0 ){ |
| 374 | 410 | do{ |
| 375 | 411 | db_bind_int(&qb, ":rid", rid); |
| 376 | 412 | db_step(&qb); |
| 377 | 413 | db_reset(&qb); |
| 378 | 414 | }while((rid = bag_next(&blobs, rid))!=0); |
| 379 | 415 | } |
| 380 | 416 | rid = bag_first(&vers); |
| 381 | | - if(rid!=0){ |
| 417 | + if( rid!=0 ){ |
| 382 | 418 | do{ |
| 383 | 419 | db_bind_int(&qc, ":rid", rid); |
| 384 | 420 | db_step(&qc); |
| 385 | 421 | db_reset(&qc); |
| 386 | 422 | }while((rid = bag_next(&vers, rid))!=0); |
| | @@ -416,15 +452,18 @@ |
| 416 | 452 | while( db_step(&q)==SQLITE_ROW ){ |
| 417 | 453 | int rid = db_column_int(&q, 0); |
| 418 | 454 | Blob content; |
| 419 | 455 | |
| 420 | 456 | while( !bag_find(&blobs, rid) ){ |
| 457 | + char *zMark; |
| 421 | 458 | content_get(rid, &content); |
| 422 | 459 | db_bind_int(&q2, ":rid", rid); |
| 423 | 460 | db_step(&q2); |
| 424 | 461 | 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); |
| 426 | 465 | bag_insert(&blobs, rid); |
| 427 | 466 | fwrite(blob_buffer(&content), 1, blob_size(&content), stdout); |
| 428 | 467 | printf("\n"); |
| 429 | 468 | blob_reset(&content); |
| 430 | 469 | |
| | @@ -470,11 +509,11 @@ |
| 470 | 509 | if( zBranch==0 ) zBranch = "trunk"; |
| 471 | 510 | zBr = mprintf("%s", zBranch); |
| 472 | 511 | for(i=0; zBr[i]; i++){ |
| 473 | 512 | if( !fossil_isalnum(zBr[i]) ) zBr[i] = '_'; |
| 474 | 513 | } |
| 475 | | - zMark = mark_name_from_rid(ckinId); |
| 514 | + zMark = mark_name_from_rid(ckinId, &unused_mark); |
| 476 | 515 | printf("commit refs/heads/%s\nmark %s\n", zBr, zMark); |
| 477 | 516 | free(zMark); |
| 478 | 517 | free(zBr); |
| 479 | 518 | printf("committer"); |
| 480 | 519 | print_person(zUser); |
| | @@ -487,21 +526,21 @@ |
| 487 | 526 | " AND pid IN (SELECT objid FROM event)", |
| 488 | 527 | ckinId |
| 489 | 528 | ); |
| 490 | 529 | if( db_step(&q3) == SQLITE_ROW ){ |
| 491 | 530 | int pid = db_column_int(&q3, 0); |
| 492 | | - zMark = mark_name_from_rid(pid); |
| 531 | + zMark = mark_name_from_rid(pid, &unused_mark); |
| 493 | 532 | printf("from %s\n", zMark); |
| 494 | 533 | free(zMark); |
| 495 | 534 | db_prepare(&q4, |
| 496 | 535 | "SELECT pid FROM plink" |
| 497 | 536 | " WHERE cid=%d AND NOT isprim" |
| 498 | 537 | " AND NOT EXISTS(SELECT 1 FROM phantom WHERE rid=pid)" |
| 499 | 538 | " ORDER BY pid", |
| 500 | 539 | ckinId); |
| 501 | 540 | 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); |
| 503 | 542 | printf("merge %s\n", zMark); |
| 504 | 543 | free(zMark); |
| 505 | 544 | } |
| 506 | 545 | db_finalize(&q4); |
| 507 | 546 | }else{ |
| | @@ -516,20 +555,22 @@ |
| 516 | 555 | ); |
| 517 | 556 | while( db_step(&q4)==SQLITE_ROW ){ |
| 518 | 557 | const char *zName = db_column_text(&q4,0); |
| 519 | 558 | int zNew = db_column_int(&q4,1); |
| 520 | 559 | int mPerm = db_column_int(&q4,2); |
| 521 | | - if( zNew==0) |
| 560 | + if( zNew==0 ){ |
| 522 | 561 | printf("D %s\n", zName); |
| 523 | | - else if( bag_find(&blobs, zNew) ) { |
| 562 | + }else if( bag_find(&blobs, zNew) ){ |
| 563 | + zMark = mark_name_from_rid(zNew, &unused_mark); |
| 524 | 564 | const char *zPerm; |
| 525 | 565 | switch( mPerm ){ |
| 526 | 566 | case PERM_LNK: zPerm = "120000"; break; |
| 527 | 567 | case PERM_EXE: zPerm = "100755"; break; |
| 528 | 568 | default: zPerm = "100644"; break; |
| 529 | 569 | } |
| 530 | | - printf("M %s :%d %s\n", zPerm, BLOBMARK(zNew), zName); |
| 570 | + printf("M %s %s %s\n", zPerm, zMark, zName); |
| 571 | + free(zMark); |
| 531 | 572 | } |
| 532 | 573 | } |
| 533 | 574 | db_finalize(&q4); |
| 534 | 575 | db_finalize(&q3); |
| 535 | 576 | printf("\n"); |
| | @@ -547,20 +588,22 @@ |
| 547 | 588 | ); |
| 548 | 589 | while( db_step(&q)==SQLITE_ROW ){ |
| 549 | 590 | const char *zTagname = db_column_text(&q, 0); |
| 550 | 591 | char *zEncoded = 0; |
| 551 | 592 | int rid = db_column_int(&q, 1); |
| 593 | + char *zMark = mark_name_from_rid(rid, &unused_mark); |
| 552 | 594 | const char *zSecSince1970 = db_column_text(&q, 2); |
| 553 | 595 | int i; |
| 554 | 596 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 555 | 597 | zTagname += 4; |
| 556 | 598 | zEncoded = mprintf("%s", zTagname); |
| 557 | 599 | for(i=0; zEncoded[i]; i++){ |
| 558 | 600 | if( !fossil_isalnum(zEncoded[i]) ) zEncoded[i] = '_'; |
| 559 | 601 | } |
| 560 | 602 | printf("tag %s\n", zEncoded); |
| 561 | | - printf("from :%d\n", COMMITMARK(rid)); |
| 603 | + printf("from %s\n", zMark); |
| 604 | + free(zMark); |
| 562 | 605 | printf("tagger <tagger> %s +0000\n", zSecSince1970); |
| 563 | 606 | printf("data 0\n"); |
| 564 | 607 | fossil_free(zEncoded); |
| 565 | 608 | } |
| 566 | 609 | db_finalize(&q); |
| | @@ -570,12 +613,12 @@ |
| 570 | 613 | f = fossil_fopen(markfile_out, "w"); |
| 571 | 614 | if( f == 0 ){ |
| 572 | 615 | fossil_fatal("cannot open %s for writing", markfile_out); |
| 573 | 616 | } |
| 574 | 617 | export_marks(f, &blobs, &vers); |
| 575 | | - if( ferror(f)!=0 || fclose(f)!=0 ) { |
| 618 | + if( ferror(f)!=0 || fclose(f)!=0 ){ |
| 576 | 619 | fossil_fatal("error while writing %s", markfile_out); |
| 577 | 620 | } |
| 578 | 621 | } |
| 579 | 622 | bag_clear(&blobs); |
| 580 | 623 | bag_clear(&vers); |
| 581 | 624 | } |
| 582 | 625 | |