Fossil SCM
Improvements to /finfo: Show all file rename events. The "rid" for each timeline entry must be a combination of the file-id "fid" and the filename-id "fnid" since either one of those two might change which should result in a new entry on the timeline.
Commit
8c598d7232c227e199612aa305e85d0f9534334077b49d66bbe163ccdff0b0f4
Parent
47bfea074b12261…
1 file changed
+21
-16
+21
-16
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -333,10 +333,11 @@ | ||
| 333 | 333 | int iTableId = timeline_tableid(); |
| 334 | 334 | int tmFlags = 0; /* Viewing mode */ |
| 335 | 335 | const char *zStyle; /* Viewing mode name */ |
| 336 | 336 | const char *zMark; /* Mark this version of the file */ |
| 337 | 337 | int selRid = 0; /* RID of the marked file version */ |
| 338 | + int mxfnid; /* Maximum filename.fnid value */ | |
| 338 | 339 | |
| 339 | 340 | login_check_credentials(); |
| 340 | 341 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 341 | 342 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| 342 | 343 | ridCi = zCI ? name_to_rid_www("ci") : 0; |
| @@ -392,11 +393,11 @@ | ||
| 392 | 393 | ** that should participate in the output. Clade is computed by |
| 393 | 394 | ** walking the graph of mlink edges. |
| 394 | 395 | */ |
| 395 | 396 | "WITH RECURSIVE clade(fid,fnid) AS (\n" |
| 396 | 397 | " SELECT blob.rid, %d FROM blob\n" /* %d is fnid */ |
| 397 | - " WHERE blob.uuid=(SELECT uuid FROM files_of_checkin(%Q)\n" | |
| 398 | + " WHERE blob.uuid=(SELECT uuid FROM files_of_checkin(%Q)" | |
| 398 | 399 | " WHERE filename=%Q)\n" /* %Q is the filename */ |
| 399 | 400 | " UNION\n" |
| 400 | 401 | " SELECT mlink.fid, mlink.fnid\n" |
| 401 | 402 | " FROM clade, mlink\n" |
| 402 | 403 | " WHERE clade.fid=mlink.pid\n" |
| @@ -477,11 +478,12 @@ | ||
| 477 | 478 | ** use a "fake fid" which is derived from the parent-fid for grouping. |
| 478 | 479 | ** The same fake-fid must be used on the graph. |
| 479 | 480 | */ |
| 480 | 481 | blob_append_sql(&sql, |
| 481 | 482 | "GROUP BY" |
| 482 | - " CASE WHEN mlink.fid>0 THEN mlink.fid ELSE mlink.pid+1000000000 END\n" | |
| 483 | + " CASE WHEN mlink.fid>0 THEN mlink.fid ELSE mlink.pid+1000000000 END," | |
| 484 | + " mlink.fnid\n" | |
| 483 | 485 | ); |
| 484 | 486 | } |
| 485 | 487 | blob_append_sql(&sql, "ORDER BY event.mtime DESC"); |
| 486 | 488 | if( (n = atoi(PD("n","0")))>0 ){ |
| 487 | 489 | blob_append_sql(&sql, " LIMIT %d", n); |
| @@ -538,22 +540,25 @@ | ||
| 538 | 540 | } |
| 539 | 541 | @ <h2>%b(&title)</h2> |
| 540 | 542 | blob_reset(&title); |
| 541 | 543 | pGraph = graph_init(); |
| 542 | 544 | @ <table id="timelineTable%d(iTableId)" class="timelineTable"> |
| 545 | + mxfnid = db_int(0, "SELECT max(fnid) FROM filename"); | |
| 543 | 546 | if( ridFrom ){ |
| 544 | 547 | db_prepare(&qparent, |
| 545 | - "SELECT DISTINCT pid FROM mlink" | |
| 548 | + "SELECT DISTINCT pid*%d+CASE WHEN pfnid>0 THEN pfnid ELSE fnid END" | |
| 549 | + " FROM mlink" | |
| 546 | 550 | " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" |
| 547 | 551 | " AND pmid IN (SELECT rid FROM ancestor)" |
| 548 | - " ORDER BY isaux /*sort*/" | |
| 552 | + " ORDER BY isaux /*sort*/", mxfnid+1 | |
| 549 | 553 | ); |
| 550 | 554 | }else{ |
| 551 | 555 | db_prepare(&qparent, |
| 552 | - "SELECT DISTINCT pid FROM mlink" | |
| 556 | + "SELECT DISTINCT pid*%d+CASE WHEN pfnid>0 THEN pfnid ELSE fnid END" | |
| 557 | + " FROM mlink" | |
| 553 | 558 | " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" |
| 554 | - " ORDER BY isaux /*sort*/" | |
| 559 | + " ORDER BY isaux /*sort*/", mxfnid+1 | |
| 555 | 560 | ); |
| 556 | 561 | } |
| 557 | 562 | while( db_step(&q)==SQLITE_ROW ){ |
| 558 | 563 | const char *zDate = db_column_text(&q, 0); |
| 559 | 564 | const char *zCom = db_column_text(&q, 1); |
| @@ -587,11 +592,12 @@ | ||
| 587 | 592 | if( uBg ){ |
| 588 | 593 | zBgClr = hash_color(zUser); |
| 589 | 594 | }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){ |
| 590 | 595 | zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr); |
| 591 | 596 | } |
| 592 | - gidx = graph_add_row(pGraph, frid>0 ? frid : fpid+1000000000, | |
| 597 | + gidx = graph_add_row(pGraph, | |
| 598 | + frid>0 ? frid*(mxfnid+1)+fnid : fpid+1000000000, | |
| 593 | 599 | nParent, 0, aParent, zBr, zBgClr, |
| 594 | 600 | zUuid, 0); |
| 595 | 601 | if( strncmp(zDate, zPrevDate, 10) ){ |
| 596 | 602 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 597 | 603 | @ <tr><td> |
| @@ -639,10 +645,16 @@ | ||
| 639 | 645 | } |
| 640 | 646 | if( tmFlags & TIMELINE_COMPACT ){ |
| 641 | 647 | cgi_printf("<span class='clutter' id='detail-%d'>",frid); |
| 642 | 648 | } |
| 643 | 649 | cgi_printf("<span class='timeline%sDetail'>", zStyle); |
| 650 | + if( pfnid ){ | |
| 651 | + char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d", | |
| 652 | + pfnid); | |
| 653 | + @ <b>Renamed</b> %h(zPrevName) → %h(zFName). | |
| 654 | + fossil_free(zPrevName); | |
| 655 | + } | |
| 644 | 656 | if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("("); |
| 645 | 657 | if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){ |
| 646 | 658 | @ file: %z(href("%R/file?name=%T&ci=%!S",zFName,zCkin))\ |
| 647 | 659 | @ [%S(zUuid)]</a> |
| 648 | 660 | if( fShowId ){ |
| @@ -665,19 +677,12 @@ | ||
| 665 | 677 | if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ){ |
| 666 | 678 | @ size: %d(szFile)) |
| 667 | 679 | }else{ |
| 668 | 680 | @ size: %d(szFile) |
| 669 | 681 | } |
| 670 | - if( zUuid && ridTo==0 ){ | |
| 671 | - if( nParent==0 ){ | |
| 672 | - @ <b>Added</b> | |
| 673 | - }else if( pfnid ){ | |
| 674 | - char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d", | |
| 675 | - pfnid); | |
| 676 | - @ <b>Renamed</b> from | |
| 677 | - @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a> | |
| 678 | - } | |
| 682 | + if( zUuid && ridTo==0 && nParent==0 ){ | |
| 683 | + @ <b>Added</b> | |
| 679 | 684 | } |
| 680 | 685 | if( zUuid==0 ){ |
| 681 | 686 | char *zNewName; |
| 682 | 687 | zNewName = db_text(0, |
| 683 | 688 | "SELECT name FROM filename WHERE fnid = " |
| 684 | 689 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -333,10 +333,11 @@ | |
| 333 | int iTableId = timeline_tableid(); |
| 334 | int tmFlags = 0; /* Viewing mode */ |
| 335 | const char *zStyle; /* Viewing mode name */ |
| 336 | const char *zMark; /* Mark this version of the file */ |
| 337 | int selRid = 0; /* RID of the marked file version */ |
| 338 | |
| 339 | login_check_credentials(); |
| 340 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 341 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| 342 | ridCi = zCI ? name_to_rid_www("ci") : 0; |
| @@ -392,11 +393,11 @@ | |
| 392 | ** that should participate in the output. Clade is computed by |
| 393 | ** walking the graph of mlink edges. |
| 394 | */ |
| 395 | "WITH RECURSIVE clade(fid,fnid) AS (\n" |
| 396 | " SELECT blob.rid, %d FROM blob\n" /* %d is fnid */ |
| 397 | " WHERE blob.uuid=(SELECT uuid FROM files_of_checkin(%Q)\n" |
| 398 | " WHERE filename=%Q)\n" /* %Q is the filename */ |
| 399 | " UNION\n" |
| 400 | " SELECT mlink.fid, mlink.fnid\n" |
| 401 | " FROM clade, mlink\n" |
| 402 | " WHERE clade.fid=mlink.pid\n" |
| @@ -477,11 +478,12 @@ | |
| 477 | ** use a "fake fid" which is derived from the parent-fid for grouping. |
| 478 | ** The same fake-fid must be used on the graph. |
| 479 | */ |
| 480 | blob_append_sql(&sql, |
| 481 | "GROUP BY" |
| 482 | " CASE WHEN mlink.fid>0 THEN mlink.fid ELSE mlink.pid+1000000000 END\n" |
| 483 | ); |
| 484 | } |
| 485 | blob_append_sql(&sql, "ORDER BY event.mtime DESC"); |
| 486 | if( (n = atoi(PD("n","0")))>0 ){ |
| 487 | blob_append_sql(&sql, " LIMIT %d", n); |
| @@ -538,22 +540,25 @@ | |
| 538 | } |
| 539 | @ <h2>%b(&title)</h2> |
| 540 | blob_reset(&title); |
| 541 | pGraph = graph_init(); |
| 542 | @ <table id="timelineTable%d(iTableId)" class="timelineTable"> |
| 543 | if( ridFrom ){ |
| 544 | db_prepare(&qparent, |
| 545 | "SELECT DISTINCT pid FROM mlink" |
| 546 | " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" |
| 547 | " AND pmid IN (SELECT rid FROM ancestor)" |
| 548 | " ORDER BY isaux /*sort*/" |
| 549 | ); |
| 550 | }else{ |
| 551 | db_prepare(&qparent, |
| 552 | "SELECT DISTINCT pid FROM mlink" |
| 553 | " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" |
| 554 | " ORDER BY isaux /*sort*/" |
| 555 | ); |
| 556 | } |
| 557 | while( db_step(&q)==SQLITE_ROW ){ |
| 558 | const char *zDate = db_column_text(&q, 0); |
| 559 | const char *zCom = db_column_text(&q, 1); |
| @@ -587,11 +592,12 @@ | |
| 587 | if( uBg ){ |
| 588 | zBgClr = hash_color(zUser); |
| 589 | }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){ |
| 590 | zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr); |
| 591 | } |
| 592 | gidx = graph_add_row(pGraph, frid>0 ? frid : fpid+1000000000, |
| 593 | nParent, 0, aParent, zBr, zBgClr, |
| 594 | zUuid, 0); |
| 595 | if( strncmp(zDate, zPrevDate, 10) ){ |
| 596 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 597 | @ <tr><td> |
| @@ -639,10 +645,16 @@ | |
| 639 | } |
| 640 | if( tmFlags & TIMELINE_COMPACT ){ |
| 641 | cgi_printf("<span class='clutter' id='detail-%d'>",frid); |
| 642 | } |
| 643 | cgi_printf("<span class='timeline%sDetail'>", zStyle); |
| 644 | if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("("); |
| 645 | if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){ |
| 646 | @ file: %z(href("%R/file?name=%T&ci=%!S",zFName,zCkin))\ |
| 647 | @ [%S(zUuid)]</a> |
| 648 | if( fShowId ){ |
| @@ -665,19 +677,12 @@ | |
| 665 | if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ){ |
| 666 | @ size: %d(szFile)) |
| 667 | }else{ |
| 668 | @ size: %d(szFile) |
| 669 | } |
| 670 | if( zUuid && ridTo==0 ){ |
| 671 | if( nParent==0 ){ |
| 672 | @ <b>Added</b> |
| 673 | }else if( pfnid ){ |
| 674 | char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d", |
| 675 | pfnid); |
| 676 | @ <b>Renamed</b> from |
| 677 | @ %z(href("%R/finfo?name=%t", zPrevName))%h(zPrevName)</a> |
| 678 | } |
| 679 | } |
| 680 | if( zUuid==0 ){ |
| 681 | char *zNewName; |
| 682 | zNewName = db_text(0, |
| 683 | "SELECT name FROM filename WHERE fnid = " |
| 684 |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -333,10 +333,11 @@ | |
| 333 | int iTableId = timeline_tableid(); |
| 334 | int tmFlags = 0; /* Viewing mode */ |
| 335 | const char *zStyle; /* Viewing mode name */ |
| 336 | const char *zMark; /* Mark this version of the file */ |
| 337 | int selRid = 0; /* RID of the marked file version */ |
| 338 | int mxfnid; /* Maximum filename.fnid value */ |
| 339 | |
| 340 | login_check_credentials(); |
| 341 | if( !g.perm.Read ){ login_needed(g.anon.Read); return; } |
| 342 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", zFilename); |
| 343 | ridCi = zCI ? name_to_rid_www("ci") : 0; |
| @@ -392,11 +393,11 @@ | |
| 393 | ** that should participate in the output. Clade is computed by |
| 394 | ** walking the graph of mlink edges. |
| 395 | */ |
| 396 | "WITH RECURSIVE clade(fid,fnid) AS (\n" |
| 397 | " SELECT blob.rid, %d FROM blob\n" /* %d is fnid */ |
| 398 | " WHERE blob.uuid=(SELECT uuid FROM files_of_checkin(%Q)" |
| 399 | " WHERE filename=%Q)\n" /* %Q is the filename */ |
| 400 | " UNION\n" |
| 401 | " SELECT mlink.fid, mlink.fnid\n" |
| 402 | " FROM clade, mlink\n" |
| 403 | " WHERE clade.fid=mlink.pid\n" |
| @@ -477,11 +478,12 @@ | |
| 478 | ** use a "fake fid" which is derived from the parent-fid for grouping. |
| 479 | ** The same fake-fid must be used on the graph. |
| 480 | */ |
| 481 | blob_append_sql(&sql, |
| 482 | "GROUP BY" |
| 483 | " CASE WHEN mlink.fid>0 THEN mlink.fid ELSE mlink.pid+1000000000 END," |
| 484 | " mlink.fnid\n" |
| 485 | ); |
| 486 | } |
| 487 | blob_append_sql(&sql, "ORDER BY event.mtime DESC"); |
| 488 | if( (n = atoi(PD("n","0")))>0 ){ |
| 489 | blob_append_sql(&sql, " LIMIT %d", n); |
| @@ -538,22 +540,25 @@ | |
| 540 | } |
| 541 | @ <h2>%b(&title)</h2> |
| 542 | blob_reset(&title); |
| 543 | pGraph = graph_init(); |
| 544 | @ <table id="timelineTable%d(iTableId)" class="timelineTable"> |
| 545 | mxfnid = db_int(0, "SELECT max(fnid) FROM filename"); |
| 546 | if( ridFrom ){ |
| 547 | db_prepare(&qparent, |
| 548 | "SELECT DISTINCT pid*%d+CASE WHEN pfnid>0 THEN pfnid ELSE fnid END" |
| 549 | " FROM mlink" |
| 550 | " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" |
| 551 | " AND pmid IN (SELECT rid FROM ancestor)" |
| 552 | " ORDER BY isaux /*sort*/", mxfnid+1 |
| 553 | ); |
| 554 | }else{ |
| 555 | db_prepare(&qparent, |
| 556 | "SELECT DISTINCT pid*%d+CASE WHEN pfnid>0 THEN pfnid ELSE fnid END" |
| 557 | " FROM mlink" |
| 558 | " WHERE fid=:fid AND mid=:mid AND pid>0 AND fnid=:fnid" |
| 559 | " ORDER BY isaux /*sort*/", mxfnid+1 |
| 560 | ); |
| 561 | } |
| 562 | while( db_step(&q)==SQLITE_ROW ){ |
| 563 | const char *zDate = db_column_text(&q, 0); |
| 564 | const char *zCom = db_column_text(&q, 1); |
| @@ -587,11 +592,12 @@ | |
| 592 | if( uBg ){ |
| 593 | zBgClr = hash_color(zUser); |
| 594 | }else if( brBg || zBgClr==0 || zBgClr[0]==0 ){ |
| 595 | zBgClr = strcmp(zBr,"trunk")==0 ? "" : hash_color(zBr); |
| 596 | } |
| 597 | gidx = graph_add_row(pGraph, |
| 598 | frid>0 ? frid*(mxfnid+1)+fnid : fpid+1000000000, |
| 599 | nParent, 0, aParent, zBr, zBgClr, |
| 600 | zUuid, 0); |
| 601 | if( strncmp(zDate, zPrevDate, 10) ){ |
| 602 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 603 | @ <tr><td> |
| @@ -639,10 +645,16 @@ | |
| 645 | } |
| 646 | if( tmFlags & TIMELINE_COMPACT ){ |
| 647 | cgi_printf("<span class='clutter' id='detail-%d'>",frid); |
| 648 | } |
| 649 | cgi_printf("<span class='timeline%sDetail'>", zStyle); |
| 650 | if( pfnid ){ |
| 651 | char *zPrevName = db_text(0,"SELECT name FROM filename WHERE fnid=%d", |
| 652 | pfnid); |
| 653 | @ <b>Renamed</b> %h(zPrevName) → %h(zFName). |
| 654 | fossil_free(zPrevName); |
| 655 | } |
| 656 | if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ) cgi_printf("("); |
| 657 | if( zUuid && (tmFlags & TIMELINE_VERBOSE)==0 ){ |
| 658 | @ file: %z(href("%R/file?name=%T&ci=%!S",zFName,zCkin))\ |
| 659 | @ [%S(zUuid)]</a> |
| 660 | if( fShowId ){ |
| @@ -665,19 +677,12 @@ | |
| 677 | if( tmFlags & (TIMELINE_COMPACT|TIMELINE_VERBOSE) ){ |
| 678 | @ size: %d(szFile)) |
| 679 | }else{ |
| 680 | @ size: %d(szFile) |
| 681 | } |
| 682 | if( zUuid && ridTo==0 && nParent==0 ){ |
| 683 | @ <b>Added</b> |
| 684 | } |
| 685 | if( zUuid==0 ){ |
| 686 | char *zNewName; |
| 687 | zNewName = db_text(0, |
| 688 | "SELECT name FROM filename WHERE fnid = " |
| 689 |