github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/util/configv3/write_config.go (about) 1 package configv3 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 "os" 7 "os/signal" 8 "syscall" 9 "time" 10 ) 11 12 // WriteConfig creates the .cf directory and then writes the config.json. The 13 // location of .cf directory is written in the same way LoadConfig reads .cf 14 // directory. 15 func (c *Config) WriteConfig() error { 16 rawConfig, err := json.MarshalIndent(c.ConfigFile, "", " ") 17 if err != nil { 18 return err 19 } 20 21 dir := configDirectory() 22 err = os.MkdirAll(dir, 0700) 23 if err != nil { 24 return err 25 } 26 27 // Developer Note: The following is untested! Change at your own risk. 28 // Setup notifications of termination signals to channel sig, create a process to 29 // watch for these signals so we can remove transient config temp files. 30 sig := make(chan os.Signal, 10) 31 signal.Notify(sig, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM, os.Interrupt) 32 defer signal.Stop(sig) 33 34 tempConfigFile, err := ioutil.TempFile(dir, "temp-config") 35 if err != nil { 36 return err 37 } 38 tempConfigFile.Close() 39 tempConfigFileName := tempConfigFile.Name() 40 41 go catchSignal(sig, tempConfigFileName) 42 43 err = ioutil.WriteFile(tempConfigFileName, rawConfig, 0600) 44 if err != nil { 45 return err 46 } 47 48 for i := 0; i < 5; i++ { 49 if err := os.Rename(tempConfigFileName, ConfigFilePath()); err == nil { 50 return nil 51 } 52 53 time.Sleep(50 * time.Millisecond) 54 } 55 56 return os.Rename(tempConfigFileName, ConfigFilePath()) 57 } 58 59 // catchSignal tries to catch SIGHUP, SIGINT, SIGKILL, SIGQUIT and SIGTERM, and 60 // Interrupt for removing temporarily created config files before the program 61 // ends. Note: we cannot intercept a `kill -9`, so a well-timed `kill -9` 62 // will allow a temp config file to linger. 63 func catchSignal(sig chan os.Signal, tempConfigFileName string) { 64 <-sig 65 _ = os.Remove(tempConfigFileName) 66 os.Exit(2) 67 }