package unpack import ( "archive/zip" "bytes" "fmt" "io" "os" "path/filepath" "strings" ) const ownerRWXworldRX = 0o755 type GitHubZipball struct { io.Reader } func (v GitHubZipball) UnpackTo(libTarget string) error { raw, err := io.ReadAll(v) if err != nil { return err } zipReader, err := zip.NewReader(bytes.NewReader(raw), int64(len(raw))) if err != nil { return fmt.Errorf("zip: %w", err) } // GitHub packages entire repo contents into a top-level folder, e.g. databrickslabs-ucx-2800c6b rootDirInZIP := zipReader.File[0].FileHeader.Name for _, zf := range zipReader.File { if zf.Name == rootDirInZIP { continue } normalizedName := strings.TrimPrefix(zf.Name, rootDirInZIP) targetName := filepath.Join(libTarget, normalizedName) if zf.FileInfo().IsDir() { err = os.MkdirAll(targetName, ownerRWXworldRX) if err != nil { return fmt.Errorf("mkdir %s: %w", normalizedName, err) } continue } err = v.extractFile(zf, targetName) if err != nil { return fmt.Errorf("extract %s: %w", zf.Name, err) } } return nil } func (v GitHubZipball) extractFile(zf *zip.File, targetName string) error { reader, err := zf.Open() if err != nil { return fmt.Errorf("source: %w", err) } defer reader.Close() writer, err := os.OpenFile(targetName, os.O_CREATE|os.O_RDWR, zf.Mode()) if err != nil { return fmt.Errorf("target: %w", err) } defer writer.Close() _, err = io.Copy(writer, reader) return err }