Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch purge Excluding Merge-Ins
This is equivalent to a diff from f1a480e130 to 501f3e1143
|
2016-08-02
| ||
| 15:18 | Merge the "purge" command onto trunk, even though it is incomplete. check-in: b78a32f43d user: drh tags: trunk | |
| 15:17 | Add a further warning on the purge command to indicate that it is dicey. That extra warning makes the purge code permissible to add to trunk. Closed-Leaf check-in: 501f3e1143 user: drh tags: purge | |
| 14:52 | Improved help and remove redundant file listings for the "fossil purge" command. check-in: 2c53d022c3 user: drh tags: purge | |
| 14:41 | Sync up with the trunk. check-in: 12f8633aa1 user: drh tags: purge | |
| 09:10 | Corrections to information about running Fossil in a chroot jail. check-in: f1a480e130 user: drh tags: trunk | |
| 08:46 | Compiler warning fixes. This includes disabling the undocumented FOSSIL_PWREADER feature and upgrading the built-in SQLite. check-in: f35b46d4cb user: drh tags: trunk | |
Changes to src/name.c.
| ︙ | ︙ | |||
932 933 934 935 936 937 938 | /* Mark private elements */ db_multi_exec( "UPDATE description SET isPrivate=1 WHERE rid IN private" ); } /* | | > > > > > | | | 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
/* Mark private elements */
db_multi_exec(
"UPDATE description SET isPrivate=1 WHERE rid IN private"
);
}
/*
** Print the content of the description table on stdout.
**
** The description table is computed using the WHERE clause zWhere if
** the zWhere parameter is not NULL. If zWhere is NULL, then this
** routine assumes that the description table already exists and is
** populated and merely prints the contents.
*/
int describe_artifacts_to_stdout(const char *zWhere, const char *zLabel){
Stmt q;
int cnt = 0;
if( zWhere!=0 ) describe_artifacts(zWhere);
db_prepare(&q,
"SELECT uuid, summary, isPrivate\n"
" FROM description\n"
" ORDER BY ctime, type;"
);
while( db_step(&q)==SQLITE_ROW ){
if( zLabel ){
fossil_print("%s\n", zLabel);
zLabel = 0;
}
fossil_print(" %.16s %s", db_column_text(&q,0), db_column_text(&q,1));
if( db_column_int(&q,2) ) fossil_print(" (unpublished)");
fossil_print("\n");
cnt++;
}
db_finalize(&q);
if( zWhere!=0 ) db_multi_exec("DELETE FROM description;");
return cnt;
}
/*
** COMMAND: test-describe-artifacts
**
** Usage: %fossil test-describe-artifacts [--from S] [--count N]
|
| ︙ | ︙ |
Changes to src/purge.c.
| ︙ | ︙ | |||
20 21 22 23 24 25 26 | ** manages the graveyard of purged content. */ #include "config.h" #include "purge.h" #include <assert.h> /* | | | 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | ** manages the graveyard of purged content. */ #include "config.h" #include "purge.h" #include <assert.h> /* ** SQL code used to initialize the schema of the graveyard. ** ** The purgeevent table contains one entry for each purge event. For each ** purge event, multiple artifacts might have been removed. Each removed ** artifact is stored as an entry in the purgeitem table. ** ** The purgeevent and purgeitem tables are not synced, even by the ** "fossil config" command. They exist only as a backup in case of a |
| ︙ | ︙ | |||
50 51 52 53 54 55 56 57 58 59 60 61 62 63 | @ isPrivate BOOLEAN, -- True if artifact was originally private @ sz INT NOT NULL, -- Uncompressed size of the purged artifact @ desc TEXT, -- Brief description of this artifact @ data BLOB -- Compressed artifact content @ ); ; /* ** This routine purges multiple artifacts from the repository, transfering ** those artifacts into the PURGEITEM table. ** ** Prior to invoking this routine, the caller must create a (TEMP) table ** named zTab that contains the RID of every artifact to be purged. ** | > > > > > > > > > | 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | @ isPrivate BOOLEAN, -- True if artifact was originally private @ sz INT NOT NULL, -- Uncompressed size of the purged artifact @ desc TEXT, -- Brief description of this artifact @ data BLOB -- Compressed artifact content @ ); ; /* ** Flags for the purge_artifact_list() function. */ #if INTERFACE #define PURGE_MOVETO_GRAVEYARD 0x0001 /* Move artifacts in graveyard */ #define PURGE_EXPLAIN_ONLY 0x0002 /* Show what would have happened */ #define PURGE_PRINT_SUMMARY 0x0004 /* Print a summary report at end */ #endif /* ** This routine purges multiple artifacts from the repository, transfering ** those artifacts into the PURGEITEM table. ** ** Prior to invoking this routine, the caller must create a (TEMP) table ** named zTab that contains the RID of every artifact to be purged. ** |
| ︙ | ︙ | |||
79 80 81 82 83 84 85 | ** (h) BACKLINK ** (i) ATTACHMENT ** (j) TICKETCHNG ** (7) If any ticket artifacts were removed (6j) then rebuild the ** corresponding ticket entries. Possibly remove entries from ** the ticket table. ** | | | > > > > > > > > > > | 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 |
** (h) BACKLINK
** (i) ATTACHMENT
** (j) TICKETCHNG
** (7) If any ticket artifacts were removed (6j) then rebuild the
** corresponding ticket entries. Possibly remove entries from
** the ticket table.
**
** Steps 1-4 (saving the purged artifacts into the graveyard) are only
** undertaken if the moveToGraveyard flag is true.
*/
int purge_artifact_list(
const char *zTab, /* TEMP table containing list of RIDS to be purged */
const char *zNote, /* Text of the purgeevent.pnotes field */
unsigned purgeFlags /* zero or more PURGE_* flags */
){
int peid = 0; /* New purgeevent ID */
Stmt q; /* General-use prepared statement */
char *z;
assert( g.repositoryOpen ); /* Main database must already be open */
db_begin_transaction();
z = sqlite3_mprintf("IN \"%w\"", zTab);
describe_artifacts(z);
sqlite3_free(z);
describe_artifacts_to_stdout(0, 0);
/* The explain-only flags causes this routine to list the artifacts
** that would have been purged but to not actually make any changes
** to the repository.
*/
if( purgeFlags & PURGE_EXPLAIN_ONLY ){
db_end_transaction(0);
return 0;
}
/* Make sure we are not removing a manifest that is the baseline of some
** manifest that is being left behind. This step is not strictly necessary.
** is is just a safety check. */
if( purge_baseline_out_from_under_delta(zTab) ){
fossil_fatal("attempt to purge a baseline manifest without also purging "
"all of its deltas");
|
| ︙ | ︙ | |||
119 120 121 122 123 124 125 |
content_undelta(rid);
verify_before_commit(rid);
}
db_finalize(&q);
/* Construct the graveyard and copy the artifacts to be purged into the
** graveyard */
| | | 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
content_undelta(rid);
verify_before_commit(rid);
}
db_finalize(&q);
/* Construct the graveyard and copy the artifacts to be purged into the
** graveyard */
if( purgeFlags & PURGE_MOVETO_GRAVEYARD ){
db_multi_exec(zPurgeInit /*works-like:"%w%w"*/,
db_name("repository"), db_name("repository"));
db_multi_exec(
"INSERT INTO purgeevent(ctime,pnotes) VALUES(now(),%Q)", zNote
);
peid = db_last_insert_rowid();
db_prepare(&q, "SELECT rid FROM delta WHERE rid IN \"%w\""
|
| ︙ | ︙ | |||
187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
ticket_rebuild_entry(db_column_text(&q, 0));
}
db_finalize(&q);
/* db_multi_exec("DROP TABLE \"%w_tickets\"", zTab); */
/* Mission accomplished */
db_end_transaction(0);
return peid;
}
/*
** The TEMP table named zTab contains RIDs for a set of check-ins.
**
** Check to see if any check-in in zTab is a baseline manifest for some
| > > > > > > > | 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 |
ticket_rebuild_entry(db_column_text(&q, 0));
}
db_finalize(&q);
/* db_multi_exec("DROP TABLE \"%w_tickets\"", zTab); */
/* Mission accomplished */
db_end_transaction(0);
if( purgeFlags & PURGE_PRINT_SUMMARY ){
fossil_print("%d artifacts purged\n",
db_int(0, "SELECT count(*) FROM \"%w\";", zTab));
fossil_print("undoable using \"%s purge undo %d\".\n",
g.nameOfExe, peid);
}
return peid;
}
/*
** The TEMP table named zTab contains RIDs for a set of check-ins.
**
** Check to see if any check-in in zTab is a baseline manifest for some
|
| ︙ | ︙ | |||
218 219 220 221 222 223 224 | } } /* ** The TEMP table named zTab contains the RIDs for a set of check-in ** artifacts. Expand this set (by adding new entries to zTab) to include | | | 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 | } } /* ** The TEMP table named zTab contains the RIDs for a set of check-in ** artifacts. Expand this set (by adding new entries to zTab) to include ** all other artifacts that are used by the check-ins in ** the original list. ** ** If the bExclusive flag is true, then the set is only expanded by ** artifacts that are used exclusively by the check-ins in the set. ** When bExclusive is false, then all artifacts used by the check-ins ** are added even if those artifacts are also used by other check-ins ** not in the set. |
| ︙ | ︙ | |||
424 425 426 427 428 429 430 | } /* ** COMMAND: purge ** ** The purge command removes content from a repository and stores that content ** in a "graveyard". The graveyard exists so that content can be recovered | | > > > > > > > > > > > > > | | | < < < > > | > > | | | > > > > > > > > > > > > > > | | > > > > > > > > > > > > > > > > > > > > > | | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | | | | | | | | | | | | | | | | | | | | < < < < < < < < < < < < < < < < < < > | < < < < < < | < < | < < < > > | 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 |
}
/*
** COMMAND: purge
**
** The purge command removes content from a repository and stores that content
** in a "graveyard". The graveyard exists so that content can be recovered
** using the "fossil purge undo" command. The "fossil purge obliterate"
** command empties the graveyard, making the content unrecoverable.
**
** ==== WARNING: This command can potentially destroy historical data and ====
** ==== leave your repository in a goofy state. Know what you are doing! ====
** ==== Make a backup of your repository before using this command! ====
**
** ==== FURTHER WARNING: This command is a work-in-progress and may yet ====
** ==== contains bugs. ====
**
** fossil purge artifacts UUID... ?OPTIONS?
**
** Move arbitrary artifacts identified by the UUID list into the
** graveyard.
**
** fossil purge cat UUID...
**
** Write the content of one or more artifacts in the graveyard onto
** standard output.
**
** fossil purge checkins TAGS... ?OPTIONS?
**
** Move the check-ins or branches identified by TAGS and all of
** their descendants out of the repository and into the graveyard.
** If TAGS includes a branch name then it means all the check-ins
** on the most recent occurrence of that branch.
**
** fossil purge files NAME ... ?OPTIONS?
**
** Move all instances of files called NAME into the graveyard.
** NAME should be the name of the file relative to the root of the
** repository. If NAME is a directory, then all files within that
** directory are moved.
**
** fossil purge list|ls ?-l?
**
** Show the graveyard of prior purges. The -l option gives more
** detail in the output.
**
** fossil purge obliterate ID... ?--force?
**
** Remove one or more purge events from the graveyard. Once a purge
** event is obliterated, it can no longer be undone. The --force
** option suppresses the confirmation prompt.
**
** fossil purge tickets NAME ... ?OPTIONS?
**
** TBD...
**
** fossil purge undo ID
**
** Restore the content previously removed by purge ID.
**
** fossil purge wiki NAME ... ?OPTIONS?
**
** TBD...
**
** COMMON OPTIONS:
**
** --explain Make no changes, but show what would happen.
** --dry-run An alias for --explain
**
** SUMMARY:
** fossil purge artifacts UUID.. [OPTIONS]
** fossil purge cat UUID...
** fossil purge checkins TAGS... [OPTIONS]
** fossil purge files FILENAME... [OPTIONS]
** fossil purge list
** fossil purge obliterate ID...
** fossil purge tickets NAME... [OPTIONS]
** fossil purge undo ID
** fossil purge wiki NAME... [OPTIONS]
*/
void purge_cmd(void){
int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY;
const char *zSubcmd;
int n;
int i;
Stmt q;
if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?");
zSubcmd = g.argv[2];
db_find_and_open_repository(0,0);
n = (int)strlen(zSubcmd);
if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){
purgeFlags |= PURGE_EXPLAIN_ONLY;
}
if( strncmp(zSubcmd, "artifacts", n)==0 ){
verify_all_options();
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
for(i=3; i<g.argc; i++){
int r = name_to_typed_rid(g.argv[i], "");
db_multi_exec("INSERT OR IGNORE INTO ok(rid) VALUES(%d);", r);
}
describe_artifacts_to_stdout("IN ok", 0);
purge_artifact_list("ok", "", purgeFlags);
db_end_transaction(0);
}else if( strncmp(zSubcmd, "cat", n)==0 ){
int i, piid;
Blob content;
if( g.argc<4 ) usage("cat UUID...");
for(i=3; i<g.argc; i++){
piid = db_int(0, "SELECT piid FROM purgeitem WHERE uuid LIKE '%q%%'",
g.argv[i]);
if( piid==0 ) fossil_fatal("no such item: %s", g.argv[3]);
purge_extract_item(piid, &content);
blob_write_to_file(&content, "-");
blob_reset(&content);
}
}else if( strncmp(zSubcmd, "checkins", n)==0 ){
int vid;
if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){
purgeFlags |= PURGE_EXPLAIN_ONLY;
}
verify_all_options();
db_begin_transaction();
if( g.argc<=3 ) usage("checkins TAGS... [OPTIONS]");
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
for(i=3; i<g.argc; i++){
int r = name_to_typed_rid(g.argv[i], "br");
compute_descendants(r, 1000000000);
}
vid = db_lget_int("checkout",0);
if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
fossil_fatal("cannot purge the current checkout");
}
find_checkin_associates("ok", 1);
purge_artifact_list("ok", "", purgeFlags);
db_end_transaction(0);
}else if( strncmp(zSubcmd, "files", n)==0 ){
verify_all_options();
db_begin_transaction();
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
for(i=3; i<g.argc; i++){
db_multi_exec(
"INSERT OR IGNORE INTO ok(rid) "
" SELECT fid FROM mlink, filename"
" WHERE mlink.fnid=filename.fnid"
" AND (filename.name=%Q OR filename.name GLOB '%q/*')",
g.argv[i], g.argv[i]
);
}
purge_artifact_list("ok", "", purgeFlags);
db_end_transaction(0);
}else if( strncmp(zSubcmd, "list", n)==0 || strcmp(zSubcmd,"ls")==0 ){
int showDetail = find_option("l","l",0)!=0;
if( !db_table_exists("repository","purgeevent") ) return;
db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch',toLocal())"
" FROM purgeevent");
while( db_step(&q)==SQLITE_ROW ){
fossil_print("%4d on %s\n", db_column_int(&q,0), db_column_text(&q,1));
if( showDetail ){
purge_list_event_content(db_column_int(&q,0));
}
}
db_finalize(&q);
}else if( strncmp(zSubcmd, "obliterate", n)==0 ){
int i;
int bForce = find_option("force","f",0)!=0;
if( g.argc<4 ) usage("obliterate ID...");
if( !bForce ){
Blob ans;
char cReply;
prompt_user(
"Obliterating the graveyard will permanently delete information.\n"
"Changes cannot be undone. Continue (y/N)? ", &ans);
cReply = blob_str(&ans)[0];
if( cReply!='y' && cReply!='Y' ){
fossil_exit(1);
}
}
db_begin_transaction();
for(i=3; i<g.argc; i++){
int peid = atoi(g.argv[i]);
if( !db_exists("SELECT 1 FROM purgeevent WHERE peid=%d",peid) ){
fossil_fatal("no such purge event: %s", g.argv[i]);
}
db_multi_exec(
"DELETE FROM purgeevent WHERE peid=%d;"
"DELETE FROM purgeitem WHERE peid=%d;",
peid, peid
);
}
db_end_transaction(0);
}else if( strncmp(zSubcmd, "tickets", n)==0 ){
fossil_fatal("not yet implemented....");
}else if( strncmp(zSubcmd, "undo", n)==0 ){
int peid;
if( g.argc!=4 ) usage("undo ID");
peid = atoi(g.argv[3]);
if( (purgeFlags & PURGE_EXPLAIN_ONLY)==0 ){
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE ix("
" piid INTEGER PRIMARY KEY,"
" srcid INTEGER"
");"
"CREATE INDEX ixsrcid ON ix(srcid);"
"INSERT INTO ix(piid,srcid) "
" SELECT piid, coalesce(srcid,0) FROM purgeitem WHERE peid=%d;",
peid
);
db_multi_exec(
"DELETE FROM shun"
" WHERE uuid IN (SELECT uuid FROM purgeitem WHERE peid=%d);",
peid
);
manifest_crosslink_begin();
purge_item_resurrect(0, 0);
manifest_crosslink_end(0);
db_multi_exec("DELETE FROM purgeevent WHERE peid=%d", peid);
db_multi_exec("DELETE FROM purgeitem WHERE peid=%d", peid);
db_end_transaction(0);
}
}else if( strncmp(zSubcmd, "wiki", n)==0 ){
fossil_fatal("not yet implemented....");
}else{
fossil_fatal("unknown subcommand \"%s\".\n"
"should be one of: cat, checkins, files, list, obliterate,"
" tickets, undo, wiki", zSubcmd);
}
}
|