@@ -6,7 +6,6 @@ package script
6
6
7
7
import (
8
8
"cmd/go/internal/robustio"
9
- "context"
10
9
"errors"
11
10
"fmt"
12
11
"internal/diff"
@@ -36,7 +35,7 @@ func DefaultCmds() map[string]Cmd {
36
35
"cp" : Cp (),
37
36
"echo" : Echo (),
38
37
"env" : Env (),
39
- "exec" : Exec (os .Interrupt , 100 * time .Millisecond ), // arbitrary grace period
38
+ "exec" : Exec (func ( cmd * exec. Cmd ) error { return cmd . Process . Signal ( os .Interrupt ) } , 100 * time .Millisecond ), // arbitrary grace period
40
39
"exists" : Exists (),
41
40
"grep" : Grep (),
42
41
"help" : Help (),
@@ -400,7 +399,7 @@ func Env() Cmd {
400
399
// When the Script's context is canceled, Exec sends the interrupt signal, then
401
400
// waits for up to the given delay for the subprocess to flush output before
402
401
// terminating it with os.Kill.
403
- func Exec (interrupt os. Signal , delay time.Duration ) Cmd {
402
+ func Exec (cancel func ( * exec. Cmd ) error , waitDelay time.Duration ) Cmd {
404
403
return Command (
405
404
CmdUsage {
406
405
Summary : "run an executable program with arguments" ,
@@ -428,13 +427,19 @@ func Exec(interrupt os.Signal, delay time.Duration) Cmd {
428
427
}
429
428
}
430
429
431
- return startCommand (s , name , path , args [1 :], interrupt , delay )
430
+ return startCommand (s , name , path , args [1 :], cancel , waitDelay )
432
431
})
433
432
}
434
433
435
- func startCommand (s * State , name , path string , args []string , interrupt os. Signal , gracePeriod time.Duration ) (WaitFunc , error ) {
434
+ func startCommand (s * State , name , path string , args []string , cancel func ( * exec. Cmd ) error , waitDelay time.Duration ) (WaitFunc , error ) {
436
435
var stdoutBuf , stderrBuf strings.Builder
437
- cmd := exec .Command (path , args ... )
436
+ cmd := exec .CommandContext (s .Context (), path , args ... )
437
+ if cancel == nil {
438
+ cmd .Cancel = nil
439
+ } else {
440
+ cmd .Cancel = func () error { return cancel (cmd ) }
441
+ }
442
+ cmd .WaitDelay = waitDelay
438
443
cmd .Args [0 ] = name
439
444
cmd .Dir = s .Getwd ()
440
445
cmd .Env = s .env
@@ -444,16 +449,9 @@ func startCommand(s *State, name, path string, args []string, interrupt os.Signa
444
449
return nil , err
445
450
}
446
451
447
- var waitErr error
448
- done := make (chan struct {})
449
- go func () {
450
- waitErr = waitOrStop (s .Context (), cmd , interrupt , gracePeriod )
451
- close (done )
452
- }()
453
-
454
452
wait := func (s * State ) (stdout , stderr string , err error ) {
455
- <- done
456
- return stdoutBuf .String (), stderrBuf .String (), waitErr
453
+ err = cmd . Wait ()
454
+ return stdoutBuf .String (), stderrBuf .String (), err
457
455
}
458
456
return wait , nil
459
457
}
@@ -535,67 +533,6 @@ func pathEnvName() string {
535
533
}
536
534
}
537
535
538
- // waitOrStop waits for the already-started command cmd by calling its Wait method.
539
- //
540
- // If cmd does not return before ctx is done, waitOrStop sends it the given interrupt signal.
541
- // If killDelay is positive, waitOrStop waits that additional period for Wait to return before sending os.Kill.
542
- //
543
- // This function is copied from the one added to x/playground/internal in
544
- // http://golang.org/cl/228438.
545
- func waitOrStop (ctx context.Context , cmd * exec.Cmd , interrupt os.Signal , killDelay time.Duration ) error {
546
- if cmd .Process == nil {
547
- panic ("waitOrStop called with a nil cmd.Process — missing Start call?" )
548
- }
549
- if interrupt == nil {
550
- panic ("waitOrStop requires a non-nil interrupt signal" )
551
- }
552
-
553
- errc := make (chan error )
554
- go func () {
555
- select {
556
- case errc <- nil :
557
- return
558
- case <- ctx .Done ():
559
- }
560
-
561
- err := cmd .Process .Signal (interrupt )
562
- if err == nil {
563
- err = ctx .Err () // Report ctx.Err() as the reason we interrupted.
564
- } else if err == os .ErrProcessDone {
565
- errc <- nil
566
- return
567
- }
568
-
569
- if killDelay > 0 {
570
- timer := time .NewTimer (killDelay )
571
- select {
572
- // Report ctx.Err() as the reason we interrupted the process...
573
- case errc <- ctx .Err ():
574
- timer .Stop ()
575
- return
576
- // ...but after killDelay has elapsed, fall back to a stronger signal.
577
- case <- timer .C :
578
- }
579
-
580
- // Wait still hasn't returned.
581
- // Kill the process harder to make sure that it exits.
582
- //
583
- // Ignore any error: if cmd.Process has already terminated, we still
584
- // want to send ctx.Err() (or the error from the Interrupt call)
585
- // to properly attribute the signal that may have terminated it.
586
- _ = cmd .Process .Kill ()
587
- }
588
-
589
- errc <- err
590
- }()
591
-
592
- waitErr := cmd .Wait ()
593
- if interruptErr := <- errc ; interruptErr != nil {
594
- return interruptErr
595
- }
596
- return waitErr
597
- }
598
-
599
536
// Exists checks that the named file(s) exist.
600
537
func Exists () Cmd {
601
538
return Command (
@@ -834,7 +771,7 @@ func Mv() Cmd {
834
771
835
772
// Program returns a new command that runs the named program, found from the
836
773
// host process's PATH (not looked up in the script's PATH).
837
- func Program (name string , interrupt os. Signal , gracePeriod time.Duration ) Cmd {
774
+ func Program (name string , cancel func ( * exec. Cmd ) error , waitDelay time.Duration ) Cmd {
838
775
var (
839
776
shortName string
840
777
summary string
@@ -864,7 +801,7 @@ func Program(name string, interrupt os.Signal, gracePeriod time.Duration) Cmd {
864
801
if pathErr != nil {
865
802
return nil , pathErr
866
803
}
867
- return startCommand (s , shortName , path , args , interrupt , gracePeriod )
804
+ return startCommand (s , shortName , path , args , cancel , waitDelay )
868
805
})
869
806
}
870
807
0 commit comments