-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathruncode.go
More file actions
64 lines (57 loc) · 1.93 KB
/
Copy pathruncode.go
File metadata and controls
64 lines (57 loc) · 1.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package xshellz
import (
"context"
"fmt"
"sort"
"strings"
)
// codeInterpreters maps a RunCode language to its interpreter binary and
// temp-file extension on the box.
var codeInterpreters = map[string]struct {
command string
extension string
}{
"python": {"python3", ".py"},
"node": {"node", ".js"},
"bash": {"bash", ".sh"},
"ruby": {"ruby", ".rb"},
"php": {"php", ".php"},
}
// SupportedLanguages returns the languages RunCode accepts, sorted.
func SupportedLanguages() []string {
langs := make([]string, 0, len(codeInterpreters))
for lang := range codeInterpreters {
langs = append(langs, lang)
}
sort.Strings(langs)
return langs
}
// RunCode executes a snippet of source code on the box and returns the same
// RunResult as Run — this is the "code interpreter" path for AI-generated
// code: the code is written to a unique temp file, run with the language's
// interpreter, and the temp file is always deleted afterwards.
//
// Supported languages: "python" (python3), "node", "bash", "ruby", "php".
// An unknown language fails with ErrUnsupportedLanguage. As with Run, a
// non-zero exit code (e.g. a Python traceback) is data on the result, not an
// error. opts applies to the interpreter invocation (Cwd, Env, streaming).
func (s *Sandbox) RunCode(ctx context.Context, language, code string, opts *RunOptions) (*RunResult, error) {
spec, ok := codeInterpreters[language]
if !ok {
return nil, fmt.Errorf("%w: %q (supported: %s)", ErrUnsupportedLanguage, language, strings.Join(SupportedLanguages(), ", "))
}
suffix, err := randomHex(4)
if err != nil {
return nil, err
}
remotePath := "/tmp/xshellz-code-" + suffix + spec.extension
if err := s.WriteFile(ctx, remotePath, []byte(code)); err != nil {
return nil, err
}
res, runErr := s.Run(ctx, spec.command+" "+shellQuote(remotePath), opts)
_, _ = s.Run(ctx, "rm -f "+shellQuote(remotePath), nil)
if runErr != nil {
return nil, runErr
}
return res, nil
}