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  }