Fossil SCM
Improved select of delta basis files for "bundle export". Added the --standalone option to "bundle export". Improved help messages for both the bundle and purge commands.
Commit
eb3ae3d619cfb00c55321045d6dae668fc4ee6bc
Parent
8abe20a137fa953…
2 files changed
+147
-46
+19
-16
+147
-46
| --- src/bundle.c | ||
| +++ src/bundle.c | ||
| @@ -241,45 +241,133 @@ | ||
| 241 | 241 | } |
| 242 | 242 | |
| 243 | 243 | /* fossil bundle export BUNDLE ?OPTIONS? |
| 244 | 244 | ** |
| 245 | 245 | ** OPTIONS: |
| 246 | -** --branch BRANCH | |
| 247 | -** --from TAG | |
| 248 | -** --to TAG | |
| 246 | +** --branch BRANCH --from TAG --to TAG | |
| 249 | 247 | ** --checkin TAG |
| 248 | +** --standalone | |
| 250 | 249 | */ |
| 251 | 250 | static void bundle_export_cmd(void){ |
| 251 | + int bStandalone = find_option("standalone",0,0)!=0; | |
| 252 | + int mnToBundle; /* Minimum RID in the bundle */ | |
| 253 | + Stmt q; | |
| 254 | + | |
| 255 | + /* Decode the arguments (like --branch) that specify which artifacts | |
| 256 | + ** should be in the bundle */ | |
| 252 | 257 | db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);"); |
| 253 | 258 | subtree_from_arguments("tobundle"); |
| 259 | + find_checkin_associates("tobundle"); | |
| 254 | 260 | verify_all_options(); |
| 261 | + | |
| 262 | + /* Create the new bundle */ | |
| 255 | 263 | bundle_attach_file(g.argv[3], "b1", 1); |
| 256 | - find_checkin_associates("tobundle"); | |
| 257 | 264 | db_begin_transaction(); |
| 258 | - db_multi_exec( | |
| 259 | - "REPLACE INTO bblob(blobid,uuid,sz,delta,data) " | |
| 260 | - " SELECT" | |
| 261 | - " tobundle.rid," | |
| 262 | - " b1.uuid," | |
| 263 | - " b1.size," | |
| 264 | - " CASE WHEN delta.srcid NOT IN tobundle" | |
| 265 | - " THEN (SELECT uuid FROM blob WHERE rid=delta.srcid)" | |
| 266 | - " ELSE delta.srcid END," | |
| 267 | - " b1.content" | |
| 268 | - " FROM tobundle" | |
| 269 | - " JOIN blob AS b1 ON b1.rid=tobundle.rid" | |
| 270 | - " LEFT JOIN delta ON delta.rid=tobundle.rid" | |
| 271 | - ); | |
| 265 | + | |
| 266 | + /* Add 'mtime' and 'project-code' entries to the bconfig table */ | |
| 272 | 267 | db_multi_exec( |
| 273 | 268 | "INSERT INTO bconfig(bcname,bcvalue)" |
| 274 | 269 | " VALUES('mtime',datetime('now'));" |
| 275 | 270 | ); |
| 276 | 271 | db_multi_exec( |
| 277 | 272 | "INSERT INTO bconfig(bcname,bcvalue)" |
| 278 | 273 | " SELECT name, value FROM config" |
| 279 | 274 | " WHERE name IN ('project-code');" |
| 280 | 275 | ); |
| 276 | + | |
| 277 | + /* Directly copy content from the repository into the bundle as long | |
| 278 | + ** as the repository content is a delta from some other artifact that | |
| 279 | + ** is also in the bundle. | |
| 280 | + */ | |
| 281 | + db_multi_exec( | |
| 282 | + "REPLACE INTO bblob(blobid,uuid,sz,delta,data) " | |
| 283 | + " SELECT" | |
| 284 | + " tobundle.rid," | |
| 285 | + " blob.uuid," | |
| 286 | + " blob.size," | |
| 287 | + " delta.srcid," | |
| 288 | + " blob.content" | |
| 289 | + " FROM tobundle, blob, delta" | |
| 290 | + " WHERE blob.rid=tobundle.rid" | |
| 291 | + " AND delta.rid=tobundle.rid;" | |
| 292 | + ); | |
| 293 | + | |
| 294 | + /* For all the remaining artifacts, we need to construct their deltas | |
| 295 | + ** manually. | |
| 296 | + */ | |
| 297 | + mnToBundle = db_int(0,"SELECT min(rid) FROM tobundle"); | |
| 298 | + db_prepare(&q, | |
| 299 | + "SELECT rid FROM tobundle" | |
| 300 | + " WHERE rid NOT IN (SELECT blobid FROM bblob)" | |
| 301 | + " ORDER BY +rid;" | |
| 302 | + ); | |
| 303 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 304 | + Blob content; | |
| 305 | + int rid = db_column_int(&q,0); | |
| 306 | + int deltaFrom = 0; | |
| 307 | + | |
| 308 | + /* Get the raw, uncompressed content of the artifact into content */ | |
| 309 | + content_get(rid, &content); | |
| 310 | + | |
| 311 | + /* Try to find another artifact, not within the bundle, that is a | |
| 312 | + ** plausible candidate for being a delta basis for the content. Set | |
| 313 | + ** deltaFrom to the RID of that other artifact. Leave deltaFrom set | |
| 314 | + ** to zero if the content should not be delta-compressed | |
| 315 | + */ | |
| 316 | + if( !bStandalone ){ | |
| 317 | + if( db_exists("SELECT 1 FROM plink WHERE cid=%d",rid) ){ | |
| 318 | + deltaFrom = db_int(0, | |
| 319 | + "SELECT max(cid) FROM plink" | |
| 320 | + " WHERE cid<%d", mnToBundle); | |
| 321 | + }else{ | |
| 322 | + deltaFrom = db_int(0, | |
| 323 | + "SELECT max(fid) FROM mlink" | |
| 324 | + " WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)" | |
| 325 | + " AND fid<%d", rid, mnToBundle); | |
| 326 | + } | |
| 327 | + } | |
| 328 | + | |
| 329 | + /* Try to insert the insert the artifact as a delta | |
| 330 | + */ | |
| 331 | + if( deltaFrom ){ | |
| 332 | + Blob basis, delta; | |
| 333 | + content_get(deltaFrom, &basis); | |
| 334 | + blob_delta_create(&basis, &content, &delta); | |
| 335 | + if( blob_size(&delta)>0.9*blob_size(&content) ){ | |
| 336 | + deltaFrom = 0; | |
| 337 | + }else{ | |
| 338 | + Stmt ins; | |
| 339 | + blob_compress(&delta, &delta); | |
| 340 | + db_prepare(&ins, | |
| 341 | + "REPLACE INTO bblob(blobid,uuid,sz,delta,data)" | |
| 342 | + " SELECT %d, uuid, size, (SELECT uuid FROM blob WHERE rid=%d)," | |
| 343 | + " :delta FROM blob WHERE rid=%d", rid, deltaFrom, rid); | |
| 344 | + db_bind_blob(&ins, ":delta", &delta); | |
| 345 | + db_step(&ins); | |
| 346 | + db_finalize(&ins); | |
| 347 | + } | |
| 348 | + blob_reset(&basis); | |
| 349 | + blob_reset(&delta); | |
| 350 | + } | |
| 351 | + | |
| 352 | + /* If unable to insert the artifact as a delta, insert full-text */ | |
| 353 | + if( deltaFrom==0 ){ | |
| 354 | + Stmt ins; | |
| 355 | + blob_compress(&content, &content); | |
| 356 | + db_prepare(&ins, | |
| 357 | + "REPLACE INTO bblob(blobid,uuid,sz,delta,data)" | |
| 358 | + " SELECT rid, uuid, size, NULL, :content" | |
| 359 | + " FROM blob WHERE rid=%d", rid); | |
| 360 | + db_bind_blob(&ins, ":content", &content); | |
| 361 | + db_step(&ins); | |
| 362 | + db_finalize(&ins); | |
| 363 | + } | |
| 364 | + blob_reset(&content); | |
| 365 | + } | |
| 366 | + db_finalize(&q); | |
| 367 | + | |
| 368 | + | |
| 281 | 369 | db_end_transaction(0); |
| 282 | 370 | } |
| 283 | 371 | |
| 284 | 372 | |
| 285 | 373 | /* |
| @@ -417,68 +505,81 @@ | ||
| 417 | 505 | /* |
| 418 | 506 | ** COMMAND: bundle |
| 419 | 507 | ** |
| 420 | 508 | ** Usage: %fossil bundle SUBCOMMAND ARGS... |
| 421 | 509 | ** |
| 510 | +** fossil bundle append BUNDLE FILE... | |
| 511 | +** | |
| 512 | +** Add files named on the command line to BUNDLE. This subcommand has | |
| 513 | +** little practical use and is mostly intended for testing. | |
| 514 | +** | |
| 515 | +** fossil bundle cat BUNDLE UUID... | |
| 516 | +** | |
| 517 | +** Extract one or more artifacts from the bundle and write them | |
| 518 | +** consecutively on standard output. | |
| 519 | +** | |
| 422 | 520 | ** fossil bundle export BUNDLE ?OPTIONS? |
| 423 | 521 | ** |
| 424 | 522 | ** Generate a new bundle, in the file named BUNDLE, that constains a |
| 425 | 523 | ** subset of the check-ins in the repository (usually a single branch) |
| 426 | -** as determined by OPTIONS. OPTIONS include: | |
| 524 | +** described by the --branch, --from, --to, and/or --checkin options, | |
| 525 | +** at least one of which is required. If BUNDLE already exists, the | |
| 526 | +** specified content is added to the bundle. | |
| 427 | 527 | ** |
| 428 | 528 | ** --branch BRANCH Package all check-ins on BRANCH. |
| 429 | -** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2. | |
| 430 | -** --m COMMENT Add the comment to the bundle. | |
| 431 | -** --explain Just explain what would have happened. | |
| 529 | +** --from TAG1 --to TAG2 Package checkins between TAG1 and TAG2. | |
| 530 | +** --checkin TAG Package the single checkin TAG | |
| 531 | +** --standalone Do no use delta-encoding against | |
| 532 | +** artifacts not in the bundle | |
| 432 | 533 | ** |
| 433 | 534 | ** fossil bundle import BUNDLE ?--publish? |
| 434 | 535 | ** |
| 435 | -** Import the bundle in file BUNDLE into the repository. The --publish | |
| 436 | -** option makes the import public. The --explain option makes no changes | |
| 437 | -** to the repository but rather explains what would have happened. | |
| 536 | +** Import the bundle in file BUNDLE into the repository. By default, the | |
| 537 | +** imported files are private and will not sync. Use the --publish | |
| 538 | +** option makes the import public. | |
| 438 | 539 | ** |
| 439 | 540 | ** fossil bundle ls BUNDLE |
| 440 | 541 | ** |
| 441 | 542 | ** List the contents of BUNDLE on standard output |
| 442 | 543 | ** |
| 443 | -** fossil bundle append BUNDLE FILE... | |
| 444 | -** | |
| 445 | -** Add files named on the command line to BUNDLE. This subcommand has | |
| 446 | -** little practical use and is mostly intended for testing. | |
| 447 | -** | |
| 448 | -** fossil bundle cat BUNDLE UUID ?FILE? | |
| 449 | -** | |
| 450 | -** Extract an artifact from the bundle. Write it into FILE, or onto | |
| 451 | -** standard output if FILE is omitted. | |
| 544 | +** fossil bundle purge BUNDLE | |
| 545 | +** | |
| 546 | +** Remove all files found in BUNDLE from the repository. This has | |
| 547 | +** the effect of undoing a "fossil bundle import". | |
| 452 | 548 | ** |
| 453 | 549 | ** SUMMARY: |
| 454 | -** fossil bundle export BUNDLEFILE ?OPTIONS? | |
| 455 | -** --branch BRANCH | |
| 456 | -** --from TAG1 --to TAG2 | |
| 457 | -** --explain | |
| 458 | -** fossil bundle import BUNDLEFILE ?OPTIONS? | |
| 459 | -** --publish | |
| 460 | -** --explain | |
| 461 | -** fossil bundle ls BUNDLEFILE | |
| 550 | +** fossil bundle append BUNDLE FILE... Add files to BUNDLE | |
| 551 | +** fossil bundle cat BUNDLE UUID... Extract file from BUNDLE | |
| 552 | +** fossil bundle export BUNDLE ?OPTIONS? Create a new BUNDLE | |
| 553 | +** --branch BRANCH --from TAG1 --to TAG2 Checkins to include | |
| 554 | +** --checkin TAG Use only checkin TAG | |
| 555 | +** --standalone Omit dependencies | |
| 556 | +** fossil bundle import BUNDLE ?OPTIONS? Import a bundle | |
| 557 | +** --publish Publish the import | |
| 558 | +** --force Cross-repo import | |
| 559 | +** fossil bundle ls BUNDLE List content of a bundle | |
| 560 | +** fossil bundle purge BUNDLE Undo an import | |
| 462 | 561 | */ |
| 463 | 562 | void bundle_cmd(void){ |
| 464 | 563 | const char *zSubcmd; |
| 465 | 564 | const char *zBundleFile; |
| 466 | 565 | int n; |
| 467 | 566 | if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?ARGUMENTS?"); |
| 468 | 567 | zSubcmd = g.argv[2]; |
| 469 | 568 | db_find_and_open_repository(0,0); |
| 470 | 569 | n = (int)strlen(zSubcmd); |
| 471 | - if( strncmp(zSubcmd, "export", n)==0 ){ | |
| 570 | + if( strncmp(zSubcmd, "append", n)==0 ){ | |
| 571 | + bundle_append_cmd(); | |
| 572 | + }else if( strncmp(zSubcmd, "cat", n)==0 ){ | |
| 573 | + fossil_print("Not yet implemented...\n"); | |
| 574 | + }else if( strncmp(zSubcmd, "export", n)==0 ){ | |
| 472 | 575 | bundle_export_cmd(); |
| 473 | 576 | }else if( strncmp(zSubcmd, "import", n)==0 ){ |
| 474 | 577 | bundle_import_cmd(); |
| 475 | 578 | }else if( strncmp(zSubcmd, "ls", n)==0 ){ |
| 476 | 579 | bundle_ls_cmd(); |
| 477 | - }else if( strncmp(zSubcmd, "append", n)==0 ){ | |
| 478 | - bundle_append_cmd(); | |
| 479 | - }else if( strncmp(zSubcmd, "extract", n)==0 ){ | |
| 580 | + }else if( strncmp(zSubcmd, "purge", n)==0 ){ | |
| 480 | 581 | fossil_print("Not yet implemented...\n"); |
| 481 | 582 | }else{ |
| 482 | 583 | fossil_fatal("unknown subcommand for bundle: %s", zSubcmd); |
| 483 | 584 | } |
| 484 | 585 | } |
| 485 | 586 |
| --- src/bundle.c | |
| +++ src/bundle.c | |
| @@ -241,45 +241,133 @@ | |
| 241 | } |
| 242 | |
| 243 | /* fossil bundle export BUNDLE ?OPTIONS? |
| 244 | ** |
| 245 | ** OPTIONS: |
| 246 | ** --branch BRANCH |
| 247 | ** --from TAG |
| 248 | ** --to TAG |
| 249 | ** --checkin TAG |
| 250 | */ |
| 251 | static void bundle_export_cmd(void){ |
| 252 | db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);"); |
| 253 | subtree_from_arguments("tobundle"); |
| 254 | verify_all_options(); |
| 255 | bundle_attach_file(g.argv[3], "b1", 1); |
| 256 | find_checkin_associates("tobundle"); |
| 257 | db_begin_transaction(); |
| 258 | db_multi_exec( |
| 259 | "REPLACE INTO bblob(blobid,uuid,sz,delta,data) " |
| 260 | " SELECT" |
| 261 | " tobundle.rid," |
| 262 | " b1.uuid," |
| 263 | " b1.size," |
| 264 | " CASE WHEN delta.srcid NOT IN tobundle" |
| 265 | " THEN (SELECT uuid FROM blob WHERE rid=delta.srcid)" |
| 266 | " ELSE delta.srcid END," |
| 267 | " b1.content" |
| 268 | " FROM tobundle" |
| 269 | " JOIN blob AS b1 ON b1.rid=tobundle.rid" |
| 270 | " LEFT JOIN delta ON delta.rid=tobundle.rid" |
| 271 | ); |
| 272 | db_multi_exec( |
| 273 | "INSERT INTO bconfig(bcname,bcvalue)" |
| 274 | " VALUES('mtime',datetime('now'));" |
| 275 | ); |
| 276 | db_multi_exec( |
| 277 | "INSERT INTO bconfig(bcname,bcvalue)" |
| 278 | " SELECT name, value FROM config" |
| 279 | " WHERE name IN ('project-code');" |
| 280 | ); |
| 281 | db_end_transaction(0); |
| 282 | } |
| 283 | |
| 284 | |
| 285 | /* |
| @@ -417,68 +505,81 @@ | |
| 417 | /* |
| 418 | ** COMMAND: bundle |
| 419 | ** |
| 420 | ** Usage: %fossil bundle SUBCOMMAND ARGS... |
| 421 | ** |
| 422 | ** fossil bundle export BUNDLE ?OPTIONS? |
| 423 | ** |
| 424 | ** Generate a new bundle, in the file named BUNDLE, that constains a |
| 425 | ** subset of the check-ins in the repository (usually a single branch) |
| 426 | ** as determined by OPTIONS. OPTIONS include: |
| 427 | ** |
| 428 | ** --branch BRANCH Package all check-ins on BRANCH. |
| 429 | ** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2. |
| 430 | ** --m COMMENT Add the comment to the bundle. |
| 431 | ** --explain Just explain what would have happened. |
| 432 | ** |
| 433 | ** fossil bundle import BUNDLE ?--publish? |
| 434 | ** |
| 435 | ** Import the bundle in file BUNDLE into the repository. The --publish |
| 436 | ** option makes the import public. The --explain option makes no changes |
| 437 | ** to the repository but rather explains what would have happened. |
| 438 | ** |
| 439 | ** fossil bundle ls BUNDLE |
| 440 | ** |
| 441 | ** List the contents of BUNDLE on standard output |
| 442 | ** |
| 443 | ** fossil bundle append BUNDLE FILE... |
| 444 | ** |
| 445 | ** Add files named on the command line to BUNDLE. This subcommand has |
| 446 | ** little practical use and is mostly intended for testing. |
| 447 | ** |
| 448 | ** fossil bundle cat BUNDLE UUID ?FILE? |
| 449 | ** |
| 450 | ** Extract an artifact from the bundle. Write it into FILE, or onto |
| 451 | ** standard output if FILE is omitted. |
| 452 | ** |
| 453 | ** SUMMARY: |
| 454 | ** fossil bundle export BUNDLEFILE ?OPTIONS? |
| 455 | ** --branch BRANCH |
| 456 | ** --from TAG1 --to TAG2 |
| 457 | ** --explain |
| 458 | ** fossil bundle import BUNDLEFILE ?OPTIONS? |
| 459 | ** --publish |
| 460 | ** --explain |
| 461 | ** fossil bundle ls BUNDLEFILE |
| 462 | */ |
| 463 | void bundle_cmd(void){ |
| 464 | const char *zSubcmd; |
| 465 | const char *zBundleFile; |
| 466 | int n; |
| 467 | if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?ARGUMENTS?"); |
| 468 | zSubcmd = g.argv[2]; |
| 469 | db_find_and_open_repository(0,0); |
| 470 | n = (int)strlen(zSubcmd); |
| 471 | if( strncmp(zSubcmd, "export", n)==0 ){ |
| 472 | bundle_export_cmd(); |
| 473 | }else if( strncmp(zSubcmd, "import", n)==0 ){ |
| 474 | bundle_import_cmd(); |
| 475 | }else if( strncmp(zSubcmd, "ls", n)==0 ){ |
| 476 | bundle_ls_cmd(); |
| 477 | }else if( strncmp(zSubcmd, "append", n)==0 ){ |
| 478 | bundle_append_cmd(); |
| 479 | }else if( strncmp(zSubcmd, "extract", n)==0 ){ |
| 480 | fossil_print("Not yet implemented...\n"); |
| 481 | }else{ |
| 482 | fossil_fatal("unknown subcommand for bundle: %s", zSubcmd); |
| 483 | } |
| 484 | } |
| 485 |
| --- src/bundle.c | |
| +++ src/bundle.c | |
| @@ -241,45 +241,133 @@ | |
| 241 | } |
| 242 | |
| 243 | /* fossil bundle export BUNDLE ?OPTIONS? |
| 244 | ** |
| 245 | ** OPTIONS: |
| 246 | ** --branch BRANCH --from TAG --to TAG |
| 247 | ** --checkin TAG |
| 248 | ** --standalone |
| 249 | */ |
| 250 | static void bundle_export_cmd(void){ |
| 251 | int bStandalone = find_option("standalone",0,0)!=0; |
| 252 | int mnToBundle; /* Minimum RID in the bundle */ |
| 253 | Stmt q; |
| 254 | |
| 255 | /* Decode the arguments (like --branch) that specify which artifacts |
| 256 | ** should be in the bundle */ |
| 257 | db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);"); |
| 258 | subtree_from_arguments("tobundle"); |
| 259 | find_checkin_associates("tobundle"); |
| 260 | verify_all_options(); |
| 261 | |
| 262 | /* Create the new bundle */ |
| 263 | bundle_attach_file(g.argv[3], "b1", 1); |
| 264 | db_begin_transaction(); |
| 265 | |
| 266 | /* Add 'mtime' and 'project-code' entries to the bconfig table */ |
| 267 | db_multi_exec( |
| 268 | "INSERT INTO bconfig(bcname,bcvalue)" |
| 269 | " VALUES('mtime',datetime('now'));" |
| 270 | ); |
| 271 | db_multi_exec( |
| 272 | "INSERT INTO bconfig(bcname,bcvalue)" |
| 273 | " SELECT name, value FROM config" |
| 274 | " WHERE name IN ('project-code');" |
| 275 | ); |
| 276 | |
| 277 | /* Directly copy content from the repository into the bundle as long |
| 278 | ** as the repository content is a delta from some other artifact that |
| 279 | ** is also in the bundle. |
| 280 | */ |
| 281 | db_multi_exec( |
| 282 | "REPLACE INTO bblob(blobid,uuid,sz,delta,data) " |
| 283 | " SELECT" |
| 284 | " tobundle.rid," |
| 285 | " blob.uuid," |
| 286 | " blob.size," |
| 287 | " delta.srcid," |
| 288 | " blob.content" |
| 289 | " FROM tobundle, blob, delta" |
| 290 | " WHERE blob.rid=tobundle.rid" |
| 291 | " AND delta.rid=tobundle.rid;" |
| 292 | ); |
| 293 | |
| 294 | /* For all the remaining artifacts, we need to construct their deltas |
| 295 | ** manually. |
| 296 | */ |
| 297 | mnToBundle = db_int(0,"SELECT min(rid) FROM tobundle"); |
| 298 | db_prepare(&q, |
| 299 | "SELECT rid FROM tobundle" |
| 300 | " WHERE rid NOT IN (SELECT blobid FROM bblob)" |
| 301 | " ORDER BY +rid;" |
| 302 | ); |
| 303 | while( db_step(&q)==SQLITE_ROW ){ |
| 304 | Blob content; |
| 305 | int rid = db_column_int(&q,0); |
| 306 | int deltaFrom = 0; |
| 307 | |
| 308 | /* Get the raw, uncompressed content of the artifact into content */ |
| 309 | content_get(rid, &content); |
| 310 | |
| 311 | /* Try to find another artifact, not within the bundle, that is a |
| 312 | ** plausible candidate for being a delta basis for the content. Set |
| 313 | ** deltaFrom to the RID of that other artifact. Leave deltaFrom set |
| 314 | ** to zero if the content should not be delta-compressed |
| 315 | */ |
| 316 | if( !bStandalone ){ |
| 317 | if( db_exists("SELECT 1 FROM plink WHERE cid=%d",rid) ){ |
| 318 | deltaFrom = db_int(0, |
| 319 | "SELECT max(cid) FROM plink" |
| 320 | " WHERE cid<%d", mnToBundle); |
| 321 | }else{ |
| 322 | deltaFrom = db_int(0, |
| 323 | "SELECT max(fid) FROM mlink" |
| 324 | " WHERE fnid=(SELECT fnid FROM mlink WHERE fid=%d)" |
| 325 | " AND fid<%d", rid, mnToBundle); |
| 326 | } |
| 327 | } |
| 328 | |
| 329 | /* Try to insert the insert the artifact as a delta |
| 330 | */ |
| 331 | if( deltaFrom ){ |
| 332 | Blob basis, delta; |
| 333 | content_get(deltaFrom, &basis); |
| 334 | blob_delta_create(&basis, &content, &delta); |
| 335 | if( blob_size(&delta)>0.9*blob_size(&content) ){ |
| 336 | deltaFrom = 0; |
| 337 | }else{ |
| 338 | Stmt ins; |
| 339 | blob_compress(&delta, &delta); |
| 340 | db_prepare(&ins, |
| 341 | "REPLACE INTO bblob(blobid,uuid,sz,delta,data)" |
| 342 | " SELECT %d, uuid, size, (SELECT uuid FROM blob WHERE rid=%d)," |
| 343 | " :delta FROM blob WHERE rid=%d", rid, deltaFrom, rid); |
| 344 | db_bind_blob(&ins, ":delta", &delta); |
| 345 | db_step(&ins); |
| 346 | db_finalize(&ins); |
| 347 | } |
| 348 | blob_reset(&basis); |
| 349 | blob_reset(&delta); |
| 350 | } |
| 351 | |
| 352 | /* If unable to insert the artifact as a delta, insert full-text */ |
| 353 | if( deltaFrom==0 ){ |
| 354 | Stmt ins; |
| 355 | blob_compress(&content, &content); |
| 356 | db_prepare(&ins, |
| 357 | "REPLACE INTO bblob(blobid,uuid,sz,delta,data)" |
| 358 | " SELECT rid, uuid, size, NULL, :content" |
| 359 | " FROM blob WHERE rid=%d", rid); |
| 360 | db_bind_blob(&ins, ":content", &content); |
| 361 | db_step(&ins); |
| 362 | db_finalize(&ins); |
| 363 | } |
| 364 | blob_reset(&content); |
| 365 | } |
| 366 | db_finalize(&q); |
| 367 | |
| 368 | |
| 369 | db_end_transaction(0); |
| 370 | } |
| 371 | |
| 372 | |
| 373 | /* |
| @@ -417,68 +505,81 @@ | |
| 505 | /* |
| 506 | ** COMMAND: bundle |
| 507 | ** |
| 508 | ** Usage: %fossil bundle SUBCOMMAND ARGS... |
| 509 | ** |
| 510 | ** fossil bundle append BUNDLE FILE... |
| 511 | ** |
| 512 | ** Add files named on the command line to BUNDLE. This subcommand has |
| 513 | ** little practical use and is mostly intended for testing. |
| 514 | ** |
| 515 | ** fossil bundle cat BUNDLE UUID... |
| 516 | ** |
| 517 | ** Extract one or more artifacts from the bundle and write them |
| 518 | ** consecutively on standard output. |
| 519 | ** |
| 520 | ** fossil bundle export BUNDLE ?OPTIONS? |
| 521 | ** |
| 522 | ** Generate a new bundle, in the file named BUNDLE, that constains a |
| 523 | ** subset of the check-ins in the repository (usually a single branch) |
| 524 | ** described by the --branch, --from, --to, and/or --checkin options, |
| 525 | ** at least one of which is required. If BUNDLE already exists, the |
| 526 | ** specified content is added to the bundle. |
| 527 | ** |
| 528 | ** --branch BRANCH Package all check-ins on BRANCH. |
| 529 | ** --from TAG1 --to TAG2 Package checkins between TAG1 and TAG2. |
| 530 | ** --checkin TAG Package the single checkin TAG |
| 531 | ** --standalone Do no use delta-encoding against |
| 532 | ** artifacts not in the bundle |
| 533 | ** |
| 534 | ** fossil bundle import BUNDLE ?--publish? |
| 535 | ** |
| 536 | ** Import the bundle in file BUNDLE into the repository. By default, the |
| 537 | ** imported files are private and will not sync. Use the --publish |
| 538 | ** option makes the import public. |
| 539 | ** |
| 540 | ** fossil bundle ls BUNDLE |
| 541 | ** |
| 542 | ** List the contents of BUNDLE on standard output |
| 543 | ** |
| 544 | ** fossil bundle purge BUNDLE |
| 545 | ** |
| 546 | ** Remove all files found in BUNDLE from the repository. This has |
| 547 | ** the effect of undoing a "fossil bundle import". |
| 548 | ** |
| 549 | ** SUMMARY: |
| 550 | ** fossil bundle append BUNDLE FILE... Add files to BUNDLE |
| 551 | ** fossil bundle cat BUNDLE UUID... Extract file from BUNDLE |
| 552 | ** fossil bundle export BUNDLE ?OPTIONS? Create a new BUNDLE |
| 553 | ** --branch BRANCH --from TAG1 --to TAG2 Checkins to include |
| 554 | ** --checkin TAG Use only checkin TAG |
| 555 | ** --standalone Omit dependencies |
| 556 | ** fossil bundle import BUNDLE ?OPTIONS? Import a bundle |
| 557 | ** --publish Publish the import |
| 558 | ** --force Cross-repo import |
| 559 | ** fossil bundle ls BUNDLE List content of a bundle |
| 560 | ** fossil bundle purge BUNDLE Undo an import |
| 561 | */ |
| 562 | void bundle_cmd(void){ |
| 563 | const char *zSubcmd; |
| 564 | const char *zBundleFile; |
| 565 | int n; |
| 566 | if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?ARGUMENTS?"); |
| 567 | zSubcmd = g.argv[2]; |
| 568 | db_find_and_open_repository(0,0); |
| 569 | n = (int)strlen(zSubcmd); |
| 570 | if( strncmp(zSubcmd, "append", n)==0 ){ |
| 571 | bundle_append_cmd(); |
| 572 | }else if( strncmp(zSubcmd, "cat", n)==0 ){ |
| 573 | fossil_print("Not yet implemented...\n"); |
| 574 | }else if( strncmp(zSubcmd, "export", n)==0 ){ |
| 575 | bundle_export_cmd(); |
| 576 | }else if( strncmp(zSubcmd, "import", n)==0 ){ |
| 577 | bundle_import_cmd(); |
| 578 | }else if( strncmp(zSubcmd, "ls", n)==0 ){ |
| 579 | bundle_ls_cmd(); |
| 580 | }else if( strncmp(zSubcmd, "purge", n)==0 ){ |
| 581 | fossil_print("Not yet implemented...\n"); |
| 582 | }else{ |
| 583 | fossil_fatal("unknown subcommand for bundle: %s", zSubcmd); |
| 584 | } |
| 585 | } |
| 586 |
+19
-16
| --- src/purge.c | ||
| +++ src/purge.c | ||
| @@ -400,13 +400,28 @@ | ||
| 400 | 400 | } |
| 401 | 401 | |
| 402 | 402 | /* |
| 403 | 403 | ** COMMAND: purge |
| 404 | 404 | ** |
| 405 | -** The purge command is used to remove content from a repository into a | |
| 406 | -** "graveyard" and also to show manage the graveyard and optionally restored | |
| 407 | -** content into the repository from the graveyard. | |
| 405 | +** The purge command removes content from a repository and stores that content | |
| 406 | +** in a "graveyard". The graveyard exists so that content can be recovered | |
| 407 | +** using the "fossil purge undo" command. | |
| 408 | +** | |
| 409 | +** fossil purge cat UUID... | |
| 410 | +** | |
| 411 | +** Write the content of one or more artifacts in the graveyard onto | |
| 412 | +** standard output. | |
| 413 | +** | |
| 414 | +** fossil purge [checkin] TAGS... [--explain] | |
| 415 | +** | |
| 416 | +** Move the checkins identified by TAGS and all of their descendants | |
| 417 | +** out of the repository and into the graveyard. If a TAG is a branch | |
| 418 | +** name then it means all the checkins on that branch. If the --explain | |
| 419 | +** option appears, then the repository and graveyard are unchanged and | |
| 420 | +** an explaination of what would have happened is shown instead. The | |
| 421 | +** "checkin" subcommand keyword is only required if TAGS would be | |
| 422 | +** ambiguous with one of the other subcommands. | |
| 408 | 423 | ** |
| 409 | 424 | ** fossil purge list|ls [-l] |
| 410 | 425 | ** |
| 411 | 426 | ** Show the graveyard of prior purges. The -l option gives more |
| 412 | 427 | ** detail in the output. |
| @@ -413,27 +428,15 @@ | ||
| 413 | 428 | ** |
| 414 | 429 | ** fossil purge undo ID |
| 415 | 430 | ** |
| 416 | 431 | ** Restore the content previously removed by purge ID. |
| 417 | 432 | ** |
| 418 | -** fossil purge cat UUID ?FILENAME? | |
| 419 | -** | |
| 420 | -** Whow the content of artifact UUID from the graveyard | |
| 421 | -** | |
| 422 | -** fossil purge [checkin] TAGS... [--explain] | |
| 423 | -** | |
| 424 | -** Move the checkins identified by TAGS and all of their descendants | |
| 425 | -** out of the repository and into the graveyard. If a TAG is a branch | |
| 426 | -** name then it means all the checkins on that branch. If the --explain | |
| 427 | -** option appears, then the repository and graveyard are unchanged and | |
| 428 | -** an explaination of what would have happened is shown instead. | |
| 429 | -** | |
| 430 | 433 | ** SUMMARY: |
| 434 | +** fossil purge cat UUID... | |
| 431 | 435 | ** fossil purge [checkin] TAGS... [--explain] |
| 432 | 436 | ** fossil purge list |
| 433 | 437 | ** fossil purge undo ID |
| 434 | -** fossil purge cat UUID [FILENAME] | |
| 435 | 438 | */ |
| 436 | 439 | void purge_cmd(void){ |
| 437 | 440 | const char *zSubcmd; |
| 438 | 441 | int n; |
| 439 | 442 | Stmt q; |
| 440 | 443 |
| --- src/purge.c | |
| +++ src/purge.c | |
| @@ -400,13 +400,28 @@ | |
| 400 | } |
| 401 | |
| 402 | /* |
| 403 | ** COMMAND: purge |
| 404 | ** |
| 405 | ** The purge command is used to remove content from a repository into a |
| 406 | ** "graveyard" and also to show manage the graveyard and optionally restored |
| 407 | ** content into the repository from the graveyard. |
| 408 | ** |
| 409 | ** fossil purge list|ls [-l] |
| 410 | ** |
| 411 | ** Show the graveyard of prior purges. The -l option gives more |
| 412 | ** detail in the output. |
| @@ -413,27 +428,15 @@ | |
| 413 | ** |
| 414 | ** fossil purge undo ID |
| 415 | ** |
| 416 | ** Restore the content previously removed by purge ID. |
| 417 | ** |
| 418 | ** fossil purge cat UUID ?FILENAME? |
| 419 | ** |
| 420 | ** Whow the content of artifact UUID from the graveyard |
| 421 | ** |
| 422 | ** fossil purge [checkin] TAGS... [--explain] |
| 423 | ** |
| 424 | ** Move the checkins identified by TAGS and all of their descendants |
| 425 | ** out of the repository and into the graveyard. If a TAG is a branch |
| 426 | ** name then it means all the checkins on that branch. If the --explain |
| 427 | ** option appears, then the repository and graveyard are unchanged and |
| 428 | ** an explaination of what would have happened is shown instead. |
| 429 | ** |
| 430 | ** SUMMARY: |
| 431 | ** fossil purge [checkin] TAGS... [--explain] |
| 432 | ** fossil purge list |
| 433 | ** fossil purge undo ID |
| 434 | ** fossil purge cat UUID [FILENAME] |
| 435 | */ |
| 436 | void purge_cmd(void){ |
| 437 | const char *zSubcmd; |
| 438 | int n; |
| 439 | Stmt q; |
| 440 |
| --- src/purge.c | |
| +++ src/purge.c | |
| @@ -400,13 +400,28 @@ | |
| 400 | } |
| 401 | |
| 402 | /* |
| 403 | ** COMMAND: purge |
| 404 | ** |
| 405 | ** The purge command removes content from a repository and stores that content |
| 406 | ** in a "graveyard". The graveyard exists so that content can be recovered |
| 407 | ** using the "fossil purge undo" command. |
| 408 | ** |
| 409 | ** fossil purge cat UUID... |
| 410 | ** |
| 411 | ** Write the content of one or more artifacts in the graveyard onto |
| 412 | ** standard output. |
| 413 | ** |
| 414 | ** fossil purge [checkin] TAGS... [--explain] |
| 415 | ** |
| 416 | ** Move the checkins identified by TAGS and all of their descendants |
| 417 | ** out of the repository and into the graveyard. If a TAG is a branch |
| 418 | ** name then it means all the checkins on that branch. If the --explain |
| 419 | ** option appears, then the repository and graveyard are unchanged and |
| 420 | ** an explaination of what would have happened is shown instead. The |
| 421 | ** "checkin" subcommand keyword is only required if TAGS would be |
| 422 | ** ambiguous with one of the other subcommands. |
| 423 | ** |
| 424 | ** fossil purge list|ls [-l] |
| 425 | ** |
| 426 | ** Show the graveyard of prior purges. The -l option gives more |
| 427 | ** detail in the output. |
| @@ -413,27 +428,15 @@ | |
| 428 | ** |
| 429 | ** fossil purge undo ID |
| 430 | ** |
| 431 | ** Restore the content previously removed by purge ID. |
| 432 | ** |
| 433 | ** SUMMARY: |
| 434 | ** fossil purge cat UUID... |
| 435 | ** fossil purge [checkin] TAGS... [--explain] |
| 436 | ** fossil purge list |
| 437 | ** fossil purge undo ID |
| 438 | */ |
| 439 | void purge_cmd(void){ |
| 440 | const char *zSubcmd; |
| 441 | int n; |
| 442 | Stmt q; |
| 443 |