Fossil SCM

Updates to the "bisect" command. Add "bisect chart". Add the "display" option to choose the display to occur after "bisect next". Default the display to "chart".

drh 2013-06-21 05:31 UTC trunk
Commit 0a7af8d3a87cc966895f0bbfbd937515f6c662ec
1 file changed +81 -32
+81 -32
--- src/bisect.c
+++ src/bisect.c
@@ -65,10 +65,12 @@
6565
} aBisectOption[] = {
6666
{ "auto-next", "on", "Automatically run \"bisect next\" after each "
6767
"\"bisect good\" or \"bisect bad\"" },
6868
{ "direct-only", "on", "Follow only primary parent-child links, not "
6969
"merges\n" },
70
+ { "display", "chart", "Command to run after \"next\". \"chart\", "
71
+ "\"log\", \"status\", or \"none\"" },
7072
};
7173
7274
/*
7375
** Return the value of a boolean bisect option.
7476
*/
@@ -165,10 +167,61 @@
165167
db_multi_exec(
166168
"REPLACE INTO vvar(name,value) VALUES('bisect-log',"
167169
"COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
168170
" || '%d')", rid);
169171
}
172
+
173
+/*
174
+** Show a chart of bisect "good" and "bad" versions. The chart can be
175
+** sorted either chronologically by bisect time, or by check-in time.
176
+*/
177
+static void bisect_chart(int sortByCkinTime){
178
+ char *zLog = db_lget("bisect-log","");
179
+ Blob log, id;
180
+ Stmt q;
181
+ int cnt = 0;
182
+ blob_init(&log, zLog, -1);
183
+ db_multi_exec(
184
+ "CREATE TEMP TABLE bilog("
185
+ " seq INTEGER PRIMARY KEY," /* Sequence of events */
186
+ " stat TEXT," /* Type of occurrence */
187
+ " rid INTEGER" /* Check-in number */
188
+ ");"
189
+ );
190
+ db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)"
191
+ " VALUES(:seq,:stat,:rid)");
192
+ while( blob_token(&log, &id) ){
193
+ int rid = atoi(blob_str(&id));
194
+ db_bind_int(&q, ":seq", ++cnt);
195
+ db_bind_text(&q, ":stat", rid>0 ? "GOOD" : "BAD");
196
+ db_bind_int(&q, ":rid", rid>=0 ? rid : -rid);
197
+ db_step(&q);
198
+ db_reset(&q);
199
+ }
200
+ db_bind_int(&q, ":seq", ++cnt);
201
+ db_bind_text(&q, ":stat", "CURRENT");
202
+ db_bind_int(&q, ":rid", db_lget_int("checkout", 0));
203
+ db_step(&q);
204
+ db_finalize(&q);
205
+ db_prepare(&q,
206
+ "SELECT bilog.seq, bilog.stat,"
207
+ " substr(blob.uuid,1,16), datetime(event.mtime)"
208
+ " FROM bilog, blob, event"
209
+ " WHERE blob.rid=bilog.rid AND event.objid=bilog.rid"
210
+ " AND event.type='ci'"
211
+ " ORDER BY %s",
212
+ (sortByCkinTime ? "event.mtime DESC" : "bilog.rowid ASC")
213
+ );
214
+ while( db_step(&q)==SQLITE_ROW ){
215
+ fossil_print("%3d %-7s %s %s\n",
216
+ db_column_int(&q, 0),
217
+ db_column_text(&q, 1),
218
+ db_column_text(&q, 3),
219
+ db_column_text(&q, 2));
220
+ }
221
+ db_finalize(&q);
222
+}
170223
171224
/*
172225
** COMMAND: bisect
173226
**
174227
** Usage: %fossil bisect SUBCOMMAND ...
@@ -184,12 +237,15 @@
184237
**
185238
** Identify version VERSION as working. If VERSION is omitted,
186239
** the current checkout is marked as working.
187240
**
188241
** fossil bisect log
242
+** fossil bisect chart
189243
**
190
-** Show a log of "good" and "bad" versions
244
+** Show a log of "good" and "bad" versions. "bisect log" shows the
245
+** events in the order that they were tested. "bisect chart" shows
246
+** them in order of check-in.
191247
**
192248
** fossil bisect next
193249
**
194250
** Update to the next version that is halfway between the working and
195251
** non-working versions.
@@ -215,10 +271,11 @@
215271
** Summary:
216272
**
217273
** fossil bisect bad ?VERSION?
218274
** fossil bisect good ?VERSION?
219275
** fossil bisect log
276
+** fossil bisect chart
220277
** fossil bisect next
221278
** fossil bisect options
222279
** fossil bisect reset
223280
** fossil bisect status
224281
** fossil bisect undo
@@ -232,11 +289,11 @@
232289
usage("bad|good|log|next|options|reset|status|undo");
233290
}
234291
zCmd = g.argv[2];
235292
n = strlen(zCmd);
236293
if( n==0 ) zCmd = "-";
237
- if( memcmp(zCmd, "bad", n)==0 ){
294
+ if( strncmp(zCmd, "bad", n)==0 ){
238295
int ridBad;
239296
foundCmd = 1;
240297
if( g.argc==3 ){
241298
ridBad = db_lget_int("checkout",0);
242299
}else{
@@ -247,11 +304,11 @@
247304
if( bisect_option("auto-next") && db_lget_int("bisect-good",0)>0 ){
248305
zCmd = "next";
249306
n = 4;
250307
}
251308
}
252
- }else if( memcmp(zCmd, "good", n)==0 ){
309
+ }else if( strncmp(zCmd, "good", n)==0 ){
253310
int ridGood;
254311
foundCmd = 1;
255312
if( g.argc==3 ){
256313
ridGood = db_lget_int("checkout",0);
257314
}else{
@@ -262,11 +319,11 @@
262319
if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
263320
zCmd = "next";
264321
n = 4;
265322
}
266323
}
267
- }else if( memcmp(zCmd, "undo", n)==0 ){
324
+ }else if( strncmp(zCmd, "undo", n)==0 ){
268325
char *zLog;
269326
Blob log, id;
270327
int ridBad = 0;
271328
int ridGood = 0;
272329
int cnt = 0, i;
@@ -298,12 +355,14 @@
298355
n = 4;
299356
}
300357
}
301358
/* No else here so that the above commands can morph themselves into
302359
** a "next" command */
303
- if( memcmp(zCmd, "next", n)==0 ){
360
+ if( strncmp(zCmd, "next", n)==0 ){
304361
PathNode *pMid;
362
+ char *zDisplay = db_lget("bisect-display","chart");
363
+ int m = (int)strlen(zDisplay);
305364
bisect_path();
306365
pMid = path_midpoint();
307366
if( pMid==0 ){
308367
fossil_print("bisect complete\n");
309368
}else{
@@ -311,33 +370,23 @@
311370
g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
312371
g.argc = 3;
313372
g.fNoSync = 1;
314373
update_cmd();
315374
}
316
- bisect_list(1);
317
- }else if( memcmp(zCmd, "log", n)==0 ){
318
- char *zLog = db_lget("bisect-log","");
319
- Blob log, id;
320
- Stmt q;
321
- int cnt = 0;
322
- blob_init(&log, zLog, -1);
323
- db_prepare(&q, "SELECT substr(blob.uuid,1,16), datetime(event.mtime)"
324
- " FROM blob, event"
325
- " WHERE blob.rid=:rid AND event.objid=:rid"
326
- " AND event.type='ci'");
327
- while( blob_token(&log, &id) ){
328
- int rid = atoi(blob_str(&id));
329
- db_bind_int(&q, ":rid", rid<0 ? -rid : rid);
330
- if( db_step(&q)==SQLITE_ROW ){
331
- cnt++;
332
- fossil_print("%3d %-4s %s %s\n", cnt, rid<0 ? "BAD" : "GOOD",
333
- db_column_text(&q, 1), db_column_text(&q, 0));
334
- }
335
- db_reset(&q);
336
- }
337
- db_finalize(&q);
338
- }else if( memcmp(zCmd, "options", n)==0 ){
375
+
376
+ if( strncmp(zDisplay,"chart",m)==0 ){
377
+ bisect_chart(1);
378
+ }else if( strncmp(zDisplay, "log", m)==0 ){
379
+ bisect_chart(0);
380
+ }else if( strncmp(zDisplay, "status", m)==0 ){
381
+ bisect_list(1);
382
+ }
383
+ }else if( strncmp(zCmd, "log", n)==0 ){
384
+ bisect_chart(0);
385
+ }else if( strncmp(zCmd, "chart", n)==0 ){
386
+ bisect_chart(1);
387
+ }else if( strncmp(zCmd, "options", n)==0 ){
339388
if( g.argc==3 ){
340389
unsigned int i;
341390
for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){
342391
char *z = mprintf("bisect-%s", aBisectOption[i].zName);
343392
fossil_print(" %-15s %-6s ", aBisectOption[i].zName,
@@ -363,20 +412,20 @@
363412
fossil_fatal("no such bisect option: %s", g.argv[3]);
364413
}
365414
}else{
366415
usage("bisect option ?NAME? ?VALUE?");
367416
}
368
- }else if( memcmp(zCmd, "reset", n)==0 ){
417
+ }else if( strncmp(zCmd, "reset", n)==0 ){
369418
db_multi_exec(
370419
"DELETE FROM vvar WHERE name IN "
371420
" ('bisect-good', 'bisect-bad', 'bisect-log')"
372421
);
373
- }else if( memcmp(zCmd, "vlist", n)==0
374
- || memcmp(zCmd, "ls", n)==0
375
- || memcmp(zCmd, "status", n)==0
422
+ }else if( strncmp(zCmd, "vlist", n)==0
423
+ || strncmp(zCmd, "ls", n)==0
424
+ || strncmp(zCmd, "status", n)==0
376425
){
377426
int fAll = find_option("all", "a", 0)!=0;
378427
bisect_list(!fAll);
379428
}else if( !foundCmd ){
380429
usage("bad|good|log|next|options|reset|status|undo");
381430
}
382431
}
383432
--- src/bisect.c
+++ src/bisect.c
@@ -65,10 +65,12 @@
65 } aBisectOption[] = {
66 { "auto-next", "on", "Automatically run \"bisect next\" after each "
67 "\"bisect good\" or \"bisect bad\"" },
68 { "direct-only", "on", "Follow only primary parent-child links, not "
69 "merges\n" },
 
 
70 };
71
72 /*
73 ** Return the value of a boolean bisect option.
74 */
@@ -165,10 +167,61 @@
165 db_multi_exec(
166 "REPLACE INTO vvar(name,value) VALUES('bisect-log',"
167 "COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
168 " || '%d')", rid);
169 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
171 /*
172 ** COMMAND: bisect
173 **
174 ** Usage: %fossil bisect SUBCOMMAND ...
@@ -184,12 +237,15 @@
184 **
185 ** Identify version VERSION as working. If VERSION is omitted,
186 ** the current checkout is marked as working.
187 **
188 ** fossil bisect log
 
189 **
190 ** Show a log of "good" and "bad" versions
 
 
191 **
192 ** fossil bisect next
193 **
194 ** Update to the next version that is halfway between the working and
195 ** non-working versions.
@@ -215,10 +271,11 @@
215 ** Summary:
216 **
217 ** fossil bisect bad ?VERSION?
218 ** fossil bisect good ?VERSION?
219 ** fossil bisect log
 
220 ** fossil bisect next
221 ** fossil bisect options
222 ** fossil bisect reset
223 ** fossil bisect status
224 ** fossil bisect undo
@@ -232,11 +289,11 @@
232 usage("bad|good|log|next|options|reset|status|undo");
233 }
234 zCmd = g.argv[2];
235 n = strlen(zCmd);
236 if( n==0 ) zCmd = "-";
237 if( memcmp(zCmd, "bad", n)==0 ){
238 int ridBad;
239 foundCmd = 1;
240 if( g.argc==3 ){
241 ridBad = db_lget_int("checkout",0);
242 }else{
@@ -247,11 +304,11 @@
247 if( bisect_option("auto-next") && db_lget_int("bisect-good",0)>0 ){
248 zCmd = "next";
249 n = 4;
250 }
251 }
252 }else if( memcmp(zCmd, "good", n)==0 ){
253 int ridGood;
254 foundCmd = 1;
255 if( g.argc==3 ){
256 ridGood = db_lget_int("checkout",0);
257 }else{
@@ -262,11 +319,11 @@
262 if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
263 zCmd = "next";
264 n = 4;
265 }
266 }
267 }else if( memcmp(zCmd, "undo", n)==0 ){
268 char *zLog;
269 Blob log, id;
270 int ridBad = 0;
271 int ridGood = 0;
272 int cnt = 0, i;
@@ -298,12 +355,14 @@
298 n = 4;
299 }
300 }
301 /* No else here so that the above commands can morph themselves into
302 ** a "next" command */
303 if( memcmp(zCmd, "next", n)==0 ){
304 PathNode *pMid;
 
 
305 bisect_path();
306 pMid = path_midpoint();
307 if( pMid==0 ){
308 fossil_print("bisect complete\n");
309 }else{
@@ -311,33 +370,23 @@
311 g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
312 g.argc = 3;
313 g.fNoSync = 1;
314 update_cmd();
315 }
316 bisect_list(1);
317 }else if( memcmp(zCmd, "log", n)==0 ){
318 char *zLog = db_lget("bisect-log","");
319 Blob log, id;
320 Stmt q;
321 int cnt = 0;
322 blob_init(&log, zLog, -1);
323 db_prepare(&q, "SELECT substr(blob.uuid,1,16), datetime(event.mtime)"
324 " FROM blob, event"
325 " WHERE blob.rid=:rid AND event.objid=:rid"
326 " AND event.type='ci'");
327 while( blob_token(&log, &id) ){
328 int rid = atoi(blob_str(&id));
329 db_bind_int(&q, ":rid", rid<0 ? -rid : rid);
330 if( db_step(&q)==SQLITE_ROW ){
331 cnt++;
332 fossil_print("%3d %-4s %s %s\n", cnt, rid<0 ? "BAD" : "GOOD",
333 db_column_text(&q, 1), db_column_text(&q, 0));
334 }
335 db_reset(&q);
336 }
337 db_finalize(&q);
338 }else if( memcmp(zCmd, "options", n)==0 ){
339 if( g.argc==3 ){
340 unsigned int i;
341 for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){
342 char *z = mprintf("bisect-%s", aBisectOption[i].zName);
343 fossil_print(" %-15s %-6s ", aBisectOption[i].zName,
@@ -363,20 +412,20 @@
363 fossil_fatal("no such bisect option: %s", g.argv[3]);
364 }
365 }else{
366 usage("bisect option ?NAME? ?VALUE?");
367 }
368 }else if( memcmp(zCmd, "reset", n)==0 ){
369 db_multi_exec(
370 "DELETE FROM vvar WHERE name IN "
371 " ('bisect-good', 'bisect-bad', 'bisect-log')"
372 );
373 }else if( memcmp(zCmd, "vlist", n)==0
374 || memcmp(zCmd, "ls", n)==0
375 || memcmp(zCmd, "status", n)==0
376 ){
377 int fAll = find_option("all", "a", 0)!=0;
378 bisect_list(!fAll);
379 }else if( !foundCmd ){
380 usage("bad|good|log|next|options|reset|status|undo");
381 }
382 }
383
--- src/bisect.c
+++ src/bisect.c
@@ -65,10 +65,12 @@
65 } aBisectOption[] = {
66 { "auto-next", "on", "Automatically run \"bisect next\" after each "
67 "\"bisect good\" or \"bisect bad\"" },
68 { "direct-only", "on", "Follow only primary parent-child links, not "
69 "merges\n" },
70 { "display", "chart", "Command to run after \"next\". \"chart\", "
71 "\"log\", \"status\", or \"none\"" },
72 };
73
74 /*
75 ** Return the value of a boolean bisect option.
76 */
@@ -165,10 +167,61 @@
167 db_multi_exec(
168 "REPLACE INTO vvar(name,value) VALUES('bisect-log',"
169 "COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
170 " || '%d')", rid);
171 }
172
173 /*
174 ** Show a chart of bisect "good" and "bad" versions. The chart can be
175 ** sorted either chronologically by bisect time, or by check-in time.
176 */
177 static void bisect_chart(int sortByCkinTime){
178 char *zLog = db_lget("bisect-log","");
179 Blob log, id;
180 Stmt q;
181 int cnt = 0;
182 blob_init(&log, zLog, -1);
183 db_multi_exec(
184 "CREATE TEMP TABLE bilog("
185 " seq INTEGER PRIMARY KEY," /* Sequence of events */
186 " stat TEXT," /* Type of occurrence */
187 " rid INTEGER" /* Check-in number */
188 ");"
189 );
190 db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)"
191 " VALUES(:seq,:stat,:rid)");
192 while( blob_token(&log, &id) ){
193 int rid = atoi(blob_str(&id));
194 db_bind_int(&q, ":seq", ++cnt);
195 db_bind_text(&q, ":stat", rid>0 ? "GOOD" : "BAD");
196 db_bind_int(&q, ":rid", rid>=0 ? rid : -rid);
197 db_step(&q);
198 db_reset(&q);
199 }
200 db_bind_int(&q, ":seq", ++cnt);
201 db_bind_text(&q, ":stat", "CURRENT");
202 db_bind_int(&q, ":rid", db_lget_int("checkout", 0));
203 db_step(&q);
204 db_finalize(&q);
205 db_prepare(&q,
206 "SELECT bilog.seq, bilog.stat,"
207 " substr(blob.uuid,1,16), datetime(event.mtime)"
208 " FROM bilog, blob, event"
209 " WHERE blob.rid=bilog.rid AND event.objid=bilog.rid"
210 " AND event.type='ci'"
211 " ORDER BY %s",
212 (sortByCkinTime ? "event.mtime DESC" : "bilog.rowid ASC")
213 );
214 while( db_step(&q)==SQLITE_ROW ){
215 fossil_print("%3d %-7s %s %s\n",
216 db_column_int(&q, 0),
217 db_column_text(&q, 1),
218 db_column_text(&q, 3),
219 db_column_text(&q, 2));
220 }
221 db_finalize(&q);
222 }
223
224 /*
225 ** COMMAND: bisect
226 **
227 ** Usage: %fossil bisect SUBCOMMAND ...
@@ -184,12 +237,15 @@
237 **
238 ** Identify version VERSION as working. If VERSION is omitted,
239 ** the current checkout is marked as working.
240 **
241 ** fossil bisect log
242 ** fossil bisect chart
243 **
244 ** Show a log of "good" and "bad" versions. "bisect log" shows the
245 ** events in the order that they were tested. "bisect chart" shows
246 ** them in order of check-in.
247 **
248 ** fossil bisect next
249 **
250 ** Update to the next version that is halfway between the working and
251 ** non-working versions.
@@ -215,10 +271,11 @@
271 ** Summary:
272 **
273 ** fossil bisect bad ?VERSION?
274 ** fossil bisect good ?VERSION?
275 ** fossil bisect log
276 ** fossil bisect chart
277 ** fossil bisect next
278 ** fossil bisect options
279 ** fossil bisect reset
280 ** fossil bisect status
281 ** fossil bisect undo
@@ -232,11 +289,11 @@
289 usage("bad|good|log|next|options|reset|status|undo");
290 }
291 zCmd = g.argv[2];
292 n = strlen(zCmd);
293 if( n==0 ) zCmd = "-";
294 if( strncmp(zCmd, "bad", n)==0 ){
295 int ridBad;
296 foundCmd = 1;
297 if( g.argc==3 ){
298 ridBad = db_lget_int("checkout",0);
299 }else{
@@ -247,11 +304,11 @@
304 if( bisect_option("auto-next") && db_lget_int("bisect-good",0)>0 ){
305 zCmd = "next";
306 n = 4;
307 }
308 }
309 }else if( strncmp(zCmd, "good", n)==0 ){
310 int ridGood;
311 foundCmd = 1;
312 if( g.argc==3 ){
313 ridGood = db_lget_int("checkout",0);
314 }else{
@@ -262,11 +319,11 @@
319 if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
320 zCmd = "next";
321 n = 4;
322 }
323 }
324 }else if( strncmp(zCmd, "undo", n)==0 ){
325 char *zLog;
326 Blob log, id;
327 int ridBad = 0;
328 int ridGood = 0;
329 int cnt = 0, i;
@@ -298,12 +355,14 @@
355 n = 4;
356 }
357 }
358 /* No else here so that the above commands can morph themselves into
359 ** a "next" command */
360 if( strncmp(zCmd, "next", n)==0 ){
361 PathNode *pMid;
362 char *zDisplay = db_lget("bisect-display","chart");
363 int m = (int)strlen(zDisplay);
364 bisect_path();
365 pMid = path_midpoint();
366 if( pMid==0 ){
367 fossil_print("bisect complete\n");
368 }else{
@@ -311,33 +370,23 @@
370 g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
371 g.argc = 3;
372 g.fNoSync = 1;
373 update_cmd();
374 }
375
376 if( strncmp(zDisplay,"chart",m)==0 ){
377 bisect_chart(1);
378 }else if( strncmp(zDisplay, "log", m)==0 ){
379 bisect_chart(0);
380 }else if( strncmp(zDisplay, "status", m)==0 ){
381 bisect_list(1);
382 }
383 }else if( strncmp(zCmd, "log", n)==0 ){
384 bisect_chart(0);
385 }else if( strncmp(zCmd, "chart", n)==0 ){
386 bisect_chart(1);
387 }else if( strncmp(zCmd, "options", n)==0 ){
 
 
 
 
 
 
 
 
 
 
388 if( g.argc==3 ){
389 unsigned int i;
390 for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){
391 char *z = mprintf("bisect-%s", aBisectOption[i].zName);
392 fossil_print(" %-15s %-6s ", aBisectOption[i].zName,
@@ -363,20 +412,20 @@
412 fossil_fatal("no such bisect option: %s", g.argv[3]);
413 }
414 }else{
415 usage("bisect option ?NAME? ?VALUE?");
416 }
417 }else if( strncmp(zCmd, "reset", n)==0 ){
418 db_multi_exec(
419 "DELETE FROM vvar WHERE name IN "
420 " ('bisect-good', 'bisect-bad', 'bisect-log')"
421 );
422 }else if( strncmp(zCmd, "vlist", n)==0
423 || strncmp(zCmd, "ls", n)==0
424 || strncmp(zCmd, "status", n)==0
425 ){
426 int fAll = find_option("all", "a", 0)!=0;
427 bisect_list(!fAll);
428 }else if( !foundCmd ){
429 usage("bad|good|log|next|options|reset|status|undo");
430 }
431 }
432

Keyboard Shortcuts

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