Skip to content

Commit c8314b8

Browse files
committed
Add new package xio with WriteCloserStack
@kodawah raised the problem that xz.Writer.Close doesn't close the underlying writer. Instead of changing the behavior of the Writer I added WriteCloserStack in a new package to address the problem. fixes: #61
1 parent 4f11dce commit c8314b8

File tree

7 files changed

+112
-4
lines changed

7 files changed

+112
-4
lines changed

TODO.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@
8686

8787
## Log
8888

89+
### 2025-08-20
90+
91+
Release v0.5.13 addressed issue #61 regarding handling of multiple WriteClosers
92+
together. So I added a new package xio with a WriteCloserStack to address the
93+
issue.
94+
8995
### 2024-04-03
9096

9197
Release v0.5.12 updates README.md and SECURITY.md to address the supply chain

cmd/gxz/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package main
22

3-
const version = "v0.5.11"
3+
const version = "v0.5.13"

cmd/xb/copyright.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2014-2022 Ulrich Kunitz. All rights reserved.
1+
// Copyright 2014-2025 Ulrich Kunitz. All rights reserved.
22
// Use of this source code is governed by a BSD-style
33
// license that can be found in the LICENSE file.
44

@@ -28,7 +28,7 @@ func crUsage(w io.Writer) {
2828
}
2929

3030
const copyrightText = `
31-
Copyright 2014-2022 Ulrich Kunitz. All rights reserved.
31+
Copyright 2014-2025 Ulrich Kunitz. All rights reserved.
3232
Use of this source code is governed by a BSD-style
3333
license that can be found in the LICENSE file.
3434
`

cmd/xb/version.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
package main
22

3-
const version = "v0.5.11"
3+
const version = "v0.5.13"

doc/relnotes/release-v0.5.13.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Release Notes v0.5.13
2+
3+
This release adds package xio to handle situations with multiple WriteClosers
4+
that were pointed out by @kodawah in issue #61.

xio/write_closer_stack.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2014-2025 Ulrich Kunitz. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Package xio provides tools to handle I/O operations. It contains the
6+
// [WriteCloserStack] type supporting combining multiple WriterClosers as single
7+
// [io.WriteCloser].
8+
package xio
9+
10+
import (
11+
"errors"
12+
"io"
13+
)
14+
15+
// WriteCloserStack allows to support multiple WriteClosers to be handled as
16+
// single WriteCloser.
17+
type WriteCloserStack struct {
18+
Stack []io.WriteCloser
19+
}
20+
21+
// NewWriteCloserStack creates a new WriteCloserStack. It will have an an empty
22+
// stack.
23+
func NewWriteCloserStack() *WriteCloserStack {
24+
return &WriteCloserStack{}
25+
}
26+
27+
// Write writes data to the top WriteCloser in the stack. If the stack is empty
28+
// Write will always succeed.
29+
func (w *WriteCloserStack) Write(p []byte) (n int, err error) {
30+
k := len(w.Stack)
31+
if k == 0 {
32+
return len(p), nil
33+
}
34+
return w.Stack[k-1].Write(p)
35+
}
36+
37+
// Close closes all writers on the stack and combines the errors. It will clear
38+
// the stack.
39+
func (w *WriteCloserStack) Close() error {
40+
var errs []error
41+
for k := len(w.Stack) - 1; k >= 0; k-- {
42+
err := w.Stack[k].Close()
43+
errs = append(errs, err)
44+
}
45+
w.Stack = nil
46+
return errors.Join(errs...)
47+
}
48+
49+
// Push adds a new WriteCloser to the top of the stack. It panics if the
50+
// WriteCloser is nil.
51+
func (w *WriteCloserStack) Push(wc io.WriteCloser) {
52+
if wc == nil {
53+
panic("cannot push nil WriteCloser onto stack")
54+
}
55+
w.Stack = append(w.Stack, wc)
56+
}

xio/write_closer_stack_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2014-2025 Ulrich Kunitz. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package xio_test
6+
7+
import (
8+
"io"
9+
"os"
10+
11+
"github.com/ulikunitz/xz"
12+
"github.com/ulikunitz/xz/xio"
13+
)
14+
15+
func ExampleWriteCloserStack() {
16+
wcStack := xio.NewWriteCloserStack()
17+
defer wcStack.Close()
18+
19+
f, err := os.CreateTemp("", "example_write_closer_stack-*.xz")
20+
if err != nil {
21+
panic(err)
22+
}
23+
wcStack.Push(f)
24+
25+
z, err := xz.NewWriter(f)
26+
if err != nil {
27+
panic(err)
28+
}
29+
wcStack.Push(z)
30+
31+
_, err = io.WriteString(wcStack, "The fox jumps over the lazy dog.\n")
32+
if err != nil {
33+
panic(err)
34+
}
35+
36+
err = wcStack.Close()
37+
if err != nil {
38+
panic(err)
39+
}
40+
41+
// Output:
42+
}

0 commit comments

Comments
 (0)