aboutsummaryrefslogtreecommitdiffhomepage
path: root/pkg/archive.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/archive.go')
-rw-r--r--pkg/archive.go85
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() {}