util.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright 2017 Google Inc. All rights reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package build
  15. import (
  16. "compress/gzip"
  17. "fmt"
  18. "io"
  19. "os"
  20. "path/filepath"
  21. "strings"
  22. )
  23. func absPath(ctx Context, p string) string {
  24. ret, err := filepath.Abs(p)
  25. if err != nil {
  26. ctx.Fatalf("Failed to get absolute path: %v", err)
  27. }
  28. return ret
  29. }
  30. // indexList finds the index of a string in a []string
  31. func indexList(s string, list []string) int {
  32. for i, l := range list {
  33. if l == s {
  34. return i
  35. }
  36. }
  37. return -1
  38. }
  39. // inList determines whether a string is in a []string
  40. func inList(s string, list []string) bool {
  41. return indexList(s, list) != -1
  42. }
  43. // removeFromlist removes all occurrences of the string in list.
  44. func removeFromList(s string, list []string) []string {
  45. filteredList := make([]string, 0, len(list))
  46. for _, ls := range list {
  47. if s != ls {
  48. filteredList = append(filteredList, ls)
  49. }
  50. }
  51. return filteredList
  52. }
  53. // ensureDirectoriesExist is a shortcut to os.MkdirAll, sending errors to the ctx logger.
  54. func ensureDirectoriesExist(ctx Context, dirs ...string) {
  55. for _, dir := range dirs {
  56. err := os.MkdirAll(dir, 0777)
  57. if err != nil {
  58. ctx.Fatalf("Error creating %s: %q\n", dir, err)
  59. }
  60. }
  61. }
  62. // ensureEmptyDirectoriesExist ensures that the given directories exist and are empty
  63. func ensureEmptyDirectoriesExist(ctx Context, dirs ...string) {
  64. // remove all the directories
  65. for _, dir := range dirs {
  66. seenErr := map[string]bool{}
  67. for {
  68. err := os.RemoveAll(dir)
  69. if err == nil {
  70. break
  71. }
  72. if pathErr, ok := err.(*os.PathError); !ok ||
  73. dir == pathErr.Path || seenErr[pathErr.Path] {
  74. ctx.Fatalf("Error removing %s: %q\n", dir, err)
  75. } else {
  76. seenErr[pathErr.Path] = true
  77. err = os.Chmod(filepath.Dir(pathErr.Path), 0700)
  78. if err != nil {
  79. ctx.Fatal(err)
  80. }
  81. }
  82. }
  83. }
  84. // recreate all the directories
  85. ensureDirectoriesExist(ctx, dirs...)
  86. }
  87. // ensureEmptyFileExists ensures that the containing directory exists, and the
  88. // specified file exists. If it doesn't exist, it will write an empty file.
  89. func ensureEmptyFileExists(ctx Context, file string) {
  90. ensureDirectoriesExist(ctx, filepath.Dir(file))
  91. if _, err := os.Stat(file); os.IsNotExist(err) {
  92. f, err := os.Create(file)
  93. if err != nil {
  94. ctx.Fatalf("Error creating %s: %q\n", file, err)
  95. }
  96. f.Close()
  97. } else if err != nil {
  98. ctx.Fatalf("Error checking %s: %q\n", file, err)
  99. }
  100. }
  101. // singleUnquote is similar to strconv.Unquote, but can handle multi-character strings inside single quotes.
  102. func singleUnquote(str string) (string, bool) {
  103. if len(str) < 2 || str[0] != '\'' || str[len(str)-1] != '\'' {
  104. return "", false
  105. }
  106. return str[1 : len(str)-1], true
  107. }
  108. // decodeKeyValue decodes a key=value string
  109. func decodeKeyValue(str string) (string, string, bool) {
  110. idx := strings.IndexRune(str, '=')
  111. if idx == -1 {
  112. return "", "", false
  113. }
  114. return str[:idx], str[idx+1:], true
  115. }
  116. // copyFile copies a file from src to dst. filepath.Dir(dst) must exist.
  117. func copyFile(src, dst string) (int64, error) {
  118. source, err := os.Open(src)
  119. if err != nil {
  120. return 0, err
  121. }
  122. defer source.Close()
  123. destination, err := os.Create(dst)
  124. if err != nil {
  125. return 0, err
  126. }
  127. defer destination.Close()
  128. return io.Copy(destination, source)
  129. }
  130. // gzipFileToDir writes a compressed copy of src to destDir with the suffix ".gz".
  131. func gzipFileToDir(src, destDir string) error {
  132. in, err := os.Open(src)
  133. if err != nil {
  134. return fmt.Errorf("failed to open %s: %s", src, err.Error())
  135. }
  136. defer in.Close()
  137. dest := filepath.Join(destDir, filepath.Base(src)+".gz")
  138. out, err := os.OpenFile(dest, os.O_CREATE|os.O_WRONLY, 0666)
  139. if err != nil {
  140. return fmt.Errorf("failed to open %s: %s", dest, err.Error())
  141. }
  142. defer out.Close()
  143. gz := gzip.NewWriter(out)
  144. defer gz.Close()
  145. _, err = io.Copy(gz, in)
  146. if err != nil {
  147. return fmt.Errorf("failed to gzip %s: %s", dest, err.Error())
  148. }
  149. return nil
  150. }