Fossil SCM
Add support for annotation in the web interface.
Commit
eae7ddfa4e7a5ae90feda01d3c664c1b852d0e3f
Parent
c8da83ca36c0d9a…
2 files changed
+99
+5
-1
+99
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -704,5 +704,104 @@ | ||
| 704 | 704 | const char *zSrc = x.aOrig[i].zSrc; |
| 705 | 705 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 706 | 706 | printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 707 | 707 | } |
| 708 | 708 | } |
| 709 | + | |
| 710 | +/* | |
| 711 | +** Create an annotation string based on the manifest id. | |
| 712 | +*/ | |
| 713 | +static char *annotation_label(int mid, int webLabel){ | |
| 714 | + char *z; | |
| 715 | + z = db_text("?", | |
| 716 | + "SELECT" | |
| 717 | + " substr(blob.uuid,1,10) ||" | |
| 718 | + " ' ' || date(event.mtime) ||" | |
| 719 | + " ' (' || substr(event.user || ' ',1,9) || ')'" | |
| 720 | + " FROM blob, event" | |
| 721 | + " WHERE blob.rid=%d" | |
| 722 | + " AND event.objid=%d" | |
| 723 | + " AND event.type='ci'", | |
| 724 | + mid, mid | |
| 725 | + ); | |
| 726 | + return z; | |
| 727 | +} | |
| 728 | + | |
| 729 | +/* | |
| 730 | +** Compute a complete annotation on a file. The file is identified | |
| 731 | +** by its filename number (filename.fnid) and the baseline in which | |
| 732 | +** it was checked in (mlink.mid). | |
| 733 | +*/ | |
| 734 | +static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ | |
| 735 | + Blob toAnnotate; /* Text of the final version of the file */ | |
| 736 | + Blob step; /* Text of previous revision */ | |
| 737 | + int rid; | |
| 738 | + int fromid; | |
| 739 | + char *zLabel; | |
| 740 | + int i; | |
| 741 | + | |
| 742 | + /* Initialize the annotation */ | |
| 743 | + rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); | |
| 744 | + if( rid==0 ){ | |
| 745 | + fossil_panic("no changes to file #%d in manifest #%d", fnid, mid); | |
| 746 | + } | |
| 747 | + if( !content_get(rid, &toAnnotate) ){ | |
| 748 | + fossil_panic("unable to retrieve content of artifact #%d", rid); | |
| 749 | + } | |
| 750 | + annotation_start(p, &toAnnotate); | |
| 751 | + fromid = db_int(0,"SELECT pid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); | |
| 752 | + zLabel = annotation_label(mid, webLabel); | |
| 753 | + if( fromid ){ | |
| 754 | + content_get(fromid, &step); | |
| 755 | + annotation_step(p, &step, zLabel); | |
| 756 | + } | |
| 757 | + | |
| 758 | + /* Step back through the change history */ | |
| 759 | + while( fromid>0 ){ | |
| 760 | + mid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); | |
| 761 | + if( mid==0 ) break; | |
| 762 | + rid = db_int(-1, "SELECT pid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); | |
| 763 | + if( rid<0 ) continue; | |
| 764 | + zLabel = annotation_label(mid, webLabel); | |
| 765 | + if( rid==0 ) break; | |
| 766 | + fromid = rid; | |
| 767 | + content_get(fromid, &step); | |
| 768 | + annotation_step(p, &step, zLabel); | |
| 769 | + } | |
| 770 | + | |
| 771 | + /* Any unannotated lines are due to the last revision seen. | |
| 772 | + */ | |
| 773 | + for(i=0; i<p->nOrig; i++){ | |
| 774 | + if( p->aOrig[i].zSrc==0 ) p->aOrig[i].zSrc = zLabel; | |
| 775 | + } | |
| 776 | +} | |
| 777 | + | |
| 778 | +/* | |
| 779 | +** WEBPAGE: annotate | |
| 780 | +** | |
| 781 | +** Query parameters: | |
| 782 | +** | |
| 783 | +** mid=NUM The manifest ID at which to start the annotation | |
| 784 | +** fnid=NUM The filename ID. | |
| 785 | +*/ | |
| 786 | +void annotation_page(void){ | |
| 787 | + int mid = atoi(PD("mid","0")); | |
| 788 | + int fnid = atoi(PD("fnid","0")); | |
| 789 | + int i; | |
| 790 | + Annotator ann; | |
| 791 | + | |
| 792 | + login_check_credentials(); | |
| 793 | + if( !g.okHistory ){ login_needed(); return; } | |
| 794 | + if( mid==0 || fnid==0 ){ cgi_redirect("index"); } | |
| 795 | + if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ | |
| 796 | + cgi_redirect("index"); | |
| 797 | + } | |
| 798 | + style_header("File Annotation"); | |
| 799 | + annotate_file(&ann, fnid, mid, 1); | |
| 800 | + @ <pre> | |
| 801 | + for(i=0; i<ann.nOrig; i++){ | |
| 802 | + ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; | |
| 803 | + @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) | |
| 804 | + } | |
| 805 | + @ </pre> | |
| 806 | + style_footer(); | |
| 807 | +} | |
| 709 | 808 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -704,5 +704,104 @@ | |
| 704 | const char *zSrc = x.aOrig[i].zSrc; |
| 705 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 706 | printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 707 | } |
| 708 | } |
| 709 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -704,5 +704,104 @@ | |
| 704 | const char *zSrc = x.aOrig[i].zSrc; |
| 705 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 706 | printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 707 | } |
| 708 | } |
| 709 | |
| 710 | /* |
| 711 | ** Create an annotation string based on the manifest id. |
| 712 | */ |
| 713 | static char *annotation_label(int mid, int webLabel){ |
| 714 | char *z; |
| 715 | z = db_text("?", |
| 716 | "SELECT" |
| 717 | " substr(blob.uuid,1,10) ||" |
| 718 | " ' ' || date(event.mtime) ||" |
| 719 | " ' (' || substr(event.user || ' ',1,9) || ')'" |
| 720 | " FROM blob, event" |
| 721 | " WHERE blob.rid=%d" |
| 722 | " AND event.objid=%d" |
| 723 | " AND event.type='ci'", |
| 724 | mid, mid |
| 725 | ); |
| 726 | return z; |
| 727 | } |
| 728 | |
| 729 | /* |
| 730 | ** Compute a complete annotation on a file. The file is identified |
| 731 | ** by its filename number (filename.fnid) and the baseline in which |
| 732 | ** it was checked in (mlink.mid). |
| 733 | */ |
| 734 | static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ |
| 735 | Blob toAnnotate; /* Text of the final version of the file */ |
| 736 | Blob step; /* Text of previous revision */ |
| 737 | int rid; |
| 738 | int fromid; |
| 739 | char *zLabel; |
| 740 | int i; |
| 741 | |
| 742 | /* Initialize the annotation */ |
| 743 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 744 | if( rid==0 ){ |
| 745 | fossil_panic("no changes to file #%d in manifest #%d", fnid, mid); |
| 746 | } |
| 747 | if( !content_get(rid, &toAnnotate) ){ |
| 748 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 749 | } |
| 750 | annotation_start(p, &toAnnotate); |
| 751 | fromid = db_int(0,"SELECT pid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 752 | zLabel = annotation_label(mid, webLabel); |
| 753 | if( fromid ){ |
| 754 | content_get(fromid, &step); |
| 755 | annotation_step(p, &step, zLabel); |
| 756 | } |
| 757 | |
| 758 | /* Step back through the change history */ |
| 759 | while( fromid>0 ){ |
| 760 | mid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); |
| 761 | if( mid==0 ) break; |
| 762 | rid = db_int(-1, "SELECT pid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 763 | if( rid<0 ) continue; |
| 764 | zLabel = annotation_label(mid, webLabel); |
| 765 | if( rid==0 ) break; |
| 766 | fromid = rid; |
| 767 | content_get(fromid, &step); |
| 768 | annotation_step(p, &step, zLabel); |
| 769 | } |
| 770 | |
| 771 | /* Any unannotated lines are due to the last revision seen. |
| 772 | */ |
| 773 | for(i=0; i<p->nOrig; i++){ |
| 774 | if( p->aOrig[i].zSrc==0 ) p->aOrig[i].zSrc = zLabel; |
| 775 | } |
| 776 | } |
| 777 | |
| 778 | /* |
| 779 | ** WEBPAGE: annotate |
| 780 | ** |
| 781 | ** Query parameters: |
| 782 | ** |
| 783 | ** mid=NUM The manifest ID at which to start the annotation |
| 784 | ** fnid=NUM The filename ID. |
| 785 | */ |
| 786 | void annotation_page(void){ |
| 787 | int mid = atoi(PD("mid","0")); |
| 788 | int fnid = atoi(PD("fnid","0")); |
| 789 | int i; |
| 790 | Annotator ann; |
| 791 | |
| 792 | login_check_credentials(); |
| 793 | if( !g.okHistory ){ login_needed(); return; } |
| 794 | if( mid==0 || fnid==0 ){ cgi_redirect("index"); } |
| 795 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 796 | cgi_redirect("index"); |
| 797 | } |
| 798 | style_header("File Annotation"); |
| 799 | annotate_file(&ann, fnid, mid, 1); |
| 800 | @ <pre> |
| 801 | for(i=0; i<ann.nOrig; i++){ |
| 802 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 803 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 804 | } |
| 805 | @ </pre> |
| 806 | style_footer(); |
| 807 | } |
| 808 |
+5
-1
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -455,11 +455,11 @@ | ||
| 455 | 455 | zFilename = PD("name",""); |
| 456 | 456 | db_prepare(&q, |
| 457 | 457 | "SELECT a.uuid, substr(b.uuid,1,10), datetime(event.mtime,'localtime')," |
| 458 | 458 | " coalesce(event.ecomment, event.comment)," |
| 459 | 459 | " coalesce(event.euser, event.user)," |
| 460 | - " mlink.pid, mlink.fid" | |
| 460 | + " mlink.pid, mlink.fid, mlink.mid, mlink.fnid" | |
| 461 | 461 | " FROM mlink, blob a, blob b, event" |
| 462 | 462 | " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" |
| 463 | 463 | " AND a.rid=mlink.mid" |
| 464 | 464 | " AND b.rid=mlink.fid" |
| 465 | 465 | " AND event.objid=mlink.mid" |
| @@ -474,10 +474,12 @@ | ||
| 474 | 474 | const char *zDate = db_column_text(&q, 2); |
| 475 | 475 | const char *zCom = db_column_text(&q, 3); |
| 476 | 476 | const char *zUser = db_column_text(&q, 4); |
| 477 | 477 | int fpid = db_column_int(&q, 5); |
| 478 | 478 | int frid = db_column_int(&q, 6); |
| 479 | + int mid = db_column_int(&q, 7); | |
| 480 | + int fnid = db_column_int(&q, 8); | |
| 479 | 481 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 480 | 482 | sprintf(zPrevDate, "%.10s", zDate); |
| 481 | 483 | @ <tr><td colspan=3> |
| 482 | 484 | @ <table cellpadding=2 border=0> |
| 483 | 485 | @ <tr><td bgcolor="#a0b5f4" class="border1"> |
| @@ -495,10 +497,12 @@ | ||
| 495 | 497 | @ Id: %s(zUuid)/%d(frid) |
| 496 | 498 | @ <a href="%s(g.zBaseURL)/fview/%d(frid)">[view]</a> |
| 497 | 499 | if( fpid ){ |
| 498 | 500 | @ <a href="%s(g.zBaseURL)/fdiff?v1=%d(fpid)&v2=%d(frid)">[diff]</a> |
| 499 | 501 | } |
| 502 | + @ <a href="%s(g.zBaseURL)/annotate?mid=%d(mid)&fnid=%d(fnid)"> | |
| 503 | + @ [annotate]</a> | |
| 500 | 504 | @ </td> |
| 501 | 505 | } |
| 502 | 506 | db_finalize(&q); |
| 503 | 507 | @ </table> |
| 504 | 508 | style_footer(); |
| 505 | 509 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -455,11 +455,11 @@ | |
| 455 | zFilename = PD("name",""); |
| 456 | db_prepare(&q, |
| 457 | "SELECT a.uuid, substr(b.uuid,1,10), datetime(event.mtime,'localtime')," |
| 458 | " coalesce(event.ecomment, event.comment)," |
| 459 | " coalesce(event.euser, event.user)," |
| 460 | " mlink.pid, mlink.fid" |
| 461 | " FROM mlink, blob a, blob b, event" |
| 462 | " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" |
| 463 | " AND a.rid=mlink.mid" |
| 464 | " AND b.rid=mlink.fid" |
| 465 | " AND event.objid=mlink.mid" |
| @@ -474,10 +474,12 @@ | |
| 474 | const char *zDate = db_column_text(&q, 2); |
| 475 | const char *zCom = db_column_text(&q, 3); |
| 476 | const char *zUser = db_column_text(&q, 4); |
| 477 | int fpid = db_column_int(&q, 5); |
| 478 | int frid = db_column_int(&q, 6); |
| 479 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 480 | sprintf(zPrevDate, "%.10s", zDate); |
| 481 | @ <tr><td colspan=3> |
| 482 | @ <table cellpadding=2 border=0> |
| 483 | @ <tr><td bgcolor="#a0b5f4" class="border1"> |
| @@ -495,10 +497,12 @@ | |
| 495 | @ Id: %s(zUuid)/%d(frid) |
| 496 | @ <a href="%s(g.zBaseURL)/fview/%d(frid)">[view]</a> |
| 497 | if( fpid ){ |
| 498 | @ <a href="%s(g.zBaseURL)/fdiff?v1=%d(fpid)&v2=%d(frid)">[diff]</a> |
| 499 | } |
| 500 | @ </td> |
| 501 | } |
| 502 | db_finalize(&q); |
| 503 | @ </table> |
| 504 | style_footer(); |
| 505 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -455,11 +455,11 @@ | |
| 455 | zFilename = PD("name",""); |
| 456 | db_prepare(&q, |
| 457 | "SELECT a.uuid, substr(b.uuid,1,10), datetime(event.mtime,'localtime')," |
| 458 | " coalesce(event.ecomment, event.comment)," |
| 459 | " coalesce(event.euser, event.user)," |
| 460 | " mlink.pid, mlink.fid, mlink.mid, mlink.fnid" |
| 461 | " FROM mlink, blob a, blob b, event" |
| 462 | " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" |
| 463 | " AND a.rid=mlink.mid" |
| 464 | " AND b.rid=mlink.fid" |
| 465 | " AND event.objid=mlink.mid" |
| @@ -474,10 +474,12 @@ | |
| 474 | const char *zDate = db_column_text(&q, 2); |
| 475 | const char *zCom = db_column_text(&q, 3); |
| 476 | const char *zUser = db_column_text(&q, 4); |
| 477 | int fpid = db_column_int(&q, 5); |
| 478 | int frid = db_column_int(&q, 6); |
| 479 | int mid = db_column_int(&q, 7); |
| 480 | int fnid = db_column_int(&q, 8); |
| 481 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 482 | sprintf(zPrevDate, "%.10s", zDate); |
| 483 | @ <tr><td colspan=3> |
| 484 | @ <table cellpadding=2 border=0> |
| 485 | @ <tr><td bgcolor="#a0b5f4" class="border1"> |
| @@ -495,10 +497,12 @@ | |
| 497 | @ Id: %s(zUuid)/%d(frid) |
| 498 | @ <a href="%s(g.zBaseURL)/fview/%d(frid)">[view]</a> |
| 499 | if( fpid ){ |
| 500 | @ <a href="%s(g.zBaseURL)/fdiff?v1=%d(fpid)&v2=%d(frid)">[diff]</a> |
| 501 | } |
| 502 | @ <a href="%s(g.zBaseURL)/annotate?mid=%d(mid)&fnid=%d(fnid)"> |
| 503 | @ [annotate]</a> |
| 504 | @ </td> |
| 505 | } |
| 506 | db_finalize(&q); |
| 507 | @ </table> |
| 508 | style_footer(); |
| 509 |