Fossil

Check-in [4b902843]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Add the "fossil purge cat" command for extracting individual artifacts from the graveyard.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | DBP-workflow
Files: files | file ages | folders
SHA1: 4b902843fc797b49cdbb85a30aab62adbf1f1c08
User & Date: drh 2014-11-25 14:00:39
Context
2014-11-25
16:07
Implement the "fossil purge undo" command. check-in: eb36d28a user: drh tags: DBP-workflow
14:00
Add the "fossil purge cat" command for extracting individual artifacts from the graveyard. check-in: 4b902843 user: drh tags: DBP-workflow
12:37
Use delta compression on elements of a single purgeevent in the graveyard. Record whether or not elements were originally private when moving them into the graveyard. check-in: 916cd4b8 user: drh tags: DBP-workflow
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/purge.c.

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
262
263
264
265
266
267
268

























































269
270
271
272
273
274
275
...
279
280
281
282
283
284
285




286
287
288
289
290
291
292
293
294
295
296
297

298
299
300
301
302
303
304
...
308
309
310
311
312
313
314
315
316
317
318
319
320












321
322
323
324
325
326
327

  db_end_transaction(0);
}

/*
** Display the content of a single purge event.
*/
static void purge_event_content(int peid){
  Stmt q;
  sqlite3_int64 sz1 = 0;
  sqlite3_int64 sz2 = 0;
  db_prepare(&q, "SELECT piid, substr(uuid,1,16), srcid, isPrivate,"
                 "       sz, length(data)"
                 " FROM purgeitem WHERE peid=%d", peid);
  while( db_step(&q)==SQLITE_ROW ){
................................................................................
       db_column_int(&q,5));
    sz1 += db_column_int(&q,4);
    sz2 += db_column_int(&q,5);
  }
  db_finalize(&q);
  fossil_print("%.11c%16s%.8c%10lld %10lld\n", ' ', "Total:", ' ', sz1, sz2);
}


























































/*
** COMMAND: purge
**
** The purge command is used to remove content from a repository into a
** "graveyard" and also to show manage the graveyard and optionally restored
** content into the repository from the graveyard.
................................................................................
**      Show the graveyard of prior purges.  The -l option gives more
**      detail in the output.
**
**   fossil purge undo ID
**
**      Restore the content previously removed by purge ID.
**




**   fossil purge [checkin] TAGS... [--explain]
**
**      Move the checkins identified by TAGS and all of their descendants
**      out of the repository and into the graveyard.  If a TAG is a branch
**      name then it means all the checkins on that branch.  If the --explain
**      option appears, then the repository and graveyard are unchanged and
**      an explaination of what would have happened is shown instead.
**
** SUMMARY:
**   fossil purge [checkin] TAGS... [--explain]
**   fossil purge list
**   fossil purge undo ID

*/
void purge_cmd(void){
  const char *zSubcmd;
  int n;
  Stmt q;
  if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?");
  zSubcmd = g.argv[2];
................................................................................
    int showDetail = find_option("l","l",0)!=0;
    if( db_int(-1,"PRAGMA table_info('purgeevent')")<0 ) return;
    db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch','localtime')"
                   " 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_event_content(db_column_int(&q,0));
      }
    }
    db_finalize(&q);
  }else if( strncmp(zSubcmd, "undo", n)==0 ){
    fossil_print("Not yet implemented...\n");












  }else{
    int explainOnly = find_option("explain",0,0)!=0;
    int dryRun = find_option("dry-run",0,0)!=0;
    const char *zTag;
    int i;
    int vid;
    int nCkin;







|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>












>







 







|





>
>
>
>
>
>
>
>
>
>
>
>







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
...
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
...
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401

  db_end_transaction(0);
}

/*
** Display the content of a single purge event.
*/
static void purge_list_event_content(int peid){
  Stmt q;
  sqlite3_int64 sz1 = 0;
  sqlite3_int64 sz2 = 0;
  db_prepare(&q, "SELECT piid, substr(uuid,1,16), srcid, isPrivate,"
                 "       sz, length(data)"
                 " FROM purgeitem WHERE peid=%d", peid);
  while( db_step(&q)==SQLITE_ROW ){
................................................................................
       db_column_int(&q,5));
    sz1 += db_column_int(&q,4);
    sz2 += db_column_int(&q,5);
  }
  db_finalize(&q);
  fossil_print("%.11c%16s%.8c%10lld %10lld\n", ' ', "Total:", ' ', sz1, sz2);
}

/*
** Extract the content for purgeitem number piid into a Blob.  Return
** the number of errors.
*/
static int purge_extract_item(
  int piid,            /* ID of the item to extract */
  Blob *pOut,          /* Write the content into this blob */
  Blob *pHash,         /* If not NULL, write the hash into this blob */
  int *pIsPrivate      /* If not NULL, write the isPrivate flag here */
){
  Stmt q;
  int srcid;
  Blob h1, h2, x;
  static Bag busy;

  db_prepare(&q, "SELECT uuid, srcid, isPrivate, data FROM purgeitem"
                 " WHERE piid=%d", piid);
  if( db_step(&q)!=SQLITE_ROW ){
    db_finalize(&q);
    fossil_fatal("missing purge-item %d", piid);
  }
  if( bag_find(&busy, piid) ) return 1;
  if( pIsPrivate ) *pIsPrivate = db_column_int(&q, 2);
  srcid = db_column_int(&q, 1);
  blob_zero(pOut);
  blob_zero(&x);
  db_column_blob(&q, 3, &x);
  blob_uncompress(&x, pOut);
  blob_reset(&x);
  if( srcid>0 ){
    Blob baseline, out;
    bag_insert(&busy, piid);
    purge_extract_item(srcid, &baseline, 0, 0);
    blob_zero(&out);
    blob_delta_apply(&baseline, pOut, &out);
    blob_reset(pOut);
    *pOut = out;
    blob_reset(&baseline);
  }
  bag_remove(&busy, piid);
  blob_zero(&h1);
  db_column_blob(&q, 0, &h1);
  sha1sum_blob(pOut, &h2);
  if( blob_compare(&h1, &h2)!=0 ){
    fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
                 blob_str(&h1), blob_str(&h2));
  }
  if( pHash ){
    *pHash = h1;
  }else{
    blob_reset(&h1);
  }
  blob_reset(&h2);
  db_finalize(&q);
  return 0;
}

/*
** COMMAND: purge
**
** The purge command is used to remove content from a repository into a
** "graveyard" and also to show manage the graveyard and optionally restored
** content into the repository from the graveyard.
................................................................................
**      Show the graveyard of prior purges.  The -l option gives more
**      detail in the output.
**
**   fossil purge undo ID
**
**      Restore the content previously removed by purge ID.
**
**   fossil purge cat UUID ?FILENAME?
**
**      Whow the content of artifact UUID from the graveyard
**
**   fossil purge [checkin] TAGS... [--explain]
**
**      Move the checkins identified by TAGS and all of their descendants
**      out of the repository and into the graveyard.  If a TAG is a branch
**      name then it means all the checkins on that branch.  If the --explain
**      option appears, then the repository and graveyard are unchanged and
**      an explaination of what would have happened is shown instead.
**
** SUMMARY:
**   fossil purge [checkin] TAGS... [--explain]
**   fossil purge list
**   fossil purge undo ID
**   fossil purge cat UUID [FILENAME]
*/
void purge_cmd(void){
  const char *zSubcmd;
  int n;
  Stmt q;
  if( g.argc<3 ) usage("SUBCOMMAND ?ARGS?");
  zSubcmd = g.argv[2];
................................................................................
    int showDetail = find_option("l","l",0)!=0;
    if( db_int(-1,"PRAGMA table_info('purgeevent')")<0 ) return;
    db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch','localtime')"
                   " 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, "undo", n)==0 ){
    fossil_print("Not yet implemented...\n");
  }else if( strncmp(zSubcmd, "cat", n)==0 ){
    const char *zOutFile;
    int piid;
    Blob content;
    if( g.argc!=4 && g.argc!=5 ) usage("cat UUID [FILENAME]");
    zOutFile = g.argc==5 ? g.argv[4] : "-";
    piid = db_int(0, "SELECT piid FROM purgeitem WHERE uuid LIKE '%q%%'",
                     g.argv[3]);
    if( piid==0 ) fossil_fatal("no such item: %s", g.argv[3]);
    purge_extract_item(piid, &content, 0, 0);
    blob_write_to_file(&content, zOutFile);
    blob_reset(&content);
  }else{
    int explainOnly = find_option("explain",0,0)!=0;
    int dryRun = find_option("dry-run",0,0)!=0;
    const char *zTag;
    int i;
    int vid;
    int nCkin;