@@ -13,6 +13,7 @@ import (
1313 "io/ioutil"
1414 "os"
1515 "os/exec"
16+ "os/signal"
1617 "path/filepath"
1718 "regexp"
1819 "strings"
@@ -158,6 +159,10 @@ func (ms *mutationStats) Total() int {
158159 return ms .passed + ms .failed + ms .skipped
159160}
160161
162+ // Used by OS signal handler.
163+ var tmpFiles = make (map [string ]struct {})
164+ var tmpDir string
165+
161166func mainCmd (args []string ) int {
162167 var opts = & options {}
163168 var mutationBlackList = map [string ]struct {}{}
@@ -166,6 +171,28 @@ func mainCmd(args []string) int {
166171 return exitCode
167172 }
168173
174+ sigCh := make (chan os.Signal , 1 )
175+ signal .Notify (sigCh , os .Interrupt , syscall .SIGINT , syscall .SIGTERM , syscall .SIGHUP , syscall .SIGQUIT )
176+ go func () {
177+ for {
178+ sig := <- sigCh
179+ verbose (opts , "Signal (%s) received, exiting..." , sig )
180+
181+ for file := range tmpFiles {
182+ // "smth.tmp" -> "smth"
183+ if err := os .Rename (file , file [:len (file )- 4 ]); err != nil {
184+ fmt .Printf ("Failed to restore original version of file %s, it is stored in %s.\n " , file [:len (file )- 4 ], file )
185+ fmt .Println (err )
186+ }
187+ }
188+ if err := os .RemoveAll (tmpDir ); err != nil {
189+ fmt .Printf ("Failed to remove temporary directory (%s): %v.\n " , tmpDir , err )
190+ }
191+
192+ os .Exit (1 )
193+ }
194+ }()
195+
169196 files := importing .FilesOfArgs (opts .Remaining .Targets )
170197 if len (files ) == 0 {
171198 return exitError ("Could not find any suitable Go source files" )
@@ -238,7 +265,8 @@ MUTATOR:
238265 })
239266 }
240267
241- tmpDir , err := ioutil .TempDir ("" , "go-mutesting-" )
268+ var err error
269+ tmpDir , err = ioutil .TempDir ("" , "go-mutesting-" )
242270 if err != nil {
243271 panic (err )
244272 }
@@ -390,6 +418,9 @@ func mutateExec(opts *options, pkg *types.Package, file string, src ast.Node, mu
390418 }
391419
392420 defer func () {
421+ // Remove tmp file from clean list for signal handler.
422+ delete (tmpFiles , file + ".tmp" )
423+
393424 _ = os .Rename (file + ".tmp" , file )
394425 }()
395426
@@ -402,6 +433,9 @@ func mutateExec(opts *options, pkg *types.Package, file string, src ast.Node, mu
402433 panic (err )
403434 }
404435
436+ // Add tmp file to clean list for signal handler.
437+ tmpFiles [file + ".tmp" ] = struct {}{}
438+
405439 pkgName := pkg .Path ()
406440 if opts .Test .Recursive {
407441 pkgName += "/..."
0 commit comments