code.vegaprotocol.io/vega@v0.79.0/visor/utils/utils.go (about) 1 // Copyright (C) 2023 Gobalsky Labs Limited 2 // 3 // This program is free software: you can redistribute it and/or modify 4 // it under the terms of the GNU Affero General Public License as 5 // published by the Free Software Foundation, either version 3 of the 6 // License, or (at your option) any later version. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU Affero General Public License for more details. 12 // 13 // You should have received a copy of the GNU Affero General Public License 14 // along with this program. If not, see <http://www.gnu.org/licenses/>. 15 16 package utils 17 18 import ( 19 "archive/zip" 20 "bytes" 21 "encoding/json" 22 "fmt" 23 "io" 24 "os" 25 "os/exec" 26 "path/filepath" 27 "strings" 28 ) 29 30 func AbsPath(p string) (string, error) { 31 if filepath.IsAbs(p) { 32 return p, nil 33 } 34 35 aPath, err := filepath.Abs(p) 36 if err != nil { 37 return "", fmt.Errorf("failed to get absolute path for %q: %w", p, err) 38 } 39 40 return aPath, nil 41 } 42 43 func PathExists(path string) (bool, error) { 44 _, err := os.Stat(path) 45 if err == nil { 46 return true, nil 47 } 48 if os.IsNotExist(err) { 49 return false, nil 50 } 51 return false, fmt.Errorf("failed to check if %q path exists: %w", path, err) 52 } 53 54 func EnsureBinary(path string) error { 55 info, err := os.Stat(path) 56 if err != nil { 57 return err 58 } 59 if !info.Mode().IsRegular() { 60 _, f := filepath.Split(path) 61 return fmt.Errorf("%s is not a regular file", f) 62 } 63 // Make sure all executable bits are set. 64 oldMode := info.Mode().Perm() 65 newMode := oldMode | 0o111 // Set the three execute bits to on (a+x). 66 if oldMode != newMode { 67 return os.Chmod(path, newMode) 68 } 69 return nil 70 } 71 72 // UnzipSource iterates over zip files inside the archive and unzips each of them to the destination. 73 func UnzipSource(source, destination string) error { 74 reader, err := zip.OpenReader(source) 75 if err != nil { 76 return err 77 } 78 defer reader.Close() 79 80 destination, err = filepath.Abs(destination) 81 if err != nil { 82 return err 83 } 84 85 for _, f := range reader.File { 86 err := unzipFile(f, destination) 87 if err != nil { 88 return err 89 } 90 } 91 92 return nil 93 } 94 95 func unzipFile(f *zip.File, destination string) error { 96 filePath := filepath.Join(destination, f.Name) 97 if !strings.HasPrefix(filePath, filepath.Clean(destination)+string(os.PathSeparator)) { 98 return fmt.Errorf("invalid file path: %s", filePath) 99 } 100 101 if f.FileInfo().IsDir() { 102 if err := os.MkdirAll(filePath, os.ModePerm); err != nil { 103 return err 104 } 105 return nil 106 } 107 108 if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { 109 return err 110 } 111 112 destinationFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) 113 if err != nil { 114 return err 115 } 116 defer destinationFile.Close() 117 118 zippedFile, err := f.Open() 119 if err != nil { 120 return err 121 } 122 defer zippedFile.Close() 123 124 if _, err := io.Copy(destinationFile, zippedFile); err != nil { 125 return err 126 } 127 return nil 128 } 129 130 func ToLookupMap[T comparable](slice []T) map[T]struct{} { 131 m := make(map[T]struct{}, len(slice)) 132 for _, v := range slice { 133 m[v] = struct{}{} 134 } 135 return m 136 } 137 138 func ExecuteBinary(binaryPath string, args []string, v interface{}) ([]byte, error) { 139 command := exec.Command(binaryPath, args...) 140 141 var stdOut, stErr bytes.Buffer 142 command.Stdout = &stdOut 143 command.Stderr = &stErr 144 145 if err := command.Run(); err != nil { 146 return nil, fmt.Errorf( 147 "failed to execute binary %s %v with error: %s, %s: %s", 148 binaryPath, 149 args, 150 stErr.String(), 151 stdOut.String(), 152 err.Error(), 153 ) 154 } 155 156 if v == nil { 157 return stdOut.Bytes(), nil 158 } 159 160 if err := json.Unmarshal(stdOut.Bytes(), v); err != nil { 161 return nil, fmt.Errorf("failed to parse command output %q: %w", stdOut.String(), err) 162 } 163 164 return nil, nil 165 }