forked from amenzhinsky/go-memexec
-
Notifications
You must be signed in to change notification settings - Fork 0
/
memexec.go
77 lines (68 loc) · 1.66 KB
/
memexec.go
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
65
66
67
68
69
70
71
72
73
74
75
76
77
package memexec
import (
"context"
"os"
"os/exec"
)
type Option func(e *Exec)
// Exec is an in-memory executable code unit.
type Exec struct {
f *os.File
opts []func(cmd *exec.Cmd)
clean func() error
}
// WithPrepare configures cmd with default values such as Env, Dir, etc.
func WithPrepare(fn func(cmd *exec.Cmd)) Option {
return func(e *Exec) {
e.opts = append(e.opts, fn)
}
}
// WithCleanup is executed right after Exec.Close.
func WithCleanup(fn func() error) Option {
return func(e *Exec) {
e.clean = fn
}
}
// New creates new memory execution object that can be
// used for executing commands on a memory based binary.
func New(b []byte, opts ...Option) (*Exec, error) {
f, err := open(b)
if err != nil {
return nil, err
}
e := &Exec{f: f}
for _, opt := range opts {
opt(e)
}
return e, nil
}
// Command is an equivalent of `exec.Command`,
// except that the path to the executable is being omitted.
func (m *Exec) Command(args ...string) *exec.Cmd {
return m.CommandContext(context.Background(), args...)
}
// CommandContext is an equivalent of `exec.CommandContext`,
// except that the path to the executable is being omitted.
func (m *Exec) CommandContext(ctx context.Context, args ...string) *exec.Cmd {
exe := exec.CommandContext(ctx, m.f.Name(), args...)
for _, opt := range m.opts {
opt(exe)
}
return exe
}
// Close closes Exec object.
//
// Any further command will fail, it's client's responsibility
// to control the flow by using synchronization algorithms.
func (m *Exec) Close() error {
if err := clean(m.f); err != nil {
if m.clean != nil {
_ = m.clean()
}
return err
}
if m.clean == nil {
return nil
}
return m.clean()
}