Fossil SCM
merged in rss-cli.
Commit
4d910042718484bfa1dff20f1b20cb8a0d47bdd1
Parent
2864db30806fc5e…
1 file changed
+176
-1
+176
-1
| --- src/rss.c | ||
| +++ src/rss.c | ||
| @@ -160,11 +160,11 @@ | ||
| 160 | 160 | @ <pubDate>%s(zPubDate)</pubDate> |
| 161 | 161 | @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> |
| 162 | 162 | free(zPubDate); |
| 163 | 163 | db_prepare(&q, blob_str(&bSQL)); |
| 164 | 164 | blob_reset( &bSQL ); |
| 165 | - while( db_step(&q)==SQLITE_ROW && nLine<=nLimit ){ | |
| 165 | + while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){ | |
| 166 | 166 | const char *zId = db_column_text(&q, 1); |
| 167 | 167 | const char *zCom = db_column_text(&q, 3); |
| 168 | 168 | const char *zAuthor = db_column_text(&q, 4); |
| 169 | 169 | char *zPrefix = ""; |
| 170 | 170 | char *zDate; |
| @@ -196,10 +196,185 @@ | ||
| 196 | 196 | } |
| 197 | 197 | |
| 198 | 198 | db_finalize(&q); |
| 199 | 199 | @ </channel> |
| 200 | 200 | @ </rss> |
| 201 | + | |
| 202 | + if( zFreeProjectName != 0 ){ | |
| 203 | + free( zFreeProjectName ); | |
| 204 | + } | |
| 205 | +} | |
| 206 | + | |
| 207 | +/* | |
| 208 | +** COMMAND: rss | |
| 209 | +** | |
| 210 | +** The CLI variant of the /timeline.rss page, this produces an RSS | |
| 211 | +** feed of the timeline to stdout. Options: | |
| 212 | +** | |
| 213 | +** -type|y FLAG | |
| 214 | +** may be: all (default), ci (show checkins only), t (show tickets only), | |
| 215 | +** w (show wiki only). LIMIT is the number of items to show. | |
| 216 | +** | |
| 217 | +** -tkt UUID | |
| 218 | +** Filters for only those events for the specified ticket. | |
| 219 | +** | |
| 220 | +** -tag TAG | |
| 221 | +** filters for a tag | |
| 222 | +** | |
| 223 | +** -wiki NAME | |
| 224 | +** Filters on a specific wiki page. | |
| 225 | +** | |
| 226 | +** Only one of -tkt, -tag, or -wiki may be used. | |
| 227 | +** | |
| 228 | +** -name FILENAME | |
| 229 | +** filters for a specific file. This may be combined with one of the other | |
| 230 | +** filters (useful for looking at a specific branch). | |
| 231 | +** | |
| 232 | +** -url STRING | |
| 233 | +** Sets the RSS feed's root URL to the given string. The default is | |
| 234 | +** "URL-PLACEHOLDER" (without quotes). | |
| 235 | +*/ | |
| 236 | +void cmd_timeline_rss(void){ | |
| 237 | + Stmt q; | |
| 238 | + int nLine=0; | |
| 239 | + char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; | |
| 240 | + Blob bSQL; | |
| 241 | + const char *zType = find_option("type","y",1); /* Type of events. All if NULL */ | |
| 242 | + const char *zTicketUuid = find_option("tkt",NULL,1); | |
| 243 | + const char *zTag = find_option("tag",NULL,1); | |
| 244 | + const char *zFilename = find_option("name",NULL,1); | |
| 245 | + const char *zWiki = find_option("wiki",NULL,1); | |
| 246 | + const char *zLimit = find_option("limit", "n",1); | |
| 247 | + const char *zBaseURL = find_option("url", NULL, 1); | |
| 248 | + int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" ); | |
| 249 | + int nTagId; | |
| 250 | + const char zSQL1[] = | |
| 251 | + @ SELECT | |
| 252 | + @ blob.rid, | |
| 253 | + @ uuid, | |
| 254 | + @ event.mtime, | |
| 255 | + @ coalesce(ecomment,comment), | |
| 256 | + @ coalesce(euser,user), | |
| 257 | + @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim), | |
| 258 | + @ (SELECT count(*) FROM plink WHERE cid=blob.rid) | |
| 259 | + @ FROM event, blob | |
| 260 | + @ WHERE blob.rid=event.objid | |
| 261 | + ; | |
| 262 | + if(!zType || !*zType){ | |
| 263 | + zType = "all"; | |
| 264 | + } | |
| 265 | + if(!zBaseURL || !*zBaseURL){ | |
| 266 | + zBaseURL = "URL-PLACEHOLDER"; | |
| 267 | + } | |
| 268 | + | |
| 269 | + db_find_and_open_repository(0, 0); | |
| 270 | + | |
| 271 | + blob_zero(&bSQL); | |
| 272 | + blob_append( &bSQL, zSQL1, -1 ); | |
| 273 | + | |
| 274 | + if( zType[0]!='a' ){ | |
| 275 | + blob_appendf(&bSQL, " AND event.type=%Q", zType); | |
| 276 | + } | |
| 277 | + | |
| 278 | + if( zTicketUuid ){ | |
| 279 | + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", | |
| 280 | + zTicketUuid); | |
| 281 | + if ( nTagId==0 ){ | |
| 282 | + nTagId = -1; | |
| 283 | + } | |
| 284 | + }else if( zTag ){ | |
| 285 | + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'", | |
| 286 | + zTag); | |
| 287 | + if ( nTagId==0 ){ | |
| 288 | + nTagId = -1; | |
| 289 | + } | |
| 290 | + }else if( zWiki ){ | |
| 291 | + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'", | |
| 292 | + zWiki); | |
| 293 | + if ( nTagId==0 ){ | |
| 294 | + nTagId = -1; | |
| 295 | + } | |
| 296 | + }else{ | |
| 297 | + nTagId = 0; | |
| 298 | + } | |
| 299 | + | |
| 300 | + if( nTagId==-1 ){ | |
| 301 | + blob_appendf(&bSQL, " AND 0"); | |
| 302 | + }else if( nTagId!=0 ){ | |
| 303 | + blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" | |
| 304 | + " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); | |
| 305 | + } | |
| 306 | + | |
| 307 | + if( zFilename ){ | |
| 308 | + blob_appendf(&bSQL, | |
| 309 | + " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", | |
| 310 | + zFilename, filename_collation() | |
| 311 | + ); | |
| 312 | + } | |
| 313 | + | |
| 314 | + blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); | |
| 315 | + | |
| 316 | + zProjectName = db_get("project-name", 0); | |
| 317 | + if( zProjectName==0 ){ | |
| 318 | + zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s", | |
| 319 | + zBaseURL); | |
| 320 | + } | |
| 321 | + zProjectDescr = db_get("project-description", 0); | |
| 322 | + if( zProjectDescr==0 ){ | |
| 323 | + zProjectDescr = zProjectName; | |
| 324 | + } | |
| 325 | + | |
| 326 | + zPubDate = cgi_rfc822_datestamp(time(NULL)); | |
| 327 | + | |
| 328 | + fossil_print("<?xml version=\"1.0\"?>"); | |
| 329 | + fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">"); | |
| 330 | + fossil_print("<channel>\n"); | |
| 331 | + fossil_print("<title>%h</title>\n", zProjectName); | |
| 332 | + fossil_print("<link>%s</link>\n", zBaseURL); | |
| 333 | + fossil_print("<description>%h</description>\n", zProjectDescr); | |
| 334 | + fossil_print("<pubDate>%s</pubDate>\n", zPubDate); | |
| 335 | + fossil_print("<generator>Fossil version %s %s</generator>\n", | |
| 336 | + MANIFEST_VERSION, MANIFEST_DATE); | |
| 337 | + free(zPubDate); | |
| 338 | + db_prepare(&q, blob_str(&bSQL)); | |
| 339 | + blob_reset( &bSQL ); | |
| 340 | + while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){ | |
| 341 | + const char *zId = db_column_text(&q, 1); | |
| 342 | + const char *zCom = db_column_text(&q, 3); | |
| 343 | + const char *zAuthor = db_column_text(&q, 4); | |
| 344 | + char *zPrefix = ""; | |
| 345 | + char *zDate; | |
| 346 | + int nChild = db_column_int(&q, 5); | |
| 347 | + int nParent = db_column_int(&q, 6); | |
| 348 | + time_t ts; | |
| 349 | + | |
| 350 | + ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0); | |
| 351 | + zDate = cgi_rfc822_datestamp(ts); | |
| 352 | + | |
| 353 | + if( nParent>1 && nChild>1 ){ | |
| 354 | + zPrefix = "*MERGE/FORK* "; | |
| 355 | + }else if( nParent>1 ){ | |
| 356 | + zPrefix = "*MERGE* "; | |
| 357 | + }else if( nChild>1 ){ | |
| 358 | + zPrefix = "*FORK* "; | |
| 359 | + } | |
| 360 | + | |
| 361 | + fossil_print("<item>"); | |
| 362 | + fossil_print("<title>%s%h</title>\n", zPrefix, zCom); | |
| 363 | + fossil_print("<link>%s/info/%s</link>\n", zBaseURL, zId); | |
| 364 | + fossil_print("<description>%s%h</description>\n", zPrefix, zCom); | |
| 365 | + fossil_print("<pubDate>%s</pubDate>\n", zDate); | |
| 366 | + fossil_print("<dc:creator>%h</dc:creator>\n", zAuthor); | |
| 367 | + fossil_print("<guid>%s/info/%s</guid>\n", g.zBaseURL, zId); | |
| 368 | + fossil_print("</item>\n"); | |
| 369 | + free(zDate); | |
| 370 | + nLine++; | |
| 371 | + } | |
| 372 | + | |
| 373 | + db_finalize(&q); | |
| 374 | + fossil_print("</channel>\n"); | |
| 375 | + fossil_print("</rss>\n"); | |
| 201 | 376 | |
| 202 | 377 | if( zFreeProjectName != 0 ){ |
| 203 | 378 | free( zFreeProjectName ); |
| 204 | 379 | } |
| 205 | 380 | } |
| 206 | 381 |
| --- src/rss.c | |
| +++ src/rss.c | |
| @@ -160,11 +160,11 @@ | |
| 160 | @ <pubDate>%s(zPubDate)</pubDate> |
| 161 | @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> |
| 162 | free(zPubDate); |
| 163 | db_prepare(&q, blob_str(&bSQL)); |
| 164 | blob_reset( &bSQL ); |
| 165 | while( db_step(&q)==SQLITE_ROW && nLine<=nLimit ){ |
| 166 | const char *zId = db_column_text(&q, 1); |
| 167 | const char *zCom = db_column_text(&q, 3); |
| 168 | const char *zAuthor = db_column_text(&q, 4); |
| 169 | char *zPrefix = ""; |
| 170 | char *zDate; |
| @@ -196,10 +196,185 @@ | |
| 196 | } |
| 197 | |
| 198 | db_finalize(&q); |
| 199 | @ </channel> |
| 200 | @ </rss> |
| 201 | |
| 202 | if( zFreeProjectName != 0 ){ |
| 203 | free( zFreeProjectName ); |
| 204 | } |
| 205 | } |
| 206 |
| --- src/rss.c | |
| +++ src/rss.c | |
| @@ -160,11 +160,11 @@ | |
| 160 | @ <pubDate>%s(zPubDate)</pubDate> |
| 161 | @ <generator>Fossil version %s(MANIFEST_VERSION) %s(MANIFEST_DATE)</generator> |
| 162 | free(zPubDate); |
| 163 | db_prepare(&q, blob_str(&bSQL)); |
| 164 | blob_reset( &bSQL ); |
| 165 | while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){ |
| 166 | const char *zId = db_column_text(&q, 1); |
| 167 | const char *zCom = db_column_text(&q, 3); |
| 168 | const char *zAuthor = db_column_text(&q, 4); |
| 169 | char *zPrefix = ""; |
| 170 | char *zDate; |
| @@ -196,10 +196,185 @@ | |
| 196 | } |
| 197 | |
| 198 | db_finalize(&q); |
| 199 | @ </channel> |
| 200 | @ </rss> |
| 201 | |
| 202 | if( zFreeProjectName != 0 ){ |
| 203 | free( zFreeProjectName ); |
| 204 | } |
| 205 | } |
| 206 | |
| 207 | /* |
| 208 | ** COMMAND: rss |
| 209 | ** |
| 210 | ** The CLI variant of the /timeline.rss page, this produces an RSS |
| 211 | ** feed of the timeline to stdout. Options: |
| 212 | ** |
| 213 | ** -type|y FLAG |
| 214 | ** may be: all (default), ci (show checkins only), t (show tickets only), |
| 215 | ** w (show wiki only). LIMIT is the number of items to show. |
| 216 | ** |
| 217 | ** -tkt UUID |
| 218 | ** Filters for only those events for the specified ticket. |
| 219 | ** |
| 220 | ** -tag TAG |
| 221 | ** filters for a tag |
| 222 | ** |
| 223 | ** -wiki NAME |
| 224 | ** Filters on a specific wiki page. |
| 225 | ** |
| 226 | ** Only one of -tkt, -tag, or -wiki may be used. |
| 227 | ** |
| 228 | ** -name FILENAME |
| 229 | ** filters for a specific file. This may be combined with one of the other |
| 230 | ** filters (useful for looking at a specific branch). |
| 231 | ** |
| 232 | ** -url STRING |
| 233 | ** Sets the RSS feed's root URL to the given string. The default is |
| 234 | ** "URL-PLACEHOLDER" (without quotes). |
| 235 | */ |
| 236 | void cmd_timeline_rss(void){ |
| 237 | Stmt q; |
| 238 | int nLine=0; |
| 239 | char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; |
| 240 | Blob bSQL; |
| 241 | const char *zType = find_option("type","y",1); /* Type of events. All if NULL */ |
| 242 | const char *zTicketUuid = find_option("tkt",NULL,1); |
| 243 | const char *zTag = find_option("tag",NULL,1); |
| 244 | const char *zFilename = find_option("name",NULL,1); |
| 245 | const char *zWiki = find_option("wiki",NULL,1); |
| 246 | const char *zLimit = find_option("limit", "n",1); |
| 247 | const char *zBaseURL = find_option("url", NULL, 1); |
| 248 | int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" ); |
| 249 | int nTagId; |
| 250 | const char zSQL1[] = |
| 251 | @ SELECT |
| 252 | @ blob.rid, |
| 253 | @ uuid, |
| 254 | @ event.mtime, |
| 255 | @ coalesce(ecomment,comment), |
| 256 | @ coalesce(euser,user), |
| 257 | @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim), |
| 258 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) |
| 259 | @ FROM event, blob |
| 260 | @ WHERE blob.rid=event.objid |
| 261 | ; |
| 262 | if(!zType || !*zType){ |
| 263 | zType = "all"; |
| 264 | } |
| 265 | if(!zBaseURL || !*zBaseURL){ |
| 266 | zBaseURL = "URL-PLACEHOLDER"; |
| 267 | } |
| 268 | |
| 269 | db_find_and_open_repository(0, 0); |
| 270 | |
| 271 | blob_zero(&bSQL); |
| 272 | blob_append( &bSQL, zSQL1, -1 ); |
| 273 | |
| 274 | if( zType[0]!='a' ){ |
| 275 | blob_appendf(&bSQL, " AND event.type=%Q", zType); |
| 276 | } |
| 277 | |
| 278 | if( zTicketUuid ){ |
| 279 | nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", |
| 280 | zTicketUuid); |
| 281 | if ( nTagId==0 ){ |
| 282 | nTagId = -1; |
| 283 | } |
| 284 | }else if( zTag ){ |
| 285 | nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'", |
| 286 | zTag); |
| 287 | if ( nTagId==0 ){ |
| 288 | nTagId = -1; |
| 289 | } |
| 290 | }else if( zWiki ){ |
| 291 | nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'", |
| 292 | zWiki); |
| 293 | if ( nTagId==0 ){ |
| 294 | nTagId = -1; |
| 295 | } |
| 296 | }else{ |
| 297 | nTagId = 0; |
| 298 | } |
| 299 | |
| 300 | if( nTagId==-1 ){ |
| 301 | blob_appendf(&bSQL, " AND 0"); |
| 302 | }else if( nTagId!=0 ){ |
| 303 | blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" |
| 304 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); |
| 305 | } |
| 306 | |
| 307 | if( zFilename ){ |
| 308 | blob_appendf(&bSQL, |
| 309 | " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", |
| 310 | zFilename, filename_collation() |
| 311 | ); |
| 312 | } |
| 313 | |
| 314 | blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); |
| 315 | |
| 316 | zProjectName = db_get("project-name", 0); |
| 317 | if( zProjectName==0 ){ |
| 318 | zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s", |
| 319 | zBaseURL); |
| 320 | } |
| 321 | zProjectDescr = db_get("project-description", 0); |
| 322 | if( zProjectDescr==0 ){ |
| 323 | zProjectDescr = zProjectName; |
| 324 | } |
| 325 | |
| 326 | zPubDate = cgi_rfc822_datestamp(time(NULL)); |
| 327 | |
| 328 | fossil_print("<?xml version=\"1.0\"?>"); |
| 329 | fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">"); |
| 330 | fossil_print("<channel>\n"); |
| 331 | fossil_print("<title>%h</title>\n", zProjectName); |
| 332 | fossil_print("<link>%s</link>\n", zBaseURL); |
| 333 | fossil_print("<description>%h</description>\n", zProjectDescr); |
| 334 | fossil_print("<pubDate>%s</pubDate>\n", zPubDate); |
| 335 | fossil_print("<generator>Fossil version %s %s</generator>\n", |
| 336 | MANIFEST_VERSION, MANIFEST_DATE); |
| 337 | free(zPubDate); |
| 338 | db_prepare(&q, blob_str(&bSQL)); |
| 339 | blob_reset( &bSQL ); |
| 340 | while( db_step(&q)==SQLITE_ROW && nLine<nLimit ){ |
| 341 | const char *zId = db_column_text(&q, 1); |
| 342 | const char *zCom = db_column_text(&q, 3); |
| 343 | const char *zAuthor = db_column_text(&q, 4); |
| 344 | char *zPrefix = ""; |
| 345 | char *zDate; |
| 346 | int nChild = db_column_int(&q, 5); |
| 347 | int nParent = db_column_int(&q, 6); |
| 348 | time_t ts; |
| 349 | |
| 350 | ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0); |
| 351 | zDate = cgi_rfc822_datestamp(ts); |
| 352 | |
| 353 | if( nParent>1 && nChild>1 ){ |
| 354 | zPrefix = "*MERGE/FORK* "; |
| 355 | }else if( nParent>1 ){ |
| 356 | zPrefix = "*MERGE* "; |
| 357 | }else if( nChild>1 ){ |
| 358 | zPrefix = "*FORK* "; |
| 359 | } |
| 360 | |
| 361 | fossil_print("<item>"); |
| 362 | fossil_print("<title>%s%h</title>\n", zPrefix, zCom); |
| 363 | fossil_print("<link>%s/info/%s</link>\n", zBaseURL, zId); |
| 364 | fossil_print("<description>%s%h</description>\n", zPrefix, zCom); |
| 365 | fossil_print("<pubDate>%s</pubDate>\n", zDate); |
| 366 | fossil_print("<dc:creator>%h</dc:creator>\n", zAuthor); |
| 367 | fossil_print("<guid>%s/info/%s</guid>\n", g.zBaseURL, zId); |
| 368 | fossil_print("</item>\n"); |
| 369 | free(zDate); |
| 370 | nLine++; |
| 371 | } |
| 372 | |
| 373 | db_finalize(&q); |
| 374 | fossil_print("</channel>\n"); |
| 375 | fossil_print("</rss>\n"); |
| 376 | |
| 377 | if( zFreeProjectName != 0 ){ |
| 378 | free( zFreeProjectName ); |
| 379 | } |
| 380 | } |
| 381 |