Fossil

Check-in [63ac111d5b]
Login

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

Overview
Comment:Add a path-tracing option to the timeline display.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 63ac111d5baf713827bef1a5dc31fb9a34cf410f
User & Date: drh 2011-03-09 17:33:43.878
Context
2011-03-09
22:56
Show a path timeline without extraneous decoration. ... (check-in: d37c6a4bc1 user: drh tags: trunk)
17:33
Add a path-tracing option to the timeline display. ... (check-in: 63ac111d5b user: drh tags: trunk)
15:45
Change the tarball generator to use the USTAR tar format. ... (check-in: 1b7777b9ee user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/bisect.c.
19
20
21
22
23
24
25

26
27
28
29
30
31
32
33
34
35
36
37
38

39
40
41
42
43
44
45
** This file also contains logic used to compute the closure of filename
** changes that have occurred across multiple check-ins.
*/
#include "config.h"
#include "bisect.h"
#include <assert.h>


/* Nodes for the shortest path algorithm.
*/
typedef struct BisectNode BisectNode;
struct BisectNode {
  int rid;                 /* ID for this node */
  int fromIsParent;        /* True if pFrom is the parent of rid */
  BisectNode *pFrom;       /* Node we came from */
  union {
    BisectNode *pPeer;       /* List of nodes of the same generation */
    BisectNode *pTo;         /* Next on path from beginning to end */
  } u;
  BisectNode *pAll;        /* List of all nodes */
};


/*
** Local variables for this module
*/
static struct {
  BisectNode *pCurrent;   /* Current generation of nodes */
  BisectNode *pAll;       /* All nodes */







>


<










>







19
20
21
22
23
24
25
26
27
28

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
** This file also contains logic used to compute the closure of filename
** changes that have occurred across multiple check-ins.
*/
#include "config.h"
#include "bisect.h"
#include <assert.h>

#if INTERFACE
/* Nodes for the shortest path algorithm.
*/

struct BisectNode {
  int rid;                 /* ID for this node */
  int fromIsParent;        /* True if pFrom is the parent of rid */
  BisectNode *pFrom;       /* Node we came from */
  union {
    BisectNode *pPeer;       /* List of nodes of the same generation */
    BisectNode *pTo;         /* Next on path from beginning to end */
  } u;
  BisectNode *pAll;        /* List of all nodes */
};
#endif

/*
** Local variables for this module
*/
static struct {
  BisectNode *pCurrent;   /* Current generation of nodes */
  BisectNode *pAll;       /* All nodes */
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
  bag_insert(&bisect.seen, rid);
  return p;
}

/*
** Reset memory used by the shortest path algorithm.
*/
static void bisect_reset(void){
  BisectNode *p;
  while( bisect.pAll ){
    p = bisect.pAll;
    bisect.pAll = p->pAll;
    fossil_free(p);
  }
  bag_clear(&bisect.seen);
  bisect.pCurrent = 0;
  bisect.pAll = 0;
  bisect.pEnd = 0;
  bisect.nStep = 0;
}

/*
** Compute the shortest path from iFrom to iTo
**
** If directOnly is true, then use only the "primary" links from parent to
** child.  In other words, ignore merges.
*/
static BisectNode *bisect_shortest_path(int iFrom, int iTo, int directOnly){
  Stmt s;
  BisectNode *pPrev;
  BisectNode *p;

  bisect_reset();
  bisect.pStart = bisect_new_node(iFrom, 0, 0);
  if( iTo==iFrom ) return bisect.pStart;







|



















|







70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
  bag_insert(&bisect.seen, rid);
  return p;
}

/*
** Reset memory used by the shortest path algorithm.
*/
void bisect_reset(void){
  BisectNode *p;
  while( bisect.pAll ){
    p = bisect.pAll;
    bisect.pAll = p->pAll;
    fossil_free(p);
  }
  bag_clear(&bisect.seen);
  bisect.pCurrent = 0;
  bisect.pAll = 0;
  bisect.pEnd = 0;
  bisect.nStep = 0;
}

/*
** Compute the shortest path from iFrom to iTo
**
** If directOnly is true, then use only the "primary" links from parent to
** child.  In other words, ignore merges.
*/
BisectNode *bisect_shortest_path(int iFrom, int iTo, int directOnly){
  Stmt s;
  BisectNode *pPrev;
  BisectNode *p;

  bisect_reset();
  bisect.pStart = bisect_new_node(iFrom, 0, 0);
  if( iTo==iFrom ) return bisect.pStart;
137
138
139
140
141
142
143
144
145
146
147
148
149
150

151
152
153
154
155
156
157
  bisect_reset();
  return 0;
}

/*
** Construct the path from bisect.pStart to bisect.pEnd in the u.pTo fields.
*/
static void bisect_reverse_path(void){
  BisectNode *p;
  for(p=bisect.pEnd; p && p->pFrom; p = p->pFrom){
    p->pFrom->u.pTo = p;
  }
  bisect.pEnd->u.pTo = 0;
  assert( p==bisect.pStart );

}

/*
** COMMAND:  test-shortest-path
**
** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2
**







|






>







138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
  bisect_reset();
  return 0;
}

/*
** Construct the path from bisect.pStart to bisect.pEnd in the u.pTo fields.
*/
BisectNode *bisect_reverse_path(void){
  BisectNode *p;
  for(p=bisect.pEnd; p && p->pFrom; p = p->pFrom){
    p->pFrom->u.pTo = p;
  }
  bisect.pEnd->u.pTo = 0;
  assert( p==bisect.pStart );
  return p;
}

/*
** COMMAND:  test-shortest-path
**
** Usage: %fossil test-shortest-path ?--no-merge? VERSION1 VERSION2
**
187
188
189
190
191
192
193












194
195
196
197
198
199
200
    if( p->u.pTo ){
      printf(" is a %s of\n", p->u.pTo->fromIsParent ? "parent" : "child");
    }else{
      printf("\n");
    }
  }
}













/*
** Find the shortest path between bad and good.
*/
static BisectNode *bisect_path(void){
  BisectNode *p;
  bisect.bad = db_lget_int("bisect-bad", 0);







>
>
>
>
>
>
>
>
>
>
>
>







189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
    if( p->u.pTo ){
      printf(" is a %s of\n", p->u.pTo->fromIsParent ? "parent" : "child");
    }else{
      printf("\n");
    }
  }
}

/*
** WEBPAGE:  path
**
** example:  /path?from=trunk&to=experimental&nomerge
**
** Show a timeline of all changes along a path between two versions.
*/
void path_page(void){
  login_check_credentials();
  if( !g.okRead ){ login_needed(); return; }
}

/*
** Find the shortest path between bad and good.
*/
static BisectNode *bisect_path(void){
  BisectNode *p;
  bisect.bad = db_lget_int("bisect-bad", 0);
Changes to src/timeline.c.
724
725
726
727
728
729
730



731
732
733
734
735
736
737
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't', 'e'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**    nd             Suppress "divider" lines
**    f=RID          Show family (immediate parents and children) of RID



**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
**
** If a= and b= appear, only a= is used.  If neither appear, the most
** recent events are choosen.
**







>
>
>







724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't', 'e'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**    nd             Suppress "divider" lines
**    f=RID          Show family (immediate parents and children) of RID
**    from=RID       Path from...
**    to=RID           ... to this
**    nomerge          ... avoid merge links on the path
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
**
** If a= and b= appear, only a= is used.  If neither appear, the most
** recent events are choosen.
**
755
756
757
758
759
760
761



762
763
764
765
766
767
768
  const char *zSearch = P("s");      /* Search string */
  int useDividers = P("nd")==0;      /* Show dividers if "nd" is missing */
  int tagid;                         /* Tag ID */
  int tmFlags;                       /* Timeline flags */
  const char *zThisTag = 0;          /* Suppress links to this tag */
  const char *zThisUser = 0;         /* Suppress links to this user */
  HQuery url;                        /* URL for various branch links */




  /* To view the timeline, must have permission to read project data.
  */
  login_check_credentials();
  if( !g.okRead && !g.okRdTkt && !g.okRdWiki ){ login_needed(); return; }
  if( zTagName && g.okRead ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);







>
>
>







758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
  const char *zSearch = P("s");      /* Search string */
  int useDividers = P("nd")==0;      /* Show dividers if "nd" is missing */
  int tagid;                         /* Tag ID */
  int tmFlags;                       /* Timeline flags */
  const char *zThisTag = 0;          /* Suppress links to this tag */
  const char *zThisUser = 0;         /* Suppress links to this user */
  HQuery url;                        /* URL for various branch links */
  int from_rid = name_to_rid(P("from"));  /* from= for path timelines */
  int to_rid = name_to_rid(P("to"));      /* to= for path timelines */
  int noMerge = P("nomerge")!=0;          /* Do not follow merge links */

  /* To view the timeline, must have permission to read project data.
  */
  login_check_credentials();
  if( !g.okRead && !g.okRdTkt && !g.okRdWiki ){ login_needed(); return; }
  if( zTagName && g.okRead ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName);
787
788
789
790
791
792
793































794
795
796
797
798
799
800
801
  timeline_temp_table();
  blob_zero(&sql);
  blob_zero(&desc);
  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
  blob_append(&sql, timeline_query_for_www(), -1);
  url_initialize(&url, "timeline");
  if( !useDividers ) url_add_parameter(&url, "nd", 0);































  if( (p_rid || d_rid) && g.okRead ){
    /* If p= or d= is present, ignore all other parameters other than n= */
    char *zUuid;
    int np, nd;

    if( p_rid && d_rid ){
      if( p_rid!=d_rid ) p_rid = d_rid;
      if( P("n")==0 ) nEntry = 10;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|







793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  timeline_temp_table();
  blob_zero(&sql);
  blob_zero(&desc);
  blob_append(&sql, "INSERT OR IGNORE INTO timeline ", -1);
  blob_append(&sql, timeline_query_for_www(), -1);
  url_initialize(&url, "timeline");
  if( !useDividers ) url_add_parameter(&url, "nd", 0);
  if( from_rid && to_rid && g.okRead ){
    /* If from= and to= are present, display all nodes on a path connecting
    ** the two */
    BisectNode *p;
    const char *z;

    bisect_shortest_path(from_rid, to_rid, noMerge);
    p = bisect_reverse_path();
    blob_append(&sql, " AND event.objid IN (0", -1);
    while( p ){
      blob_appendf(&sql, ",%d", p->rid);
      p = p->u.pTo;
    }
    blob_append(&sql, ")", -1);
    bisect_reset();
    blob_append(&desc, "All nodes on the path from ", -1);
    z = P("from");
    if( g.okHistory ){
      blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>",  g.zTop, z, z);
    }else{
      blob_appendf(&desc, "[%h]", z);
    }
    blob_append(&desc, " and ", -1);
    z = P("to");
    if( g.okHistory ){
      blob_appendf(&desc, "<a href='%s/info/%h'>[%h]</a>.",  g.zTop, z, z);
    }else{
      blob_appendf(&desc, "[%h].", z);
    }
    db_multi_exec("%s", blob_str(&sql));

  }else if( (p_rid || d_rid) && g.okRead ){
    /* If p= or d= is present, ignore all other parameters other than n= */
    char *zUuid;
    int np, nd;

    if( p_rid && d_rid ){
      if( p_rid!=d_rid ) p_rid = d_rid;
      if( P("n")==0 ) nEntry = 10;
851
852
853
854
855
856
857

858
859
860
861
862
863
864
    if( g.okHistory ){
      blob_appendf(&desc, "<a href='%s/info/%s'>[%.10s]</a>",
                   g.zTop, zUuid, zUuid);
    }else{
      blob_appendf(&desc, "[%.10s]", zUuid);
    }
  }else{

    int n;
    const char *zEType = "timeline item";
    char *zDate;
    char *zNEntry = mprintf("%d", nEntry);
    url_add_parameter(&url, "n", zNEntry);
    if( tagid>0 ){
      blob_appendf(&sql,







>







888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
    if( g.okHistory ){
      blob_appendf(&desc, "<a href='%s/info/%s'>[%.10s]</a>",
                   g.zTop, zUuid, zUuid);
    }else{
      blob_appendf(&desc, "[%.10s]", zUuid);
    }
  }else{
    /* Otherwise, a timeline based on a span of time */
    int n;
    const char *zEType = "timeline item";
    char *zDate;
    char *zNEntry = mprintf("%d", nEntry);
    url_add_parameter(&url, "n", zNEntry);
    if( tagid>0 ){
      blob_appendf(&sql,