Fossil SCM

Show the ages of files in the file tree viewer.

drh 2014-12-16 16:32 UTC trunk
Commit f8d54372e76ca5d3a8075be4b5d9b02ca5851ebd
2 files changed +33 -28 +5
+33 -28
--- src/browse.c
+++ src/browse.c
@@ -310,10 +310,11 @@
310310
FileTreeNode *pPrev; /* Previous line */
311311
FileTreeNode *pParent; /* Directory containing this line */
312312
char *zName; /* Name of this entry. The "tail" */
313313
char *zFullName; /* Full pathname of this entry */
314314
char *zUuid; /* SHA1 hash of this file. May be NULL. */
315
+ double mtime; /* Modification time for this entry */
315316
unsigned nFullName; /* Length of zFullName */
316317
unsigned iLevel; /* Levels of parent directories */
317318
u8 isDir; /* True if there are children */
318319
u8 isLast; /* True if this is the last child of its parent */
319320
};
@@ -331,11 +332,12 @@
331332
** leaf object zPathname is at the end of the node list
332333
*/
333334
static void tree_add_node(
334335
FileTree *pTree, /* Tree into which nodes are added */
335336
const char *zPath, /* The full pathname of file to add */
336
- const char *zUuid /* UUID of the file. Might be NULL. */
337
+ const char *zUuid, /* UUID of the file. Might be NULL. */
338
+ double mtime /* Modification time for this entry */
337339
){
338340
int i;
339341
FileTreeNode *pParent;
340342
FileTreeNode *pChild;
341343
@@ -379,12 +381,19 @@
379381
pNew->pParent = pParent;
380382
pTree->pLast = pNew;
381383
pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
382384
pNew->isDir = zPath[i]=='/';
383385
pNew->isLast = 1;
386
+ pNew->mtime = mtime;
384387
while( zPath[i]=='/' ){ i++; }
385388
pParent = pNew;
389
+ }
390
+ while( pParent && pParent->pParent ){
391
+ if( pParent->pParent->mtime < pParent->mtime ){
392
+ pParent->pParent->mtime = pParent->mtime;
393
+ }
394
+ pParent = pParent->pParent;
386395
}
387396
}
388397
389398
/*
390399
** WEBPAGE: tree
@@ -403,10 +412,11 @@
403412
const char *zCI = P("ci");
404413
int rid = 0;
405414
char *zUuid = 0;
406415
Blob dirname;
407416
Manifest *pM = 0;
417
+ double rNow = db_double(0.0,"SELECT julianday('now')");
408418
int nFile = 0; /* Number of files (or folders with "nofiles") */
409419
int linkTrunk = 1; /* include link to "trunk" */
410420
int linkTip = 1; /* include link to "tip" */
411421
const char *zRE; /* the value for the re=REGEXP query parameter */
412422
const char *zObjType; /* "files" by default or "folders" for "nofiles" */
@@ -507,38 +517,25 @@
507517
}
508518
509519
/* Compute the file hierarchy.
510520
*/
511521
if( zCI ){
512
- Stmt ins, q;
513
- ManifestFile *pFile;
514
-
515
- db_multi_exec(
516
- "CREATE TEMP TABLE filelist("
517
- " x TEXT PRIMARY KEY COLLATE nocase,"
518
- " uuid TEXT"
519
- ") WITHOUT ROWID;"
522
+ Stmt q;
523
+ compute_fileage(rid, 0);
524
+ db_prepare(&q,
525
+ "SELECT filename.name, blob.uuid, fileage.mtime\n"
526
+ " FROM fileage, filename, blob\n"
527
+ " WHERE filename.fnid=fileage.fnid\n"
528
+ " AND blob.rid=fileage.fid\n"
529
+ " ORDER BY filename.name COLLATE nocase;"
520530
);
521
- db_prepare(&ins, "INSERT OR IGNORE INTO filelist VALUES(:f,:u)");
522
- manifest_file_rewind(pM);
523
- while( (pFile = manifest_file_next(pM,0))!=0 ){
524
- if( nD>0
525
- && (fossil_strncmp(pFile->zName, zD, nD-1)!=0
526
- || pFile->zName[nD-1]!='/')
527
- ){
528
- continue;
529
- }
530
- if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
531
- db_bind_text(&ins, ":f", pFile->zName);
532
- db_bind_text(&ins, ":u", pFile->zUuid);
533
- db_step(&ins);
534
- db_reset(&ins);
535
- }
536
- db_finalize(&ins);
537
- db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x");
538531
while( db_step(&q)==SQLITE_ROW ){
539
- tree_add_node(&sTree, db_column_text(&q,0), db_column_text(&q,1));
532
+ const char *zFile = db_column_text(&q,0);
533
+ const char *zUuid = db_column_text(&q,1);
534
+ double mtime = db_column_double(&q,2);
535
+ if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
536
+ tree_add_node(&sTree, zFile, zUuid, mtime);
540537
nFile++;
541538
}
542539
db_finalize(&q);
543540
}else{
544541
Stmt q;
@@ -547,11 +544,11 @@
547544
const char *z = db_column_text(&q, 0);
548545
if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
549546
continue;
550547
}
551548
if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
552
- tree_add_node(&sTree, z, 0);
549
+ tree_add_node(&sTree, z, 0, 0.0);
553550
nFile++;
554551
}
555552
db_finalize(&q);
556553
}
557554
@@ -604,10 +601,14 @@
604601
const char *zLastClass = p->isLast ? " last" : "";
605602
if( p->isDir ){
606603
const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : "";
607604
@ <li class="dir%s(zSubdirClass)%s(zLastClass)">
608605
@ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a>
606
+ if( p->mtime>0 ){
607
+ char *zAge = human_readable_age(rNow - p->mtime);
608
+ @ <div class="filetreeage">%s(zAge) ago</div>
609
+ }
609610
if( startExpanded || p->nFullName<=nD ){
610611
@ <ul id="dir%d(nDir)">
611612
}else{
612613
@ <ul id="dir%d(nDir)" class="collapsed">
613614
}
@@ -619,10 +620,14 @@
619620
zLink = href("%R/artifact/%s",p->zUuid);
620621
}else{
621622
zLink = href("%R/finfo?name=%T",p->zFullName);
622623
}
623624
@ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
625
+ if( p->mtime>0 ){
626
+ char *zAge = human_readable_age(rNow - p->mtime);
627
+ @ <div class="filetreeage">%s(zAge) ago</div>
628
+ }
624629
}
625630
if( p->isLast ){
626631
int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0);
627632
while( nClose-- > 0 ){
628633
@ </ul>
629634
--- src/browse.c
+++ src/browse.c
@@ -310,10 +310,11 @@
310 FileTreeNode *pPrev; /* Previous line */
311 FileTreeNode *pParent; /* Directory containing this line */
312 char *zName; /* Name of this entry. The "tail" */
313 char *zFullName; /* Full pathname of this entry */
314 char *zUuid; /* SHA1 hash of this file. May be NULL. */
 
315 unsigned nFullName; /* Length of zFullName */
316 unsigned iLevel; /* Levels of parent directories */
317 u8 isDir; /* True if there are children */
318 u8 isLast; /* True if this is the last child of its parent */
319 };
@@ -331,11 +332,12 @@
331 ** leaf object zPathname is at the end of the node list
332 */
333 static void tree_add_node(
334 FileTree *pTree, /* Tree into which nodes are added */
335 const char *zPath, /* The full pathname of file to add */
336 const char *zUuid /* UUID of the file. Might be NULL. */
 
337 ){
338 int i;
339 FileTreeNode *pParent;
340 FileTreeNode *pChild;
341
@@ -379,12 +381,19 @@
379 pNew->pParent = pParent;
380 pTree->pLast = pNew;
381 pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
382 pNew->isDir = zPath[i]=='/';
383 pNew->isLast = 1;
 
384 while( zPath[i]=='/' ){ i++; }
385 pParent = pNew;
 
 
 
 
 
 
386 }
387 }
388
389 /*
390 ** WEBPAGE: tree
@@ -403,10 +412,11 @@
403 const char *zCI = P("ci");
404 int rid = 0;
405 char *zUuid = 0;
406 Blob dirname;
407 Manifest *pM = 0;
 
408 int nFile = 0; /* Number of files (or folders with "nofiles") */
409 int linkTrunk = 1; /* include link to "trunk" */
410 int linkTip = 1; /* include link to "tip" */
411 const char *zRE; /* the value for the re=REGEXP query parameter */
412 const char *zObjType; /* "files" by default or "folders" for "nofiles" */
@@ -507,38 +517,25 @@
507 }
508
509 /* Compute the file hierarchy.
510 */
511 if( zCI ){
512 Stmt ins, q;
513 ManifestFile *pFile;
514
515 db_multi_exec(
516 "CREATE TEMP TABLE filelist("
517 " x TEXT PRIMARY KEY COLLATE nocase,"
518 " uuid TEXT"
519 ") WITHOUT ROWID;"
520 );
521 db_prepare(&ins, "INSERT OR IGNORE INTO filelist VALUES(:f,:u)");
522 manifest_file_rewind(pM);
523 while( (pFile = manifest_file_next(pM,0))!=0 ){
524 if( nD>0
525 && (fossil_strncmp(pFile->zName, zD, nD-1)!=0
526 || pFile->zName[nD-1]!='/')
527 ){
528 continue;
529 }
530 if( pRE && re_match(pRE, (const u8*)pFile->zName, -1)==0 ) continue;
531 db_bind_text(&ins, ":f", pFile->zName);
532 db_bind_text(&ins, ":u", pFile->zUuid);
533 db_step(&ins);
534 db_reset(&ins);
535 }
536 db_finalize(&ins);
537 db_prepare(&q, "SELECT x, uuid FROM filelist ORDER BY x");
538 while( db_step(&q)==SQLITE_ROW ){
539 tree_add_node(&sTree, db_column_text(&q,0), db_column_text(&q,1));
 
 
 
 
540 nFile++;
541 }
542 db_finalize(&q);
543 }else{
544 Stmt q;
@@ -547,11 +544,11 @@
547 const char *z = db_column_text(&q, 0);
548 if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
549 continue;
550 }
551 if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
552 tree_add_node(&sTree, z, 0);
553 nFile++;
554 }
555 db_finalize(&q);
556 }
557
@@ -604,10 +601,14 @@
604 const char *zLastClass = p->isLast ? " last" : "";
605 if( p->isDir ){
606 const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : "";
607 @ <li class="dir%s(zSubdirClass)%s(zLastClass)">
608 @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a>
 
 
 
 
609 if( startExpanded || p->nFullName<=nD ){
610 @ <ul id="dir%d(nDir)">
611 }else{
612 @ <ul id="dir%d(nDir)" class="collapsed">
613 }
@@ -619,10 +620,14 @@
619 zLink = href("%R/artifact/%s",p->zUuid);
620 }else{
621 zLink = href("%R/finfo?name=%T",p->zFullName);
622 }
623 @ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
 
 
 
 
624 }
625 if( p->isLast ){
626 int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0);
627 while( nClose-- > 0 ){
628 @ </ul>
629
--- src/browse.c
+++ src/browse.c
@@ -310,10 +310,11 @@
310 FileTreeNode *pPrev; /* Previous line */
311 FileTreeNode *pParent; /* Directory containing this line */
312 char *zName; /* Name of this entry. The "tail" */
313 char *zFullName; /* Full pathname of this entry */
314 char *zUuid; /* SHA1 hash of this file. May be NULL. */
315 double mtime; /* Modification time for this entry */
316 unsigned nFullName; /* Length of zFullName */
317 unsigned iLevel; /* Levels of parent directories */
318 u8 isDir; /* True if there are children */
319 u8 isLast; /* True if this is the last child of its parent */
320 };
@@ -331,11 +332,12 @@
332 ** leaf object zPathname is at the end of the node list
333 */
334 static void tree_add_node(
335 FileTree *pTree, /* Tree into which nodes are added */
336 const char *zPath, /* The full pathname of file to add */
337 const char *zUuid, /* UUID of the file. Might be NULL. */
338 double mtime /* Modification time for this entry */
339 ){
340 int i;
341 FileTreeNode *pParent;
342 FileTreeNode *pChild;
343
@@ -379,12 +381,19 @@
381 pNew->pParent = pParent;
382 pTree->pLast = pNew;
383 pNew->iLevel = pParent ? pParent->iLevel+1 : 0;
384 pNew->isDir = zPath[i]=='/';
385 pNew->isLast = 1;
386 pNew->mtime = mtime;
387 while( zPath[i]=='/' ){ i++; }
388 pParent = pNew;
389 }
390 while( pParent && pParent->pParent ){
391 if( pParent->pParent->mtime < pParent->mtime ){
392 pParent->pParent->mtime = pParent->mtime;
393 }
394 pParent = pParent->pParent;
395 }
396 }
397
398 /*
399 ** WEBPAGE: tree
@@ -403,10 +412,11 @@
412 const char *zCI = P("ci");
413 int rid = 0;
414 char *zUuid = 0;
415 Blob dirname;
416 Manifest *pM = 0;
417 double rNow = db_double(0.0,"SELECT julianday('now')");
418 int nFile = 0; /* Number of files (or folders with "nofiles") */
419 int linkTrunk = 1; /* include link to "trunk" */
420 int linkTip = 1; /* include link to "tip" */
421 const char *zRE; /* the value for the re=REGEXP query parameter */
422 const char *zObjType; /* "files" by default or "folders" for "nofiles" */
@@ -507,38 +517,25 @@
517 }
518
519 /* Compute the file hierarchy.
520 */
521 if( zCI ){
522 Stmt q;
523 compute_fileage(rid, 0);
524 db_prepare(&q,
525 "SELECT filename.name, blob.uuid, fileage.mtime\n"
526 " FROM fileage, filename, blob\n"
527 " WHERE filename.fnid=fileage.fnid\n"
528 " AND blob.rid=fileage.fid\n"
529 " ORDER BY filename.name COLLATE nocase;"
530 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
531 while( db_step(&q)==SQLITE_ROW ){
532 const char *zFile = db_column_text(&q,0);
533 const char *zUuid = db_column_text(&q,1);
534 double mtime = db_column_double(&q,2);
535 if( pRE && re_match(pRE, (const unsigned char*)zFile, -1)==0 ) continue;
536 tree_add_node(&sTree, zFile, zUuid, mtime);
537 nFile++;
538 }
539 db_finalize(&q);
540 }else{
541 Stmt q;
@@ -547,11 +544,11 @@
544 const char *z = db_column_text(&q, 0);
545 if( nD>0 && (fossil_strncmp(z, zD, nD-1)!=0 || z[nD-1]!='/') ){
546 continue;
547 }
548 if( pRE && re_match(pRE, (const u8*)z, -1)==0 ) continue;
549 tree_add_node(&sTree, z, 0, 0.0);
550 nFile++;
551 }
552 db_finalize(&q);
553 }
554
@@ -604,10 +601,14 @@
601 const char *zLastClass = p->isLast ? " last" : "";
602 if( p->isDir ){
603 const char *zSubdirClass = p->nFullName==nD-1 ? " subdir" : "";
604 @ <li class="dir%s(zSubdirClass)%s(zLastClass)">
605 @ %z(href("%s",url_render(&sURI,"name",p->zFullName,0,0)))%h(p->zName)</a>
606 if( p->mtime>0 ){
607 char *zAge = human_readable_age(rNow - p->mtime);
608 @ <div class="filetreeage">%s(zAge) ago</div>
609 }
610 if( startExpanded || p->nFullName<=nD ){
611 @ <ul id="dir%d(nDir)">
612 }else{
613 @ <ul id="dir%d(nDir)" class="collapsed">
614 }
@@ -619,10 +620,14 @@
620 zLink = href("%R/artifact/%s",p->zUuid);
621 }else{
622 zLink = href("%R/finfo?name=%T",p->zFullName);
623 }
624 @ <li class="%z(zFileClass)%s(zLastClass)">%z(zLink)%h(p->zName)</a>
625 if( p->mtime>0 ){
626 char *zAge = human_readable_age(rNow - p->mtime);
627 @ <div class="filetreeage">%s(zAge) ago</div>
628 }
629 }
630 if( p->isLast ){
631 int nClose = p->iLevel - (p->pNext ? p->pNext->iLevel : 0);
632 while( nClose-- > 0 ){
633 @ </ul>
634
--- src/style.c
+++ src/style.c
@@ -842,10 +842,15 @@
842842
@ background-repeat: no-repeat;
843843
},
844844
{ ".filetree .dir > a",
845845
"tree-view directory links",
846846
@ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
847
+ },
848
+ { "div.filetreeage",
849
+ "Last change floating display on the right",
850
+ @ clear: right;
851
+ @ float: right;
847852
},
848853
{ "table.login_out",
849854
"table format for login/out label/input table",
850855
@ text-align: left;
851856
@ margin-right: 10px;
852857
--- src/style.c
+++ src/style.c
@@ -842,10 +842,15 @@
842 @ background-repeat: no-repeat;
843 },
844 { ".filetree .dir > a",
845 "tree-view directory links",
846 @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
 
 
 
 
 
847 },
848 { "table.login_out",
849 "table format for login/out label/input table",
850 @ text-align: left;
851 @ margin-right: 10px;
852
--- src/style.c
+++ src/style.c
@@ -842,10 +842,15 @@
842 @ background-repeat: no-repeat;
843 },
844 { ".filetree .dir > a",
845 "tree-view directory links",
846 @ background-image: url(data:image/gif;base64,R0lGODlhEAAQAJEAAP/WVCIiIv\/\/\/wAAACH5BAEHAAIALAAAAAAQABAAAAInlI9pwa3XYniCgQtkrAFfLXkiFo1jaXpo+jUs6b5Z/K4siDu5RPUFADs=);
847 },
848 { "div.filetreeage",
849 "Last change floating display on the right",
850 @ clear: right;
851 @ float: right;
852 },
853 { "table.login_out",
854 "table format for login/out label/input table",
855 @ text-align: left;
856 @ margin-right: 10px;
857

Keyboard Shortcuts

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