You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
3.9 KiB

10 years ago
  1. package common
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "os"
  6. "os/signal"
  7. "sync"
  8. "time"
  9. )
  10. func TrapSignal(cb func()) {
  11. c := make(chan os.Signal, 1)
  12. signal.Notify(c, os.Interrupt)
  13. signal.Notify(c, os.Kill)
  14. go func() {
  15. for sig := range c {
  16. fmt.Printf("captured %v, exiting...\n", sig)
  17. if cb != nil {
  18. cb()
  19. }
  20. os.Exit(1)
  21. }
  22. }()
  23. select {}
  24. }
  25. func Exit(s string) {
  26. fmt.Printf(s + "\n")
  27. os.Exit(1)
  28. }
  29. func EnsureDir(dir string) error {
  30. if _, err := os.Stat(dir); os.IsNotExist(err) {
  31. err := os.MkdirAll(dir, 0700)
  32. if err != nil {
  33. return fmt.Errorf("Could not create directory %v. %v", dir, err)
  34. }
  35. }
  36. return nil
  37. }
  38. func FileExists(filePath string) bool {
  39. _, err := os.Stat(filePath)
  40. return !os.IsNotExist(err)
  41. }
  42. func ReadFile(filePath string) ([]byte, error) {
  43. return ioutil.ReadFile(filePath)
  44. }
  45. func MustReadFile(filePath string) []byte {
  46. fileBytes, err := ioutil.ReadFile(filePath)
  47. if err != nil {
  48. Exit(Fmt("MustReadFile failed: %v", err))
  49. return nil
  50. }
  51. return fileBytes
  52. }
  53. func WriteFile(filePath string, contents []byte) error {
  54. err := ioutil.WriteFile(filePath, contents, 0600)
  55. if err != nil {
  56. return err
  57. }
  58. fmt.Printf("File written to %v.\n", filePath)
  59. return nil
  60. }
  61. func MustWriteFile(filePath string, contents []byte) {
  62. err := WriteFile(filePath, contents)
  63. if err != nil {
  64. Exit(Fmt("MustWriteFile failed: %v", err))
  65. }
  66. }
  67. // Writes to newBytes to filePath.
  68. // Guaranteed not to lose *both* oldBytes and newBytes,
  69. // (assuming that the OS is perfect)
  70. func WriteFileAtomic(filePath string, newBytes []byte) error {
  71. // If a file already exists there, copy to filePath+".bak" (overwrite anything)
  72. if _, err := os.Stat(filePath); !os.IsNotExist(err) {
  73. fileBytes, err := ioutil.ReadFile(filePath)
  74. if err != nil {
  75. return fmt.Errorf("Could not read file %v. %v", filePath, err)
  76. }
  77. err = ioutil.WriteFile(filePath+".bak", fileBytes, 0600)
  78. if err != nil {
  79. return fmt.Errorf("Could not write file %v. %v", filePath+".bak", err)
  80. }
  81. }
  82. // Write newBytes to filePath.new
  83. err := ioutil.WriteFile(filePath+".new", newBytes, 0600)
  84. if err != nil {
  85. return fmt.Errorf("Could not write file %v. %v", filePath+".new", err)
  86. }
  87. // Move filePath.new to filePath
  88. err = os.Rename(filePath+".new", filePath)
  89. return err
  90. }
  91. //--------------------------------------------------------------------------------
  92. /* AutoFile usage
  93. // Create/Append to ./autofile_test
  94. af, err := OpenAutoFile("autofile_test")
  95. if err != nil {
  96. panic(err)
  97. }
  98. // Stream of writes.
  99. // During this time, the file may be moved e.g. by logRotate.
  100. for i := 0; i < 60; i++ {
  101. af.Write([]byte(Fmt("LOOP(%v)", i)))
  102. time.Sleep(time.Second)
  103. }
  104. // Close the AutoFile
  105. err = af.Close()
  106. if err != nil {
  107. panic(err)
  108. }
  109. */
  110. const autoFileOpenDuration = 1000 * time.Millisecond
  111. // Automatically closes and re-opens file for writing.
  112. // This is useful for using a log file with the logrotate tool.
  113. type AutoFile struct {
  114. Path string
  115. ticker *time.Ticker
  116. mtx sync.Mutex
  117. file *os.File
  118. }
  119. func OpenAutoFile(path string) (af *AutoFile, err error) {
  120. af = &AutoFile{
  121. Path: path,
  122. ticker: time.NewTicker(autoFileOpenDuration),
  123. }
  124. if err = af.openFile(); err != nil {
  125. return
  126. }
  127. go af.processTicks()
  128. return
  129. }
  130. func (af *AutoFile) Close() error {
  131. af.ticker.Stop()
  132. af.mtx.Lock()
  133. err := af.closeFile()
  134. af.mtx.Unlock()
  135. return err
  136. }
  137. func (af *AutoFile) processTicks() {
  138. for {
  139. _, ok := <-af.ticker.C
  140. if !ok {
  141. return // Done.
  142. }
  143. af.mtx.Lock()
  144. af.closeFile()
  145. af.mtx.Unlock()
  146. }
  147. }
  148. func (af *AutoFile) closeFile() (err error) {
  149. file := af.file
  150. if file == nil {
  151. return nil
  152. }
  153. af.file = nil
  154. return file.Close()
  155. }
  156. func (af *AutoFile) Write(b []byte) (n int, err error) {
  157. af.mtx.Lock()
  158. defer af.mtx.Unlock()
  159. if af.file == nil {
  160. if err = af.openFile(); err != nil {
  161. return
  162. }
  163. }
  164. return af.file.Write(b)
  165. }
  166. func (af *AutoFile) openFile() error {
  167. file, err := os.OpenFile(af.Path, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
  168. if err != nil {
  169. return err
  170. }
  171. af.file = file
  172. return nil
  173. }