blob: 64dbbff6d5c5119203018a4ff74c73376b3542f8 [file] [log] [blame]
package fs
import (
"archive/tar"
"compress/gzip"
"io"
"os"
"os/exec"
"path/filepath"
"cos.googlesource.com/cos/tools.git/src/pkg/utils"
)
const gzipFileExt = ".gz"
// TarFile compresses the file at src to dst.
func TarFile(src, dst string) error {
args := []string{"cf", dst}
dirPath := filepath.Dir(src)
baseName := filepath.Base(src)
// Add the compression type based on the dst, if the
// file type is not supported tar using default compression.
if filepath.Ext(dst) == gzipFileExt {
args = append(args, "-I", "/bin/gzip")
}
// add inputFilePath args
args = append(args, "-C", dirPath, baseName)
cmd := exec.Command("tar", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// TarDir compresses the directory at root to dst.
func TarDir(root, dst string) error {
args := []string{"cf", dst, "-C", root}
inputFiles, err := filepath.Glob(filepath.Join(root, "*"))
if err != nil {
return err
}
var relInputFiles []string
for _, path := range inputFiles {
relPath, err := filepath.Rel(root, path)
if err != nil {
return err
}
relInputFiles = append(relInputFiles, relPath)
}
if relInputFiles == nil {
relInputFiles = []string{"."}
}
args = append(args, relInputFiles...)
cmd := exec.Command("tar", args...)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// ExtractFile decompresses the tar file at inputFile to destDir.
func ExtractFile(inputFile, destDir string) error {
var reader io.Reader
fileReader, err := os.Open(inputFile)
if err != nil {
return err
}
defer utils.CheckClose(fileReader, "error closing the file reader", &err)
if filepath.Ext(inputFile) == ".gz" {
reader, err = gzip.NewReader(fileReader)
if err != nil {
return err
}
} else {
reader = fileReader
}
return extractFile(reader, destDir)
}
// extractFile decompresses the tar file reader at inputFile to destDir.
func extractFile(reader io.Reader, destDir string) error {
// Open the file for read
// Use gzip to read from the file
tarReader := tar.NewReader(reader)
// Read the file sequentially
for {
fileHeader, err := tarReader.Next()
switch {
// If no more files are found, return
case err == io.EOF:
return nil
// Return if hit any error
case err != nil:
return err
// If next file's header is nil, just skip it.
case fileHeader == nil:
continue
}
// Create a target file locally
localTarget := filepath.Join(destDir, fileHeader.Name)
switch fileHeader.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(localTarget, 0755); err != nil {
return err
}
// This should be tar.TypeReg, e.g regular file.
default:
localDir := filepath.Dir(localTarget)
// Create a dir if it doesn't exist but it should have created dir already.
if err := os.MkdirAll(localDir, 0755); err != nil {
return err
}
localFile, err := os.Create(localTarget)
if err != nil {
return err
}
// Copy over the contents.
if _, err = io.Copy(localFile, tarReader); err != nil {
localFile.Close()
return err
}
localFile.Close()
}
}
return nil
}