mirror of
https://github.com/TECHNOFAB11/powerproto.git
synced 2025-12-12 08:00:04 +01:00
init
Signed-off-by: storyicon <yuanchao@bilibili.com>
This commit is contained in:
commit
9aac714c32
47 changed files with 5480 additions and 0 deletions
31
pkg/component/actionmanager/actions/actions.go
Normal file
31
pkg/component/actionmanager/actions/actions.go
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// CommonOptions is common options of action
|
||||
type CommonOptions struct {
|
||||
ConfigFilePath string
|
||||
}
|
||||
|
||||
// ActionFunc defines the common prototype of action func
|
||||
type ActionFunc func(ctx context.Context,
|
||||
log logger.Logger,
|
||||
args []string, options *CommonOptions) error
|
||||
64
pkg/component/actionmanager/actions/copy.go
Normal file
64
pkg/component/actionmanager/actions/copy.go
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionCopy is used to copy directory or file from src to dest
|
||||
// Its args prototype is:
|
||||
// args: (src string, dest string)
|
||||
func ActionCopy(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
if len(args) != 2 || util.ContainsEmpty(args...) {
|
||||
return errors.Errorf("expected length of args is 3, but received %d", len(args))
|
||||
}
|
||||
var (
|
||||
source = args[0]
|
||||
destination = args[1]
|
||||
path = filepath.Dir(options.ConfigFilePath)
|
||||
absSource = filepath.Join(path, source)
|
||||
absDestination = filepath.Join(path, destination)
|
||||
)
|
||||
|
||||
if filepath.IsAbs(source) {
|
||||
return errors.Errorf("absolute source %s is not allowed in action move", source)
|
||||
}
|
||||
|
||||
if filepath.IsAbs(destination) {
|
||||
return errors.Errorf("absolute destination %s is not allowed in action move", destination)
|
||||
}
|
||||
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "copy",
|
||||
"from": absSource,
|
||||
"to": absDestination,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := util.CopyDirectory(absSource, absDestination); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
68
pkg/component/actionmanager/actions/move.go
Normal file
68
pkg/component/actionmanager/actions/move.go
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionMove is used to move directory or file from src to dest
|
||||
// Its args prototype is:
|
||||
// args: (src string, dest string)
|
||||
func ActionMove(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
if len(args) != 2 || util.ContainsEmpty(args...) {
|
||||
return errors.Errorf("expected length of args is 3, but received %d", len(args))
|
||||
}
|
||||
var (
|
||||
source = args[0]
|
||||
destination = args[1]
|
||||
path = filepath.Dir(options.ConfigFilePath)
|
||||
absSource = filepath.Join(path, source)
|
||||
absDestination = filepath.Join(path, destination)
|
||||
)
|
||||
|
||||
if filepath.IsAbs(source) {
|
||||
return errors.Errorf("absolute source %s is not allowed in action move", source)
|
||||
}
|
||||
|
||||
if filepath.IsAbs(destination) {
|
||||
return errors.Errorf("absolute destination %s is not allowed in action move", destination)
|
||||
}
|
||||
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "move",
|
||||
"from": absSource,
|
||||
"to": absDestination,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := util.CopyDirectory(absSource, absDestination); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.RemoveAll(absSource); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
51
pkg/component/actionmanager/actions/remove.go
Normal file
51
pkg/component/actionmanager/actions/remove.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actions
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionRemove is used to delete directories or files
|
||||
// Its args prototype is:
|
||||
// args: (path ...string)
|
||||
func ActionRemove(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
for _, arg := range args {
|
||||
if filepath.IsAbs(arg) {
|
||||
return errors.Errorf("absolute path %s is not allowed in action remove", arg)
|
||||
}
|
||||
path := filepath.Join(filepath.Dir(options.ConfigFilePath), arg)
|
||||
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "remove",
|
||||
"target": path,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.RemoveAll(path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
80
pkg/component/actionmanager/actions/replace.go
Normal file
80
pkg/component/actionmanager/actions/replace.go
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actions
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"io/fs"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionReplace is used to replace text in bulk
|
||||
// Its args prototype is:
|
||||
// args: (pattern string, from string, to string)
|
||||
// pattern is used to match files
|
||||
func ActionReplace(ctx context.Context, log logger.Logger, args []string, options *CommonOptions) error {
|
||||
if len(args) != 3 {
|
||||
return errors.Errorf("expected length of args is 3, but received %d", len(args))
|
||||
}
|
||||
var (
|
||||
pattern = args[0]
|
||||
path = filepath.Dir(options.ConfigFilePath)
|
||||
from = args[1]
|
||||
to = args[2]
|
||||
)
|
||||
|
||||
if pattern == "" || from == "" {
|
||||
return errors.Errorf("pattern and from arguments in action replace can not be empty")
|
||||
}
|
||||
if filepath.IsAbs(pattern) {
|
||||
return errors.Errorf("absolute path %s is not allowed in action replace", pattern)
|
||||
}
|
||||
pattern = filepath.Join(path, pattern)
|
||||
return filepath.Walk(path, func(path string, info fs.FileInfo, err error) error {
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
matched, err := util.MatchPath(pattern, path)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if matched {
|
||||
if command.IsDryRun(ctx) {
|
||||
log.LogInfo(map[string]interface{}{
|
||||
"action": "replace",
|
||||
"file": path,
|
||||
"from": from,
|
||||
"to": to,
|
||||
}, "DryRun")
|
||||
return nil
|
||||
}
|
||||
data, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data = bytes.ReplaceAll(data, []byte(from), []byte(to))
|
||||
return ioutil.WriteFile(path, data, fs.ModePerm)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
42
pkg/component/actionmanager/errors.go
Normal file
42
pkg/component/actionmanager/errors.go
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actionmanager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
)
|
||||
|
||||
// ErrPostShell defines the post shell command error
|
||||
type ErrPostShell struct {
|
||||
Path string
|
||||
*command.ErrCommandExec
|
||||
}
|
||||
|
||||
// ErrPostAction defines the post action error
|
||||
type ErrPostAction struct {
|
||||
Path string
|
||||
Name string
|
||||
Arguments []string
|
||||
Err error
|
||||
}
|
||||
|
||||
// Error implements the standard error interface
|
||||
func (err *ErrPostAction) Error() string {
|
||||
return fmt.Sprintf("failed to execute action: %s, path: %s, arguments: %s, err: %s",
|
||||
err.Name, err.Path, err.Arguments, err.Err,
|
||||
)
|
||||
}
|
||||
100
pkg/component/actionmanager/manager.go
Normal file
100
pkg/component/actionmanager/manager.go
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
// Copyright 2021 storyicon@foxmail.com
|
||||
//
|
||||
// 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 actionmanager
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/storyicon/powerproto/pkg/component/actionmanager/actions"
|
||||
"github.com/storyicon/powerproto/pkg/configs"
|
||||
"github.com/storyicon/powerproto/pkg/util/command"
|
||||
"github.com/storyicon/powerproto/pkg/util/logger"
|
||||
)
|
||||
|
||||
// ActionManager is used to manage actions
|
||||
type ActionManager interface {
|
||||
// ExecutePostShell is used to execute post shell in config item
|
||||
ExecutePostShell(ctx context.Context, config configs.ConfigItem) error
|
||||
// ExecutePostAction is used to execute post action in config item
|
||||
ExecutePostAction(ctx context.Context, config configs.ConfigItem) error
|
||||
}
|
||||
|
||||
// BasicActionManager is a basic implement of ActionManager
|
||||
type BasicActionManager struct {
|
||||
logger.Logger
|
||||
|
||||
// map[string]ActionFunc
|
||||
actions map[string]actions.ActionFunc
|
||||
}
|
||||
|
||||
// NewActionManager is used to create action manager
|
||||
func NewActionManager(log logger.Logger) (ActionManager, error) {
|
||||
return NewBasicActionManager(log)
|
||||
}
|
||||
|
||||
// NewBasicActionManager is used to create a BasicActionManager
|
||||
func NewBasicActionManager(log logger.Logger) (*BasicActionManager, error) {
|
||||
return &BasicActionManager{
|
||||
Logger: log.NewLogger("actionmanager"),
|
||||
actions: map[string]actions.ActionFunc{
|
||||
"move": actions.ActionMove,
|
||||
"replace": actions.ActionReplace,
|
||||
"remove": actions.ActionRemove,
|
||||
"copy": actions.ActionCopy,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ExecutePostShell is used to execute post shell in config item
|
||||
func (m *BasicActionManager) ExecutePostShell(ctx context.Context, config configs.ConfigItem) error {
|
||||
script := config.Config().PostShell
|
||||
if script == "" {
|
||||
return nil
|
||||
}
|
||||
dir := filepath.Dir(config.Path())
|
||||
_, err := command.Execute(ctx, m.Logger, dir, "/bin/sh", []string{
|
||||
"-c", script,
|
||||
}, nil)
|
||||
if err != nil {
|
||||
return &ErrPostShell{
|
||||
Path: config.Path(),
|
||||
ErrCommandExec: err,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExecutePostAction is used to execute post action in config item
|
||||
func (m *BasicActionManager) ExecutePostAction(ctx context.Context, config configs.ConfigItem) error {
|
||||
for _, action := range config.Config().PostActions {
|
||||
actionFunc, ok := m.actions[action.Name]
|
||||
if !ok {
|
||||
return fmt.Errorf("unknown action: %s", action.Name)
|
||||
}
|
||||
if err := actionFunc(ctx, m.Logger, action.Args, &actions.CommonOptions{
|
||||
ConfigFilePath: config.Path(),
|
||||
}); err != nil {
|
||||
return &ErrPostAction{
|
||||
Path: config.Path(),
|
||||
Name: action.Name,
|
||||
Arguments: action.Args,
|
||||
Err: err,
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue