Fossil SCM

Reworked the /json/artifact/FILE|CHECKIN response payloads to streamline the structures, remove duplicate data, and add file parent information.

stephan 2012-07-13 18:49 trunk
Commit 824ede2af6250936b7020812748fd7af65e745bc
--- src/json_artifact.c
+++ src/json_artifact.c
@@ -29,12 +29,16 @@
2929
** specialized to return a JSON form of one type of artifact.
3030
**
3131
** Implementations may assert() that rid refers to requested artifact
3232
** type, since mismatches in the artifact types come from
3333
** json_page_artifact() as opposed to client data.
34
+**
35
+** The pParent parameter points to the response payload object. It
36
+** _may_ be used to populate "top-level" information in the response
37
+** payload, but normally this is neither necessary nor desired.
3438
*/
35
-typedef cson_value * (*artifact_f)( int rid );
39
+typedef cson_value * (*artifact_f)( cson_object * pParent, int rid );
3640
3741
/*
3842
** Internal per-artifact-type dispatching helper.
3943
*/
4044
typedef struct ArtifactDispatchEntry {
@@ -160,11 +164,11 @@
160164
if(tmpV){
161165
SET("tags",tmpV);
162166
}
163167
164168
if( showFiles ){
165
- tmpV = json_get_changed_files(rid);
169
+ tmpV = json_get_changed_files(rid, 1);
166170
if(tmpV){
167171
SET("files",tmpV);
168172
}
169173
}
170174
@@ -175,11 +179,11 @@
175179
}
176180
177181
/*
178182
** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
179183
*/
180
-cson_value * json_artifact_ticket( int rid ){
184
+cson_value * json_artifact_ticket( cson_object * zParent, int rid ){
181185
cson_object * pay = NULL;
182186
Manifest *pTktChng = NULL;
183187
static cson_value * eventTypeLabel = NULL;
184188
if(! g.perm.RdTkt ){
185189
g.json.resultCode = FSL_JSON_E_DENIED;
@@ -205,16 +209,22 @@
205209
}
206210
207211
/*
208212
** Sub-impl of /json/artifact for checkins.
209213
*/
210
-static cson_value * json_artifact_ci( int rid ){
214
+static cson_value * json_artifact_ci( cson_object * zParent, int rid ){
211215
if(!g.perm.Read){
212216
json_set_err( FSL_JSON_E_DENIED, "Viewing checkins requires 'o' privileges." );
213217
return NULL;
214218
}else{
215
- return json_artifact_for_ci(rid, 1);
219
+ cson_value * artV = json_artifact_for_ci(rid, 1);
220
+ cson_object * art = cson_value_get_object(artV);
221
+ if(art){
222
+ cson_object_merge( zParent, art, CSON_MERGE_REPLACE );
223
+ cson_free_object(art);
224
+ }
225
+ return cson_object_value(zParent);
216226
}
217227
}
218228
219229
/*
220230
** Internal mapping of /json/artifact/FOO commands/callbacks.
@@ -228,27 +238,36 @@
228238
/* Final entry MUST have a NULL name. */
229239
{NULL,NULL}
230240
};
231241
232242
/*
233
-** Internal helper which returns true (non-0) if the includeContent
234
-** (HTTP) or -content|-c flags (CLI) are set.
243
+** Internal helper which returns:
244
+**
245
+** If the "format" (CLI: -f) flag is set function returns the same as
246
+** json_wiki_get_content_format_flag(), else it returns true (non-0)
247
+** if either the includeContent (HTTP) or -content|-c boolean flags
248
+** (CLI) are set.
235249
*/
236
-static char json_artifact_include_content_flag(){
237
- return json_find_option_bool("includeContent","content","c",0);
250
+static char json_artifact_get_content_format_flag(){
251
+ enum { MagicValue = -9 };
252
+ char contentFormat = json_wiki_get_content_format_flag(MagicValue);
253
+ if(MagicValue == contentFormat){
254
+ contentFormat = json_find_option_bool("includeContent","content","c",0) /* deprecated */ ? -1 : 0;
255
+ }
256
+ return contentFormat;
238257
}
239258
240
-cson_value * json_artifact_wiki(int rid){
259
+extern char json_wiki_get_content_format_flag( char defaultValue ) /* json_wiki.c */;
260
+
261
+cson_value * json_artifact_wiki(cson_object * zParent, int rid){
241262
if( ! g.perm.RdWiki ){
242263
json_set_err(FSL_JSON_E_DENIED,
243264
"Requires 'j' privileges.");
244265
return NULL;
245266
}else{
246
- char contentFormat = json_wiki_get_content_format_flag(-9);
247
- if(-9 == contentFormat){
248
- contentFormat = json_artifact_include_content_flag() ? -1 : 0;
249
- }
267
+ enum { MagicValue = -9 };
268
+ char const contentFormat = json_artifact_get_content_format_flag();
250269
return json_get_wiki_page_by_rid(rid, contentFormat);
251270
}
252271
}
253272
254273
/*
@@ -266,48 +285,83 @@
266285
: (isDel
267286
? "removed"
268287
: "modified");
269288
}
270289
271
-cson_value * json_artifact_file(int rid){
290
+cson_value * json_artifact_file(cson_object * zParent, int rid){
272291
cson_object * pay = NULL;
273292
Stmt q = empty_Stmt;
274293
cson_array * checkin_arr = NULL;
275
-
294
+ char contentFormat;
295
+ i64 contentSize = -1;
296
+ char * parentUuid;
276297
if( ! g.perm.Read ){
277298
json_set_err(FSL_JSON_E_DENIED,
278299
"Requires 'o' privileges.");
279300
return NULL;
280301
}
281302
282
- pay = cson_new_object();
303
+ pay = zParent;
283304
284
- if( json_artifact_include_content_flag() ){
305
+ contentFormat = json_artifact_get_content_format_flag();
306
+ if( 0 != contentFormat ){
285307
Blob content = empty_blob;
286308
const char *zMime;
309
+ char const * zFormat = (contentFormat<1) ? "raw" : "html";
287310
content_get(rid, &content);
288311
zMime = mimetype_from_content(&content);
289
- cson_object_set(pay, "contentType",
312
+ cson_object_set(zParent, "contentType",
290313
json_new_string(zMime ? zMime : "text/plain"));
291
- cson_object_set(pay, "size", json_new_int( blob_size(&content)) );
292
- if(!zMime){
293
- cson_object_set(pay, "content",
314
+ if(!zMime){/* text/plain */
315
+ if(0 < blob_size(&content)){
316
+ if( 0 < contentFormat ){/*HTML-size it*/
317
+ Blob html = empty_blob;
318
+ wiki_convert(&content, &html, 0);
319
+ assert( blob_size(&content) < blob_size(&html) );
320
+ blob_swap( &html, &content );
321
+ assert( blob_size(&content) > blob_size(&html) );
322
+ blob_reset( &html );
323
+ }/*else as-is*/
324
+ }
325
+ cson_object_set(zParent, "content",
294326
cson_value_new_string(blob_str(&content),
295327
(unsigned int)blob_size(&content)));
296
- }
328
+ }/*else binary: ignore*/
329
+ contentSize = blob_size(&content);
330
+ cson_object_set(zParent, "contentSize", json_new_int(contentSize) );
331
+ cson_object_set(zParent, "contentFormat", json_new_string(zFormat) );
297332
blob_reset(&content);
298333
}
334
+ contentSize = db_int64(-1, "SELECT size FROM blob WHERE rid=%d", rid);
335
+ assert( -1 < contentSize );
336
+ cson_object_set(zParent, "size", json_new_int(contentSize) );
299337
338
+ parentUuid = db_text(NULL,
339
+ "SELECT DISTINCT p.uuid "
340
+ "FROM blob p, blob f, mlink m "
341
+ "WHERE m.pid=p.rid "
342
+ "AND m.fid=f.rid "
343
+ "AND f.rid=%d",
344
+ rid
345
+ );
346
+ if(parentUuid){
347
+ cson_object_set( zParent, "parent", json_new_string(parentUuid) );
348
+ fossil_free(parentUuid);
349
+ }
350
+
351
+ /* Find checkins associated with this file... */
300352
db_prepare(&q,
301353
"SELECT filename.name AS name, "
302354
" (mlink.pid==0) AS isNew,"
303355
" (mlink.fid==0) AS isDel,"
304356
" cast(strftime('%%s',event.mtime) as int) AS timestamp,"
305357
" coalesce(event.ecomment,event.comment) as comment,"
306358
" coalesce(event.euser,event.user) as user,"
307
- " a.size AS size,"
308
- " b.uuid as uuid, "
359
+#if 0
360
+ " a.size AS size," /* same for all checkins. */
361
+#endif
362
+ " b.uuid as checkin, "
309363
#if 0
310364
" mlink.mperm as mperm,"
311365
#endif
312366
" coalesce((SELECT value FROM tagxref"
313367
" WHERE tagid=%d AND tagtype>0 AND "
@@ -326,10 +380,11 @@
326380
*/
327381
checkin_arr = cson_new_array();
328382
cson_object_set(pay, "checkins", cson_array_value(checkin_arr));
329383
while( (SQLITE_ROW==db_step(&q) ) ){
330384
cson_object * row = cson_value_get_object(cson_sqlite3_row_to_object(q.pStmt));
385
+ /* FIXME: move this isNew/isDel stuff into an SQL CASE statement. */
331386
char const isNew = cson_value_get_bool(cson_object_get(row,"isNew"));
332387
char const isDel = cson_value_get_bool(cson_object_get(row,"isDel"));
333388
cson_object_set(row, "isNew", NULL);
334389
cson_object_set(row, "isDel", NULL);
335390
cson_object_set(row, "state",
@@ -371,10 +426,11 @@
371426
goto handle_entry;
372427
}
373428
}
374429
blob_set(&uuid,zName);
375430
rc = name_to_uuid(&uuid,-1,"*");
431
+ /* FIXME: check for a filename if all else fails. */
376432
if(1==rc){
377433
g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
378434
goto error;
379435
}else if(2==rc){
380436
g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID;
@@ -411,32 +467,36 @@
411467
error:
412468
assert( 0 != g.json.resultCode );
413469
goto veryend;
414470
415471
handle_entry:
472
+ pay = cson_new_object();
416473
assert( (NULL != zType) && "Internal dispatching error." );
417474
for( ; dispatcher->name; ++dispatcher ){
418475
if(0!=strcmp(dispatcher->name, zType)){
419476
continue;
420477
}else{
421
- entry = (*dispatcher->func)(rid);
478
+ entry = (*dispatcher->func)(pay, rid);
422479
break;
423480
}
424481
}
425482
if(!g.json.resultCode){
426483
assert( NULL != entry );
427484
assert( NULL != zType );
428
- pay = cson_new_object();
429485
cson_object_set( pay, "type", json_new_string(zType) );
430
- /*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/
431
- cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );
486
+ cson_object_set( pay, "uuid", json_new_string(zUuid) );
487
+ /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/
432488
/*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/
433
- if(entry){
489
+ if(cson_value_is_object(entry) && (cson_value_get_object(entry) != pay)){
434490
cson_object_set(pay, "artifact", entry);
435491
}
436492
}
437493
veryend:
438494
blob_reset(&uuid);
495
+ if(g.json.resultCode && pay){
496
+ cson_free_object(pay);
497
+ pay = NULL;
498
+ }
439499
return cson_object_value(pay);
440500
}
441501
442502
#endif /* FOSSIL_ENABLE_JSON */
443503
--- src/json_artifact.c
+++ src/json_artifact.c
@@ -29,12 +29,16 @@
29 ** specialized to return a JSON form of one type of artifact.
30 **
31 ** Implementations may assert() that rid refers to requested artifact
32 ** type, since mismatches in the artifact types come from
33 ** json_page_artifact() as opposed to client data.
 
 
 
 
34 */
35 typedef cson_value * (*artifact_f)( int rid );
36
37 /*
38 ** Internal per-artifact-type dispatching helper.
39 */
40 typedef struct ArtifactDispatchEntry {
@@ -160,11 +164,11 @@
160 if(tmpV){
161 SET("tags",tmpV);
162 }
163
164 if( showFiles ){
165 tmpV = json_get_changed_files(rid);
166 if(tmpV){
167 SET("files",tmpV);
168 }
169 }
170
@@ -175,11 +179,11 @@
175 }
176
177 /*
178 ** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
179 */
180 cson_value * json_artifact_ticket( int rid ){
181 cson_object * pay = NULL;
182 Manifest *pTktChng = NULL;
183 static cson_value * eventTypeLabel = NULL;
184 if(! g.perm.RdTkt ){
185 g.json.resultCode = FSL_JSON_E_DENIED;
@@ -205,16 +209,22 @@
205 }
206
207 /*
208 ** Sub-impl of /json/artifact for checkins.
209 */
210 static cson_value * json_artifact_ci( int rid ){
211 if(!g.perm.Read){
212 json_set_err( FSL_JSON_E_DENIED, "Viewing checkins requires 'o' privileges." );
213 return NULL;
214 }else{
215 return json_artifact_for_ci(rid, 1);
 
 
 
 
 
 
216 }
217 }
218
219 /*
220 ** Internal mapping of /json/artifact/FOO commands/callbacks.
@@ -228,27 +238,36 @@
228 /* Final entry MUST have a NULL name. */
229 {NULL,NULL}
230 };
231
232 /*
233 ** Internal helper which returns true (non-0) if the includeContent
234 ** (HTTP) or -content|-c flags (CLI) are set.
 
 
 
 
235 */
236 static char json_artifact_include_content_flag(){
237 return json_find_option_bool("includeContent","content","c",0);
 
 
 
 
 
238 }
239
240 cson_value * json_artifact_wiki(int rid){
 
 
241 if( ! g.perm.RdWiki ){
242 json_set_err(FSL_JSON_E_DENIED,
243 "Requires 'j' privileges.");
244 return NULL;
245 }else{
246 char contentFormat = json_wiki_get_content_format_flag(-9);
247 if(-9 == contentFormat){
248 contentFormat = json_artifact_include_content_flag() ? -1 : 0;
249 }
250 return json_get_wiki_page_by_rid(rid, contentFormat);
251 }
252 }
253
254 /*
@@ -266,48 +285,83 @@
266 : (isDel
267 ? "removed"
268 : "modified");
269 }
270
271 cson_value * json_artifact_file(int rid){
272 cson_object * pay = NULL;
273 Stmt q = empty_Stmt;
274 cson_array * checkin_arr = NULL;
275
 
 
276 if( ! g.perm.Read ){
277 json_set_err(FSL_JSON_E_DENIED,
278 "Requires 'o' privileges.");
279 return NULL;
280 }
281
282 pay = cson_new_object();
283
284 if( json_artifact_include_content_flag() ){
 
285 Blob content = empty_blob;
286 const char *zMime;
 
287 content_get(rid, &content);
288 zMime = mimetype_from_content(&content);
289 cson_object_set(pay, "contentType",
290 json_new_string(zMime ? zMime : "text/plain"));
291 cson_object_set(pay, "size", json_new_int( blob_size(&content)) );
292 if(!zMime){
293 cson_object_set(pay, "content",
 
 
 
 
 
 
 
 
 
294 cson_value_new_string(blob_str(&content),
295 (unsigned int)blob_size(&content)));
296 }
 
 
 
297 blob_reset(&content);
298 }
 
 
 
299
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300 db_prepare(&q,
301 "SELECT filename.name AS name, "
302 " (mlink.pid==0) AS isNew,"
303 " (mlink.fid==0) AS isDel,"
304 " cast(strftime('%%s',event.mtime) as int) AS timestamp,"
305 " coalesce(event.ecomment,event.comment) as comment,"
306 " coalesce(event.euser,event.user) as user,"
307 " a.size AS size,"
308 " b.uuid as uuid, "
 
 
309 #if 0
310 " mlink.mperm as mperm,"
311 #endif
312 " coalesce((SELECT value FROM tagxref"
313 " WHERE tagid=%d AND tagtype>0 AND "
@@ -326,10 +380,11 @@
326 */
327 checkin_arr = cson_new_array();
328 cson_object_set(pay, "checkins", cson_array_value(checkin_arr));
329 while( (SQLITE_ROW==db_step(&q) ) ){
330 cson_object * row = cson_value_get_object(cson_sqlite3_row_to_object(q.pStmt));
 
331 char const isNew = cson_value_get_bool(cson_object_get(row,"isNew"));
332 char const isDel = cson_value_get_bool(cson_object_get(row,"isDel"));
333 cson_object_set(row, "isNew", NULL);
334 cson_object_set(row, "isDel", NULL);
335 cson_object_set(row, "state",
@@ -371,10 +426,11 @@
371 goto handle_entry;
372 }
373 }
374 blob_set(&uuid,zName);
375 rc = name_to_uuid(&uuid,-1,"*");
 
376 if(1==rc){
377 g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
378 goto error;
379 }else if(2==rc){
380 g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID;
@@ -411,32 +467,36 @@
411 error:
412 assert( 0 != g.json.resultCode );
413 goto veryend;
414
415 handle_entry:
 
416 assert( (NULL != zType) && "Internal dispatching error." );
417 for( ; dispatcher->name; ++dispatcher ){
418 if(0!=strcmp(dispatcher->name, zType)){
419 continue;
420 }else{
421 entry = (*dispatcher->func)(rid);
422 break;
423 }
424 }
425 if(!g.json.resultCode){
426 assert( NULL != entry );
427 assert( NULL != zType );
428 pay = cson_new_object();
429 cson_object_set( pay, "type", json_new_string(zType) );
430 /*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/
431 cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );
432 /*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/
433 if(entry){
434 cson_object_set(pay, "artifact", entry);
435 }
436 }
437 veryend:
438 blob_reset(&uuid);
 
 
 
 
439 return cson_object_value(pay);
440 }
441
442 #endif /* FOSSIL_ENABLE_JSON */
443
--- src/json_artifact.c
+++ src/json_artifact.c
@@ -29,12 +29,16 @@
29 ** specialized to return a JSON form of one type of artifact.
30 **
31 ** Implementations may assert() that rid refers to requested artifact
32 ** type, since mismatches in the artifact types come from
33 ** json_page_artifact() as opposed to client data.
34 **
35 ** The pParent parameter points to the response payload object. It
36 ** _may_ be used to populate "top-level" information in the response
37 ** payload, but normally this is neither necessary nor desired.
38 */
39 typedef cson_value * (*artifact_f)( cson_object * pParent, int rid );
40
41 /*
42 ** Internal per-artifact-type dispatching helper.
43 */
44 typedef struct ArtifactDispatchEntry {
@@ -160,11 +164,11 @@
164 if(tmpV){
165 SET("tags",tmpV);
166 }
167
168 if( showFiles ){
169 tmpV = json_get_changed_files(rid, 1);
170 if(tmpV){
171 SET("files",tmpV);
172 }
173 }
174
@@ -175,11 +179,11 @@
179 }
180
181 /*
182 ** Very incomplete/incorrect impl of /json/artifact/TICKET_ID.
183 */
184 cson_value * json_artifact_ticket( cson_object * zParent, int rid ){
185 cson_object * pay = NULL;
186 Manifest *pTktChng = NULL;
187 static cson_value * eventTypeLabel = NULL;
188 if(! g.perm.RdTkt ){
189 g.json.resultCode = FSL_JSON_E_DENIED;
@@ -205,16 +209,22 @@
209 }
210
211 /*
212 ** Sub-impl of /json/artifact for checkins.
213 */
214 static cson_value * json_artifact_ci( cson_object * zParent, int rid ){
215 if(!g.perm.Read){
216 json_set_err( FSL_JSON_E_DENIED, "Viewing checkins requires 'o' privileges." );
217 return NULL;
218 }else{
219 cson_value * artV = json_artifact_for_ci(rid, 1);
220 cson_object * art = cson_value_get_object(artV);
221 if(art){
222 cson_object_merge( zParent, art, CSON_MERGE_REPLACE );
223 cson_free_object(art);
224 }
225 return cson_object_value(zParent);
226 }
227 }
228
229 /*
230 ** Internal mapping of /json/artifact/FOO commands/callbacks.
@@ -228,27 +238,36 @@
238 /* Final entry MUST have a NULL name. */
239 {NULL,NULL}
240 };
241
242 /*
243 ** Internal helper which returns:
244 **
245 ** If the "format" (CLI: -f) flag is set function returns the same as
246 ** json_wiki_get_content_format_flag(), else it returns true (non-0)
247 ** if either the includeContent (HTTP) or -content|-c boolean flags
248 ** (CLI) are set.
249 */
250 static char json_artifact_get_content_format_flag(){
251 enum { MagicValue = -9 };
252 char contentFormat = json_wiki_get_content_format_flag(MagicValue);
253 if(MagicValue == contentFormat){
254 contentFormat = json_find_option_bool("includeContent","content","c",0) /* deprecated */ ? -1 : 0;
255 }
256 return contentFormat;
257 }
258
259 extern char json_wiki_get_content_format_flag( char defaultValue ) /* json_wiki.c */;
260
261 cson_value * json_artifact_wiki(cson_object * zParent, int rid){
262 if( ! g.perm.RdWiki ){
263 json_set_err(FSL_JSON_E_DENIED,
264 "Requires 'j' privileges.");
265 return NULL;
266 }else{
267 enum { MagicValue = -9 };
268 char const contentFormat = json_artifact_get_content_format_flag();
 
 
269 return json_get_wiki_page_by_rid(rid, contentFormat);
270 }
271 }
272
273 /*
@@ -266,48 +285,83 @@
285 : (isDel
286 ? "removed"
287 : "modified");
288 }
289
290 cson_value * json_artifact_file(cson_object * zParent, int rid){
291 cson_object * pay = NULL;
292 Stmt q = empty_Stmt;
293 cson_array * checkin_arr = NULL;
294 char contentFormat;
295 i64 contentSize = -1;
296 char * parentUuid;
297 if( ! g.perm.Read ){
298 json_set_err(FSL_JSON_E_DENIED,
299 "Requires 'o' privileges.");
300 return NULL;
301 }
302
303 pay = zParent;
304
305 contentFormat = json_artifact_get_content_format_flag();
306 if( 0 != contentFormat ){
307 Blob content = empty_blob;
308 const char *zMime;
309 char const * zFormat = (contentFormat<1) ? "raw" : "html";
310 content_get(rid, &content);
311 zMime = mimetype_from_content(&content);
312 cson_object_set(zParent, "contentType",
313 json_new_string(zMime ? zMime : "text/plain"));
314 if(!zMime){/* text/plain */
315 if(0 < blob_size(&content)){
316 if( 0 < contentFormat ){/*HTML-size it*/
317 Blob html = empty_blob;
318 wiki_convert(&content, &html, 0);
319 assert( blob_size(&content) < blob_size(&html) );
320 blob_swap( &html, &content );
321 assert( blob_size(&content) > blob_size(&html) );
322 blob_reset( &html );
323 }/*else as-is*/
324 }
325 cson_object_set(zParent, "content",
326 cson_value_new_string(blob_str(&content),
327 (unsigned int)blob_size(&content)));
328 }/*else binary: ignore*/
329 contentSize = blob_size(&content);
330 cson_object_set(zParent, "contentSize", json_new_int(contentSize) );
331 cson_object_set(zParent, "contentFormat", json_new_string(zFormat) );
332 blob_reset(&content);
333 }
334 contentSize = db_int64(-1, "SELECT size FROM blob WHERE rid=%d", rid);
335 assert( -1 < contentSize );
336 cson_object_set(zParent, "size", json_new_int(contentSize) );
337
338 parentUuid = db_text(NULL,
339 "SELECT DISTINCT p.uuid "
340 "FROM blob p, blob f, mlink m "
341 "WHERE m.pid=p.rid "
342 "AND m.fid=f.rid "
343 "AND f.rid=%d",
344 rid
345 );
346 if(parentUuid){
347 cson_object_set( zParent, "parent", json_new_string(parentUuid) );
348 fossil_free(parentUuid);
349 }
350
351 /* Find checkins associated with this file... */
352 db_prepare(&q,
353 "SELECT filename.name AS name, "
354 " (mlink.pid==0) AS isNew,"
355 " (mlink.fid==0) AS isDel,"
356 " cast(strftime('%%s',event.mtime) as int) AS timestamp,"
357 " coalesce(event.ecomment,event.comment) as comment,"
358 " coalesce(event.euser,event.user) as user,"
359 #if 0
360 " a.size AS size," /* same for all checkins. */
361 #endif
362 " b.uuid as checkin, "
363 #if 0
364 " mlink.mperm as mperm,"
365 #endif
366 " coalesce((SELECT value FROM tagxref"
367 " WHERE tagid=%d AND tagtype>0 AND "
@@ -326,10 +380,11 @@
380 */
381 checkin_arr = cson_new_array();
382 cson_object_set(pay, "checkins", cson_array_value(checkin_arr));
383 while( (SQLITE_ROW==db_step(&q) ) ){
384 cson_object * row = cson_value_get_object(cson_sqlite3_row_to_object(q.pStmt));
385 /* FIXME: move this isNew/isDel stuff into an SQL CASE statement. */
386 char const isNew = cson_value_get_bool(cson_object_get(row,"isNew"));
387 char const isDel = cson_value_get_bool(cson_object_get(row,"isDel"));
388 cson_object_set(row, "isNew", NULL);
389 cson_object_set(row, "isDel", NULL);
390 cson_object_set(row, "state",
@@ -371,10 +426,11 @@
426 goto handle_entry;
427 }
428 }
429 blob_set(&uuid,zName);
430 rc = name_to_uuid(&uuid,-1,"*");
431 /* FIXME: check for a filename if all else fails. */
432 if(1==rc){
433 g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND;
434 goto error;
435 }else if(2==rc){
436 g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID;
@@ -411,32 +467,36 @@
467 error:
468 assert( 0 != g.json.resultCode );
469 goto veryend;
470
471 handle_entry:
472 pay = cson_new_object();
473 assert( (NULL != zType) && "Internal dispatching error." );
474 for( ; dispatcher->name; ++dispatcher ){
475 if(0!=strcmp(dispatcher->name, zType)){
476 continue;
477 }else{
478 entry = (*dispatcher->func)(pay, rid);
479 break;
480 }
481 }
482 if(!g.json.resultCode){
483 assert( NULL != entry );
484 assert( NULL != zType );
 
485 cson_object_set( pay, "type", json_new_string(zType) );
486 cson_object_set( pay, "uuid", json_new_string(zUuid) );
487 /*cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) );*/
488 /*cson_object_set( pay, "rid", cson_value_new_integer(rid) );*/
489 if(cson_value_is_object(entry) && (cson_value_get_object(entry) != pay)){
490 cson_object_set(pay, "artifact", entry);
491 }
492 }
493 veryend:
494 blob_reset(&uuid);
495 if(g.json.resultCode && pay){
496 cson_free_object(pay);
497 pay = NULL;
498 }
499 return cson_object_value(pay);
500 }
501
502 #endif /* FOSSIL_ENABLE_JSON */
503
--- src/json_detail.h
+++ src/json_detail.h
@@ -20,15 +20,20 @@
2020
2121
#include "cson_amalgamation.h"
2222
2323
/**
2424
FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest
25
- "significant" change to the JSON API (a change in an interface
26
- or new functionality). It is sent as part of the /json/version
27
- request. We could arguably add it to each response.
25
+ "significant" change to the JSON API (a change in an interface or
26
+ new functionality). It is sent as part of the /json/version
27
+ request. We could arguably add it to each response or even add a
28
+ version number to each response type, allowing very fine (too
29
+ fine?) granularity in compatibility change notification. The
30
+ version number could be included in part of the command dispatching
31
+ framework, allowing the top-level dispatching code to deal with it
32
+ (for the most part).
2833
*/
29
-#define FOSSIL_JSON_API_VERSION "20120409"
34
+#define FOSSIL_JSON_API_VERSION "20120713"
3035
3136
/*
3237
** Impl details for the JSON API which need to be shared
3338
** across multiple C files.
3439
*/
@@ -251,8 +256,11 @@
251256
** difference in argument/parameter handling in many JSON rountines,
252257
** and thus this distinction.
253258
*/
254259
char fossil_has_json();
255260
261
+enum json_get_changed_files_flags {
262
+ json_get_changed_files_ELIDE_PARENT = 1 << 0
263
+};
256264
257265
#endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
258266
#endif /* FOSSIL_ENABLE_JSON */
259267
--- src/json_detail.h
+++ src/json_detail.h
@@ -20,15 +20,20 @@
20
21 #include "cson_amalgamation.h"
22
23 /**
24 FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest
25 "significant" change to the JSON API (a change in an interface
26 or new functionality). It is sent as part of the /json/version
27 request. We could arguably add it to each response.
 
 
 
 
 
28 */
29 #define FOSSIL_JSON_API_VERSION "20120409"
30
31 /*
32 ** Impl details for the JSON API which need to be shared
33 ** across multiple C files.
34 */
@@ -251,8 +256,11 @@
251 ** difference in argument/parameter handling in many JSON rountines,
252 ** and thus this distinction.
253 */
254 char fossil_has_json();
255
 
 
 
256
257 #endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
258 #endif /* FOSSIL_ENABLE_JSON */
259
--- src/json_detail.h
+++ src/json_detail.h
@@ -20,15 +20,20 @@
20
21 #include "cson_amalgamation.h"
22
23 /**
24 FOSSIL_JSON_API_VERSION holds the date (YYYYMMDD) of the latest
25 "significant" change to the JSON API (a change in an interface or
26 new functionality). It is sent as part of the /json/version
27 request. We could arguably add it to each response or even add a
28 version number to each response type, allowing very fine (too
29 fine?) granularity in compatibility change notification. The
30 version number could be included in part of the command dispatching
31 framework, allowing the top-level dispatching code to deal with it
32 (for the most part).
33 */
34 #define FOSSIL_JSON_API_VERSION "20120713"
35
36 /*
37 ** Impl details for the JSON API which need to be shared
38 ** across multiple C files.
39 */
@@ -251,8 +256,11 @@
256 ** difference in argument/parameter handling in many JSON rountines,
257 ** and thus this distinction.
258 */
259 char fossil_has_json();
260
261 enum json_get_changed_files_flags {
262 json_get_changed_files_ELIDE_PARENT = 1 << 0
263 };
264
265 #endif/*FOSSIL_JSON_DETAIL_H_INCLUDED*/
266 #endif /* FOSSIL_ENABLE_JSON */
267
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -280,17 +280,21 @@
280280
if(pPayload){
281281
cson_object_set(pPayload, "limit", json_new_int(limit));
282282
}
283283
return 0;
284284
}
285
+
285286
286287
/*
287288
** If any files are associated with the given rid, a JSON array
288289
** containing information about them is returned (and is owned by the
289290
** caller). If no files are associated with it then NULL is returned.
291
+**
292
+** flags may optionally be a bitmask of json_get_changed_files flags,
293
+** or 0 for defaults.
290294
*/
291
-cson_value * json_get_changed_files(int rid){
295
+cson_value * json_get_changed_files(int rid, int flags){
292296
cson_value * rowsV = NULL;
293297
cson_array * rows = NULL;
294298
Stmt q = empty_Stmt;
295299
db_prepare(&q,
296300
"SELECT (pid==0) AS isnew,"
@@ -316,11 +320,11 @@
316320
rows = cson_value_get_array(rowsV);
317321
}
318322
cson_array_append( rows, rowV );
319323
cson_object_set(row, "name", json_new_string(db_column_text(&q,2)));
320324
cson_object_set(row, "uuid", json_new_string(db_column_text(&q,3)));
321
- if(!isNew){
325
+ if(!isNew && (flags & json_get_changed_files_ELIDE_PARENT)){
322326
cson_object_set(row, "parent", json_new_string(db_column_text(&q,4)));
323327
}
324328
cson_object_set(row, "size", json_new_int(db_column_int(&q,5)));
325329
326330
cson_object_set(row, "state",
327331
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -280,17 +280,21 @@
280 if(pPayload){
281 cson_object_set(pPayload, "limit", json_new_int(limit));
282 }
283 return 0;
284 }
 
285
286 /*
287 ** If any files are associated with the given rid, a JSON array
288 ** containing information about them is returned (and is owned by the
289 ** caller). If no files are associated with it then NULL is returned.
 
 
 
290 */
291 cson_value * json_get_changed_files(int rid){
292 cson_value * rowsV = NULL;
293 cson_array * rows = NULL;
294 Stmt q = empty_Stmt;
295 db_prepare(&q,
296 "SELECT (pid==0) AS isnew,"
@@ -316,11 +320,11 @@
316 rows = cson_value_get_array(rowsV);
317 }
318 cson_array_append( rows, rowV );
319 cson_object_set(row, "name", json_new_string(db_column_text(&q,2)));
320 cson_object_set(row, "uuid", json_new_string(db_column_text(&q,3)));
321 if(!isNew){
322 cson_object_set(row, "parent", json_new_string(db_column_text(&q,4)));
323 }
324 cson_object_set(row, "size", json_new_int(db_column_int(&q,5)));
325
326 cson_object_set(row, "state",
327
--- src/json_timeline.c
+++ src/json_timeline.c
@@ -280,17 +280,21 @@
280 if(pPayload){
281 cson_object_set(pPayload, "limit", json_new_int(limit));
282 }
283 return 0;
284 }
285
286
287 /*
288 ** If any files are associated with the given rid, a JSON array
289 ** containing information about them is returned (and is owned by the
290 ** caller). If no files are associated with it then NULL is returned.
291 **
292 ** flags may optionally be a bitmask of json_get_changed_files flags,
293 ** or 0 for defaults.
294 */
295 cson_value * json_get_changed_files(int rid, int flags){
296 cson_value * rowsV = NULL;
297 cson_array * rows = NULL;
298 Stmt q = empty_Stmt;
299 db_prepare(&q,
300 "SELECT (pid==0) AS isnew,"
@@ -316,11 +320,11 @@
320 rows = cson_value_get_array(rowsV);
321 }
322 cson_array_append( rows, rowV );
323 cson_object_set(row, "name", json_new_string(db_column_text(&q,2)));
324 cson_object_set(row, "uuid", json_new_string(db_column_text(&q,3)));
325 if(!isNew && (flags & json_get_changed_files_ELIDE_PARENT)){
326 cson_object_set(row, "parent", json_new_string(db_column_text(&q,4)));
327 }
328 cson_object_set(row, "size", json_new_int(db_column_int(&q,5)));
329
330 cson_object_set(row, "state",
331

Keyboard Shortcuts

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