Fossil SCM

Enhance the "vdiff" web method so that it shows the differences between to arbitrary check-ins identified by the "from" and "to" query parameters.

drh 2010-08-07 18:09 trunk
Commit 1d713f3f4d2292573363cf3b731ee3517a76fb5c
1 file changed +160 -88
+160 -88
--- src/info.c
+++ src/info.c
@@ -238,10 +238,51 @@
238238
blob_reset(&from);
239239
blob_reset(&to);
240240
blob_reset(&out);
241241
}
242242
243
+/*
244
+** Write a line of web-page output that shows changes that have occurred
245
+** to a file between two check-ins.
246
+*/
247
+static void append_file_change_line(
248
+ const char *zName, /* Name of the file that has changed */
249
+ const char *zOld, /* blob.uuid before change. NULL for added files */
250
+ const char *zNew, /* blob.uuid after change. NULL for deletes */
251
+ int showDiff /* Show edit diffs if true */
252
+){
253
+ if( !g.okHistory ){
254
+ if( zNew==0 ){
255
+ @ <p>Deleted %h(zName)</p>
256
+ }else if( zOld==0 ){
257
+ @ <p>Added %h(zName)</p>
258
+ }else{
259
+ @ <p>Changes to %h(zName)</p>
260
+ }
261
+ }else if( zOld && zNew ){
262
+ @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
263
+ @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
264
+ @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
265
+ if( !showDiff ){
266
+ @ &nbsp;&nbsp;
267
+ @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a>
268
+ }else{
269
+ int rid1 = uuid_to_rid(zOld, 0);
270
+ int rid2 = uuid_to_rid(zNew, 0);
271
+ @ <blockquote><pre>
272
+ append_diff(rid1, rid2);
273
+ @ </pre></blockquote>
274
+ }
275
+ }else if( zOld ){
276
+ @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
277
+ @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a></p>
278
+ }else{
279
+ @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
280
+ @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a></p>
281
+ }
282
+}
283
+
243284
244285
/*
245286
** WEBPAGE: vinfo
246287
** WEBPAGE: ci
247288
** URL: /ci?name=RID|ARTIFACTID
@@ -391,52 +432,23 @@
391432
}else{
392433
@ <a href="%s(g.zBaseURL)/vinfo/%T(zName)">[show&nbsp;diffs]</a><br/>
393434
}
394435
}
395436
db_prepare(&q,
396
- "SELECT pid, fid, name,"
437
+ "SELECT name,"
397438
" (SELECT uuid FROM blob WHERE rid=mlink.pid),"
398439
" (SELECT uuid FROM blob WHERE rid=mlink.fid)"
399440
" FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
400441
" WHERE mlink.mid=%d"
401442
" ORDER BY name",
402443
rid
403444
);
404445
while( db_step(&q)==SQLITE_ROW ){
405
- int pid = db_column_int(&q,0);
406
- int fid = db_column_int(&q,1);
407
- const char *zName = db_column_text(&q,2);
408
- const char *zOld = db_column_text(&q,3);
409
- const char *zNew = db_column_text(&q,4);
410
- if( !g.okHistory ){
411
- if( zNew==0 ){
412
- @ <p>Deleted %h(zName)</p>
413
- continue;
414
- }else{
415
- @ <p>Changes to %h(zName)</p>
416
- }
417
- }else if( zOld && zNew ){
418
- @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
419
- @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
420
- @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
421
- if( !showDiff ){
422
- @ &nbsp;&nbsp;
423
- @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a>
424
- }
425
- }else if( zOld ){
426
- @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
427
- @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a></p>
428
- continue;
429
- }else{
430
- @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
431
- @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a></p>
432
- }
433
- if( showDiff ){
434
- @ <blockquote><pre>
435
- append_diff(pid, fid);
436
- @ </pre></blockquote>
437
- }
446
+ const char *zName = db_column_text(&q,0);
447
+ const char *zOld = db_column_text(&q,1);
448
+ const char *zNew = db_column_text(&q,2);
449
+ append_file_change_line(zName, zOld, zNew, showDiff);
438450
}
439451
db_finalize(&q);
440452
style_footer();
441453
}
442454
@@ -520,76 +532,135 @@
520532
}
521533
manifest_clear(&m);
522534
}
523535
style_footer();
524536
}
537
+
538
+/*
539
+** Show a webpage error message
540
+*/
541
+void webpage_error(const char *zFormat, ...){
542
+ va_list ap;
543
+ const char *z;
544
+ va_start(ap, zFormat);
545
+ z = vmprintf(zFormat, ap);
546
+ va_end(ap);
547
+ style_header("URL Error");
548
+ @ <h1>Error</h1>
549
+ @ <p>%h(z)</p>
550
+ style_footer();
551
+}
552
+
553
+/*
554
+** Find an checkin based on query parameter zParam and parse its
555
+** manifest. Return the number of errors.
556
+*/
557
+static int vdiff_parse_manifest(const char *zParam, int *pRid, Manifest *pM){
558
+ int rid;
559
+ Blob content;
560
+
561
+ *pRid = rid = name_to_rid_www(zParam);
562
+ if( rid==0 ){
563
+ webpage_error("Missing \"%s\" query parameter.", zParam);
564
+ return 1;
565
+ }
566
+ if( !is_a_version(rid) ){
567
+ webpage_error("Artifact %s is not a checkin.", P(zParam));
568
+ return 1;
569
+ }
570
+ content_get(rid, &content);
571
+ manifest_parse(pM, &content);
572
+ return 0;
573
+}
574
+
575
+/*
576
+** Output a description of a check-in
577
+*/
578
+void checkin_description(int rid){
579
+ Stmt q;
580
+ db_prepare(&q,
581
+ "SELECT datetime(mtime), coalesce(euser,user),"
582
+ " coalesce(ecomment,comment), uuid"
583
+ " FROM event, blob"
584
+ " WHERE event.objid=%d AND type='ci'"
585
+ " AND blob.rid=%d",
586
+ rid, rid
587
+ );
588
+ while( db_step(&q)==SQLITE_ROW ){
589
+ const char *zDate = db_column_text(&q, 0);
590
+ const char *zUser = db_column_text(&q, 1);
591
+ const char *zCom = db_column_text(&q, 2);
592
+ const char *zUuid = db_column_text(&q, 3);
593
+ @ Check-in
594
+ hyperlink_to_uuid(zUuid);
595
+ @ - %w(zCom) by
596
+ hyperlink_to_user(zUser,zDate," on");
597
+ hyperlink_to_date(zDate, ".");
598
+ }
599
+ db_finalize(&q);
600
+}
601
+
525602
526603
/*
527604
** WEBPAGE: vdiff
528
-** URL: /vdiff?name=RID
605
+** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN
529606
**
530
-** Show all differences for a particular check-in.
607
+** Show all differences between two checkins.
531608
*/
532609
void vdiff_page(void){
533
- int rid;
534
- Stmt q;
535
- char *zUuid;
610
+ int ridFrom, ridTo;
611
+ int showDetail = 0;
612
+ int iFrom, iTo;
613
+ Manifest mFrom, mTo;
536614
537615
login_check_credentials();
538616
if( !g.okRead ){ login_needed(); return; }
539617
login_anonymous_available();
540618
541
- rid = name_to_rid_www("name");
542
- if( rid==0 ){
543
- fossil_redirect_home();
544
- }
545
- zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
546
- style_header("Check-in [%.10s]", zUuid);
547
- db_prepare(&q,
548
- "SELECT datetime(mtime), "
549
- " coalesce(event.ecomment,event.comment),"
550
- " coalesce(event.euser,event.user)"
551
- " FROM event WHERE type='ci' AND objid=%d",
552
- rid
553
- );
554
- while( db_step(&q)==SQLITE_ROW ){
555
- const char *zDate = db_column_text(&q, 0);
556
- const char *zUser = db_column_text(&q, 2);
557
- const char *zComment = db_column_text(&q, 1);
558
- @ <h2>Check-in %s(zUuid)</h2>
559
- @ <p>Made by
560
- hyperlink_to_user(zUser,zDate," on");
561
- hyperlink_to_date(zDate, ":");
562
- @ %w(zComment).
563
- if( g.okHistory ){
564
- @ <a href="%s(g.zBaseURL)/ci/%s(zUuid)">[details]</a>
565
- }
566
- @ </p><hr>
567
- }
568
- db_finalize(&q);
569
- db_prepare(&q,
570
- "SELECT pid, fid, name"
571
- " FROM mlink, filename"
572
- " WHERE mlink.mid=%d"
573
- " AND filename.fnid=mlink.fnid"
574
- " ORDER BY name",
575
- rid
576
- );
577
- while( db_step(&q)==SQLITE_ROW ){
578
- int pid = db_column_int(&q,0);
579
- int fid = db_column_int(&q,1);
580
- const char *zName = db_column_text(&q,2);
581
- if( g.okHistory ){
582
- @ <p><a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></p>
619
+ if( vdiff_parse_manifest("from", &ridFrom, &mFrom) ) return;
620
+ if( vdiff_parse_manifest("to", &ridTo, &mTo) ) return;
621
+ showDetail = atoi(PD("detail","0"));
622
+ style_header("Check-in Differences");
623
+ @ <h2>Difference From:</h2><blockquote>
624
+ checkin_description(ridFrom);
625
+ @ </blockquote><h2>To:</h2><blockquote>
626
+ checkin_description(ridTo);
627
+ @ </blockquote><hr><p>
628
+
629
+ iFrom = iTo = 0;
630
+ while( iFrom<mFrom.nFile && iTo<mTo.nFile ){
631
+ int cmp;
632
+ if( iFrom>=mFrom.nFile ){
633
+ cmp = +1;
634
+ }else if( iTo>=mTo.nFile ){
635
+ cmp = -1;
636
+ }else{
637
+ cmp = strcmp(mFrom.aFile[iFrom].zName, mTo.aFile[iTo].zName);
638
+ }
639
+ if( cmp<0 ){
640
+ append_file_change_line(mFrom.aFile[iFrom].zName,
641
+ mFrom.aFile[iFrom].zUuid, 0, 0);
642
+ iFrom++;
643
+ }else if( cmp>0 ){
644
+ append_file_change_line(mTo.aFile[iTo].zName,
645
+ 0, mTo.aFile[iTo].zUuid, 0);
646
+ iTo++;
647
+ }else if( strcmp(mFrom.aFile[iFrom].zUuid, mTo.aFile[iTo].zUuid)==0 ){
648
+ /* No changes */
649
+ iFrom++;
650
+ iTo++;
583651
}else{
584
- @ <p>%h(zName)</p>
652
+ append_file_change_line(mFrom.aFile[iFrom].zName,
653
+ mFrom.aFile[iFrom].zUuid,
654
+ mTo.aFile[iTo].zUuid, showDetail);
655
+ iFrom++;
656
+ iTo++;
585657
}
586
- @ <blockquote><pre>
587
- append_diff(pid, fid);
588
- @ </pre></blockquote>
589658
}
590
- db_finalize(&q);
659
+ manifest_clear(&mFrom);
660
+ manifest_clear(&mTo);
661
+
591662
style_footer();
592663
}
593664
594665
/*
595666
** Write a description of an object to the www reply.
@@ -783,16 +854,17 @@
783854
**
784855
** Two arguments, v1 and v2, are integers. Show the difference between
785856
** the two records.
786857
*/
787858
void diff_page(void){
788
- int v1 = name_to_rid(P("v1"));
789
- int v2 = name_to_rid(P("v2"));
859
+ int v1, v2;
790860
Blob c1, c2, diff;
791861
792862
login_check_credentials();
793863
if( !g.okRead ){ login_needed(); return; }
864
+ v1 = name_to_rid_www("v1");
865
+ v2 = name_to_rid_www("v2");
794866
if( v1==0 || v2==0 ) fossil_redirect_home();
795867
style_header("Diff");
796868
@ <h2>Differences From:</h2>
797869
@ <blockquote>
798870
object_description(v1, 1, 0);
799871
--- src/info.c
+++ src/info.c
@@ -238,10 +238,51 @@
238 blob_reset(&from);
239 blob_reset(&to);
240 blob_reset(&out);
241 }
242
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
244 /*
245 ** WEBPAGE: vinfo
246 ** WEBPAGE: ci
247 ** URL: /ci?name=RID|ARTIFACTID
@@ -391,52 +432,23 @@
391 }else{
392 @ <a href="%s(g.zBaseURL)/vinfo/%T(zName)">[show&nbsp;diffs]</a><br/>
393 }
394 }
395 db_prepare(&q,
396 "SELECT pid, fid, name,"
397 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
398 " (SELECT uuid FROM blob WHERE rid=mlink.fid)"
399 " FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
400 " WHERE mlink.mid=%d"
401 " ORDER BY name",
402 rid
403 );
404 while( db_step(&q)==SQLITE_ROW ){
405 int pid = db_column_int(&q,0);
406 int fid = db_column_int(&q,1);
407 const char *zName = db_column_text(&q,2);
408 const char *zOld = db_column_text(&q,3);
409 const char *zNew = db_column_text(&q,4);
410 if( !g.okHistory ){
411 if( zNew==0 ){
412 @ <p>Deleted %h(zName)</p>
413 continue;
414 }else{
415 @ <p>Changes to %h(zName)</p>
416 }
417 }else if( zOld && zNew ){
418 @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
419 @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
420 @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
421 if( !showDiff ){
422 @ &nbsp;&nbsp;
423 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a>
424 }
425 }else if( zOld ){
426 @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
427 @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a></p>
428 continue;
429 }else{
430 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
431 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a></p>
432 }
433 if( showDiff ){
434 @ <blockquote><pre>
435 append_diff(pid, fid);
436 @ </pre></blockquote>
437 }
438 }
439 db_finalize(&q);
440 style_footer();
441 }
442
@@ -520,76 +532,135 @@
520 }
521 manifest_clear(&m);
522 }
523 style_footer();
524 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
525
526 /*
527 ** WEBPAGE: vdiff
528 ** URL: /vdiff?name=RID
529 **
530 ** Show all differences for a particular check-in.
531 */
532 void vdiff_page(void){
533 int rid;
534 Stmt q;
535 char *zUuid;
 
536
537 login_check_credentials();
538 if( !g.okRead ){ login_needed(); return; }
539 login_anonymous_available();
540
541 rid = name_to_rid_www("name");
542 if( rid==0 ){
543 fossil_redirect_home();
544 }
545 zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
546 style_header("Check-in [%.10s]", zUuid);
547 db_prepare(&q,
548 "SELECT datetime(mtime), "
549 " coalesce(event.ecomment,event.comment),"
550 " coalesce(event.euser,event.user)"
551 " FROM event WHERE type='ci' AND objid=%d",
552 rid
553 );
554 while( db_step(&q)==SQLITE_ROW ){
555 const char *zDate = db_column_text(&q, 0);
556 const char *zUser = db_column_text(&q, 2);
557 const char *zComment = db_column_text(&q, 1);
558 @ <h2>Check-in %s(zUuid)</h2>
559 @ <p>Made by
560 hyperlink_to_user(zUser,zDate," on");
561 hyperlink_to_date(zDate, ":");
562 @ %w(zComment).
563 if( g.okHistory ){
564 @ <a href="%s(g.zBaseURL)/ci/%s(zUuid)">[details]</a>
565 }
566 @ </p><hr>
567 }
568 db_finalize(&q);
569 db_prepare(&q,
570 "SELECT pid, fid, name"
571 " FROM mlink, filename"
572 " WHERE mlink.mid=%d"
573 " AND filename.fnid=mlink.fnid"
574 " ORDER BY name",
575 rid
576 );
577 while( db_step(&q)==SQLITE_ROW ){
578 int pid = db_column_int(&q,0);
579 int fid = db_column_int(&q,1);
580 const char *zName = db_column_text(&q,2);
581 if( g.okHistory ){
582 @ <p><a href="%s(g.zBaseURL)/finfo?name=%T(zName)">%h(zName)</a></p>
583 }else{
584 @ <p>%h(zName)</p>
 
 
 
 
585 }
586 @ <blockquote><pre>
587 append_diff(pid, fid);
588 @ </pre></blockquote>
589 }
590 db_finalize(&q);
 
 
591 style_footer();
592 }
593
594 /*
595 ** Write a description of an object to the www reply.
@@ -783,16 +854,17 @@
783 **
784 ** Two arguments, v1 and v2, are integers. Show the difference between
785 ** the two records.
786 */
787 void diff_page(void){
788 int v1 = name_to_rid(P("v1"));
789 int v2 = name_to_rid(P("v2"));
790 Blob c1, c2, diff;
791
792 login_check_credentials();
793 if( !g.okRead ){ login_needed(); return; }
 
 
794 if( v1==0 || v2==0 ) fossil_redirect_home();
795 style_header("Diff");
796 @ <h2>Differences From:</h2>
797 @ <blockquote>
798 object_description(v1, 1, 0);
799
--- src/info.c
+++ src/info.c
@@ -238,10 +238,51 @@
238 blob_reset(&from);
239 blob_reset(&to);
240 blob_reset(&out);
241 }
242
243 /*
244 ** Write a line of web-page output that shows changes that have occurred
245 ** to a file between two check-ins.
246 */
247 static void append_file_change_line(
248 const char *zName, /* Name of the file that has changed */
249 const char *zOld, /* blob.uuid before change. NULL for added files */
250 const char *zNew, /* blob.uuid after change. NULL for deletes */
251 int showDiff /* Show edit diffs if true */
252 ){
253 if( !g.okHistory ){
254 if( zNew==0 ){
255 @ <p>Deleted %h(zName)</p>
256 }else if( zOld==0 ){
257 @ <p>Added %h(zName)</p>
258 }else{
259 @ <p>Changes to %h(zName)</p>
260 }
261 }else if( zOld && zNew ){
262 @ <p>Modified <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
263 @ from <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a>
264 @ to <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)].</a>
265 if( !showDiff ){
266 @ &nbsp;&nbsp;
267 @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)">[diff]</a>
268 }else{
269 int rid1 = uuid_to_rid(zOld, 0);
270 int rid2 = uuid_to_rid(zNew, 0);
271 @ <blockquote><pre>
272 append_diff(rid1, rid2);
273 @ </pre></blockquote>
274 }
275 }else if( zOld ){
276 @ <p>Deleted <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
277 @ version <a href="%s(g.zTop)/artifact/%s(zOld)">[%S(zOld)]</a></p>
278 }else{
279 @ <p>Added <a href="%s(g.zTop)/finfo?name=%T(zName)">%h(zName)</a>
280 @ version <a href="%s(g.zTop)/artifact/%s(zNew)">[%S(zNew)]</a></p>
281 }
282 }
283
284
285 /*
286 ** WEBPAGE: vinfo
287 ** WEBPAGE: ci
288 ** URL: /ci?name=RID|ARTIFACTID
@@ -391,52 +432,23 @@
432 }else{
433 @ <a href="%s(g.zBaseURL)/vinfo/%T(zName)">[show&nbsp;diffs]</a><br/>
434 }
435 }
436 db_prepare(&q,
437 "SELECT name,"
438 " (SELECT uuid FROM blob WHERE rid=mlink.pid),"
439 " (SELECT uuid FROM blob WHERE rid=mlink.fid)"
440 " FROM mlink JOIN filename ON filename.fnid=mlink.fnid"
441 " WHERE mlink.mid=%d"
442 " ORDER BY name",
443 rid
444 );
445 while( db_step(&q)==SQLITE_ROW ){
446 const char *zName = db_column_text(&q,0);
447 const char *zOld = db_column_text(&q,1);
448 const char *zNew = db_column_text(&q,2);
449 append_file_change_line(zName, zOld, zNew, showDiff);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450 }
451 db_finalize(&q);
452 style_footer();
453 }
454
@@ -520,76 +532,135 @@
532 }
533 manifest_clear(&m);
534 }
535 style_footer();
536 }
537
538 /*
539 ** Show a webpage error message
540 */
541 void webpage_error(const char *zFormat, ...){
542 va_list ap;
543 const char *z;
544 va_start(ap, zFormat);
545 z = vmprintf(zFormat, ap);
546 va_end(ap);
547 style_header("URL Error");
548 @ <h1>Error</h1>
549 @ <p>%h(z)</p>
550 style_footer();
551 }
552
553 /*
554 ** Find an checkin based on query parameter zParam and parse its
555 ** manifest. Return the number of errors.
556 */
557 static int vdiff_parse_manifest(const char *zParam, int *pRid, Manifest *pM){
558 int rid;
559 Blob content;
560
561 *pRid = rid = name_to_rid_www(zParam);
562 if( rid==0 ){
563 webpage_error("Missing \"%s\" query parameter.", zParam);
564 return 1;
565 }
566 if( !is_a_version(rid) ){
567 webpage_error("Artifact %s is not a checkin.", P(zParam));
568 return 1;
569 }
570 content_get(rid, &content);
571 manifest_parse(pM, &content);
572 return 0;
573 }
574
575 /*
576 ** Output a description of a check-in
577 */
578 void checkin_description(int rid){
579 Stmt q;
580 db_prepare(&q,
581 "SELECT datetime(mtime), coalesce(euser,user),"
582 " coalesce(ecomment,comment), uuid"
583 " FROM event, blob"
584 " WHERE event.objid=%d AND type='ci'"
585 " AND blob.rid=%d",
586 rid, rid
587 );
588 while( db_step(&q)==SQLITE_ROW ){
589 const char *zDate = db_column_text(&q, 0);
590 const char *zUser = db_column_text(&q, 1);
591 const char *zCom = db_column_text(&q, 2);
592 const char *zUuid = db_column_text(&q, 3);
593 @ Check-in
594 hyperlink_to_uuid(zUuid);
595 @ - %w(zCom) by
596 hyperlink_to_user(zUser,zDate," on");
597 hyperlink_to_date(zDate, ".");
598 }
599 db_finalize(&q);
600 }
601
602
603 /*
604 ** WEBPAGE: vdiff
605 ** URL: /vdiff?from=UUID&to=UUID&detail=BOOLEAN
606 **
607 ** Show all differences between two checkins.
608 */
609 void vdiff_page(void){
610 int ridFrom, ridTo;
611 int showDetail = 0;
612 int iFrom, iTo;
613 Manifest mFrom, mTo;
614
615 login_check_credentials();
616 if( !g.okRead ){ login_needed(); return; }
617 login_anonymous_available();
618
619 if( vdiff_parse_manifest("from", &ridFrom, &mFrom) ) return;
620 if( vdiff_parse_manifest("to", &ridTo, &mTo) ) return;
621 showDetail = atoi(PD("detail","0"));
622 style_header("Check-in Differences");
623 @ <h2>Difference From:</h2><blockquote>
624 checkin_description(ridFrom);
625 @ </blockquote><h2>To:</h2><blockquote>
626 checkin_description(ridTo);
627 @ </blockquote><hr><p>
628
629 iFrom = iTo = 0;
630 while( iFrom<mFrom.nFile && iTo<mTo.nFile ){
631 int cmp;
632 if( iFrom>=mFrom.nFile ){
633 cmp = +1;
634 }else if( iTo>=mTo.nFile ){
635 cmp = -1;
636 }else{
637 cmp = strcmp(mFrom.aFile[iFrom].zName, mTo.aFile[iTo].zName);
638 }
639 if( cmp<0 ){
640 append_file_change_line(mFrom.aFile[iFrom].zName,
641 mFrom.aFile[iFrom].zUuid, 0, 0);
642 iFrom++;
643 }else if( cmp>0 ){
644 append_file_change_line(mTo.aFile[iTo].zName,
645 0, mTo.aFile[iTo].zUuid, 0);
646 iTo++;
647 }else if( strcmp(mFrom.aFile[iFrom].zUuid, mTo.aFile[iTo].zUuid)==0 ){
648 /* No changes */
649 iFrom++;
650 iTo++;
 
 
 
 
 
 
 
 
 
 
651 }else{
652 append_file_change_line(mFrom.aFile[iFrom].zName,
653 mFrom.aFile[iFrom].zUuid,
654 mTo.aFile[iTo].zUuid, showDetail);
655 iFrom++;
656 iTo++;
657 }
 
 
 
658 }
659 manifest_clear(&mFrom);
660 manifest_clear(&mTo);
661
662 style_footer();
663 }
664
665 /*
666 ** Write a description of an object to the www reply.
@@ -783,16 +854,17 @@
854 **
855 ** Two arguments, v1 and v2, are integers. Show the difference between
856 ** the two records.
857 */
858 void diff_page(void){
859 int v1, v2;
 
860 Blob c1, c2, diff;
861
862 login_check_credentials();
863 if( !g.okRead ){ login_needed(); return; }
864 v1 = name_to_rid_www("v1");
865 v2 = name_to_rid_www("v2");
866 if( v1==0 || v2==0 ) fossil_redirect_home();
867 style_header("Diff");
868 @ <h2>Differences From:</h2>
869 @ <blockquote>
870 object_description(v1, 1, 0);
871

Keyboard Shortcuts

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