Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,7 @@ Sinks are methods that return some data from a pipe, ending the pipeline and ext

| Version | New |
| ----------- | ------- |
| 0.25.2 | Fixed bug where [`Post`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Post) would error on posting a file ([#250](https://github.com/bitfield/script/issues/250))|
| 0.25.1 | [`Unique`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Unique) |
| 0.25.0 | [`ExecCommand`](https://pkg.go.dev/github.com/bitfield/script#Pipe.ExecCommand) / [`Shell`](https://pkg.go.dev/github.com/bitfield/script#Pipe.Shell) supersede `Exec` (thanks [Dhanalakshmi-D04](https://github.com/Dhanalakshmi-D04)) |
| | [`WithContext`](https://pkg.go.dev/github.com/bitfield/script#Pipe.WithContext) (thanks [billvamva](https://github.com/billvamva)) |
Expand Down
14 changes: 13 additions & 1 deletion script.go
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,18 @@ type ReadAutoCloser struct {
r io.ReadCloser
}

// onceCloser makes Close safe to call more than once.
type onceCloser struct {
io.ReadCloser
once sync.Once
err error
}

func (c *onceCloser) Close() error {
c.once.Do(func() { c.err = c.ReadCloser.Close() })
return c.err
}

// NewReadAutoCloser returns a [ReadAutoCloser] wrapping the reader r.
func NewReadAutoCloser(r io.Reader) ReadAutoCloser {
if _, ok := r.(io.Closer); !ok {
Expand All @@ -1213,7 +1225,7 @@ func NewReadAutoCloser(r io.Reader) ReadAutoCloser {
// This can never happen, but just in case it does...
panic("internal error: type assertion to io.ReadCloser failed")
}
return ReadAutoCloser{rc}
return ReadAutoCloser{&onceCloser{ReadCloser: rc}}
}

// Close closes ra's reader, returning any resulting error.
Expand Down
33 changes: 33 additions & 0 deletions script_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1029,6 +1029,18 @@ func TestPostPostsToGivenURLUsingPipeAsRequestBody(t *testing.T) {
}
}

func TestPostDoesNotErrorWhenFileAutoClosed(t *testing.T) {
t.Parallel()
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, r.Body)
}))
defer ts.Close()
_, err := script.File("testdata/hello.txt").Post(ts.URL).String()
if err != nil {
t.Fatal(err)
}
}

func TestRejectRegexp_DropsMatchingLinesFromInput(t *testing.T) {
t.Parallel()
input := "hello world"
Expand Down Expand Up @@ -1477,6 +1489,27 @@ func TestReadAutoCloser_ReadsAllDataFromSourceAndClosesItAutomatically(t *testin
}
}

type mockCloser struct {
io.Reader
closed bool
t *testing.T
}

func (mc *mockCloser) Close() error {
if mc.closed {
mc.t.Fatal("source closed twice")
}
mc.closed = true
return nil
}

func TestReadAutoCloser_OnlyClosesSourceOnce(t *testing.T) {
t.Parallel()
acr := script.NewReadAutoCloser(&mockCloser{t: t})
acr.Close()
acr.Close()
}

func TestSliceProducesElementsOfSpecifiedSliceOnePerLine(t *testing.T) {
t.Parallel()
want := "1\n2\n3\n"
Expand Down
Loading