forked from hashicorp/go-getter
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request hashicorp#133 from hashicorp/gracefull_termination
Gracefull (context) cancellation
- Loading branch information
Showing
13 changed files
with
225 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,20 @@ | ||
package getter | ||
|
||
import "context" | ||
|
||
// getter is our base getter; it regroups | ||
// fields all getters have in common. | ||
type getter struct { | ||
client *Client | ||
} | ||
|
||
func (g *getter) SetClient(c *Client) { g.client = c } | ||
|
||
// Context tries to returns the Contex from the getter's | ||
// client. otherwise context.Background() is returned. | ||
func (g *getter) Context() context.Context { | ||
if g == nil || g.client == nil { | ||
return context.Background() | ||
} | ||
return g.client.Ctx | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package getter | ||
|
||
import ( | ||
"context" | ||
"io" | ||
) | ||
|
||
// readerFunc is syntactic sugar for read interface. | ||
type readerFunc func(p []byte) (n int, err error) | ||
|
||
func (rf readerFunc) Read(p []byte) (n int, err error) { return rf(p) } | ||
|
||
// Copy is a io.Copy cancellable by context | ||
func Copy(ctx context.Context, dst io.Writer, src io.Reader) (int64, error) { | ||
// Copy will call the Reader and Writer interface multiple time, in order | ||
// to copy by chunk (avoiding loading the whole file in memory). | ||
return io.Copy(dst, readerFunc(func(p []byte) (int, error) { | ||
|
||
select { | ||
case <-ctx.Done(): | ||
// context has been canceled | ||
// stop process and propagate "context canceled" error | ||
return 0, ctx.Err() | ||
default: | ||
// otherwise just run default io.Reader implementation | ||
return src.Read(p) | ||
} | ||
})) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package getter | ||
|
||
import ( | ||
"bytes" | ||
"context" | ||
"io" | ||
"testing" | ||
"time" | ||
) | ||
|
||
// OneDoneContext is a context that is | ||
// cancelled after a first done is called. | ||
type OneDoneContext bool | ||
|
||
func (*OneDoneContext) Deadline() (deadline time.Time, ok bool) { return } | ||
func (*OneDoneContext) Value(key interface{}) interface{} { return nil } | ||
|
||
func (o *OneDoneContext) Err() error { | ||
if *o == false { | ||
return nil | ||
} | ||
return context.Canceled | ||
} | ||
|
||
func (o *OneDoneContext) Done() <-chan struct{} { | ||
if *o == false { | ||
*o = true | ||
return nil | ||
} | ||
c := make(chan struct{}) | ||
close(c) | ||
return c | ||
} | ||
|
||
func (o *OneDoneContext) String() string { | ||
if *o { | ||
return "done OneDoneContext" | ||
} | ||
return "OneDoneContext" | ||
} | ||
|
||
func TestCopy(t *testing.T) { | ||
const text3lines = `line1 | ||
line2 | ||
line3 | ||
` | ||
|
||
cancelledContext, cancel := context.WithCancel(context.Background()) | ||
_ = cancelledContext | ||
cancel() | ||
type args struct { | ||
ctx context.Context | ||
src io.Reader | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want int64 | ||
wantDst string | ||
wantErr error | ||
}{ | ||
{"read all", args{context.Background(), bytes.NewBufferString(text3lines)}, int64(len(text3lines)), text3lines, nil}, | ||
{"read none", args{cancelledContext, bytes.NewBufferString(text3lines)}, 0, "", context.Canceled}, | ||
{"cancel after read", args{new(OneDoneContext), bytes.NewBufferString(text3lines)}, int64(len(text3lines)), text3lines, context.Canceled}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
dst := &bytes.Buffer{} | ||
got, err := Copy(tt.args.ctx, dst, tt.args.src) | ||
if err != tt.wantErr { | ||
t.Errorf("Copy() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if got != tt.want { | ||
t.Errorf("Copy() = %v, want %v", got, tt.want) | ||
} | ||
if gotDst := dst.String(); gotDst != tt.wantDst { | ||
t.Errorf("Copy() = %v, want %v", gotDst, tt.wantDst) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.