-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial stage implementation
- Loading branch information
Showing
7 changed files
with
322 additions
and
18 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
package stage | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"time" | ||
|
||
"github.com/hazelcast/hazelcast-commandline-client/clc" | ||
"github.com/hazelcast/hazelcast-commandline-client/internal" | ||
"github.com/hazelcast/hazelcast-commandline-client/internal/plug" | ||
"github.com/hazelcast/hazelcast-commandline-client/internal/str" | ||
) | ||
|
||
type Statuser interface { | ||
SetProgress(progress float32) | ||
SetRemainingDuration(dur time.Duration) | ||
} | ||
|
||
type basicStatuser struct { | ||
text string | ||
textFmtWithRemaining string | ||
indexText string | ||
sp clc.Spinner | ||
} | ||
|
||
func (s *basicStatuser) SetProgress(progress float32) { | ||
s.sp.SetProgress(progress) | ||
} | ||
|
||
func (s *basicStatuser) SetRemainingDuration(dur time.Duration) { | ||
text := s.text | ||
if dur > 0 { | ||
text = fmt.Sprintf(s.textFmtWithRemaining, dur) | ||
} | ||
s.sp.SetText(s.indexText + " " + text) | ||
} | ||
|
||
type Stage struct { | ||
ProgressMsg string | ||
SuccessMsg string | ||
FailureMsg string | ||
Func func(status Statuser) error | ||
} | ||
|
||
type Provider internal.Iterator[Stage] | ||
|
||
type Counter interface { | ||
StageCount() int | ||
} | ||
|
||
type FixedProvider struct { | ||
stages []Stage | ||
offset int | ||
current Stage | ||
err error | ||
} | ||
|
||
func NewFixedProvider(stages ...Stage) *FixedProvider { | ||
return &FixedProvider{stages: stages} | ||
} | ||
|
||
func (sp *FixedProvider) Next() bool { | ||
if sp.offset >= len(sp.stages) { | ||
return false | ||
} | ||
sp.current = sp.stages[sp.offset] | ||
sp.offset++ | ||
return true | ||
} | ||
|
||
func (sp *FixedProvider) Value() Stage { | ||
return sp.current | ||
} | ||
|
||
func (sp *FixedProvider) Err() error { | ||
return sp.err | ||
} | ||
|
||
func (sp *FixedProvider) StageCount() int { | ||
return len(sp.stages) | ||
} | ||
|
||
func Execute(ctx context.Context, ec plug.ExecContext, sp Provider) error { | ||
ss := &basicStatuser{} | ||
var index int | ||
var stageCount int | ||
if sc, ok := sp.(Counter); ok { | ||
stageCount = sc.StageCount() | ||
} | ||
for sp.Next() { | ||
if sp.Err() != nil { | ||
return sp.Err() | ||
} | ||
stg := sp.Value() | ||
index++ | ||
ss.text = stg.ProgressMsg | ||
ss.textFmtWithRemaining = stg.ProgressMsg + " (%s left)" | ||
if stageCount > 0 { | ||
d := str.SpacePaddedIntFormat(stageCount) | ||
ss.indexText = fmt.Sprintf("["+d+"/%d]", index, stageCount) | ||
} else { | ||
ss.indexText = "" | ||
} | ||
_, stop, err := ec.ExecuteBlocking(ctx, func(ctx context.Context, spinner clc.Spinner) (any, error) { | ||
ss.sp = spinner | ||
ss.SetRemainingDuration(0) | ||
return nil, stg.Func(ss) | ||
}) | ||
if err != nil { | ||
ec.PrintlnUnnecessary(fmt.Sprintf("FAIL %s: %s", stg.FailureMsg, err.Error())) | ||
return err | ||
} | ||
stop() | ||
ec.PrintlnUnnecessary(fmt.Sprintf("OK %s %s.", ss.indexText, stg.SuccessMsg)) | ||
} | ||
return nil | ||
} |
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,97 @@ | ||
package stage_test | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
"time" | ||
|
||
"github.com/stretchr/testify/assert" | ||
|
||
"github.com/hazelcast/hazelcast-commandline-client/clc/ux/stage" | ||
"github.com/hazelcast/hazelcast-commandline-client/internal/it" | ||
) | ||
|
||
func TestExecute(t *testing.T) { | ||
stages := []stage.Stage{ | ||
{ | ||
ProgressMsg: "Progressing 1", | ||
SuccessMsg: "Success 1", | ||
FailureMsg: "Failure 1", | ||
Func: func(status stage.Statuser) error { | ||
time.Sleep(1 * time.Millisecond) | ||
return nil | ||
}, | ||
}, | ||
{ | ||
ProgressMsg: "Progressing 2", | ||
SuccessMsg: "Success 2", | ||
FailureMsg: "Failure 2", | ||
Func: func(status stage.Statuser) error { | ||
for i := 0; i < 5; i++ { | ||
status.SetProgress(float32(i+1) / float32(5)) | ||
} | ||
time.Sleep(1 * time.Millisecond) | ||
return nil | ||
}, | ||
}, | ||
{ | ||
ProgressMsg: "Progressing 3", | ||
SuccessMsg: "Success 3", | ||
FailureMsg: "Failure 3", | ||
Func: func(status stage.Statuser) error { | ||
for i := 0; i < 5; i++ { | ||
status.SetRemainingDuration(5*time.Second - time.Duration(i+1)*time.Second) | ||
} | ||
time.Sleep(1 * time.Millisecond) | ||
return nil | ||
}, | ||
}, | ||
} | ||
ec := it.NewExecuteContext(nil) | ||
err := stage.Execute(context.TODO(), ec, stage.NewFixedProvider(stages...)) | ||
assert.NoError(t, err) | ||
texts := []string{ | ||
"[1/3] Progressing 1", | ||
"[2/3] Progressing 2", | ||
"[3/3] Progressing 3", | ||
"[3/3] Progressing 3 (4s left)", | ||
"[3/3] Progressing 3 (3s left)", | ||
"[3/3] Progressing 3 (2s left)", | ||
"[3/3] Progressing 3 (1s left)", | ||
"[3/3] Progressing 3", | ||
} | ||
assert.Equal(t, texts, ec.Spinner.Texts) | ||
progresses := []float32{0.2, 0.4, 0.6, 0.8, 1} | ||
assert.Equal(t, progresses, ec.Spinner.Progresses) | ||
text := "OK [1/3] Success 1.\nOK [2/3] Success 2.\nOK [3/3] Success 3.\n" | ||
assert.Equal(t, text, ec.StdoutText()) | ||
} | ||
|
||
func TestExecute_WithFailure(t *testing.T) { | ||
stages := []stage.Stage{ | ||
{ | ||
ProgressMsg: "Progressing 1", | ||
SuccessMsg: "Success 1", | ||
FailureMsg: "Failure 1", | ||
Func: func(status stage.Statuser) error { | ||
return fmt.Errorf("some error") | ||
}, | ||
}, | ||
{ | ||
ProgressMsg: "Progressing 2", | ||
SuccessMsg: "Success 2", | ||
FailureMsg: "Failure 2", | ||
Func: func(status stage.Statuser) error { | ||
return nil | ||
}, | ||
}, | ||
} | ||
ec := it.NewExecuteContext(nil) | ||
err := stage.Execute(context.TODO(), ec, stage.NewFixedProvider(stages...)) | ||
assert.Error(t, err) | ||
texts := []string{"[1/2] Progressing 1"} | ||
assert.Equal(t, texts, ec.Spinner.Texts) | ||
text := "FAIL Failure 1: some error\n" | ||
assert.Equal(t, text, ec.StdoutText()) | ||
} |
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 |
---|---|---|
@@ -0,0 +1,17 @@ | ||
package internal | ||
|
||
// Iterator is a generic iterator interface. | ||
// Non thread safe. | ||
type Iterator[T any] interface { | ||
// Next returns false if the iterator is exhausted. | ||
// Otherwise advances the iterator and returns true. | ||
Next() bool | ||
// Value returns the current value in the iterator. | ||
// Next should always be called before Value is called. | ||
// Otherwise may panic. | ||
Value() T | ||
// Err contains the error after advancing the iterator. | ||
// If it is nil, it is safe to call Next. | ||
// Otherwise Next should not be called. | ||
Err() error | ||
} |
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.