Fossil

Check-in [67529340]
Login

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

Overview
Comment:On a branch timeline, in addition to showing the checkins of the branch, also show check-ins of other branches that merge into or from the branch being displayed. This helps to show what has happened to an infrequently changing branch which is part of a much more active project.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 67529340264cf8bb2383593a8aadae16428094cb
User & Date: drh 2010-06-16 20:33:58
Context
2010-06-17
01:37
Update to the latest version of SQLite - one that includes the fix for the corruption bug associated with the file-size in byte 28 of the database header. Also fix a bug in the graph generator, and change an index to help timeline run faster for branch queries. check-in: 5129d32a user: drh tags: trunk
2010-06-16
20:33
On a branch timeline, in addition to showing the checkins of the branch, also show check-ins of other branches that merge into or from the branch being displayed. This helps to show what has happened to an infrequently changing branch which is part of a much more active project. check-in: 67529340 user: drh tags: trunk
2010-06-13
15:58
Add the ability to escape Wiki page names in hyperlinks using a wiki: prefix. Ticket [f58a05747498d3aaa9ea1e4f8f4015c209dfc54a]. check-in: d6b2c387 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/branch.c.

250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      @ <h2>Open Branches:</h2>
      @ <ul>
      cnt++;
    }
    if( g.okHistory ){
      @ <li><a href="%s(g.zBaseURL)/timeline?t=%T(zBr)">%h(zBr)</a></li>
    }else{
      @ <li><b>%h(zBr)</b></li>
    }
  }
  db_finalize(&q);
  if( cnt ){
    @ </ul>
................................................................................
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      @ <h2>Closed Branches:</h2>
      @ <ul>
      cnt++;     
    }
    if( g.okHistory ){
      @ <li><a href="%s(g.zBaseURL)/timeline?t=%T(zBr)">%h(zBr)</a></li>
    }else{
      @ <li><b>%h(zBr)</b></li>
    }
  }
  if( cnt ){
    @ </ul>
  }
................................................................................
    "   AND tagxref.tagid=tag.tagid"
    "   AND tagxref.tagtype>0"
    "   AND tag.tagname GLOB 'sym-*'",
    rid
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zTagName = db_column_text(&q, 0);
    @ <a href="%s(g.zBaseURL)/timeline?t=%T(zTagName)">[timeline]</a>
  }
  db_finalize(&q);
}

/*
** WEBPAGE: brtimeline
**







|







 







|







 







|







250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
...
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      @ <h2>Open Branches:</h2>
      @ <ul>
      cnt++;
    }
    if( g.okHistory ){
      @ <li><a href="%s(g.zBaseURL)/timeline?r=%T(zBr)">%h(zBr)</a></li>
    }else{
      @ <li><b>%h(zBr)</b></li>
    }
  }
  db_finalize(&q);
  if( cnt ){
    @ </ul>
................................................................................
    const char *zBr = db_column_text(&q, 0);
    if( cnt==0 ){
      @ <h2>Closed Branches:</h2>
      @ <ul>
      cnt++;     
    }
    if( g.okHistory ){
      @ <li><a href="%s(g.zBaseURL)/timeline?r=%T(zBr)">%h(zBr)</a></li>
    }else{
      @ <li><b>%h(zBr)</b></li>
    }
  }
  if( cnt ){
    @ </ul>
  }
................................................................................
    "   AND tagxref.tagid=tag.tagid"
    "   AND tagxref.tagtype>0"
    "   AND tag.tagname GLOB 'sym-*'",
    rid
  );
  while( db_step(&q)==SQLITE_ROW ){
    const char *zTagName = db_column_text(&q, 0);
    @ <a href="%s(g.zBaseURL)/timeline?r=%T(zTagName)">[timeline]</a>
  }
  db_finalize(&q);
}

/*
** WEBPAGE: brtimeline
**

Changes to src/info.c.

200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        @ inherited from
        hyperlink_to_uuid(zOrigUuid);
      }else{
        @ propagates to descendants
      }
      if( zValue && strcmp(zTagname,"branch")==0 ){
        @ &nbsp;&nbsp;
        @ <a href="%s(g.zBaseURL)/timeline?t=%T(zValue)">branch timeline</a>
      }
    }
    if( zSrcUuid && zSrcUuid[0] ){
      if( tagtype==0 ){
        @ by
      }else{
        @ added by
................................................................................
      @    | <a href="%s(g.zBaseURL)/timeline?d=%S(zUuid)&p=%S(zUuid)">both</a>
      db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
                     " WHERE rid=%d AND tagtype>0 "
                     "   AND tag.tagid=tagxref.tagid "
                     "   AND +tag.tagname GLOB 'sym-*'", rid);
      while( db_step(&q)==SQLITE_ROW ){
        const char *zTagName = db_column_text(&q, 0);
        @  | <a href="%s(g.zTop)/timeline?t=%T(zTagName)">%h(zTagName)</a>
      }
      db_finalize(&q);
      @ </td></tr>
      @ <tr><th>Other&nbsp;Links:</th>
      @   <td>
      @     <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a>
      @   | <a href="%s(g.zTop)/zip/%s(zProjName)-%S(zUuid).zip?uuid=%s(zUuid)">







|







 







|







200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
...
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
        @ inherited from
        hyperlink_to_uuid(zOrigUuid);
      }else{
        @ propagates to descendants
      }
      if( zValue && strcmp(zTagname,"branch")==0 ){
        @ &nbsp;&nbsp;
        @ <a href="%s(g.zBaseURL)/timeline?r=%T(zValue)">branch timeline</a>
      }
    }
    if( zSrcUuid && zSrcUuid[0] ){
      if( tagtype==0 ){
        @ by
      }else{
        @ added by
................................................................................
      @    | <a href="%s(g.zBaseURL)/timeline?d=%S(zUuid)&p=%S(zUuid)">both</a>
      db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
                     " WHERE rid=%d AND tagtype>0 "
                     "   AND tag.tagid=tagxref.tagid "
                     "   AND +tag.tagname GLOB 'sym-*'", rid);
      while( db_step(&q)==SQLITE_ROW ){
        const char *zTagName = db_column_text(&q, 0);
        @  | <a href="%s(g.zTop)/timeline?r=%T(zTagName)">%h(zTagName)</a>
      }
      db_finalize(&q);
      @ </td></tr>
      @ <tr><th>Other&nbsp;Links:</th>
      @   <td>
      @     <a href="%s(g.zTop)/dir?ci=%S(zUuid)">files</a>
      @   | <a href="%s(g.zTop)/zip/%s(zProjName)-%S(zUuid).zip?uuid=%s(zUuid)">

Changes to src/timeline.c.

623
624
625
626
627
628
629

630
631
632
633
634
635
636
...
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
...
738
739
740
741
742
743
744











745
746

747
748







749
750
751
752
753
754
755
...
850
851
852
853
854
855
856
857
858
859



860
861
862
863
864
865
866
**    a=TIMESTAMP    after this date
**    b=TIMESTAMP    before this date.
**    c=TIMESTAMP    "circa" this date.
**    n=COUNT        number of events in output
**    p=RID          artifact RID and up to COUNT parents and ancestors
**    d=RID          artifact RID and up to COUNT descendants
**    t=TAGID        show only check-ins with the given tagid

**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
................................................................................
  int d_rid = name_to_rid(P("d"));    /* artifact d and its descendants */
  const char *zUser = P("u");        /* All entries by this user if not NULL */
  const char *zType = PD("y","all"); /* Type of events.  All if NULL */
  const char *zAfter = P("a");       /* Events after this time */
  const char *zBefore = P("b");      /* Events before this time */
  const char *zCirca = P("c");       /* Events near this time */
  const char *zTagName = P("t");     /* Show events with this tag */

  const char *zSearch = P("s");      /* Search string */
  HQuery url;                        /* URL for various branch links */
  int tagid;                         /* Tag ID */
  int tmFlags;                       /* Timeline flags */

  /* 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);


  }else{
    tagid = 0;
  }
  if( zType[0]=='a' ){
    tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
  }else{
    tmFlags = TIMELINE_GRAPH;
................................................................................
    const char *zEType = "event";
    char *zDate;
    char *zNEntry = mprintf("%d", nEntry);
    url_initialize(&url, "timeline");
    url_add_parameter(&url, "n", zNEntry);
    if( tagid>0 ){
      zType = "ci";











      url_add_parameter(&url, "t", zTagName);
      blob_appendf(&sql, " AND EXISTS (SELECT 1 FROM tagxref WHERE tagid=%d"

                                        " AND tagtype>0 AND rid=blob.rid)",
                   tagid);







    }
    if( (zType[0]=='w' && !g.okRdWiki)
     || (zType[0]=='t' && !g.okRdTkt)
     || (zType[0]=='c' && !g.okRead)
    ){
      zType = "all";
    }
................................................................................
    }else{
      blob_appendf(&desc, "%d %ss", n, zEType);
    }
    if( zUser ){
      blob_appendf(&desc, " by user %h", zUser);
      tmFlags |= TIMELINE_DISJOINT;
    }
    if( tagid>0 ){
      blob_appendf(&desc, " tagged with \"%h\"", zTagName);
      tmFlags |= TIMELINE_DISJOINT;



    }
    if( zAfter ){
      blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
    }else if( zBefore ){
      blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
    }else if( zCirca ){
      blob_appendf(&desc, " occurring around %h.<br>", zCirca);







>







 







>











>
>







 







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







 







|


>
>
>







623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
...
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
...
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
...
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
**    a=TIMESTAMP    after this date
**    b=TIMESTAMP    before this date.
**    c=TIMESTAMP    "circa" this date.
**    n=COUNT        number of events in output
**    p=RID          artifact RID and up to COUNT parents and ancestors
**    d=RID          artifact RID and up to COUNT descendants
**    t=TAGID        show only check-ins with the given tagid
**    r=TAGID        show check-ins related to tagid
**    u=USER         only if belonging to this user
**    y=TYPE         'ci', 'w', 't'
**    s=TEXT         string search (comment and brief)
**    ng             Suppress the graph if present
**
** p= and d= can appear individually or together.  If either p= or d=
** appear, then u=, y=, a=, and b= are ignored.
................................................................................
  int d_rid = name_to_rid(P("d"));    /* artifact d and its descendants */
  const char *zUser = P("u");        /* All entries by this user if not NULL */
  const char *zType = PD("y","all"); /* Type of events.  All if NULL */
  const char *zAfter = P("a");       /* Events after this time */
  const char *zBefore = P("b");      /* Events before this time */
  const char *zCirca = P("c");       /* Events near this time */
  const char *zTagName = P("t");     /* Show events with this tag */
  const char *zBrName = P("r");      /* Show events related to this tag */
  const char *zSearch = P("s");      /* Search string */
  HQuery url;                        /* URL for various branch links */
  int tagid;                         /* Tag ID */
  int tmFlags;                       /* Timeline flags */

  /* 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);
  }else if( zBrName && g.okRead ){
    tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName);
  }else{
    tagid = 0;
  }
  if( zType[0]=='a' ){
    tmFlags = TIMELINE_BRIEF | TIMELINE_GRAPH;
  }else{
    tmFlags = TIMELINE_GRAPH;
................................................................................
    const char *zEType = "event";
    char *zDate;
    char *zNEntry = mprintf("%d", nEntry);
    url_initialize(&url, "timeline");
    url_add_parameter(&url, "n", zNEntry);
    if( tagid>0 ){
      zType = "ci";
      blob_appendf(&sql,
        "AND (EXISTS(SELECT 1 FROM tagxref"
                    " WHERE tagid=%d AND tagtype>0 AND rid=blob.rid)", tagid);

      if( zBrName ){
        /* The next two blob_appendf() calls add SQL that causes checkins that
        ** are not part of the branch which are parents or childen of the branch
        ** to be included in the report.  This related check-ins are useful
        ** in helping to visualize what has happened on a quiescent branch 
        ** that is infrequently merged with a much more activate branch.
        */
        url_add_parameter(&url, "r", zBrName);
        blob_appendf(&sql,
          " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=cid"
                     " WHERE tagid=%d AND tagtype>0 AND pid=blob.rid)", tagid);

        blob_appendf(&sql,
          " OR EXISTS(SELECT 1 FROM plink JOIN tagxref ON rid=pid"
                     " WHERE tagid=%d AND tagtype>0 AND cid=blob.rid)", tagid);
      }else{
        url_add_parameter(&url, "t", zTagName);
      }
      blob_appendf(&sql, ")");
    }
    if( (zType[0]=='w' && !g.okRdWiki)
     || (zType[0]=='t' && !g.okRdTkt)
     || (zType[0]=='c' && !g.okRead)
    ){
      zType = "all";
    }
................................................................................
    }else{
      blob_appendf(&desc, "%d %ss", n, zEType);
    }
    if( zUser ){
      blob_appendf(&desc, " by user %h", zUser);
      tmFlags |= TIMELINE_DISJOINT;
    }
    if( zTagName ){
      blob_appendf(&desc, " tagged with \"%h\"", zTagName);
      tmFlags |= TIMELINE_DISJOINT;
    }else if( zBrName ){
      blob_appendf(&desc, " related to \"%h\"", zBrName);
      tmFlags |= TIMELINE_DISJOINT;
    }
    if( zAfter ){
      blob_appendf(&desc, " occurring on or after %h.<br>", zAfter);
    }else if( zBefore ){
      blob_appendf(&desc, " occurring on or before %h.<br>", zBefore);
    }else if( zCirca ){
      blob_appendf(&desc, " occurring around %h.<br>", zCirca);