Fossil SCM
merge from trunk
Commit
287dd50e7b85aca157ee72aed11c1d8039881dc8
Parent
32e85b6638a4cd6…
1 file changed
+97
-44
+97
-44
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -72,16 +72,20 @@ | ||
| 72 | 72 | @ content TEXT |
| 73 | 73 | @ ); |
| 74 | 74 | ; |
| 75 | 75 | |
| 76 | 76 | /* |
| 77 | -** Variables used for progress information | |
| 77 | +** Variables used to store state information about an on-going "rebuild" | |
| 78 | +** or "deconstruct". | |
| 78 | 79 | */ |
| 79 | 80 | static int totalSize; /* Total number of artifacts to process */ |
| 80 | 81 | static int processCnt; /* Number processed so far */ |
| 81 | 82 | static int ttyOutput; /* Do progress output */ |
| 82 | 83 | static Bag bagDone; /* Bag of records rebuilt */ |
| 84 | + | |
| 85 | +static char *zFNameFormat; /* Format string for filenames on deconstruct */ | |
| 86 | +static int prefixLength; /* Length of directory prefix for deconstruct */ | |
| 83 | 87 | |
| 84 | 88 | /* |
| 85 | 89 | ** Called after each artifact is processed |
| 86 | 90 | */ |
| 87 | 91 | static void rebuild_step_done(rid){ |
| @@ -98,10 +102,21 @@ | ||
| 98 | 102 | |
| 99 | 103 | /* |
| 100 | 104 | ** Rebuild cross-referencing information for the artifact |
| 101 | 105 | ** rid with content pBase and all of its descendants. This |
| 102 | 106 | ** routine clears the content buffer before returning. |
| 107 | +** | |
| 108 | +** If the zFNameFormat variable is set, then this routine is | |
| 109 | +** called to run "fossil deconstruct" instead of the usual | |
| 110 | +** "fossil rebuild". In that case, instead of rebuilding the | |
| 111 | +** cross-referencing information, write the file content out | |
| 112 | +** to the approriate directory. | |
| 113 | +** | |
| 114 | +** In both cases, this routine automatically recurses to process | |
| 115 | +** other artifacts that are deltas off of the current artifact. | |
| 116 | +** This is the most efficient way to extract all of the original | |
| 117 | +** artifact content from the Fossil repository. | |
| 103 | 118 | */ |
| 104 | 119 | static void rebuild_step(int rid, int size, Blob *pBase){ |
| 105 | 120 | static Stmt q1; |
| 106 | 121 | Bag children; |
| 107 | 122 | Blob copy; |
| @@ -133,12 +148,23 @@ | ||
| 133 | 148 | pUse = pBase; |
| 134 | 149 | }else{ |
| 135 | 150 | blob_copy(©, pBase); |
| 136 | 151 | pUse = © |
| 137 | 152 | } |
| 138 | - manifest_crosslink(rid, pUse); | |
| 153 | + if( zFNameFormat==0 ){ | |
| 154 | + /* We are doing "fossil rebuild" */ | |
| 155 | + manifest_crosslink(rid, pUse); | |
| 156 | + }else{ | |
| 157 | + /* We are doing "fossil deconstruct" */ | |
| 158 | + char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); | |
| 159 | + char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); | |
| 160 | + blob_write_to_file(pUse,zFile); | |
| 161 | + free(zFile); | |
| 162 | + free(zUuid); | |
| 163 | + } | |
| 139 | 164 | blob_reset(pUse); |
| 165 | + rebuild_step_done(rid); | |
| 140 | 166 | |
| 141 | 167 | /* Call all children recursively */ |
| 142 | 168 | for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ |
| 143 | 169 | Stmt q2; |
| 144 | 170 | int sz; |
| @@ -161,11 +187,10 @@ | ||
| 161 | 187 | db_finalize(&q2); |
| 162 | 188 | blob_reset(pUse); |
| 163 | 189 | } |
| 164 | 190 | } |
| 165 | 191 | bag_clear(&children); |
| 166 | - rebuild_step_done(rid); | |
| 167 | 192 | } |
| 168 | 193 | |
| 169 | 194 | /* |
| 170 | 195 | ** Check to see if the "sym-trunk" tag exists. If not, create it |
| 171 | 196 | ** and attach it to the very first check-in. |
| @@ -402,18 +427,19 @@ | ||
| 402 | 427 | rebuild_db(0, 1); |
| 403 | 428 | db_end_transaction(0); |
| 404 | 429 | } |
| 405 | 430 | } |
| 406 | 431 | |
| 407 | -/* | |
| 408 | -** help function for reconstruct for recursiv directory | |
| 409 | -** reading. | |
| 432 | +/* | |
| 433 | +** Recursively read all files from the directory zPath and install | |
| 434 | +** every file read as a new artifact in the repository. | |
| 410 | 435 | */ |
| 411 | -void recon_read_dir(char * zPath){ | |
| 436 | +void recon_read_dir(char *zPath){ | |
| 412 | 437 | DIR *d; |
| 413 | 438 | struct dirent *pEntry; |
| 414 | 439 | Blob aContent; /* content of the just read artifact */ |
| 440 | + static int nFileRead = 0; | |
| 415 | 441 | |
| 416 | 442 | d = opendir(zPath); |
| 417 | 443 | if( d ){ |
| 418 | 444 | while( (pEntry=readdir(d))!=0 ){ |
| 419 | 445 | Blob path; |
| @@ -434,10 +460,12 @@ | ||
| 434 | 460 | } |
| 435 | 461 | content_put(&aContent, 0, 0); |
| 436 | 462 | blob_reset(&path); |
| 437 | 463 | blob_reset(&aContent); |
| 438 | 464 | free(zSubpath); |
| 465 | + printf("\r%d", ++nFileRead); | |
| 466 | + fflush(stdout); | |
| 439 | 467 | } |
| 440 | 468 | }else { |
| 441 | 469 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| 442 | 470 | errno, g.argv[3]); |
| 443 | 471 | } |
| @@ -467,14 +495,22 @@ | ||
| 467 | 495 | db_open_repository(g.argv[2]); |
| 468 | 496 | db_open_config(0); |
| 469 | 497 | db_begin_transaction(); |
| 470 | 498 | db_initial_setup(0, 0, 1); |
| 471 | 499 | |
| 500 | + printf("Reading files from directory \"%s\"...\n", g.argv[3]); | |
| 472 | 501 | recon_read_dir(g.argv[3]); |
| 502 | + printf("\nBuilding the Fossil repository...\n"); | |
| 473 | 503 | |
| 474 | 504 | rebuild_db(0, 1); |
| 475 | 505 | |
| 506 | + /* Skip the verify_before_commit() step on a reconstruct. Most artifacts | |
| 507 | + ** will have been changed and verification therefore takes a really, really | |
| 508 | + ** long time. | |
| 509 | + */ | |
| 510 | + verify_cancel(); | |
| 511 | + | |
| 476 | 512 | db_end_transaction(0); |
| 477 | 513 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 478 | 514 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 479 | 515 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 480 | 516 | printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); |
| @@ -493,13 +529,11 @@ | ||
| 493 | 529 | ** prefix can be set to 0,1,..,9 characters. |
| 494 | 530 | */ |
| 495 | 531 | void deconstruct_cmd(void){ |
| 496 | 532 | const char *zDestDir; |
| 497 | 533 | const char *zPrefixOpt; |
| 498 | - int prefixLength = 0; | |
| 499 | - char *zAFileOutFormat; | |
| 500 | - Stmt q; | |
| 534 | + Stmt s; | |
| 501 | 535 | |
| 502 | 536 | /* check number of arguments */ |
| 503 | 537 | if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){ |
| 504 | 538 | usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION"); |
| 505 | 539 | } |
| @@ -514,52 +548,71 @@ | ||
| 514 | 548 | prefixLength = 2; |
| 515 | 549 | }else{ |
| 516 | 550 | if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){ |
| 517 | 551 | prefixLength = (int)(*zPrefixOpt-'0'); |
| 518 | 552 | }else{ |
| 519 | - fossil_panic("N(%s) is not a a valid prefix length!",zPrefixOpt); | |
| 553 | + fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); | |
| 520 | 554 | } |
| 521 | 555 | } |
| 522 | - if( prefixLength ){ | |
| 523 | - zAFileOutFormat = mprintf("%%s/%%.%ds/%%s",prefixLength); | |
| 524 | - }else{ | |
| 525 | - zAFileOutFormat = mprintf("%%s/%%s"); | |
| 526 | - } | |
| 527 | 556 | #ifndef _WIN32 |
| 528 | 557 | if( access(zDestDir, W_OK) ){ |
| 529 | - fossil_panic("DESTINATION(%s) is not writeable!",zDestDir); | |
| 558 | + fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); | |
| 530 | 559 | } |
| 531 | 560 | #else |
| 532 | 561 | /* write access on windows is not checked, errors will be |
| 533 | 562 | ** dected on blob_write_to_file |
| 534 | 563 | */ |
| 535 | 564 | #endif |
| 565 | + if( prefixLength ){ | |
| 566 | + zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); | |
| 567 | + }else{ | |
| 568 | + zFNameFormat = mprintf("%s/%%s",zDestDir); | |
| 569 | + } | |
| 536 | 570 | /* open repository and open query for all artifacts */ |
| 537 | 571 | db_find_and_open_repository(1); |
| 538 | - db_prepare(&q, "SELECT rid,uuid FROM blob"); | |
| 539 | - /* loop over artifacts and write them to single files */ | |
| 540 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 541 | - int aRid; | |
| 542 | - const char *zAUuid; | |
| 543 | - char *zAFName; | |
| 544 | - Blob zACont; | |
| 545 | - | |
| 546 | - /* get data from query */ | |
| 547 | - aRid = db_column_int (&q, 0); | |
| 548 | - zAUuid = db_column_text(&q, 1); | |
| 549 | - | |
| 550 | - /* construct output filename */ | |
| 551 | - zAFName = mprintf(zAFileOutFormat, zDestDir, zAUuid, zAUuid + prefixLength); | |
| 552 | - | |
| 553 | - /* read artifact contents from db and write to file */ | |
| 554 | - content_get(aRid,&zACont); | |
| 555 | - blob_write_to_file(&zACont,zAFName); | |
| 556 | - blob_reset(&zACont); | |
| 557 | - | |
| 558 | - /* free artifact filename string */ | |
| 559 | - free(zAFName); | |
| 560 | - } | |
| 561 | - /* close query statement */ | |
| 562 | - db_finalize(&q); | |
| 563 | - /* free filename format string */ | |
| 564 | - free(zAFileOutFormat); | |
| 572 | + bag_init(&bagDone); | |
| 573 | + ttyOutput = 1; | |
| 574 | + processCnt = 0; | |
| 575 | + if (!g.fQuiet) { | |
| 576 | + printf("0 (0%%)...\r"); | |
| 577 | + fflush(stdout); | |
| 578 | + } | |
| 579 | + totalSize = db_int(0, "SELECT count(*) FROM blob"); | |
| 580 | + db_prepare(&s, | |
| 581 | + "SELECT rid, size FROM blob /*scan*/" | |
| 582 | + " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" | |
| 583 | + " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)" | |
| 584 | + ); | |
| 585 | + while( db_step(&s)==SQLITE_ROW ){ | |
| 586 | + int rid = db_column_int(&s, 0); | |
| 587 | + int size = db_column_int(&s, 1); | |
| 588 | + if( size>=0 ){ | |
| 589 | + Blob content; | |
| 590 | + content_get(rid, &content); | |
| 591 | + rebuild_step(rid, size, &content); | |
| 592 | + } | |
| 593 | + } | |
| 594 | + db_finalize(&s); | |
| 595 | + db_prepare(&s, | |
| 596 | + "SELECT rid, size FROM blob" | |
| 597 | + " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" | |
| 598 | + ); | |
| 599 | + while( db_step(&s)==SQLITE_ROW ){ | |
| 600 | + int rid = db_column_int(&s, 0); | |
| 601 | + int size = db_column_int(&s, 1); | |
| 602 | + if( size>=0 ){ | |
| 603 | + if( !bag_find(&bagDone, rid) ){ | |
| 604 | + Blob content; | |
| 605 | + content_get(rid, &content); | |
| 606 | + rebuild_step(rid, size, &content); | |
| 607 | + } | |
| 608 | + } | |
| 609 | + } | |
| 610 | + db_finalize(&s); | |
| 611 | + if(!g.fQuiet && ttyOutput ){ | |
| 612 | + printf("\n"); | |
| 613 | + } | |
| 614 | + | |
| 615 | + /* free filename format string */ | |
| 616 | + free(zFNameFormat); | |
| 617 | + zFNameFormat = 0; | |
| 565 | 618 | } |
| 566 | 619 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -72,16 +72,20 @@ | |
| 72 | @ content TEXT |
| 73 | @ ); |
| 74 | ; |
| 75 | |
| 76 | /* |
| 77 | ** Variables used for progress information |
| 78 | */ |
| 79 | static int totalSize; /* Total number of artifacts to process */ |
| 80 | static int processCnt; /* Number processed so far */ |
| 81 | static int ttyOutput; /* Do progress output */ |
| 82 | static Bag bagDone; /* Bag of records rebuilt */ |
| 83 | |
| 84 | /* |
| 85 | ** Called after each artifact is processed |
| 86 | */ |
| 87 | static void rebuild_step_done(rid){ |
| @@ -98,10 +102,21 @@ | |
| 98 | |
| 99 | /* |
| 100 | ** Rebuild cross-referencing information for the artifact |
| 101 | ** rid with content pBase and all of its descendants. This |
| 102 | ** routine clears the content buffer before returning. |
| 103 | */ |
| 104 | static void rebuild_step(int rid, int size, Blob *pBase){ |
| 105 | static Stmt q1; |
| 106 | Bag children; |
| 107 | Blob copy; |
| @@ -133,12 +148,23 @@ | |
| 133 | pUse = pBase; |
| 134 | }else{ |
| 135 | blob_copy(©, pBase); |
| 136 | pUse = © |
| 137 | } |
| 138 | manifest_crosslink(rid, pUse); |
| 139 | blob_reset(pUse); |
| 140 | |
| 141 | /* Call all children recursively */ |
| 142 | for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ |
| 143 | Stmt q2; |
| 144 | int sz; |
| @@ -161,11 +187,10 @@ | |
| 161 | db_finalize(&q2); |
| 162 | blob_reset(pUse); |
| 163 | } |
| 164 | } |
| 165 | bag_clear(&children); |
| 166 | rebuild_step_done(rid); |
| 167 | } |
| 168 | |
| 169 | /* |
| 170 | ** Check to see if the "sym-trunk" tag exists. If not, create it |
| 171 | ** and attach it to the very first check-in. |
| @@ -402,18 +427,19 @@ | |
| 402 | rebuild_db(0, 1); |
| 403 | db_end_transaction(0); |
| 404 | } |
| 405 | } |
| 406 | |
| 407 | /* |
| 408 | ** help function for reconstruct for recursiv directory |
| 409 | ** reading. |
| 410 | */ |
| 411 | void recon_read_dir(char * zPath){ |
| 412 | DIR *d; |
| 413 | struct dirent *pEntry; |
| 414 | Blob aContent; /* content of the just read artifact */ |
| 415 | |
| 416 | d = opendir(zPath); |
| 417 | if( d ){ |
| 418 | while( (pEntry=readdir(d))!=0 ){ |
| 419 | Blob path; |
| @@ -434,10 +460,12 @@ | |
| 434 | } |
| 435 | content_put(&aContent, 0, 0); |
| 436 | blob_reset(&path); |
| 437 | blob_reset(&aContent); |
| 438 | free(zSubpath); |
| 439 | } |
| 440 | }else { |
| 441 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| 442 | errno, g.argv[3]); |
| 443 | } |
| @@ -467,14 +495,22 @@ | |
| 467 | db_open_repository(g.argv[2]); |
| 468 | db_open_config(0); |
| 469 | db_begin_transaction(); |
| 470 | db_initial_setup(0, 0, 1); |
| 471 | |
| 472 | recon_read_dir(g.argv[3]); |
| 473 | |
| 474 | rebuild_db(0, 1); |
| 475 | |
| 476 | db_end_transaction(0); |
| 477 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 478 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 479 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 480 | printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); |
| @@ -493,13 +529,11 @@ | |
| 493 | ** prefix can be set to 0,1,..,9 characters. |
| 494 | */ |
| 495 | void deconstruct_cmd(void){ |
| 496 | const char *zDestDir; |
| 497 | const char *zPrefixOpt; |
| 498 | int prefixLength = 0; |
| 499 | char *zAFileOutFormat; |
| 500 | Stmt q; |
| 501 | |
| 502 | /* check number of arguments */ |
| 503 | if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){ |
| 504 | usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION"); |
| 505 | } |
| @@ -514,52 +548,71 @@ | |
| 514 | prefixLength = 2; |
| 515 | }else{ |
| 516 | if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){ |
| 517 | prefixLength = (int)(*zPrefixOpt-'0'); |
| 518 | }else{ |
| 519 | fossil_panic("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 520 | } |
| 521 | } |
| 522 | if( prefixLength ){ |
| 523 | zAFileOutFormat = mprintf("%%s/%%.%ds/%%s",prefixLength); |
| 524 | }else{ |
| 525 | zAFileOutFormat = mprintf("%%s/%%s"); |
| 526 | } |
| 527 | #ifndef _WIN32 |
| 528 | if( access(zDestDir, W_OK) ){ |
| 529 | fossil_panic("DESTINATION(%s) is not writeable!",zDestDir); |
| 530 | } |
| 531 | #else |
| 532 | /* write access on windows is not checked, errors will be |
| 533 | ** dected on blob_write_to_file |
| 534 | */ |
| 535 | #endif |
| 536 | /* open repository and open query for all artifacts */ |
| 537 | db_find_and_open_repository(1); |
| 538 | db_prepare(&q, "SELECT rid,uuid FROM blob"); |
| 539 | /* loop over artifacts and write them to single files */ |
| 540 | while( db_step(&q)==SQLITE_ROW ){ |
| 541 | int aRid; |
| 542 | const char *zAUuid; |
| 543 | char *zAFName; |
| 544 | Blob zACont; |
| 545 | |
| 546 | /* get data from query */ |
| 547 | aRid = db_column_int (&q, 0); |
| 548 | zAUuid = db_column_text(&q, 1); |
| 549 | |
| 550 | /* construct output filename */ |
| 551 | zAFName = mprintf(zAFileOutFormat, zDestDir, zAUuid, zAUuid + prefixLength); |
| 552 | |
| 553 | /* read artifact contents from db and write to file */ |
| 554 | content_get(aRid,&zACont); |
| 555 | blob_write_to_file(&zACont,zAFName); |
| 556 | blob_reset(&zACont); |
| 557 | |
| 558 | /* free artifact filename string */ |
| 559 | free(zAFName); |
| 560 | } |
| 561 | /* close query statement */ |
| 562 | db_finalize(&q); |
| 563 | /* free filename format string */ |
| 564 | free(zAFileOutFormat); |
| 565 | } |
| 566 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -72,16 +72,20 @@ | |
| 72 | @ content TEXT |
| 73 | @ ); |
| 74 | ; |
| 75 | |
| 76 | /* |
| 77 | ** Variables used to store state information about an on-going "rebuild" |
| 78 | ** or "deconstruct". |
| 79 | */ |
| 80 | static int totalSize; /* Total number of artifacts to process */ |
| 81 | static int processCnt; /* Number processed so far */ |
| 82 | static int ttyOutput; /* Do progress output */ |
| 83 | static Bag bagDone; /* Bag of records rebuilt */ |
| 84 | |
| 85 | static char *zFNameFormat; /* Format string for filenames on deconstruct */ |
| 86 | static int prefixLength; /* Length of directory prefix for deconstruct */ |
| 87 | |
| 88 | /* |
| 89 | ** Called after each artifact is processed |
| 90 | */ |
| 91 | static void rebuild_step_done(rid){ |
| @@ -98,10 +102,21 @@ | |
| 102 | |
| 103 | /* |
| 104 | ** Rebuild cross-referencing information for the artifact |
| 105 | ** rid with content pBase and all of its descendants. This |
| 106 | ** routine clears the content buffer before returning. |
| 107 | ** |
| 108 | ** If the zFNameFormat variable is set, then this routine is |
| 109 | ** called to run "fossil deconstruct" instead of the usual |
| 110 | ** "fossil rebuild". In that case, instead of rebuilding the |
| 111 | ** cross-referencing information, write the file content out |
| 112 | ** to the approriate directory. |
| 113 | ** |
| 114 | ** In both cases, this routine automatically recurses to process |
| 115 | ** other artifacts that are deltas off of the current artifact. |
| 116 | ** This is the most efficient way to extract all of the original |
| 117 | ** artifact content from the Fossil repository. |
| 118 | */ |
| 119 | static void rebuild_step(int rid, int size, Blob *pBase){ |
| 120 | static Stmt q1; |
| 121 | Bag children; |
| 122 | Blob copy; |
| @@ -133,12 +148,23 @@ | |
| 148 | pUse = pBase; |
| 149 | }else{ |
| 150 | blob_copy(©, pBase); |
| 151 | pUse = © |
| 152 | } |
| 153 | if( zFNameFormat==0 ){ |
| 154 | /* We are doing "fossil rebuild" */ |
| 155 | manifest_crosslink(rid, pUse); |
| 156 | }else{ |
| 157 | /* We are doing "fossil deconstruct" */ |
| 158 | char *zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid); |
| 159 | char *zFile = mprintf(zFNameFormat, zUuid, zUuid+prefixLength); |
| 160 | blob_write_to_file(pUse,zFile); |
| 161 | free(zFile); |
| 162 | free(zUuid); |
| 163 | } |
| 164 | blob_reset(pUse); |
| 165 | rebuild_step_done(rid); |
| 166 | |
| 167 | /* Call all children recursively */ |
| 168 | for(cid=bag_first(&children), i=1; cid; cid=bag_next(&children, cid), i++){ |
| 169 | Stmt q2; |
| 170 | int sz; |
| @@ -161,11 +187,10 @@ | |
| 187 | db_finalize(&q2); |
| 188 | blob_reset(pUse); |
| 189 | } |
| 190 | } |
| 191 | bag_clear(&children); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | ** Check to see if the "sym-trunk" tag exists. If not, create it |
| 196 | ** and attach it to the very first check-in. |
| @@ -402,18 +427,19 @@ | |
| 427 | rebuild_db(0, 1); |
| 428 | db_end_transaction(0); |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | /* |
| 433 | ** Recursively read all files from the directory zPath and install |
| 434 | ** every file read as a new artifact in the repository. |
| 435 | */ |
| 436 | void recon_read_dir(char *zPath){ |
| 437 | DIR *d; |
| 438 | struct dirent *pEntry; |
| 439 | Blob aContent; /* content of the just read artifact */ |
| 440 | static int nFileRead = 0; |
| 441 | |
| 442 | d = opendir(zPath); |
| 443 | if( d ){ |
| 444 | while( (pEntry=readdir(d))!=0 ){ |
| 445 | Blob path; |
| @@ -434,10 +460,12 @@ | |
| 460 | } |
| 461 | content_put(&aContent, 0, 0); |
| 462 | blob_reset(&path); |
| 463 | blob_reset(&aContent); |
| 464 | free(zSubpath); |
| 465 | printf("\r%d", ++nFileRead); |
| 466 | fflush(stdout); |
| 467 | } |
| 468 | }else { |
| 469 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| 470 | errno, g.argv[3]); |
| 471 | } |
| @@ -467,14 +495,22 @@ | |
| 495 | db_open_repository(g.argv[2]); |
| 496 | db_open_config(0); |
| 497 | db_begin_transaction(); |
| 498 | db_initial_setup(0, 0, 1); |
| 499 | |
| 500 | printf("Reading files from directory \"%s\"...\n", g.argv[3]); |
| 501 | recon_read_dir(g.argv[3]); |
| 502 | printf("\nBuilding the Fossil repository...\n"); |
| 503 | |
| 504 | rebuild_db(0, 1); |
| 505 | |
| 506 | /* Skip the verify_before_commit() step on a reconstruct. Most artifacts |
| 507 | ** will have been changed and verification therefore takes a really, really |
| 508 | ** long time. |
| 509 | */ |
| 510 | verify_cancel(); |
| 511 | |
| 512 | db_end_transaction(0); |
| 513 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 514 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 515 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 516 | printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); |
| @@ -493,13 +529,11 @@ | |
| 529 | ** prefix can be set to 0,1,..,9 characters. |
| 530 | */ |
| 531 | void deconstruct_cmd(void){ |
| 532 | const char *zDestDir; |
| 533 | const char *zPrefixOpt; |
| 534 | Stmt s; |
| 535 | |
| 536 | /* check number of arguments */ |
| 537 | if( (g.argc != 3) && (g.argc != 5) && (g.argc != 7)){ |
| 538 | usage ("?-R|--repository REPOSITORY? ?-L|--prefixlength N? DESTINATION"); |
| 539 | } |
| @@ -514,52 +548,71 @@ | |
| 548 | prefixLength = 2; |
| 549 | }else{ |
| 550 | if( zPrefixOpt[0]>='0' && zPrefixOpt[0]<='9' && !zPrefixOpt[1] ){ |
| 551 | prefixLength = (int)(*zPrefixOpt-'0'); |
| 552 | }else{ |
| 553 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 554 | } |
| 555 | } |
| 556 | #ifndef _WIN32 |
| 557 | if( access(zDestDir, W_OK) ){ |
| 558 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 559 | } |
| 560 | #else |
| 561 | /* write access on windows is not checked, errors will be |
| 562 | ** dected on blob_write_to_file |
| 563 | */ |
| 564 | #endif |
| 565 | if( prefixLength ){ |
| 566 | zFNameFormat = mprintf("%s/%%.%ds/%%s",zDestDir,prefixLength); |
| 567 | }else{ |
| 568 | zFNameFormat = mprintf("%s/%%s",zDestDir); |
| 569 | } |
| 570 | /* open repository and open query for all artifacts */ |
| 571 | db_find_and_open_repository(1); |
| 572 | bag_init(&bagDone); |
| 573 | ttyOutput = 1; |
| 574 | processCnt = 0; |
| 575 | if (!g.fQuiet) { |
| 576 | printf("0 (0%%)...\r"); |
| 577 | fflush(stdout); |
| 578 | } |
| 579 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 580 | db_prepare(&s, |
| 581 | "SELECT rid, size FROM blob /*scan*/" |
| 582 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" |
| 583 | " AND NOT EXISTS(SELECT 1 FROM delta WHERE rid=blob.rid)" |
| 584 | ); |
| 585 | while( db_step(&s)==SQLITE_ROW ){ |
| 586 | int rid = db_column_int(&s, 0); |
| 587 | int size = db_column_int(&s, 1); |
| 588 | if( size>=0 ){ |
| 589 | Blob content; |
| 590 | content_get(rid, &content); |
| 591 | rebuild_step(rid, size, &content); |
| 592 | } |
| 593 | } |
| 594 | db_finalize(&s); |
| 595 | db_prepare(&s, |
| 596 | "SELECT rid, size FROM blob" |
| 597 | " WHERE NOT EXISTS(SELECT 1 FROM shun WHERE uuid=blob.uuid)" |
| 598 | ); |
| 599 | while( db_step(&s)==SQLITE_ROW ){ |
| 600 | int rid = db_column_int(&s, 0); |
| 601 | int size = db_column_int(&s, 1); |
| 602 | if( size>=0 ){ |
| 603 | if( !bag_find(&bagDone, rid) ){ |
| 604 | Blob content; |
| 605 | content_get(rid, &content); |
| 606 | rebuild_step(rid, size, &content); |
| 607 | } |
| 608 | } |
| 609 | } |
| 610 | db_finalize(&s); |
| 611 | if(!g.fQuiet && ttyOutput ){ |
| 612 | printf("\n"); |
| 613 | } |
| 614 | |
| 615 | /* free filename format string */ |
| 616 | free(zFNameFormat); |
| 617 | zFNameFormat = 0; |
| 618 | } |
| 619 |