internal/pkg: stream decompress artifact
All checks were successful
Test / Create distribution (push) Successful in 2m56s
Test / Sandbox (push) Successful in 6m55s
Test / Hakurei (push) Successful in 9m46s
Test / ShareFS (push) Successful in 10m21s
Test / Sandbox (race detector) (push) Successful in 10m44s
Test / Hakurei (race detector) (push) Successful in 14m34s
Test / Flake checks (push) Successful in 3m14s
All checks were successful
Test / Create distribution (push) Successful in 2m56s
Test / Sandbox (push) Successful in 6m55s
Test / Hakurei (push) Successful in 9m46s
Test / ShareFS (push) Successful in 10m21s
Test / Sandbox (race detector) (push) Successful in 10m44s
Test / Hakurei (race detector) (push) Successful in 14m34s
Test / Flake checks (push) Successful in 3m14s
The tarArtifact predates FileArtifact pipelining. This migrates decompression and buffering into a standalone artifact implementation. Signed-off-by: Ophestra <cat@gensokyo.uk>
This commit is contained in:
119
internal/pkg/compress.go
Normal file
119
internal/pkg/compress.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package pkg
|
||||
|
||||
import (
|
||||
"compress/bzip2"
|
||||
"compress/gzip"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
const (
|
||||
// Gzip denotes a stream compressed via [gzip].
|
||||
Gzip = iota
|
||||
// Bzip2 denotes a stream compressed via [bzip2].
|
||||
Bzip2
|
||||
)
|
||||
|
||||
// A decompressArtifact is a [FileArtifact] decompressing a backing
|
||||
// [FileArtifact] stream.
|
||||
type decompressArtifact struct {
|
||||
// Caller-supplied backing stream.
|
||||
f Artifact
|
||||
// Compression on top of the stream.
|
||||
compress uint32
|
||||
}
|
||||
|
||||
var _ FileArtifact = new(decompressArtifact)
|
||||
|
||||
// decompressArtifactNamed embeds decompressArtifact for a [fmt.Stringer] stream.
|
||||
type decompressArtifactNamed struct {
|
||||
decompressArtifact
|
||||
// Copied from decompressArtifact.f.
|
||||
name string
|
||||
}
|
||||
|
||||
var _ fmt.Stringer = new(decompressArtifactNamed)
|
||||
|
||||
// NewDecompress returns a [FileArtifact] decompressing the supplied [Artifact].
|
||||
func NewDecompress(a Artifact, compress uint32) Artifact {
|
||||
da := decompressArtifact{a, compress}
|
||||
if s, ok := a.(fmt.Stringer); ok {
|
||||
if name := s.String(); name != "" {
|
||||
return &decompressArtifactNamed{da, name}
|
||||
}
|
||||
}
|
||||
return &da
|
||||
}
|
||||
|
||||
// String returns the name of the underlying [Artifact] suffixed with decompress.
|
||||
func (a *decompressArtifactNamed) String() string { return a.name + "-decompress" }
|
||||
|
||||
// Kind returns the hardcoded [Kind] constant.
|
||||
func (a *decompressArtifact) Kind() Kind { return KindDecompress }
|
||||
|
||||
// Params writes value of compression enum.
|
||||
func (a *decompressArtifact) Params(ctx *IContext) { ctx.WriteUint32(a.compress) }
|
||||
|
||||
func init() {
|
||||
register(KindDecompress, func(r *IRReader) Artifact {
|
||||
a := NewDecompress(r.Next(), r.ReadUint32())
|
||||
if _, ok := r.Finalise(); ok {
|
||||
panic(ErrUnexpectedChecksum)
|
||||
}
|
||||
return a
|
||||
})
|
||||
}
|
||||
|
||||
// Dependencies returns a slice containing the backing file.
|
||||
func (a *decompressArtifact) Dependencies() []Artifact {
|
||||
return []Artifact{a.f}
|
||||
}
|
||||
|
||||
// IsExclusive returns false: decompressor is fully sequential.
|
||||
func (a *decompressArtifact) IsExclusive() bool { return false }
|
||||
|
||||
// compoundCloser is an [io.ReadCloser] with an additional [io.Closer] attached.
|
||||
type compoundCloser struct {
|
||||
io.ReadCloser
|
||||
c io.Closer
|
||||
}
|
||||
|
||||
// Close closes [io.ReadCloser] and the additional [io.Closer]. It returns the
|
||||
// non-nil error returned by the underlying [io.ReadCloser], otherwise it
|
||||
// returns the error returned by the additional [io.Closer].
|
||||
func (c compoundCloser) Close() error {
|
||||
err := c.ReadCloser.Close()
|
||||
if _err := c.c.Close(); err == nil {
|
||||
err = _err
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Cure returns a decompressor [io.ReadCloser].
|
||||
func (a *decompressArtifact) Cure(r *RContext) (io.ReadCloser, error) {
|
||||
sr, err := r.Open(a.f)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
br := r.cache.getReaderRC(sr)
|
||||
|
||||
var dr io.ReadCloser
|
||||
switch a.compress {
|
||||
case Gzip:
|
||||
if dr, err = gzip.NewReader(br); err != nil {
|
||||
_ = br.Close()
|
||||
return nil, err
|
||||
}
|
||||
return compoundCloser{dr, br}, nil
|
||||
|
||||
case Bzip2:
|
||||
return struct {
|
||||
io.Reader
|
||||
io.Closer
|
||||
}{bzip2.NewReader(br), br}, nil
|
||||
|
||||
default:
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user