mirror of
https://github.com/maaslalani/slides.git
synced 2026-01-10 06:48:01 -05:00
feat: multiple code execute commands; rust code support (#104)
This commit is contained in:
@@ -5,7 +5,9 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -88,21 +90,54 @@ func Execute(code Block) Result {
|
||||
}
|
||||
}
|
||||
|
||||
cmd := exec.Command(language.Command[0], append(language.Command[1:], f.Name())...)
|
||||
var (
|
||||
output strings.Builder
|
||||
exitCode int
|
||||
)
|
||||
|
||||
// replacer for commands
|
||||
repl := strings.NewReplacer(
|
||||
"<file>", f.Name(),
|
||||
// <name>: file name without extension and without path
|
||||
"<name>", filepath.Base(strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))),
|
||||
"<path>", filepath.Dir(f.Name()),
|
||||
)
|
||||
|
||||
// For accuracy of program execution speed, we can't put anything after
|
||||
// recording the start time or before recording the end time.
|
||||
start := time.Now()
|
||||
out, err := cmd.Output()
|
||||
end := time.Now()
|
||||
|
||||
exitCode := 0
|
||||
if err != nil {
|
||||
exitCode = 1
|
||||
var cmds multi
|
||||
|
||||
switch t := language.Cmds.(type) {
|
||||
case base:
|
||||
cmds = multi{append(t, "<file>")}
|
||||
case single:
|
||||
cmds = multi{t}
|
||||
case multi:
|
||||
cmds = t
|
||||
}
|
||||
|
||||
for _, c := range cmds {
|
||||
// replace <file>, <name> and <path> in commands
|
||||
for i, v := range c {
|
||||
c[i] = repl.Replace(v)
|
||||
}
|
||||
// execute and write output
|
||||
cmd := exec.Command(c[0], c[1:]...)
|
||||
out, err := cmd.Output()
|
||||
output.Write(out)
|
||||
|
||||
// update status code
|
||||
if err != nil {
|
||||
exitCode = 1
|
||||
}
|
||||
}
|
||||
|
||||
end := time.Now()
|
||||
|
||||
return Result{
|
||||
Out: string(out),
|
||||
Out: output.String(),
|
||||
ExitCode: exitCode,
|
||||
ExecutionTime: end.Sub(start),
|
||||
}
|
||||
|
||||
@@ -11,6 +11,16 @@ func TestExecute(t *testing.T) {
|
||||
block code.Block
|
||||
expected code.Result
|
||||
}{
|
||||
{
|
||||
block: code.Block{
|
||||
Code: `fn main() { println!("Hello, world!"); }`,
|
||||
Language: code.Rust,
|
||||
},
|
||||
expected: code.Result{
|
||||
Out: "Hello, world!\n",
|
||||
ExitCode: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
block: code.Block{
|
||||
Code: `puts "Hello, world!"`,
|
||||
@@ -107,7 +117,8 @@ func main() {
|
||||
}
|
||||
r := code.Execute(tc.block)
|
||||
if r.Out != tc.expected.Out {
|
||||
t.Fatalf("invalid output, got %s, want %s", r.Out, tc.expected.Out)
|
||||
t.Fatalf("invalid output for lang %s, got %s, want %s | %+v",
|
||||
tc.block.Language, r.Out, tc.expected.Out, r)
|
||||
}
|
||||
|
||||
if r.ExitCode != tc.expected.ExitCode {
|
||||
|
||||
@@ -1,8 +1,23 @@
|
||||
package code
|
||||
|
||||
// base: A filename is appended to the end of the arguments.
|
||||
// Example: base{"py"} -> `py test.py`
|
||||
// Placeholders <file>, <name> and <path> can be used.
|
||||
type base []string
|
||||
|
||||
// single: Same as base, except that the filename is not appended.
|
||||
type single []string
|
||||
|
||||
// multi: Multiple commands; placeholders can be used
|
||||
type multi [][]string
|
||||
|
||||
// ----
|
||||
|
||||
type Language struct {
|
||||
Extension string
|
||||
Command []string
|
||||
// Commands [][]string // placeholders: <name> file name (without extension),
|
||||
// <file> file name, <path> path without file name
|
||||
Cmds interface{} // type of multi, single, base
|
||||
}
|
||||
|
||||
// Supported Languages
|
||||
@@ -15,39 +30,51 @@ const (
|
||||
Perl = "perl"
|
||||
Python = "python"
|
||||
Ruby = "ruby"
|
||||
Rust = "rust"
|
||||
)
|
||||
|
||||
var Languages = map[string]Language{
|
||||
Bash: {
|
||||
Extension: "sh",
|
||||
Command: []string{"bash"},
|
||||
Cmds: base{"bash"},
|
||||
},
|
||||
Elixir: {
|
||||
Extension: "exs",
|
||||
Command: []string{"elixir"},
|
||||
Cmds: base{"elixir"},
|
||||
},
|
||||
Go: {
|
||||
Extension: "go",
|
||||
Command: []string{"go", "run"},
|
||||
Cmds: base{"go", "run"},
|
||||
},
|
||||
Javascript: {
|
||||
Extension: "js",
|
||||
Command: []string{"node"},
|
||||
Cmds: base{"node"},
|
||||
},
|
||||
Lua: {
|
||||
Extension: "lua",
|
||||
Command: []string{"lua"},
|
||||
Cmds: base{"lua"},
|
||||
},
|
||||
Ruby: {
|
||||
Extension: "rb",
|
||||
Command: []string{"ruby"},
|
||||
Cmds: base{"ruby"},
|
||||
},
|
||||
Python: {
|
||||
Extension: "py",
|
||||
Command: []string{"python"},
|
||||
Cmds: base{"python"},
|
||||
},
|
||||
Perl: {
|
||||
Extension: "pl",
|
||||
Command: []string{"perl"},
|
||||
Cmds: base{"pl"},
|
||||
},
|
||||
Rust: {
|
||||
Extension: "rs",
|
||||
Cmds: multi{
|
||||
// compile code
|
||||
{"rustc", "<file>", "-o", "<path>/<name>.run"},
|
||||
// grant execute permissions
|
||||
{"chmod", "+x", "<path>/<name>.run"},
|
||||
// run compiled file
|
||||
{"<path>/<name>.run"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user