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  }