diff options
Diffstat (limited to 'pkg/archive.go')
| -rw-r--r-- | pkg/archive.go | 85 |
1 files changed, 69 insertions, 16 deletions
diff --git a/pkg/archive.go b/pkg/archive.go index ea4017d9..ba7c61b9 100644 --- a/pkg/archive.go +++ b/pkg/archive.go @@ -311,31 +311,28 @@ func (a archiveArtifact) Inputs() []Artifact { // IsExclusive returns false: [Reader] is fully sequential. func (archiveArtifact) IsExclusive() bool { return false } -// Cure cures the [Artifact], producing a directory located at work. -func (a archiveArtifact) Cure(t *TContext) (err error) { - var r io.ReadCloser - if r, err = t.Open(a.f); err != nil { - return - } - - defer func() { - closeErr := r.Close() - if err == nil { - err = closeErr - } - }() +// Revision satisfies [RevisionArtifact] for status behaviour. +func (archiveArtifact) Revision() uint64 { return 0 } +// Extract reads an archive stream from r and writes its contents to dir. If +// writeStatus is non-nil, it is called with a user-facing message after +// each successfully extracted entry. +func Extract( + r io.Reader, + dir string, + writeStatus func(s string) error, +) (err error) { type dirTargetPerm struct { path string mode fs.FileMode } var madeDirectories []dirTargetPerm - if err = os.MkdirAll(t.GetWorkDir().String(), 0700); err != nil { + if err = os.MkdirAll(dir, 0700); err != nil { return } var root *os.Root - if root, err = os.OpenRoot(t.GetWorkDir().String()); err != nil { + if root, err = os.OpenRoot(dir); err != nil { return } defer func() { @@ -348,6 +345,7 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { var header *ArchiveHeader ar := NewReader(r) for header, err = ar.Next(); err == nil; header, err = ar.Next() { + var m string if header.Mode.IsRegular() { var f *os.File if f, err = root.OpenFile( @@ -363,18 +361,33 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { } else if err = f.Close(); err != nil { return } + + m = fmt.Sprintf( + "%s %s (%d bytes)", + header.Mode, + header.Path, + header.Size, + ) } else if header.Mode&fs.ModeSymlink != 0 { var p []byte if p, err = io.ReadAll(ar); err != nil { return } + linkname := unsafe.String(unsafe.SliceData(p), len(p)) if err = root.Symlink( - unsafe.String(unsafe.SliceData(p), len(p)), + linkname, header.Path, ); err != nil { return } + + m = fmt.Sprintf( + "%s %s linkname %s", + header.Mode, + header.Path, + linkname, + ) } else if header.Mode.IsDir() { if header.Path == "." { continue @@ -387,9 +400,21 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { if err = root.Mkdir(header.Path, 0700); err != nil { return } + + m = fmt.Sprintf( + "%s %s", + header.Mode, + header.Path, + ) } else { return InvalidFileModeError(header.Mode) } + + if writeStatus != nil && m != "" { + if err = writeStatus(m); err != nil { + return + } + } } if errors.Is(err, io.EOF) { err = nil @@ -406,6 +431,34 @@ func (a archiveArtifact) Cure(t *TContext) (err error) { return } +// Cure cures the [Artifact], producing a directory located at work. +func (a archiveArtifact) Cure(t *TContext) (err error) { + var status io.Writer + if status, err = t.GetStatusWriter(); err != nil { + return + } + + var r io.ReadCloser + if r, err = t.Open(a.f); err != nil { + return + } + + msg := t.GetMessage() + err = Extract(r, t.GetWorkDir().String(), func(s string) (err error) { + msg.Verbose(s) + if _, err = io.WriteString(status, s); err != nil { + return + } + _, err = status.Write([]byte{'\n'}) + return + }) + + if closeErr := r.Close(); err == nil { + err = closeErr + } + return +} + // CuresExempt exempts the cheap [KindArchive] implementation often found at // the end of a [FileArtifact] pipeline. func (archiveArtifact) CuresExempt() {} |
