github.com/mkimuram/operator-sdk@v0.7.1-0.20190410172100-52ad33a4bda0/internal/util/projutil/project_util.go (about) 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 15 package projutil 16 17 import ( 18 "fmt" 19 "os" 20 "os/exec" 21 "path/filepath" 22 "regexp" 23 "strings" 24 25 log "github.com/sirupsen/logrus" 26 "github.com/spf13/cobra" 27 ) 28 29 const ( 30 GopathEnv = "GOPATH" 31 GoFlagsEnv = "GOFLAGS" 32 SrcDir = "src" 33 34 fsep = string(filepath.Separator) 35 mainFile = "cmd" + fsep + "manager" + fsep + "main.go" 36 buildDockerfile = "build" + fsep + "Dockerfile" 37 rolesDir = "roles" 38 helmChartsDir = "helm-charts" 39 ) 40 41 // OperatorType - the type of operator 42 type OperatorType = string 43 44 const ( 45 // OperatorTypeGo - golang type of operator. 46 OperatorTypeGo OperatorType = "go" 47 // OperatorTypeAnsible - ansible type of operator. 48 OperatorTypeAnsible OperatorType = "ansible" 49 // OperatorTypeHelm - helm type of operator. 50 OperatorTypeHelm OperatorType = "helm" 51 // OperatorTypeUnknown - unknown type of operator. 52 OperatorTypeUnknown OperatorType = "unknown" 53 ) 54 55 type ErrUnknownOperatorType struct { 56 Type string 57 } 58 59 func (e ErrUnknownOperatorType) Error() string { 60 if e.Type == "" { 61 return "unknown operator type" 62 } 63 return fmt.Sprintf(`unknown operator type "%v"`, e.Type) 64 } 65 66 // MustInProjectRoot checks if the current dir is the project root and returns 67 // the current repo's import path, ex github.com/example-inc/app-operator 68 func MustInProjectRoot() { 69 // If the current directory has a "build/dockerfile", then it is safe to say 70 // we are at the project root. 71 if _, err := os.Stat(buildDockerfile); err != nil { 72 if os.IsNotExist(err) { 73 log.Fatalf("Must run command in project root dir: project structure requires %s", buildDockerfile) 74 } 75 log.Fatalf("Error while checking if current directory is the project root: (%v)", err) 76 } 77 } 78 79 func CheckGoProjectCmd(cmd *cobra.Command) error { 80 if IsOperatorGo() { 81 return nil 82 } 83 return fmt.Errorf("'%s' can only be run for Go operators; %s does not exist.", cmd.CommandPath(), mainFile) 84 } 85 86 func MustGetwd() string { 87 wd, err := os.Getwd() 88 if err != nil { 89 log.Fatalf("Failed to get working directory: (%v)", err) 90 } 91 return wd 92 } 93 94 // CheckAndGetProjectGoPkg checks if this project's repository path is rooted under $GOPATH and returns the current directory's import path 95 // e.g: "github.com/example-inc/app-operator" 96 func CheckAndGetProjectGoPkg() string { 97 gopath := MustSetGopath(MustGetGopath()) 98 goSrc := filepath.Join(gopath, SrcDir) 99 wd := MustGetwd() 100 currPkg := strings.Replace(wd, goSrc+fsep, "", 1) 101 // strip any "/" prefix from the repo path. 102 return strings.TrimPrefix(currPkg, fsep) 103 } 104 105 // GetOperatorType returns type of operator is in cwd. 106 // This function should be called after verifying the user is in project root. 107 func GetOperatorType() OperatorType { 108 switch { 109 case IsOperatorGo(): 110 return OperatorTypeGo 111 case IsOperatorAnsible(): 112 return OperatorTypeAnsible 113 case IsOperatorHelm(): 114 return OperatorTypeHelm 115 } 116 return OperatorTypeUnknown 117 } 118 119 func IsOperatorGo() bool { 120 _, err := os.Stat(mainFile) 121 return err == nil 122 } 123 124 func IsOperatorAnsible() bool { 125 stat, err := os.Stat(rolesDir) 126 return err == nil && stat.IsDir() 127 } 128 129 func IsOperatorHelm() bool { 130 stat, err := os.Stat(helmChartsDir) 131 return err == nil && stat.IsDir() 132 } 133 134 // MustGetGopath gets GOPATH and ensures it is set and non-empty. If GOPATH 135 // is not set or empty, MustGetGopath exits. 136 func MustGetGopath() string { 137 gopath, ok := os.LookupEnv(GopathEnv) 138 if !ok || len(gopath) == 0 { 139 log.Fatal("GOPATH env not set") 140 } 141 return gopath 142 } 143 144 // MustSetGopath sets GOPATH=currentGopath after processing a path list, 145 // if any, then returns the set path. If GOPATH cannot be set, MustSetGopath 146 // exits. 147 func MustSetGopath(currentGopath string) string { 148 var ( 149 newGopath string 150 cwdInGopath bool 151 wd = MustGetwd() 152 ) 153 for _, newGopath = range strings.Split(currentGopath, ":") { 154 if strings.HasPrefix(filepath.Dir(wd), newGopath) { 155 cwdInGopath = true 156 break 157 } 158 } 159 if !cwdInGopath { 160 log.Fatalf("Project not in $GOPATH") 161 } 162 if err := os.Setenv(GopathEnv, newGopath); err != nil { 163 log.Fatal(err) 164 } 165 return newGopath 166 } 167 168 func ExecCmd(cmd *exec.Cmd) error { 169 cmd.Stdout = os.Stdout 170 cmd.Stderr = os.Stderr 171 err := cmd.Run() 172 if err != nil { 173 return fmt.Errorf("failed to exec %#v: %v", cmd.Args, err) 174 } 175 return nil 176 } 177 178 var flagRe = regexp.MustCompile("(.* )?-v(.* )?") 179 180 // IsGoVerbose returns true if GOFLAGS contains "-v". This function is useful 181 // when deciding whether to make "go" command output verbose. 182 func IsGoVerbose() bool { 183 gf, ok := os.LookupEnv(GoFlagsEnv) 184 return ok && len(gf) != 0 && flagRe.MatchString(gf) 185 }