Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Initial implementation of the "bundle import" command. Also added the "db_debug()" function for use in debugging. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | DBP-workflow |
| Files: | files | file ages | folders |
| SHA1: |
8abe20a137fa953f8c761dabd7e96f47 |
| User & Date: | drh 2014-11-26 01:40:35.588 |
Context
|
2014-11-26
| ||
| 14:26 | 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. check-in: eb3ae3d619 user: drh tags: DBP-workflow | |
| 01:40 | Initial implementation of the "bundle import" command. Also added the "db_debug()" function for use in debugging. check-in: 8abe20a137 user: drh tags: DBP-workflow | |
|
2014-11-25
| ||
| 23:15 | First cut at the "bundle export" command. Enhancements to "bundle ls". check-in: a2f04d8173 user: drh tags: DBP-workflow | |
Changes
Changes to src/bundle.c.
| ︙ | ︙ | |||
277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
"INSERT INTO bconfig(bcname,bcvalue)"
" SELECT name, value FROM config"
" WHERE name IN ('project-code');"
);
db_end_transaction(0);
}
/*
** COMMAND: bundle
**
** Usage: %fossil bundle SUBCOMMAND ARGS...
**
** fossil bundle export BUNDLE ?OPTIONS?
**
** Generate a new bundle, in the file named BUNDLE, that constains a
** subset of the check-ins in the repository (usually a single branch)
** as determined by OPTIONS. OPTIONS include:
**
** --branch BRANCH Package all check-ins on BRANCH.
** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2.
** --m COMMENT Add the comment to the bundle.
** --explain Just explain what would have happened.
**
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | | < < < | | 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 333 334 335 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 367 368 369 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 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
"INSERT INTO bconfig(bcname,bcvalue)"
" SELECT name, value FROM config"
" WHERE name IN ('project-code');"
);
db_end_transaction(0);
}
/*
** There is a TEMP table bix(blobid,delta) containing a set of purgeitems
** that need to be transferred to the BLOB table. This routine does
** all items that have srcid=iSrc. The pBasis blob holds the content
** of the source document if iSrc>0.
*/
static void bundle_import_elements(int iSrc, Blob *pBasis, int isPriv){
Stmt q;
static Bag busy;
assert( pBasis!=0 || iSrc==0 );
if( iSrc>0 ){
if( bag_find(&busy, iSrc) ){
fossil_fatal("delta loop while uncompressing bundle artifacts");
}
bag_insert(&busy, iSrc);
}
db_prepare(&q,
"SELECT uuid, data, bblob.delta, bix.blobid"
" FROM bix, bblob"
" WHERE bix.delta=%d"
" AND bix.blobid=bblob.blobid;",
iSrc
);
while( db_step(&q)==SQLITE_ROW ){
Blob h1, h2, c1, c2;
int rid;
blob_zero(&h1);
db_column_blob(&q, 0, &h1);
blob_zero(&c1);
db_column_blob(&q, 1, &c1);
blob_uncompress(&c1, &c1);
blob_zero(&c2);
if( db_column_type(&q,2)==SQLITE_TEXT && db_column_bytes(&q,2)==40 ){
Blob basis;
rid = db_int(0,"SELECT rid FROM blob WHERE uuid=%Q",
db_column_text(&q,2));
content_get(rid, &basis);
blob_delta_apply(&basis, &c1, &c2);
blob_reset(&basis);
blob_reset(&c1);
}else if( pBasis ){
blob_delta_apply(pBasis, &c1, &c2);
blob_reset(&c1);
}else{
c2 = c1;
}
sha1sum_blob(&c2, &h2);
if( blob_compare(&h1, &h2)!=0 ){
fossil_fatal("SHA1 hash mismatch - wanted %s, got %s",
blob_str(&h1), blob_str(&h2));
}
blob_reset(&h2);
rid = content_put_ex(&c2, blob_str(&h1), 0, 0, isPriv);
if( rid==0 ){
fossil_fatal("%s", g.zErrMsg);
}else{
if( !isPriv ) content_make_public(rid);
content_get(rid, &c1);
manifest_crosslink(rid, &c1, MC_NO_ERRORS);
}
bundle_import_elements(db_column_int(&q,3), &c2, isPriv);
blob_reset(&c2);
}
db_finalize(&q);
if( iSrc>0 ) bag_remove(&busy, iSrc);
}
/* fossil bundle import BUNDLE ?OPTIONS?
**
** Attempt to import the changes contained in BUNDLE. Make the change
** private so that they do not sync.
**
** OPTIONS:
** --force Import even if the project-code does not match
** --publish Imported changes are not private
*/
static void bundle_import_cmd(void){
int forceFlag = find_option("force","f",0)!=0;
int isPriv = find_option("publish",0,0)==0;
char *zMissingDeltas;
Stmt q;
verify_all_options();
bundle_attach_file(g.argv[3], "b1", 1);
/* Only import a bundle that was generated from a repo with the same
** project code, unless the --force flag is true */
if( !forceFlag ){
if( !db_exists("SELECT 1 FROM config, bconfig"
" WHERE config.name='project-code'"
" AND bconfig.bcname='project-code'"
" AND config.value=bconfig.bcvalue;")
){
fossil_fatal("project-code in the bundle does not match the "
"repository project code. (override with --force).");
}
}
/* If the bundle contains deltas with a basis that is external to the
** bundle and those external basis files are missing from the local
** repo, then the delta encodings cannot be decoded and the bundle cannot
** be extracted. */
zMissingDeltas = db_text(0,
"SELECT group_concat(substr(delta,1,10),' ')"
" FROM bblob"
" WHERE typeof(delta)='text' AND length(delta)=40"
" AND NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.delta)");
if( zMissingDeltas && zMissingDeltas[0] ){
fossil_fatal("delta basis artifacts not found in repository: %s",
zMissingDeltas);
}
db_begin_transaction();
db_multi_exec(
"CREATE TEMP TABLE bix("
" blobid INTEGER PRIMARY KEY,"
" delta INTEGER"
");"
"CREATE INDEX bixdelta ON bix(delta);"
"INSERT INTO bix(blobid,delta)"
" SELECT blobid,"
" CASE WHEN typeof(delta)=='integer'"
" THEN delta ELSE 0 END"
" FROM bblob"
" WHERE NOT EXISTS(SELECT 1 FROM blob WHERE uuid=bblob.uuid);"
);
manifest_crosslink_begin();
bundle_import_elements(0, 0, isPriv);
manifest_crosslink_end(0);
db_end_transaction(0);
}
/*
** COMMAND: bundle
**
** Usage: %fossil bundle SUBCOMMAND ARGS...
**
** fossil bundle export BUNDLE ?OPTIONS?
**
** Generate a new bundle, in the file named BUNDLE, that constains a
** subset of the check-ins in the repository (usually a single branch)
** as determined by OPTIONS. OPTIONS include:
**
** --branch BRANCH Package all check-ins on BRANCH.
** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2.
** --m COMMENT Add the comment to the bundle.
** --explain Just explain what would have happened.
**
** fossil bundle import BUNDLE ?--publish?
**
** Import the bundle in file BUNDLE into the repository. The --publish
** option makes the import public. The --explain option makes no changes
** to the repository but rather explains what would have happened.
**
** fossil bundle ls BUNDLE
**
** List the contents of BUNDLE on standard output
**
** fossil bundle append BUNDLE FILE...
**
** Add files named on the command line to BUNDLE. This subcommand has
** little practical use and is mostly intended for testing.
**
** fossil bundle cat BUNDLE UUID ?FILE?
**
** Extract an artifact from the bundle. Write it into FILE, or onto
** standard output if FILE is omitted.
**
** SUMMARY:
** fossil bundle export BUNDLEFILE ?OPTIONS?
** --branch BRANCH
** --from TAG1 --to TAG2
** --explain
** fossil bundle import BUNDLEFILE ?OPTIONS?
|
| ︙ | ︙ | |||
337 338 339 340 341 342 343 |
if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?ARGUMENTS?");
zSubcmd = g.argv[2];
db_find_and_open_repository(0,0);
n = (int)strlen(zSubcmd);
if( strncmp(zSubcmd, "export", n)==0 ){
bundle_export_cmd();
}else if( strncmp(zSubcmd, "import", n)==0 ){
| | | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
if( g.argc<4 ) usage("SUBCOMMAND BUNDLE ?ARGUMENTS?");
zSubcmd = g.argv[2];
db_find_and_open_repository(0,0);
n = (int)strlen(zSubcmd);
if( strncmp(zSubcmd, "export", n)==0 ){
bundle_export_cmd();
}else if( strncmp(zSubcmd, "import", n)==0 ){
bundle_import_cmd();
}else if( strncmp(zSubcmd, "ls", n)==0 ){
bundle_ls_cmd();
}else if( strncmp(zSubcmd, "append", n)==0 ){
bundle_append_cmd();
}else if( strncmp(zSubcmd, "extract", n)==0 ){
fossil_print("Not yet implemented...\n");
}else{
fossil_fatal("unknown subcommand for bundle: %s", zSubcmd);
}
}
|
Changes to src/db.c.
| ︙ | ︙ | |||
422 423 424 425 426 427 428 429 430 431 432 433 434 435 |
return sqlite3_changes(g.db);
}
/*
** Extract text, integer, or blob values from the N-th column of the
** current row.
*/
int db_column_bytes(Stmt *pStmt, int N){
return sqlite3_column_bytes(pStmt->pStmt, N);
}
int db_column_int(Stmt *pStmt, int N){
return sqlite3_column_int(pStmt->pStmt, N);
}
i64 db_column_int64(Stmt *pStmt, int N){
| > > > | 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 |
return sqlite3_changes(g.db);
}
/*
** Extract text, integer, or blob values from the N-th column of the
** current row.
*/
int db_column_type(Stmt *pStmt, int N){
return sqlite3_column_type(pStmt->pStmt, N);
}
int db_column_bytes(Stmt *pStmt, int N){
return sqlite3_column_bytes(pStmt->pStmt, N);
}
int db_column_int(Stmt *pStmt, int N){
return sqlite3_column_int(pStmt->pStmt, N);
}
i64 db_column_int64(Stmt *pStmt, int N){
|
| ︙ | ︙ | |||
484 485 486 487 488 489 490 491 492 493 494 495 496 497 |
int db_exec(Stmt *pStmt){
int rc;
while( (rc = db_step(pStmt))==SQLITE_ROW ){}
rc = db_reset(pStmt);
db_check_result(rc);
return rc;
}
/*
** Execute multiple SQL statements.
*/
int db_multi_exec(const char *zSql, ...){
Blob sql;
int rc = SQLITE_OK;
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 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 |
int db_exec(Stmt *pStmt){
int rc;
while( (rc = db_step(pStmt))==SQLITE_ROW ){}
rc = db_reset(pStmt);
db_check_result(rc);
return rc;
}
/*
** Print the output of one or more SQL queries on standard output.
** This routine is used for debugging purposes only.
*/
int db_debug(const char *zSql, ...){
Blob sql;
int rc = SQLITE_OK;
va_list ap;
const char *z, *zEnd;
sqlite3_stmt *pStmt;
blob_init(&sql, 0, 0);
va_start(ap, zSql);
blob_vappendf(&sql, zSql, ap);
va_end(ap);
z = blob_str(&sql);
while( rc==SQLITE_OK && z[0] ){
pStmt = 0;
rc = sqlite3_prepare_v2(g.db, z, -1, &pStmt, &zEnd);
if( rc!=SQLITE_OK ) break;
if( pStmt ){
int nRow = 0;
db.nPrepare++;
while( sqlite3_step(pStmt)==SQLITE_ROW ){
int i, n;
if( nRow++ > 0 ) fossil_print("\n");
n = sqlite3_column_count(pStmt);
for(i=0; i<n; i++){
fossil_print("%s = %s\n", sqlite3_column_name(pStmt, i),
sqlite3_column_text(pStmt,i));
}
}
rc = sqlite3_finalize(pStmt);
if( rc ) db_err("%s: {%.*s}", sqlite3_errmsg(g.db), (int)(zEnd-z), z);
}
z = zEnd;
}
blob_reset(&sql);
return rc;
}
/*
** Execute multiple SQL statements.
*/
int db_multi_exec(const char *zSql, ...){
Blob sql;
int rc = SQLITE_OK;
|
| ︙ | ︙ |