Fossil

Check-in [840699ecd9]
Login

Check-in [840699ecd9]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improvements to annotated diffs - now takes into account contributions from other branches.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 840699ecd967d5ba36ce79f0231989f4f4d6a7f6
User & Date: drh 2008-02-08 21:23:56.000
Context
2008-02-08
21:42
Rename the 'clearsign' setting to 'pgp-command'. Remove the 'safemerge' setting - safemerge is on by default and cannot be disabled. ... (check-in: 5cc845cfeb user: drh tags: trunk)
21:23
Improvements to annotated diffs - now takes into account contributions from other branches. ... (check-in: 840699ecd9 user: drh tags: trunk)
17:27
Merge two branches that were created within one second of one another. There is a race condition in the anti-forking logic that allowed this fork to occur. ... (check-in: 373e42de1d user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/diff.c.
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575

576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
/*
** The status of an annotation operation is recorded by an instance
** of the following structure.
*/
typedef struct Annotator Annotator;
struct Annotator {
  DContext c;       /* The diff-engine context */
  Blob blobTo;      /* Blob to free at next step */
  int nOrig;        /* Number of lines in original file */
  int nNoSrc;       /* Number of uncompleted aOrig[].zSrc entries */
  struct {          /* Lines of the original files... */
    const char *z;       /* The text of the line */
    int n;               /* Number of bytes (omitting trailing space and \n) */
    const char *zSrc;    /* Tag showing origin of this line */
  } *aOrig;
  int *aMap;        /* Map lines for c.aTo into aOrig */

};

/*
** Initialize the annotation process by specifying the file that is
** to be annotated.  The annotator takes control of the input Blob and
** will release it when it is finished with it.
*/
static int annotation_start(Annotator *p, Blob *pInput){
  int i;

  memset(p, 0, sizeof(*p));
  p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo);
  if( p->c.aTo==0 ){
    return 1;
  }
  p->aMap = malloc( sizeof(int)*p->c.nTo );
  if( p->aMap==0 ) fossil_panic("out of memory");
  for(i=0; i<p->c.nTo; i++) p->aMap[i] = i;
  p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo );
  if( p->aOrig==0 ) fossil_panic("out of memory");
  for(i=0; i<p->c.nTo; i++){
    p->aOrig[i].z = p->c.aTo[i].z;
    p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK;
    p->aOrig[i].zSrc = 0;
  }
  p->nOrig = p->c.nTo;
  p->nNoSrc = p->c.nTo;
  return 0;
}

/*
** The input pParent is the next most recent ancestor of the file
** being annotated.  Do another step of the annotation.  Return true
** if additional annotation is required.  zPName is the tag to insert
** on each line of the file being annotated that was contributed by
** pParent.  Memory to hold zPName is leaked.
*/
static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
  int i, j;
  int lnTo, lnFrom;
  int *aFromMap;

  /* Prepare the parent file to be diffed */
  p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom);
  if( p->c.aFrom==0 ){
    return 1;
  }

  /* Compute the differences going from pParent to the last file
  ** processed */
  diff_all(&p->c);

  /* Where new lines are inserted on this difference, record the
  ** zPName as the source of the new line.
  */
  for(i=lnTo=0; i<p->c.nEdit; i+=3){
    lnTo += p->c.aEdit[i];
    for(j=0; j<p->c.aEdit[i+2]; j++, lnTo++){
      int x = p->aMap[lnTo];
      if( x>=0 && p->aOrig[x].zSrc==0 ){
        p->aOrig[x].zSrc = zPName;
        p->nNoSrc--;
      }
    }
  }

  /* We will be converting aFrom into aTo for the next step.  Compute
  ** a map from the aFrom into the original file being annotated.
  */
  aFromMap = malloc( sizeof(int)*p->c.nFrom );
  if( aFromMap==0 ){
    fossil_panic("out of memory");
  }
  for(i=lnTo=lnFrom=0; i<p->c.nEdit; i+=3){
    for(j=0; j<p->c.aEdit[i]; j++){
      aFromMap[lnFrom++] = p->aMap[lnTo++];
    }
    for(j=0; j<p->c.aEdit[i+1]; j++){
      aFromMap[lnFrom++] = -1;
    }
    lnTo += p->c.aEdit[i+2];
  }
  assert( lnFrom==p->c.nFrom );
  free(p->aMap);
  p->aMap = aFromMap;

  /* Clear out the diff results */
  free(p->c.aEdit);
  p->c.aEdit = 0;
  p->c.nEdit = 0;
  p->c.nEditAlloc = 0;

  /* Move aFrom over to aTo in preparation for the next step */
  free(p->c.aTo);    
  if( blob_buffer(&p->blobTo) ) blob_reset(&p->blobTo);
  p->blobTo = *pParent;
  blob_zero(pParent);
  p->c.aTo = p->c.aFrom;
  p->c.nTo = p->c.nFrom;

  /* Return no errors */
  return 0;
}


/*







<
<
<





|
>















<
<
<








<












|
<







|
|






<
|
<
<
|
<
|
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<


<
<
<







|
|
<
<

<
<







560
561
562
563
564
565
566



567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588



589
590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
605
606
607
608
609

610
611
612
613
614
615
616
617
618
619
620
621
622
623
624

625


626

627

















628
629



630
631
632
633
634
635
636
637
638


639


640
641
642
643
644
645
646
/*
** The status of an annotation operation is recorded by an instance
** of the following structure.
*/
typedef struct Annotator Annotator;
struct Annotator {
  DContext c;       /* The diff-engine context */



  struct {          /* Lines of the original files... */
    const char *z;       /* The text of the line */
    int n;               /* Number of bytes (omitting trailing space and \n) */
    const char *zSrc;    /* Tag showing origin of this line */
  } *aOrig;
  int nOrig;        /* Number of elements in aOrig[] */
  int nNoSrc;       /* Number of entries where aOrig[].zSrc==NULL */
};

/*
** Initialize the annotation process by specifying the file that is
** to be annotated.  The annotator takes control of the input Blob and
** will release it when it is finished with it.
*/
static int annotation_start(Annotator *p, Blob *pInput){
  int i;

  memset(p, 0, sizeof(*p));
  p->c.aTo = break_into_lines(blob_str(pInput), &p->c.nTo);
  if( p->c.aTo==0 ){
    return 1;
  }



  p->aOrig = malloc( sizeof(p->aOrig[0])*p->c.nTo );
  if( p->aOrig==0 ) fossil_panic("out of memory");
  for(i=0; i<p->c.nTo; i++){
    p->aOrig[i].z = p->c.aTo[i].z;
    p->aOrig[i].n = p->c.aTo[i].h & LENGTH_MASK;
    p->aOrig[i].zSrc = 0;
  }
  p->nOrig = p->c.nTo;

  return 0;
}

/*
** The input pParent is the next most recent ancestor of the file
** being annotated.  Do another step of the annotation.  Return true
** if additional annotation is required.  zPName is the tag to insert
** on each line of the file being annotated that was contributed by
** pParent.  Memory to hold zPName is leaked.
*/
static int annotation_step(Annotator *p, Blob *pParent, char *zPName){
  int i, j;
  int lnTo;


  /* Prepare the parent file to be diffed */
  p->c.aFrom = break_into_lines(blob_str(pParent), &p->c.nFrom);
  if( p->c.aFrom==0 ){
    return 1;
  }

  /* Compute the differences going from pParent to the file being
  ** annotated. */
  diff_all(&p->c);

  /* Where new lines are inserted on this difference, record the
  ** zPName as the source of the new line.
  */
  for(i=lnTo=0; i<p->c.nEdit; i+=3){

    for(j=0; j<p->c.aEdit[i]; j++, lnTo++){


      p->aOrig[lnTo].zSrc = zPName;

    }

















    lnTo += p->c.aEdit[i+2];
  }




  /* Clear out the diff results */
  free(p->c.aEdit);
  p->c.aEdit = 0;
  p->c.nEdit = 0;
  p->c.nEditAlloc = 0;

  /* Clear out the from file */
  free(p->c.aFrom);    


  blob_zero(pParent);



  /* Return no errors */
  return 0;
}


/*
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740

741
742
743
744
745
746
747
748
749


750
751
752
753
754
755
756
757



758





759
760
761
762
763

764
765
766

767
768
769
770
771
772
773
774
775

776
777
778
779
780
781
782
  for(i=0; i<x.nOrig; i++){
    const char *zSrc = x.aOrig[i].zSrc;
    if( zSrc==0 ) zSrc = g.argv[g.argc-1];
    printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
  }
}

/*
** Create an annotation string based on the manifest id.
*/
static char *annotation_label(int mid, int webLabel){
  char *z;
  z = db_text("?",
    "SELECT"
    "   substr(blob.uuid,1,10) ||"
    "   ' ' || date(event.mtime) ||"
    "   ' (' || substr(event.user || '        ',1,9) || ')'"
    "  FROM blob, event"
    " WHERE blob.rid=%d"
    "   AND event.objid=%d"
    "   AND event.type='ci'",
    mid, mid
  );
  return z;
}

/*
** Compute a complete annotation on a file.  The file is identified
** by its filename number (filename.fnid) and the baseline in which
** it was checked in (mlink.mid).
*/
static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){
  Blob toAnnotate;     /* Text of the final version of the file */
  Blob step;           /* Text of previous revision */
  int rid;
  int fromid;
  char *zLabel;
  int i;


  /* Initialize the annotation */
  rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
  if( rid==0 ){
    fossil_panic("no changes to file #%d in manifest #%d", fnid, mid);
  }
  if( !content_get(rid, &toAnnotate) ){
    fossil_panic("unable to retrieve content of artifact #%d", rid);
  }


  annotation_start(p, &toAnnotate);
  fromid = db_int(0,"SELECT pid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
  zLabel = annotation_label(mid, webLabel);
  if( fromid ){
    content_get(fromid, &step);
    annotation_step(p, &step, zLabel);
  }




  /* Step back through the change history */





  while( fromid>0 ){
    mid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid);
    if( mid==0 ) break;
    rid = db_int(-1, "SELECT pid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
    if( rid<0 ) continue;

    zLabel = annotation_label(mid, webLabel);
    if( rid==0 ) break;
    fromid = rid;

    content_get(fromid, &step);
    annotation_step(p, &step, zLabel);
  }

  /* Any unannotated lines are due to the last revision seen.
  */
  for(i=0; i<p->nOrig; i++){
    if( p->aOrig[i].zSrc==0 ) p->aOrig[i].zSrc = zLabel;
  }

}

/*
** WEBPAGE: annotate
**
** Query parameters:
**







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<








|
<
|
<
>




|




>
>

<
<
<
<
<
|
|
>
>
>
|
>
>
>
>
>
|
|
<
|
|
>
|
<
<
>
|

<
|
<
<
<
<

>







668
669
670
671
672
673
674



















675
676
677
678
679
680
681
682
683

684

685
686
687
688
689
690
691
692
693
694
695
696
697





698
699
700
701
702
703
704
705
706
707
708
709
710

711
712
713
714


715
716
717

718




719
720
721
722
723
724
725
726
727
  for(i=0; i<x.nOrig; i++){
    const char *zSrc = x.aOrig[i].zSrc;
    if( zSrc==0 ) zSrc = g.argv[g.argc-1];
    printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z);
  }
}




















/*
** Compute a complete annotation on a file.  The file is identified
** by its filename number (filename.fnid) and the baseline in which
** it was checked in (mlink.mid).
*/
static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){
  Blob toAnnotate;     /* Text of the final version of the file */
  Blob step;           /* Text of previous revision */
  int rid;             /* Artifact ID of the file being annotated */

  char *zLabel;        /* Label to apply to a line */

  Stmt q;              /* Query returning all ancestor versions */

  /* Initialize the annotation */
  rid = db_int(0, "SELECT fid FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid);
  if( rid==0 ){
    fossil_panic("file #%d is unchanged in manifest #%d", fnid, mid);
  }
  if( !content_get(rid, &toAnnotate) ){
    fossil_panic("unable to retrieve content of artifact #%d", rid);
  }
  db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
  compute_ancestors(mid, 1000000000);
  annotation_start(p, &toAnnotate);






  db_prepare(&q, 
    "SELECT mlink.fid, blob.uuid, date(event.mtime), event.user "
    "  FROM mlink, blob, event"
    " WHERE mlink.fnid=%d"
    "   AND mlink.mid IN ok"
    "   AND blob.rid=mlink.mid"
    "   AND event.objid=mlink.mid"
    " ORDER BY event.mtime DESC",
    fnid
  );
  while( db_step(&q)==SQLITE_ROW ){
    int pid = db_column_int(&q, 0);

    const char *zUuid = db_column_text(&q, 1);
    const char *zDate = db_column_text(&q, 2);
    const char *zUser = db_column_text(&q, 3);
    zLabel = mprintf("<a href='%s/info/%s'>%.10s</a> %s %9.9s", 


                     g.zBaseURL, zUuid, zUuid, zDate, zUser);
    content_get(pid, &step);
    annotation_step(p, &step, zLabel);

    blob_reset(&step);




  }
  db_finalize(&q);
}

/*
** WEBPAGE: annotate
**
** Query parameters:
**