Fossil SCM

Add the whatis() SQL function, available for debugging.

drh 2026-05-27 16:33 UTC trunk
Commit 9d503225e13cf15162ff1ac92102997b11afceda648e9146f65e4911abc5a9f8
+1 -1
--- src/bundle.c
+++ src/bundle.c
@@ -660,11 +660,11 @@
660660
int n = 0;
661661
db_prepare(&q,
662662
"SELECT cid FROM plink WHERE pid IN ok AND cid NOT IN ok"
663663
);
664664
while( db_step(&q)==SQLITE_ROW ){
665
- whatis_rid(db_column_int(&q,0),0);
665
+ whatis_rid(db_column_int(&q,0),0,0);
666666
fossil_print("%.78c\n", '-');
667667
n++;
668668
}
669669
db_finalize(&q);
670670
if( n>0 ){
671671
--- src/bundle.c
+++ src/bundle.c
@@ -660,11 +660,11 @@
660 int n = 0;
661 db_prepare(&q,
662 "SELECT cid FROM plink WHERE pid IN ok AND cid NOT IN ok"
663 );
664 while( db_step(&q)==SQLITE_ROW ){
665 whatis_rid(db_column_int(&q,0),0);
666 fossil_print("%.78c\n", '-');
667 n++;
668 }
669 db_finalize(&q);
670 if( n>0 ){
671
--- src/bundle.c
+++ src/bundle.c
@@ -660,11 +660,11 @@
660 int n = 0;
661 db_prepare(&q,
662 "SELECT cid FROM plink WHERE pid IN ok AND cid NOT IN ok"
663 );
664 while( db_step(&q)==SQLITE_ROW ){
665 whatis_rid(db_column_int(&q,0),0,0);
666 fossil_print("%.78c\n", '-');
667 n++;
668 }
669 db_finalize(&q);
670 if( n>0 ){
671
+1 -1
--- src/finfo.c
+++ src/finfo.c
@@ -164,11 +164,11 @@
164164
zRevision, &fname, filename_collation());
165165
if( rid==0 ) {
166166
fossil_fatal("file not found for revision %s: %s",
167167
zRevision, blob_str(&fname));
168168
}
169
- whatis_rid(rid,whatisFlags);
169
+ whatis_rid(rid,whatisFlags,0);
170170
blob_reset(&fname);
171171
}else{
172172
Blob line;
173173
Stmt q;
174174
Blob fname;
175175
--- src/finfo.c
+++ src/finfo.c
@@ -164,11 +164,11 @@
164 zRevision, &fname, filename_collation());
165 if( rid==0 ) {
166 fossil_fatal("file not found for revision %s: %s",
167 zRevision, blob_str(&fname));
168 }
169 whatis_rid(rid,whatisFlags);
170 blob_reset(&fname);
171 }else{
172 Blob line;
173 Stmt q;
174 Blob fname;
175
--- src/finfo.c
+++ src/finfo.c
@@ -164,11 +164,11 @@
164 zRevision, &fname, filename_collation());
165 if( rid==0 ) {
166 fossil_fatal("file not found for revision %s: %s",
167 zRevision, blob_str(&fname));
168 }
169 whatis_rid(rid,whatisFlags,0);
170 blob_reset(&fname);
171 }else{
172 Blob line;
173 Stmt q;
174 Blob fname;
175
+201 -56
--- src/name.c
+++ src/name.c
@@ -1143,10 +1143,40 @@
11431143
case CFTYPE_CONTROL: zType = "Tag-change"; break;
11441144
default: break;
11451145
}
11461146
return zType;
11471147
}
1148
+
1149
+/*
1150
+** This is the output routine for whatis_rid(). If pOut is NULL
1151
+** then write zKey and zValue on fossil_print(). But if pOut is
1152
+** not NULL, append the key and value as a term of a JSON object.
1153
+*/
1154
+static void whatis_line(
1155
+ sqlite3_str *pOut,
1156
+ const char *zKey,
1157
+ const char *zValue,
1158
+ ...
1159
+){
1160
+ char *zArg;
1161
+ va_list ap;
1162
+ va_start(ap, zValue);
1163
+ zArg = sqlite3_vmprintf(zValue,ap);
1164
+ va_end(ap);
1165
+ if( pOut ){
1166
+ int n = sqlite3_str_length(pOut);
1167
+ if( n>1 && sqlite3_str_value(pOut)[n-1]!='{' ){
1168
+ sqlite3_str_append(pOut, ",", 1);
1169
+ }
1170
+ sqlite3_str_appendf(pOut, "%J:%J", zKey, zArg);
1171
+ }else{
1172
+ int n = 11 - (int)strlen(zKey);
1173
+ if( n<=0 ) n = 0;
1174
+ fossil_print("%s:%*s%s\n",zKey,n,"",zArg);
1175
+ }
1176
+ sqlite3_free(zArg);
1177
+}
11481178
11491179
/*
11501180
** Flag values for whatis_rid().
11511181
*/
11521182
#if INTERFACE
@@ -1153,18 +1183,25 @@
11531183
#define WHATIS_VERBOSE 0x01 /* Extra output */
11541184
#define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
11551185
#define WHATIS_REPO 0x04 /* Show repository name */
11561186
#define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
11571187
#define WHATIS_HASHONLY 0x10 /* Show only the hash */
1188
+#define WHATIS_JSON 0x20 /* Render as JSON */
11581189
#endif
11591190
11601191
/*
1161
-** Generate a description of artifact "rid"
1192
+** Generate a description of artifact "rid".
1193
+**
1194
+** Send results to stdout using fossil_print() if pOut==0 or if
1195
+** WHATIS_HASHONLY is set. But without WHATIS_HASHONLY and if
1196
+** pOut!=0, then write a JSON description of the object into pOut.
11621197
*/
1163
-void whatis_rid(int rid, int flags){
1198
+void whatis_rid(int rid, int flags, sqlite3_str *pOut){
11641199
Stmt q;
11651200
int cnt;
1201
+
1202
+ if( pOut ) sqlite3_str_appendf(pOut, "{\"rid\":%d", rid);
11661203
11671204
/* Basic information about the object. */
11681205
db_prepare(&q,
11691206
"SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
11701207
" FROM blob, rcvfrom"
@@ -1173,19 +1210,21 @@
11731210
rid);
11741211
if( db_step(&q)==SQLITE_ROW ){
11751212
if( flags & WHATIS_HASHONLY ){
11761213
fossil_print("%s\n", db_column_text(&q,0));
11771214
}else if( flags & WHATIS_VERBOSE ){
1178
- fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
1179
- fossil_print("size: %d bytes\n", db_column_int(&q,1));
1180
- fossil_print("received: %s from %s\n",
1215
+ whatis_line(pOut, "artifact", "%s (%d)", db_column_text(&q,0), rid);
1216
+ whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
1217
+ whatis_line(pOut, "received", "%s from %s",
11811218
db_column_text(&q, 2),
11821219
db_column_text(&q, 3));
11831220
}else{
1184
- fossil_print("artifact: %s\n", db_column_text(&q,0));
1185
- fossil_print("size: %d bytes\n", db_column_int(&q,1));
1221
+ whatis_line(pOut, "artifact","%s", db_column_text(&q,0));
1222
+ whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
11861223
}
1224
+ }else if( pOut ){
1225
+ sqlite3_str_appendf(pOut, ",\"artifact\":null");
11871226
}
11881227
db_finalize(&q);
11891228
if( flags & WHATIS_HASHONLY ) return;
11901229
11911230
/* Report any symbolic tags on this artifact */
@@ -1198,14 +1237,27 @@
11981237
" ORDER BY 1",
11991238
rid
12001239
);
12011240
cnt = 0;
12021241
while( db_step(&q)==SQLITE_ROW ){
1203
- const char *zPrefix = cnt++ ? ", " : "tags: ";
1204
- fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1242
+ const char *zTag = (const char*)db_column_text(&q,0);
1243
+ if( pOut ){
1244
+ const char *zSep = cnt==0 ? ",tags:[" : ",";
1245
+ sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1246
+ }else{
1247
+ const char *zPrefix = cnt ? ", " : "tags: ";
1248
+ fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1249
+ }
1250
+ cnt++;
12051251
}
1206
- if( cnt ) fossil_print("\n");
1252
+ if( cnt ){
1253
+ if( pOut ){
1254
+ sqlite3_str_append(pOut, "]", 1);
1255
+ }else{
1256
+ fossil_print("\n");
1257
+ }
1258
+ }
12071259
db_finalize(&q);
12081260
12091261
/* Report any HIDDEN, PRIVATE, CLUSTER, or CLOSED tags on this artifact */
12101262
db_prepare(&q,
12111263
"SELECT tagname"
@@ -1215,14 +1267,27 @@
12151267
" ORDER BY 1",
12161268
rid
12171269
);
12181270
cnt = 0;
12191271
while( db_step(&q)==SQLITE_ROW ){
1220
- const char *zPrefix = cnt++ ? ", " : "raw-tags: ";
1221
- fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1272
+ const char *zTag = (const char*)db_column_text(&q,0);
1273
+ if( pOut ){
1274
+ const char *zSep = cnt==0 ? ",\"raw-tags\":[" : ",";
1275
+ sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1276
+ }else{
1277
+ const char *zPrefix = cnt ? ", " : "raw-tags: ";
1278
+ fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1279
+ }
1280
+ cnt++;
12221281
}
1223
- if( cnt ) fossil_print("\n");
1282
+ if( cnt ){
1283
+ if( pOut ){
1284
+ sqlite3_str_append(pOut, "]", 1);
1285
+ }else{
1286
+ fossil_print("\n");
1287
+ }
1288
+ }
12241289
db_finalize(&q);
12251290
12261291
/* Check for entries on the timeline that reference this object */
12271292
db_prepare(&q,
12281293
"SELECT"
@@ -1244,17 +1309,21 @@
12441309
case 'f': zType = "Forum-post"; break;
12451310
case 't': zType = "Ticket-change"; break;
12461311
case 'g': zType = "Tag-change"; break;
12471312
default: zType = "Unknown"; break;
12481313
}
1249
- fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
1314
+ whatis_line(pOut, "type", "%s by %s on %s", zType, db_column_text(&q,2),
12501315
db_column_text(&q, 1));
12511316
if( eType=='t' && db_column_type(&q,4)==SQLITE_TEXT ){
1252
- fossil_print("ticket-id: %s\n", db_column_text(&q,4));
1317
+ whatis_line(pOut, "ticket-id", "%s", db_column_text(&q,4));
12531318
}
1254
- fossil_print("comment: ");
1255
- comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
1319
+ if( pOut ){
1320
+ sqlite3_str_appendf(pOut, ",\"comment\":%J", db_column_text(&q,3));
1321
+ }else{
1322
+ fossil_print("comment: ");
1323
+ comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
1324
+ }
12561325
cnt++;
12571326
}
12581327
db_finalize(&q);
12591328
12601329
/* Check to see if this object is used as a file in a check-in */
@@ -1271,20 +1340,25 @@
12711340
" ORDER BY event.mtime %s /*sort*/",
12721341
TAG_BRANCH, rid,
12731342
(flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
12741343
while( db_step(&q)==SQLITE_ROW ){
12751344
if( flags & WHATIS_BRIEF ){
1276
- fossil_print("mtime: %s\n", db_column_text(&q,2));
1277
- }
1278
- fossil_print("file: %s\n", db_column_text(&q,0));
1279
- fossil_print(" part of [%S] on branch %s by %s on %s\n",
1280
- db_column_text(&q, 1),
1281
- db_column_text(&q, 5),
1282
- db_column_text(&q, 3),
1283
- db_column_text(&q, 2));
1284
- fossil_print(" ");
1285
- comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
1345
+ whatis_line(pOut, "mtime","%s", db_column_text(&q,2));
1346
+ }
1347
+ if( pOut ){
1348
+ whatis_line(pOut,"file","%s", db_column_text(&q,0));
1349
+ whatis_line(pOut,"part-of","%s", db_column_text(&q,1));
1350
+ }else{
1351
+ fossil_print("file: %s\n", db_column_text(&q,0));
1352
+ fossil_print(" part of [%S] on branch %s by %s on %s\n",
1353
+ db_column_text(&q, 1),
1354
+ db_column_text(&q, 5),
1355
+ db_column_text(&q, 3),
1356
+ db_column_text(&q, 2));
1357
+ fossil_print(" ");
1358
+ comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
1359
+ }
12861360
cnt++;
12871361
}
12881362
db_finalize(&q);
12891363
12901364
/* Check to see if this object is used as an attachment */
@@ -1303,30 +1377,36 @@
13031377
" FROM attachment JOIN blob ON attachment.src=blob.uuid"
13041378
" WHERE blob.rid=%d",
13051379
rid
13061380
);
13071381
while( db_step(&q)==SQLITE_ROW ){
1308
- fossil_print("attachment: %s\n", db_column_text(&q,0));
1309
- fossil_print(" attached to %s %s\n",
1310
- db_column_text(&q,5), db_column_text(&q,4));
1311
- if( flags & WHATIS_VERBOSE ){
1312
- fossil_print(" via %s (%d)\n",
1313
- db_column_text(&q,7), db_column_int(&q,6));
1382
+ if( pOut ){
1383
+ whatis_line(pOut, "attachment", "%s", db_column_text(&q,0));
1384
+ whatis_line(pOut, "attached-to", "%s %s",
1385
+ db_column_text(&q,5), db_column_text(&q,4));
13141386
}else{
1315
- fossil_print(" via %s\n",
1316
- db_column_text(&q,7));
1387
+ fossil_print("attachment: %s\n", db_column_text(&q,0));
1388
+ fossil_print(" attached to %s %s\n",
1389
+ db_column_text(&q,5), db_column_text(&q,4));
1390
+ if( flags & WHATIS_VERBOSE ){
1391
+ fossil_print(" via %s (%d)\n",
1392
+ db_column_text(&q,7), db_column_int(&q,6));
1393
+ }else{
1394
+ fossil_print(" via %s\n",
1395
+ db_column_text(&q,7));
1396
+ }
1397
+ fossil_print(" by user %s on %s\n",
1398
+ db_column_text(&q,2), db_column_text(&q,3));
1399
+ fossil_print(" ");
1400
+ comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
13171401
}
1318
- fossil_print(" by user %s on %s\n",
1319
- db_column_text(&q,2), db_column_text(&q,3));
1320
- fossil_print(" ");
1321
- comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
13221402
cnt++;
13231403
}
13241404
db_finalize(&q);
13251405
13261406
/* If other information available, try to describe the object */
1327
- if( cnt==0 ){
1407
+ if( cnt==0 && pOut==0 ){
13281408
char *zWhere = mprintf("=%d", rid);
13291409
char *zDesc;
13301410
describe_artifacts(zWhere);
13311411
free(zWhere);
13321412
zDesc = db_text(0,
@@ -1333,25 +1413,33 @@
13331413
"SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
13341414
" FROM description WHERE rid=%d", rid);
13351415
fossil_print("%s\n", zDesc);
13361416
fossil_free(zDesc);
13371417
}
1418
+
1419
+ if( pOut ) sqlite3_str_append(pOut, "}", 1);
13381420
}
13391421
13401422
/*
13411423
** Generate a description of artifact from it symbolic name.
13421424
*/
13431425
void whatis_artifact(
1344
- const char *zName, /* Symbolic name or full hash */
1345
- const char *zFileName,/* Optional: original filename (in file mode) */
1346
- const char *zType, /* Artifact type filter */
1347
- int mFlags /* WHATIS_* flags */
1426
+ const char *zName, /* Symbolic name or full hash */
1427
+ const char *zFileName,/* Optional: original filename (in file mode) */
1428
+ const char *zType, /* Artifact type filter */
1429
+ int mFlags, /* WHATIS_* flags */
1430
+ sqlite3_str *pOut /* Write JSON here, if not NULL */
13481431
){
13491432
int rid = symbolic_name_to_rid(zName, zType);
13501433
size_t nName;
13511434
char *zC = 0;
13521435
int nTkt = 0;
1436
+
1437
+ if( pOut ){
1438
+ mFlags &= ~(WHATIS_HASHONLY|WHATIS_REPO);
1439
+ zFileName = 0;
1440
+ }
13531441
if( (nName = strlen(zName))>=4 && validate16(zName,nName) ){
13541442
zC = fossil_strdup(zName);
13551443
canonical16(zC, nName);
13561444
nTkt = db_int(0,"SELECT count(*) FROM tag WHERE tagname GLOB 'tkt-%q*'",zC);
13571445
if( nTkt>0 ){
@@ -1376,18 +1464,28 @@
13761464
fossil_print("\nrepository: %s\n", g.zRepositoryName);
13771465
}
13781466
if( zFileName ){
13791467
fossil_print("%-12s%s\n", "name:", zFileName);
13801468
}
1381
- fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
1469
+ if( pOut ){
1470
+ sqlite3_str_appendall(pOut, "{\"ambiguous\":[");
1471
+ }else{
1472
+ fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
1473
+ }
13821474
db_prepare(&q,
13831475
"SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
13841476
zName, zName
13851477
);
13861478
while( db_step(&q)==SQLITE_ROW ){
1387
- if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1388
- whatis_rid(db_column_int(&q, 0), mFlags);
1479
+ if( cnt++ ){
1480
+ if( pOut ){
1481
+ sqlite3_str_append(pOut, ",", 1);
1482
+ }else{
1483
+ fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1484
+ }
1485
+ }
1486
+ whatis_rid(db_column_int(&q, 0), mFlags, pOut);
13891487
}
13901488
db_finalize(&q);
13911489
if( nTkt>0 ){
13921490
db_prepare(&q,
13931491
"SELECT (SELECT srcid FROM tagxref"
@@ -1396,34 +1494,41 @@
13961494
" ORDER BY mtime LIMIT 1)"
13971495
" FROM tag WHERE tagname GLOB 'tkt-%q*'",
13981496
zC
13991497
);
14001498
while( db_step(&q)==SQLITE_ROW ){
1401
- if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1402
- whatis_rid(db_column_int(&q, 0), mFlags);
1499
+ if( pOut ){
1500
+ sqlite3_str_append(pOut, ",", 1);
1501
+ }else{
1502
+ fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1503
+ }
1504
+ whatis_rid(db_column_int(&q, 0), mFlags, pOut);
14031505
}
14041506
db_finalize(&q);
14051507
}
1508
+ if( pOut ) sqlite3_str_append(pOut, "]}", 2);
14061509
}else if( rid==0 ){
14071510
if( (mFlags & (WHATIS_OMIT_UNK|WHATIS_HASHONLY))==0 ){
14081511
/* 0123456789 12 */
14091512
if( zFileName ){
14101513
fossil_print("%-12s%s\n", "name:", zFileName);
14111514
}
1412
- fossil_print("unknown: %s\n", zName);
1515
+ if( pOut ) sqlite3_str_append(pOut, "{", 1);
1516
+ whatis_line(pOut, "unknown", "%s", zName);
1517
+ if( pOut ) sqlite3_str_append(pOut, "}", 1);
14131518
}
14141519
}else{
14151520
if( mFlags & WHATIS_REPO ){
14161521
fossil_print("\nrepository: %s\n", g.zRepositoryName);
14171522
}
14181523
if( zFileName ){
14191524
zName = zFileName;
14201525
}
1421
- if( (mFlags & WHATIS_HASHONLY)==0 ){
1422
- fossil_print("%-12s%s\n", "name:", zName);
1526
+ if( (mFlags & WHATIS_HASHONLY)==0 && pOut==0 ){
1527
+ whatis_line(pOut, "name", "%s", zName);
14231528
}
1424
- whatis_rid(rid, mFlags);
1529
+ whatis_rid(rid, mFlags, pOut);
14251530
}
14261531
fossil_free(zC);
14271532
}
14281533
14291534
/*
@@ -1449,10 +1554,11 @@
14491554
void whatis_cmd(void){
14501555
int mFlags = 0;
14511556
int fileFlag;
14521557
int i;
14531558
const char *zType = 0;
1559
+ sqlite3_str *pOut = 0;
14541560
db_find_and_open_repository(0,0);
14551561
if( find_option("verbose","v",0)!=0 ){
14561562
mFlags |= WHATIS_VERBOSE;
14571563
}
14581564
if( find_option("hash","h",0)!=0 ){
@@ -1461,10 +1567,14 @@
14611567
if( g.fQuiet ){
14621568
mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
14631569
}
14641570
fileFlag = find_option("file","f",0)!=0;
14651571
zType = find_option("type",0,1);
1572
+
1573
+ if( find_option("json",0,0)!=0 ){ /* undocumented test option */
1574
+ pOut = sqlite3_str_new(0);
1575
+ }
14661576
14671577
/* We should be done with options.. */
14681578
verify_all_options();
14691579
14701580
if( g.argc<3 ) usage("NAME ...");
@@ -1487,17 +1597,52 @@
14871597
** the primary hash name. */
14881598
blob_reset(&hash);
14891599
hname_hash(&in, 0, &hash);
14901600
zHash = (const char*)blob_str(&hash);
14911601
}
1492
- whatis_artifact(zHash, zName, zType, mFlags);
1602
+ whatis_artifact(zHash, zName, zType, mFlags, pOut);
14931603
blob_reset(&hash);
14941604
}else{
1495
- whatis_artifact(zName, 0, zType, mFlags);
1605
+ whatis_artifact(zName, 0, zType, mFlags, pOut);
1606
+ }
1607
+ if( pOut ){
1608
+ fossil_print("%s\n", sqlite3_str_value(pOut));
1609
+ sqlite3_str_truncate(pOut, 0);
14961610
}
14971611
}
1612
+ if( pOut ) sqlite3_str_free(pOut);
1613
+}
1614
+
1615
+/*
1616
+** This is an SQL function that does the rough equivalent of the
1617
+** "whatis" command. The argument can be a text identifier, or a
1618
+** integer RID.
1619
+*/
1620
+void whatis_sql_function(
1621
+ sqlite3_context *context,
1622
+ int argc,
1623
+ sqlite3_value **argv
1624
+){
1625
+ sqlite3_str *pOut = sqlite3_str_new(0);
1626
+ int n;
1627
+ assert( argc==1 );
1628
+ if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
1629
+ int rid = sqlite3_value_int(argv[0]);
1630
+ whatis_rid(rid, 0, pOut);
1631
+ }else if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
1632
+ const char *zName = (const char*)sqlite3_value_text(argv[0]);
1633
+ whatis_artifact(zName, 0, 0, 0, pOut);
1634
+ }else{
1635
+ sqlite3_str_free(pOut);
1636
+ return;
1637
+ }
1638
+ n = sqlite3_str_length(pOut);
1639
+ sqlite3_result_text64(context, sqlite3_str_finish(pOut), n,
1640
+ sqlite3_free, SQLITE_UTF8);
1641
+ sqlite3_result_subtype(context, 'J');
14981642
}
1643
+
14991644
15001645
/*
15011646
** COMMAND: test-whatis-all
15021647
**
15031648
** Usage: %fossil test-whatis-all
@@ -1509,11 +1654,11 @@
15091654
int cnt = 0;
15101655
db_find_and_open_repository(0,0);
15111656
db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
15121657
while( db_step(&q)==SQLITE_ROW ){
15131658
if( cnt++ ) fossil_print("%.79c\n", '-');
1514
- whatis_rid(db_column_int(&q,0), 1);
1659
+ whatis_rid(db_column_int(&q,0), 1, 0);
15151660
}
15161661
db_finalize(&q);
15171662
}
15181663
15191664
15201665
--- src/name.c
+++ src/name.c
@@ -1143,10 +1143,40 @@
1143 case CFTYPE_CONTROL: zType = "Tag-change"; break;
1144 default: break;
1145 }
1146 return zType;
1147 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1148
1149 /*
1150 ** Flag values for whatis_rid().
1151 */
1152 #if INTERFACE
@@ -1153,18 +1183,25 @@
1153 #define WHATIS_VERBOSE 0x01 /* Extra output */
1154 #define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
1155 #define WHATIS_REPO 0x04 /* Show repository name */
1156 #define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
1157 #define WHATIS_HASHONLY 0x10 /* Show only the hash */
 
1158 #endif
1159
1160 /*
1161 ** Generate a description of artifact "rid"
 
 
 
 
1162 */
1163 void whatis_rid(int rid, int flags){
1164 Stmt q;
1165 int cnt;
 
 
1166
1167 /* Basic information about the object. */
1168 db_prepare(&q,
1169 "SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
1170 " FROM blob, rcvfrom"
@@ -1173,19 +1210,21 @@
1173 rid);
1174 if( db_step(&q)==SQLITE_ROW ){
1175 if( flags & WHATIS_HASHONLY ){
1176 fossil_print("%s\n", db_column_text(&q,0));
1177 }else if( flags & WHATIS_VERBOSE ){
1178 fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
1179 fossil_print("size: %d bytes\n", db_column_int(&q,1));
1180 fossil_print("received: %s from %s\n",
1181 db_column_text(&q, 2),
1182 db_column_text(&q, 3));
1183 }else{
1184 fossil_print("artifact: %s\n", db_column_text(&q,0));
1185 fossil_print("size: %d bytes\n", db_column_int(&q,1));
1186 }
 
 
1187 }
1188 db_finalize(&q);
1189 if( flags & WHATIS_HASHONLY ) return;
1190
1191 /* Report any symbolic tags on this artifact */
@@ -1198,14 +1237,27 @@
1198 " ORDER BY 1",
1199 rid
1200 );
1201 cnt = 0;
1202 while( db_step(&q)==SQLITE_ROW ){
1203 const char *zPrefix = cnt++ ? ", " : "tags: ";
1204 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
 
 
 
 
 
 
 
1205 }
1206 if( cnt ) fossil_print("\n");
 
 
 
 
 
 
1207 db_finalize(&q);
1208
1209 /* Report any HIDDEN, PRIVATE, CLUSTER, or CLOSED tags on this artifact */
1210 db_prepare(&q,
1211 "SELECT tagname"
@@ -1215,14 +1267,27 @@
1215 " ORDER BY 1",
1216 rid
1217 );
1218 cnt = 0;
1219 while( db_step(&q)==SQLITE_ROW ){
1220 const char *zPrefix = cnt++ ? ", " : "raw-tags: ";
1221 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
 
 
 
 
 
 
 
1222 }
1223 if( cnt ) fossil_print("\n");
 
 
 
 
 
 
1224 db_finalize(&q);
1225
1226 /* Check for entries on the timeline that reference this object */
1227 db_prepare(&q,
1228 "SELECT"
@@ -1244,17 +1309,21 @@
1244 case 'f': zType = "Forum-post"; break;
1245 case 't': zType = "Ticket-change"; break;
1246 case 'g': zType = "Tag-change"; break;
1247 default: zType = "Unknown"; break;
1248 }
1249 fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
1250 db_column_text(&q, 1));
1251 if( eType=='t' && db_column_type(&q,4)==SQLITE_TEXT ){
1252 fossil_print("ticket-id: %s\n", db_column_text(&q,4));
1253 }
1254 fossil_print("comment: ");
1255 comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
 
 
 
 
1256 cnt++;
1257 }
1258 db_finalize(&q);
1259
1260 /* Check to see if this object is used as a file in a check-in */
@@ -1271,20 +1340,25 @@
1271 " ORDER BY event.mtime %s /*sort*/",
1272 TAG_BRANCH, rid,
1273 (flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
1274 while( db_step(&q)==SQLITE_ROW ){
1275 if( flags & WHATIS_BRIEF ){
1276 fossil_print("mtime: %s\n", db_column_text(&q,2));
1277 }
1278 fossil_print("file: %s\n", db_column_text(&q,0));
1279 fossil_print(" part of [%S] on branch %s by %s on %s\n",
1280 db_column_text(&q, 1),
1281 db_column_text(&q, 5),
1282 db_column_text(&q, 3),
1283 db_column_text(&q, 2));
1284 fossil_print(" ");
1285 comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
 
 
 
 
 
1286 cnt++;
1287 }
1288 db_finalize(&q);
1289
1290 /* Check to see if this object is used as an attachment */
@@ -1303,30 +1377,36 @@
1303 " FROM attachment JOIN blob ON attachment.src=blob.uuid"
1304 " WHERE blob.rid=%d",
1305 rid
1306 );
1307 while( db_step(&q)==SQLITE_ROW ){
1308 fossil_print("attachment: %s\n", db_column_text(&q,0));
1309 fossil_print(" attached to %s %s\n",
1310 db_column_text(&q,5), db_column_text(&q,4));
1311 if( flags & WHATIS_VERBOSE ){
1312 fossil_print(" via %s (%d)\n",
1313 db_column_text(&q,7), db_column_int(&q,6));
1314 }else{
1315 fossil_print(" via %s\n",
1316 db_column_text(&q,7));
 
 
 
 
 
 
 
 
 
 
 
 
1317 }
1318 fossil_print(" by user %s on %s\n",
1319 db_column_text(&q,2), db_column_text(&q,3));
1320 fossil_print(" ");
1321 comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
1322 cnt++;
1323 }
1324 db_finalize(&q);
1325
1326 /* If other information available, try to describe the object */
1327 if( cnt==0 ){
1328 char *zWhere = mprintf("=%d", rid);
1329 char *zDesc;
1330 describe_artifacts(zWhere);
1331 free(zWhere);
1332 zDesc = db_text(0,
@@ -1333,25 +1413,33 @@
1333 "SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
1334 " FROM description WHERE rid=%d", rid);
1335 fossil_print("%s\n", zDesc);
1336 fossil_free(zDesc);
1337 }
 
 
1338 }
1339
1340 /*
1341 ** Generate a description of artifact from it symbolic name.
1342 */
1343 void whatis_artifact(
1344 const char *zName, /* Symbolic name or full hash */
1345 const char *zFileName,/* Optional: original filename (in file mode) */
1346 const char *zType, /* Artifact type filter */
1347 int mFlags /* WHATIS_* flags */
 
1348 ){
1349 int rid = symbolic_name_to_rid(zName, zType);
1350 size_t nName;
1351 char *zC = 0;
1352 int nTkt = 0;
 
 
 
 
 
1353 if( (nName = strlen(zName))>=4 && validate16(zName,nName) ){
1354 zC = fossil_strdup(zName);
1355 canonical16(zC, nName);
1356 nTkt = db_int(0,"SELECT count(*) FROM tag WHERE tagname GLOB 'tkt-%q*'",zC);
1357 if( nTkt>0 ){
@@ -1376,18 +1464,28 @@
1376 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1377 }
1378 if( zFileName ){
1379 fossil_print("%-12s%s\n", "name:", zFileName);
1380 }
1381 fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
 
 
 
 
1382 db_prepare(&q,
1383 "SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
1384 zName, zName
1385 );
1386 while( db_step(&q)==SQLITE_ROW ){
1387 if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1388 whatis_rid(db_column_int(&q, 0), mFlags);
 
 
 
 
 
 
1389 }
1390 db_finalize(&q);
1391 if( nTkt>0 ){
1392 db_prepare(&q,
1393 "SELECT (SELECT srcid FROM tagxref"
@@ -1396,34 +1494,41 @@
1396 " ORDER BY mtime LIMIT 1)"
1397 " FROM tag WHERE tagname GLOB 'tkt-%q*'",
1398 zC
1399 );
1400 while( db_step(&q)==SQLITE_ROW ){
1401 if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1402 whatis_rid(db_column_int(&q, 0), mFlags);
 
 
 
 
1403 }
1404 db_finalize(&q);
1405 }
 
1406 }else if( rid==0 ){
1407 if( (mFlags & (WHATIS_OMIT_UNK|WHATIS_HASHONLY))==0 ){
1408 /* 0123456789 12 */
1409 if( zFileName ){
1410 fossil_print("%-12s%s\n", "name:", zFileName);
1411 }
1412 fossil_print("unknown: %s\n", zName);
 
 
1413 }
1414 }else{
1415 if( mFlags & WHATIS_REPO ){
1416 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1417 }
1418 if( zFileName ){
1419 zName = zFileName;
1420 }
1421 if( (mFlags & WHATIS_HASHONLY)==0 ){
1422 fossil_print("%-12s%s\n", "name:", zName);
1423 }
1424 whatis_rid(rid, mFlags);
1425 }
1426 fossil_free(zC);
1427 }
1428
1429 /*
@@ -1449,10 +1554,11 @@
1449 void whatis_cmd(void){
1450 int mFlags = 0;
1451 int fileFlag;
1452 int i;
1453 const char *zType = 0;
 
1454 db_find_and_open_repository(0,0);
1455 if( find_option("verbose","v",0)!=0 ){
1456 mFlags |= WHATIS_VERBOSE;
1457 }
1458 if( find_option("hash","h",0)!=0 ){
@@ -1461,10 +1567,14 @@
1461 if( g.fQuiet ){
1462 mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
1463 }
1464 fileFlag = find_option("file","f",0)!=0;
1465 zType = find_option("type",0,1);
 
 
 
 
1466
1467 /* We should be done with options.. */
1468 verify_all_options();
1469
1470 if( g.argc<3 ) usage("NAME ...");
@@ -1487,17 +1597,52 @@
1487 ** the primary hash name. */
1488 blob_reset(&hash);
1489 hname_hash(&in, 0, &hash);
1490 zHash = (const char*)blob_str(&hash);
1491 }
1492 whatis_artifact(zHash, zName, zType, mFlags);
1493 blob_reset(&hash);
1494 }else{
1495 whatis_artifact(zName, 0, zType, mFlags);
 
 
 
 
1496 }
1497 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1498 }
 
1499
1500 /*
1501 ** COMMAND: test-whatis-all
1502 **
1503 ** Usage: %fossil test-whatis-all
@@ -1509,11 +1654,11 @@
1509 int cnt = 0;
1510 db_find_and_open_repository(0,0);
1511 db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
1512 while( db_step(&q)==SQLITE_ROW ){
1513 if( cnt++ ) fossil_print("%.79c\n", '-');
1514 whatis_rid(db_column_int(&q,0), 1);
1515 }
1516 db_finalize(&q);
1517 }
1518
1519
1520
--- src/name.c
+++ src/name.c
@@ -1143,10 +1143,40 @@
1143 case CFTYPE_CONTROL: zType = "Tag-change"; break;
1144 default: break;
1145 }
1146 return zType;
1147 }
1148
1149 /*
1150 ** This is the output routine for whatis_rid(). If pOut is NULL
1151 ** then write zKey and zValue on fossil_print(). But if pOut is
1152 ** not NULL, append the key and value as a term of a JSON object.
1153 */
1154 static void whatis_line(
1155 sqlite3_str *pOut,
1156 const char *zKey,
1157 const char *zValue,
1158 ...
1159 ){
1160 char *zArg;
1161 va_list ap;
1162 va_start(ap, zValue);
1163 zArg = sqlite3_vmprintf(zValue,ap);
1164 va_end(ap);
1165 if( pOut ){
1166 int n = sqlite3_str_length(pOut);
1167 if( n>1 && sqlite3_str_value(pOut)[n-1]!='{' ){
1168 sqlite3_str_append(pOut, ",", 1);
1169 }
1170 sqlite3_str_appendf(pOut, "%J:%J", zKey, zArg);
1171 }else{
1172 int n = 11 - (int)strlen(zKey);
1173 if( n<=0 ) n = 0;
1174 fossil_print("%s:%*s%s\n",zKey,n,"",zArg);
1175 }
1176 sqlite3_free(zArg);
1177 }
1178
1179 /*
1180 ** Flag values for whatis_rid().
1181 */
1182 #if INTERFACE
@@ -1153,18 +1183,25 @@
1183 #define WHATIS_VERBOSE 0x01 /* Extra output */
1184 #define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
1185 #define WHATIS_REPO 0x04 /* Show repository name */
1186 #define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
1187 #define WHATIS_HASHONLY 0x10 /* Show only the hash */
1188 #define WHATIS_JSON 0x20 /* Render as JSON */
1189 #endif
1190
1191 /*
1192 ** Generate a description of artifact "rid".
1193 **
1194 ** Send results to stdout using fossil_print() if pOut==0 or if
1195 ** WHATIS_HASHONLY is set. But without WHATIS_HASHONLY and if
1196 ** pOut!=0, then write a JSON description of the object into pOut.
1197 */
1198 void whatis_rid(int rid, int flags, sqlite3_str *pOut){
1199 Stmt q;
1200 int cnt;
1201
1202 if( pOut ) sqlite3_str_appendf(pOut, "{\"rid\":%d", rid);
1203
1204 /* Basic information about the object. */
1205 db_prepare(&q,
1206 "SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
1207 " FROM blob, rcvfrom"
@@ -1173,19 +1210,21 @@
1210 rid);
1211 if( db_step(&q)==SQLITE_ROW ){
1212 if( flags & WHATIS_HASHONLY ){
1213 fossil_print("%s\n", db_column_text(&q,0));
1214 }else if( flags & WHATIS_VERBOSE ){
1215 whatis_line(pOut, "artifact", "%s (%d)", db_column_text(&q,0), rid);
1216 whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
1217 whatis_line(pOut, "received", "%s from %s",
1218 db_column_text(&q, 2),
1219 db_column_text(&q, 3));
1220 }else{
1221 whatis_line(pOut, "artifact","%s", db_column_text(&q,0));
1222 whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
1223 }
1224 }else if( pOut ){
1225 sqlite3_str_appendf(pOut, ",\"artifact\":null");
1226 }
1227 db_finalize(&q);
1228 if( flags & WHATIS_HASHONLY ) return;
1229
1230 /* Report any symbolic tags on this artifact */
@@ -1198,14 +1237,27 @@
1237 " ORDER BY 1",
1238 rid
1239 );
1240 cnt = 0;
1241 while( db_step(&q)==SQLITE_ROW ){
1242 const char *zTag = (const char*)db_column_text(&q,0);
1243 if( pOut ){
1244 const char *zSep = cnt==0 ? ",tags:[" : ",";
1245 sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1246 }else{
1247 const char *zPrefix = cnt ? ", " : "tags: ";
1248 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1249 }
1250 cnt++;
1251 }
1252 if( cnt ){
1253 if( pOut ){
1254 sqlite3_str_append(pOut, "]", 1);
1255 }else{
1256 fossil_print("\n");
1257 }
1258 }
1259 db_finalize(&q);
1260
1261 /* Report any HIDDEN, PRIVATE, CLUSTER, or CLOSED tags on this artifact */
1262 db_prepare(&q,
1263 "SELECT tagname"
@@ -1215,14 +1267,27 @@
1267 " ORDER BY 1",
1268 rid
1269 );
1270 cnt = 0;
1271 while( db_step(&q)==SQLITE_ROW ){
1272 const char *zTag = (const char*)db_column_text(&q,0);
1273 if( pOut ){
1274 const char *zSep = cnt==0 ? ",\"raw-tags\":[" : ",";
1275 sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1276 }else{
1277 const char *zPrefix = cnt ? ", " : "raw-tags: ";
1278 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1279 }
1280 cnt++;
1281 }
1282 if( cnt ){
1283 if( pOut ){
1284 sqlite3_str_append(pOut, "]", 1);
1285 }else{
1286 fossil_print("\n");
1287 }
1288 }
1289 db_finalize(&q);
1290
1291 /* Check for entries on the timeline that reference this object */
1292 db_prepare(&q,
1293 "SELECT"
@@ -1244,17 +1309,21 @@
1309 case 'f': zType = "Forum-post"; break;
1310 case 't': zType = "Ticket-change"; break;
1311 case 'g': zType = "Tag-change"; break;
1312 default: zType = "Unknown"; break;
1313 }
1314 whatis_line(pOut, "type", "%s by %s on %s", zType, db_column_text(&q,2),
1315 db_column_text(&q, 1));
1316 if( eType=='t' && db_column_type(&q,4)==SQLITE_TEXT ){
1317 whatis_line(pOut, "ticket-id", "%s", db_column_text(&q,4));
1318 }
1319 if( pOut ){
1320 sqlite3_str_appendf(pOut, ",\"comment\":%J", db_column_text(&q,3));
1321 }else{
1322 fossil_print("comment: ");
1323 comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
1324 }
1325 cnt++;
1326 }
1327 db_finalize(&q);
1328
1329 /* Check to see if this object is used as a file in a check-in */
@@ -1271,20 +1340,25 @@
1340 " ORDER BY event.mtime %s /*sort*/",
1341 TAG_BRANCH, rid,
1342 (flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
1343 while( db_step(&q)==SQLITE_ROW ){
1344 if( flags & WHATIS_BRIEF ){
1345 whatis_line(pOut, "mtime","%s", db_column_text(&q,2));
1346 }
1347 if( pOut ){
1348 whatis_line(pOut,"file","%s", db_column_text(&q,0));
1349 whatis_line(pOut,"part-of","%s", db_column_text(&q,1));
1350 }else{
1351 fossil_print("file: %s\n", db_column_text(&q,0));
1352 fossil_print(" part of [%S] on branch %s by %s on %s\n",
1353 db_column_text(&q, 1),
1354 db_column_text(&q, 5),
1355 db_column_text(&q, 3),
1356 db_column_text(&q, 2));
1357 fossil_print(" ");
1358 comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
1359 }
1360 cnt++;
1361 }
1362 db_finalize(&q);
1363
1364 /* Check to see if this object is used as an attachment */
@@ -1303,30 +1377,36 @@
1377 " FROM attachment JOIN blob ON attachment.src=blob.uuid"
1378 " WHERE blob.rid=%d",
1379 rid
1380 );
1381 while( db_step(&q)==SQLITE_ROW ){
1382 if( pOut ){
1383 whatis_line(pOut, "attachment", "%s", db_column_text(&q,0));
1384 whatis_line(pOut, "attached-to", "%s %s",
1385 db_column_text(&q,5), db_column_text(&q,4));
 
 
1386 }else{
1387 fossil_print("attachment: %s\n", db_column_text(&q,0));
1388 fossil_print(" attached to %s %s\n",
1389 db_column_text(&q,5), db_column_text(&q,4));
1390 if( flags & WHATIS_VERBOSE ){
1391 fossil_print(" via %s (%d)\n",
1392 db_column_text(&q,7), db_column_int(&q,6));
1393 }else{
1394 fossil_print(" via %s\n",
1395 db_column_text(&q,7));
1396 }
1397 fossil_print(" by user %s on %s\n",
1398 db_column_text(&q,2), db_column_text(&q,3));
1399 fossil_print(" ");
1400 comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
1401 }
 
 
 
 
1402 cnt++;
1403 }
1404 db_finalize(&q);
1405
1406 /* If other information available, try to describe the object */
1407 if( cnt==0 && pOut==0 ){
1408 char *zWhere = mprintf("=%d", rid);
1409 char *zDesc;
1410 describe_artifacts(zWhere);
1411 free(zWhere);
1412 zDesc = db_text(0,
@@ -1333,25 +1413,33 @@
1413 "SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
1414 " FROM description WHERE rid=%d", rid);
1415 fossil_print("%s\n", zDesc);
1416 fossil_free(zDesc);
1417 }
1418
1419 if( pOut ) sqlite3_str_append(pOut, "}", 1);
1420 }
1421
1422 /*
1423 ** Generate a description of artifact from it symbolic name.
1424 */
1425 void whatis_artifact(
1426 const char *zName, /* Symbolic name or full hash */
1427 const char *zFileName,/* Optional: original filename (in file mode) */
1428 const char *zType, /* Artifact type filter */
1429 int mFlags, /* WHATIS_* flags */
1430 sqlite3_str *pOut /* Write JSON here, if not NULL */
1431 ){
1432 int rid = symbolic_name_to_rid(zName, zType);
1433 size_t nName;
1434 char *zC = 0;
1435 int nTkt = 0;
1436
1437 if( pOut ){
1438 mFlags &= ~(WHATIS_HASHONLY|WHATIS_REPO);
1439 zFileName = 0;
1440 }
1441 if( (nName = strlen(zName))>=4 && validate16(zName,nName) ){
1442 zC = fossil_strdup(zName);
1443 canonical16(zC, nName);
1444 nTkt = db_int(0,"SELECT count(*) FROM tag WHERE tagname GLOB 'tkt-%q*'",zC);
1445 if( nTkt>0 ){
@@ -1376,18 +1464,28 @@
1464 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1465 }
1466 if( zFileName ){
1467 fossil_print("%-12s%s\n", "name:", zFileName);
1468 }
1469 if( pOut ){
1470 sqlite3_str_appendall(pOut, "{\"ambiguous\":[");
1471 }else{
1472 fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
1473 }
1474 db_prepare(&q,
1475 "SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
1476 zName, zName
1477 );
1478 while( db_step(&q)==SQLITE_ROW ){
1479 if( cnt++ ){
1480 if( pOut ){
1481 sqlite3_str_append(pOut, ",", 1);
1482 }else{
1483 fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1484 }
1485 }
1486 whatis_rid(db_column_int(&q, 0), mFlags, pOut);
1487 }
1488 db_finalize(&q);
1489 if( nTkt>0 ){
1490 db_prepare(&q,
1491 "SELECT (SELECT srcid FROM tagxref"
@@ -1396,34 +1494,41 @@
1494 " ORDER BY mtime LIMIT 1)"
1495 " FROM tag WHERE tagname GLOB 'tkt-%q*'",
1496 zC
1497 );
1498 while( db_step(&q)==SQLITE_ROW ){
1499 if( pOut ){
1500 sqlite3_str_append(pOut, ",", 1);
1501 }else{
1502 fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1503 }
1504 whatis_rid(db_column_int(&q, 0), mFlags, pOut);
1505 }
1506 db_finalize(&q);
1507 }
1508 if( pOut ) sqlite3_str_append(pOut, "]}", 2);
1509 }else if( rid==0 ){
1510 if( (mFlags & (WHATIS_OMIT_UNK|WHATIS_HASHONLY))==0 ){
1511 /* 0123456789 12 */
1512 if( zFileName ){
1513 fossil_print("%-12s%s\n", "name:", zFileName);
1514 }
1515 if( pOut ) sqlite3_str_append(pOut, "{", 1);
1516 whatis_line(pOut, "unknown", "%s", zName);
1517 if( pOut ) sqlite3_str_append(pOut, "}", 1);
1518 }
1519 }else{
1520 if( mFlags & WHATIS_REPO ){
1521 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1522 }
1523 if( zFileName ){
1524 zName = zFileName;
1525 }
1526 if( (mFlags & WHATIS_HASHONLY)==0 && pOut==0 ){
1527 whatis_line(pOut, "name", "%s", zName);
1528 }
1529 whatis_rid(rid, mFlags, pOut);
1530 }
1531 fossil_free(zC);
1532 }
1533
1534 /*
@@ -1449,10 +1554,11 @@
1554 void whatis_cmd(void){
1555 int mFlags = 0;
1556 int fileFlag;
1557 int i;
1558 const char *zType = 0;
1559 sqlite3_str *pOut = 0;
1560 db_find_and_open_repository(0,0);
1561 if( find_option("verbose","v",0)!=0 ){
1562 mFlags |= WHATIS_VERBOSE;
1563 }
1564 if( find_option("hash","h",0)!=0 ){
@@ -1461,10 +1567,14 @@
1567 if( g.fQuiet ){
1568 mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
1569 }
1570 fileFlag = find_option("file","f",0)!=0;
1571 zType = find_option("type",0,1);
1572
1573 if( find_option("json",0,0)!=0 ){ /* undocumented test option */
1574 pOut = sqlite3_str_new(0);
1575 }
1576
1577 /* We should be done with options.. */
1578 verify_all_options();
1579
1580 if( g.argc<3 ) usage("NAME ...");
@@ -1487,17 +1597,52 @@
1597 ** the primary hash name. */
1598 blob_reset(&hash);
1599 hname_hash(&in, 0, &hash);
1600 zHash = (const char*)blob_str(&hash);
1601 }
1602 whatis_artifact(zHash, zName, zType, mFlags, pOut);
1603 blob_reset(&hash);
1604 }else{
1605 whatis_artifact(zName, 0, zType, mFlags, pOut);
1606 }
1607 if( pOut ){
1608 fossil_print("%s\n", sqlite3_str_value(pOut));
1609 sqlite3_str_truncate(pOut, 0);
1610 }
1611 }
1612 if( pOut ) sqlite3_str_free(pOut);
1613 }
1614
1615 /*
1616 ** This is an SQL function that does the rough equivalent of the
1617 ** "whatis" command. The argument can be a text identifier, or a
1618 ** integer RID.
1619 */
1620 void whatis_sql_function(
1621 sqlite3_context *context,
1622 int argc,
1623 sqlite3_value **argv
1624 ){
1625 sqlite3_str *pOut = sqlite3_str_new(0);
1626 int n;
1627 assert( argc==1 );
1628 if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
1629 int rid = sqlite3_value_int(argv[0]);
1630 whatis_rid(rid, 0, pOut);
1631 }else if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
1632 const char *zName = (const char*)sqlite3_value_text(argv[0]);
1633 whatis_artifact(zName, 0, 0, 0, pOut);
1634 }else{
1635 sqlite3_str_free(pOut);
1636 return;
1637 }
1638 n = sqlite3_str_length(pOut);
1639 sqlite3_result_text64(context, sqlite3_str_finish(pOut), n,
1640 sqlite3_free, SQLITE_UTF8);
1641 sqlite3_result_subtype(context, 'J');
1642 }
1643
1644
1645 /*
1646 ** COMMAND: test-whatis-all
1647 **
1648 ** Usage: %fossil test-whatis-all
@@ -1509,11 +1654,11 @@
1654 int cnt = 0;
1655 db_find_and_open_repository(0,0);
1656 db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
1657 while( db_step(&q)==SQLITE_ROW ){
1658 if( cnt++ ) fossil_print("%.79c\n", '-');
1659 whatis_rid(db_column_int(&q,0), 1, 0);
1660 }
1661 db_finalize(&q);
1662 }
1663
1664
1665
+201 -56
--- src/name.c
+++ src/name.c
@@ -1143,10 +1143,40 @@
11431143
case CFTYPE_CONTROL: zType = "Tag-change"; break;
11441144
default: break;
11451145
}
11461146
return zType;
11471147
}
1148
+
1149
+/*
1150
+** This is the output routine for whatis_rid(). If pOut is NULL
1151
+** then write zKey and zValue on fossil_print(). But if pOut is
1152
+** not NULL, append the key and value as a term of a JSON object.
1153
+*/
1154
+static void whatis_line(
1155
+ sqlite3_str *pOut,
1156
+ const char *zKey,
1157
+ const char *zValue,
1158
+ ...
1159
+){
1160
+ char *zArg;
1161
+ va_list ap;
1162
+ va_start(ap, zValue);
1163
+ zArg = sqlite3_vmprintf(zValue,ap);
1164
+ va_end(ap);
1165
+ if( pOut ){
1166
+ int n = sqlite3_str_length(pOut);
1167
+ if( n>1 && sqlite3_str_value(pOut)[n-1]!='{' ){
1168
+ sqlite3_str_append(pOut, ",", 1);
1169
+ }
1170
+ sqlite3_str_appendf(pOut, "%J:%J", zKey, zArg);
1171
+ }else{
1172
+ int n = 11 - (int)strlen(zKey);
1173
+ if( n<=0 ) n = 0;
1174
+ fossil_print("%s:%*s%s\n",zKey,n,"",zArg);
1175
+ }
1176
+ sqlite3_free(zArg);
1177
+}
11481178
11491179
/*
11501180
** Flag values for whatis_rid().
11511181
*/
11521182
#if INTERFACE
@@ -1153,18 +1183,25 @@
11531183
#define WHATIS_VERBOSE 0x01 /* Extra output */
11541184
#define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
11551185
#define WHATIS_REPO 0x04 /* Show repository name */
11561186
#define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
11571187
#define WHATIS_HASHONLY 0x10 /* Show only the hash */
1188
+#define WHATIS_JSON 0x20 /* Render as JSON */
11581189
#endif
11591190
11601191
/*
1161
-** Generate a description of artifact "rid"
1192
+** Generate a description of artifact "rid".
1193
+**
1194
+** Send results to stdout using fossil_print() if pOut==0 or if
1195
+** WHATIS_HASHONLY is set. But without WHATIS_HASHONLY and if
1196
+** pOut!=0, then write a JSON description of the object into pOut.
11621197
*/
1163
-void whatis_rid(int rid, int flags){
1198
+void whatis_rid(int rid, int flags, sqlite3_str *pOut){
11641199
Stmt q;
11651200
int cnt;
1201
+
1202
+ if( pOut ) sqlite3_str_appendf(pOut, "{\"rid\":%d", rid);
11661203
11671204
/* Basic information about the object. */
11681205
db_prepare(&q,
11691206
"SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
11701207
" FROM blob, rcvfrom"
@@ -1173,19 +1210,21 @@
11731210
rid);
11741211
if( db_step(&q)==SQLITE_ROW ){
11751212
if( flags & WHATIS_HASHONLY ){
11761213
fossil_print("%s\n", db_column_text(&q,0));
11771214
}else if( flags & WHATIS_VERBOSE ){
1178
- fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
1179
- fossil_print("size: %d bytes\n", db_column_int(&q,1));
1180
- fossil_print("received: %s from %s\n",
1215
+ whatis_line(pOut, "artifact", "%s (%d)", db_column_text(&q,0), rid);
1216
+ whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
1217
+ whatis_line(pOut, "received", "%s from %s",
11811218
db_column_text(&q, 2),
11821219
db_column_text(&q, 3));
11831220
}else{
1184
- fossil_print("artifact: %s\n", db_column_text(&q,0));
1185
- fossil_print("size: %d bytes\n", db_column_int(&q,1));
1221
+ whatis_line(pOut, "artifact","%s", db_column_text(&q,0));
1222
+ whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
11861223
}
1224
+ }else if( pOut ){
1225
+ sqlite3_str_appendf(pOut, ",\"artifact\":null");
11871226
}
11881227
db_finalize(&q);
11891228
if( flags & WHATIS_HASHONLY ) return;
11901229
11911230
/* Report any symbolic tags on this artifact */
@@ -1198,14 +1237,27 @@
11981237
" ORDER BY 1",
11991238
rid
12001239
);
12011240
cnt = 0;
12021241
while( db_step(&q)==SQLITE_ROW ){
1203
- const char *zPrefix = cnt++ ? ", " : "tags: ";
1204
- fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1242
+ const char *zTag = (const char*)db_column_text(&q,0);
1243
+ if( pOut ){
1244
+ const char *zSep = cnt==0 ? ",tags:[" : ",";
1245
+ sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1246
+ }else{
1247
+ const char *zPrefix = cnt ? ", " : "tags: ";
1248
+ fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1249
+ }
1250
+ cnt++;
12051251
}
1206
- if( cnt ) fossil_print("\n");
1252
+ if( cnt ){
1253
+ if( pOut ){
1254
+ sqlite3_str_append(pOut, "]", 1);
1255
+ }else{
1256
+ fossil_print("\n");
1257
+ }
1258
+ }
12071259
db_finalize(&q);
12081260
12091261
/* Report any HIDDEN, PRIVATE, CLUSTER, or CLOSED tags on this artifact */
12101262
db_prepare(&q,
12111263
"SELECT tagname"
@@ -1215,14 +1267,27 @@
12151267
" ORDER BY 1",
12161268
rid
12171269
);
12181270
cnt = 0;
12191271
while( db_step(&q)==SQLITE_ROW ){
1220
- const char *zPrefix = cnt++ ? ", " : "raw-tags: ";
1221
- fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1272
+ const char *zTag = (const char*)db_column_text(&q,0);
1273
+ if( pOut ){
1274
+ const char *zSep = cnt==0 ? ",\"raw-tags\":[" : ",";
1275
+ sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1276
+ }else{
1277
+ const char *zPrefix = cnt ? ", " : "raw-tags: ";
1278
+ fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1279
+ }
1280
+ cnt++;
12221281
}
1223
- if( cnt ) fossil_print("\n");
1282
+ if( cnt ){
1283
+ if( pOut ){
1284
+ sqlite3_str_append(pOut, "]", 1);
1285
+ }else{
1286
+ fossil_print("\n");
1287
+ }
1288
+ }
12241289
db_finalize(&q);
12251290
12261291
/* Check for entries on the timeline that reference this object */
12271292
db_prepare(&q,
12281293
"SELECT"
@@ -1244,17 +1309,21 @@
12441309
case 'f': zType = "Forum-post"; break;
12451310
case 't': zType = "Ticket-change"; break;
12461311
case 'g': zType = "Tag-change"; break;
12471312
default: zType = "Unknown"; break;
12481313
}
1249
- fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
1314
+ whatis_line(pOut, "type", "%s by %s on %s", zType, db_column_text(&q,2),
12501315
db_column_text(&q, 1));
12511316
if( eType=='t' && db_column_type(&q,4)==SQLITE_TEXT ){
1252
- fossil_print("ticket-id: %s\n", db_column_text(&q,4));
1317
+ whatis_line(pOut, "ticket-id", "%s", db_column_text(&q,4));
12531318
}
1254
- fossil_print("comment: ");
1255
- comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
1319
+ if( pOut ){
1320
+ sqlite3_str_appendf(pOut, ",\"comment\":%J", db_column_text(&q,3));
1321
+ }else{
1322
+ fossil_print("comment: ");
1323
+ comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
1324
+ }
12561325
cnt++;
12571326
}
12581327
db_finalize(&q);
12591328
12601329
/* Check to see if this object is used as a file in a check-in */
@@ -1271,20 +1340,25 @@
12711340
" ORDER BY event.mtime %s /*sort*/",
12721341
TAG_BRANCH, rid,
12731342
(flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
12741343
while( db_step(&q)==SQLITE_ROW ){
12751344
if( flags & WHATIS_BRIEF ){
1276
- fossil_print("mtime: %s\n", db_column_text(&q,2));
1277
- }
1278
- fossil_print("file: %s\n", db_column_text(&q,0));
1279
- fossil_print(" part of [%S] on branch %s by %s on %s\n",
1280
- db_column_text(&q, 1),
1281
- db_column_text(&q, 5),
1282
- db_column_text(&q, 3),
1283
- db_column_text(&q, 2));
1284
- fossil_print(" ");
1285
- comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
1345
+ whatis_line(pOut, "mtime","%s", db_column_text(&q,2));
1346
+ }
1347
+ if( pOut ){
1348
+ whatis_line(pOut,"file","%s", db_column_text(&q,0));
1349
+ whatis_line(pOut,"part-of","%s", db_column_text(&q,1));
1350
+ }else{
1351
+ fossil_print("file: %s\n", db_column_text(&q,0));
1352
+ fossil_print(" part of [%S] on branch %s by %s on %s\n",
1353
+ db_column_text(&q, 1),
1354
+ db_column_text(&q, 5),
1355
+ db_column_text(&q, 3),
1356
+ db_column_text(&q, 2));
1357
+ fossil_print(" ");
1358
+ comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
1359
+ }
12861360
cnt++;
12871361
}
12881362
db_finalize(&q);
12891363
12901364
/* Check to see if this object is used as an attachment */
@@ -1303,30 +1377,36 @@
13031377
" FROM attachment JOIN blob ON attachment.src=blob.uuid"
13041378
" WHERE blob.rid=%d",
13051379
rid
13061380
);
13071381
while( db_step(&q)==SQLITE_ROW ){
1308
- fossil_print("attachment: %s\n", db_column_text(&q,0));
1309
- fossil_print(" attached to %s %s\n",
1310
- db_column_text(&q,5), db_column_text(&q,4));
1311
- if( flags & WHATIS_VERBOSE ){
1312
- fossil_print(" via %s (%d)\n",
1313
- db_column_text(&q,7), db_column_int(&q,6));
1382
+ if( pOut ){
1383
+ whatis_line(pOut, "attachment", "%s", db_column_text(&q,0));
1384
+ whatis_line(pOut, "attached-to", "%s %s",
1385
+ db_column_text(&q,5), db_column_text(&q,4));
13141386
}else{
1315
- fossil_print(" via %s\n",
1316
- db_column_text(&q,7));
1387
+ fossil_print("attachment: %s\n", db_column_text(&q,0));
1388
+ fossil_print(" attached to %s %s\n",
1389
+ db_column_text(&q,5), db_column_text(&q,4));
1390
+ if( flags & WHATIS_VERBOSE ){
1391
+ fossil_print(" via %s (%d)\n",
1392
+ db_column_text(&q,7), db_column_int(&q,6));
1393
+ }else{
1394
+ fossil_print(" via %s\n",
1395
+ db_column_text(&q,7));
1396
+ }
1397
+ fossil_print(" by user %s on %s\n",
1398
+ db_column_text(&q,2), db_column_text(&q,3));
1399
+ fossil_print(" ");
1400
+ comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
13171401
}
1318
- fossil_print(" by user %s on %s\n",
1319
- db_column_text(&q,2), db_column_text(&q,3));
1320
- fossil_print(" ");
1321
- comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
13221402
cnt++;
13231403
}
13241404
db_finalize(&q);
13251405
13261406
/* If other information available, try to describe the object */
1327
- if( cnt==0 ){
1407
+ if( cnt==0 && pOut==0 ){
13281408
char *zWhere = mprintf("=%d", rid);
13291409
char *zDesc;
13301410
describe_artifacts(zWhere);
13311411
free(zWhere);
13321412
zDesc = db_text(0,
@@ -1333,25 +1413,33 @@
13331413
"SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
13341414
" FROM description WHERE rid=%d", rid);
13351415
fossil_print("%s\n", zDesc);
13361416
fossil_free(zDesc);
13371417
}
1418
+
1419
+ if( pOut ) sqlite3_str_append(pOut, "}", 1);
13381420
}
13391421
13401422
/*
13411423
** Generate a description of artifact from it symbolic name.
13421424
*/
13431425
void whatis_artifact(
1344
- const char *zName, /* Symbolic name or full hash */
1345
- const char *zFileName,/* Optional: original filename (in file mode) */
1346
- const char *zType, /* Artifact type filter */
1347
- int mFlags /* WHATIS_* flags */
1426
+ const char *zName, /* Symbolic name or full hash */
1427
+ const char *zFileName,/* Optional: original filename (in file mode) */
1428
+ const char *zType, /* Artifact type filter */
1429
+ int mFlags, /* WHATIS_* flags */
1430
+ sqlite3_str *pOut /* Write JSON here, if not NULL */
13481431
){
13491432
int rid = symbolic_name_to_rid(zName, zType);
13501433
size_t nName;
13511434
char *zC = 0;
13521435
int nTkt = 0;
1436
+
1437
+ if( pOut ){
1438
+ mFlags &= ~(WHATIS_HASHONLY|WHATIS_REPO);
1439
+ zFileName = 0;
1440
+ }
13531441
if( (nName = strlen(zName))>=4 && validate16(zName,nName) ){
13541442
zC = fossil_strdup(zName);
13551443
canonical16(zC, nName);
13561444
nTkt = db_int(0,"SELECT count(*) FROM tag WHERE tagname GLOB 'tkt-%q*'",zC);
13571445
if( nTkt>0 ){
@@ -1376,18 +1464,28 @@
13761464
fossil_print("\nrepository: %s\n", g.zRepositoryName);
13771465
}
13781466
if( zFileName ){
13791467
fossil_print("%-12s%s\n", "name:", zFileName);
13801468
}
1381
- fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
1469
+ if( pOut ){
1470
+ sqlite3_str_appendall(pOut, "{\"ambiguous\":[");
1471
+ }else{
1472
+ fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
1473
+ }
13821474
db_prepare(&q,
13831475
"SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
13841476
zName, zName
13851477
);
13861478
while( db_step(&q)==SQLITE_ROW ){
1387
- if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1388
- whatis_rid(db_column_int(&q, 0), mFlags);
1479
+ if( cnt++ ){
1480
+ if( pOut ){
1481
+ sqlite3_str_append(pOut, ",", 1);
1482
+ }else{
1483
+ fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1484
+ }
1485
+ }
1486
+ whatis_rid(db_column_int(&q, 0), mFlags, pOut);
13891487
}
13901488
db_finalize(&q);
13911489
if( nTkt>0 ){
13921490
db_prepare(&q,
13931491
"SELECT (SELECT srcid FROM tagxref"
@@ -1396,34 +1494,41 @@
13961494
" ORDER BY mtime LIMIT 1)"
13971495
" FROM tag WHERE tagname GLOB 'tkt-%q*'",
13981496
zC
13991497
);
14001498
while( db_step(&q)==SQLITE_ROW ){
1401
- if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1402
- whatis_rid(db_column_int(&q, 0), mFlags);
1499
+ if( pOut ){
1500
+ sqlite3_str_append(pOut, ",", 1);
1501
+ }else{
1502
+ fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1503
+ }
1504
+ whatis_rid(db_column_int(&q, 0), mFlags, pOut);
14031505
}
14041506
db_finalize(&q);
14051507
}
1508
+ if( pOut ) sqlite3_str_append(pOut, "]}", 2);
14061509
}else if( rid==0 ){
14071510
if( (mFlags & (WHATIS_OMIT_UNK|WHATIS_HASHONLY))==0 ){
14081511
/* 0123456789 12 */
14091512
if( zFileName ){
14101513
fossil_print("%-12s%s\n", "name:", zFileName);
14111514
}
1412
- fossil_print("unknown: %s\n", zName);
1515
+ if( pOut ) sqlite3_str_append(pOut, "{", 1);
1516
+ whatis_line(pOut, "unknown", "%s", zName);
1517
+ if( pOut ) sqlite3_str_append(pOut, "}", 1);
14131518
}
14141519
}else{
14151520
if( mFlags & WHATIS_REPO ){
14161521
fossil_print("\nrepository: %s\n", g.zRepositoryName);
14171522
}
14181523
if( zFileName ){
14191524
zName = zFileName;
14201525
}
1421
- if( (mFlags & WHATIS_HASHONLY)==0 ){
1422
- fossil_print("%-12s%s\n", "name:", zName);
1526
+ if( (mFlags & WHATIS_HASHONLY)==0 && pOut==0 ){
1527
+ whatis_line(pOut, "name", "%s", zName);
14231528
}
1424
- whatis_rid(rid, mFlags);
1529
+ whatis_rid(rid, mFlags, pOut);
14251530
}
14261531
fossil_free(zC);
14271532
}
14281533
14291534
/*
@@ -1449,10 +1554,11 @@
14491554
void whatis_cmd(void){
14501555
int mFlags = 0;
14511556
int fileFlag;
14521557
int i;
14531558
const char *zType = 0;
1559
+ sqlite3_str *pOut = 0;
14541560
db_find_and_open_repository(0,0);
14551561
if( find_option("verbose","v",0)!=0 ){
14561562
mFlags |= WHATIS_VERBOSE;
14571563
}
14581564
if( find_option("hash","h",0)!=0 ){
@@ -1461,10 +1567,14 @@
14611567
if( g.fQuiet ){
14621568
mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
14631569
}
14641570
fileFlag = find_option("file","f",0)!=0;
14651571
zType = find_option("type",0,1);
1572
+
1573
+ if( find_option("json",0,0)!=0 ){ /* undocumented test option */
1574
+ pOut = sqlite3_str_new(0);
1575
+ }
14661576
14671577
/* We should be done with options.. */
14681578
verify_all_options();
14691579
14701580
if( g.argc<3 ) usage("NAME ...");
@@ -1487,17 +1597,52 @@
14871597
** the primary hash name. */
14881598
blob_reset(&hash);
14891599
hname_hash(&in, 0, &hash);
14901600
zHash = (const char*)blob_str(&hash);
14911601
}
1492
- whatis_artifact(zHash, zName, zType, mFlags);
1602
+ whatis_artifact(zHash, zName, zType, mFlags, pOut);
14931603
blob_reset(&hash);
14941604
}else{
1495
- whatis_artifact(zName, 0, zType, mFlags);
1605
+ whatis_artifact(zName, 0, zType, mFlags, pOut);
1606
+ }
1607
+ if( pOut ){
1608
+ fossil_print("%s\n", sqlite3_str_value(pOut));
1609
+ sqlite3_str_truncate(pOut, 0);
14961610
}
14971611
}
1612
+ if( pOut ) sqlite3_str_free(pOut);
1613
+}
1614
+
1615
+/*
1616
+** This is an SQL function that does the rough equivalent of the
1617
+** "whatis" command. The argument can be a text identifier, or a
1618
+** integer RID.
1619
+*/
1620
+void whatis_sql_function(
1621
+ sqlite3_context *context,
1622
+ int argc,
1623
+ sqlite3_value **argv
1624
+){
1625
+ sqlite3_str *pOut = sqlite3_str_new(0);
1626
+ int n;
1627
+ assert( argc==1 );
1628
+ if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
1629
+ int rid = sqlite3_value_int(argv[0]);
1630
+ whatis_rid(rid, 0, pOut);
1631
+ }else if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
1632
+ const char *zName = (const char*)sqlite3_value_text(argv[0]);
1633
+ whatis_artifact(zName, 0, 0, 0, pOut);
1634
+ }else{
1635
+ sqlite3_str_free(pOut);
1636
+ return;
1637
+ }
1638
+ n = sqlite3_str_length(pOut);
1639
+ sqlite3_result_text64(context, sqlite3_str_finish(pOut), n,
1640
+ sqlite3_free, SQLITE_UTF8);
1641
+ sqlite3_result_subtype(context, 'J');
14981642
}
1643
+
14991644
15001645
/*
15011646
** COMMAND: test-whatis-all
15021647
**
15031648
** Usage: %fossil test-whatis-all
@@ -1509,11 +1654,11 @@
15091654
int cnt = 0;
15101655
db_find_and_open_repository(0,0);
15111656
db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
15121657
while( db_step(&q)==SQLITE_ROW ){
15131658
if( cnt++ ) fossil_print("%.79c\n", '-');
1514
- whatis_rid(db_column_int(&q,0), 1);
1659
+ whatis_rid(db_column_int(&q,0), 1, 0);
15151660
}
15161661
db_finalize(&q);
15171662
}
15181663
15191664
15201665
--- src/name.c
+++ src/name.c
@@ -1143,10 +1143,40 @@
1143 case CFTYPE_CONTROL: zType = "Tag-change"; break;
1144 default: break;
1145 }
1146 return zType;
1147 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1148
1149 /*
1150 ** Flag values for whatis_rid().
1151 */
1152 #if INTERFACE
@@ -1153,18 +1183,25 @@
1153 #define WHATIS_VERBOSE 0x01 /* Extra output */
1154 #define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
1155 #define WHATIS_REPO 0x04 /* Show repository name */
1156 #define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
1157 #define WHATIS_HASHONLY 0x10 /* Show only the hash */
 
1158 #endif
1159
1160 /*
1161 ** Generate a description of artifact "rid"
 
 
 
 
1162 */
1163 void whatis_rid(int rid, int flags){
1164 Stmt q;
1165 int cnt;
 
 
1166
1167 /* Basic information about the object. */
1168 db_prepare(&q,
1169 "SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
1170 " FROM blob, rcvfrom"
@@ -1173,19 +1210,21 @@
1173 rid);
1174 if( db_step(&q)==SQLITE_ROW ){
1175 if( flags & WHATIS_HASHONLY ){
1176 fossil_print("%s\n", db_column_text(&q,0));
1177 }else if( flags & WHATIS_VERBOSE ){
1178 fossil_print("artifact: %s (%d)\n", db_column_text(&q,0), rid);
1179 fossil_print("size: %d bytes\n", db_column_int(&q,1));
1180 fossil_print("received: %s from %s\n",
1181 db_column_text(&q, 2),
1182 db_column_text(&q, 3));
1183 }else{
1184 fossil_print("artifact: %s\n", db_column_text(&q,0));
1185 fossil_print("size: %d bytes\n", db_column_int(&q,1));
1186 }
 
 
1187 }
1188 db_finalize(&q);
1189 if( flags & WHATIS_HASHONLY ) return;
1190
1191 /* Report any symbolic tags on this artifact */
@@ -1198,14 +1237,27 @@
1198 " ORDER BY 1",
1199 rid
1200 );
1201 cnt = 0;
1202 while( db_step(&q)==SQLITE_ROW ){
1203 const char *zPrefix = cnt++ ? ", " : "tags: ";
1204 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
 
 
 
 
 
 
 
1205 }
1206 if( cnt ) fossil_print("\n");
 
 
 
 
 
 
1207 db_finalize(&q);
1208
1209 /* Report any HIDDEN, PRIVATE, CLUSTER, or CLOSED tags on this artifact */
1210 db_prepare(&q,
1211 "SELECT tagname"
@@ -1215,14 +1267,27 @@
1215 " ORDER BY 1",
1216 rid
1217 );
1218 cnt = 0;
1219 while( db_step(&q)==SQLITE_ROW ){
1220 const char *zPrefix = cnt++ ? ", " : "raw-tags: ";
1221 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
 
 
 
 
 
 
 
1222 }
1223 if( cnt ) fossil_print("\n");
 
 
 
 
 
 
1224 db_finalize(&q);
1225
1226 /* Check for entries on the timeline that reference this object */
1227 db_prepare(&q,
1228 "SELECT"
@@ -1244,17 +1309,21 @@
1244 case 'f': zType = "Forum-post"; break;
1245 case 't': zType = "Ticket-change"; break;
1246 case 'g': zType = "Tag-change"; break;
1247 default: zType = "Unknown"; break;
1248 }
1249 fossil_print("type: %s by %s on %s\n", zType, db_column_text(&q,2),
1250 db_column_text(&q, 1));
1251 if( eType=='t' && db_column_type(&q,4)==SQLITE_TEXT ){
1252 fossil_print("ticket-id: %s\n", db_column_text(&q,4));
1253 }
1254 fossil_print("comment: ");
1255 comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
 
 
 
 
1256 cnt++;
1257 }
1258 db_finalize(&q);
1259
1260 /* Check to see if this object is used as a file in a check-in */
@@ -1271,20 +1340,25 @@
1271 " ORDER BY event.mtime %s /*sort*/",
1272 TAG_BRANCH, rid,
1273 (flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
1274 while( db_step(&q)==SQLITE_ROW ){
1275 if( flags & WHATIS_BRIEF ){
1276 fossil_print("mtime: %s\n", db_column_text(&q,2));
1277 }
1278 fossil_print("file: %s\n", db_column_text(&q,0));
1279 fossil_print(" part of [%S] on branch %s by %s on %s\n",
1280 db_column_text(&q, 1),
1281 db_column_text(&q, 5),
1282 db_column_text(&q, 3),
1283 db_column_text(&q, 2));
1284 fossil_print(" ");
1285 comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
 
 
 
 
 
1286 cnt++;
1287 }
1288 db_finalize(&q);
1289
1290 /* Check to see if this object is used as an attachment */
@@ -1303,30 +1377,36 @@
1303 " FROM attachment JOIN blob ON attachment.src=blob.uuid"
1304 " WHERE blob.rid=%d",
1305 rid
1306 );
1307 while( db_step(&q)==SQLITE_ROW ){
1308 fossil_print("attachment: %s\n", db_column_text(&q,0));
1309 fossil_print(" attached to %s %s\n",
1310 db_column_text(&q,5), db_column_text(&q,4));
1311 if( flags & WHATIS_VERBOSE ){
1312 fossil_print(" via %s (%d)\n",
1313 db_column_text(&q,7), db_column_int(&q,6));
1314 }else{
1315 fossil_print(" via %s\n",
1316 db_column_text(&q,7));
 
 
 
 
 
 
 
 
 
 
 
 
1317 }
1318 fossil_print(" by user %s on %s\n",
1319 db_column_text(&q,2), db_column_text(&q,3));
1320 fossil_print(" ");
1321 comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
1322 cnt++;
1323 }
1324 db_finalize(&q);
1325
1326 /* If other information available, try to describe the object */
1327 if( cnt==0 ){
1328 char *zWhere = mprintf("=%d", rid);
1329 char *zDesc;
1330 describe_artifacts(zWhere);
1331 free(zWhere);
1332 zDesc = db_text(0,
@@ -1333,25 +1413,33 @@
1333 "SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
1334 " FROM description WHERE rid=%d", rid);
1335 fossil_print("%s\n", zDesc);
1336 fossil_free(zDesc);
1337 }
 
 
1338 }
1339
1340 /*
1341 ** Generate a description of artifact from it symbolic name.
1342 */
1343 void whatis_artifact(
1344 const char *zName, /* Symbolic name or full hash */
1345 const char *zFileName,/* Optional: original filename (in file mode) */
1346 const char *zType, /* Artifact type filter */
1347 int mFlags /* WHATIS_* flags */
 
1348 ){
1349 int rid = symbolic_name_to_rid(zName, zType);
1350 size_t nName;
1351 char *zC = 0;
1352 int nTkt = 0;
 
 
 
 
 
1353 if( (nName = strlen(zName))>=4 && validate16(zName,nName) ){
1354 zC = fossil_strdup(zName);
1355 canonical16(zC, nName);
1356 nTkt = db_int(0,"SELECT count(*) FROM tag WHERE tagname GLOB 'tkt-%q*'",zC);
1357 if( nTkt>0 ){
@@ -1376,18 +1464,28 @@
1376 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1377 }
1378 if( zFileName ){
1379 fossil_print("%-12s%s\n", "name:", zFileName);
1380 }
1381 fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
 
 
 
 
1382 db_prepare(&q,
1383 "SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
1384 zName, zName
1385 );
1386 while( db_step(&q)==SQLITE_ROW ){
1387 if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1388 whatis_rid(db_column_int(&q, 0), mFlags);
 
 
 
 
 
 
1389 }
1390 db_finalize(&q);
1391 if( nTkt>0 ){
1392 db_prepare(&q,
1393 "SELECT (SELECT srcid FROM tagxref"
@@ -1396,34 +1494,41 @@
1396 " ORDER BY mtime LIMIT 1)"
1397 " FROM tag WHERE tagname GLOB 'tkt-%q*'",
1398 zC
1399 );
1400 while( db_step(&q)==SQLITE_ROW ){
1401 if( cnt++ ) fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1402 whatis_rid(db_column_int(&q, 0), mFlags);
 
 
 
 
1403 }
1404 db_finalize(&q);
1405 }
 
1406 }else if( rid==0 ){
1407 if( (mFlags & (WHATIS_OMIT_UNK|WHATIS_HASHONLY))==0 ){
1408 /* 0123456789 12 */
1409 if( zFileName ){
1410 fossil_print("%-12s%s\n", "name:", zFileName);
1411 }
1412 fossil_print("unknown: %s\n", zName);
 
 
1413 }
1414 }else{
1415 if( mFlags & WHATIS_REPO ){
1416 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1417 }
1418 if( zFileName ){
1419 zName = zFileName;
1420 }
1421 if( (mFlags & WHATIS_HASHONLY)==0 ){
1422 fossil_print("%-12s%s\n", "name:", zName);
1423 }
1424 whatis_rid(rid, mFlags);
1425 }
1426 fossil_free(zC);
1427 }
1428
1429 /*
@@ -1449,10 +1554,11 @@
1449 void whatis_cmd(void){
1450 int mFlags = 0;
1451 int fileFlag;
1452 int i;
1453 const char *zType = 0;
 
1454 db_find_and_open_repository(0,0);
1455 if( find_option("verbose","v",0)!=0 ){
1456 mFlags |= WHATIS_VERBOSE;
1457 }
1458 if( find_option("hash","h",0)!=0 ){
@@ -1461,10 +1567,14 @@
1461 if( g.fQuiet ){
1462 mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
1463 }
1464 fileFlag = find_option("file","f",0)!=0;
1465 zType = find_option("type",0,1);
 
 
 
 
1466
1467 /* We should be done with options.. */
1468 verify_all_options();
1469
1470 if( g.argc<3 ) usage("NAME ...");
@@ -1487,17 +1597,52 @@
1487 ** the primary hash name. */
1488 blob_reset(&hash);
1489 hname_hash(&in, 0, &hash);
1490 zHash = (const char*)blob_str(&hash);
1491 }
1492 whatis_artifact(zHash, zName, zType, mFlags);
1493 blob_reset(&hash);
1494 }else{
1495 whatis_artifact(zName, 0, zType, mFlags);
 
 
 
 
1496 }
1497 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1498 }
 
1499
1500 /*
1501 ** COMMAND: test-whatis-all
1502 **
1503 ** Usage: %fossil test-whatis-all
@@ -1509,11 +1654,11 @@
1509 int cnt = 0;
1510 db_find_and_open_repository(0,0);
1511 db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
1512 while( db_step(&q)==SQLITE_ROW ){
1513 if( cnt++ ) fossil_print("%.79c\n", '-');
1514 whatis_rid(db_column_int(&q,0), 1);
1515 }
1516 db_finalize(&q);
1517 }
1518
1519
1520
--- src/name.c
+++ src/name.c
@@ -1143,10 +1143,40 @@
1143 case CFTYPE_CONTROL: zType = "Tag-change"; break;
1144 default: break;
1145 }
1146 return zType;
1147 }
1148
1149 /*
1150 ** This is the output routine for whatis_rid(). If pOut is NULL
1151 ** then write zKey and zValue on fossil_print(). But if pOut is
1152 ** not NULL, append the key and value as a term of a JSON object.
1153 */
1154 static void whatis_line(
1155 sqlite3_str *pOut,
1156 const char *zKey,
1157 const char *zValue,
1158 ...
1159 ){
1160 char *zArg;
1161 va_list ap;
1162 va_start(ap, zValue);
1163 zArg = sqlite3_vmprintf(zValue,ap);
1164 va_end(ap);
1165 if( pOut ){
1166 int n = sqlite3_str_length(pOut);
1167 if( n>1 && sqlite3_str_value(pOut)[n-1]!='{' ){
1168 sqlite3_str_append(pOut, ",", 1);
1169 }
1170 sqlite3_str_appendf(pOut, "%J:%J", zKey, zArg);
1171 }else{
1172 int n = 11 - (int)strlen(zKey);
1173 if( n<=0 ) n = 0;
1174 fossil_print("%s:%*s%s\n",zKey,n,"",zArg);
1175 }
1176 sqlite3_free(zArg);
1177 }
1178
1179 /*
1180 ** Flag values for whatis_rid().
1181 */
1182 #if INTERFACE
@@ -1153,18 +1183,25 @@
1183 #define WHATIS_VERBOSE 0x01 /* Extra output */
1184 #define WHATIS_BRIEF 0x02 /* Omit unnecessary output */
1185 #define WHATIS_REPO 0x04 /* Show repository name */
1186 #define WHATIS_OMIT_UNK 0x08 /* Do not show "unknown" lines */
1187 #define WHATIS_HASHONLY 0x10 /* Show only the hash */
1188 #define WHATIS_JSON 0x20 /* Render as JSON */
1189 #endif
1190
1191 /*
1192 ** Generate a description of artifact "rid".
1193 **
1194 ** Send results to stdout using fossil_print() if pOut==0 or if
1195 ** WHATIS_HASHONLY is set. But without WHATIS_HASHONLY and if
1196 ** pOut!=0, then write a JSON description of the object into pOut.
1197 */
1198 void whatis_rid(int rid, int flags, sqlite3_str *pOut){
1199 Stmt q;
1200 int cnt;
1201
1202 if( pOut ) sqlite3_str_appendf(pOut, "{\"rid\":%d", rid);
1203
1204 /* Basic information about the object. */
1205 db_prepare(&q,
1206 "SELECT uuid, size, datetime(mtime,toLocal()), ipaddr"
1207 " FROM blob, rcvfrom"
@@ -1173,19 +1210,21 @@
1210 rid);
1211 if( db_step(&q)==SQLITE_ROW ){
1212 if( flags & WHATIS_HASHONLY ){
1213 fossil_print("%s\n", db_column_text(&q,0));
1214 }else if( flags & WHATIS_VERBOSE ){
1215 whatis_line(pOut, "artifact", "%s (%d)", db_column_text(&q,0), rid);
1216 whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
1217 whatis_line(pOut, "received", "%s from %s",
1218 db_column_text(&q, 2),
1219 db_column_text(&q, 3));
1220 }else{
1221 whatis_line(pOut, "artifact","%s", db_column_text(&q,0));
1222 whatis_line(pOut, "size", "%d bytes", db_column_int(&q,1));
1223 }
1224 }else if( pOut ){
1225 sqlite3_str_appendf(pOut, ",\"artifact\":null");
1226 }
1227 db_finalize(&q);
1228 if( flags & WHATIS_HASHONLY ) return;
1229
1230 /* Report any symbolic tags on this artifact */
@@ -1198,14 +1237,27 @@
1237 " ORDER BY 1",
1238 rid
1239 );
1240 cnt = 0;
1241 while( db_step(&q)==SQLITE_ROW ){
1242 const char *zTag = (const char*)db_column_text(&q,0);
1243 if( pOut ){
1244 const char *zSep = cnt==0 ? ",tags:[" : ",";
1245 sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1246 }else{
1247 const char *zPrefix = cnt ? ", " : "tags: ";
1248 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1249 }
1250 cnt++;
1251 }
1252 if( cnt ){
1253 if( pOut ){
1254 sqlite3_str_append(pOut, "]", 1);
1255 }else{
1256 fossil_print("\n");
1257 }
1258 }
1259 db_finalize(&q);
1260
1261 /* Report any HIDDEN, PRIVATE, CLUSTER, or CLOSED tags on this artifact */
1262 db_prepare(&q,
1263 "SELECT tagname"
@@ -1215,14 +1267,27 @@
1267 " ORDER BY 1",
1268 rid
1269 );
1270 cnt = 0;
1271 while( db_step(&q)==SQLITE_ROW ){
1272 const char *zTag = (const char*)db_column_text(&q,0);
1273 if( pOut ){
1274 const char *zSep = cnt==0 ? ",\"raw-tags\":[" : ",";
1275 sqlite3_str_appendf(pOut, "%s%J", zSep, zTag);
1276 }else{
1277 const char *zPrefix = cnt ? ", " : "raw-tags: ";
1278 fossil_print("%s%s", zPrefix, db_column_text(&q,0));
1279 }
1280 cnt++;
1281 }
1282 if( cnt ){
1283 if( pOut ){
1284 sqlite3_str_append(pOut, "]", 1);
1285 }else{
1286 fossil_print("\n");
1287 }
1288 }
1289 db_finalize(&q);
1290
1291 /* Check for entries on the timeline that reference this object */
1292 db_prepare(&q,
1293 "SELECT"
@@ -1244,17 +1309,21 @@
1309 case 'f': zType = "Forum-post"; break;
1310 case 't': zType = "Ticket-change"; break;
1311 case 'g': zType = "Tag-change"; break;
1312 default: zType = "Unknown"; break;
1313 }
1314 whatis_line(pOut, "type", "%s by %s on %s", zType, db_column_text(&q,2),
1315 db_column_text(&q, 1));
1316 if( eType=='t' && db_column_type(&q,4)==SQLITE_TEXT ){
1317 whatis_line(pOut, "ticket-id", "%s", db_column_text(&q,4));
1318 }
1319 if( pOut ){
1320 sqlite3_str_appendf(pOut, ",\"comment\":%J", db_column_text(&q,3));
1321 }else{
1322 fossil_print("comment: ");
1323 comment_print(db_column_text(&q,3), 0, 12, -1, get_comment_format());
1324 }
1325 cnt++;
1326 }
1327 db_finalize(&q);
1328
1329 /* Check to see if this object is used as a file in a check-in */
@@ -1271,20 +1340,25 @@
1340 " ORDER BY event.mtime %s /*sort*/",
1341 TAG_BRANCH, rid,
1342 (flags & WHATIS_BRIEF) ? "LIMIT 1" : "DESC");
1343 while( db_step(&q)==SQLITE_ROW ){
1344 if( flags & WHATIS_BRIEF ){
1345 whatis_line(pOut, "mtime","%s", db_column_text(&q,2));
1346 }
1347 if( pOut ){
1348 whatis_line(pOut,"file","%s", db_column_text(&q,0));
1349 whatis_line(pOut,"part-of","%s", db_column_text(&q,1));
1350 }else{
1351 fossil_print("file: %s\n", db_column_text(&q,0));
1352 fossil_print(" part of [%S] on branch %s by %s on %s\n",
1353 db_column_text(&q, 1),
1354 db_column_text(&q, 5),
1355 db_column_text(&q, 3),
1356 db_column_text(&q, 2));
1357 fossil_print(" ");
1358 comment_print(db_column_text(&q,4), 0, 12, -1, get_comment_format());
1359 }
1360 cnt++;
1361 }
1362 db_finalize(&q);
1363
1364 /* Check to see if this object is used as an attachment */
@@ -1303,30 +1377,36 @@
1377 " FROM attachment JOIN blob ON attachment.src=blob.uuid"
1378 " WHERE blob.rid=%d",
1379 rid
1380 );
1381 while( db_step(&q)==SQLITE_ROW ){
1382 if( pOut ){
1383 whatis_line(pOut, "attachment", "%s", db_column_text(&q,0));
1384 whatis_line(pOut, "attached-to", "%s %s",
1385 db_column_text(&q,5), db_column_text(&q,4));
 
 
1386 }else{
1387 fossil_print("attachment: %s\n", db_column_text(&q,0));
1388 fossil_print(" attached to %s %s\n",
1389 db_column_text(&q,5), db_column_text(&q,4));
1390 if( flags & WHATIS_VERBOSE ){
1391 fossil_print(" via %s (%d)\n",
1392 db_column_text(&q,7), db_column_int(&q,6));
1393 }else{
1394 fossil_print(" via %s\n",
1395 db_column_text(&q,7));
1396 }
1397 fossil_print(" by user %s on %s\n",
1398 db_column_text(&q,2), db_column_text(&q,3));
1399 fossil_print(" ");
1400 comment_print(db_column_text(&q,1), 0, 12, -1, get_comment_format());
1401 }
 
 
 
 
1402 cnt++;
1403 }
1404 db_finalize(&q);
1405
1406 /* If other information available, try to describe the object */
1407 if( cnt==0 && pOut==0 ){
1408 char *zWhere = mprintf("=%d", rid);
1409 char *zDesc;
1410 describe_artifacts(zWhere);
1411 free(zWhere);
1412 zDesc = db_text(0,
@@ -1333,25 +1413,33 @@
1413 "SELECT printf('%%-12s%%s %%s',type||':',summary,substr(ref,1,16))"
1414 " FROM description WHERE rid=%d", rid);
1415 fossil_print("%s\n", zDesc);
1416 fossil_free(zDesc);
1417 }
1418
1419 if( pOut ) sqlite3_str_append(pOut, "}", 1);
1420 }
1421
1422 /*
1423 ** Generate a description of artifact from it symbolic name.
1424 */
1425 void whatis_artifact(
1426 const char *zName, /* Symbolic name or full hash */
1427 const char *zFileName,/* Optional: original filename (in file mode) */
1428 const char *zType, /* Artifact type filter */
1429 int mFlags, /* WHATIS_* flags */
1430 sqlite3_str *pOut /* Write JSON here, if not NULL */
1431 ){
1432 int rid = symbolic_name_to_rid(zName, zType);
1433 size_t nName;
1434 char *zC = 0;
1435 int nTkt = 0;
1436
1437 if( pOut ){
1438 mFlags &= ~(WHATIS_HASHONLY|WHATIS_REPO);
1439 zFileName = 0;
1440 }
1441 if( (nName = strlen(zName))>=4 && validate16(zName,nName) ){
1442 zC = fossil_strdup(zName);
1443 canonical16(zC, nName);
1444 nTkt = db_int(0,"SELECT count(*) FROM tag WHERE tagname GLOB 'tkt-%q*'",zC);
1445 if( nTkt>0 ){
@@ -1376,18 +1464,28 @@
1464 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1465 }
1466 if( zFileName ){
1467 fossil_print("%-12s%s\n", "name:", zFileName);
1468 }
1469 if( pOut ){
1470 sqlite3_str_appendall(pOut, "{\"ambiguous\":[");
1471 }else{
1472 fossil_print("%-12s%s (ambiguous)\n", "hash:", zName);
1473 }
1474 db_prepare(&q,
1475 "SELECT rid FROM blob WHERE uuid>=lower(%Q) AND uuid<(lower(%Q)||'z')",
1476 zName, zName
1477 );
1478 while( db_step(&q)==SQLITE_ROW ){
1479 if( cnt++ ){
1480 if( pOut ){
1481 sqlite3_str_append(pOut, ",", 1);
1482 }else{
1483 fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1484 }
1485 }
1486 whatis_rid(db_column_int(&q, 0), mFlags, pOut);
1487 }
1488 db_finalize(&q);
1489 if( nTkt>0 ){
1490 db_prepare(&q,
1491 "SELECT (SELECT srcid FROM tagxref"
@@ -1396,34 +1494,41 @@
1494 " ORDER BY mtime LIMIT 1)"
1495 " FROM tag WHERE tagname GLOB 'tkt-%q*'",
1496 zC
1497 );
1498 while( db_step(&q)==SQLITE_ROW ){
1499 if( pOut ){
1500 sqlite3_str_append(pOut, ",", 1);
1501 }else{
1502 fossil_print("%12s---- meaning #%d ----\n", " ", cnt);
1503 }
1504 whatis_rid(db_column_int(&q, 0), mFlags, pOut);
1505 }
1506 db_finalize(&q);
1507 }
1508 if( pOut ) sqlite3_str_append(pOut, "]}", 2);
1509 }else if( rid==0 ){
1510 if( (mFlags & (WHATIS_OMIT_UNK|WHATIS_HASHONLY))==0 ){
1511 /* 0123456789 12 */
1512 if( zFileName ){
1513 fossil_print("%-12s%s\n", "name:", zFileName);
1514 }
1515 if( pOut ) sqlite3_str_append(pOut, "{", 1);
1516 whatis_line(pOut, "unknown", "%s", zName);
1517 if( pOut ) sqlite3_str_append(pOut, "}", 1);
1518 }
1519 }else{
1520 if( mFlags & WHATIS_REPO ){
1521 fossil_print("\nrepository: %s\n", g.zRepositoryName);
1522 }
1523 if( zFileName ){
1524 zName = zFileName;
1525 }
1526 if( (mFlags & WHATIS_HASHONLY)==0 && pOut==0 ){
1527 whatis_line(pOut, "name", "%s", zName);
1528 }
1529 whatis_rid(rid, mFlags, pOut);
1530 }
1531 fossil_free(zC);
1532 }
1533
1534 /*
@@ -1449,10 +1554,11 @@
1554 void whatis_cmd(void){
1555 int mFlags = 0;
1556 int fileFlag;
1557 int i;
1558 const char *zType = 0;
1559 sqlite3_str *pOut = 0;
1560 db_find_and_open_repository(0,0);
1561 if( find_option("verbose","v",0)!=0 ){
1562 mFlags |= WHATIS_VERBOSE;
1563 }
1564 if( find_option("hash","h",0)!=0 ){
@@ -1461,10 +1567,14 @@
1567 if( g.fQuiet ){
1568 mFlags |= WHATIS_OMIT_UNK | WHATIS_REPO;
1569 }
1570 fileFlag = find_option("file","f",0)!=0;
1571 zType = find_option("type",0,1);
1572
1573 if( find_option("json",0,0)!=0 ){ /* undocumented test option */
1574 pOut = sqlite3_str_new(0);
1575 }
1576
1577 /* We should be done with options.. */
1578 verify_all_options();
1579
1580 if( g.argc<3 ) usage("NAME ...");
@@ -1487,17 +1597,52 @@
1597 ** the primary hash name. */
1598 blob_reset(&hash);
1599 hname_hash(&in, 0, &hash);
1600 zHash = (const char*)blob_str(&hash);
1601 }
1602 whatis_artifact(zHash, zName, zType, mFlags, pOut);
1603 blob_reset(&hash);
1604 }else{
1605 whatis_artifact(zName, 0, zType, mFlags, pOut);
1606 }
1607 if( pOut ){
1608 fossil_print("%s\n", sqlite3_str_value(pOut));
1609 sqlite3_str_truncate(pOut, 0);
1610 }
1611 }
1612 if( pOut ) sqlite3_str_free(pOut);
1613 }
1614
1615 /*
1616 ** This is an SQL function that does the rough equivalent of the
1617 ** "whatis" command. The argument can be a text identifier, or a
1618 ** integer RID.
1619 */
1620 void whatis_sql_function(
1621 sqlite3_context *context,
1622 int argc,
1623 sqlite3_value **argv
1624 ){
1625 sqlite3_str *pOut = sqlite3_str_new(0);
1626 int n;
1627 assert( argc==1 );
1628 if( sqlite3_value_type(argv[0])==SQLITE_INTEGER ){
1629 int rid = sqlite3_value_int(argv[0]);
1630 whatis_rid(rid, 0, pOut);
1631 }else if( sqlite3_value_type(argv[0])==SQLITE_TEXT ){
1632 const char *zName = (const char*)sqlite3_value_text(argv[0]);
1633 whatis_artifact(zName, 0, 0, 0, pOut);
1634 }else{
1635 sqlite3_str_free(pOut);
1636 return;
1637 }
1638 n = sqlite3_str_length(pOut);
1639 sqlite3_result_text64(context, sqlite3_str_finish(pOut), n,
1640 sqlite3_free, SQLITE_UTF8);
1641 sqlite3_result_subtype(context, 'J');
1642 }
1643
1644
1645 /*
1646 ** COMMAND: test-whatis-all
1647 **
1648 ** Usage: %fossil test-whatis-all
@@ -1509,11 +1654,11 @@
1654 int cnt = 0;
1655 db_find_and_open_repository(0,0);
1656 db_prepare(&q, "SELECT rid FROM blob ORDER BY rid");
1657 while( db_step(&q)==SQLITE_ROW ){
1658 if( cnt++ ) fossil_print("%.79c\n", '-');
1659 whatis_rid(db_column_int(&q,0), 1, 0);
1660 }
1661 db_finalize(&q);
1662 }
1663
1664
1665
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -142,10 +142,12 @@
142142
}
143143
144144
/*
145145
** Add the content(), compress(), decompress(), and
146146
** gather_artifact_stats() SQL functions to database connection db.
147
+**
148
+** Also add whatis().
147149
*/
148150
int add_content_sql_commands(sqlite3 *db){
149151
sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
150152
sqlcmd_content, 0, 0);
151153
sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
@@ -152,10 +154,12 @@
152154
sqlcmd_compress, 0, 0);
153155
sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
154156
sqlcmd_decompress, 0, 0);
155157
sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0,
156158
sqlcmd_gather_artifact_stats, 0, 0);
159
+ sqlite3_create_function(db, "whatis", 1, SQLITE_UTF8|SQLITE_RESULT_SUBTYPE, 0,
160
+ whatis_sql_function, 0, 0);
157161
return SQLITE_OK;
158162
}
159163
160164
/*
161165
** Undocumented test SQL functions:
162166
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -142,10 +142,12 @@
142 }
143
144 /*
145 ** Add the content(), compress(), decompress(), and
146 ** gather_artifact_stats() SQL functions to database connection db.
 
 
147 */
148 int add_content_sql_commands(sqlite3 *db){
149 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
150 sqlcmd_content, 0, 0);
151 sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
@@ -152,10 +154,12 @@
152 sqlcmd_compress, 0, 0);
153 sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
154 sqlcmd_decompress, 0, 0);
155 sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0,
156 sqlcmd_gather_artifact_stats, 0, 0);
 
 
157 return SQLITE_OK;
158 }
159
160 /*
161 ** Undocumented test SQL functions:
162
--- src/sqlcmd.c
+++ src/sqlcmd.c
@@ -142,10 +142,12 @@
142 }
143
144 /*
145 ** Add the content(), compress(), decompress(), and
146 ** gather_artifact_stats() SQL functions to database connection db.
147 **
148 ** Also add whatis().
149 */
150 int add_content_sql_commands(sqlite3 *db){
151 sqlite3_create_function(db, "content", 1, SQLITE_UTF8, 0,
152 sqlcmd_content, 0, 0);
153 sqlite3_create_function(db, "compress", 1, SQLITE_UTF8, 0,
@@ -152,10 +154,12 @@
154 sqlcmd_compress, 0, 0);
155 sqlite3_create_function(db, "decompress", 1, SQLITE_UTF8, 0,
156 sqlcmd_decompress, 0, 0);
157 sqlite3_create_function(db, "gather_artifact_stats", 0, SQLITE_UTF8, 0,
158 sqlcmd_gather_artifact_stats, 0, 0);
159 sqlite3_create_function(db, "whatis", 1, SQLITE_UTF8|SQLITE_RESULT_SUBTYPE, 0,
160 whatis_sql_function, 0, 0);
161 return SQLITE_OK;
162 }
163
164 /*
165 ** Undocumented test SQL functions:
166

Keyboard Shortcuts

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