Fossil SCM
experimental CLI version of rss feed, per ML request.
Commit
e28a5765faf5aeac7e40ffea2ab96d8f0d548b8d
Parent
bed113ca3fb1d89…
1 file changed
+170
+170
| --- src/rss.c | ||
| +++ src/rss.c | ||
| @@ -196,10 +196,180 @@ | ||
| 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. | |
| 211 | +*/ | |
| 212 | +void cmd_timeline_rss(void){ | |
| 213 | + Stmt q; | |
| 214 | + int nLine=0; | |
| 215 | + char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; | |
| 216 | + Blob bSQL; | |
| 217 | + const char *zType = find_option("y",NULL,1); /* Type of events. All if NULL */ | |
| 218 | + const char *zTicketUuid = find_option("tkt",NULL,1); | |
| 219 | + const char *zTag = find_option("tag",NULL,1); | |
| 220 | + const char *zFilename = find_option("name",NULL,1); | |
| 221 | + const char *zWiki = find_option("wiki",NULL,1); | |
| 222 | + const char *zLimit = find_option("limit", "n",1); | |
| 223 | + int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" ); | |
| 224 | + int nTagId; | |
| 225 | + const char zSQL1[] = | |
| 226 | + @ SELECT | |
| 227 | + @ blob.rid, | |
| 228 | + @ uuid, | |
| 229 | + @ event.mtime, | |
| 230 | + @ coalesce(ecomment,comment), | |
| 231 | + @ coalesce(euser,user), | |
| 232 | + @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim), | |
| 233 | + @ (SELECT count(*) FROM plink WHERE cid=blob.rid) | |
| 234 | + @ FROM event, blob | |
| 235 | + @ WHERE blob.rid=event.objid | |
| 236 | + ; | |
| 237 | + if(!zType || !*zType){ | |
| 238 | + zType = "all"; | |
| 239 | + } | |
| 240 | + | |
| 241 | + db_find_and_open_repository(0, 0); | |
| 242 | + | |
| 243 | + blob_zero(&bSQL); | |
| 244 | + blob_append( &bSQL, zSQL1, -1 ); | |
| 245 | + | |
| 246 | + if( zType[0]!='a' ){ | |
| 247 | + if( zType[0]=='c' && !g.perm.Read ) zType = "x"; | |
| 248 | + if( zType[0]=='w' && !g.perm.RdWiki ) zType = "x"; | |
| 249 | + if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x"; | |
| 250 | + blob_appendf(&bSQL, " AND event.type=%Q", zType); | |
| 251 | + }else{ | |
| 252 | + if( !g.perm.Read ){ | |
| 253 | + if( g.perm.RdTkt && g.perm.RdWiki ){ | |
| 254 | + blob_append(&bSQL, " AND event.type!='ci'", -1); | |
| 255 | + }else if( g.perm.RdTkt ){ | |
| 256 | + blob_append(&bSQL, " AND event.type=='t'", -1); | |
| 257 | + | |
| 258 | + }else{ | |
| 259 | + blob_append(&bSQL, " AND event.type=='w'", -1); | |
| 260 | + } | |
| 261 | + }else if( !g.perm.RdWiki ){ | |
| 262 | + if( g.perm.RdTkt ){ | |
| 263 | + blob_append(&bSQL, " AND event.type!='w'", -1); | |
| 264 | + }else{ | |
| 265 | + blob_append(&bSQL, " AND event.type=='ci'", -1); | |
| 266 | + } | |
| 267 | + }else if( !g.perm.RdTkt ){ | |
| 268 | + assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki ); | |
| 269 | + blob_append(&bSQL, " AND event.type!='t'", -1); | |
| 270 | + } | |
| 271 | + } | |
| 272 | + | |
| 273 | + if( zTicketUuid ){ | |
| 274 | + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", | |
| 275 | + zTicketUuid); | |
| 276 | + if ( nTagId==0 ){ | |
| 277 | + nTagId = -1; | |
| 278 | + } | |
| 279 | + }else if( zTag ){ | |
| 280 | + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'", | |
| 281 | + zTag); | |
| 282 | + if ( nTagId==0 ){ | |
| 283 | + nTagId = -1; | |
| 284 | + } | |
| 285 | + }else if( zWiki ){ | |
| 286 | + nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'", | |
| 287 | + zWiki); | |
| 288 | + if ( nTagId==0 ){ | |
| 289 | + nTagId = -1; | |
| 290 | + } | |
| 291 | + }else{ | |
| 292 | + nTagId = 0; | |
| 293 | + } | |
| 294 | + | |
| 295 | + if( nTagId==-1 ){ | |
| 296 | + blob_appendf(&bSQL, " AND 0"); | |
| 297 | + }else if( nTagId!=0 ){ | |
| 298 | + blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" | |
| 299 | + " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); | |
| 300 | + } | |
| 301 | + | |
| 302 | + if( zFilename ){ | |
| 303 | + blob_appendf(&bSQL, | |
| 304 | + " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", | |
| 305 | + zFilename, filename_collation() | |
| 306 | + ); | |
| 307 | + } | |
| 308 | + | |
| 309 | + blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); | |
| 310 | + | |
| 311 | + zProjectName = db_get("project-name", 0); | |
| 312 | + if( zProjectName==0 ){ | |
| 313 | + zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s", | |
| 314 | + g.zBaseURL); | |
| 315 | + } | |
| 316 | + zProjectDescr = db_get("project-description", 0); | |
| 317 | + if( zProjectDescr==0 ){ | |
| 318 | + zProjectDescr = zProjectName; | |
| 319 | + } | |
| 320 | + | |
| 321 | + zPubDate = cgi_rfc822_datestamp(time(NULL)); | |
| 322 | + | |
| 323 | + fossil_print("<?xml version=\"1.0\"?>"); | |
| 324 | + fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">"); | |
| 325 | + fossil_print("<channel>\n"); | |
| 326 | + fossil_print("<title>%h</title>\n", zProjectName); | |
| 327 | + fossil_print("<link>%s</link>\n", g.zBaseURL); | |
| 328 | + fossil_print("<description>%h</description>\n", zProjectDescr); | |
| 329 | + fossil_print("<pubDate>%s</pubDate>\n", zPubDate); | |
| 330 | + fossil_print("<generator>Fossil version %s %s</generator>\n", | |
| 331 | + MANIFEST_VERSION, MANIFEST_DATE); | |
| 332 | + free(zPubDate); | |
| 333 | + db_prepare(&q, blob_str(&bSQL)); | |
| 334 | + blob_reset( &bSQL ); | |
| 335 | + while( db_step(&q)==SQLITE_ROW && nLine<=nLimit ){ | |
| 336 | + const char *zId = db_column_text(&q, 1); | |
| 337 | + const char *zCom = db_column_text(&q, 3); | |
| 338 | + const char *zAuthor = db_column_text(&q, 4); | |
| 339 | + char *zPrefix = ""; | |
| 340 | + char *zDate; | |
| 341 | + int nChild = db_column_int(&q, 5); | |
| 342 | + int nParent = db_column_int(&q, 6); | |
| 343 | + time_t ts; | |
| 344 | + | |
| 345 | + ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0); | |
| 346 | + zDate = cgi_rfc822_datestamp(ts); | |
| 347 | + | |
| 348 | + if( nParent>1 && nChild>1 ){ | |
| 349 | + zPrefix = "*MERGE/FORK* "; | |
| 350 | + }else if( nParent>1 ){ | |
| 351 | + zPrefix = "*MERGE* "; | |
| 352 | + }else if( nChild>1 ){ | |
| 353 | + zPrefix = "*FORK* "; | |
| 354 | + } | |
| 355 | + | |
| 356 | + fossil_print("<item>"); | |
| 357 | + fossil_print("<title>%s%h</title>\n", zPrefix, zCom); | |
| 358 | + fossil_print("<link>%s/info/%s</link>\n", g.zBaseURL, zId); | |
| 359 | + fossil_print("<description>%s%h</description>\n", zPrefix, zCom); | |
| 360 | + fossil_print("<pubDate>%s</pubDate>\n", zDate); | |
| 361 | + fossil_print("<dc:creator>%h</dc:creator>\n", zAuthor); | |
| 362 | + fossil_print("<guid>%s/info/%s</guid>\n", g.zBaseURL, zId); | |
| 363 | + fossil_print("</item>\n"); | |
| 364 | + free(zDate); | |
| 365 | + nLine++; | |
| 366 | + } | |
| 367 | + | |
| 368 | + db_finalize(&q); | |
| 369 | + fossil_print("</channel>\n"); | |
| 370 | + fossil_print("</rss>\n"); | |
| 201 | 371 | |
| 202 | 372 | if( zFreeProjectName != 0 ){ |
| 203 | 373 | free( zFreeProjectName ); |
| 204 | 374 | } |
| 205 | 375 | } |
| 206 | 376 |
| --- src/rss.c | |
| +++ src/rss.c | |
| @@ -196,10 +196,180 @@ | |
| 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 | |
| @@ -196,10 +196,180 @@ | |
| 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. |
| 211 | */ |
| 212 | void cmd_timeline_rss(void){ |
| 213 | Stmt q; |
| 214 | int nLine=0; |
| 215 | char *zPubDate, *zProjectName, *zProjectDescr, *zFreeProjectName=0; |
| 216 | Blob bSQL; |
| 217 | const char *zType = find_option("y",NULL,1); /* Type of events. All if NULL */ |
| 218 | const char *zTicketUuid = find_option("tkt",NULL,1); |
| 219 | const char *zTag = find_option("tag",NULL,1); |
| 220 | const char *zFilename = find_option("name",NULL,1); |
| 221 | const char *zWiki = find_option("wiki",NULL,1); |
| 222 | const char *zLimit = find_option("limit", "n",1); |
| 223 | int nLimit = atoi( (zLimit && *zLimit) ? zLimit : "20" ); |
| 224 | int nTagId; |
| 225 | const char zSQL1[] = |
| 226 | @ SELECT |
| 227 | @ blob.rid, |
| 228 | @ uuid, |
| 229 | @ event.mtime, |
| 230 | @ coalesce(ecomment,comment), |
| 231 | @ coalesce(euser,user), |
| 232 | @ (SELECT count(*) FROM plink WHERE pid=blob.rid AND isprim), |
| 233 | @ (SELECT count(*) FROM plink WHERE cid=blob.rid) |
| 234 | @ FROM event, blob |
| 235 | @ WHERE blob.rid=event.objid |
| 236 | ; |
| 237 | if(!zType || !*zType){ |
| 238 | zType = "all"; |
| 239 | } |
| 240 | |
| 241 | db_find_and_open_repository(0, 0); |
| 242 | |
| 243 | blob_zero(&bSQL); |
| 244 | blob_append( &bSQL, zSQL1, -1 ); |
| 245 | |
| 246 | if( zType[0]!='a' ){ |
| 247 | if( zType[0]=='c' && !g.perm.Read ) zType = "x"; |
| 248 | if( zType[0]=='w' && !g.perm.RdWiki ) zType = "x"; |
| 249 | if( zType[0]=='t' && !g.perm.RdTkt ) zType = "x"; |
| 250 | blob_appendf(&bSQL, " AND event.type=%Q", zType); |
| 251 | }else{ |
| 252 | if( !g.perm.Read ){ |
| 253 | if( g.perm.RdTkt && g.perm.RdWiki ){ |
| 254 | blob_append(&bSQL, " AND event.type!='ci'", -1); |
| 255 | }else if( g.perm.RdTkt ){ |
| 256 | blob_append(&bSQL, " AND event.type=='t'", -1); |
| 257 | |
| 258 | }else{ |
| 259 | blob_append(&bSQL, " AND event.type=='w'", -1); |
| 260 | } |
| 261 | }else if( !g.perm.RdWiki ){ |
| 262 | if( g.perm.RdTkt ){ |
| 263 | blob_append(&bSQL, " AND event.type!='w'", -1); |
| 264 | }else{ |
| 265 | blob_append(&bSQL, " AND event.type=='ci'", -1); |
| 266 | } |
| 267 | }else if( !g.perm.RdTkt ){ |
| 268 | assert( !g.perm.RdTkt &&& g.perm.Read && g.perm.RdWiki ); |
| 269 | blob_append(&bSQL, " AND event.type!='t'", -1); |
| 270 | } |
| 271 | } |
| 272 | |
| 273 | if( zTicketUuid ){ |
| 274 | nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'tkt-%q*'", |
| 275 | zTicketUuid); |
| 276 | if ( nTagId==0 ){ |
| 277 | nTagId = -1; |
| 278 | } |
| 279 | }else if( zTag ){ |
| 280 | nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'sym-%q*'", |
| 281 | zTag); |
| 282 | if ( nTagId==0 ){ |
| 283 | nTagId = -1; |
| 284 | } |
| 285 | }else if( zWiki ){ |
| 286 | nTagId = db_int(0, "SELECT tagid FROM tag WHERE tagname GLOB 'wiki-%q*'", |
| 287 | zWiki); |
| 288 | if ( nTagId==0 ){ |
| 289 | nTagId = -1; |
| 290 | } |
| 291 | }else{ |
| 292 | nTagId = 0; |
| 293 | } |
| 294 | |
| 295 | if( nTagId==-1 ){ |
| 296 | blob_appendf(&bSQL, " AND 0"); |
| 297 | }else if( nTagId!=0 ){ |
| 298 | blob_appendf(&bSQL, " AND (EXISTS(SELECT 1 FROM tagxref" |
| 299 | " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid))", nTagId); |
| 300 | } |
| 301 | |
| 302 | if( zFilename ){ |
| 303 | blob_appendf(&bSQL, |
| 304 | " AND (SELECT mlink.fnid FROM mlink WHERE event.objid=mlink.mid) IN (SELECT fnid FROM filename WHERE name=%Q %s)", |
| 305 | zFilename, filename_collation() |
| 306 | ); |
| 307 | } |
| 308 | |
| 309 | blob_append( &bSQL, " ORDER BY event.mtime DESC", -1 ); |
| 310 | |
| 311 | zProjectName = db_get("project-name", 0); |
| 312 | if( zProjectName==0 ){ |
| 313 | zFreeProjectName = zProjectName = mprintf("Fossil source repository for: %s", |
| 314 | g.zBaseURL); |
| 315 | } |
| 316 | zProjectDescr = db_get("project-description", 0); |
| 317 | if( zProjectDescr==0 ){ |
| 318 | zProjectDescr = zProjectName; |
| 319 | } |
| 320 | |
| 321 | zPubDate = cgi_rfc822_datestamp(time(NULL)); |
| 322 | |
| 323 | fossil_print("<?xml version=\"1.0\"?>"); |
| 324 | fossil_print("<rss xmlns:dc=\"http://purl.org/dc/elements/1.1/\" version=\"2.0\">"); |
| 325 | fossil_print("<channel>\n"); |
| 326 | fossil_print("<title>%h</title>\n", zProjectName); |
| 327 | fossil_print("<link>%s</link>\n", g.zBaseURL); |
| 328 | fossil_print("<description>%h</description>\n", zProjectDescr); |
| 329 | fossil_print("<pubDate>%s</pubDate>\n", zPubDate); |
| 330 | fossil_print("<generator>Fossil version %s %s</generator>\n", |
| 331 | MANIFEST_VERSION, MANIFEST_DATE); |
| 332 | free(zPubDate); |
| 333 | db_prepare(&q, blob_str(&bSQL)); |
| 334 | blob_reset( &bSQL ); |
| 335 | while( db_step(&q)==SQLITE_ROW && nLine<=nLimit ){ |
| 336 | const char *zId = db_column_text(&q, 1); |
| 337 | const char *zCom = db_column_text(&q, 3); |
| 338 | const char *zAuthor = db_column_text(&q, 4); |
| 339 | char *zPrefix = ""; |
| 340 | char *zDate; |
| 341 | int nChild = db_column_int(&q, 5); |
| 342 | int nParent = db_column_int(&q, 6); |
| 343 | time_t ts; |
| 344 | |
| 345 | ts = (time_t)((db_column_double(&q,2) - 2440587.5)*86400.0); |
| 346 | zDate = cgi_rfc822_datestamp(ts); |
| 347 | |
| 348 | if( nParent>1 && nChild>1 ){ |
| 349 | zPrefix = "*MERGE/FORK* "; |
| 350 | }else if( nParent>1 ){ |
| 351 | zPrefix = "*MERGE* "; |
| 352 | }else if( nChild>1 ){ |
| 353 | zPrefix = "*FORK* "; |
| 354 | } |
| 355 | |
| 356 | fossil_print("<item>"); |
| 357 | fossil_print("<title>%s%h</title>\n", zPrefix, zCom); |
| 358 | fossil_print("<link>%s/info/%s</link>\n", g.zBaseURL, zId); |
| 359 | fossil_print("<description>%s%h</description>\n", zPrefix, zCom); |
| 360 | fossil_print("<pubDate>%s</pubDate>\n", zDate); |
| 361 | fossil_print("<dc:creator>%h</dc:creator>\n", zAuthor); |
| 362 | fossil_print("<guid>%s/info/%s</guid>\n", g.zBaseURL, zId); |
| 363 | fossil_print("</item>\n"); |
| 364 | free(zDate); |
| 365 | nLine++; |
| 366 | } |
| 367 | |
| 368 | db_finalize(&q); |
| 369 | fossil_print("</channel>\n"); |
| 370 | fossil_print("</rss>\n"); |
| 371 | |
| 372 | if( zFreeProjectName != 0 ){ |
| 373 | free( zFreeProjectName ); |
| 374 | } |
| 375 | } |
| 376 |