Fossil SCM

Enable propagating tags for forum, wiki, and technotes.

drh 2021-06-03 23:57 trunk merge
Commit 7c64fe0b677344e0209731b04925a7aa8a84648d4b2c9482649c5dfbc6a2116f
+1 -1
--- src/info.c
+++ src/info.c
@@ -509,11 +509,11 @@
509509
style_finish_page();
510510
return;
511511
}
512512
zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
513513
style_header("Tags and Properties");
514
- zType = whatis_rid_type(rid);
514
+ zType = whatis_rid_type_label(rid);
515515
if(!zType) zType = "Artifact";
516516
@ <h1>Tags and Properties for %s(zType) \
517517
@ %z(href("%R/ci/%!S",zHash))%S(zHash)</a></h1>
518518
db_prepare(&q,
519519
"SELECT tag.tagid, tagname, "
520520
--- src/info.c
+++ src/info.c
@@ -509,11 +509,11 @@
509 style_finish_page();
510 return;
511 }
512 zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
513 style_header("Tags and Properties");
514 zType = whatis_rid_type(rid);
515 if(!zType) zType = "Artifact";
516 @ <h1>Tags and Properties for %s(zType) \
517 @ %z(href("%R/ci/%!S",zHash))%S(zHash)</a></h1>
518 db_prepare(&q,
519 "SELECT tag.tagid, tagname, "
520
--- src/info.c
+++ src/info.c
@@ -509,11 +509,11 @@
509 style_finish_page();
510 return;
511 }
512 zHash = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
513 style_header("Tags and Properties");
514 zType = whatis_rid_type_label(rid);
515 if(!zType) zType = "Artifact";
516 @ <h1>Tags and Properties for %s(zType) \
517 @ %z(href("%R/ci/%!S",zHash))%S(zHash)</a></h1>
518 db_prepare(&q,
519 "SELECT tag.tagid, tagname, "
520
--- src/manifest.c
+++ src/manifest.c
@@ -2250,10 +2250,38 @@
22502250
if( c==0 ){
22512251
c = fossil_strcmp(pA->zName, pB->zName);
22522252
}
22532253
return c;
22542254
}
2255
+
2256
+/*
2257
+** Inserts plink entries for FORUM, WIKI, and TECHNOTE manifests. May
2258
+** assert for other manifest types. If a parent entry exists, it also
2259
+** propagates any tags for that parent. This is a no-op if
2260
+** p->nParent==0.
2261
+*/
2262
+static void manifest_add_fwt_plink(int rid, Manifest *p){
2263
+ int i;
2264
+ int parentId = 0;
2265
+ assert(p->type==CFTYPE_WIKI ||
2266
+ p->type==CFTYPE_FORUM ||
2267
+ p->type==CFTYPE_EVENT);
2268
+ for(i=0; i<p->nParent; ++i){
2269
+ int const pid = uuid_to_rid(p->azParent[i], 1);
2270
+ if(0==i){
2271
+ parentId = pid;
2272
+ }
2273
+ db_multi_exec(
2274
+ "INSERT OR IGNORE INTO plink"
2275
+ "(pid, cid, isprim, mtime, baseid)"
2276
+ "VALUES(%d, %d, %d, %.17g, NULL)",
2277
+ pid, rid, i==0, p->rDate);
2278
+ }
2279
+ if(parentId){
2280
+ tag_propagate_all(parentId);
2281
+ }
2282
+}
22552283
22562284
/*
22572285
** Scan artifact rid/pContent to see if it is a control artifact of
22582286
** any type:
22592287
**
@@ -2416,10 +2444,14 @@
24162444
}
24172445
}
24182446
if( parentid ){
24192447
tag_propagate_all(parentid);
24202448
}
2449
+ }
2450
+ if(p->type==CFTYPE_WIKI || p->type==CFTYPE_FORUM
2451
+ || p->type==CFTYPE_EVENT){
2452
+ manifest_add_fwt_plink(rid, p);
24212453
}
24222454
if( p->type==CFTYPE_WIKI ){
24232455
char *zTag = mprintf("wiki-%s", p->zWikiTitle);
24242456
int prior = 0;
24252457
char cPrefix;
@@ -2814,10 +2846,11 @@
28142846
}
28152847
if( p->zWiki[0] ){
28162848
backlink_extract(p->zWiki, p->zMimetype, rid, BKLNK_FORUM, p->rDate, 1);
28172849
}
28182850
}
2851
+
28192852
db_end_transaction(0);
28202853
if( permitHooks ){
28212854
rc = xfer_run_common_script();
28222855
if( rc==TH_OK ){
28232856
rc = xfer_run_script(zScript, zUuid, 0);
28242857
--- src/manifest.c
+++ src/manifest.c
@@ -2250,10 +2250,38 @@
2250 if( c==0 ){
2251 c = fossil_strcmp(pA->zName, pB->zName);
2252 }
2253 return c;
2254 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2255
2256 /*
2257 ** Scan artifact rid/pContent to see if it is a control artifact of
2258 ** any type:
2259 **
@@ -2416,10 +2444,14 @@
2416 }
2417 }
2418 if( parentid ){
2419 tag_propagate_all(parentid);
2420 }
 
 
 
 
2421 }
2422 if( p->type==CFTYPE_WIKI ){
2423 char *zTag = mprintf("wiki-%s", p->zWikiTitle);
2424 int prior = 0;
2425 char cPrefix;
@@ -2814,10 +2846,11 @@
2814 }
2815 if( p->zWiki[0] ){
2816 backlink_extract(p->zWiki, p->zMimetype, rid, BKLNK_FORUM, p->rDate, 1);
2817 }
2818 }
 
2819 db_end_transaction(0);
2820 if( permitHooks ){
2821 rc = xfer_run_common_script();
2822 if( rc==TH_OK ){
2823 rc = xfer_run_script(zScript, zUuid, 0);
2824
--- src/manifest.c
+++ src/manifest.c
@@ -2250,10 +2250,38 @@
2250 if( c==0 ){
2251 c = fossil_strcmp(pA->zName, pB->zName);
2252 }
2253 return c;
2254 }
2255
2256 /*
2257 ** Inserts plink entries for FORUM, WIKI, and TECHNOTE manifests. May
2258 ** assert for other manifest types. If a parent entry exists, it also
2259 ** propagates any tags for that parent. This is a no-op if
2260 ** p->nParent==0.
2261 */
2262 static void manifest_add_fwt_plink(int rid, Manifest *p){
2263 int i;
2264 int parentId = 0;
2265 assert(p->type==CFTYPE_WIKI ||
2266 p->type==CFTYPE_FORUM ||
2267 p->type==CFTYPE_EVENT);
2268 for(i=0; i<p->nParent; ++i){
2269 int const pid = uuid_to_rid(p->azParent[i], 1);
2270 if(0==i){
2271 parentId = pid;
2272 }
2273 db_multi_exec(
2274 "INSERT OR IGNORE INTO plink"
2275 "(pid, cid, isprim, mtime, baseid)"
2276 "VALUES(%d, %d, %d, %.17g, NULL)",
2277 pid, rid, i==0, p->rDate);
2278 }
2279 if(parentId){
2280 tag_propagate_all(parentId);
2281 }
2282 }
2283
2284 /*
2285 ** Scan artifact rid/pContent to see if it is a control artifact of
2286 ** any type:
2287 **
@@ -2416,10 +2444,14 @@
2444 }
2445 }
2446 if( parentid ){
2447 tag_propagate_all(parentid);
2448 }
2449 }
2450 if(p->type==CFTYPE_WIKI || p->type==CFTYPE_FORUM
2451 || p->type==CFTYPE_EVENT){
2452 manifest_add_fwt_plink(rid, p);
2453 }
2454 if( p->type==CFTYPE_WIKI ){
2455 char *zTag = mprintf("wiki-%s", p->zWikiTitle);
2456 int prior = 0;
2457 char cPrefix;
@@ -2814,10 +2846,11 @@
2846 }
2847 if( p->zWiki[0] ){
2848 backlink_extract(p->zWiki, p->zMimetype, rid, BKLNK_FORUM, p->rDate, 1);
2849 }
2850 }
2851
2852 db_end_transaction(0);
2853 if( permitHooks ){
2854 rc = xfer_run_common_script();
2855 if( rc==TH_OK ){
2856 rc = xfer_run_script(zScript, zUuid, 0);
2857
+39 -15
--- src/name.c
+++ src/name.c
@@ -740,36 +740,60 @@
740740
return rid;
741741
}
742742
743743
/*
744744
** Given an RID of a structural artifact, which is assumed to be
745
-** valid, this function returns a brief string (in static memory)
746
-** describing the record type. Returns NULL if rid does not refer to
747
-** an artifact record (as determined by reading the event table). The
748
-** returned string is intended to be used in headers which can refer
749
-** to different artifact types. It is not "definitive," in that it
750
-** does not distinguish between closely-related types like wiki
751
-** creation, edit, and removal.
745
+** valid, this function returns one of the CFTYPE_xxx values
746
+** describing the record type, or 0 if the RID does not refer to an
747
+** artifact record (as determined by reading the event table).
748
+**
749
+** Note that this function neve returns CFTYPE_ATTACHMENT or
750
+** CFTYPE_CLUSTER because those are not used in the event table. Thus
751
+** it cannot be used to distinguish those artifact types from
752
+** non-artifact file content.
752753
*/
753
-char const * whatis_rid_type(int rid){
754
+int whatis_rid_type(int rid){
754755
Stmt q = empty_Stmt;
755
- char const * zType = 0;
756
+ int type = 0;
756757
/* Check for entries on the timeline that reference this object */
757758
db_prepare(&q,
758759
"SELECT type FROM event WHERE objid=%d", rid);
759760
if( db_step(&q)==SQLITE_ROW ){
760761
switch( db_column_text(&q,0)[0] ){
761
- case 'c': zType = "Check-in"; break;
762
- case 'w': zType = "Wiki-edit"; break;
763
- case 'e': zType = "Technote"; break;
764
- case 'f': zType = "Forum-post"; break;
765
- case 't': zType = "Ticket-change"; break;
766
- case 'g': zType = "Tag-change"; break;
762
+ case 'c': type = CFTYPE_MANIFEST; break;
763
+ case 'w': type = CFTYPE_WIKI; break;
764
+ case 'e': type = CFTYPE_EVENT; break;
765
+ case 'f': type = CFTYPE_FORUM; break;
766
+ case 't': type = CFTYPE_TICKET; break;
767
+ case 'g': type = CFTYPE_CONTROL; break;
767768
default: break;
768769
}
769770
}
770771
db_finalize(&q);
772
+ return type;
773
+}
774
+
775
+/*
776
+** A proxy for whatis_rid_type() which returns a brief string (in
777
+** static memory) describing the record type. Returns NULL if rid does
778
+** not refer to an artifact record (as determined by reading the event
779
+** table). The returned string is intended to be used in headers which
780
+** can refer to different artifact types. It is not "definitive," in
781
+** that it does not distinguish between closely-related types like
782
+** wiki creation, edit, and removal.
783
+*/
784
+char const * whatis_rid_type_label(int rid){
785
+ char const * zType = 0;
786
+ switch( whatis_rid_type(rid) ){
787
+ case CFTYPE_MANIFEST: zType = "Check-in"; break;
788
+ case CFTYPE_WIKI: zType = "Wiki-edit"; break;
789
+ case CFTYPE_EVENT: zType = "Technote"; break;
790
+ case CFTYPE_FORUM: zType = "Forum-post"; break;
791
+ case CFTYPE_TICKET: zType = "Ticket-change"; break;
792
+ case CFTYPE_CONTROL: zType = "Tag-change"; break;
793
+ default: break;
794
+ }
771795
return zType;
772796
}
773797
774798
/*
775799
** Generate a description of artifact "rid"
776800
--- src/name.c
+++ src/name.c
@@ -740,36 +740,60 @@
740 return rid;
741 }
742
743 /*
744 ** Given an RID of a structural artifact, which is assumed to be
745 ** valid, this function returns a brief string (in static memory)
746 ** describing the record type. Returns NULL if rid does not refer to
747 ** an artifact record (as determined by reading the event table). The
748 ** returned string is intended to be used in headers which can refer
749 ** to different artifact types. It is not "definitive," in that it
750 ** does not distinguish between closely-related types like wiki
751 ** creation, edit, and removal.
 
752 */
753 char const * whatis_rid_type(int rid){
754 Stmt q = empty_Stmt;
755 char const * zType = 0;
756 /* Check for entries on the timeline that reference this object */
757 db_prepare(&q,
758 "SELECT type FROM event WHERE objid=%d", rid);
759 if( db_step(&q)==SQLITE_ROW ){
760 switch( db_column_text(&q,0)[0] ){
761 case 'c': zType = "Check-in"; break;
762 case 'w': zType = "Wiki-edit"; break;
763 case 'e': zType = "Technote"; break;
764 case 'f': zType = "Forum-post"; break;
765 case 't': zType = "Ticket-change"; break;
766 case 'g': zType = "Tag-change"; break;
767 default: break;
768 }
769 }
770 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
771 return zType;
772 }
773
774 /*
775 ** Generate a description of artifact "rid"
776
--- src/name.c
+++ src/name.c
@@ -740,36 +740,60 @@
740 return rid;
741 }
742
743 /*
744 ** Given an RID of a structural artifact, which is assumed to be
745 ** valid, this function returns one of the CFTYPE_xxx values
746 ** describing the record type, or 0 if the RID does not refer to an
747 ** artifact record (as determined by reading the event table).
748 **
749 ** Note that this function neve returns CFTYPE_ATTACHMENT or
750 ** CFTYPE_CLUSTER because those are not used in the event table. Thus
751 ** it cannot be used to distinguish those artifact types from
752 ** non-artifact file content.
753 */
754 int whatis_rid_type(int rid){
755 Stmt q = empty_Stmt;
756 int type = 0;
757 /* Check for entries on the timeline that reference this object */
758 db_prepare(&q,
759 "SELECT type FROM event WHERE objid=%d", rid);
760 if( db_step(&q)==SQLITE_ROW ){
761 switch( db_column_text(&q,0)[0] ){
762 case 'c': type = CFTYPE_MANIFEST; break;
763 case 'w': type = CFTYPE_WIKI; break;
764 case 'e': type = CFTYPE_EVENT; break;
765 case 'f': type = CFTYPE_FORUM; break;
766 case 't': type = CFTYPE_TICKET; break;
767 case 'g': type = CFTYPE_CONTROL; break;
768 default: break;
769 }
770 }
771 db_finalize(&q);
772 return type;
773 }
774
775 /*
776 ** A proxy for whatis_rid_type() which returns a brief string (in
777 ** static memory) describing the record type. Returns NULL if rid does
778 ** not refer to an artifact record (as determined by reading the event
779 ** table). The returned string is intended to be used in headers which
780 ** can refer to different artifact types. It is not "definitive," in
781 ** that it does not distinguish between closely-related types like
782 ** wiki creation, edit, and removal.
783 */
784 char const * whatis_rid_type_label(int rid){
785 char const * zType = 0;
786 switch( whatis_rid_type(rid) ){
787 case CFTYPE_MANIFEST: zType = "Check-in"; break;
788 case CFTYPE_WIKI: zType = "Wiki-edit"; break;
789 case CFTYPE_EVENT: zType = "Technote"; break;
790 case CFTYPE_FORUM: zType = "Forum-post"; break;
791 case CFTYPE_TICKET: zType = "Ticket-change"; break;
792 case CFTYPE_CONTROL: zType = "Tag-change"; break;
793 default: break;
794 }
795 return zType;
796 }
797
798 /*
799 ** Generate a description of artifact "rid"
800
+80 -22
--- src/tag.c
+++ src/tag.c
@@ -363,45 +363,71 @@
363363
assert( blob_is_reset(&ctrl) );
364364
if( g.localOpen ){
365365
manifest_to_disk(rid);
366366
}
367367
}
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
+}
368384
369385
/*
370386
** COMMAND: tag
371387
**
372388
** Usage: %fossil tag SUBCOMMAND ...
373389
**
374390
** Run various subcommands to control tags and properties.
375391
**
376
-** > fossil tag add ?OPTIONS? TAGNAME CHECK-IN ?VALUE?
392
+** > fossil tag add ?OPTIONS? TAGNAME ARTIFACT-ID ?VALUE?
377393
**
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.
382400
**
383401
** 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.
390409
**
391410
** The --date-override and --user-override options support
392411
** importing history from other SCM systems. DATETIME has
393412
** the form 'YYYY-MMM-DD HH:MM:SS'.
394413
**
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
396419
**
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.
400425
**
401426
** Options:
402
-** --raw Raw tag name.
427
+** --raw Raw tag name. Ignored for
428
+** non-CHECK-IN artifacts.
403429
** --date-override DATETIME Set date and time deleted.
404430
** --user-override USER Name USER when deleting the tag.
405431
** -n|--dryrun Display the control artifact, but do
406432
** not insert it into the database.
407433
**
@@ -461,21 +487,37 @@
461487
462488
if( strncmp(g.argv[2],"add",n)==0 ){
463489
char *zValue;
464490
int dryRun = 0;
465491
int fRaw = find_option("raw","",0)!=0;
466
- const char *zPrefix = fRaw ? "" : "sym-";
492
+ const char *zPrefix = "";
467493
int fPropagate = find_option("propagate","",0)!=0;
468494
const char *zDateOvrd = find_option("date-override",0,1);
469495
const char *zUserOvrd = find_option("user-override",0,1);
496
+ const char *zTag;
497
+ const char *zObjId;
498
+ int objType;
470499
if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
471500
if( g.argc!=5 && g.argc!=6 ){
472
- usage("add ?options? TAGNAME CHECK-IN ?VALUE?");
501
+ usage("add ?options? TAGNAME ARTIFACT-ID ?VALUE?");
473502
}
503
+ zTag = g.argv[3];
504
+ tag_cmd_tagname_check(zTag);
505
+ zObjId = g.argv[4];
474506
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
+ }
475517
db_begin_transaction();
476
- tag_add_artifact(zPrefix, g.argv[3], g.argv[4], zValue,
518
+ tag_add_artifact(zPrefix, zTag, zObjId, zValue,
477519
1+fPropagate+dryRun,zDateOvrd,zUserOvrd);
478520
db_end_transaction(0);
479521
}else
480522
481523
if( strncmp(g.argv[2],"branch",n)==0 ){
@@ -484,19 +526,35 @@
484526
}else
485527
486528
if( strncmp(g.argv[2],"cancel",n)==0 ){
487529
int dryRun = 0;
488530
int fRaw = find_option("raw","",0)!=0;
489
- const char *zPrefix = fRaw ? "" : "sym-";
531
+ const char *zPrefix = "";
490532
const char *zDateOvrd = find_option("date-override",0,1);
491533
const char *zUserOvrd = find_option("user-override",0,1);
534
+ const char *zTag;
535
+ const char *zObjId;
536
+ int objType;
492537
if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
493538
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;
495553
}
496554
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,
498556
zDateOvrd, zUserOvrd);
499557
db_end_transaction(0);
500558
}else
501559
502560
if( strncmp(g.argv[2],"find",n)==0 ){
503561
--- src/tag.c
+++ src/tag.c
@@ -363,45 +363,71 @@
363 assert( blob_is_reset(&ctrl) );
364 if( g.localOpen ){
365 manifest_to_disk(rid);
366 }
367 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
369 /*
370 ** COMMAND: tag
371 **
372 ** Usage: %fossil tag SUBCOMMAND ...
373 **
374 ** Run various subcommands to control tags and properties.
375 **
376 ** > fossil tag add ?OPTIONS? TAGNAME CHECK-IN ?VALUE?
377 **
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
 
 
382 **
383 ** 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.
 
390 **
391 ** The --date-override and --user-override options support
392 ** importing history from other SCM systems. DATETIME has
393 ** the form 'YYYY-MMM-DD HH:MM:SS'.
394 **
395 ** > fossil tag cancel ?--raw? TAGNAME CHECK-IN
 
 
 
 
396 **
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.
 
 
400 **
401 ** Options:
402 ** --raw Raw tag name.
 
403 ** --date-override DATETIME Set date and time deleted.
404 ** --user-override USER Name USER when deleting the tag.
405 ** -n|--dryrun Display the control artifact, but do
406 ** not insert it into the database.
407 **
@@ -461,21 +487,37 @@
461
462 if( strncmp(g.argv[2],"add",n)==0 ){
463 char *zValue;
464 int dryRun = 0;
465 int fRaw = find_option("raw","",0)!=0;
466 const char *zPrefix = fRaw ? "" : "sym-";
467 int fPropagate = find_option("propagate","",0)!=0;
468 const char *zDateOvrd = find_option("date-override",0,1);
469 const char *zUserOvrd = find_option("user-override",0,1);
 
 
 
470 if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
471 if( g.argc!=5 && g.argc!=6 ){
472 usage("add ?options? TAGNAME CHECK-IN ?VALUE?");
473 }
 
 
 
474 zValue = g.argc==6 ? g.argv[5] : 0;
 
 
 
 
 
 
 
 
 
 
475 db_begin_transaction();
476 tag_add_artifact(zPrefix, g.argv[3], g.argv[4], zValue,
477 1+fPropagate+dryRun,zDateOvrd,zUserOvrd);
478 db_end_transaction(0);
479 }else
480
481 if( strncmp(g.argv[2],"branch",n)==0 ){
@@ -484,19 +526,35 @@
484 }else
485
486 if( strncmp(g.argv[2],"cancel",n)==0 ){
487 int dryRun = 0;
488 int fRaw = find_option("raw","",0)!=0;
489 const char *zPrefix = fRaw ? "" : "sym-";
490 const char *zDateOvrd = find_option("date-override",0,1);
491 const char *zUserOvrd = find_option("user-override",0,1);
 
 
 
492 if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
493 if( g.argc!=5 ){
494 usage("cancel ?options? TAGNAME CHECK-IN");
 
 
 
 
 
 
 
 
 
 
 
 
 
495 }
496 db_begin_transaction();
497 tag_add_artifact(zPrefix, g.argv[3], g.argv[4], 0, dryRun,
498 zDateOvrd, zUserOvrd);
499 db_end_transaction(0);
500 }else
501
502 if( strncmp(g.argv[2],"find",n)==0 ){
503
--- src/tag.c
+++ src/tag.c
@@ -363,45 +363,71 @@
363 assert( blob_is_reset(&ctrl) );
364 if( g.localOpen ){
365 manifest_to_disk(rid);
366 }
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 }
384
385 /*
386 ** COMMAND: tag
387 **
388 ** Usage: %fossil tag SUBCOMMAND ...
389 **
390 ** Run various subcommands to control tags and properties.
391 **
392 ** > fossil tag add ?OPTIONS? TAGNAME ARTIFACT-ID ?VALUE?
393 **
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.
400 **
401 ** Options:
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.
409 **
410 ** The --date-override and --user-override options support
411 ** importing history from other SCM systems. DATETIME has
412 ** the form 'YYYY-MMM-DD HH:MM:SS'.
413 **
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
419 **
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.
425 **
426 ** Options:
427 ** --raw Raw tag name. Ignored for
428 ** non-CHECK-IN artifacts.
429 ** --date-override DATETIME Set date and time deleted.
430 ** --user-override USER Name USER when deleting the tag.
431 ** -n|--dryrun Display the control artifact, but do
432 ** not insert it into the database.
433 **
@@ -461,21 +487,37 @@
487
488 if( strncmp(g.argv[2],"add",n)==0 ){
489 char *zValue;
490 int dryRun = 0;
491 int fRaw = find_option("raw","",0)!=0;
492 const char *zPrefix = "";
493 int fPropagate = find_option("propagate","",0)!=0;
494 const char *zDateOvrd = find_option("date-override",0,1);
495 const char *zUserOvrd = find_option("user-override",0,1);
496 const char *zTag;
497 const char *zObjId;
498 int objType;
499 if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
500 if( g.argc!=5 && g.argc!=6 ){
501 usage("add ?options? TAGNAME ARTIFACT-ID ?VALUE?");
502 }
503 zTag = g.argv[3];
504 tag_cmd_tagname_check(zTag);
505 zObjId = g.argv[4];
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 }
517 db_begin_transaction();
518 tag_add_artifact(zPrefix, zTag, zObjId, zValue,
519 1+fPropagate+dryRun,zDateOvrd,zUserOvrd);
520 db_end_transaction(0);
521 }else
522
523 if( strncmp(g.argv[2],"branch",n)==0 ){
@@ -484,19 +526,35 @@
526 }else
527
528 if( strncmp(g.argv[2],"cancel",n)==0 ){
529 int dryRun = 0;
530 int fRaw = find_option("raw","",0)!=0;
531 const char *zPrefix = "";
532 const char *zDateOvrd = find_option("date-override",0,1);
533 const char *zUserOvrd = find_option("user-override",0,1);
534 const char *zTag;
535 const char *zObjId;
536 int objType;
537 if( find_option("dryrun","n",0)!=0 ) dryRun = TAG_ADD_DRYRUN;
538 if( g.argc!=5 ){
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;
553 }
554 db_begin_transaction();
555 tag_add_artifact(zPrefix, zTag, zObjId, 0, dryRun,
556 zDateOvrd, zUserOvrd);
557 db_end_transaction(0);
558 }else
559
560 if( strncmp(g.argv[2],"find",n)==0 ){
561

Keyboard Shortcuts

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