Fossil SCM
Add the "fileage" webpage.
Commit
368347d660ffb3f67b6543cfe8c9aa943853a204
Parent
9ba8a393fcc569b…
2 files changed
+141
+1
+141
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -293,5 +293,146 @@ | ||
| 293 | 293 | db_finalize(&q); |
| 294 | 294 | manifest_destroy(pM); |
| 295 | 295 | @ </ul></td></tr></table> |
| 296 | 296 | style_footer(); |
| 297 | 297 | } |
| 298 | + | |
| 299 | +/* | |
| 300 | +** Look at all file containing in the version "vid". Construct a | |
| 301 | +** temporary table named "fileage" that contains the file-id for each | |
| 302 | +** files, the pathname, the check-in where the file was added, and the | |
| 303 | +** mtime on that checkin. | |
| 304 | +*/ | |
| 305 | +int compute_fileage(int vid){ | |
| 306 | + Manifest *pManifest; | |
| 307 | + ManifestFile *pFile; | |
| 308 | + int nFile = 0; | |
| 309 | + double vmtime; | |
| 310 | + Stmt ins; | |
| 311 | + Stmt q1, q2, q3; | |
| 312 | + Stmt upd; | |
| 313 | + db_multi_exec( | |
| 314 | + /*"DROP TABLE IF EXISTS temp.fileage;"*/ | |
| 315 | + "CREATE TEMP TABLE fileage(" | |
| 316 | + " fid INTEGER," | |
| 317 | + " mid INTEGER," | |
| 318 | + " mtime DATETIME," | |
| 319 | + " pathname TEXT" | |
| 320 | + ");" | |
| 321 | + "CREATE INDEX fileage_fid ON fileage(fid);" | |
| 322 | + ); | |
| 323 | + pManifest = manifest_get(vid, CFTYPE_MANIFEST); | |
| 324 | + if( pManifest==0 ) return 1; | |
| 325 | + manifest_file_rewind(pManifest); | |
| 326 | + db_prepare(&ins, | |
| 327 | + "INSERT INTO temp.fileage(fid, pathname)" | |
| 328 | + " SELECT rid, :path FROM blob WHERE uuid=:uuid" | |
| 329 | + ); | |
| 330 | + while( (pFile = manifest_file_next(pManifest, 0))!=0 ){ | |
| 331 | + db_bind_text(&ins, ":uuid", pFile->zUuid); | |
| 332 | + db_bind_text(&ins, ":path", pFile->zName); | |
| 333 | + db_step(&ins); | |
| 334 | + db_reset(&ins); | |
| 335 | + nFile++; | |
| 336 | + } | |
| 337 | + db_finalize(&ins); | |
| 338 | + manifest_destroy(pManifest); | |
| 339 | + db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid"); | |
| 340 | + db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime" | |
| 341 | + " WHERE fid=:fid AND mid IS NULL"); | |
| 342 | + db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim"); | |
| 343 | + db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid"); | |
| 344 | + while( nFile>0 && vid>0 ){ | |
| 345 | + db_bind_int(&q3, ":vid", vid); | |
| 346 | + if( db_step(&q3)==SQLITE_ROW ){ | |
| 347 | + vmtime = db_column_double(&q3, 0); | |
| 348 | + }else{ | |
| 349 | + break; | |
| 350 | + } | |
| 351 | + db_reset(&q3); | |
| 352 | + db_bind_int(&q1, ":mid", vid); | |
| 353 | + db_bind_int(&upd, ":mid", vid); | |
| 354 | + db_bind_double(&upd, ":vmtime", vmtime); | |
| 355 | + while( db_step(&q1)==SQLITE_ROW ){ | |
| 356 | + db_bind_int(&upd, ":fid", db_column_int(&q1, 0)); | |
| 357 | + db_step(&upd); | |
| 358 | + nFile -= db_changes(); | |
| 359 | + db_reset(&upd); | |
| 360 | + } | |
| 361 | + db_reset(&q1); | |
| 362 | + db_bind_int(&q2, ":vid", vid); | |
| 363 | + if( db_step(&q2)!=SQLITE_ROW ) break; | |
| 364 | + vid = db_column_int(&q2, 0); | |
| 365 | + db_reset(&q2); | |
| 366 | + } | |
| 367 | + db_finalize(&q1); | |
| 368 | + db_finalize(&upd); | |
| 369 | + db_finalize(&q2); | |
| 370 | + db_finalize(&q3); | |
| 371 | + return 0; | |
| 372 | +} | |
| 373 | + | |
| 374 | +/* | |
| 375 | +** WEBPAGE: fileage | |
| 376 | +** | |
| 377 | +** Parameters: | |
| 378 | +** name=VERSION | |
| 379 | +*/ | |
| 380 | +void fileage_page(void){ | |
| 381 | + int rid; | |
| 382 | + const char *zName; | |
| 383 | + Stmt q; | |
| 384 | + double baseTime; | |
| 385 | + int lastMid = -1; | |
| 386 | + | |
| 387 | + login_check_credentials(); | |
| 388 | + if( !g.perm.Read ){ login_needed(); return; } | |
| 389 | + zName = P("name"); | |
| 390 | + if( zName==0 ) zName = "tip"; | |
| 391 | + rid = symbolic_name_to_rid(zName, "ci"); | |
| 392 | + if( rid==0 ){ | |
| 393 | + fossil_fatal("not a valid check-in: %s", zName); | |
| 394 | + } | |
| 395 | + style_header("File Ages for %h", zName); | |
| 396 | + compute_fileage(rid); | |
| 397 | + @ <h1>Times since each file was changed as of check-in %h(zName)</h1> | |
| 398 | + @ <table border=0 cellspacing=0 cellpadding=0> | |
| 399 | + baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); | |
| 400 | + db_prepare(&q, | |
| 401 | + "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" | |
| 402 | + " FROM fileage" | |
| 403 | + " ORDER BY mtime DESC, mid, pathname" | |
| 404 | + ); | |
| 405 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 406 | + double age = baseTime - db_column_double(&q, 0); | |
| 407 | + int mid = db_column_int(&q, 2); | |
| 408 | + const char *zFUuid = db_column_text(&q, 1); | |
| 409 | + char zAge[200]; | |
| 410 | + if( lastMid!=mid ){ | |
| 411 | + @ <tr><td colspan=3><hr></tr> | |
| 412 | + lastMid = mid; | |
| 413 | + if( age*86400.0<120 ){ | |
| 414 | + sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0)); | |
| 415 | + }else if( age*1440.0<90 ){ | |
| 416 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0); | |
| 417 | + }else if( age*24.0<36 ){ | |
| 418 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0); | |
| 419 | + }else if( age<365.0 ){ | |
| 420 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age); | |
| 421 | + }else{ | |
| 422 | + sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0); | |
| 423 | + } | |
| 424 | + }else{ | |
| 425 | + zAge[0] = 0; | |
| 426 | + } | |
| 427 | + @ <tr> | |
| 428 | + @ <td>%s(zAge) | |
| 429 | + @ <td width="25"> | |
| 430 | + @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a> | |
| 431 | + @ </tr> | |
| 432 | + @ | |
| 433 | + } | |
| 434 | + @ <tr><td colspan=3><hr></tr> | |
| 435 | + @ </table> | |
| 436 | + db_finalize(&q); | |
| 437 | + style_footer(); | |
| 438 | +} | |
| 298 | 439 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -293,5 +293,146 @@ | |
| 293 | db_finalize(&q); |
| 294 | manifest_destroy(pM); |
| 295 | @ </ul></td></tr></table> |
| 296 | style_footer(); |
| 297 | } |
| 298 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -293,5 +293,146 @@ | |
| 293 | db_finalize(&q); |
| 294 | manifest_destroy(pM); |
| 295 | @ </ul></td></tr></table> |
| 296 | style_footer(); |
| 297 | } |
| 298 | |
| 299 | /* |
| 300 | ** Look at all file containing in the version "vid". Construct a |
| 301 | ** temporary table named "fileage" that contains the file-id for each |
| 302 | ** files, the pathname, the check-in where the file was added, and the |
| 303 | ** mtime on that checkin. |
| 304 | */ |
| 305 | int compute_fileage(int vid){ |
| 306 | Manifest *pManifest; |
| 307 | ManifestFile *pFile; |
| 308 | int nFile = 0; |
| 309 | double vmtime; |
| 310 | Stmt ins; |
| 311 | Stmt q1, q2, q3; |
| 312 | Stmt upd; |
| 313 | db_multi_exec( |
| 314 | /*"DROP TABLE IF EXISTS temp.fileage;"*/ |
| 315 | "CREATE TEMP TABLE fileage(" |
| 316 | " fid INTEGER," |
| 317 | " mid INTEGER," |
| 318 | " mtime DATETIME," |
| 319 | " pathname TEXT" |
| 320 | ");" |
| 321 | "CREATE INDEX fileage_fid ON fileage(fid);" |
| 322 | ); |
| 323 | pManifest = manifest_get(vid, CFTYPE_MANIFEST); |
| 324 | if( pManifest==0 ) return 1; |
| 325 | manifest_file_rewind(pManifest); |
| 326 | db_prepare(&ins, |
| 327 | "INSERT INTO temp.fileage(fid, pathname)" |
| 328 | " SELECT rid, :path FROM blob WHERE uuid=:uuid" |
| 329 | ); |
| 330 | while( (pFile = manifest_file_next(pManifest, 0))!=0 ){ |
| 331 | db_bind_text(&ins, ":uuid", pFile->zUuid); |
| 332 | db_bind_text(&ins, ":path", pFile->zName); |
| 333 | db_step(&ins); |
| 334 | db_reset(&ins); |
| 335 | nFile++; |
| 336 | } |
| 337 | db_finalize(&ins); |
| 338 | manifest_destroy(pManifest); |
| 339 | db_prepare(&q1,"SELECT fid FROM mlink WHERE mid=:mid"); |
| 340 | db_prepare(&upd, "UPDATE fileage SET mid=:mid, mtime=:vmtime" |
| 341 | " WHERE fid=:fid AND mid IS NULL"); |
| 342 | db_prepare(&q2,"SELECT pid FROM plink WHERE cid=:vid AND isprim"); |
| 343 | db_prepare(&q3,"SELECT mtime FROM event WHERE objid=:vid"); |
| 344 | while( nFile>0 && vid>0 ){ |
| 345 | db_bind_int(&q3, ":vid", vid); |
| 346 | if( db_step(&q3)==SQLITE_ROW ){ |
| 347 | vmtime = db_column_double(&q3, 0); |
| 348 | }else{ |
| 349 | break; |
| 350 | } |
| 351 | db_reset(&q3); |
| 352 | db_bind_int(&q1, ":mid", vid); |
| 353 | db_bind_int(&upd, ":mid", vid); |
| 354 | db_bind_double(&upd, ":vmtime", vmtime); |
| 355 | while( db_step(&q1)==SQLITE_ROW ){ |
| 356 | db_bind_int(&upd, ":fid", db_column_int(&q1, 0)); |
| 357 | db_step(&upd); |
| 358 | nFile -= db_changes(); |
| 359 | db_reset(&upd); |
| 360 | } |
| 361 | db_reset(&q1); |
| 362 | db_bind_int(&q2, ":vid", vid); |
| 363 | if( db_step(&q2)!=SQLITE_ROW ) break; |
| 364 | vid = db_column_int(&q2, 0); |
| 365 | db_reset(&q2); |
| 366 | } |
| 367 | db_finalize(&q1); |
| 368 | db_finalize(&upd); |
| 369 | db_finalize(&q2); |
| 370 | db_finalize(&q3); |
| 371 | return 0; |
| 372 | } |
| 373 | |
| 374 | /* |
| 375 | ** WEBPAGE: fileage |
| 376 | ** |
| 377 | ** Parameters: |
| 378 | ** name=VERSION |
| 379 | */ |
| 380 | void fileage_page(void){ |
| 381 | int rid; |
| 382 | const char *zName; |
| 383 | Stmt q; |
| 384 | double baseTime; |
| 385 | int lastMid = -1; |
| 386 | |
| 387 | login_check_credentials(); |
| 388 | if( !g.perm.Read ){ login_needed(); return; } |
| 389 | zName = P("name"); |
| 390 | if( zName==0 ) zName = "tip"; |
| 391 | rid = symbolic_name_to_rid(zName, "ci"); |
| 392 | if( rid==0 ){ |
| 393 | fossil_fatal("not a valid check-in: %s", zName); |
| 394 | } |
| 395 | style_header("File Ages for %h", zName); |
| 396 | compute_fileage(rid); |
| 397 | @ <h1>Times since each file was changed as of check-in %h(zName)</h1> |
| 398 | @ <table border=0 cellspacing=0 cellpadding=0> |
| 399 | baseTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d", rid); |
| 400 | db_prepare(&q, |
| 401 | "SELECT mtime, (SELECT uuid FROM blob WHERE rid=fid), mid, pathname" |
| 402 | " FROM fileage" |
| 403 | " ORDER BY mtime DESC, mid, pathname" |
| 404 | ); |
| 405 | while( db_step(&q)==SQLITE_ROW ){ |
| 406 | double age = baseTime - db_column_double(&q, 0); |
| 407 | int mid = db_column_int(&q, 2); |
| 408 | const char *zFUuid = db_column_text(&q, 1); |
| 409 | char zAge[200]; |
| 410 | if( lastMid!=mid ){ |
| 411 | @ <tr><td colspan=3><hr></tr> |
| 412 | lastMid = mid; |
| 413 | if( age*86400.0<120 ){ |
| 414 | sqlite3_snprintf(sizeof(zAge), zAge, "%d seconds", (int)(age*86400.0)); |
| 415 | }else if( age*1440.0<90 ){ |
| 416 | sqlite3_snprintf(sizeof(zAge), zAge, "%.1f minutes", age*1440.0); |
| 417 | }else if( age*24.0<36 ){ |
| 418 | sqlite3_snprintf(sizeof(zAge), zAge, "%.1f hours", age*24.0); |
| 419 | }else if( age<365.0 ){ |
| 420 | sqlite3_snprintf(sizeof(zAge), zAge, "%.1f days", age); |
| 421 | }else{ |
| 422 | sqlite3_snprintf(sizeof(zAge), zAge, "%.2f years", age/365.0); |
| 423 | } |
| 424 | }else{ |
| 425 | zAge[0] = 0; |
| 426 | } |
| 427 | @ <tr> |
| 428 | @ <td>%s(zAge) |
| 429 | @ <td width="25"> |
| 430 | @ <td>%z(href("%R/artifact/%S?ln", zFUuid))%h(db_column_text(&q, 3))</a> |
| 431 | @ </tr> |
| 432 | @ |
| 433 | } |
| 434 | @ <tr><td colspan=3><hr></tr> |
| 435 | @ </table> |
| 436 | db_finalize(&q); |
| 437 | style_footer(); |
| 438 | } |
| 439 |
+1
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -630,10 +630,11 @@ | ||
| 630 | 630 | } |
| 631 | 631 | @ </td></tr> |
| 632 | 632 | @ <tr><th>Other Links:</th> |
| 633 | 633 | @ <td> |
| 634 | 634 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 635 | + @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> | |
| 635 | 636 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 636 | 637 | if( g.perm.Write ){ |
| 637 | 638 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| 638 | 639 | } |
| 639 | 640 | @ </td> |
| 640 | 641 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -630,10 +630,11 @@ | |
| 630 | } |
| 631 | @ </td></tr> |
| 632 | @ <tr><th>Other Links:</th> |
| 633 | @ <td> |
| 634 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 635 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 636 | if( g.perm.Write ){ |
| 637 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| 638 | } |
| 639 | @ </td> |
| 640 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -630,10 +630,11 @@ | |
| 630 | } |
| 631 | @ </td></tr> |
| 632 | @ <tr><th>Other Links:</th> |
| 633 | @ <td> |
| 634 | @ %z(href("%R/dir?ci=%S",zUuid))files</a> |
| 635 | @ | %z(href("%R/fileage?name=%S",zUuid))file ages</a> |
| 636 | @ | %z(href("%R/artifact/%S",zUuid))manifest</a> |
| 637 | if( g.perm.Write ){ |
| 638 | @ | %z(href("%R/ci_edit?r=%S",zUuid))edit</a> |
| 639 | } |
| 640 | @ </td> |
| 641 |