Skip to content

Commit 5b95881

Browse files
committed
cli/streams: Out, In: preserve original os.File when available
Preserve the original *os.File, if available, and add a File() method to return it. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
1 parent 0c0cd42 commit 5b95881

3 files changed

Lines changed: 33 additions & 2 deletions

File tree

cli/streams/in.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package streams
33
import (
44
"errors"
55
"io"
6+
"os"
67

78
"github.com/moby/term"
89
)
@@ -14,7 +15,8 @@ type In struct {
1415
cs commonStream
1516
}
1617

17-
// NewIn returns a new [In] from an [io.ReadCloser].
18+
// NewIn returns a new [In] from an [io.ReadCloser]. If in is an [*os.File],
19+
// a reference is kept to the file, and accessible through [In.File].
1820
func NewIn(in io.ReadCloser) *In {
1921
return &In{
2022
in: in,
@@ -27,6 +29,13 @@ func (i *In) FD() uintptr {
2729
return i.cs.fd
2830
}
2931

32+
// File returns the underlying *os.File if the stream was constructed from one.
33+
// If the stream was created from a non-file (e.g., a pipe, buffer, or wrapper),
34+
// the returned boolean will be false.
35+
func (i *In) File() (*os.File, bool) {
36+
return i.cs.file()
37+
}
38+
3039
// Read implements the [io.Reader] interface.
3140
func (i *In) Read(p []byte) (int, error) {
3241
return i.in.Read(p)

cli/streams/out.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package streams
22

33
import (
44
"io"
5+
"os"
56

67
"github.com/moby/term"
78
)
@@ -14,7 +15,8 @@ type Out struct {
1415
cs commonStream
1516
}
1617

17-
// NewOut returns a new [Out] from an [io.Writer].
18+
// NewOut returns a new [Out] from an [io.Writer]. If out is an [*os.File],
19+
// a reference is kept to the file, and accessible through [Out.File].
1820
func NewOut(out io.Writer) *Out {
1921
return &Out{
2022
out: out,
@@ -27,6 +29,13 @@ func (o *Out) FD() uintptr {
2729
return o.cs.FD()
2830
}
2931

32+
// File returns the underlying *os.File if the stream was constructed from one.
33+
// If the stream was created from a non-file (e.g., a pipe, buffer, or wrapper),
34+
// the returned boolean will be false.
35+
func (o *Out) File() (*os.File, bool) {
36+
return o.cs.file()
37+
}
38+
3039
// Write writes to the output stream.
3140
func (o *Out) Write(p []byte) (int, error) {
3241
return o.out.Write(p)

cli/streams/stream.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
2+
//go:build go1.25
3+
14
package streams
25

36
import (
@@ -8,14 +11,21 @@ import (
811
)
912

1013
func newCommonStream(stream any) commonStream {
14+
var f *os.File
15+
if v, ok := stream.(*os.File); ok {
16+
f = v
17+
}
18+
1119
fd, tty := term.GetFdInfo(stream)
1220
return commonStream{
21+
f: f,
1322
fd: fd,
1423
tty: tty,
1524
}
1625
}
1726

1827
type commonStream struct {
28+
f *os.File
1929
fd uintptr
2030
tty bool
2131
state *term.State
@@ -24,6 +34,9 @@ type commonStream struct {
2434
// FD returns the file descriptor number for this stream.
2535
func (s *commonStream) FD() uintptr { return s.fd }
2636

37+
// file returns the underlying *os.File if the stream was constructed from one.
38+
func (s *commonStream) file() (*os.File, bool) { return s.f, s.f != nil }
39+
2740
// isTerminal returns whether this stream is connected to a terminal.
2841
func (s *commonStream) isTerminal() bool { return s.tty }
2942

0 commit comments

Comments
 (0)