Fossil SCM

Add the "fossil purge cat" command for extracting individual artifacts from the graveyard.

drh 2014-11-25 14:00 UTC DBP-workflow
Commit 4b902843fc797b49cdbb85a30aab62adbf1f1c08
1 file changed +76 -2
+76 -2
--- src/purge.c
+++ src/purge.c
@@ -243,11 +243,11 @@
243243
}
244244
245245
/*
246246
** Display the content of a single purge event.
247247
*/
248
-static void purge_event_content(int peid){
248
+static void purge_list_event_content(int peid){
249249
Stmt q;
250250
sqlite3_int64 sz1 = 0;
251251
sqlite3_int64 sz2 = 0;
252252
db_prepare(&q, "SELECT piid, substr(uuid,1,16), srcid, isPrivate,"
253253
" sz, length(data)"
@@ -264,10 +264,67 @@
264264
sz2 += db_column_int(&q,5);
265265
}
266266
db_finalize(&q);
267267
fossil_print("%.11c%16s%.8c%10lld %10lld\n", ' ', "Total:", ' ', sz1, sz2);
268268
}
269
+
270
+/*
271
+** Extract the content for purgeitem number piid into a Blob. Return
272
+** the number of errors.
273
+*/
274
+static int purge_extract_item(
275
+ int piid, /* ID of the item to extract */
276
+ Blob *pOut, /* Write the content into this blob */
277
+ Blob *pHash, /* If not NULL, write the hash into this blob */
278
+ int *pIsPrivate /* If not NULL, write the isPrivate flag here */
279
+){
280
+ Stmt q;
281
+ int srcid;
282
+ Blob h1, h2, x;
283
+ static Bag busy;
284
+
285
+ db_prepare(&q, "SELECT uuid, srcid, isPrivate, data FROM purgeitem"
286
+ " WHERE piid=%d", piid);
287
+ if( db_step(&q)!=SQLITE_ROW ){
288
+ db_finalize(&q);
289
+ fossil_fatal("missing purge-item %d", piid);
290
+ }
291
+ if( bag_find(&busy, piid) ) return 1;
292
+ if( pIsPrivate ) *pIsPrivate = db_column_int(&q, 2);
293
+ srcid = db_column_int(&q, 1);
294
+ blob_zero(pOut);
295
+ blob_zero(&x);
296
+ db_column_blob(&q, 3, &x);
297
+ blob_uncompress(&x, pOut);
298
+ blob_reset(&x);
299
+ if( srcid>0 ){
300
+ Blob baseline, out;
301
+ bag_insert(&busy, piid);
302
+ purge_extract_item(srcid, &baseline, 0, 0);
303
+ blob_zero(&out);
304
+ blob_delta_apply(&baseline, pOut, &out);
305
+ blob_reset(pOut);
306
+ *pOut = out;
307
+ blob_reset(&baseline);
308
+ }
309
+ bag_remove(&busy, piid);
310
+ blob_zero(&h1);
311
+ db_column_blob(&q, 0, &h1);
312
+ sha1sum_blob(pOut, &h2);
313
+ if( blob_compare(&h1, &h2)!=0 ){
314
+ fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
315
+ blob_str(&h1), blob_str(&h2));
316
+ }
317
+ if( pHash ){
318
+ *pHash = h1;
319
+ }else{
320
+ blob_reset(&h1);
321
+ }
322
+ blob_reset(&h2);
323
+ db_finalize(&q);
324
+ return 0;
325
+}
269326
270327
/*
271328
** COMMAND: purge
272329
**
273330
** The purge command is used to remove content from a repository into a
@@ -281,10 +338,14 @@
281338
**
282339
** fossil purge undo ID
283340
**
284341
** Restore the content previously removed by purge ID.
285342
**
343
+** fossil purge cat UUID ?FILENAME?
344
+**
345
+** Whow the content of artifact UUID from the graveyard
346
+**
286347
** fossil purge [checkin] TAGS... [--explain]
287348
**
288349
** Move the checkins identified by TAGS and all of their descendants
289350
** out of the repository and into the graveyard. If a TAG is a branch
290351
** name then it means all the checkins on that branch. If the --explain
@@ -293,10 +354,11 @@
293354
**
294355
** SUMMARY:
295356
** fossil purge [checkin] TAGS... [--explain]
296357
** fossil purge list
297358
** fossil purge undo ID
359
+** fossil purge cat UUID [FILENAME]
298360
*/
299361
void purge_cmd(void){
300362
const char *zSubcmd;
301363
int n;
302364
Stmt q;
@@ -310,16 +372,28 @@
310372
db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch','localtime')"
311373
" FROM purgeevent");
312374
while( db_step(&q)==SQLITE_ROW ){
313375
fossil_print("%4d on %s\n", db_column_int(&q,0), db_column_text(&q,1));
314376
if( showDetail ){
315
- purge_event_content(db_column_int(&q,0));
377
+ purge_list_event_content(db_column_int(&q,0));
316378
}
317379
}
318380
db_finalize(&q);
319381
}else if( strncmp(zSubcmd, "undo", n)==0 ){
320382
fossil_print("Not yet implemented...\n");
383
+ }else if( strncmp(zSubcmd, "cat", n)==0 ){
384
+ const char *zOutFile;
385
+ int piid;
386
+ Blob content;
387
+ if( g.argc!=4 && g.argc!=5 ) usage("cat UUID [FILENAME]");
388
+ zOutFile = g.argc==5 ? g.argv[4] : "-";
389
+ piid = db_int(0, "SELECT piid FROM purgeitem WHERE uuid LIKE '%q%%'",
390
+ g.argv[3]);
391
+ if( piid==0 ) fossil_fatal("no such item: %s", g.argv[3]);
392
+ purge_extract_item(piid, &content, 0, 0);
393
+ blob_write_to_file(&content, zOutFile);
394
+ blob_reset(&content);
321395
}else{
322396
int explainOnly = find_option("explain",0,0)!=0;
323397
int dryRun = find_option("dry-run",0,0)!=0;
324398
const char *zTag;
325399
int i;
326400
--- src/purge.c
+++ src/purge.c
@@ -243,11 +243,11 @@
243 }
244
245 /*
246 ** Display the content of a single purge event.
247 */
248 static void purge_event_content(int peid){
249 Stmt q;
250 sqlite3_int64 sz1 = 0;
251 sqlite3_int64 sz2 = 0;
252 db_prepare(&q, "SELECT piid, substr(uuid,1,16), srcid, isPrivate,"
253 " sz, length(data)"
@@ -264,10 +264,67 @@
264 sz2 += db_column_int(&q,5);
265 }
266 db_finalize(&q);
267 fossil_print("%.11c%16s%.8c%10lld %10lld\n", ' ', "Total:", ' ', sz1, sz2);
268 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
269
270 /*
271 ** COMMAND: purge
272 **
273 ** The purge command is used to remove content from a repository into a
@@ -281,10 +338,14 @@
281 **
282 ** fossil purge undo ID
283 **
284 ** Restore the content previously removed by purge ID.
285 **
 
 
 
 
286 ** fossil purge [checkin] TAGS... [--explain]
287 **
288 ** Move the checkins identified by TAGS and all of their descendants
289 ** out of the repository and into the graveyard. If a TAG is a branch
290 ** name then it means all the checkins on that branch. If the --explain
@@ -293,10 +354,11 @@
293 **
294 ** SUMMARY:
295 ** fossil purge [checkin] TAGS... [--explain]
296 ** fossil purge list
297 ** fossil purge undo ID
 
298 */
299 void purge_cmd(void){
300 const char *zSubcmd;
301 int n;
302 Stmt q;
@@ -310,16 +372,28 @@
310 db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch','localtime')"
311 " FROM purgeevent");
312 while( db_step(&q)==SQLITE_ROW ){
313 fossil_print("%4d on %s\n", db_column_int(&q,0), db_column_text(&q,1));
314 if( showDetail ){
315 purge_event_content(db_column_int(&q,0));
316 }
317 }
318 db_finalize(&q);
319 }else if( strncmp(zSubcmd, "undo", n)==0 ){
320 fossil_print("Not yet implemented...\n");
 
 
 
 
 
 
 
 
 
 
 
 
321 }else{
322 int explainOnly = find_option("explain",0,0)!=0;
323 int dryRun = find_option("dry-run",0,0)!=0;
324 const char *zTag;
325 int i;
326
--- src/purge.c
+++ src/purge.c
@@ -243,11 +243,11 @@
243 }
244
245 /*
246 ** Display the content of a single purge event.
247 */
248 static void purge_list_event_content(int peid){
249 Stmt q;
250 sqlite3_int64 sz1 = 0;
251 sqlite3_int64 sz2 = 0;
252 db_prepare(&q, "SELECT piid, substr(uuid,1,16), srcid, isPrivate,"
253 " sz, length(data)"
@@ -264,10 +264,67 @@
264 sz2 += db_column_int(&q,5);
265 }
266 db_finalize(&q);
267 fossil_print("%.11c%16s%.8c%10lld %10lld\n", ' ', "Total:", ' ', sz1, sz2);
268 }
269
270 /*
271 ** Extract the content for purgeitem number piid into a Blob. Return
272 ** the number of errors.
273 */
274 static int purge_extract_item(
275 int piid, /* ID of the item to extract */
276 Blob *pOut, /* Write the content into this blob */
277 Blob *pHash, /* If not NULL, write the hash into this blob */
278 int *pIsPrivate /* If not NULL, write the isPrivate flag here */
279 ){
280 Stmt q;
281 int srcid;
282 Blob h1, h2, x;
283 static Bag busy;
284
285 db_prepare(&q, "SELECT uuid, srcid, isPrivate, data FROM purgeitem"
286 " WHERE piid=%d", piid);
287 if( db_step(&q)!=SQLITE_ROW ){
288 db_finalize(&q);
289 fossil_fatal("missing purge-item %d", piid);
290 }
291 if( bag_find(&busy, piid) ) return 1;
292 if( pIsPrivate ) *pIsPrivate = db_column_int(&q, 2);
293 srcid = db_column_int(&q, 1);
294 blob_zero(pOut);
295 blob_zero(&x);
296 db_column_blob(&q, 3, &x);
297 blob_uncompress(&x, pOut);
298 blob_reset(&x);
299 if( srcid>0 ){
300 Blob baseline, out;
301 bag_insert(&busy, piid);
302 purge_extract_item(srcid, &baseline, 0, 0);
303 blob_zero(&out);
304 blob_delta_apply(&baseline, pOut, &out);
305 blob_reset(pOut);
306 *pOut = out;
307 blob_reset(&baseline);
308 }
309 bag_remove(&busy, piid);
310 blob_zero(&h1);
311 db_column_blob(&q, 0, &h1);
312 sha1sum_blob(pOut, &h2);
313 if( blob_compare(&h1, &h2)!=0 ){
314 fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
315 blob_str(&h1), blob_str(&h2));
316 }
317 if( pHash ){
318 *pHash = h1;
319 }else{
320 blob_reset(&h1);
321 }
322 blob_reset(&h2);
323 db_finalize(&q);
324 return 0;
325 }
326
327 /*
328 ** COMMAND: purge
329 **
330 ** The purge command is used to remove content from a repository into a
@@ -281,10 +338,14 @@
338 **
339 ** fossil purge undo ID
340 **
341 ** Restore the content previously removed by purge ID.
342 **
343 ** fossil purge cat UUID ?FILENAME?
344 **
345 ** Whow the content of artifact UUID from the graveyard
346 **
347 ** fossil purge [checkin] TAGS... [--explain]
348 **
349 ** Move the checkins identified by TAGS and all of their descendants
350 ** out of the repository and into the graveyard. If a TAG is a branch
351 ** name then it means all the checkins on that branch. If the --explain
@@ -293,10 +354,11 @@
354 **
355 ** SUMMARY:
356 ** fossil purge [checkin] TAGS... [--explain]
357 ** fossil purge list
358 ** fossil purge undo ID
359 ** fossil purge cat UUID [FILENAME]
360 */
361 void purge_cmd(void){
362 const char *zSubcmd;
363 int n;
364 Stmt q;
@@ -310,16 +372,28 @@
372 db_prepare(&q, "SELECT peid, datetime(ctime,'unixepoch','localtime')"
373 " FROM purgeevent");
374 while( db_step(&q)==SQLITE_ROW ){
375 fossil_print("%4d on %s\n", db_column_int(&q,0), db_column_text(&q,1));
376 if( showDetail ){
377 purge_list_event_content(db_column_int(&q,0));
378 }
379 }
380 db_finalize(&q);
381 }else if( strncmp(zSubcmd, "undo", n)==0 ){
382 fossil_print("Not yet implemented...\n");
383 }else if( strncmp(zSubcmd, "cat", n)==0 ){
384 const char *zOutFile;
385 int piid;
386 Blob content;
387 if( g.argc!=4 && g.argc!=5 ) usage("cat UUID [FILENAME]");
388 zOutFile = g.argc==5 ? g.argv[4] : "-";
389 piid = db_int(0, "SELECT piid FROM purgeitem WHERE uuid LIKE '%q%%'",
390 g.argv[3]);
391 if( piid==0 ) fossil_fatal("no such item: %s", g.argv[3]);
392 purge_extract_item(piid, &content, 0, 0);
393 blob_write_to_file(&content, zOutFile);
394 blob_reset(&content);
395 }else{
396 int explainOnly = find_option("explain",0,0)!=0;
397 int dryRun = find_option("dry-run",0,0)!=0;
398 const char *zTag;
399 int i;
400

Keyboard Shortcuts

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