/internal/util/projutil/project_util.go

https://github.com/operator-framework/operator-sdk · Go · 157 lines · 105 code · 21 blank · 31 comment · 24 complexity · a01b8e38b9a6b0c347d5530586ae24a9 MD5 · raw file

  1. // Copyright 2018 The Operator-SDK Authors
  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 projutil
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "os"
  19. "regexp"
  20. "strings"
  21. log "github.com/sirupsen/logrus"
  22. "sigs.k8s.io/kubebuilder/pkg/model/config"
  23. )
  24. const (
  25. // Useful file modes.
  26. DirMode = 0755
  27. FileMode = 0644
  28. ExecFileMode = 0755
  29. )
  30. const (
  31. // Go env vars.
  32. GoFlagsEnv = "GOFLAGS"
  33. )
  34. // Default config file path.
  35. const configFile = "PROJECT"
  36. // OperatorType - the type of operator
  37. type OperatorType = string
  38. const (
  39. // OperatorTypeGo - golang type of operator.
  40. OperatorTypeGo OperatorType = "go"
  41. // OperatorTypeAnsible - ansible type of operator.
  42. OperatorTypeAnsible OperatorType = "ansible"
  43. // OperatorTypeHelm - helm type of operator.
  44. OperatorTypeHelm OperatorType = "helm"
  45. // OperatorTypeUnknown - unknown type of operator.
  46. OperatorTypeUnknown OperatorType = "unknown"
  47. )
  48. type ErrUnknownOperatorType struct {
  49. Type string
  50. }
  51. func (e ErrUnknownOperatorType) Error() string {
  52. if e.Type == "" {
  53. return "unknown operator type"
  54. }
  55. return fmt.Sprintf(`unknown operator type "%v"`, e.Type)
  56. }
  57. // HasProjectFile returns true if the project is configured as a kubebuilder
  58. // project.
  59. func HasProjectFile() bool {
  60. _, err := os.Stat(configFile)
  61. if err != nil {
  62. if os.IsNotExist(err) {
  63. return false
  64. }
  65. log.Fatalf("Failed to read PROJECT file to detect kubebuilder project: %v", err)
  66. }
  67. return true
  68. }
  69. // ReadConfig returns a configuration if a file containing one exists at the
  70. // default path (project root).
  71. func ReadConfig() (*config.Config, error) {
  72. b, err := ioutil.ReadFile(configFile)
  73. if err != nil {
  74. return nil, err
  75. }
  76. c := &config.Config{}
  77. if err = c.Unmarshal(b); err != nil {
  78. return nil, err
  79. }
  80. return c, nil
  81. }
  82. // PluginKeyToOperatorType converts a plugin key string to an operator project type.
  83. // TODO(estroz): this can probably be made more robust by checking known plugin keys directly.
  84. func PluginKeyToOperatorType(pluginKey string) OperatorType {
  85. switch {
  86. case strings.HasPrefix(pluginKey, "go"):
  87. return OperatorTypeGo
  88. case strings.HasPrefix(pluginKey, "helm"):
  89. return OperatorTypeHelm
  90. case strings.HasPrefix(pluginKey, "ansible"):
  91. return OperatorTypeAnsible
  92. }
  93. return OperatorTypeUnknown
  94. }
  95. var flagRe = regexp.MustCompile("(.* )?-v(.* )?")
  96. // SetGoVerbose sets GOFLAGS="${GOFLAGS} -v" if GOFLAGS does not
  97. // already contain "-v" to make "go" command output verbose.
  98. func SetGoVerbose() error {
  99. gf, ok := os.LookupEnv(GoFlagsEnv)
  100. if !ok || len(gf) == 0 {
  101. return os.Setenv(GoFlagsEnv, "-v")
  102. }
  103. if !flagRe.MatchString(gf) {
  104. return os.Setenv(GoFlagsEnv, gf+" -v")
  105. }
  106. return nil
  107. }
  108. // RewriteFileContents adds newContent to the line after the last occurrence of target in filename's contents,
  109. // then writes the updated contents back to disk.
  110. func RewriteFileContents(filename, target, newContent string) error {
  111. text, err := ioutil.ReadFile(filename)
  112. if err != nil {
  113. return fmt.Errorf("error in getting contents from the file, %v", err)
  114. }
  115. modifiedContent, err := appendContent(string(text), target, newContent)
  116. if err != nil {
  117. return err
  118. }
  119. err = ioutil.WriteFile(filename, []byte(modifiedContent), FileMode)
  120. if err != nil {
  121. return fmt.Errorf("error writing modified contents to file, %v", err)
  122. }
  123. return nil
  124. }
  125. func appendContent(fileContents, target, newContent string) (string, error) {
  126. labelIndex := strings.LastIndex(fileContents, target)
  127. if labelIndex == -1 {
  128. return "", fmt.Errorf("no prior string %s in newContent", target)
  129. }
  130. separationIndex := strings.Index(fileContents[labelIndex:], "\n")
  131. if separationIndex == -1 {
  132. return "", fmt.Errorf("no new line at the end of string %s", fileContents[labelIndex:])
  133. }
  134. index := labelIndex + separationIndex + 1
  135. return fileContents[:index] + newContent + fileContents[index:], nil
  136. }