Skip to content

Commit

Permalink
Apply fixes after review
Browse files Browse the repository at this point in the history
  • Loading branch information
mszostok committed Jul 5, 2023
1 parent bb9ae86 commit b9aa6e7
Show file tree
Hide file tree
Showing 7 changed files with 94 additions and 48 deletions.
25 changes: 21 additions & 4 deletions cmd/executor/x/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/sirupsen/logrus"

"github.com/kubeshop/botkube/internal/executor/x"
"github.com/kubeshop/botkube/internal/executor/x/getter"
"github.com/kubeshop/botkube/internal/executor/x/output"
"github.com/kubeshop/botkube/internal/executor/x/state"
"github.com/kubeshop/botkube/internal/loggerx"
Expand Down Expand Up @@ -98,7 +99,11 @@ func (i *XExecutor) Execute(ctx context.Context, in executor.ExecuteInput) (exec
return executor.ExecuteOutput{}, fmt.Errorf("while parsing input command: %w", err)
}

var cfg x.Config
cfg := x.Config{
Templates: []getter.Source{
{Ref: getDefaultTemplateSource()},
},
}
if err := pluginx.MergeExecutorConfigs(in.Configs, &cfg); err != nil {
return executor.ExecuteOutput{}, err
}
Expand Down Expand Up @@ -186,17 +191,21 @@ func jsonSchema() api.JSONSchema {
Value: heredoc.Docf(`{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "x",
"description": "Install and run CLIs directly from chat window without hassle. All magic included.",
"description": "Install and run CLIs directly from the chat window without hassle. All magic included.",
"type": "object",
"properties": {
"templates": {
"type": "array",
"title": "List of templates",
"description": "An array of templates that define how to convert the command output into an interactive message.",
"items": {
"type": "object",
"properties": {
"ref": {
"title": "Link to templates source",
"description": "It uses the go-getter library, which supports multiple URL formats (such as HTTP, Git repositories, or S3) and is able to unpack archives. For more details, see the documentation at https://github.com/hashicorp/go-getter.",
"type": "string",
"default": "github.com/mszostok/botkube-plugins//x-templates?ref=hackathon"
"default": ""
}
},
"required": [
Expand All @@ -209,8 +218,16 @@ func jsonSchema() api.JSONSchema {
"required": [
"templates"
]
}`),
}`, getDefaultTemplateSource()),
}
}

func getDefaultTemplateSource() string {
ver := version
if ver == "dev" {
ver = "main"
}
return fmt.Sprintf("github.com/kubeshop/botkube//cmd/executor/x/templates?ref=%s", ver)
}

func Normalize(in string) string {
Expand Down
2 changes: 0 additions & 2 deletions internal/executor/x/getter/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"crypto/sha256"
"encoding/base64"
"fmt"
"os"
"path/filepath"
)
Expand Down Expand Up @@ -37,7 +36,6 @@ func runIfFileDoesNotExist(path string, fn func() error) error {
_, err := os.Stat(path)
switch {
case err == nil:
fmt.Println("already downloaded")
case os.IsNotExist(err):
return fn()
default:
Expand Down
38 changes: 0 additions & 38 deletions internal/executor/x/getter/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,41 +55,3 @@ func Load[T any](ctx context.Context, tmpDir string, templateSources []Source) (

return out, nil
}

// symwalkFunc calls the provided WalkFn for regular files.
// However, when it encounters a symbolic link, it resolves the link fully using the
// filepath.EvalSymlinks function and recursively calls symwalk.Walk on the resolved path.
// This ensures that unlink filepath.Walk, traversal does not stop at symbolic links.
//
// Note that symwalk.Walk does not terminate if there are any non-terminating loops in
// the file structure.
func walk(filename string, linkDirname string, walkFn fs.WalkDirFunc) error {
return filepath.WalkDir(filename, func(path string, d fs.DirEntry, err error) error {
if fname, err := filepath.Rel(filename, path); err == nil {
path = filepath.Join(linkDirname, fname)
} else {
return err
}

if err == nil && d.Type()&os.ModeSymlink == os.ModeSymlink {
finalPath, err := filepath.EvalSymlinks(path)
if err != nil {
return err
}
info, err := os.Lstat(finalPath)
if err != nil {
return walkFn(path, d, err)
}
if info.IsDir() {
return walk(finalPath, path, walkFn)
}
}

return walkFn(path, d, err)
})
}

// Walk extends filepath.Walk to also follow symlinks
func Walk(path string, walkFn fs.WalkDirFunc) error {
return walk(path, path, walkFn)
}
53 changes: 53 additions & 0 deletions internal/executor/x/getter/walk.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Package getter.
//
// Code copied from: https://github.com/facebookarchive/symwalk/blob/42004b9f322246749dd73ad71008b1f3160c0052/walk.go#L12-L45
// BSD License
//
// # For symwalk software
//
// Copyright (c) 2015, Facebook, Inc. All rights reserved.
package getter

import (
"io/fs"
"os"
"path/filepath"
)

// symwalkFunc calls the provided WalkFn for regular files.
// However, when it encounters a symbolic link, it resolves the link fully using the
// filepath.EvalSymlinks function and recursively calls symwalk.Walk on the resolved path.
// This ensures that unlink filepath.Walk, traversal does not stop at symbolic links.
//
// Note that symwalk.Walk does not terminate if there are any non-terminating loops in
// the file structure.
func walk(filename string, linkDirname string, walkFn fs.WalkDirFunc) error {
return filepath.WalkDir(filename, func(path string, d fs.DirEntry, err error) error {
if fname, err := filepath.Rel(filename, path); err == nil {
path = filepath.Join(linkDirname, fname)
} else {
return err
}

if err == nil && d.Type()&os.ModeSymlink == os.ModeSymlink {
finalPath, err := filepath.EvalSymlinks(path)
if err != nil {
return err
}
info, err := os.Lstat(finalPath)
if err != nil {
return walkFn(path, d, err)
}
if info.IsDir() {
return walk(finalPath, path, walkFn)
}
}

return walkFn(path, d, err)
})
}

// Walk extends filepath.Walk to also follow symlinks
func Walk(path string, walkFn fs.WalkDirFunc) error {
return walk(path, path, walkFn)
}
9 changes: 6 additions & 3 deletions internal/executor/x/output/message_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func (p *TableCommandParser) renderActions(msgCtx template.ParseMessage, table p

return api.Section{
Buttons: []api.Button{
btnBuilder.ForCommandWithoutDesc("Raw output", fmt.Sprintf("x run %s %s", cmd, x.RawOutputIndicator)),
btnBuilder.ForCommand("Raw output", fmt.Sprintf("x run %s %s", cmd, x.RawOutputIndicator)),
},
Selects: api.Selects{
Items: []api.Select{
Expand Down Expand Up @@ -244,14 +244,17 @@ func (*TableCommandParser) resolveSelectIdx(state *state.Container, selectID str
return val
}

func (*TableCommandParser) renderGoTemplate(tpl string, cols, rows []string) (string, error) {
func (p *TableCommandParser) renderGoTemplate(tpl string, cols, rows []string) (string, error) {
data := map[string]string{}
for idx, col := range cols {
col = xstrings.ToCamelCase(strings.ToLower(col))
data[col] = rows[idx]
}

fmt.Println(data)
p.log.WithFields(logrus.Fields{
"tpl": tpl,
"data": data,
}).Debug("Rendering Go template")

tmpl, err := gotemplate.New("tpl").Parse(tpl)
if err != nil {
Expand Down
3 changes: 2 additions & 1 deletion internal/plugin/tmp_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package plugin

import (
"os"
"path"
)

type TmpDir string
Expand All @@ -16,7 +17,7 @@ func (t TmpDir) Get() (string, bool) {
return depDir, false
}

return "/tmp/bin", true
return path.Join(os.TempDir(), "bin"), true
}

func (t TmpDir) GetDirectory() string {
Expand Down
12 changes: 12 additions & 0 deletions pkg/pluginx/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,18 @@ type ExecuteCommandOutput struct {
ExitCode int
}

// ExecuteCommandWithEnvs is a simple wrapper around exec.CommandContext to simplify running a given
// command.
//
// Deprecated: Use ExecuteCommand(ctx, rawCmd, ExecuteCommandEnvs(envs)) instead.
func ExecuteCommandWithEnvs(ctx context.Context, rawCmd string, envs map[string]string) (string, error) {
out, err := ExecuteCommand(ctx, rawCmd, ExecuteCommandEnvs(envs))
if err != nil {
return "", err
}
return out.Stdout, nil
}

// ExecuteCommand is a simple wrapper around exec.CommandContext to simplify running a given command.
func ExecuteCommand(ctx context.Context, rawCmd string, mutators ...ExecuteCommandMutation) (ExecuteCommandOutput, error) {
opts := ExecuteCommandOptions{
Expand Down

0 comments on commit b9aa6e7

Please sign in to comment.