Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cli/golang_runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"fmt"
"os"
"path"
Expand All @@ -21,7 +22,7 @@ func main(){
`

// Run executes the script
func (s *GolangScript) Run() (err error) {
func (s *GolangScript) Run(ctx context.Context) (err error) {
s.Content = strings.ReplaceAll(s.Content, "#!title: "+s.Title, "")

var shellFile string
Expand Down
6 changes: 4 additions & 2 deletions cli/golang_runner_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package cli

import (
"context"
"testing"

"github.com/linuxsuren/http-downloader/pkg/exec"
"github.com/stretchr/testify/assert"
"testing"
)

func TestGolangRunner(t *testing.T) {
Expand Down Expand Up @@ -31,7 +33,7 @@ echo 1`,
},
}
assert.Equal(t, tt.title, shell.GetTitle())
err := shell.Run()
err := shell.Run(context.Background())
assert.Equal(t, tt.hasErr, err != nil)
})
}
Expand Down
3 changes: 2 additions & 1 deletion cli/python_runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"os"
"path"
)
Expand All @@ -11,7 +12,7 @@ type PythonScript struct {
}

// Run executes the script
func (s *PythonScript) Run() (err error) {
func (s *PythonScript) Run(ctx context.Context) (err error) {
var shellFile string
if shellFile, err = writeAsShell(s.Content, s.Dir); err == nil {
if !s.KeepScripts {
Expand Down
6 changes: 4 additions & 2 deletions cli/python_runner_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package cli

import (
"context"
"testing"

"github.com/linuxsuren/http-downloader/pkg/exec"
"github.com/stretchr/testify/assert"
"testing"
)

func TestPythonRunner(t *testing.T) {
Expand Down Expand Up @@ -31,7 +33,7 @@ echo 1`,
},
}
assert.Equal(t, tt.title, shell.GetTitle())
err := shell.Run()
err := shell.Run(context.Background())
assert.Equal(t, tt.hasErr, err != nil)
})
}
Expand Down
67 changes: 42 additions & 25 deletions cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
package cli

import (
"context"
"fmt"
"io"
"os"
"os/signal"
"path"
"path/filepath"
"strings"
Expand All @@ -15,7 +17,7 @@ import (
"github.com/spf13/cobra"
)

// should be inject during the build process
// should be injected during the build process
var version string

// NewRootCommand returns the instance of cobra.Command
Expand All @@ -35,39 +37,42 @@ func NewRootCommand(execer exec.Execer, out io.Writer) (cmd *cobra.Command) {
flags.BoolVarP(&opt.loop, "loop", "", true, "Run the Markdown in loop mode.")
flags.BoolVarP(&opt.keepFilter, "keep-filter", "", true, "Indicate if keep the filter.")
flags.BoolVarP(&opt.keepScripts, "keep-scripts", "", false, "Indicate if keep the temporary scripts.")
flags.IntVarP(&opt.pageSize, "page-size", "", 6, "Number of the select items.")
return
}

func (o *option) runE(cmd *cobra.Command, args []string) (err error) {
scriptRunners := NewScriptRunners()

for _, mdFilePath := range args {
var files []string
if files, err = filepath.Glob(mdFilePath); err != nil {
return
}

for _, file := range files {
if !strings.HasSuffix(file, ".md") {
continue
var scriptRunners ScriptRunners
if scriptRunners, err = o.parseMarkdownRunners(args); err == nil && scriptRunners.Size() > 1 {
for {
if err = o.executeScripts(scriptRunners); err != nil {
_, _ = fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
}
var runners ScriptRunners
if runners, err = o.parseMarkdownRunner(file); err != nil {

if !o.loop {
break
}

scriptRunners = append(scriptRunners, runners...)
}
}
return
}

if scriptRunners.Size() > 1 {
for {
if err = o.executeScripts(scriptRunners); err != nil {
fmt.Fprintln(cmd.ErrOrStderr(), err.Error())
}
func (o *option) parseMarkdownRunners(files []string) (scriptRunners ScriptRunners, err error) {
scriptRunners = NewScriptRunners()

if !o.loop {
break
for _, mdFilePath := range files {
var files []string
if files, err = filepath.Glob(mdFilePath); err == nil {
for _, file := range files {
if !strings.HasSuffix(file, ".md") {
continue
}
var runners ScriptRunners
if runners, err = o.parseMarkdownRunner(file); err != nil {
break
}

scriptRunners = append(scriptRunners, runners...)
}
}
}
Expand Down Expand Up @@ -147,17 +152,23 @@ type option struct {
loop bool
keepFilter bool
keepScripts bool
pageSize int

execer exec.Execer
}

func (o *option) executeScripts(scriptRunners ScriptRunners) (err error) {
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt)

selector := &survey.MultiSelect{
Message: "Choose the code block to run",
Options: scriptRunners.GetTitles(),
}
var titles []string
if err = survey.AskOne(selector, &titles, survey.WithKeepFilter(o.keepFilter)); err != nil {
if err = survey.AskOne(selector, &titles,
survey.WithKeepFilter(o.keepFilter),
survey.WithPageSize(o.pageSize)); err != nil {
return
}

Expand All @@ -167,9 +178,15 @@ func (o *option) executeScripts(scriptRunners ScriptRunners) (err error) {
break
}

ctx, cancel := context.WithCancel(context.Background())
go func() {
<-c
cancel()
}()

if runner := scriptRunners.GetRunner(title); runner == nil {
fmt.Println("cannot found runner:", title)
} else if err = runner.Run(); err != nil {
} else if err = runner.Run(ctx); err != nil {
break
}
}
Expand Down
14 changes: 13 additions & 1 deletion cli/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func TestNewRootCommand(t *testing.T) {
}
}

func TestParseMarkdownRUnner(t *testing.T) {
func TestParseMarkdownRunner(t *testing.T) {
opt := &option{}
runners, err := opt.parseMarkdownRunner("../README.md")
if assert.Nil(t, err) {
Expand All @@ -52,3 +52,15 @@ func TestParseMarkdownRUnner(t *testing.T) {
assert.NotNil(t, runners.GetRunner("Golang Hello World"))
}
}

func TestParseMarkdownRunners(t *testing.T) {
opt := &option{}
runners, err := opt.parseMarkdownRunners([]string{"../README.md"})
if assert.Nil(t, err) {
assert.True(t, len(runners) > 0)
assert.NotNil(t, runners.GetRunner("Variable Input Hello World"))
assert.NotNil(t, runners.GetRunner("Python Hello World"))
assert.NotNil(t, runners.GetRunner("Run long time"))
assert.NotNil(t, runners.GetRunner("Golang Hello World"))
}
}
15 changes: 8 additions & 7 deletions cli/shell_runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"io"
"os"
"path"
Expand All @@ -19,13 +20,8 @@ type ShellScript struct {
}

// Run executes the script
func (s *ShellScript) Run() (err error) {
// handle the break line
breakline := regexp.MustCompile(`\\\n`)
s.Content = breakline.ReplaceAllString(s.Content, "")

whitespaces := regexp.MustCompile(` +`)
s.Content = whitespaces.ReplaceAllString(s.Content, " ")
func (s *ShellScript) Run(ctx context.Context) (err error) {
s.Content = strings.ReplaceAll(s.Content, "\r\n", "\n")

lines := strings.Split(s.Content, "\n")[1:]

Expand Down Expand Up @@ -89,6 +85,11 @@ func (s *ShellScript) runCmdLine(cmdLine, contextDir string, keepScripts bool) (
}

func findPotentialCommands(cmdLine string) (cmds []string) {
// TODO should find a better way to skip EOF part
if strings.Contains(cmdLine, "EOF") {
return
}

lines := strings.Split(cmdLine, "\n")
for _, line := range lines {
line = strings.TrimSpace(line)
Expand Down
8 changes: 7 additions & 1 deletion cli/shell_runner_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"testing"

"github.com/linuxsuren/http-downloader/pkg/exec"
Expand Down Expand Up @@ -41,7 +42,7 @@ echo 1`,
ShellType: tt.shellType,
}
assert.Equal(t, tt.title, shell.GetTitle())
err := shell.Run()
err := shell.Run(context.Background())
assert.Equal(t, tt.hasErr, err != nil)
})
}
Expand Down Expand Up @@ -105,6 +106,11 @@ docker ps`,
name: "with extra whitespace",
cmd: " k3d create cluster",
expect: []string{"k3d"},
}, {
name: "with EOF",
cmd: `EOF
k3d create cluster`,
expect: nil,
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
10 changes: 7 additions & 3 deletions cli/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package cli

import "github.com/linuxsuren/http-downloader/pkg/exec"
import (
"context"

"github.com/linuxsuren/http-downloader/pkg/exec"
)

// Script represents a script object
type Script struct {
Expand All @@ -14,7 +18,7 @@ type Script struct {

// ScriptRunner is the interface of a common runner
type ScriptRunner interface {
Run() error
Run(context.Context) error
GetTitle() string
}

Expand Down Expand Up @@ -54,7 +58,7 @@ func (s ScriptRunners) Size() int {
type QuitRunner struct{}

// Run does nothing
func (r *QuitRunner) Run() error {
func (r *QuitRunner) Run(context.Context) error {
return nil
}

Expand Down
3 changes: 2 additions & 1 deletion cli/types_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"context"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -16,7 +17,7 @@ func TestScriptRunners(t *testing.T) {
quitRunner := runners.GetRunner("Quit")
if assert.NotNil(t, quitRunner) {
assert.Equal(t, "Quit", quitRunner.GetTitle())
assert.Nil(t, quitRunner.Run())
assert.Nil(t, quitRunner.Run(context.Background()))
}
assert.Equal(t, []string{"Quit"}, runners.GetTitles())
}