github.com/tilt-dev/wat@v0.0.2-0.20180626175338-9349b638e250/cli/wat/cleanup.go (about)

     1  package wat
     2  
     3  import (
     4  	"os"
     5  	"os/signal"
     6  	"sync"
     7  	"syscall"
     8  )
     9  
    10  var cleanupMu = &sync.Mutex{}
    11  var cleanupFuncs []*func()
    12  var cleanupCh chan os.Signal
    13  
    14  // Create a cleanup script that runs even if the process gets a SIGINT/SIGTERM
    15  //
    16  // Intended to be used like:
    17  // tearDown := createCleanup(func() { ...critical cleanup... })
    18  // defer tearDown()
    19  //
    20  // The critical cleanup will get executed in tearDown()
    21  func createCleanup(f func()) (tearDown func()) {
    22  	cleanupMu.Lock()
    23  	defer cleanupMu.Unlock()
    24  
    25  	fptr := &f
    26  
    27  	cleanupFuncs = append(cleanupFuncs, fptr)
    28  	if cleanupCh == nil {
    29  		cleanupCh = make(chan os.Signal, 1)
    30  		signal.Notify(cleanupCh, os.Interrupt, syscall.SIGTERM)
    31  		go func() {
    32  			_, ok := <-cleanupCh
    33  			if !ok {
    34  				// The channel closed normally
    35  				return
    36  			}
    37  
    38  			cleanupMu.Lock()
    39  			defer cleanupMu.Unlock()
    40  
    41  			for _, fp := range cleanupFuncs {
    42  				f := *fp
    43  				f()
    44  			}
    45  			os.Exit(1)
    46  		}()
    47  	}
    48  
    49  	return func() {
    50  		f()
    51  
    52  		cleanupMu.Lock()
    53  		defer cleanupMu.Unlock()
    54  
    55  		for i, fp := range cleanupFuncs {
    56  			if fp == fptr {
    57  				cleanupFuncs = append(cleanupFuncs[:i], cleanupFuncs[i+1:]...)
    58  				break
    59  			}
    60  		}
    61  
    62  		if len(cleanupFuncs) == 0 {
    63  			signal.Stop(cleanupCh)
    64  			close(cleanupCh)
    65  			cleanupCh = nil
    66  		}
    67  	}
    68  }