| | @@ -363,45 +363,71 @@ |
| 363 | 363 | assert( blob_is_reset(&ctrl) ); |
| 364 | 364 | if( g.localOpen ){ |
| 365 | 365 | manifest_to_disk(rid); |
| 366 | 366 | } |
| 367 | 367 | } |
| 368 | + |
| 369 | +/* |
| 370 | +** If zTag is NULL or valid for use as a tag for the `tag add` and |
| 371 | +** `tag cancel` commands, returns without side effects, else emits a |
| 372 | +** fatal error message. We reject certain prefixes to avoid that |
| 373 | +** clients cause undue grief by improperly tagging artifacts as being, |
| 374 | +** e.g., wiki pages or tickets. |
| 375 | +*/ |
| 376 | +static void tag_cmd_tagname_check(const char *zTag){ |
| 377 | + if(zTag && *zTag && |
| 378 | + (strncmp(zTag,"wiki-",5)==0 |
| 379 | + || strncmp(zTag,"tkt-",4)==0 |
| 380 | + || strncmp(zTag,"event-",6)==0)){ |
| 381 | + fossil_fatal("Invalid prefix for tag name: %s", zTag); |
| 382 | + } |
| 383 | +} |
| 368 | 384 | |
| 369 | 385 | /* |
| 370 | 386 | ** COMMAND: tag |
| 371 | 387 | ** |
| 372 | 388 | ** Usage: %fossil tag SUBCOMMAND ... |
| 373 | 389 | ** |
| 374 | 390 | ** Run various subcommands to control tags and properties. |
| 375 | 391 | ** |
| 376 | | -** > fossil tag add ?OPTIONS? TAGNAME CHECK-IN ?VALUE? |
| 392 | +** > fossil tag add ?OPTIONS? TAGNAME ARTIFACT-ID ?VALUE? |
| 377 | 393 | ** |
| 378 | | -** Add a new tag or property to CHECK-IN. The tag will |
| 379 | | -** be usable instead of a CHECK-IN in commands such as |
| 380 | | -** update and merge. If the --propagate flag is present, |
| 381 | | -** the tag value propagates to all descendants of CHECK-IN |
| 394 | +** Add a new tag or property to an artifact referenced by |
| 395 | +** ARTIFACT-ID. For checkins, the tag will be usable instead |
| 396 | +** of a CHECK-IN in commands such as update and merge. If the |
| 397 | +** --propagate flag is present and ARTIFACT-ID refers to a |
| 398 | +** wiki page, forum post, tech-note, or check-in, the tag |
| 399 | +** propagates to all descendants of that artifact. |
| 382 | 400 | ** |
| 383 | 401 | ** Options: |
| 384 | | -** --raw Raw tag name. |
| 385 | | -** --propagate Propagating tag. |
| 386 | | -** --date-override DATETIME Set date and time added. |
| 387 | | -** --user-override USER Name USER when adding the tag. |
| 388 | | -** -n|--dryrun Display the tag text, but do not |
| 389 | | -** actually insert it into the database. |
| 402 | +** --raw Raw tag name. Ignored for |
| 403 | +** non-CHECK-IN artifacts. |
| 404 | +** --propagate Propagating tag. |
| 405 | +** --date-override DATETIME Set date and time added. |
| 406 | +** --user-override USER Name USER when adding the tag. |
| 407 | +** -n|--dryrun Display the tag text, but do not |
| 408 | +** actually insert it into the database. |
| 390 | 409 | ** |
| 391 | 410 | ** The --date-override and --user-override options support |
| 392 | 411 | ** importing history from other SCM systems. DATETIME has |
| 393 | 412 | ** the form 'YYYY-MMM-DD HH:MM:SS'. |
| 394 | 413 | ** |
| 395 | | -** > fossil tag cancel ?--raw? TAGNAME CHECK-IN |
| 414 | +** Note that fossil uses some tag prefixes internally and this |
| 415 | +** command will reject tags with these prefixes to avoid |
| 416 | +** causing problems or confusion: "wiki-", "tkt-", "event-". |
| 417 | +** |
| 418 | +** > fossil tag cancel ?--raw? TAGNAME ARTIFACT-ID |
| 396 | 419 | ** |
| 397 | | -** Remove the tag TAGNAME from CHECK-IN, and also remove |
| 398 | | -** the propagation of the tag to any descendants. Use the |
| 399 | | -** the -n|--dryrun option to see what would have happened. |
| 420 | +** Remove the tag TAGNAME from the artifact referenced by |
| 421 | +** ARTIFACT-ID, and also remove the propagation of the tag to |
| 422 | +** any descendants. Use the the -n|--dryrun option to see |
| 423 | +** what would have happened. Certain tag name prefixes are |
| 424 | +** forbidden, as documented for the 'add' subcommand. |
| 400 | 425 | ** |
| 401 | 426 | ** Options: |
| 402 | | -** --raw Raw tag name. |
| 427 | +** --raw Raw tag name. Ignored for |
| 428 | +** non-CHECK-IN artifacts. |
| 403 | 429 | ** --date-override DATETIME Set date and time deleted. |
| 404 | 430 | ** --user-override USER Name USER when deleting the tag. |
| 405 | 431 | ** -n|--dryrun Display the control artifact, but do |
| 406 | 432 | ** not insert it into the database. |
| 407 | 433 | ** |
| | @@ -461,21 +487,37 @@ |
| 461 | 487 | |
| 462 | 488 | if( strncmp(g.argv[2],"add",n)==0 ){ |
| 463 | 489 | char *zValue; |
| 464 | 490 | int dryRun = 0; |
| 465 | 491 | int fRaw = find_option("raw","",0)!=0; |
| 466 | | - const char *zPrefix = fRaw ? "" : "sym-"; |
| 492 | + const char *zPrefix = ""; |
| 467 | 493 | int fPropagate = find_option("propagate","",0)!=0; |
| 468 | 494 | const char *zDateOvrd = find_option("date-override",0,1); |
| 469 | 495 | const char *zUserOvrd = find_option("user-override",0,1); |
| 496 | + const char *zTag; |
| 497 | + const char *zObjId; |
| 498 | + int objType; |
| 470 | 499 | if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN; |
| 471 | 500 | if( g.argc!=5 && g.argc!=6 ){ |
| 472 | | - usage("add ?options? TAGNAME CHECK-IN ?VALUE?"); |
| 501 | + usage("add ?options? TAGNAME ARTIFACT-ID ?VALUE?"); |
| 473 | 502 | } |
| 503 | + zTag = g.argv[3]; |
| 504 | + tag_cmd_tagname_check(zTag); |
| 505 | + zObjId = g.argv[4]; |
| 474 | 506 | zValue = g.argc==6 ? g.argv[5] : 0; |
| 507 | + objType = whatis_rid_type(symbolic_name_to_rid(zObjId, 0)); |
| 508 | + switch(objType){ |
| 509 | + case 0: |
| 510 | + fossil_fatal("Cannot resolve artifact ID: %s", zObjId); |
| 511 | + break; |
| 512 | + case CFTYPE_MANIFEST: |
| 513 | + zPrefix = fRaw ? "" : "sym-"; |
| 514 | + break; |
| 515 | + default: break; |
| 516 | + } |
| 475 | 517 | db_begin_transaction(); |
| 476 | | - tag_add_artifact(zPrefix, g.argv[3], g.argv[4], zValue, |
| 518 | + tag_add_artifact(zPrefix, zTag, zObjId, zValue, |
| 477 | 519 | 1+fPropagate+dryRun,zDateOvrd,zUserOvrd); |
| 478 | 520 | db_end_transaction(0); |
| 479 | 521 | }else |
| 480 | 522 | |
| 481 | 523 | if( strncmp(g.argv[2],"branch",n)==0 ){ |
| | @@ -484,19 +526,35 @@ |
| 484 | 526 | }else |
| 485 | 527 | |
| 486 | 528 | if( strncmp(g.argv[2],"cancel",n)==0 ){ |
| 487 | 529 | int dryRun = 0; |
| 488 | 530 | int fRaw = find_option("raw","",0)!=0; |
| 489 | | - const char *zPrefix = fRaw ? "" : "sym-"; |
| 531 | + const char *zPrefix = ""; |
| 490 | 532 | const char *zDateOvrd = find_option("date-override",0,1); |
| 491 | 533 | const char *zUserOvrd = find_option("user-override",0,1); |
| 534 | + const char *zTag; |
| 535 | + const char *zObjId; |
| 536 | + int objType; |
| 492 | 537 | if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN; |
| 493 | 538 | if( g.argc!=5 ){ |
| 494 | | - usage("cancel ?options? TAGNAME CHECK-IN"); |
| 539 | + usage("cancel ?options? TAGNAME ARTIFACT-ID"); |
| 540 | + } |
| 541 | + zTag = g.argv[3]; |
| 542 | + tag_cmd_tagname_check(zTag); |
| 543 | + zObjId = g.argv[4]; |
| 544 | + objType = whatis_rid_type(symbolic_name_to_rid(zObjId, 0)); |
| 545 | + switch(objType){ |
| 546 | + case 0: |
| 547 | + fossil_fatal("Cannot resolve artifact ID: %s", zObjId); |
| 548 | + break; |
| 549 | + case CFTYPE_MANIFEST: |
| 550 | + zPrefix = fRaw ? "" : "sym-"; |
| 551 | + break; |
| 552 | + default: break; |
| 495 | 553 | } |
| 496 | 554 | db_begin_transaction(); |
| 497 | | - tag_add_artifact(zPrefix, g.argv[3], g.argv[4], 0, dryRun, |
| 555 | + tag_add_artifact(zPrefix, zTag, zObjId, 0, dryRun, |
| 498 | 556 | zDateOvrd, zUserOvrd); |
| 499 | 557 | db_end_transaction(0); |
| 500 | 558 | }else |
| 501 | 559 | |
| 502 | 560 | if( strncmp(g.argv[2],"find",n)==0 ){ |
| 503 | 561 | |