github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/cmd/ostracon/commands/debug/io.go (about)

     1  package debug
     2  
     3  import (
     4  	"archive/zip"
     5  	"encoding/json"
     6  	"fmt"
     7  	"io"
     8  	"os"
     9  	"path"
    10  	"path/filepath"
    11  	"strings"
    12  )
    13  
    14  // zipDir zips all the contents found in src, including both files and
    15  // directories, into a destination file dest. It returns an error upon failure.
    16  // It assumes src is a directory.
    17  func zipDir(src, dest string) error {
    18  	zipFile, err := os.Create(dest)
    19  	if err != nil {
    20  		return err
    21  	}
    22  	defer zipFile.Close()
    23  
    24  	zipWriter := zip.NewWriter(zipFile)
    25  	defer zipWriter.Close()
    26  
    27  	dirName := filepath.Base(dest)
    28  	baseDir := strings.TrimSuffix(dirName, filepath.Ext(dirName))
    29  
    30  	return filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
    31  		if err != nil {
    32  			return err
    33  		}
    34  
    35  		header, err := zip.FileInfoHeader(info)
    36  		if err != nil {
    37  			return err
    38  		}
    39  
    40  		// Each execution of this utility on an Ostracon process will result in a
    41  		// unique file.
    42  		header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, src))
    43  
    44  		// Handle cases where the content to be zipped is a file or a directory,
    45  		// where a directory must have a '/' suffix.
    46  		if info.IsDir() {
    47  			header.Name += "/"
    48  		} else {
    49  			header.Method = zip.Deflate
    50  		}
    51  
    52  		headerWriter, err := zipWriter.CreateHeader(header)
    53  		if err != nil {
    54  			return err
    55  		}
    56  
    57  		if info.IsDir() {
    58  			return nil
    59  		}
    60  
    61  		file, err := os.Open(path)
    62  		if err != nil {
    63  			return err
    64  		}
    65  		defer file.Close()
    66  
    67  		_, err = io.Copy(headerWriter, file)
    68  		return err
    69  	})
    70  
    71  }
    72  
    73  // copyFile copies a file from src to dest and returns an error upon failure. The
    74  // copied file retains the source file's permissions.
    75  func copyFile(src, dest string) error {
    76  	if _, err := os.Stat(src); os.IsNotExist(err) {
    77  		return err
    78  	}
    79  
    80  	srcFile, err := os.Open(src)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	defer srcFile.Close()
    85  
    86  	destFile, err := os.Create(dest)
    87  	if err != nil {
    88  		return err
    89  	}
    90  	defer destFile.Close()
    91  
    92  	if _, err = io.Copy(destFile, srcFile); err != nil {
    93  		return err
    94  	}
    95  
    96  	srcInfo, err := os.Stat(src)
    97  	if err != nil {
    98  		return err
    99  	}
   100  
   101  	return os.Chmod(dest, srcInfo.Mode())
   102  }
   103  
   104  // writeStateToFile pretty JSON encodes an object and writes it to file composed
   105  // of dir and filename. It returns an error upon failure to encode or write to
   106  // file.
   107  func writeStateJSONToFile(state interface{}, dir, filename string) error {
   108  	stateJSON, err := json.MarshalIndent(state, "", "  ")
   109  	if err != nil {
   110  		return fmt.Errorf("failed to encode state dump: %w", err)
   111  	}
   112  
   113  	return os.WriteFile(path.Join(dir, filename), stateJSON, os.ModePerm)
   114  }