package Archive import ( "archive/tar" "bufio" "bytes" "compress/gzip" "io" "io/fs" "os" "path/filepath" ) func ExtractArchive(source, target string) error { var ( inFile *os.File gzipReader *gzip.Reader tarReader *tar.Reader e error ) inFile, e = os.Open(source) if e != nil { return e } defer inFile.Close() gzipReader, e = gzip.NewReader(inFile) defer gzipReader.Close() tarReader = tar.NewReader(gzipReader) return extractFromArchive(tarReader, target) } func extractFromArchive(tarReader *tar.Reader, target string) error { var ( header *tar.Header info fs.FileInfo file *os.File path, basePath string e error ) for { header, e = tarReader.Next() if e == io.EOF { break } if e != nil { return e } path = filepath.Join(target, header.Name) info = header.FileInfo() if filepath.Base(info.Name()) == "manifest.yml" { continue } if info.IsDir() { e = os.MkdirAll(path, info.Mode()) if e != nil { return e } continue } basePath, e = filepath.Abs(filepath.Dir(path)) if e != nil { return e } _, e = os.Stat(basePath) if os.IsNotExist(e) { e = os.MkdirAll(basePath, info.Mode()) if e != nil { return e } } file, e = os.OpenFile(path, os.O_CREATE|os.O_RDWR, info.Mode()) if e != nil { return e } defer file.Close() _, e = io.Copy(file, tarReader) if e != nil { return e } } return nil } func ExtractManifestFile(source string) (string, error) { var ( inFile *os.File gzipReader *gzip.Reader tarReader *tar.Reader e error ) inFile, e = os.Open(source) if e != nil { return "", e } defer inFile.Close() gzipReader, e = gzip.NewReader(inFile) defer gzipReader.Close() tarReader = tar.NewReader(gzipReader) return extractManifestFromArchive(tarReader) } func extractManifestFromArchive(tarReader *tar.Reader) (string, error) { var ( header *tar.Header info fs.FileInfo manifestWriter *bufio.Writer manifestBytes bytes.Buffer e error ) for { header, e = tarReader.Next() if e == io.EOF { break } if e != nil { return manifestBytes.String(), e } info = header.FileInfo() if filepath.Base(info.Name()) != "manifest.yml" { continue } manifestWriter = bufio.NewWriter(&manifestBytes) _, e = io.Copy(manifestWriter, tarReader) if e != nil { return manifestBytes.String(), e } } return manifestBytes.String(), nil } func GetPackageFilePaths(source string) ([]string, error) { var ( inFile *os.File gzipReader *gzip.Reader tarReader *tar.Reader info os.FileInfo header *tar.Header pkgFiles []string e error ) inFile, e = os.Open(source) if e != nil { return pkgFiles, e } defer inFile.Close() gzipReader, e = gzip.NewReader(inFile) defer gzipReader.Close() tarReader = tar.NewReader(gzipReader) for { header, e = tarReader.Next() if e == io.EOF { break } if e != nil { return pkgFiles, e } info = header.FileInfo() if filepath.Base(info.Name()) == "manifest.yml" { continue } pkgFiles = append(pkgFiles, header.Name) } return pkgFiles, nil }