Fossil SCM

Enhance the "fossil purge" command to allow it to specify individual artifacts and files to be purged.

drh 2016-07-28 13:58 UTC purge
Commit 263fd2dab2ec443af58b7d835be75dad2274622b
2 files changed +8 -3 +113 -49
+8 -3
--- src/name.c
+++ src/name.c
@@ -934,16 +934,21 @@
934934
"UPDATE description SET isPrivate=1 WHERE rid IN private"
935935
);
936936
}
937937
938938
/*
939
-** Print the content of the description table on stdout
939
+** Print the content of the description table on stdout.
940
+**
941
+** The description table is computed using the WHERE clause zWhere if
942
+** the zWhere parameter is not NULL. If zWhere is NULL, then this
943
+** routine assumes that the description table already exists and is
944
+** populated and merely prints the contents.
940945
*/
941946
int describe_artifacts_to_stdout(const char *zWhere, const char *zLabel){
942947
Stmt q;
943948
int cnt = 0;
944
- describe_artifacts(zWhere);
949
+ if( zWhere!=0 ) describe_artifacts(zWhere);
945950
db_prepare(&q,
946951
"SELECT uuid, summary, isPrivate\n"
947952
" FROM description\n"
948953
" ORDER BY ctime, type;"
949954
);
@@ -956,11 +961,11 @@
956961
if( db_column_int(&q,2) ) fossil_print(" (unpublished)");
957962
fossil_print("\n");
958963
cnt++;
959964
}
960965
db_finalize(&q);
961
- db_multi_exec("DELETE FROM description;");
966
+ if( zWhere!=0 ) db_multi_exec("DELETE FROM description;");
962967
return cnt;
963968
}
964969
965970
/*
966971
** COMMAND: test-describe-artifacts
967972
--- src/name.c
+++ src/name.c
@@ -934,16 +934,21 @@
934 "UPDATE description SET isPrivate=1 WHERE rid IN private"
935 );
936 }
937
938 /*
939 ** Print the content of the description table on stdout
 
 
 
 
 
940 */
941 int describe_artifacts_to_stdout(const char *zWhere, const char *zLabel){
942 Stmt q;
943 int cnt = 0;
944 describe_artifacts(zWhere);
945 db_prepare(&q,
946 "SELECT uuid, summary, isPrivate\n"
947 " FROM description\n"
948 " ORDER BY ctime, type;"
949 );
@@ -956,11 +961,11 @@
956 if( db_column_int(&q,2) ) fossil_print(" (unpublished)");
957 fossil_print("\n");
958 cnt++;
959 }
960 db_finalize(&q);
961 db_multi_exec("DELETE FROM description;");
962 return cnt;
963 }
964
965 /*
966 ** COMMAND: test-describe-artifacts
967
--- src/name.c
+++ src/name.c
@@ -934,16 +934,21 @@
934 "UPDATE description SET isPrivate=1 WHERE rid IN private"
935 );
936 }
937
938 /*
939 ** Print the content of the description table on stdout.
940 **
941 ** The description table is computed using the WHERE clause zWhere if
942 ** the zWhere parameter is not NULL. If zWhere is NULL, then this
943 ** routine assumes that the description table already exists and is
944 ** populated and merely prints the contents.
945 */
946 int describe_artifacts_to_stdout(const char *zWhere, const char *zLabel){
947 Stmt q;
948 int cnt = 0;
949 if( zWhere!=0 ) describe_artifacts(zWhere);
950 db_prepare(&q,
951 "SELECT uuid, summary, isPrivate\n"
952 " FROM description\n"
953 " ORDER BY ctime, type;"
954 );
@@ -956,11 +961,11 @@
961 if( db_column_int(&q,2) ) fossil_print(" (unpublished)");
962 fossil_print("\n");
963 cnt++;
964 }
965 db_finalize(&q);
966 if( zWhere!=0 ) db_multi_exec("DELETE FROM description;");
967 return cnt;
968 }
969
970 /*
971 ** COMMAND: test-describe-artifacts
972
+113 -49
--- src/purge.c
+++ src/purge.c
@@ -57,10 +57,12 @@
5757
/*
5858
** Flags for the purge_artifact_list() function.
5959
*/
6060
#if INTERFACE
6161
#define PURGE_MOVETO_GRAVEYARD 0x0001 /* Move artifacts in graveyard */
62
+#define PURGE_EXPLAIN_ONLY 0x0002 /* Show what would have happened */
63
+#define PURGE_PRINT_SUMMARY 0x0004 /* Print a summary report at end */
6264
#endif
6365
6466
/*
6567
** This routine purges multiple artifacts from the repository, transfering
6668
** those artifacts into the PURGEITEM table.
@@ -105,10 +107,20 @@
105107
assert( g.repositoryOpen ); /* Main database must already be open */
106108
db_begin_transaction();
107109
z = sqlite3_mprintf("IN \"%w\"", zTab);
108110
describe_artifacts(z);
109111
sqlite3_free(z);
112
+ describe_artifacts_to_stdout(0, 0);
113
+
114
+ /* The explain-only flags causes this routine to list the artifacts
115
+ ** that would have been purged but to not actually make any changes
116
+ ** to the repository.
117
+ */
118
+ if( purgeFlags & PURGE_EXPLAIN_ONLY ){
119
+ db_end_transaction(0);
120
+ return 0;
121
+ }
110122
111123
/* Make sure we are not removing a manifest that is the baseline of some
112124
** manifest that is being left behind. This step is not strictly necessary.
113125
** is is just a safety check. */
114126
if( purge_baseline_out_from_under_delta(zTab) ){
@@ -196,10 +208,17 @@
196208
db_finalize(&q);
197209
/* db_multi_exec("DROP TABLE \"%w_tickets\"", zTab); */
198210
199211
/* Mission accomplished */
200212
db_end_transaction(0);
213
+
214
+ if( purgeFlags & PURGE_PRINT_SUMMARY ){
215
+ fossil_print("%d artifacts purged\n",
216
+ db_int(0, "SELECT count(*) FROM \"%w\";", zTab));
217
+ fossil_print("undoable using \"%s purge undo %d\".\n",
218
+ g.nameOfExe, peid);
219
+ }
201220
return peid;
202221
}
203222
204223
/*
205224
** The TEMP table named zTab contains RIDs for a set of check-ins.
@@ -435,13 +454,18 @@
435454
**
436455
** The purge command removes content from a repository and stores that content
437456
** in a "graveyard". The graveyard exists so that content can be recovered
438457
** using the "fossil purge undo" command.
439458
**
440
-** fossil purge artifact UUID... ?OPTIONS?
459
+** ==== WARNING: This command can potentially destroy historical data and ====
460
+** ==== leave your repository in a goofy state. Know what you are doing! ====
461
+** ==== Make a backup of your repository before using this command! ====
462
+**
463
+** fossil purge artifacts UUID... ?OPTIONS?
441464
**
442
-** TBD...
465
+** Move arbitrary artifacts identified by the UUID list into the
466
+** graveyard.
443467
**
444468
** fossil purge cat UUID...
445469
**
446470
** Write the content of one or more artifacts in the graveyard onto
447471
** standard output.
@@ -451,26 +475,27 @@
451475
** Move the check-ins or branches identified by TAGS and all of
452476
** their descendants out of the repository and into the graveyard.
453477
** If TAGS includes a branch name then it means all the check-ins
454478
** on the most recent occurrence of that branch.
455479
**
456
-** --explain Make no changes, but show what would happen.
457
-** --dry-run Make no changes.
458
-**
459480
** fossil purge files NAME ... ?OPTIONS?
460481
**
461
-** TBD...
482
+** Move all instances of files called NAME into the graveyard.
483
+** NAME should be the name of the file relative to the root of the
484
+** repository. If NAME is a directory, then all files within that
485
+** directory are moved.
462486
**
463487
** fossil purge list|ls ?-l?
464488
**
465489
** Show the graveyard of prior purges. The -l option gives more
466490
** detail in the output.
467491
**
468
-** fossil purge obliterate ID...
492
+** fossil purge obliterate ID... ?--force?
469493
**
470494
** Remove one or more purge events from the graveyard. Once a purge
471
-** event is obliterated, it can no longer be undone.
495
+** event is obliterated, it can no longer be undone. The --force
496
+** option suppresses the confirmation prompt.
472497
**
473498
** fossil purge tickets NAME ... ?OPTIONS?
474499
**
475500
** TBD...
476501
**
@@ -480,10 +505,15 @@
480505
**
481506
** fossil purge wiki NAME ... ?OPTIONS?
482507
**
483508
** TBD...
484509
**
510
+** COMMON OPTIONS:
511
+**
512
+** --explain Make no changes, but show what would happen.
513
+** --dry-run An alias for --explain
514
+**
485515
** SUMMARY:
486516
** fossil purge artifacts UUID.. [OPTIONS]
487517
** fossil purge cat UUID...
488518
** fossil purge checkins TAGS... [OPTIONS]
489519
** fossil purge files FILENAME... [OPTIONS]
@@ -492,19 +522,34 @@
492522
** fossil purge tickets NAME... [OPTIONS]
493523
** fossil purge undo ID
494524
** fossil purge wiki NAME... [OPTIONS]
495525
*/
496526
void purge_cmd(void){
527
+ int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY;
497528
const char *zSubcmd;
498529
int n;
530
+ int i;
499531
Stmt q;
532
+
500533
if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?");
501534
zSubcmd = g.argv[2];
502535
db_find_and_open_repository(0,0);
503536
n = (int)strlen(zSubcmd);
537
+ if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){
538
+ purgeFlags |= PURGE_EXPLAIN_ONLY;
539
+ }
504540
if( strncmp(zSubcmd, "artifacts", n)==0 ){
505
- fossil_fatal("not yet implemented....");
541
+ verify_all_options();
542
+ db_begin_transaction();
543
+ db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
544
+ for(i=3; i<g.argc; i++){
545
+ int r = name_to_typed_rid(g.argv[i], "");
546
+ db_multi_exec("INSERT OR IGNORE INTO ok(rid) VALUES(%d);", r);
547
+ }
548
+ describe_artifacts_to_stdout("IN ok", 0);
549
+ purge_artifact_list("ok", "", purgeFlags);
550
+ db_end_transaction(0);
506551
}else if( strncmp(zSubcmd, "cat", n)==0 ){
507552
int i, piid;
508553
Blob content;
509554
if( g.argc<4 ) usage("cat UUID...");
510555
for(i=3; i<g.argc; i++){
@@ -514,41 +559,46 @@
514559
purge_extract_item(piid, &content);
515560
blob_write_to_file(&content, "-");
516561
blob_reset(&content);
517562
}
518563
}else if( strncmp(zSubcmd, "checkins", n)==0 ){
519
- int explainOnly = find_option("explain",0,0)!=0;
520
- int dryRun = find_option("dry-run",0,0)!=0;
521
- int i;
522564
int vid;
523
- int nCkin;
524
- int nArtifact;
565
+ if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){
566
+ purgeFlags |= PURGE_EXPLAIN_ONLY;
567
+ }
525568
verify_all_options();
526569
db_begin_transaction();
527
- if( g.argc<=3 ) usage("checkin TAGS... [OPTIONS]");
570
+ if( g.argc<=3 ) usage("checkins TAGS... [OPTIONS]");
528571
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
529572
for(i=3; i<g.argc; i++){
530573
int r = name_to_typed_rid(g.argv[i], "br");
531574
compute_descendants(r, 1000000000);
532575
}
533576
vid = db_lget_int("checkout",0);
534577
if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
535578
fossil_fatal("cannot purge the current checkout");
536579
}
537
- nCkin = db_int(0, "SELECT count(*) FROM ok");
538580
find_checkin_associates("ok", 1);
539
- nArtifact = db_int(0, "SELECT count(*) FROM ok");
540
- describe_artifacts_to_stdout("IN ok", 0);
541
- if( !explainOnly ){
542
- int peid = purge_artifact_list("ok","",PURGE_MOVETO_GRAVEYARD);
543
- fossil_print("%d check-ins and %d artifacts purged.\n", nCkin, nArtifact);
544
- fossil_print("undoable using \"%s purge undo %d\".\n",
545
- g.nameOfExe, peid);
546
- }
547
- db_end_transaction(explainOnly||dryRun);
548
- }else if( strncmp(zSubcmd, "files", n)==0 ){
549
- fossil_fatal("not yet implemented....");
581
+ describe_artifacts_to_stdout("IN ok", 0);
582
+ purge_artifact_list("ok", "", purgeFlags);
583
+ db_end_transaction(0);
584
+ }else if( strncmp(zSubcmd, "files", n)==0 ){
585
+ verify_all_options();
586
+ db_begin_transaction();
587
+ db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
588
+ for(i=3; i<g.argc; i++){
589
+ db_multi_exec(
590
+ "INSERT OR IGNORE INTO ok(rid) "
591
+ " SELECT fid FROM mlink, filename"
592
+ " WHERE mlink.fnid=filename.fnid"
593
+ " AND (filename.name=%Q OR filename.name GLOB '%q/*')",
594
+ g.argv[i], g.argv[i]
595
+ );
596
+ }
597
+ describe_artifacts_to_stdout("IN ok", 0);
598
+ purge_artifact_list("ok", "", purgeFlags);
599
+ db_end_transaction(0);
550600
}else if( strncmp(zSubcmd, "list", n)==0 || strcmp(zSubcmd,"ls")==0 ){
551601
int showDetail = find_option("l","l",0)!=0;
552602
if( !db_table_exists("repository","purgeevent") ) return;
553603
db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch',toLocal())"
554604
" FROM purgeevent");
@@ -559,11 +609,23 @@
559609
}
560610
}
561611
db_finalize(&q);
562612
}else if( strncmp(zSubcmd, "obliterate", n)==0 ){
563613
int i;
614
+ int bForce = find_option("force","f",0)!=0;
564615
if( g.argc<4 ) usage("obliterate ID...");
616
+ if( !bForce ){
617
+ Blob ans;
618
+ char cReply;
619
+ prompt_user(
620
+ "Obliterating the graveyard will permanently delete information.\n"
621
+ "Changes cannot be undone. Continue (y/N)? ", &ans);
622
+ cReply = blob_str(&ans)[0];
623
+ if( cReply!='y' && cReply!='Y' ){
624
+ fossil_exit(1);
625
+ }
626
+ }
565627
db_begin_transaction();
566628
for(i=3; i<g.argc; i++){
567629
int peid = atoi(g.argv[i]);
568630
if( !db_exists("SELECT 1 FROM purgeevent WHERE peid=%d",peid) ){
569631
fossil_fatal("no such purge event: %s", g.argv[i]);
@@ -579,35 +641,37 @@
579641
fossil_fatal("not yet implemented....");
580642
}else if( strncmp(zSubcmd, "undo", n)==0 ){
581643
int peid;
582644
if( g.argc!=4 ) usage("undo ID");
583645
peid = atoi(g.argv[3]);
584
- db_begin_transaction();
585
- db_multi_exec(
586
- "CREATE TEMP TABLE ix("
587
- " piid INTEGER PRIMARY KEY,"
588
- " srcid INTEGER"
589
- ");"
590
- "CREATE INDEX ixsrcid ON ix(srcid);"
591
- "INSERT INTO ix(piid,srcid) "
592
- " SELECT piid, coalesce(srcid,0) FROM purgeitem WHERE peid=%d;",
593
- peid
594
- );
595
- db_multi_exec(
596
- "DELETE FROM shun"
597
- " WHERE uuid IN (SELECT uuid FROM purgeitem WHERE peid=%d);",
598
- peid
599
- );
600
- manifest_crosslink_begin();
601
- purge_item_resurrect(0, 0);
602
- manifest_crosslink_end(0);
603
- db_multi_exec("DELETE FROM purgeevent WHERE peid=%d", peid);
604
- db_multi_exec("DELETE FROM purgeitem WHERE peid=%d", peid);
605
- db_end_transaction(0);
646
+ if( (purgeFlags & PURGE_EXPLAIN_ONLY)==0 ){
647
+ db_begin_transaction();
648
+ db_multi_exec(
649
+ "CREATE TEMP TABLE ix("
650
+ " piid INTEGER PRIMARY KEY,"
651
+ " srcid INTEGER"
652
+ ");"
653
+ "CREATE INDEX ixsrcid ON ix(srcid);"
654
+ "INSERT INTO ix(piid,srcid) "
655
+ " SELECT piid, coalesce(srcid,0) FROM purgeitem WHERE peid=%d;",
656
+ peid
657
+ );
658
+ db_multi_exec(
659
+ "DELETE FROM shun"
660
+ " WHERE uuid IN (SELECT uuid FROM purgeitem WHERE peid=%d);",
661
+ peid
662
+ );
663
+ manifest_crosslink_begin();
664
+ purge_item_resurrect(0, 0);
665
+ manifest_crosslink_end(0);
666
+ db_multi_exec("DELETE FROM purgeevent WHERE peid=%d", peid);
667
+ db_multi_exec("DELETE FROM purgeitem WHERE peid=%d", peid);
668
+ db_end_transaction(0);
669
+ }
606670
}else if( strncmp(zSubcmd, "wiki", n)==0 ){
607671
fossil_fatal("not yet implemented....");
608672
}else{
609673
fossil_fatal("unknown subcommand \"%s\".\n"
610674
"should be one of: cat, checkins, files, list, obliterate,"
611675
" tickets, undo, wiki", zSubcmd);
612676
}
613677
}
614678
--- src/purge.c
+++ src/purge.c
@@ -57,10 +57,12 @@
57 /*
58 ** Flags for the purge_artifact_list() function.
59 */
60 #if INTERFACE
61 #define PURGE_MOVETO_GRAVEYARD 0x0001 /* Move artifacts in graveyard */
 
 
62 #endif
63
64 /*
65 ** This routine purges multiple artifacts from the repository, transfering
66 ** those artifacts into the PURGEITEM table.
@@ -105,10 +107,20 @@
105 assert( g.repositoryOpen ); /* Main database must already be open */
106 db_begin_transaction();
107 z = sqlite3_mprintf("IN \"%w\"", zTab);
108 describe_artifacts(z);
109 sqlite3_free(z);
 
 
 
 
 
 
 
 
 
 
110
111 /* Make sure we are not removing a manifest that is the baseline of some
112 ** manifest that is being left behind. This step is not strictly necessary.
113 ** is is just a safety check. */
114 if( purge_baseline_out_from_under_delta(zTab) ){
@@ -196,10 +208,17 @@
196 db_finalize(&q);
197 /* db_multi_exec("DROP TABLE \"%w_tickets\"", zTab); */
198
199 /* Mission accomplished */
200 db_end_transaction(0);
 
 
 
 
 
 
 
201 return peid;
202 }
203
204 /*
205 ** The TEMP table named zTab contains RIDs for a set of check-ins.
@@ -435,13 +454,18 @@
435 **
436 ** The purge command removes content from a repository and stores that content
437 ** in a "graveyard". The graveyard exists so that content can be recovered
438 ** using the "fossil purge undo" command.
439 **
440 ** fossil purge artifact UUID... ?OPTIONS?
 
 
 
 
441 **
442 ** TBD...
 
443 **
444 ** fossil purge cat UUID...
445 **
446 ** Write the content of one or more artifacts in the graveyard onto
447 ** standard output.
@@ -451,26 +475,27 @@
451 ** Move the check-ins or branches identified by TAGS and all of
452 ** their descendants out of the repository and into the graveyard.
453 ** If TAGS includes a branch name then it means all the check-ins
454 ** on the most recent occurrence of that branch.
455 **
456 ** --explain Make no changes, but show what would happen.
457 ** --dry-run Make no changes.
458 **
459 ** fossil purge files NAME ... ?OPTIONS?
460 **
461 ** TBD...
 
 
 
462 **
463 ** fossil purge list|ls ?-l?
464 **
465 ** Show the graveyard of prior purges. The -l option gives more
466 ** detail in the output.
467 **
468 ** fossil purge obliterate ID...
469 **
470 ** Remove one or more purge events from the graveyard. Once a purge
471 ** event is obliterated, it can no longer be undone.
 
472 **
473 ** fossil purge tickets NAME ... ?OPTIONS?
474 **
475 ** TBD...
476 **
@@ -480,10 +505,15 @@
480 **
481 ** fossil purge wiki NAME ... ?OPTIONS?
482 **
483 ** TBD...
484 **
 
 
 
 
 
485 ** SUMMARY:
486 ** fossil purge artifacts UUID.. [OPTIONS]
487 ** fossil purge cat UUID...
488 ** fossil purge checkins TAGS... [OPTIONS]
489 ** fossil purge files FILENAME... [OPTIONS]
@@ -492,19 +522,34 @@
492 ** fossil purge tickets NAME... [OPTIONS]
493 ** fossil purge undo ID
494 ** fossil purge wiki NAME... [OPTIONS]
495 */
496 void purge_cmd(void){
 
497 const char *zSubcmd;
498 int n;
 
499 Stmt q;
 
500 if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?");
501 zSubcmd = g.argv[2];
502 db_find_and_open_repository(0,0);
503 n = (int)strlen(zSubcmd);
 
 
 
504 if( strncmp(zSubcmd, "artifacts", n)==0 ){
505 fossil_fatal("not yet implemented....");
 
 
 
 
 
 
 
 
 
506 }else if( strncmp(zSubcmd, "cat", n)==0 ){
507 int i, piid;
508 Blob content;
509 if( g.argc<4 ) usage("cat UUID...");
510 for(i=3; i<g.argc; i++){
@@ -514,41 +559,46 @@
514 purge_extract_item(piid, &content);
515 blob_write_to_file(&content, "-");
516 blob_reset(&content);
517 }
518 }else if( strncmp(zSubcmd, "checkins", n)==0 ){
519 int explainOnly = find_option("explain",0,0)!=0;
520 int dryRun = find_option("dry-run",0,0)!=0;
521 int i;
522 int vid;
523 int nCkin;
524 int nArtifact;
 
525 verify_all_options();
526 db_begin_transaction();
527 if( g.argc<=3 ) usage("checkin TAGS... [OPTIONS]");
528 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
529 for(i=3; i<g.argc; i++){
530 int r = name_to_typed_rid(g.argv[i], "br");
531 compute_descendants(r, 1000000000);
532 }
533 vid = db_lget_int("checkout",0);
534 if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
535 fossil_fatal("cannot purge the current checkout");
536 }
537 nCkin = db_int(0, "SELECT count(*) FROM ok");
538 find_checkin_associates("ok", 1);
539 nArtifact = db_int(0, "SELECT count(*) FROM ok");
540 describe_artifacts_to_stdout("IN ok", 0);
541 if( !explainOnly ){
542 int peid = purge_artifact_list("ok","",PURGE_MOVETO_GRAVEYARD);
543 fossil_print("%d check-ins and %d artifacts purged.\n", nCkin, nArtifact);
544 fossil_print("undoable using \"%s purge undo %d\".\n",
545 g.nameOfExe, peid);
546 }
547 db_end_transaction(explainOnly||dryRun);
548 }else if( strncmp(zSubcmd, "files", n)==0 ){
549 fossil_fatal("not yet implemented....");
 
 
 
 
 
 
 
 
550 }else if( strncmp(zSubcmd, "list", n)==0 || strcmp(zSubcmd,"ls")==0 ){
551 int showDetail = find_option("l","l",0)!=0;
552 if( !db_table_exists("repository","purgeevent") ) return;
553 db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch',toLocal())"
554 " FROM purgeevent");
@@ -559,11 +609,23 @@
559 }
560 }
561 db_finalize(&q);
562 }else if( strncmp(zSubcmd, "obliterate", n)==0 ){
563 int i;
 
564 if( g.argc<4 ) usage("obliterate ID...");
 
 
 
 
 
 
 
 
 
 
 
565 db_begin_transaction();
566 for(i=3; i<g.argc; i++){
567 int peid = atoi(g.argv[i]);
568 if( !db_exists("SELECT 1 FROM purgeevent WHERE peid=%d",peid) ){
569 fossil_fatal("no such purge event: %s", g.argv[i]);
@@ -579,35 +641,37 @@
579 fossil_fatal("not yet implemented....");
580 }else if( strncmp(zSubcmd, "undo", n)==0 ){
581 int peid;
582 if( g.argc!=4 ) usage("undo ID");
583 peid = atoi(g.argv[3]);
584 db_begin_transaction();
585 db_multi_exec(
586 "CREATE TEMP TABLE ix("
587 " piid INTEGER PRIMARY KEY,"
588 " srcid INTEGER"
589 ");"
590 "CREATE INDEX ixsrcid ON ix(srcid);"
591 "INSERT INTO ix(piid,srcid) "
592 " SELECT piid, coalesce(srcid,0) FROM purgeitem WHERE peid=%d;",
593 peid
594 );
595 db_multi_exec(
596 "DELETE FROM shun"
597 " WHERE uuid IN (SELECT uuid FROM purgeitem WHERE peid=%d);",
598 peid
599 );
600 manifest_crosslink_begin();
601 purge_item_resurrect(0, 0);
602 manifest_crosslink_end(0);
603 db_multi_exec("DELETE FROM purgeevent WHERE peid=%d", peid);
604 db_multi_exec("DELETE FROM purgeitem WHERE peid=%d", peid);
605 db_end_transaction(0);
 
 
606 }else if( strncmp(zSubcmd, "wiki", n)==0 ){
607 fossil_fatal("not yet implemented....");
608 }else{
609 fossil_fatal("unknown subcommand \"%s\".\n"
610 "should be one of: cat, checkins, files, list, obliterate,"
611 " tickets, undo, wiki", zSubcmd);
612 }
613 }
614
--- src/purge.c
+++ src/purge.c
@@ -57,10 +57,12 @@
57 /*
58 ** Flags for the purge_artifact_list() function.
59 */
60 #if INTERFACE
61 #define PURGE_MOVETO_GRAVEYARD 0x0001 /* Move artifacts in graveyard */
62 #define PURGE_EXPLAIN_ONLY 0x0002 /* Show what would have happened */
63 #define PURGE_PRINT_SUMMARY 0x0004 /* Print a summary report at end */
64 #endif
65
66 /*
67 ** This routine purges multiple artifacts from the repository, transfering
68 ** those artifacts into the PURGEITEM table.
@@ -105,10 +107,20 @@
107 assert( g.repositoryOpen ); /* Main database must already be open */
108 db_begin_transaction();
109 z = sqlite3_mprintf("IN \"%w\"", zTab);
110 describe_artifacts(z);
111 sqlite3_free(z);
112 describe_artifacts_to_stdout(0, 0);
113
114 /* The explain-only flags causes this routine to list the artifacts
115 ** that would have been purged but to not actually make any changes
116 ** to the repository.
117 */
118 if( purgeFlags & PURGE_EXPLAIN_ONLY ){
119 db_end_transaction(0);
120 return 0;
121 }
122
123 /* Make sure we are not removing a manifest that is the baseline of some
124 ** manifest that is being left behind. This step is not strictly necessary.
125 ** is is just a safety check. */
126 if( purge_baseline_out_from_under_delta(zTab) ){
@@ -196,10 +208,17 @@
208 db_finalize(&q);
209 /* db_multi_exec("DROP TABLE \"%w_tickets\"", zTab); */
210
211 /* Mission accomplished */
212 db_end_transaction(0);
213
214 if( purgeFlags & PURGE_PRINT_SUMMARY ){
215 fossil_print("%d artifacts purged\n",
216 db_int(0, "SELECT count(*) FROM \"%w\";", zTab));
217 fossil_print("undoable using \"%s purge undo %d\".\n",
218 g.nameOfExe, peid);
219 }
220 return peid;
221 }
222
223 /*
224 ** The TEMP table named zTab contains RIDs for a set of check-ins.
@@ -435,13 +454,18 @@
454 **
455 ** The purge command removes content from a repository and stores that content
456 ** in a "graveyard". The graveyard exists so that content can be recovered
457 ** using the "fossil purge undo" command.
458 **
459 ** ==== WARNING: This command can potentially destroy historical data and ====
460 ** ==== leave your repository in a goofy state. Know what you are doing! ====
461 ** ==== Make a backup of your repository before using this command! ====
462 **
463 ** fossil purge artifacts UUID... ?OPTIONS?
464 **
465 ** Move arbitrary artifacts identified by the UUID list into the
466 ** graveyard.
467 **
468 ** fossil purge cat UUID...
469 **
470 ** Write the content of one or more artifacts in the graveyard onto
471 ** standard output.
@@ -451,26 +475,27 @@
475 ** Move the check-ins or branches identified by TAGS and all of
476 ** their descendants out of the repository and into the graveyard.
477 ** If TAGS includes a branch name then it means all the check-ins
478 ** on the most recent occurrence of that branch.
479 **
 
 
 
480 ** fossil purge files NAME ... ?OPTIONS?
481 **
482 ** Move all instances of files called NAME into the graveyard.
483 ** NAME should be the name of the file relative to the root of the
484 ** repository. If NAME is a directory, then all files within that
485 ** directory are moved.
486 **
487 ** fossil purge list|ls ?-l?
488 **
489 ** Show the graveyard of prior purges. The -l option gives more
490 ** detail in the output.
491 **
492 ** fossil purge obliterate ID... ?--force?
493 **
494 ** Remove one or more purge events from the graveyard. Once a purge
495 ** event is obliterated, it can no longer be undone. The --force
496 ** option suppresses the confirmation prompt.
497 **
498 ** fossil purge tickets NAME ... ?OPTIONS?
499 **
500 ** TBD...
501 **
@@ -480,10 +505,15 @@
505 **
506 ** fossil purge wiki NAME ... ?OPTIONS?
507 **
508 ** TBD...
509 **
510 ** COMMON OPTIONS:
511 **
512 ** --explain Make no changes, but show what would happen.
513 ** --dry-run An alias for --explain
514 **
515 ** SUMMARY:
516 ** fossil purge artifacts UUID.. [OPTIONS]
517 ** fossil purge cat UUID...
518 ** fossil purge checkins TAGS... [OPTIONS]
519 ** fossil purge files FILENAME... [OPTIONS]
@@ -492,19 +522,34 @@
522 ** fossil purge tickets NAME... [OPTIONS]
523 ** fossil purge undo ID
524 ** fossil purge wiki NAME... [OPTIONS]
525 */
526 void purge_cmd(void){
527 int purgeFlags = PURGE_MOVETO_GRAVEYARD | PURGE_PRINT_SUMMARY;
528 const char *zSubcmd;
529 int n;
530 int i;
531 Stmt q;
532
533 if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?");
534 zSubcmd = g.argv[2];
535 db_find_and_open_repository(0,0);
536 n = (int)strlen(zSubcmd);
537 if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){
538 purgeFlags |= PURGE_EXPLAIN_ONLY;
539 }
540 if( strncmp(zSubcmd, "artifacts", n)==0 ){
541 verify_all_options();
542 db_begin_transaction();
543 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
544 for(i=3; i<g.argc; i++){
545 int r = name_to_typed_rid(g.argv[i], "");
546 db_multi_exec("INSERT OR IGNORE INTO ok(rid) VALUES(%d);", r);
547 }
548 describe_artifacts_to_stdout("IN ok", 0);
549 purge_artifact_list("ok", "", purgeFlags);
550 db_end_transaction(0);
551 }else if( strncmp(zSubcmd, "cat", n)==0 ){
552 int i, piid;
553 Blob content;
554 if( g.argc<4 ) usage("cat UUID...");
555 for(i=3; i<g.argc; i++){
@@ -514,41 +559,46 @@
559 purge_extract_item(piid, &content);
560 blob_write_to_file(&content, "-");
561 blob_reset(&content);
562 }
563 }else if( strncmp(zSubcmd, "checkins", n)==0 ){
 
 
 
564 int vid;
565 if( find_option("explain",0,0)!=0 || find_option("dry-run",0,0)!=0 ){
566 purgeFlags |= PURGE_EXPLAIN_ONLY;
567 }
568 verify_all_options();
569 db_begin_transaction();
570 if( g.argc<=3 ) usage("checkins TAGS... [OPTIONS]");
571 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
572 for(i=3; i<g.argc; i++){
573 int r = name_to_typed_rid(g.argv[i], "br");
574 compute_descendants(r, 1000000000);
575 }
576 vid = db_lget_int("checkout",0);
577 if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
578 fossil_fatal("cannot purge the current checkout");
579 }
 
580 find_checkin_associates("ok", 1);
581 describe_artifacts_to_stdout("IN ok", 0);
582 purge_artifact_list("ok", "", purgeFlags);
583 db_end_transaction(0);
584 }else if( strncmp(zSubcmd, "files", n)==0 ){
585 verify_all_options();
586 db_begin_transaction();
587 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
588 for(i=3; i<g.argc; i++){
589 db_multi_exec(
590 "INSERT OR IGNORE INTO ok(rid) "
591 " SELECT fid FROM mlink, filename"
592 " WHERE mlink.fnid=filename.fnid"
593 " AND (filename.name=%Q OR filename.name GLOB '%q/*')",
594 g.argv[i], g.argv[i]
595 );
596 }
597 describe_artifacts_to_stdout("IN ok", 0);
598 purge_artifact_list("ok", "", purgeFlags);
599 db_end_transaction(0);
600 }else if( strncmp(zSubcmd, "list", n)==0 || strcmp(zSubcmd,"ls")==0 ){
601 int showDetail = find_option("l","l",0)!=0;
602 if( !db_table_exists("repository","purgeevent") ) return;
603 db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch',toLocal())"
604 " FROM purgeevent");
@@ -559,11 +609,23 @@
609 }
610 }
611 db_finalize(&q);
612 }else if( strncmp(zSubcmd, "obliterate", n)==0 ){
613 int i;
614 int bForce = find_option("force","f",0)!=0;
615 if( g.argc<4 ) usage("obliterate ID...");
616 if( !bForce ){
617 Blob ans;
618 char cReply;
619 prompt_user(
620 "Obliterating the graveyard will permanently delete information.\n"
621 "Changes cannot be undone. Continue (y/N)? ", &ans);
622 cReply = blob_str(&ans)[0];
623 if( cReply!='y' && cReply!='Y' ){
624 fossil_exit(1);
625 }
626 }
627 db_begin_transaction();
628 for(i=3; i<g.argc; i++){
629 int peid = atoi(g.argv[i]);
630 if( !db_exists("SELECT 1 FROM purgeevent WHERE peid=%d",peid) ){
631 fossil_fatal("no such purge event: %s", g.argv[i]);
@@ -579,35 +641,37 @@
641 fossil_fatal("not yet implemented....");
642 }else if( strncmp(zSubcmd, "undo", n)==0 ){
643 int peid;
644 if( g.argc!=4 ) usage("undo ID");
645 peid = atoi(g.argv[3]);
646 if( (purgeFlags & PURGE_EXPLAIN_ONLY)==0 ){
647 db_begin_transaction();
648 db_multi_exec(
649 "CREATE TEMP TABLE ix("
650 " piid INTEGER PRIMARY KEY,"
651 " srcid INTEGER"
652 ");"
653 "CREATE INDEX ixsrcid ON ix(srcid);"
654 "INSERT INTO ix(piid,srcid) "
655 " SELECT piid, coalesce(srcid,0) FROM purgeitem WHERE peid=%d;",
656 peid
657 );
658 db_multi_exec(
659 "DELETE FROM shun"
660 " WHERE uuid IN (SELECT uuid FROM purgeitem WHERE peid=%d);",
661 peid
662 );
663 manifest_crosslink_begin();
664 purge_item_resurrect(0, 0);
665 manifest_crosslink_end(0);
666 db_multi_exec("DELETE FROM purgeevent WHERE peid=%d", peid);
667 db_multi_exec("DELETE FROM purgeitem WHERE peid=%d", peid);
668 db_end_transaction(0);
669 }
670 }else if( strncmp(zSubcmd, "wiki", n)==0 ){
671 fossil_fatal("not yet implemented....");
672 }else{
673 fossil_fatal("unknown subcommand \"%s\".\n"
674 "should be one of: cat, checkins, files, list, obliterate,"
675 " tickets, undo, wiki", zSubcmd);
676 }
677 }
678

Keyboard Shortcuts

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