github.com/fabianvf/ocp-release-operator-sdk@v0.0.0-20190426141702-57620ee2f090/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 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold" 26 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/ansible" 27 "github.com/operator-framework/operator-sdk/internal/pkg/scaffold/helm" 28 29 log "github.com/sirupsen/logrus" 30 "github.com/spf13/cobra" 31 ) 32 33 const ( 34 GopathEnv = "GOPATH" 35 GoFlagsEnv = "GOFLAGS" 36 SrcDir = "src" 37 ) 38 39 var mainFile = filepath.Join(scaffold.ManagerDir, scaffold.CmdFile) 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 // MustInProjectRoot checks if the current dir is the project root and returns the current repo's import path 56 // e.g github.com/example-inc/app-operator 57 func MustInProjectRoot() { 58 // if the current directory has the "./build/dockerfile" file, then it is safe to say 59 // we are at the project root. 60 _, err := os.Stat(filepath.Join(scaffold.BuildDir, scaffold.DockerfileFile)) 61 if err != nil { 62 if os.IsNotExist(err) { 63 log.Fatal("Must run command in project root dir: project structure requires ./build/Dockerfile") 64 } 65 log.Fatalf("Error while checking if current directory is the project root: (%v)", err) 66 } 67 } 68 69 func CheckGoProjectCmd(cmd *cobra.Command) error { 70 t := GetOperatorType() 71 switch t { 72 case OperatorTypeGo: 73 default: 74 return fmt.Errorf("'%s' can only be run for Go operators; %s does not exist.", cmd.CommandPath(), mainFile) 75 } 76 return nil 77 } 78 79 func MustGetwd() string { 80 wd, err := os.Getwd() 81 if err != nil { 82 log.Fatalf("Failed to get working directory: (%v)", err) 83 } 84 return wd 85 } 86 87 // CheckAndGetProjectGoPkg checks if this project's repository path is rooted under $GOPATH and returns the current directory's import path 88 // e.g: "github.com/example-inc/app-operator" 89 func CheckAndGetProjectGoPkg() string { 90 gopath := MustSetGopath(MustGetGopath()) 91 goSrc := filepath.Join(gopath, SrcDir) 92 wd := MustGetwd() 93 currPkg := strings.Replace(wd, goSrc+string(filepath.Separator), "", 1) 94 // strip any "/" prefix from the repo path. 95 return strings.TrimPrefix(currPkg, string(filepath.Separator)) 96 } 97 98 // GetOperatorType returns type of operator is in cwd 99 // This function should be called after verifying the user is in project root 100 // e.g: "go", "ansible" 101 func GetOperatorType() OperatorType { 102 // Assuming that if main.go exists then this is a Go operator 103 if _, err := os.Stat(mainFile); err == nil { 104 return OperatorTypeGo 105 } 106 if stat, err := os.Stat(ansible.RolesDir); err == nil && stat.IsDir() { 107 return OperatorTypeAnsible 108 } 109 if stat, err := os.Stat(helm.HelmChartsDir); err == nil && stat.IsDir() { 110 return OperatorTypeHelm 111 } 112 return OperatorTypeUnknown 113 } 114 115 func IsOperatorGo() bool { 116 return GetOperatorType() == OperatorTypeGo 117 } 118 119 // MustGetGopath gets GOPATH and ensures it is set and non-empty. If GOPATH 120 // is not set or empty, MustGetGopath exits. 121 func MustGetGopath() string { 122 gopath, ok := os.LookupEnv(GopathEnv) 123 if !ok || len(gopath) == 0 { 124 log.Fatal("GOPATH env not set") 125 } 126 return gopath 127 } 128 129 // MustSetGopath sets GOPATH=currentGopath after processing a path list, 130 // if any, then returns the set path. If GOPATH cannot be set, MustSetGopath 131 // exits. 132 func MustSetGopath(currentGopath string) string { 133 var ( 134 newGopath string 135 cwdInGopath bool 136 wd = MustGetwd() 137 ) 138 for _, newGopath = range strings.Split(currentGopath, ":") { 139 if strings.HasPrefix(filepath.Dir(wd), newGopath) { 140 cwdInGopath = true 141 break 142 } 143 } 144 if !cwdInGopath { 145 log.Fatalf("Project not in $GOPATH") 146 } 147 if err := os.Setenv(GopathEnv, newGopath); err != nil { 148 log.Fatal(err) 149 } 150 return newGopath 151 } 152 153 func ExecCmd(cmd *exec.Cmd) error { 154 cmd.Stdout = os.Stdout 155 cmd.Stderr = os.Stderr 156 err := cmd.Run() 157 if err != nil { 158 return fmt.Errorf("failed to exec %#v: %v", cmd.Args, err) 159 } 160 return nil 161 } 162 163 var flagRe = regexp.MustCompile("(.* )?-v(.* )?") 164 165 // IsGoVerbose returns true if GOFLAGS contains "-v". This function is useful 166 // when deciding whether to make "go" command output verbose. 167 func IsGoVerbose() bool { 168 gf, ok := os.LookupEnv(GoFlagsEnv) 169 return ok && len(gf) != 0 && flagRe.MatchString(gf) 170 }