tool/util/util.go (239 lines of code) (raw):

// Copyright (c) 2024 Alibaba Group Holding Ltd. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package util import ( "encoding/json" "fmt" "io" "io/ioutil" "math/rand" "os" "os/exec" "path/filepath" "runtime" "strings" "time" "github.com/alibaba/opentelemetry-go-auto-instrumentation/tool/errc" ) type RunPhase string const ( PInvalid = "invalid" PPreprocess = "preprocess" PInstrument = "instrument" ) var rp RunPhase = "bad" func SetRunPhase(phase RunPhase) { rp = phase } func GetRunPhase() RunPhase { return rp } func (rp RunPhase) String() string { return string(rp) } func InPreprocess() bool { return rp == PPreprocess } func InInstrument() bool { return rp == PInstrument } func GuaranteeInPreprocess() { Assert(rp == PPreprocess, "not in preprocess stage") } func GuaranteeInInstrument() { Assert(rp == PInstrument, "not in instrument stage") } func Assert(cond bool, format string, args ...interface{}) { if !cond { panic(fmt.Sprintf(format, args...)) } } func Unimplemented() { panic("unimplemented") } func UnimplementedT(msg string) { panic("unimplemented: " + msg) } func ShouldNotReachHere() { panic("should not reach here") } func ShouldNotReachHereT(msg string) { panic("should not reach here: " + msg) } var recordedRand = make(map[string]bool) // RandomString generates a globally unique random string of length n func RandomString(n int) string { for { var letters = []rune("0123456789") b := make([]rune, n) for i := range b { b[i] = letters[rand.Intn(len(letters))] } s := string(b) // Random suffix collision? Reroll until we get a unique one if _, ok := recordedRand[s]; !ok { recordedRand[s] = true return s } } } func RunCmd(args ...string) error { path := args[0] args = args[1:] cmd := exec.Command(path, args...) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { return errc.New(errc.ErrRunCmd, err.Error()). With("command", fmt.Sprintf("%v", args)) } return nil } func CopyFile(src, dst string) error { sourceFile, err := os.Open(src) if err != nil { return errc.New(errc.ErrOpenFile, err.Error()) } defer func(sourceFile *os.File) { err := sourceFile.Close() if err != nil { LogFatal("failed to close file %s: %v", sourceFile.Name(), err) } }(sourceFile) destFile, err := os.Create(dst) if err != nil { return errc.New(errc.ErrCreateFile, err.Error()) } defer func(destFile *os.File) { err := destFile.Close() if err != nil { LogFatal("failed to close file %s: %v", destFile.Name(), err) } }(destFile) _, err = io.Copy(destFile, sourceFile) if err != nil { return errc.New(errc.ErrCopyFile, err.Error()) } return nil } func ReadFile(filePath string) (string, error) { file, err := os.Open(filePath) if err != nil { return "", errc.New(errc.ErrOpenFile, err.Error()) } defer func(file *os.File) { err := file.Close() if err != nil { LogFatal("failed to close file %s: %v", file.Name(), err) } }(file) buf := new(strings.Builder) _, err = io.Copy(buf, file) if err != nil { return "", errc.New(errc.ErrCopyFile, err.Error()) } return buf.String(), nil } func WriteFile(filePath string, content string) (string, error) { file, err := os.Create(filePath) if err != nil { return "", errc.New(errc.ErrOpenFile, err.Error()) } defer func(file *os.File) { err := file.Close() if err != nil { LogFatal("failed to close file %s: %v", file.Name(), err) } }(file) _, err = file.WriteString(content) if err != nil { return "", errc.New(errc.ErrWriteFile, err.Error()) } return file.Name(), nil } func ListFiles(dir string) ([]string, error) { var files []string walkFn := func(path string, info os.FileInfo, err error) error { if err != nil { return errc.New(errc.ErrWalkDir, err.Error()) } // Dont list files under hidden directories if strings.HasPrefix(info.Name(), ".") { return filepath.SkipDir } if !info.IsDir() { files = append(files, path) } return nil } err := filepath.Walk(dir, walkFn) if err != nil { return nil, errc.New(errc.ErrWalkDir, err.Error()) } return files, nil } func ListFilesFlat(dir string) ([]string, error) { // no recursive files, err := os.ReadDir(dir) if err != nil { return nil, errc.New(errc.ErrReadDir, err.Error()) } var paths []string for _, file := range files { paths = append(paths, filepath.Join(dir, file.Name())) } return paths, nil } func CopyDir(src string, dst string) error { // Get the properties of the source directory sourceInfo, err := os.Stat(src) if err != nil { return errc.New(errc.ErrStat, err.Error()) } // Create the destination directory if err := os.MkdirAll(dst, sourceInfo.Mode()); err != nil { return errc.New(errc.ErrMkdirAll, err.Error()) } // Read the contents of the source directory entries, err := ioutil.ReadDir(src) if err != nil { return errc.New(errc.ErrReadDir, err.Error()) } // Iterate through each entry in the source directory for _, entry := range entries { srcPath := filepath.Join(src, entry.Name()) dstPath := filepath.Join(dst, entry.Name()) if entry.IsDir() { // Recursively copy subdirectories if err := CopyDir(srcPath, dstPath); err != nil { return err } } else { // Copy files if err := CopyFile(srcPath, dstPath); err != nil { return err } } } return nil } func PathExists(path string) bool { _, err := os.Stat(path) return err == nil } func PathNotExists(path string) bool { return !PathExists(path) } func IsWindows() bool { return runtime.GOOS == "windows" } func IsUnix() bool { return runtime.GOOS == "linux" || runtime.GOOS == "darwin" } func PhaseTimer(name string) func() { start := time.Now() return func() { Log("%s took %f s", name, time.Since(start).Seconds()) } } func GetToolName() (string, error) { // Get the path of the current executable ex, err := os.Executable() if err != nil { return "", errc.New(errc.ErrGetExecutable, err.Error()) } return filepath.Base(ex), nil } func Jsonify(v interface{}) string { b, _ := json.Marshal(v) return string(b) }