Fossil SCM

Rework the tag system so that propagation to children is a property of each tag and does not depend on the tag name beginning with "br". Older tag artifacts might not work. The database will need to be rebuilt after upgrading to this version.

drh 2007-09-22 23:41 trunk
Commit 09c4adeb6f9009bd4eb9893d1d4f8f676810c74b
+3 -3
--- src/info.c
+++ src/info.c
@@ -245,11 +245,11 @@
245245
static void showTags(int rid){
246246
Stmt q;
247247
int cnt = 0;
248248
db_prepare(&q,
249249
"SELECT tag.tagid, tagname, srcid, blob.uuid, value,"
250
- " datetime(tagxref.mtime,'localtime'), addflag"
250
+ " datetime(tagxref.mtime,'localtime'), tagtype"
251251
" FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid"
252252
" LEFT JOIN blob ON blob.rid=tagxref.srcid"
253253
" WHERE tagxref.rid=%d"
254254
" ORDER BY tagname", rid
255255
);
@@ -257,21 +257,21 @@
257257
const char *zTagname = db_column_text(&q, 1);
258258
int srcid = db_column_int(&q, 2);
259259
const char *zUuid = db_column_text(&q, 3);
260260
const char *zValue = db_column_text(&q, 4);
261261
const char *zDate = db_column_text(&q, 5);
262
- int addFlag = db_column_int(&q, 6);
262
+ int tagtype = db_column_int(&q, 6);
263263
cnt++;
264264
if( cnt==1 ){
265265
@ <h2>Tags And Properties</h2>
266266
@ <ul>
267267
}
268268
@ <li>
269269
@ <b>%h(zTagname)</b>
270270
if( zValue ){
271271
@ = %h(zValue)<i>
272
- }else if( !addFlag ){
272
+ }else if( tagtype==0 ){
273273
@ <i>Cancelled
274274
}else{
275275
@ <i>
276276
}
277277
if( srcid==0 ){
278278
--- src/info.c
+++ src/info.c
@@ -245,11 +245,11 @@
245 static void showTags(int rid){
246 Stmt q;
247 int cnt = 0;
248 db_prepare(&q,
249 "SELECT tag.tagid, tagname, srcid, blob.uuid, value,"
250 " datetime(tagxref.mtime,'localtime'), addflag"
251 " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid"
252 " LEFT JOIN blob ON blob.rid=tagxref.srcid"
253 " WHERE tagxref.rid=%d"
254 " ORDER BY tagname", rid
255 );
@@ -257,21 +257,21 @@
257 const char *zTagname = db_column_text(&q, 1);
258 int srcid = db_column_int(&q, 2);
259 const char *zUuid = db_column_text(&q, 3);
260 const char *zValue = db_column_text(&q, 4);
261 const char *zDate = db_column_text(&q, 5);
262 int addFlag = db_column_int(&q, 6);
263 cnt++;
264 if( cnt==1 ){
265 @ <h2>Tags And Properties</h2>
266 @ <ul>
267 }
268 @ <li>
269 @ <b>%h(zTagname)</b>
270 if( zValue ){
271 @ = %h(zValue)<i>
272 }else if( !addFlag ){
273 @ <i>Cancelled
274 }else{
275 @ <i>
276 }
277 if( srcid==0 ){
278
--- src/info.c
+++ src/info.c
@@ -245,11 +245,11 @@
245 static void showTags(int rid){
246 Stmt q;
247 int cnt = 0;
248 db_prepare(&q,
249 "SELECT tag.tagid, tagname, srcid, blob.uuid, value,"
250 " datetime(tagxref.mtime,'localtime'), tagtype"
251 " FROM tagxref JOIN tag ON tagxref.tagid=tag.tagid"
252 " LEFT JOIN blob ON blob.rid=tagxref.srcid"
253 " WHERE tagxref.rid=%d"
254 " ORDER BY tagname", rid
255 );
@@ -257,21 +257,21 @@
257 const char *zTagname = db_column_text(&q, 1);
258 int srcid = db_column_int(&q, 2);
259 const char *zUuid = db_column_text(&q, 3);
260 const char *zValue = db_column_text(&q, 4);
261 const char *zDate = db_column_text(&q, 5);
262 int tagtype = db_column_int(&q, 6);
263 cnt++;
264 if( cnt==1 ){
265 @ <h2>Tags And Properties</h2>
266 @ <ul>
267 }
268 @ <li>
269 @ <b>%h(zTagname)</b>
270 if( zValue ){
271 @ = %h(zValue)<i>
272 }else if( tagtype==0 ){
273 @ <i>Cancelled
274 }else{
275 @ <i>
276 }
277 if( srcid==0 ){
278
+34 -10
--- src/manifest.c
+++ src/manifest.c
@@ -20,11 +20,13 @@
2020
** http://www.hwaci.com/drh/
2121
**
2222
*******************************************************************************
2323
**
2424
** This file contains code used to cross link control files and
25
-** manifests.
25
+** manifests. The file is named "manifest.c" because it was
26
+** original only used to parse manifests. Then later clusters
27
+** and control files were added.
2628
*/
2729
#include "config.h"
2830
#include "manifest.h"
2931
#include <assert.h>
3032
@@ -41,10 +43,11 @@
4143
*/
4244
struct Manifest {
4345
Blob content; /* The original content blob */
4446
int type; /* Type of file */
4547
char *zComment; /* Decoded comment */
48
+ char zUuid[UUID_SIZE+1]; /* Self UUID */
4649
double rDate; /* Time in the "D" line */
4750
char *zUser; /* Name of the user */
4851
char *zRepoCksum; /* MD5 checksum of the baseline content */
4952
int nFile; /* Number of F lines */
5053
int nFileAlloc; /* Slots allocated in aFile[] */
@@ -96,14 +99,18 @@
9699
*/
97100
int manifest_parse(Manifest *p, Blob *pContent){
98101
int seenHeader = 0;
99102
int i;
100103
Blob line, token, a1, a2, a3;
104
+ Blob selfuuid;
101105
char zPrevLine[10];
102106
103107
memset(p, 0, sizeof(*p));
104108
memcpy(&p->content, pContent, sizeof(p->content));
109
+ sha1sum_blob(&p->content, &selfuuid);
110
+ memcpy(p->zUuid, blob_buffer(&selfuuid), UUID_SIZE);
111
+ p->zUuid[UUID_SIZE] = 0;
105112
blob_zero(pContent);
106113
pContent = &p->content;
107114
108115
blob_zero(&a1);
109116
blob_zero(&a2);
@@ -226,16 +233,22 @@
226233
}
227234
break;
228235
}
229236
230237
/*
231
- ** T (+|-)<tagname> <uuid> ?<value>?
238
+ ** T (+|*|-)<tagname> <uuid> ?<value>?
232239
**
233240
** Create or cancel a tag or property. The tagname is fossil-encoded.
234
- ** The first character of the name must be either "+" to create or
235
- ** "-" to cancel. The tag is applied to <uuid>. If <value> is
236
- ** provided then the tag is really a property with the given value.
241
+ ** The first character of the name must be either "+" to create a
242
+ ** singleton tag, "*" to create a propagating tag, or "-" to create
243
+ ** anti-tag that undoes a prior "+" or blocks propagation of of
244
+ ** a "*".
245
+ **
246
+ ** The tag is applied to <uuid>. If <uuid> is "*" then the tag is
247
+ ** applied to the current manifest. If <value> is provided then
248
+ ** the tag is really a property with the given value.
249
+ **
237250
** Tags are not allowed in clusters. Multiple T lines are allowed.
238251
*/
239252
case 'T': {
240253
char *zName, *zUuid, *zValue;
241254
md5sum_step_text(blob_buffer(&line), blob_size(&line));
@@ -247,14 +260,19 @@
247260
zValue = 0;
248261
}else{
249262
zValue = blob_terminate(&a3);
250263
defossilize(zValue);
251264
}
252
- if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
253
- if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
265
+ if( blob_size(&a2)==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){
266
+ /* A valid uuid */
267
+ }else if( blob_size(&a2)==1 && zUuid[0]=='*' ){
268
+ zUuid = p->zUuid;
269
+ }else{
270
+ goto manifest_syntax_error;
271
+ }
254272
defossilize(zName);
255
- if( zName[0]!='-' && zName[0]!='+' ){
273
+ if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
256274
goto manifest_syntax_error;
257275
}
258276
if( validate16(&zName[1], strlen(&zName[1])) ){
259277
/* Do not allow tags whose names look like UUIDs */
260278
goto manifest_syntax_error;
@@ -532,14 +550,20 @@
532550
}
533551
}
534552
if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){
535553
for(i=0; i<m.nTag; i++){
536554
int tid;
555
+ int type;
537556
tid = uuid_to_rid(m.aTag[i].zUuid, 1);
538
- tag_insert(&m.aTag[i].zName[1], m.aTag[i].zName[0]=='+',
539
- m.aTag[i].zValue, rid, m.rDate, tid);
557
+ switch( m.aTag[i].zName[0] ){
558
+ case '+': type = 1; break;
559
+ case '*': type = 2; break;
560
+ case '-': type = 0; break;
561
+ }
562
+ tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue,
563
+ rid, m.rDate, tid);
540564
}
541565
}
542566
db_end_transaction(0);
543567
manifest_clear(&m);
544568
return 1;
545569
}
546570
--- src/manifest.c
+++ src/manifest.c
@@ -20,11 +20,13 @@
20 ** http://www.hwaci.com/drh/
21 **
22 *******************************************************************************
23 **
24 ** This file contains code used to cross link control files and
25 ** manifests.
 
 
26 */
27 #include "config.h"
28 #include "manifest.h"
29 #include <assert.h>
30
@@ -41,10 +43,11 @@
41 */
42 struct Manifest {
43 Blob content; /* The original content blob */
44 int type; /* Type of file */
45 char *zComment; /* Decoded comment */
 
46 double rDate; /* Time in the "D" line */
47 char *zUser; /* Name of the user */
48 char *zRepoCksum; /* MD5 checksum of the baseline content */
49 int nFile; /* Number of F lines */
50 int nFileAlloc; /* Slots allocated in aFile[] */
@@ -96,14 +99,18 @@
96 */
97 int manifest_parse(Manifest *p, Blob *pContent){
98 int seenHeader = 0;
99 int i;
100 Blob line, token, a1, a2, a3;
 
101 char zPrevLine[10];
102
103 memset(p, 0, sizeof(*p));
104 memcpy(&p->content, pContent, sizeof(p->content));
 
 
 
105 blob_zero(pContent);
106 pContent = &p->content;
107
108 blob_zero(&a1);
109 blob_zero(&a2);
@@ -226,16 +233,22 @@
226 }
227 break;
228 }
229
230 /*
231 ** T (+|-)<tagname> <uuid> ?<value>?
232 **
233 ** Create or cancel a tag or property. The tagname is fossil-encoded.
234 ** The first character of the name must be either "+" to create or
235 ** "-" to cancel. The tag is applied to <uuid>. If <value> is
236 ** provided then the tag is really a property with the given value.
 
 
 
 
 
 
237 ** Tags are not allowed in clusters. Multiple T lines are allowed.
238 */
239 case 'T': {
240 char *zName, *zUuid, *zValue;
241 md5sum_step_text(blob_buffer(&line), blob_size(&line));
@@ -247,14 +260,19 @@
247 zValue = 0;
248 }else{
249 zValue = blob_terminate(&a3);
250 defossilize(zValue);
251 }
252 if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
253 if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
 
 
 
 
 
254 defossilize(zName);
255 if( zName[0]!='-' && zName[0]!='+' ){
256 goto manifest_syntax_error;
257 }
258 if( validate16(&zName[1], strlen(&zName[1])) ){
259 /* Do not allow tags whose names look like UUIDs */
260 goto manifest_syntax_error;
@@ -532,14 +550,20 @@
532 }
533 }
534 if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){
535 for(i=0; i<m.nTag; i++){
536 int tid;
 
537 tid = uuid_to_rid(m.aTag[i].zUuid, 1);
538 tag_insert(&m.aTag[i].zName[1], m.aTag[i].zName[0]=='+',
539 m.aTag[i].zValue, rid, m.rDate, tid);
 
 
 
 
 
540 }
541 }
542 db_end_transaction(0);
543 manifest_clear(&m);
544 return 1;
545 }
546
--- src/manifest.c
+++ src/manifest.c
@@ -20,11 +20,13 @@
20 ** http://www.hwaci.com/drh/
21 **
22 *******************************************************************************
23 **
24 ** This file contains code used to cross link control files and
25 ** manifests. The file is named "manifest.c" because it was
26 ** original only used to parse manifests. Then later clusters
27 ** and control files were added.
28 */
29 #include "config.h"
30 #include "manifest.h"
31 #include <assert.h>
32
@@ -41,10 +43,11 @@
43 */
44 struct Manifest {
45 Blob content; /* The original content blob */
46 int type; /* Type of file */
47 char *zComment; /* Decoded comment */
48 char zUuid[UUID_SIZE+1]; /* Self UUID */
49 double rDate; /* Time in the "D" line */
50 char *zUser; /* Name of the user */
51 char *zRepoCksum; /* MD5 checksum of the baseline content */
52 int nFile; /* Number of F lines */
53 int nFileAlloc; /* Slots allocated in aFile[] */
@@ -96,14 +99,18 @@
99 */
100 int manifest_parse(Manifest *p, Blob *pContent){
101 int seenHeader = 0;
102 int i;
103 Blob line, token, a1, a2, a3;
104 Blob selfuuid;
105 char zPrevLine[10];
106
107 memset(p, 0, sizeof(*p));
108 memcpy(&p->content, pContent, sizeof(p->content));
109 sha1sum_blob(&p->content, &selfuuid);
110 memcpy(p->zUuid, blob_buffer(&selfuuid), UUID_SIZE);
111 p->zUuid[UUID_SIZE] = 0;
112 blob_zero(pContent);
113 pContent = &p->content;
114
115 blob_zero(&a1);
116 blob_zero(&a2);
@@ -226,16 +233,22 @@
233 }
234 break;
235 }
236
237 /*
238 ** T (+|*|-)<tagname> <uuid> ?<value>?
239 **
240 ** Create or cancel a tag or property. The tagname is fossil-encoded.
241 ** The first character of the name must be either "+" to create a
242 ** singleton tag, "*" to create a propagating tag, or "-" to create
243 ** anti-tag that undoes a prior "+" or blocks propagation of of
244 ** a "*".
245 **
246 ** The tag is applied to <uuid>. If <uuid> is "*" then the tag is
247 ** applied to the current manifest. If <value> is provided then
248 ** the tag is really a property with the given value.
249 **
250 ** Tags are not allowed in clusters. Multiple T lines are allowed.
251 */
252 case 'T': {
253 char *zName, *zUuid, *zValue;
254 md5sum_step_text(blob_buffer(&line), blob_size(&line));
@@ -247,14 +260,19 @@
260 zValue = 0;
261 }else{
262 zValue = blob_terminate(&a3);
263 defossilize(zValue);
264 }
265 if( blob_size(&a2)==UUID_SIZE && validate16(zUuid, UUID_SIZE) ){
266 /* A valid uuid */
267 }else if( blob_size(&a2)==1 && zUuid[0]=='*' ){
268 zUuid = p->zUuid;
269 }else{
270 goto manifest_syntax_error;
271 }
272 defossilize(zName);
273 if( zName[0]!='-' && zName[0]!='+' && zName[0]!='*' ){
274 goto manifest_syntax_error;
275 }
276 if( validate16(&zName[1], strlen(&zName[1])) ){
277 /* Do not allow tags whose names look like UUIDs */
278 goto manifest_syntax_error;
@@ -532,14 +550,20 @@
550 }
551 }
552 if( m.type==CFTYPE_CONTROL || m.type==CFTYPE_MANIFEST ){
553 for(i=0; i<m.nTag; i++){
554 int tid;
555 int type;
556 tid = uuid_to_rid(m.aTag[i].zUuid, 1);
557 switch( m.aTag[i].zName[0] ){
558 case '+': type = 1; break;
559 case '*': type = 2; break;
560 case '-': type = 0; break;
561 }
562 tag_insert(&m.aTag[i].zName[1], type, m.aTag[i].zValue,
563 rid, m.rDate, tid);
564 }
565 }
566 db_end_transaction(0);
567 manifest_clear(&m);
568 return 1;
569 }
570
+1 -1
--- src/name.c
+++ src/name.c
@@ -51,11 +51,11 @@
5151
5252
db_prepare(&q,
5353
"SELECT (SELECT uuid FROM blob WHERE rid=objid)"
5454
" FROM tagxref JOIN event ON rid=objid"
5555
" WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)"
56
- " AND addflag"
56
+ " AND tagtype>0"
5757
" AND value IS NULL"
5858
" ORDER BY event.mtime DESC",
5959
pName
6060
);
6161
blob_zero(&uuid);
6262
--- src/name.c
+++ src/name.c
@@ -51,11 +51,11 @@
51
52 db_prepare(&q,
53 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
54 " FROM tagxref JOIN event ON rid=objid"
55 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)"
56 " AND addflag"
57 " AND value IS NULL"
58 " ORDER BY event.mtime DESC",
59 pName
60 );
61 blob_zero(&uuid);
62
--- src/name.c
+++ src/name.c
@@ -51,11 +51,11 @@
51
52 db_prepare(&q,
53 "SELECT (SELECT uuid FROM blob WHERE rid=objid)"
54 " FROM tagxref JOIN event ON rid=objid"
55 " WHERE tagid=(SELECT tagid FROM tag WHERE tagname=%B)"
56 " AND tagtype>0"
57 " AND value IS NULL"
58 " ORDER BY event.mtime DESC",
59 pName
60 );
61 blob_zero(&uuid);
62
+6 -8
--- src/schema.c
+++ src/schema.c
@@ -204,25 +204,24 @@
204204
@ -- Tags that begin with "br" automatically propagate to direct
205205
@ -- children, but not to merge children.
206206
@ --
207207
@ CREATE TABLE tag(
208208
@ tagid INTEGER PRIMARY KEY, -- Numeric tag ID
209
-@ tagname TEXT UNIQUE -- Tag name. Prefixed by 'v' or 'b'
209
+@ tagname TEXT UNIQUE -- Tag name.
210210
@ );
211211
@ INSERT INTO tag VALUES(1, 'bgcolor'); -- TAG_BGCOLOR
212
-@ INSERT INTO tag VALUES(2, 'br-bgcolor'); -- TAG_BR_BGCOLOR
213
-@ INSERT INTO tag VALUES(3, 'comment'); -- TAG_COMMENT
214
-@ INSERT INTO tag VALUES(4, 'user'); -- TAG_USER
212
+@ INSERT INTO tag VALUES(2, 'comment'); -- TAG_COMMENT
213
+@ INSERT INTO tag VALUES(3, 'user'); -- TAG_USER
215214
@
216215
@ -- Assignments of tags to baselines. Note that we allow tags to
217216
@ -- have values assigned to them. So we are not really dealing with
218217
@ -- tags here. These are really properties. But we are going to
219218
@ -- keep calling them tags because in many cases the value is ignored.
220219
@ --
221220
@ CREATE TABLE tagxref(
222221
@ tagid INTEGER REFERENCES tag, -- The tag that added or removed
223
-@ addFlag BOOLEAN, -- True to add the tag, False to remove
222
+@ tagtype INTEGER, -- 0:cancel 1:single 2:branch
224223
@ srcid INTEGER REFERENCES blob, -- Origin of the tag. 0 for propagated tags
225224
@ value TEXT, -- Value of the tag. Might be NULL.
226225
@ mtime TIMESTAMP, -- Time of addition or removal
227226
@ rid INTEGER REFERENCE blob, -- Baseline that tag added/removed from
228227
@ UNIQUE(rid, tagid)
@@ -233,13 +232,12 @@
233232
/*
234233
** Predefined tagid values
235234
*/
236235
#if INTERFACE
237236
# define TAG_BGCOLOR 1
238
-# define TAG_BR_BGCOLOR 2
239
-# define TAG_COMMENT 3
240
-# define TAG_USER 4
237
+# define TAG_COMMENT 2
238
+# define TAG_USER 3
241239
#endif
242240
243241
/*
244242
** The schema for the locate FOSSIL database file found at the root
245243
** of very check-out. This database contains the complete state of
246244
--- src/schema.c
+++ src/schema.c
@@ -204,25 +204,24 @@
204 @ -- Tags that begin with "br" automatically propagate to direct
205 @ -- children, but not to merge children.
206 @ --
207 @ CREATE TABLE tag(
208 @ tagid INTEGER PRIMARY KEY, -- Numeric tag ID
209 @ tagname TEXT UNIQUE -- Tag name. Prefixed by 'v' or 'b'
210 @ );
211 @ INSERT INTO tag VALUES(1, 'bgcolor'); -- TAG_BGCOLOR
212 @ INSERT INTO tag VALUES(2, 'br-bgcolor'); -- TAG_BR_BGCOLOR
213 @ INSERT INTO tag VALUES(3, 'comment'); -- TAG_COMMENT
214 @ INSERT INTO tag VALUES(4, 'user'); -- TAG_USER
215 @
216 @ -- Assignments of tags to baselines. Note that we allow tags to
217 @ -- have values assigned to them. So we are not really dealing with
218 @ -- tags here. These are really properties. But we are going to
219 @ -- keep calling them tags because in many cases the value is ignored.
220 @ --
221 @ CREATE TABLE tagxref(
222 @ tagid INTEGER REFERENCES tag, -- The tag that added or removed
223 @ addFlag BOOLEAN, -- True to add the tag, False to remove
224 @ srcid INTEGER REFERENCES blob, -- Origin of the tag. 0 for propagated tags
225 @ value TEXT, -- Value of the tag. Might be NULL.
226 @ mtime TIMESTAMP, -- Time of addition or removal
227 @ rid INTEGER REFERENCE blob, -- Baseline that tag added/removed from
228 @ UNIQUE(rid, tagid)
@@ -233,13 +232,12 @@
233 /*
234 ** Predefined tagid values
235 */
236 #if INTERFACE
237 # define TAG_BGCOLOR 1
238 # define TAG_BR_BGCOLOR 2
239 # define TAG_COMMENT 3
240 # define TAG_USER 4
241 #endif
242
243 /*
244 ** The schema for the locate FOSSIL database file found at the root
245 ** of very check-out. This database contains the complete state of
246
--- src/schema.c
+++ src/schema.c
@@ -204,25 +204,24 @@
204 @ -- Tags that begin with "br" automatically propagate to direct
205 @ -- children, but not to merge children.
206 @ --
207 @ CREATE TABLE tag(
208 @ tagid INTEGER PRIMARY KEY, -- Numeric tag ID
209 @ tagname TEXT UNIQUE -- Tag name.
210 @ );
211 @ INSERT INTO tag VALUES(1, 'bgcolor'); -- TAG_BGCOLOR
212 @ INSERT INTO tag VALUES(2, 'comment'); -- TAG_COMMENT
213 @ INSERT INTO tag VALUES(3, 'user'); -- TAG_USER
 
214 @
215 @ -- Assignments of tags to baselines. Note that we allow tags to
216 @ -- have values assigned to them. So we are not really dealing with
217 @ -- tags here. These are really properties. But we are going to
218 @ -- keep calling them tags because in many cases the value is ignored.
219 @ --
220 @ CREATE TABLE tagxref(
221 @ tagid INTEGER REFERENCES tag, -- The tag that added or removed
222 @ tagtype INTEGER, -- 0:cancel 1:single 2:branch
223 @ srcid INTEGER REFERENCES blob, -- Origin of the tag. 0 for propagated tags
224 @ value TEXT, -- Value of the tag. Might be NULL.
225 @ mtime TIMESTAMP, -- Time of addition or removal
226 @ rid INTEGER REFERENCE blob, -- Baseline that tag added/removed from
227 @ UNIQUE(rid, tagid)
@@ -233,13 +232,12 @@
232 /*
233 ** Predefined tagid values
234 */
235 #if INTERFACE
236 # define TAG_BGCOLOR 1
237 # define TAG_COMMENT 2
238 # define TAG_USER 3
 
239 #endif
240
241 /*
242 ** The schema for the locate FOSSIL database file found at the root
243 ** of very check-out. This database contains the complete state of
244
+69 -63
--- src/tag.c
+++ src/tag.c
@@ -31,46 +31,49 @@
3131
** Propagate the tag given by tagid to the children of pid.
3232
**
3333
** This routine assumes that tagid is a tag that should be
3434
** propagated and that the tag is already present in pid.
3535
**
36
-** If addFlag is true then the tag is added. If false, then the
37
-** tag is removed.
36
+** If tagtype is 2 then the tag is being propagated from an
37
+** ancestor node. If tagtype is 0 it means a branch tag is
38
+** being cancelled.
3839
*/
3940
void tag_propagate(
4041
int pid, /* Propagate the tag to children of this node */
4142
int tagid, /* Tag to propagate */
42
- int addFlag, /* True to add the tag. False to delete it. */
43
+ int tagType, /* 2 for a propagating tag. 0 for an antitag */
4344
const char *zValue, /* Value of the tag. Might be NULL */
4445
double mtime /* Timestamp on the tag */
4546
){
4647
PQueue queue;
4748
Stmt s, ins, eventupdate;
49
+
50
+ assert( tagType==0 || tagType==2 );
4851
pqueue_init(&queue);
4952
pqueue_insert(&queue, pid, 0.0);
5053
db_prepare(&s,
5154
"SELECT cid, plink.mtime,"
5255
" coalesce(srcid=0 AND tagxref.mtime<:mtime, %d) AS doit"
5356
" FROM plink LEFT JOIN tagxref ON cid=rid AND tagid=%d"
5457
" WHERE pid=:pid AND isprim",
55
- addFlag, tagid
58
+ tagType!=0, tagid
5659
);
5760
db_bind_double(&s, ":mtime", mtime);
58
- if( addFlag ){
61
+ if( tagType==2 ){
5962
db_prepare(&ins,
60
- "REPLACE INTO tagxref(tagid, addFlag, srcid, value, mtime, rid)"
61
- "VALUES(%d,1,0,%Q,:mtime,:rid)",
63
+ "REPLACE INTO tagxref(tagid, tagtype, srcid, value, mtime, rid)"
64
+ "VALUES(%d,2,0,%Q,:mtime,:rid)",
6265
tagid, zValue
6366
);
6467
db_bind_double(&ins, ":mtime", mtime);
6568
}else{
6669
zValue = 0;
6770
db_prepare(&ins,
6871
"DELETE FROM tagxref WHERE tagid=%d AND rid=:rid", tagid
6972
);
7073
}
71
- if( tagid==TAG_BR_BGCOLOR ){
74
+ if( tagid==TAG_BGCOLOR ){
7275
db_prepare(&eventupdate,
7376
"UPDATE event SET brbgcolor=%Q WHERE objid=:rid", zValue
7477
);
7578
}
7679
while( (pid = pqueue_extract(&queue))!=0 ){
@@ -82,11 +85,11 @@
8285
double mtime = db_column_double(&s, 1);
8386
pqueue_insert(&queue, cid, mtime);
8487
db_bind_int(&ins, ":rid", cid);
8588
db_step(&ins);
8689
db_reset(&ins);
87
- if( tagid==TAG_BR_BGCOLOR ){
90
+ if( tagid==TAG_BGCOLOR ){
8891
db_bind_int(&eventupdate, ":rid", cid);
8992
db_step(&eventupdate);
9093
db_reset(&eventupdate);
9194
}
9295
}
@@ -94,11 +97,11 @@
9497
db_reset(&s);
9598
}
9699
pqueue_clear(&queue);
97100
db_finalize(&ins);
98101
db_finalize(&s);
99
- if( tagid==TAG_BR_BGCOLOR ){
102
+ if( tagid==TAG_BGCOLOR ){
100103
db_finalize(&eventupdate);
101104
}
102105
}
103106
104107
/*
@@ -105,21 +108,21 @@
105108
** Propagate all propagatable tags in pid to its children.
106109
*/
107110
void tag_propagate_all(int pid){
108111
Stmt q;
109112
db_prepare(&q,
110
- "SELECT tagid, addflag, mtime, value FROM tagxref"
113
+ "SELECT tagid, tagtype, mtime, value FROM tagxref"
111114
" WHERE rid=%d"
112
- " AND (SELECT tagname FROM tag WHERE tagid=tagxref.tagid) LIKE 'br%'",
115
+ " AND (tagtype=0 OR tagtype=2)",
113116
pid
114117
);
115118
while( db_step(&q)==SQLITE_ROW ){
116119
int tagid = db_column_int(&q, 0);
117
- int addflag = db_column_int(&q, 1);
120
+ int tagtype = db_column_int(&q, 1);
118121
double mtime = db_column_double(&q, 2);
119122
const char *zValue = db_column_text(&q, 3);
120
- tag_propagate(pid, tagid, addflag, zValue, mtime);
123
+ tag_propagate(pid, tagid, tagtype, zValue, mtime);
121124
}
122125
db_finalize(&q);
123126
}
124127
125128
/*
@@ -139,106 +142,93 @@
139142
/*
140143
** Insert a tag into the database.
141144
*/
142145
void tag_insert(
143146
const char *zTag, /* Name of the tag (w/o the "+" or "-" prefix */
144
- int addFlag, /* True to add. False to remove */
147
+ int tagtype, /* 0:cancel 1:singleton 2:propagated */
145148
const char *zValue, /* Value if the tag is really a property */
146149
int srcId, /* Artifact that contains this tag */
147150
double mtime, /* Timestamp. Use default if <=0.0 */
148151
int rid /* Artifact to which the tag is to attached */
149152
){
150153
Stmt s;
154
+ const char *zCol;
151155
int tagid = tag_findid(zTag, 1);
152156
if( mtime<=0.0 ){
153157
mtime = db_double(0.0, "SELECT julianday('now')");
154158
}
155159
db_prepare(&s,
156
- "REPLACE INTO tagxref(tagid,addFlag,srcId,value,mtime,rid)"
160
+ "REPLACE INTO tagxref(tagid,tagtype,srcId,value,mtime,rid)"
157161
" VALUES(%d,%d,%d,%Q,:mtime,%d)",
158
- tagid, addFlag, srcId, zValue, rid
162
+ tagid, tagtype, srcId, zValue, rid
159163
);
160164
db_bind_double(&s, ":mtime", mtime);
161165
db_step(&s);
162166
db_finalize(&s);
163
- if( addFlag==0 ){
167
+ if( tagtype==0 ){
164168
zValue = 0;
165169
}
170
+ zCol = 0;
166171
switch( tagid ){
167172
case TAG_BGCOLOR: {
168
- db_multi_exec("UPDATE event SET bgcolor=%Q WHERE objid=%d", zValue, rid);
169
- break;
170
- }
171
- case TAG_BR_BGCOLOR: {
172
- db_multi_exec("UPDATE event SET brbgcolor=%Q WHERE objid=%d", zValue,rid);
173
+ if( tagtype==1 ){
174
+ zCol = "bgcolor";
175
+ }else{
176
+ zCol = "brbgcolor";
177
+ }
173178
break;
174179
}
175180
case TAG_COMMENT: {
176
- db_multi_exec("UPDATE event SET ecomment=%Q WHERE objid=%d", zValue, rid);
181
+ zCol = "ecomment";
177182
break;
178183
}
179184
case TAG_USER: {
180
- db_multi_exec("UPDATE event SET euser=%Q WHERE objid=%d", zValue, rid);
185
+ zCol = "euser";
181186
break;
182187
}
183188
}
184
- if( strncmp(zTag, "br", 2)==0 ){
185
- tag_propagate(rid, tagid, addFlag, zValue, mtime);
189
+ if( zCol ){
190
+ db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid);
191
+ }
192
+ if( tagtype==0 || tagtype==2 ){
193
+ tag_propagate(rid, tagid, tagtype, zValue, mtime);
186194
}
187195
}
188196
189197
190198
/*
191
-** COMMAND: test-addtag
192
-** %fossil test-addtag TAGNAME UUID ?VALUE?
199
+** COMMAND: test-tag
200
+** %fossil test-tag (+|*|-)TAGNAME UUID ?VALUE?
193201
**
194
-** Add a tag to the rebuildable tables of the local repository.
202
+** Add a tag or anti-tag to the rebuildable tables of the local repository.
195203
** No tag artifact is created so the new tag is erased the next
196204
** time the repository is rebuilt. This routine is for testing
197205
** use only.
198206
*/
199
-void addtag_cmd(void){
207
+void testtag_cmd(void){
200208
const char *zTag;
201209
const char *zValue;
202210
int rid;
211
+ int tagtype;
203212
db_must_be_within_tree();
204213
if( g.argc!=4 && g.argc!=5 ){
205214
usage("TAGNAME UUID ?VALUE?");
206215
}
207216
zTag = g.argv[2];
217
+ switch( zTag[0] ){
218
+ case '+': tagtype = 1; break;
219
+ case '*': tagtype = 2; break;
220
+ case '-': tagtype = 0; break;
221
+ default: fossil_fatal("tag should begin with '+', '*', or '-'");
222
+ }
208223
rid = name_to_rid(g.argv[3]);
209224
if( rid==0 ){
210225
fossil_fatal("no such object: %s", g.argv[3]);
211226
}
212227
zValue = g.argc==5 ? g.argv[4] : 0;
213228
db_begin_transaction();
214
- tag_insert(zTag, 1, zValue, -1, 0.0, rid);
215
- db_end_transaction(0);
216
-}
217
-/*
218
-** COMMAND: test-deltag
219
-** %fossil test-deltag TAGNAME UUID
220
-**
221
-** Cancel a tag to the rebuildable tables of the local repository.
222
-** No tag artifact is created so the cancellation is undone the next
223
-** time the repository is rebuilt. This routine is for testing
224
-** use only.
225
-*/
226
-void deltag_cmd(void){
227
- const char *zTag;
228
- int rid;
229
- db_must_be_within_tree();
230
- if( g.argc!=4 ){
231
- usage("TAGNAME UUID");
232
- }
233
- zTag = g.argv[2];
234
- rid = name_to_rid(g.argv[3]);
235
- if( rid==0 ){
236
- fossil_fatal("no such object: %s", g.argv[3]);
237
- }
238
- db_begin_transaction();
239
- tag_insert(zTag, 0, 0, -1, 0.0, rid);
229
+ tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
240230
db_end_transaction(0);
241231
}
242232
243233
/*
244234
** Add a control record to the repository that either creates
@@ -246,19 +236,21 @@
246236
*/
247237
static void tag_add_artifact(
248238
const char *zTagname, /* The tag to add or cancel */
249239
const char *zObjName, /* Name of object attached to */
250240
const char *zValue, /* Value for the tag. Might be NULL */
251
- int addFlag /* True to add. false to cancel */
241
+ int tagtype /* 0:cancel 1:singleton 2:propagated */
252242
){
253243
int rid;
254244
int nrid;
255245
char *zDate;
256246
Blob uuid;
257247
Blob ctrl;
258248
Blob cksum;
249
+ static const char zTagtype[] = { '-', '+', '*' };
259250
251
+ assert( tagtype>=0 && tagtype<=2 );
260252
user_select();
261253
rid = name_to_rid(zObjName);
262254
blob_zero(&uuid);
263255
db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
264256
blob_zero(&ctrl);
@@ -268,12 +260,12 @@
268260
zTagname);
269261
}
270262
zDate = db_text(0, "SELECT datetime('now')");
271263
zDate[10] = 'T';
272264
blob_appendf(&ctrl, "D %s\n", zDate);
273
- blob_appendf(&ctrl, "T %c%F %b", addFlag ? '+' : '-', zTagname, &uuid);
274
- if( addFlag && zValue && zValue[0] ){
265
+ blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
266
+ if( tagtype && zValue && zValue[0] ){
275267
blob_appendf(&ctrl, " %F\n", zValue);
276268
}else{
277269
blob_appendf(&ctrl, "\n");
278270
}
279271
blob_appendf(&ctrl, "U %F\n", g.zLogin);
@@ -293,10 +285,15 @@
293285
**
294286
** %fossil tag add TAGNAME UUID ?VALUE?
295287
**
296288
** Add a new tag or property to UUID.
297289
**
290
+** %fossil tag branch TAGNAME UUID ?VALUE?
291
+**
292
+** Add a new tag or property to UUID and make that
293
+** tag propagate to all direct children.
294
+**
298295
** %fossil tag delete TAGNAME UUID
299296
**
300297
** Delete the tag TAGNAME from UUID
301298
**
302299
** %fossil tag find TAGNAME
@@ -325,10 +322,19 @@
325322
usage("tag add TAGNAME UUID ?VALUE?");
326323
}
327324
zValue = g.argc==6 ? g.argv[5] : 0;
328325
tag_add_artifact(g.argv[3], g.argv[4], zValue, 1);
329326
}else
327
+
328
+ if( strncmp(g.argv[2],"branch",n)==0 ){
329
+ char *zValue;
330
+ if( g.argc!=5 && g.argc!=6 ){
331
+ usage("tag branch TAGNAME UUID ?VALUE?");
332
+ }
333
+ zValue = g.argc==6 ? g.argv[5] : 0;
334
+ tag_add_artifact(g.argv[3], g.argv[4], zValue, 2);
335
+ }else
330336
331337
if( strncmp(g.argv[2],"delete",n)==0 ){
332338
if( g.argc!=5 ){
333339
usage("tag delete TAGNAME UUID");
334340
}
@@ -357,11 +363,11 @@
357363
db_prepare(&q,
358364
"SELECT tagname"
359365
" FROM tag"
360366
" WHERE EXISTS(SELECT 1 FROM tagxref"
361367
" WHERE tagid=tag.tagid"
362
- " AND addflag)"
368
+ " AND tagtype>0)"
363369
" ORDER BY tagname"
364370
);
365371
while( db_step(&q)==SQLITE_ROW ){
366372
printf("%s\n", db_column_text(&q, 0));
367373
}
@@ -370,11 +376,11 @@
370376
int rid = name_to_rid(g.argv[3]);
371377
db_prepare(&q,
372378
"SELECT tagname, value"
373379
" FROM tagxref, tag"
374380
" WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
375
- " AND addflag"
381
+ " AND tagtype>0"
376382
" ORDER BY tagname",
377383
rid
378384
);
379385
while( db_step(&q)==SQLITE_ROW ){
380386
const char *zName = db_column_text(&q, 0);
@@ -394,7 +400,7 @@
394400
goto tag_cmd_usage;
395401
}
396402
return;
397403
398404
tag_cmd_usage:
399
- usage("add|delete|find|list ...");
405
+ usage("add|branch|delete|find|list ...");
400406
}
401407
--- src/tag.c
+++ src/tag.c
@@ -31,46 +31,49 @@
31 ** Propagate the tag given by tagid to the children of pid.
32 **
33 ** This routine assumes that tagid is a tag that should be
34 ** propagated and that the tag is already present in pid.
35 **
36 ** If addFlag is true then the tag is added. If false, then the
37 ** tag is removed.
 
38 */
39 void tag_propagate(
40 int pid, /* Propagate the tag to children of this node */
41 int tagid, /* Tag to propagate */
42 int addFlag, /* True to add the tag. False to delete it. */
43 const char *zValue, /* Value of the tag. Might be NULL */
44 double mtime /* Timestamp on the tag */
45 ){
46 PQueue queue;
47 Stmt s, ins, eventupdate;
 
 
48 pqueue_init(&queue);
49 pqueue_insert(&queue, pid, 0.0);
50 db_prepare(&s,
51 "SELECT cid, plink.mtime,"
52 " coalesce(srcid=0 AND tagxref.mtime<:mtime, %d) AS doit"
53 " FROM plink LEFT JOIN tagxref ON cid=rid AND tagid=%d"
54 " WHERE pid=:pid AND isprim",
55 addFlag, tagid
56 );
57 db_bind_double(&s, ":mtime", mtime);
58 if( addFlag ){
59 db_prepare(&ins,
60 "REPLACE INTO tagxref(tagid, addFlag, srcid, value, mtime, rid)"
61 "VALUES(%d,1,0,%Q,:mtime,:rid)",
62 tagid, zValue
63 );
64 db_bind_double(&ins, ":mtime", mtime);
65 }else{
66 zValue = 0;
67 db_prepare(&ins,
68 "DELETE FROM tagxref WHERE tagid=%d AND rid=:rid", tagid
69 );
70 }
71 if( tagid==TAG_BR_BGCOLOR ){
72 db_prepare(&eventupdate,
73 "UPDATE event SET brbgcolor=%Q WHERE objid=:rid", zValue
74 );
75 }
76 while( (pid = pqueue_extract(&queue))!=0 ){
@@ -82,11 +85,11 @@
82 double mtime = db_column_double(&s, 1);
83 pqueue_insert(&queue, cid, mtime);
84 db_bind_int(&ins, ":rid", cid);
85 db_step(&ins);
86 db_reset(&ins);
87 if( tagid==TAG_BR_BGCOLOR ){
88 db_bind_int(&eventupdate, ":rid", cid);
89 db_step(&eventupdate);
90 db_reset(&eventupdate);
91 }
92 }
@@ -94,11 +97,11 @@
94 db_reset(&s);
95 }
96 pqueue_clear(&queue);
97 db_finalize(&ins);
98 db_finalize(&s);
99 if( tagid==TAG_BR_BGCOLOR ){
100 db_finalize(&eventupdate);
101 }
102 }
103
104 /*
@@ -105,21 +108,21 @@
105 ** Propagate all propagatable tags in pid to its children.
106 */
107 void tag_propagate_all(int pid){
108 Stmt q;
109 db_prepare(&q,
110 "SELECT tagid, addflag, mtime, value FROM tagxref"
111 " WHERE rid=%d"
112 " AND (SELECT tagname FROM tag WHERE tagid=tagxref.tagid) LIKE 'br%'",
113 pid
114 );
115 while( db_step(&q)==SQLITE_ROW ){
116 int tagid = db_column_int(&q, 0);
117 int addflag = db_column_int(&q, 1);
118 double mtime = db_column_double(&q, 2);
119 const char *zValue = db_column_text(&q, 3);
120 tag_propagate(pid, tagid, addflag, zValue, mtime);
121 }
122 db_finalize(&q);
123 }
124
125 /*
@@ -139,106 +142,93 @@
139 /*
140 ** Insert a tag into the database.
141 */
142 void tag_insert(
143 const char *zTag, /* Name of the tag (w/o the "+" or "-" prefix */
144 int addFlag, /* True to add. False to remove */
145 const char *zValue, /* Value if the tag is really a property */
146 int srcId, /* Artifact that contains this tag */
147 double mtime, /* Timestamp. Use default if <=0.0 */
148 int rid /* Artifact to which the tag is to attached */
149 ){
150 Stmt s;
 
151 int tagid = tag_findid(zTag, 1);
152 if( mtime<=0.0 ){
153 mtime = db_double(0.0, "SELECT julianday('now')");
154 }
155 db_prepare(&s,
156 "REPLACE INTO tagxref(tagid,addFlag,srcId,value,mtime,rid)"
157 " VALUES(%d,%d,%d,%Q,:mtime,%d)",
158 tagid, addFlag, srcId, zValue, rid
159 );
160 db_bind_double(&s, ":mtime", mtime);
161 db_step(&s);
162 db_finalize(&s);
163 if( addFlag==0 ){
164 zValue = 0;
165 }
 
166 switch( tagid ){
167 case TAG_BGCOLOR: {
168 db_multi_exec("UPDATE event SET bgcolor=%Q WHERE objid=%d", zValue, rid);
169 break;
170 }
171 case TAG_BR_BGCOLOR: {
172 db_multi_exec("UPDATE event SET brbgcolor=%Q WHERE objid=%d", zValue,rid);
173 break;
174 }
175 case TAG_COMMENT: {
176 db_multi_exec("UPDATE event SET ecomment=%Q WHERE objid=%d", zValue, rid);
177 break;
178 }
179 case TAG_USER: {
180 db_multi_exec("UPDATE event SET euser=%Q WHERE objid=%d", zValue, rid);
181 break;
182 }
183 }
184 if( strncmp(zTag, "br", 2)==0 ){
185 tag_propagate(rid, tagid, addFlag, zValue, mtime);
 
 
 
186 }
187 }
188
189
190 /*
191 ** COMMAND: test-addtag
192 ** %fossil test-addtag TAGNAME UUID ?VALUE?
193 **
194 ** Add a tag to the rebuildable tables of the local repository.
195 ** No tag artifact is created so the new tag is erased the next
196 ** time the repository is rebuilt. This routine is for testing
197 ** use only.
198 */
199 void addtag_cmd(void){
200 const char *zTag;
201 const char *zValue;
202 int rid;
 
203 db_must_be_within_tree();
204 if( g.argc!=4 && g.argc!=5 ){
205 usage("TAGNAME UUID ?VALUE?");
206 }
207 zTag = g.argv[2];
 
 
 
 
 
 
208 rid = name_to_rid(g.argv[3]);
209 if( rid==0 ){
210 fossil_fatal("no such object: %s", g.argv[3]);
211 }
212 zValue = g.argc==5 ? g.argv[4] : 0;
213 db_begin_transaction();
214 tag_insert(zTag, 1, zValue, -1, 0.0, rid);
215 db_end_transaction(0);
216 }
217 /*
218 ** COMMAND: test-deltag
219 ** %fossil test-deltag TAGNAME UUID
220 **
221 ** Cancel a tag to the rebuildable tables of the local repository.
222 ** No tag artifact is created so the cancellation is undone the next
223 ** time the repository is rebuilt. This routine is for testing
224 ** use only.
225 */
226 void deltag_cmd(void){
227 const char *zTag;
228 int rid;
229 db_must_be_within_tree();
230 if( g.argc!=4 ){
231 usage("TAGNAME UUID");
232 }
233 zTag = g.argv[2];
234 rid = name_to_rid(g.argv[3]);
235 if( rid==0 ){
236 fossil_fatal("no such object: %s", g.argv[3]);
237 }
238 db_begin_transaction();
239 tag_insert(zTag, 0, 0, -1, 0.0, rid);
240 db_end_transaction(0);
241 }
242
243 /*
244 ** Add a control record to the repository that either creates
@@ -246,19 +236,21 @@
246 */
247 static void tag_add_artifact(
248 const char *zTagname, /* The tag to add or cancel */
249 const char *zObjName, /* Name of object attached to */
250 const char *zValue, /* Value for the tag. Might be NULL */
251 int addFlag /* True to add. false to cancel */
252 ){
253 int rid;
254 int nrid;
255 char *zDate;
256 Blob uuid;
257 Blob ctrl;
258 Blob cksum;
 
259
 
260 user_select();
261 rid = name_to_rid(zObjName);
262 blob_zero(&uuid);
263 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
264 blob_zero(&ctrl);
@@ -268,12 +260,12 @@
268 zTagname);
269 }
270 zDate = db_text(0, "SELECT datetime('now')");
271 zDate[10] = 'T';
272 blob_appendf(&ctrl, "D %s\n", zDate);
273 blob_appendf(&ctrl, "T %c%F %b", addFlag ? '+' : '-', zTagname, &uuid);
274 if( addFlag && zValue && zValue[0] ){
275 blob_appendf(&ctrl, " %F\n", zValue);
276 }else{
277 blob_appendf(&ctrl, "\n");
278 }
279 blob_appendf(&ctrl, "U %F\n", g.zLogin);
@@ -293,10 +285,15 @@
293 **
294 ** %fossil tag add TAGNAME UUID ?VALUE?
295 **
296 ** Add a new tag or property to UUID.
297 **
 
 
 
 
 
298 ** %fossil tag delete TAGNAME UUID
299 **
300 ** Delete the tag TAGNAME from UUID
301 **
302 ** %fossil tag find TAGNAME
@@ -325,10 +322,19 @@
325 usage("tag add TAGNAME UUID ?VALUE?");
326 }
327 zValue = g.argc==6 ? g.argv[5] : 0;
328 tag_add_artifact(g.argv[3], g.argv[4], zValue, 1);
329 }else
 
 
 
 
 
 
 
 
 
330
331 if( strncmp(g.argv[2],"delete",n)==0 ){
332 if( g.argc!=5 ){
333 usage("tag delete TAGNAME UUID");
334 }
@@ -357,11 +363,11 @@
357 db_prepare(&q,
358 "SELECT tagname"
359 " FROM tag"
360 " WHERE EXISTS(SELECT 1 FROM tagxref"
361 " WHERE tagid=tag.tagid"
362 " AND addflag)"
363 " ORDER BY tagname"
364 );
365 while( db_step(&q)==SQLITE_ROW ){
366 printf("%s\n", db_column_text(&q, 0));
367 }
@@ -370,11 +376,11 @@
370 int rid = name_to_rid(g.argv[3]);
371 db_prepare(&q,
372 "SELECT tagname, value"
373 " FROM tagxref, tag"
374 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
375 " AND addflag"
376 " ORDER BY tagname",
377 rid
378 );
379 while( db_step(&q)==SQLITE_ROW ){
380 const char *zName = db_column_text(&q, 0);
@@ -394,7 +400,7 @@
394 goto tag_cmd_usage;
395 }
396 return;
397
398 tag_cmd_usage:
399 usage("add|delete|find|list ...");
400 }
401
--- src/tag.c
+++ src/tag.c
@@ -31,46 +31,49 @@
31 ** Propagate the tag given by tagid to the children of pid.
32 **
33 ** This routine assumes that tagid is a tag that should be
34 ** propagated and that the tag is already present in pid.
35 **
36 ** If tagtype is 2 then the tag is being propagated from an
37 ** ancestor node. If tagtype is 0 it means a branch tag is
38 ** being cancelled.
39 */
40 void tag_propagate(
41 int pid, /* Propagate the tag to children of this node */
42 int tagid, /* Tag to propagate */
43 int tagType, /* 2 for a propagating tag. 0 for an antitag */
44 const char *zValue, /* Value of the tag. Might be NULL */
45 double mtime /* Timestamp on the tag */
46 ){
47 PQueue queue;
48 Stmt s, ins, eventupdate;
49
50 assert( tagType==0 || tagType==2 );
51 pqueue_init(&queue);
52 pqueue_insert(&queue, pid, 0.0);
53 db_prepare(&s,
54 "SELECT cid, plink.mtime,"
55 " coalesce(srcid=0 AND tagxref.mtime<:mtime, %d) AS doit"
56 " FROM plink LEFT JOIN tagxref ON cid=rid AND tagid=%d"
57 " WHERE pid=:pid AND isprim",
58 tagType!=0, tagid
59 );
60 db_bind_double(&s, ":mtime", mtime);
61 if( tagType==2 ){
62 db_prepare(&ins,
63 "REPLACE INTO tagxref(tagid, tagtype, srcid, value, mtime, rid)"
64 "VALUES(%d,2,0,%Q,:mtime,:rid)",
65 tagid, zValue
66 );
67 db_bind_double(&ins, ":mtime", mtime);
68 }else{
69 zValue = 0;
70 db_prepare(&ins,
71 "DELETE FROM tagxref WHERE tagid=%d AND rid=:rid", tagid
72 );
73 }
74 if( tagid==TAG_BGCOLOR ){
75 db_prepare(&eventupdate,
76 "UPDATE event SET brbgcolor=%Q WHERE objid=:rid", zValue
77 );
78 }
79 while( (pid = pqueue_extract(&queue))!=0 ){
@@ -82,11 +85,11 @@
85 double mtime = db_column_double(&s, 1);
86 pqueue_insert(&queue, cid, mtime);
87 db_bind_int(&ins, ":rid", cid);
88 db_step(&ins);
89 db_reset(&ins);
90 if( tagid==TAG_BGCOLOR ){
91 db_bind_int(&eventupdate, ":rid", cid);
92 db_step(&eventupdate);
93 db_reset(&eventupdate);
94 }
95 }
@@ -94,11 +97,11 @@
97 db_reset(&s);
98 }
99 pqueue_clear(&queue);
100 db_finalize(&ins);
101 db_finalize(&s);
102 if( tagid==TAG_BGCOLOR ){
103 db_finalize(&eventupdate);
104 }
105 }
106
107 /*
@@ -105,21 +108,21 @@
108 ** Propagate all propagatable tags in pid to its children.
109 */
110 void tag_propagate_all(int pid){
111 Stmt q;
112 db_prepare(&q,
113 "SELECT tagid, tagtype, mtime, value FROM tagxref"
114 " WHERE rid=%d"
115 " AND (tagtype=0 OR tagtype=2)",
116 pid
117 );
118 while( db_step(&q)==SQLITE_ROW ){
119 int tagid = db_column_int(&q, 0);
120 int tagtype = db_column_int(&q, 1);
121 double mtime = db_column_double(&q, 2);
122 const char *zValue = db_column_text(&q, 3);
123 tag_propagate(pid, tagid, tagtype, zValue, mtime);
124 }
125 db_finalize(&q);
126 }
127
128 /*
@@ -139,106 +142,93 @@
142 /*
143 ** Insert a tag into the database.
144 */
145 void tag_insert(
146 const char *zTag, /* Name of the tag (w/o the "+" or "-" prefix */
147 int tagtype, /* 0:cancel 1:singleton 2:propagated */
148 const char *zValue, /* Value if the tag is really a property */
149 int srcId, /* Artifact that contains this tag */
150 double mtime, /* Timestamp. Use default if <=0.0 */
151 int rid /* Artifact to which the tag is to attached */
152 ){
153 Stmt s;
154 const char *zCol;
155 int tagid = tag_findid(zTag, 1);
156 if( mtime<=0.0 ){
157 mtime = db_double(0.0, "SELECT julianday('now')");
158 }
159 db_prepare(&s,
160 "REPLACE INTO tagxref(tagid,tagtype,srcId,value,mtime,rid)"
161 " VALUES(%d,%d,%d,%Q,:mtime,%d)",
162 tagid, tagtype, srcId, zValue, rid
163 );
164 db_bind_double(&s, ":mtime", mtime);
165 db_step(&s);
166 db_finalize(&s);
167 if( tagtype==0 ){
168 zValue = 0;
169 }
170 zCol = 0;
171 switch( tagid ){
172 case TAG_BGCOLOR: {
173 if( tagtype==1 ){
174 zCol = "bgcolor";
175 }else{
176 zCol = "brbgcolor";
177 }
178 break;
179 }
180 case TAG_COMMENT: {
181 zCol = "ecomment";
182 break;
183 }
184 case TAG_USER: {
185 zCol = "euser";
186 break;
187 }
188 }
189 if( zCol ){
190 db_multi_exec("UPDATE event SET %s=%Q WHERE objid=%d", zCol, zValue, rid);
191 }
192 if( tagtype==0 || tagtype==2 ){
193 tag_propagate(rid, tagid, tagtype, zValue, mtime);
194 }
195 }
196
197
198 /*
199 ** COMMAND: test-tag
200 ** %fossil test-tag (+|*|-)TAGNAME UUID ?VALUE?
201 **
202 ** Add a tag or anti-tag to the rebuildable tables of the local repository.
203 ** No tag artifact is created so the new tag is erased the next
204 ** time the repository is rebuilt. This routine is for testing
205 ** use only.
206 */
207 void testtag_cmd(void){
208 const char *zTag;
209 const char *zValue;
210 int rid;
211 int tagtype;
212 db_must_be_within_tree();
213 if( g.argc!=4 && g.argc!=5 ){
214 usage("TAGNAME UUID ?VALUE?");
215 }
216 zTag = g.argv[2];
217 switch( zTag[0] ){
218 case '+': tagtype = 1; break;
219 case '*': tagtype = 2; break;
220 case '-': tagtype = 0; break;
221 default: fossil_fatal("tag should begin with '+', '*', or '-'");
222 }
223 rid = name_to_rid(g.argv[3]);
224 if( rid==0 ){
225 fossil_fatal("no such object: %s", g.argv[3]);
226 }
227 zValue = g.argc==5 ? g.argv[4] : 0;
228 db_begin_transaction();
229 tag_insert(zTag, tagtype, zValue, -1, 0.0, rid);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230 db_end_transaction(0);
231 }
232
233 /*
234 ** Add a control record to the repository that either creates
@@ -246,19 +236,21 @@
236 */
237 static void tag_add_artifact(
238 const char *zTagname, /* The tag to add or cancel */
239 const char *zObjName, /* Name of object attached to */
240 const char *zValue, /* Value for the tag. Might be NULL */
241 int tagtype /* 0:cancel 1:singleton 2:propagated */
242 ){
243 int rid;
244 int nrid;
245 char *zDate;
246 Blob uuid;
247 Blob ctrl;
248 Blob cksum;
249 static const char zTagtype[] = { '-', '+', '*' };
250
251 assert( tagtype>=0 && tagtype<=2 );
252 user_select();
253 rid = name_to_rid(zObjName);
254 blob_zero(&uuid);
255 db_blob(&uuid, "SELECT uuid FROM blob WHERE rid=%d", rid);
256 blob_zero(&ctrl);
@@ -268,12 +260,12 @@
260 zTagname);
261 }
262 zDate = db_text(0, "SELECT datetime('now')");
263 zDate[10] = 'T';
264 blob_appendf(&ctrl, "D %s\n", zDate);
265 blob_appendf(&ctrl, "T %c%F %b", zTagtype[tagtype], zTagname, &uuid);
266 if( tagtype && zValue && zValue[0] ){
267 blob_appendf(&ctrl, " %F\n", zValue);
268 }else{
269 blob_appendf(&ctrl, "\n");
270 }
271 blob_appendf(&ctrl, "U %F\n", g.zLogin);
@@ -293,10 +285,15 @@
285 **
286 ** %fossil tag add TAGNAME UUID ?VALUE?
287 **
288 ** Add a new tag or property to UUID.
289 **
290 ** %fossil tag branch TAGNAME UUID ?VALUE?
291 **
292 ** Add a new tag or property to UUID and make that
293 ** tag propagate to all direct children.
294 **
295 ** %fossil tag delete TAGNAME UUID
296 **
297 ** Delete the tag TAGNAME from UUID
298 **
299 ** %fossil tag find TAGNAME
@@ -325,10 +322,19 @@
322 usage("tag add TAGNAME UUID ?VALUE?");
323 }
324 zValue = g.argc==6 ? g.argv[5] : 0;
325 tag_add_artifact(g.argv[3], g.argv[4], zValue, 1);
326 }else
327
328 if( strncmp(g.argv[2],"branch",n)==0 ){
329 char *zValue;
330 if( g.argc!=5 && g.argc!=6 ){
331 usage("tag branch TAGNAME UUID ?VALUE?");
332 }
333 zValue = g.argc==6 ? g.argv[5] : 0;
334 tag_add_artifact(g.argv[3], g.argv[4], zValue, 2);
335 }else
336
337 if( strncmp(g.argv[2],"delete",n)==0 ){
338 if( g.argc!=5 ){
339 usage("tag delete TAGNAME UUID");
340 }
@@ -357,11 +363,11 @@
363 db_prepare(&q,
364 "SELECT tagname"
365 " FROM tag"
366 " WHERE EXISTS(SELECT 1 FROM tagxref"
367 " WHERE tagid=tag.tagid"
368 " AND tagtype>0)"
369 " ORDER BY tagname"
370 );
371 while( db_step(&q)==SQLITE_ROW ){
372 printf("%s\n", db_column_text(&q, 0));
373 }
@@ -370,11 +376,11 @@
376 int rid = name_to_rid(g.argv[3]);
377 db_prepare(&q,
378 "SELECT tagname, value"
379 " FROM tagxref, tag"
380 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
381 " AND tagtype>0"
382 " ORDER BY tagname",
383 rid
384 );
385 while( db_step(&q)==SQLITE_ROW ){
386 const char *zName = db_column_text(&q, 0);
@@ -394,7 +400,7 @@
400 goto tag_cmd_usage;
401 }
402 return;
403
404 tag_cmd_usage:
405 usage("add|branch|delete|find|list ...");
406 }
407

Keyboard Shortcuts

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