This repository has been archived by the owner on Feb 18, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 41
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 #287 from CodeNoobKing/feat/ark_deploy
Feat/ark deploy
- Loading branch information
Showing
26 changed files
with
2,142 additions
and
345 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,177 @@ | ||
/** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package cmdutil | ||
|
||
import ( | ||
"bufio" | ||
"context" | ||
"errors" | ||
"os/exec" | ||
"strings" | ||
"sync/atomic" | ||
) | ||
|
||
// Command is a wrapper for executing cmd command | ||
type Command interface { | ||
// Exec execute the command | ||
Exec() error | ||
|
||
// GetCommand return the command | ||
GetCommand() string | ||
|
||
// GetArgs return the args | ||
GetArgs() []string | ||
|
||
// Output return the output of command | ||
Output() <-chan string | ||
|
||
// Wait wait for command to finish | ||
// is stderr is not empty, send an error | ||
Wait() <-chan error | ||
|
||
// GetExitState return the exit state of command | ||
GetExitError() error | ||
|
||
// Kill the command | ||
Kill() error | ||
|
||
// String return the string representation of command | ||
String() string | ||
} | ||
|
||
// BuildCommand return a new Command | ||
func BuildCommand( | ||
ctx context.Context, | ||
cmd string, args ...string) Command { | ||
return BuildCommandWithWorkDir(ctx, "", cmd, args...) | ||
} | ||
|
||
func BuildCommandWithWorkDir( | ||
ctx context.Context, | ||
workdir string, | ||
cmd string, | ||
args ...string) Command { | ||
cancableContext, cancelFunc := context.WithCancel(ctx) | ||
return &command{ | ||
ctx: cancableContext, | ||
cmd: cmd, | ||
workdir: workdir, | ||
args: args, | ||
output: make(chan string, 1), | ||
completeSignal: make(chan error, 1), | ||
cancel: cancelFunc, | ||
} | ||
} | ||
|
||
type command struct { | ||
started *atomic.Bool | ||
ctx context.Context | ||
workdir string | ||
cmd string | ||
args []string | ||
|
||
cancel context.CancelFunc | ||
output chan string | ||
completeSignal chan error | ||
exitState error | ||
} | ||
|
||
func (c *command) String() string { | ||
return c.cmd + " " + strings.Join(c.args, " ") | ||
} | ||
|
||
func (c *command) GetCommand() string { | ||
return c.cmd | ||
} | ||
|
||
func (c *command) GetArgs() []string { | ||
return c.args | ||
} | ||
|
||
func (c *command) GetExitError() error { | ||
return c.exitState | ||
} | ||
|
||
func (c *command) Exec() error { | ||
execCmd := exec.CommandContext(c.ctx, c.cmd, c.args...) | ||
execCmd.Dir = c.workdir | ||
|
||
stdoutpipeline, err := execCmd.StdoutPipe() | ||
|
||
if err != nil { | ||
return err | ||
} | ||
|
||
stderrorPipeline, err := execCmd.StderrPipe() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
closed := &atomic.Bool{} | ||
closed.Store(false) | ||
closeCompleteSignal := func(err error) { | ||
if closed.CompareAndSwap(false, true) { | ||
if err != nil { | ||
c.completeSignal <- err | ||
} | ||
close(c.completeSignal) | ||
} | ||
} | ||
|
||
go func() { | ||
scanner := bufio.NewScanner(stdoutpipeline) | ||
for scanner.Scan() { | ||
c.output <- scanner.Text() | ||
} | ||
close(c.output) | ||
}() | ||
|
||
go func() { | ||
scanner := bufio.NewScanner(stderrorPipeline) | ||
sb := &strings.Builder{} | ||
for scanner.Scan() { | ||
sb.WriteString(scanner.Text()) | ||
sb.WriteString("\n") | ||
} | ||
|
||
if len(sb.String()) != 0 { | ||
closeCompleteSignal(errors.New(sb.String())) | ||
} | ||
}() | ||
|
||
if err := execCmd.Start(); err != nil { | ||
return err | ||
} | ||
|
||
go func() { | ||
c.exitState = execCmd.Wait() | ||
closeCompleteSignal(nil) | ||
}() | ||
|
||
return nil | ||
} | ||
|
||
func (c *command) Wait() <-chan error { | ||
return c.completeSignal | ||
} | ||
|
||
func (c *command) Kill() error { | ||
c.cancel() | ||
return nil | ||
} | ||
|
||
func (c *command) Output() <-chan string { | ||
return c.output | ||
} |
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,79 @@ | ||
/** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package cmdutil | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"strings" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestCommand_HappyPath(t *testing.T) { | ||
// ls command is available in most platform | ||
cmd := BuildCommand(context.Background(), "ls", "-l") | ||
|
||
err := cmd.Exec() | ||
assert.Nil(t, err) | ||
|
||
output := cmd.Output() | ||
containsCurFile := false | ||
for line := range output { | ||
fmt.Println(line) | ||
containsCurFile = containsCurFile || strings.Contains(line, "cmd_util_test.go") | ||
} | ||
assert.True(t, containsCurFile) | ||
|
||
for err := range cmd.Wait() { | ||
assert.Nil(t, err) | ||
} | ||
|
||
err = cmd.Kill() | ||
assert.Nil(t, err) | ||
} | ||
|
||
func TestCommand_StdErr(t *testing.T) { | ||
cmd := BuildCommand(context.Background(), "ls", "-l", "/not/exist/path") | ||
|
||
err := cmd.Exec() | ||
assert.Nil(t, err) | ||
|
||
output := cmd.Output() | ||
hasStdout := false | ||
for _ = range output { | ||
hasStdout = true | ||
} | ||
assert.False(t, hasStdout) | ||
|
||
for err := range cmd.Wait() { | ||
assert.NotNil(t, err) | ||
assert.True(t, len(err.Error()) != 0) | ||
} | ||
|
||
err = cmd.Kill() | ||
assert.Nil(t, err) | ||
|
||
err = cmd.GetExitError() | ||
assert.Nil(t, err) | ||
} | ||
|
||
func TestCommand_WrongCommannd(t *testing.T) { | ||
cmd := BuildCommand(context.Background(), "not_exist_command") | ||
err := cmd.Exec() | ||
assert.NotNil(t, err) | ||
assert.True(t, len(err.Error()) != 0) | ||
} |
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,15 @@ | ||
/** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package cmdutil |
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,52 @@ | ||
/** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package contextutil | ||
|
||
import "golang.org/x/net/context" | ||
|
||
type Context struct { | ||
context.Context | ||
value map[interface{}]interface{} | ||
} | ||
|
||
// NewContext return a new Context | ||
func NewContext(ctx context.Context) *Context { | ||
return &Context{ | ||
Context: ctx, | ||
value: make(map[interface{}]interface{}), | ||
} | ||
} | ||
|
||
// Put add kv to current context | ||
func (ctx *Context) Put(key, value interface{}) context.Context { | ||
if ctx.value == nil { | ||
ctx.value = make(map[interface{}]interface{}) | ||
} | ||
ctx.value[key] = value | ||
return ctx | ||
} | ||
|
||
// Value get value from context | ||
func (ctx *Context) Value(key interface{}) interface{} { | ||
if ctx.value == nil { | ||
return ctx.Context.Value(key) | ||
} | ||
|
||
value, ok := ctx.value[key] | ||
if !ok { | ||
return ctx.Context.Value(key) | ||
} | ||
return value | ||
} |
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,36 @@ | ||
/** | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package contextutil | ||
|
||
import ( | ||
"context" | ||
"github.com/sirupsen/logrus" | ||
) | ||
|
||
var ( | ||
enableLogger = true | ||
) | ||
|
||
func DisableLogger() { | ||
enableLogger = false | ||
} | ||
|
||
func GetLogger(ctx context.Context) logrus.FieldLogger { | ||
logger := logrus.WithContext(ctx) | ||
if !enableLogger { | ||
logger.Logger.Level = logrus.FatalLevel | ||
} | ||
return logger | ||
} |
Oops, something went wrong.