@@ -10,6 +10,7 @@ import (
10
10
"fmt"
11
11
"io"
12
12
"os"
13
+ "regexp"
13
14
"strconv"
14
15
"strings"
15
16
"sync"
@@ -377,9 +378,16 @@ func (tm *tasksManager) watch(task *task, terminal *terminal.Term) {
377
378
go func () {
378
379
defer stdout .Close ()
379
380
380
- fileName := tm .prebuildLogFileName (task )
381
- // TODO(janx): If the file already exists (from a parent prebuild), extract its "time saved", and log that below
382
- // (instead, or in addition to, the incremental prebuild time).
381
+ var (
382
+ fileName = tm .prebuildLogFileName (task )
383
+ oldFileName = fileName + "-old"
384
+ )
385
+ if _ , err := os .Stat (fileName ); err == nil {
386
+ // If the file already exists (from a parent prebuild), temporarily move it so that it doesn't get truncated.
387
+ // On the off chance that renaming fails here, we silently ignore that -- the new prebuild logs simply won't reflect
388
+ // the older logs and elapsed time (`importParentLogAndGetDuration` is always safe thanks to its initial `os.Stat`).
389
+ _ = os .Rename (fileName , oldFileName )
390
+ }
383
391
file , err := os .Create (fileName )
384
392
var fileWriter * bufio.Writer
385
393
if err != nil {
@@ -391,12 +399,17 @@ func (tm *tasksManager) watch(task *task, terminal *terminal.Term) {
391
399
fileWriter = bufio .NewWriter (file )
392
400
defer fileWriter .Flush ()
393
401
}
402
+ // Import any parent prebuild logs and parse their total duration if available
403
+ parentElapsed := importParentLogAndGetDuration (oldFileName , fileWriter )
394
404
395
405
buf := make ([]byte , 4096 )
396
406
for {
397
407
n , err := stdout .Read (buf )
398
408
if err == io .EOF {
399
409
elapsed := time .Since (start )
410
+ if parentElapsed > elapsed {
411
+ elapsed = parentElapsed
412
+ }
400
413
duration := ""
401
414
if elapsed >= 1 * time .Minute {
402
415
elapsedInMinutes := strconv .Itoa (int (elapsed .Minutes ()))
@@ -425,6 +438,46 @@ func (tm *tasksManager) watch(task *task, terminal *terminal.Term) {
425
438
}()
426
439
}
427
440
441
+ func importParentLogAndGetDuration (fn string , out io.Writer ) time.Duration {
442
+ if _ , err := os .Stat (fn ); err != nil {
443
+ return 0
444
+ }
445
+ defer os .Remove (fn )
446
+
447
+ file , err := os .Open (fn )
448
+ if err != nil {
449
+ return 0
450
+ }
451
+ defer file .Close ()
452
+
453
+ defer out .Write ([]byte ("♻️ Re-running task as an incremental workspace prebuild\n \n " ))
454
+
455
+ scanner := bufio .NewScanner (file )
456
+ for scanner .Scan () {
457
+ l := scanner .Text ()
458
+ if strings .Contains (l , "🤙 This task ran as a workspace prebuild" ) {
459
+ break
460
+ }
461
+ out .Write ([]byte (l + "\n " ))
462
+ }
463
+ if ! scanner .Scan () {
464
+ return 0
465
+ }
466
+ reg , err := regexp .Compile (`🎉 Well done on saving (\d+) minute` )
467
+ if err != nil {
468
+ return 0
469
+ }
470
+ res := reg .FindStringSubmatch (scanner .Text ())
471
+ if res == nil {
472
+ return 0
473
+ }
474
+ elapsedInMinutes , err := strconv .Atoi (res [1 ])
475
+ if err != nil {
476
+ return 0
477
+ }
478
+ return time .Duration (elapsedInMinutes ) * time .Minute
479
+ }
480
+
428
481
type composeCommandOptions struct {
429
482
commands []* string
430
483
format string
0 commit comments