Fossil SCM

Improvements to annotated diffs - now takes into account contributions from other branches.

drh 2008-02-08 21:23 trunk
Commit 840699ecd967d5ba36ce79f0231989f4f4d6a7f6
1 file changed +39 -94
+39 -94
--- src/diff.c
+++ src/diff.c
@@ -562,19 +562,17 @@
562562
** of the following structure.
563563
*/
564564
typedef struct Annotator Annotator;
565565
struct Annotator {
566566
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 */
570567
struct { /* Lines of the original files... */
571568
const char *z; /* The text of the line */
572569
int n; /* Number of bytes (omitting trailing space and \n) */
573570
const char *zSrc; /* Tag showing origin of this line */
574571
} *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 */
576574
};
577575
578576
/*
579577
** Initialize the annotation process by specifying the file that is
580578
** to be annotated. The annotator takes control of the input Blob and
@@ -586,22 +584,18 @@
586584
memset(p, 0, sizeof(*p));
587585
p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo);
588586
if( p->c.aTo==0 ){
589587
return 1;
590588
}
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;
594589
p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo );
595590
if( p->aOrig==0 ) fossil_panic("out of memory");
596591
for(i=0; i<p->c.nTo; i++){
597592
p->aOrig[i].z = p->c.aTo[i].z;
598593
p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK;
599594
p->aOrig[i].zSrc = 0;
600595
}
601596
p->nOrig = p->c.nTo;
602
- p->nNoSrc = p->c.nTo;
603597
return 0;
604598
}
605599
606600
/*
607601
** The input pParent is the next most recent ancestor of the file
@@ -610,70 +604,41 @@
610604
** on each line of the file being annotated that was contributed by
611605
** pParent. Memory to hold zPName is leaked.
612606
*/
613607
static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
614608
int i, j;
615
- int lnTo, lnFrom;
616
- int *aFromMap;
609
+ int lnTo;
617610
618611
/* Prepare the parent file to be diffed */
619612
p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom);
620613
if( p->c.aFrom==0 ){
621614
return 1;
622615
}
623616
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. */
626619
diff_all(&p->c);
627620
628621
/* Where new lines are inserted on this difference, record the
629622
** zPName as the source of the new line.
630623
*/
631624
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;
655627
}
656628
lnTo += p->c.aEdit[i+2];
657629
}
658
- assert( lnFrom==p->c.nFrom );
659
- free(p->aMap);
660
- p->aMap = aFromMap;
661630
662631
/* Clear out the diff results */
663632
free(p->c.aEdit);
664633
p->c.aEdit = 0;
665634
p->c.nEdit = 0;
666635
p->c.nEditAlloc = 0;
667636
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);
672639
blob_zero(pParent);
673
- p->c.aTo = p->c.aFrom;
674
- p->c.nTo = p->c.nFrom;
675640
676641
/* Return no errors */
677642
return 0;
678643
}
679644
@@ -705,76 +670,56 @@
705670
if( zSrc==0 ) zSrc = g.argv[g.argc-1];
706671
printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
707672
}
708673
}
709674
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
-
729675
/*
730676
** Compute a complete annotation on a file. The file is identified
731677
** by its filename number (filename.fnid) and the baseline in which
732678
** it was checked in (mlink.mid).
733679
*/
734680
static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){
735681
Blob toAnnotate; /* Text of the final version of the file */
736682
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 */
741686
742687
/* Initialize the annotation */
743688
rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
744689
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);
746691
}
747692
if( !content_get(rid, &toAnnotate) ){
748693
fossil_panic("unable to retrieve content of artifact #%d", rid);
749694
}
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);
776721
}
777722
778723
/*
779724
** WEBPAGE: annotate
780725
**
781726
--- 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

Keyboard Shortcuts

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