Fossil SCM
Improvements to annotated diffs - now takes into account contributions from other branches.
Commit
840699ecd967d5ba36ce79f0231989f4f4d6a7f6
Parent
373e42de1d8eea8…
1 file changed
+39
-94
+39
-94
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -562,19 +562,17 @@ | ||
| 562 | 562 | ** of the following structure. |
| 563 | 563 | */ |
| 564 | 564 | typedef struct Annotator Annotator; |
| 565 | 565 | struct Annotator { |
| 566 | 566 | DContext c; /* The diff-engine context */ |
| 567 | - Blob blobTo; /* Blob to free at next step */ | |
| 568 | - int nOrig; /* Number of lines in original file */ | |
| 569 | - int nNoSrc; /* Number of uncompleted aOrig[].zSrc entries */ | |
| 570 | 567 | struct { /* Lines of the original files... */ |
| 571 | 568 | const char *z; /* The text of the line */ |
| 572 | 569 | int n; /* Number of bytes (omitting trailing space and \n) */ |
| 573 | 570 | const char *zSrc; /* Tag showing origin of this line */ |
| 574 | 571 | } *aOrig; |
| 575 | - int *aMap; /* Map lines for c.aTo into aOrig */ | |
| 572 | + int nOrig; /* Number of elements in aOrig[] */ | |
| 573 | + int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ | |
| 576 | 574 | }; |
| 577 | 575 | |
| 578 | 576 | /* |
| 579 | 577 | ** Initialize the annotation process by specifying the file that is |
| 580 | 578 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -586,22 +584,18 @@ | ||
| 586 | 584 | memset(p, 0, sizeof(*p)); |
| 587 | 585 | p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo); |
| 588 | 586 | if( p->c.aTo==0 ){ |
| 589 | 587 | return 1; |
| 590 | 588 | } |
| 591 | - p->aMap = malloc( sizeof(int)*p->c.nTo ); | |
| 592 | - if( p->aMap==0 ) fossil_panic("out of memory"); | |
| 593 | - for(i=0; i<p->c.nTo; i++) p->aMap[i] = i; | |
| 594 | 589 | p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo ); |
| 595 | 590 | if( p->aOrig==0 ) fossil_panic("out of memory"); |
| 596 | 591 | for(i=0; i<p->c.nTo; i++){ |
| 597 | 592 | p->aOrig[i].z = p->c.aTo[i].z; |
| 598 | 593 | p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK; |
| 599 | 594 | p->aOrig[i].zSrc = 0; |
| 600 | 595 | } |
| 601 | 596 | p->nOrig = p->c.nTo; |
| 602 | - p->nNoSrc = p->c.nTo; | |
| 603 | 597 | return 0; |
| 604 | 598 | } |
| 605 | 599 | |
| 606 | 600 | /* |
| 607 | 601 | ** The input pParent is the next most recent ancestor of the file |
| @@ -610,70 +604,41 @@ | ||
| 610 | 604 | ** on each line of the file being annotated that was contributed by |
| 611 | 605 | ** pParent. Memory to hold zPName is leaked. |
| 612 | 606 | */ |
| 613 | 607 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 614 | 608 | int i, j; |
| 615 | - int lnTo, lnFrom; | |
| 616 | - int *aFromMap; | |
| 609 | + int lnTo; | |
| 617 | 610 | |
| 618 | 611 | /* Prepare the parent file to be diffed */ |
| 619 | 612 | p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom); |
| 620 | 613 | if( p->c.aFrom==0 ){ |
| 621 | 614 | return 1; |
| 622 | 615 | } |
| 623 | 616 | |
| 624 | - /* Compute the differences going from pParent to the last file | |
| 625 | - ** processed */ | |
| 617 | + /* Compute the differences going from pParent to the file being | |
| 618 | + ** annotated. */ | |
| 626 | 619 | diff_all(&p->c); |
| 627 | 620 | |
| 628 | 621 | /* Where new lines are inserted on this difference, record the |
| 629 | 622 | ** zPName as the source of the new line. |
| 630 | 623 | */ |
| 631 | 624 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 632 | - lnTo += p->c.aEdit[i]; | |
| 633 | - for(j=0; j<p->c.aEdit[i+2]; j++, lnTo++){ | |
| 634 | - int x = p->aMap[lnTo]; | |
| 635 | - if( x>=0 && p->aOrig[x].zSrc==0 ){ | |
| 636 | - p->aOrig[x].zSrc = zPName; | |
| 637 | - p->nNoSrc--; | |
| 638 | - } | |
| 639 | - } | |
| 640 | - } | |
| 641 | - | |
| 642 | - /* We will be converting aFrom into aTo for the next step. Compute | |
| 643 | - ** a map from the aFrom into the original file being annotated. | |
| 644 | - */ | |
| 645 | - aFromMap = malloc( sizeof(int)*p->c.nFrom ); | |
| 646 | - if( aFromMap==0 ){ | |
| 647 | - fossil_panic("out of memory"); | |
| 648 | - } | |
| 649 | - for(i=lnTo=lnFrom=0; i<p->c.nEdit; i+=3){ | |
| 650 | - for(j=0; j<p->c.aEdit[i]; j++){ | |
| 651 | - aFromMap[lnFrom++] = p->aMap[lnTo++]; | |
| 652 | - } | |
| 653 | - for(j=0; j<p->c.aEdit[i+1]; j++){ | |
| 654 | - aFromMap[lnFrom++] = -1; | |
| 625 | + for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ | |
| 626 | + p->aOrig[lnTo].zSrc = zPName; | |
| 655 | 627 | } |
| 656 | 628 | lnTo += p->c.aEdit[i+2]; |
| 657 | 629 | } |
| 658 | - assert( lnFrom==p->c.nFrom ); | |
| 659 | - free(p->aMap); | |
| 660 | - p->aMap = aFromMap; | |
| 661 | 630 | |
| 662 | 631 | /* Clear out the diff results */ |
| 663 | 632 | free(p->c.aEdit); |
| 664 | 633 | p->c.aEdit = 0; |
| 665 | 634 | p->c.nEdit = 0; |
| 666 | 635 | p->c.nEditAlloc = 0; |
| 667 | 636 | |
| 668 | - /* Move aFrom over to aTo in preparation for the next step */ | |
| 669 | - free(p->c.aTo); | |
| 670 | - if( blob_buffer(&p->blobTo) ) blob_reset(&p->blobTo); | |
| 671 | - p->blobTo = *pParent; | |
| 637 | + /* Clear out the from file */ | |
| 638 | + free(p->c.aFrom); | |
| 672 | 639 | blob_zero(pParent); |
| 673 | - p->c.aTo = p->c.aFrom; | |
| 674 | - p->c.nTo = p->c.nFrom; | |
| 675 | 640 | |
| 676 | 641 | /* Return no errors */ |
| 677 | 642 | return 0; |
| 678 | 643 | } |
| 679 | 644 | |
| @@ -705,76 +670,56 @@ | ||
| 705 | 670 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 706 | 671 | printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 707 | 672 | } |
| 708 | 673 | } |
| 709 | 674 | |
| 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 | 675 | /* |
| 730 | 676 | ** Compute a complete annotation on a file. The file is identified |
| 731 | 677 | ** by its filename number (filename.fnid) and the baseline in which |
| 732 | 678 | ** it was checked in (mlink.mid). |
| 733 | 679 | */ |
| 734 | 680 | static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ |
| 735 | 681 | Blob toAnnotate; /* Text of the final version of the file */ |
| 736 | 682 | Blob step; /* Text of previous revision */ |
| 737 | - int rid; | |
| 738 | - int fromid; | |
| 739 | - char *zLabel; | |
| 740 | - int i; | |
| 683 | + int rid; /* Artifact ID of the file being annotated */ | |
| 684 | + char *zLabel; /* Label to apply to a line */ | |
| 685 | + Stmt q; /* Query returning all ancestor versions */ | |
| 741 | 686 | |
| 742 | 687 | /* Initialize the annotation */ |
| 743 | 688 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 744 | 689 | if( rid==0 ){ |
| 745 | - fossil_panic("no changes to file #%d in manifest #%d", fnid, mid); | |
| 690 | + fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid); | |
| 746 | 691 | } |
| 747 | 692 | if( !content_get(rid, &toAnnotate) ){ |
| 748 | 693 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 749 | 694 | } |
| 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 | - } | |
| 695 | + db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); | |
| 696 | + compute_ancestors(mid, 1000000000); | |
| 697 | + annotation_start(p, &toAnnotate); | |
| 698 | + | |
| 699 | + db_prepare(&q, | |
| 700 | + "SELECT mlink.fid, blob.uuid, date(event.mtime), event.user " | |
| 701 | + " FROM mlink, blob, event" | |
| 702 | + " WHERE mlink.fnid=%d" | |
| 703 | + " AND mlink.mid IN ok" | |
| 704 | + " AND blob.rid=mlink.mid" | |
| 705 | + " AND event.objid=mlink.mid" | |
| 706 | + " ORDER BY event.mtime DESC", | |
| 707 | + fnid | |
| 708 | + ); | |
| 709 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 710 | + int pid = db_column_int(&q, 0); | |
| 711 | + const char *zUuid = db_column_text(&q, 1); | |
| 712 | + const char *zDate = db_column_text(&q, 2); | |
| 713 | + const char *zUser = db_column_text(&q, 3); | |
| 714 | + zLabel = mprintf("<a href='%s/info/%s'>%.10s</a> %s %9.9s", | |
| 715 | + g.zBaseURL, zUuid, zUuid, zDate, zUser); | |
| 716 | + content_get(pid, &step); | |
| 717 | + annotation_step(p, &step, zLabel); | |
| 718 | + blob_reset(&step); | |
| 719 | + } | |
| 720 | + db_finalize(&q); | |
| 776 | 721 | } |
| 777 | 722 | |
| 778 | 723 | /* |
| 779 | 724 | ** WEBPAGE: annotate |
| 780 | 725 | ** |
| 781 | 726 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -562,19 +562,17 @@ | |
| 562 | ** of the following structure. |
| 563 | */ |
| 564 | typedef struct Annotator Annotator; |
| 565 | struct Annotator { |
| 566 | DContext c; /* The diff-engine context */ |
| 567 | Blob blobTo; /* Blob to free at next step */ |
| 568 | int nOrig; /* Number of lines in original file */ |
| 569 | int nNoSrc; /* Number of uncompleted aOrig[].zSrc entries */ |
| 570 | struct { /* Lines of the original files... */ |
| 571 | const char *z; /* The text of the line */ |
| 572 | int n; /* Number of bytes (omitting trailing space and \n) */ |
| 573 | const char *zSrc; /* Tag showing origin of this line */ |
| 574 | } *aOrig; |
| 575 | int *aMap; /* Map lines for c.aTo into aOrig */ |
| 576 | }; |
| 577 | |
| 578 | /* |
| 579 | ** Initialize the annotation process by specifying the file that is |
| 580 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -586,22 +584,18 @@ | |
| 586 | memset(p, 0, sizeof(*p)); |
| 587 | p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo); |
| 588 | if( p->c.aTo==0 ){ |
| 589 | return 1; |
| 590 | } |
| 591 | p->aMap = malloc( sizeof(int)*p->c.nTo ); |
| 592 | if( p->aMap==0 ) fossil_panic("out of memory"); |
| 593 | for(i=0; i<p->c.nTo; i++) p->aMap[i] = i; |
| 594 | p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo ); |
| 595 | if( p->aOrig==0 ) fossil_panic("out of memory"); |
| 596 | for(i=0; i<p->c.nTo; i++){ |
| 597 | p->aOrig[i].z = p->c.aTo[i].z; |
| 598 | p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK; |
| 599 | p->aOrig[i].zSrc = 0; |
| 600 | } |
| 601 | p->nOrig = p->c.nTo; |
| 602 | p->nNoSrc = p->c.nTo; |
| 603 | return 0; |
| 604 | } |
| 605 | |
| 606 | /* |
| 607 | ** The input pParent is the next most recent ancestor of the file |
| @@ -610,70 +604,41 @@ | |
| 610 | ** on each line of the file being annotated that was contributed by |
| 611 | ** pParent. Memory to hold zPName is leaked. |
| 612 | */ |
| 613 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 614 | int i, j; |
| 615 | int lnTo, lnFrom; |
| 616 | int *aFromMap; |
| 617 | |
| 618 | /* Prepare the parent file to be diffed */ |
| 619 | p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom); |
| 620 | if( p->c.aFrom==0 ){ |
| 621 | return 1; |
| 622 | } |
| 623 | |
| 624 | /* Compute the differences going from pParent to the last file |
| 625 | ** processed */ |
| 626 | diff_all(&p->c); |
| 627 | |
| 628 | /* Where new lines are inserted on this difference, record the |
| 629 | ** zPName as the source of the new line. |
| 630 | */ |
| 631 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 632 | lnTo += p->c.aEdit[i]; |
| 633 | for(j=0; j<p->c.aEdit[i+2]; j++, lnTo++){ |
| 634 | int x = p->aMap[lnTo]; |
| 635 | if( x>=0 && p->aOrig[x].zSrc==0 ){ |
| 636 | p->aOrig[x].zSrc = zPName; |
| 637 | p->nNoSrc--; |
| 638 | } |
| 639 | } |
| 640 | } |
| 641 | |
| 642 | /* We will be converting aFrom into aTo for the next step. Compute |
| 643 | ** a map from the aFrom into the original file being annotated. |
| 644 | */ |
| 645 | aFromMap = malloc( sizeof(int)*p->c.nFrom ); |
| 646 | if( aFromMap==0 ){ |
| 647 | fossil_panic("out of memory"); |
| 648 | } |
| 649 | for(i=lnTo=lnFrom=0; i<p->c.nEdit; i+=3){ |
| 650 | for(j=0; j<p->c.aEdit[i]; j++){ |
| 651 | aFromMap[lnFrom++] = p->aMap[lnTo++]; |
| 652 | } |
| 653 | for(j=0; j<p->c.aEdit[i+1]; j++){ |
| 654 | aFromMap[lnFrom++] = -1; |
| 655 | } |
| 656 | lnTo += p->c.aEdit[i+2]; |
| 657 | } |
| 658 | assert( lnFrom==p->c.nFrom ); |
| 659 | free(p->aMap); |
| 660 | p->aMap = aFromMap; |
| 661 | |
| 662 | /* Clear out the diff results */ |
| 663 | free(p->c.aEdit); |
| 664 | p->c.aEdit = 0; |
| 665 | p->c.nEdit = 0; |
| 666 | p->c.nEditAlloc = 0; |
| 667 | |
| 668 | /* Move aFrom over to aTo in preparation for the next step */ |
| 669 | free(p->c.aTo); |
| 670 | if( blob_buffer(&p->blobTo) ) blob_reset(&p->blobTo); |
| 671 | p->blobTo = *pParent; |
| 672 | blob_zero(pParent); |
| 673 | p->c.aTo = p->c.aFrom; |
| 674 | p->c.nTo = p->c.nFrom; |
| 675 | |
| 676 | /* Return no errors */ |
| 677 | return 0; |
| 678 | } |
| 679 | |
| @@ -705,76 +670,56 @@ | |
| 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 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -562,19 +562,17 @@ | |
| 562 | ** of the following structure. |
| 563 | */ |
| 564 | typedef struct Annotator Annotator; |
| 565 | struct Annotator { |
| 566 | DContext c; /* The diff-engine context */ |
| 567 | struct { /* Lines of the original files... */ |
| 568 | const char *z; /* The text of the line */ |
| 569 | int n; /* Number of bytes (omitting trailing space and \n) */ |
| 570 | const char *zSrc; /* Tag showing origin of this line */ |
| 571 | } *aOrig; |
| 572 | int nOrig; /* Number of elements in aOrig[] */ |
| 573 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 574 | }; |
| 575 | |
| 576 | /* |
| 577 | ** Initialize the annotation process by specifying the file that is |
| 578 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -586,22 +584,18 @@ | |
| 584 | memset(p, 0, sizeof(*p)); |
| 585 | p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo); |
| 586 | if( p->c.aTo==0 ){ |
| 587 | return 1; |
| 588 | } |
| 589 | p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo ); |
| 590 | if( p->aOrig==0 ) fossil_panic("out of memory"); |
| 591 | for(i=0; i<p->c.nTo; i++){ |
| 592 | p->aOrig[i].z = p->c.aTo[i].z; |
| 593 | p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK; |
| 594 | p->aOrig[i].zSrc = 0; |
| 595 | } |
| 596 | p->nOrig = p->c.nTo; |
| 597 | return 0; |
| 598 | } |
| 599 | |
| 600 | /* |
| 601 | ** The input pParent is the next most recent ancestor of the file |
| @@ -610,70 +604,41 @@ | |
| 604 | ** on each line of the file being annotated that was contributed by |
| 605 | ** pParent. Memory to hold zPName is leaked. |
| 606 | */ |
| 607 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 608 | int i, j; |
| 609 | int lnTo; |
| 610 | |
| 611 | /* Prepare the parent file to be diffed */ |
| 612 | p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom); |
| 613 | if( p->c.aFrom==0 ){ |
| 614 | return 1; |
| 615 | } |
| 616 | |
| 617 | /* Compute the differences going from pParent to the file being |
| 618 | ** annotated. */ |
| 619 | diff_all(&p->c); |
| 620 | |
| 621 | /* Where new lines are inserted on this difference, record the |
| 622 | ** zPName as the source of the new line. |
| 623 | */ |
| 624 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 625 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ |
| 626 | p->aOrig[lnTo].zSrc = zPName; |
| 627 | } |
| 628 | lnTo += p->c.aEdit[i+2]; |
| 629 | } |
| 630 | |
| 631 | /* Clear out the diff results */ |
| 632 | free(p->c.aEdit); |
| 633 | p->c.aEdit = 0; |
| 634 | p->c.nEdit = 0; |
| 635 | p->c.nEditAlloc = 0; |
| 636 | |
| 637 | /* Clear out the from file */ |
| 638 | free(p->c.aFrom); |
| 639 | blob_zero(pParent); |
| 640 | |
| 641 | /* Return no errors */ |
| 642 | return 0; |
| 643 | } |
| 644 | |
| @@ -705,76 +670,56 @@ | |
| 670 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 671 | printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 672 | } |
| 673 | } |
| 674 | |
| 675 | /* |
| 676 | ** Compute a complete annotation on a file. The file is identified |
| 677 | ** by its filename number (filename.fnid) and the baseline in which |
| 678 | ** it was checked in (mlink.mid). |
| 679 | */ |
| 680 | static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ |
| 681 | Blob toAnnotate; /* Text of the final version of the file */ |
| 682 | Blob step; /* Text of previous revision */ |
| 683 | int rid; /* Artifact ID of the file being annotated */ |
| 684 | char *zLabel; /* Label to apply to a line */ |
| 685 | Stmt q; /* Query returning all ancestor versions */ |
| 686 | |
| 687 | /* Initialize the annotation */ |
| 688 | rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid); |
| 689 | if( rid==0 ){ |
| 690 | fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid); |
| 691 | } |
| 692 | if( !content_get(rid, &toAnnotate) ){ |
| 693 | fossil_panic("unable to retrieve content of artifact #%d", rid); |
| 694 | } |
| 695 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 696 | compute_ancestors(mid, 1000000000); |
| 697 | annotation_start(p, &toAnnotate); |
| 698 | |
| 699 | db_prepare(&q, |
| 700 | "SELECT mlink.fid, blob.uuid, date(event.mtime), event.user " |
| 701 | " FROM mlink, blob, event" |
| 702 | " WHERE mlink.fnid=%d" |
| 703 | " AND mlink.mid IN ok" |
| 704 | " AND blob.rid=mlink.mid" |
| 705 | " AND event.objid=mlink.mid" |
| 706 | " ORDER BY event.mtime DESC", |
| 707 | fnid |
| 708 | ); |
| 709 | while( db_step(&q)==SQLITE_ROW ){ |
| 710 | int pid = db_column_int(&q, 0); |
| 711 | const char *zUuid = db_column_text(&q, 1); |
| 712 | const char *zDate = db_column_text(&q, 2); |
| 713 | const char *zUser = db_column_text(&q, 3); |
| 714 | zLabel = mprintf("<a href='%s/info/%s'>%.10s</a> %s %9.9s", |
| 715 | g.zBaseURL, zUuid, zUuid, zDate, zUser); |
| 716 | content_get(pid, &step); |
| 717 | annotation_step(p, &step, zLabel); |
| 718 | blob_reset(&step); |
| 719 | } |
| 720 | db_finalize(&q); |
| 721 | } |
| 722 | |
| 723 | /* |
| 724 | ** WEBPAGE: annotate |
| 725 | ** |
| 726 |