package debug
|
|
|
|
import (
|
|
"archive/zip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// zipDir zips all the contents found in src, including both files and
|
|
// directories, into a destination file dest. It returns an error upon failure.
|
|
// It assumes src is a directory.
|
|
func zipDir(src, dest string) error {
|
|
zipFile, err := os.Create(dest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer zipFile.Close()
|
|
|
|
zipWriter := zip.NewWriter(zipFile)
|
|
defer zipWriter.Close()
|
|
|
|
dirName := filepath.Base(dest)
|
|
baseDir := strings.TrimSuffix(dirName, filepath.Ext(dirName))
|
|
|
|
filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
header, err := zip.FileInfoHeader(info)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Each execution of this utility on a Tendermint process will result in a
|
|
// unique file.
|
|
header.Name = filepath.Join(baseDir, strings.TrimPrefix(path, src))
|
|
|
|
// Handle cases where the content to be zipped is a file or a directory,
|
|
// where a directory must have a '/' suffix.
|
|
if info.IsDir() {
|
|
header.Name += "/"
|
|
} else {
|
|
header.Method = zip.Deflate
|
|
}
|
|
|
|
headerWriter, err := zipWriter.CreateHeader(header)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if info.IsDir() {
|
|
return nil
|
|
}
|
|
|
|
file, err := os.Open(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
|
|
_, err = io.Copy(headerWriter, file)
|
|
return err
|
|
})
|
|
|
|
return nil
|
|
}
|
|
|
|
// copyFile copies a file from src to dest and returns an error upon failure. The
|
|
// copied file retains the source file's permissions.
|
|
func copyFile(src, dest string) error {
|
|
if _, err := os.Stat(src); os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
|
|
srcFile, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer srcFile.Close()
|
|
|
|
destFile, err := os.Create(dest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer destFile.Close()
|
|
|
|
if _, err = io.Copy(destFile, srcFile); err != nil {
|
|
return err
|
|
}
|
|
|
|
srcInfo, err := os.Stat(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return os.Chmod(dest, srcInfo.Mode())
|
|
}
|
|
|
|
// writeStateToFile pretty JSON encodes an object and writes it to file composed
|
|
// of dir and filename. It returns an error upon failure to encode or write to
|
|
// file.
|
|
func writeStateJSONToFile(state interface{}, dir, filename string) error {
|
|
stateJSON, err := json.MarshalIndent(state, "", " ")
|
|
if err != nil {
|
|
return fmt.Errorf("failed to encode state dump: %w", err)
|
|
}
|
|
|
|
return ioutil.WriteFile(path.Join(dir, filename), stateJSON, os.ModePerm)
|
|
}
|