Fossil SCM
Allow specifying tags using TAG:DATE. The result is the newest check-in with TAG that occurs or before DATE.
Commit
337a1aca06cd6d75827acfa4f78cfdbc73b62e08
Parent
3f0393f555f0da3…
1 file changed
+54
-1
+54
-1
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -111,15 +111,39 @@ | ||
| 111 | 111 | }else{ |
| 112 | 112 | rc = 0; |
| 113 | 113 | } |
| 114 | 114 | return rc; |
| 115 | 115 | } |
| 116 | + | |
| 117 | +/* | |
| 118 | +** Return TRUE if the string begins with an ISO8601 date: YYYY-MM-DD. | |
| 119 | +*/ | |
| 120 | +static int is_date(const char *z){ | |
| 121 | + if( !isdigit(z[0]) ) return 0; | |
| 122 | + if( !isdigit(z[1]) ) return 0; | |
| 123 | + if( !isdigit(z[2]) ) return 0; | |
| 124 | + if( !isdigit(z[3]) ) return 0; | |
| 125 | + if( z[4]!='-') return 0; | |
| 126 | + if( !isdigit(z[5]) ) return 0; | |
| 127 | + if( !isdigit(z[6]) ) return 0; | |
| 128 | + if( z[7]!='-') return 0; | |
| 129 | + if( !isdigit(z[8]) ) return 0; | |
| 130 | + if( !isdigit(z[9]) ) return 0; | |
| 131 | + return 1; | |
| 132 | +} | |
| 116 | 133 | |
| 117 | 134 | /* |
| 118 | 135 | ** Convert a symbolic tag name into the UUID of a check-in that contains |
| 119 | 136 | ** that tag. If the tag appears on multiple check-ins, return the UUID |
| 120 | 137 | ** of the most recent check-in with the tag. |
| 138 | +** | |
| 139 | +** If the input string is of the form: | |
| 140 | +** | |
| 141 | +** tag:date | |
| 142 | +** | |
| 143 | +** Then return the UUID of the oldest check-in with that tag that is | |
| 144 | +** not older than 'date'. | |
| 121 | 145 | ** |
| 122 | 146 | ** Memory to hold the returned string comes from malloc() and needs to |
| 123 | 147 | ** be freed by the caller. |
| 124 | 148 | */ |
| 125 | 149 | char *tag_to_uuid(const char *zTag){ |
| @@ -132,10 +156,39 @@ | ||
| 132 | 156 | " AND event.objid=tagxref.rid " |
| 133 | 157 | " AND blob.rid=event.objid " |
| 134 | 158 | " ORDER BY event.mtime DESC ", |
| 135 | 159 | zTag |
| 136 | 160 | ); |
| 161 | + if( zUuid==0 ){ | |
| 162 | + int nTag = strlen(zTag); | |
| 163 | + int i; | |
| 164 | + for(i=0; i<nTag-10; i++){ | |
| 165 | + if( zTag[i]==':' && is_date(&zTag[i+1]) ){ | |
| 166 | + char *zDate = mprintf("%s", &zTag[i+1]); | |
| 167 | + char *zTagBase = mprintf("%.*s", i, zTag); | |
| 168 | + int nDate = strlen(zDate); | |
| 169 | + int useUtc = 0; | |
| 170 | + if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ | |
| 171 | + nDate -= 3; | |
| 172 | + zDate[nDate] = 0; | |
| 173 | + useUtc = 1; | |
| 174 | + } | |
| 175 | + zUuid = db_text(0, | |
| 176 | + "SELECT blob.uuid" | |
| 177 | + " FROM tag, tagxref, event, blob" | |
| 178 | + " WHERE tag.tagname='sym-'||%Q " | |
| 179 | + " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " | |
| 180 | + " AND event.objid=tagxref.rid " | |
| 181 | + " AND blob.rid=event.objid " | |
| 182 | + " AND event.mtime<=julianday(%Q %s)" | |
| 183 | + " ORDER BY event.mtime DESC ", | |
| 184 | + zTagBase, zDate, (useUtc ? "" : ",'utc'") | |
| 185 | + ); | |
| 186 | + break; | |
| 187 | + } | |
| 188 | + } | |
| 189 | + } | |
| 137 | 190 | return zUuid; |
| 138 | 191 | } |
| 139 | 192 | |
| 140 | 193 | /* |
| 141 | 194 | ** Convert a date/time string into a UUID. |
| @@ -162,11 +215,11 @@ | ||
| 162 | 215 | }else if( memcmp(zDate, "utc:", 4)==0 ){ |
| 163 | 216 | zDate += 4; |
| 164 | 217 | useUtc = 1; |
| 165 | 218 | } |
| 166 | 219 | n = strlen(zDate); |
| 167 | - if( n<10 || zDate[4]!='-' || zDate[7]!='-' ) return 0; | |
| 220 | + if( n<10 || !is_date(zDate) ) return 0; | |
| 168 | 221 | if( n>4 && sqlite3_strnicmp(&zDate[n-3], "utc", 3)==0 ){ |
| 169 | 222 | zCopy = mprintf("%s", zDate); |
| 170 | 223 | zCopy[n-3] = 0; |
| 171 | 224 | zDate = zCopy; |
| 172 | 225 | n -= 3; |
| 173 | 226 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -111,15 +111,39 @@ | |
| 111 | }else{ |
| 112 | rc = 0; |
| 113 | } |
| 114 | return rc; |
| 115 | } |
| 116 | |
| 117 | /* |
| 118 | ** Convert a symbolic tag name into the UUID of a check-in that contains |
| 119 | ** that tag. If the tag appears on multiple check-ins, return the UUID |
| 120 | ** of the most recent check-in with the tag. |
| 121 | ** |
| 122 | ** Memory to hold the returned string comes from malloc() and needs to |
| 123 | ** be freed by the caller. |
| 124 | */ |
| 125 | char *tag_to_uuid(const char *zTag){ |
| @@ -132,10 +156,39 @@ | |
| 132 | " AND event.objid=tagxref.rid " |
| 133 | " AND blob.rid=event.objid " |
| 134 | " ORDER BY event.mtime DESC ", |
| 135 | zTag |
| 136 | ); |
| 137 | return zUuid; |
| 138 | } |
| 139 | |
| 140 | /* |
| 141 | ** Convert a date/time string into a UUID. |
| @@ -162,11 +215,11 @@ | |
| 162 | }else if( memcmp(zDate, "utc:", 4)==0 ){ |
| 163 | zDate += 4; |
| 164 | useUtc = 1; |
| 165 | } |
| 166 | n = strlen(zDate); |
| 167 | if( n<10 || zDate[4]!='-' || zDate[7]!='-' ) return 0; |
| 168 | if( n>4 && sqlite3_strnicmp(&zDate[n-3], "utc", 3)==0 ){ |
| 169 | zCopy = mprintf("%s", zDate); |
| 170 | zCopy[n-3] = 0; |
| 171 | zDate = zCopy; |
| 172 | n -= 3; |
| 173 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -111,15 +111,39 @@ | |
| 111 | }else{ |
| 112 | rc = 0; |
| 113 | } |
| 114 | return rc; |
| 115 | } |
| 116 | |
| 117 | /* |
| 118 | ** Return TRUE if the string begins with an ISO8601 date: YYYY-MM-DD. |
| 119 | */ |
| 120 | static int is_date(const char *z){ |
| 121 | if( !isdigit(z[0]) ) return 0; |
| 122 | if( !isdigit(z[1]) ) return 0; |
| 123 | if( !isdigit(z[2]) ) return 0; |
| 124 | if( !isdigit(z[3]) ) return 0; |
| 125 | if( z[4]!='-') return 0; |
| 126 | if( !isdigit(z[5]) ) return 0; |
| 127 | if( !isdigit(z[6]) ) return 0; |
| 128 | if( z[7]!='-') return 0; |
| 129 | if( !isdigit(z[8]) ) return 0; |
| 130 | if( !isdigit(z[9]) ) return 0; |
| 131 | return 1; |
| 132 | } |
| 133 | |
| 134 | /* |
| 135 | ** Convert a symbolic tag name into the UUID of a check-in that contains |
| 136 | ** that tag. If the tag appears on multiple check-ins, return the UUID |
| 137 | ** of the most recent check-in with the tag. |
| 138 | ** |
| 139 | ** If the input string is of the form: |
| 140 | ** |
| 141 | ** tag:date |
| 142 | ** |
| 143 | ** Then return the UUID of the oldest check-in with that tag that is |
| 144 | ** not older than 'date'. |
| 145 | ** |
| 146 | ** Memory to hold the returned string comes from malloc() and needs to |
| 147 | ** be freed by the caller. |
| 148 | */ |
| 149 | char *tag_to_uuid(const char *zTag){ |
| @@ -132,10 +156,39 @@ | |
| 156 | " AND event.objid=tagxref.rid " |
| 157 | " AND blob.rid=event.objid " |
| 158 | " ORDER BY event.mtime DESC ", |
| 159 | zTag |
| 160 | ); |
| 161 | if( zUuid==0 ){ |
| 162 | int nTag = strlen(zTag); |
| 163 | int i; |
| 164 | for(i=0; i<nTag-10; i++){ |
| 165 | if( zTag[i]==':' && is_date(&zTag[i+1]) ){ |
| 166 | char *zDate = mprintf("%s", &zTag[i+1]); |
| 167 | char *zTagBase = mprintf("%.*s", i, zTag); |
| 168 | int nDate = strlen(zDate); |
| 169 | int useUtc = 0; |
| 170 | if( sqlite3_strnicmp(&zDate[nDate-3],"utc",3)==0 ){ |
| 171 | nDate -= 3; |
| 172 | zDate[nDate] = 0; |
| 173 | useUtc = 1; |
| 174 | } |
| 175 | zUuid = db_text(0, |
| 176 | "SELECT blob.uuid" |
| 177 | " FROM tag, tagxref, event, blob" |
| 178 | " WHERE tag.tagname='sym-'||%Q " |
| 179 | " AND tagxref.tagid=tag.tagid AND tagxref.tagtype>0 " |
| 180 | " AND event.objid=tagxref.rid " |
| 181 | " AND blob.rid=event.objid " |
| 182 | " AND event.mtime<=julianday(%Q %s)" |
| 183 | " ORDER BY event.mtime DESC ", |
| 184 | zTagBase, zDate, (useUtc ? "" : ",'utc'") |
| 185 | ); |
| 186 | break; |
| 187 | } |
| 188 | } |
| 189 | } |
| 190 | return zUuid; |
| 191 | } |
| 192 | |
| 193 | /* |
| 194 | ** Convert a date/time string into a UUID. |
| @@ -162,11 +215,11 @@ | |
| 215 | }else if( memcmp(zDate, "utc:", 4)==0 ){ |
| 216 | zDate += 4; |
| 217 | useUtc = 1; |
| 218 | } |
| 219 | n = strlen(zDate); |
| 220 | if( n<10 || !is_date(zDate) ) return 0; |
| 221 | if( n>4 && sqlite3_strnicmp(&zDate[n-3], "utc", 3)==0 ){ |
| 222 | zCopy = mprintf("%s", zDate); |
| 223 | zCopy[n-3] = 0; |
| 224 | zDate = zCopy; |
| 225 | n -= 3; |
| 226 |