Fossil SCM
Accept date/time strings as a valid tag. They resolve to the most recent check-in prior to the given date/time.
Commit
93827b8450af7af33da279ad8339c81a0fe37a21
Parent
94bb313444b0165…
1 file changed
+59
-1
+59
-1
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -36,10 +36,16 @@ | ||
| 36 | 36 | ** case and might only be a prefix of the full UUID and converts it |
| 37 | 37 | ** into the full-length UUID in canonical form. |
| 38 | 38 | ** |
| 39 | 39 | ** If the input is not a UUID or a UUID prefix, then try to resolve |
| 40 | 40 | ** the name as a tag. If multiple tags match, pick the latest. |
| 41 | +** If the input name matches "tag:*" then always resolve as a tag. | |
| 42 | +** | |
| 43 | +** If the input is not a tag, then try to match it as an ISO-8601 date | |
| 44 | +** string YYYY-MM-DD HH:MM:SS and pick the nearest check-in to that date. | |
| 45 | +** If the input is of the form "date:*" or "localtime:*" or "utc:*" then | |
| 46 | +** always resolve the name as a date. | |
| 41 | 47 | ** |
| 42 | 48 | ** Return the number of errors. |
| 43 | 49 | */ |
| 44 | 50 | int name_to_uuid(Blob *pName, int iErrPriority){ |
| 45 | 51 | int rc; |
| @@ -48,12 +54,17 @@ | ||
| 48 | 54 | if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){ |
| 49 | 55 | char *zUuid; |
| 50 | 56 | const char *zName = blob_str(pName); |
| 51 | 57 | if( memcmp(zName, "tag:", 4)==0 ){ |
| 52 | 58 | zName += 4; |
| 59 | + zUuid = tag_to_uuid(zName); | |
| 60 | + }else{ | |
| 61 | + zUuid = tag_to_uuid(zName); | |
| 62 | + if( zUuid==0 ){ | |
| 63 | + zUuid = date_to_uuid(zName); | |
| 64 | + } | |
| 53 | 65 | } |
| 54 | - zUuid = tag_to_uuid(zName); | |
| 55 | 66 | if( zUuid ){ |
| 56 | 67 | blob_reset(pName); |
| 57 | 68 | blob_append(pName, zUuid, -1); |
| 58 | 69 | free(zUuid); |
| 59 | 70 | return 0; |
| @@ -123,10 +134,57 @@ | ||
| 123 | 134 | " ORDER BY event.mtime DESC ", |
| 124 | 135 | zTag |
| 125 | 136 | ); |
| 126 | 137 | return zUuid; |
| 127 | 138 | } |
| 139 | + | |
| 140 | +/* | |
| 141 | +** Convert a date/time string into a UUID. | |
| 142 | +** | |
| 143 | +** Input forms accepted: | |
| 144 | +** | |
| 145 | +** date:DATE | |
| 146 | +** local:DATE | |
| 147 | +** utc:DATE | |
| 148 | +** | |
| 149 | +** The DATE is interpreted as localtime unless the "utc:" prefix is used | |
| 150 | +** or a "utc" string appears at the end of the DATE string. | |
| 151 | +*/ | |
| 152 | +char *date_to_uuid(const char *zDate){ | |
| 153 | + int useUtc = 0; | |
| 154 | + int n; | |
| 155 | + char *zCopy = 0; | |
| 156 | + char *zUuid; | |
| 157 | + | |
| 158 | + if( memcmp(zDate, "date:", 5)==0 ){ | |
| 159 | + zDate += 5; | |
| 160 | + }else if( memcmp(zDate, "local:", 6)==0 ){ | |
| 161 | + zDate += 6; | |
| 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 | + useUtc = 1; | |
| 174 | + } | |
| 175 | + free(zCopy); | |
| 176 | + zUuid = db_text(0, | |
| 177 | + "SELECT (SELECT uuid FROM blob WHERE rid=event.objid)" | |
| 178 | + " FROM event" | |
| 179 | + " WHERE mtime<=julianday(%Q %s) AND type='ci'" | |
| 180 | + " ORDER BY mtime DESC LIMIT 1", | |
| 181 | + zDate, useUtc ? "" : ",'utc'" | |
| 182 | + ); | |
| 183 | + free(zCopy); | |
| 184 | + return zUuid; | |
| 185 | +} | |
| 128 | 186 | |
| 129 | 187 | /* |
| 130 | 188 | ** COMMAND: test-name-to-id |
| 131 | 189 | ** |
| 132 | 190 | ** Convert a name to a full artifact ID. |
| 133 | 191 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -36,10 +36,16 @@ | |
| 36 | ** case and might only be a prefix of the full UUID and converts it |
| 37 | ** into the full-length UUID in canonical form. |
| 38 | ** |
| 39 | ** If the input is not a UUID or a UUID prefix, then try to resolve |
| 40 | ** the name as a tag. If multiple tags match, pick the latest. |
| 41 | ** |
| 42 | ** Return the number of errors. |
| 43 | */ |
| 44 | int name_to_uuid(Blob *pName, int iErrPriority){ |
| 45 | int rc; |
| @@ -48,12 +54,17 @@ | |
| 48 | if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){ |
| 49 | char *zUuid; |
| 50 | const char *zName = blob_str(pName); |
| 51 | if( memcmp(zName, "tag:", 4)==0 ){ |
| 52 | zName += 4; |
| 53 | } |
| 54 | zUuid = tag_to_uuid(zName); |
| 55 | if( zUuid ){ |
| 56 | blob_reset(pName); |
| 57 | blob_append(pName, zUuid, -1); |
| 58 | free(zUuid); |
| 59 | return 0; |
| @@ -123,10 +134,57 @@ | |
| 123 | " ORDER BY event.mtime DESC ", |
| 124 | zTag |
| 125 | ); |
| 126 | return zUuid; |
| 127 | } |
| 128 | |
| 129 | /* |
| 130 | ** COMMAND: test-name-to-id |
| 131 | ** |
| 132 | ** Convert a name to a full artifact ID. |
| 133 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -36,10 +36,16 @@ | |
| 36 | ** case and might only be a prefix of the full UUID and converts it |
| 37 | ** into the full-length UUID in canonical form. |
| 38 | ** |
| 39 | ** If the input is not a UUID or a UUID prefix, then try to resolve |
| 40 | ** the name as a tag. If multiple tags match, pick the latest. |
| 41 | ** If the input name matches "tag:*" then always resolve as a tag. |
| 42 | ** |
| 43 | ** If the input is not a tag, then try to match it as an ISO-8601 date |
| 44 | ** string YYYY-MM-DD HH:MM:SS and pick the nearest check-in to that date. |
| 45 | ** If the input is of the form "date:*" or "localtime:*" or "utc:*" then |
| 46 | ** always resolve the name as a date. |
| 47 | ** |
| 48 | ** Return the number of errors. |
| 49 | */ |
| 50 | int name_to_uuid(Blob *pName, int iErrPriority){ |
| 51 | int rc; |
| @@ -48,12 +54,17 @@ | |
| 54 | if( sz>UUID_SIZE || sz<4 || !validate16(blob_buffer(pName), sz) ){ |
| 55 | char *zUuid; |
| 56 | const char *zName = blob_str(pName); |
| 57 | if( memcmp(zName, "tag:", 4)==0 ){ |
| 58 | zName += 4; |
| 59 | zUuid = tag_to_uuid(zName); |
| 60 | }else{ |
| 61 | zUuid = tag_to_uuid(zName); |
| 62 | if( zUuid==0 ){ |
| 63 | zUuid = date_to_uuid(zName); |
| 64 | } |
| 65 | } |
| 66 | if( zUuid ){ |
| 67 | blob_reset(pName); |
| 68 | blob_append(pName, zUuid, -1); |
| 69 | free(zUuid); |
| 70 | return 0; |
| @@ -123,10 +134,57 @@ | |
| 134 | " ORDER BY event.mtime DESC ", |
| 135 | zTag |
| 136 | ); |
| 137 | return zUuid; |
| 138 | } |
| 139 | |
| 140 | /* |
| 141 | ** Convert a date/time string into a UUID. |
| 142 | ** |
| 143 | ** Input forms accepted: |
| 144 | ** |
| 145 | ** date:DATE |
| 146 | ** local:DATE |
| 147 | ** utc:DATE |
| 148 | ** |
| 149 | ** The DATE is interpreted as localtime unless the "utc:" prefix is used |
| 150 | ** or a "utc" string appears at the end of the DATE string. |
| 151 | */ |
| 152 | char *date_to_uuid(const char *zDate){ |
| 153 | int useUtc = 0; |
| 154 | int n; |
| 155 | char *zCopy = 0; |
| 156 | char *zUuid; |
| 157 | |
| 158 | if( memcmp(zDate, "date:", 5)==0 ){ |
| 159 | zDate += 5; |
| 160 | }else if( memcmp(zDate, "local:", 6)==0 ){ |
| 161 | zDate += 6; |
| 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 | useUtc = 1; |
| 174 | } |
| 175 | free(zCopy); |
| 176 | zUuid = db_text(0, |
| 177 | "SELECT (SELECT uuid FROM blob WHERE rid=event.objid)" |
| 178 | " FROM event" |
| 179 | " WHERE mtime<=julianday(%Q %s) AND type='ci'" |
| 180 | " ORDER BY mtime DESC LIMIT 1", |
| 181 | zDate, useUtc ? "" : ",'utc'" |
| 182 | ); |
| 183 | free(zCopy); |
| 184 | return zUuid; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | ** COMMAND: test-name-to-id |
| 189 | ** |
| 190 | ** Convert a name to a full artifact ID. |
| 191 |