66 lines
2.4 KiB
Go
Executable File
66 lines
2.4 KiB
Go
Executable File
// Unpack: extract a source tarball.
|
|
//
|
|
// Supports .tar.gz, .tar.bz2, .tar.xz, .tar.lz, .tgz, .txz, .tbz2, and
|
|
// plain .tar. The destination directory is created if it doesn't exist.
|
|
// We shell out to `tar` because it's universally available on every
|
|
// Source Mage box and is far faster than a pure-Go reimplementation
|
|
// (it uses splice() for zero-copy extraction on recent kernels).
|
|
package cast
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"dcos.net/sorcery-go/pkg/eventbus"
|
|
)
|
|
|
|
// Unpack extracts `archivePath` into `destDir`. destDir is created.
|
|
// Returns the path to the top-level source directory inside destDir.
|
|
func Unpack(archivePath, destDir string, bus *eventbus.Bus, taskID string) error {
|
|
if bus != nil {
|
|
bus.Log(taskID, "📦 Unpacking "+filepath.Base(archivePath))
|
|
}
|
|
if err := os.MkdirAll(destDir, 0755); err != nil {
|
|
return err
|
|
}
|
|
// `tar` auto-detects compression from the file content, so we don't
|
|
// need to inspect the extension — `tar -xf` does the right thing.
|
|
cmd := exec.Command("tar", "-xf", archivePath, "-C", destDir, "--no-same-owner", "--no-same-permissions")
|
|
if out, err := cmd.CombinedOutput(); err != nil {
|
|
return fmt.Errorf("unpack: %w (output: %s)", err, string(out))
|
|
}
|
|
if bus != nil {
|
|
bus.Log(taskID, "✓ Unpacked into "+destDir)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GuessSourceDir inspects destDir after extraction and returns the
|
|
// single top-level subdirectory if there is one (the typical
|
|
// ${SPELL}-${VERSION} directory), otherwise returns destDir itself.
|
|
func GuessSourceDir(destDir string) (string, error) {
|
|
entries, err := os.ReadDir(destDir)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
if len(entries) == 1 && entries[0].IsDir() {
|
|
return filepath.Join(destDir, entries[0].Name()), nil
|
|
}
|
|
return destDir, nil
|
|
}
|
|
|
|
// ArchiveExtension returns the recognised archive extension of path.
|
|
func ArchiveExtension(path string) string {
|
|
low := strings.ToLower(path)
|
|
for _, ext := range []string{".tar.gz", ".tar.bz2", ".tar.xz", ".tar.lz",
|
|
".tgz", ".txz", ".tbz2", ".tar"} {
|
|
if strings.HasSuffix(low, ext) {
|
|
return ext
|
|
}
|
|
}
|
|
return ""
|
|
}
|