/
compiler.go
102 lines (83 loc) · 2.04 KB
/
compiler.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package octavius
import (
"bytes"
log "github.com/sirupsen/logrus"
"go/build"
"io"
"io/ioutil"
"os"
"os/exec"
"path"
"plugin"
"strings"
)
type Program struct {
Source string
lib []byte
p *plugin.Plugin
}
func (p *Program) Compile() {
source := p.Source
base := path.Join(build.Default.GOPATH, "src")
srcdir, err := ioutil.TempDir(base, "source")
if err != nil {
log.Fatal("Unable to create temp package: ", err)
}
defer os.RemoveAll(srcdir)
if !strings.HasPrefix(srcdir, base) {
log.Fatal("Invalid package. Expected %v/* \tGot %v", base, srcdir)
}
pkgName := srcdir[len(base)+1:]
srcFile, err := os.Create(path.Join(srcdir, "main.go"))
if err != nil {
log.Fatal("Unable to create temp file: ", err)
}
log.Info("Source", source)
io.Copy(srcFile, strings.NewReader(source))
srcFile.Close()
outfile, err := ioutil.TempFile("", "out")
if err != nil {
log.Fatal("Unable to create temp file: ", err)
}
defer os.Remove(outfile.Name())
outfile.Close()
log.Infof("Building from %v", srcFile.Name())
cmd := exec.Command("go", "build", "-buildmode=plugin", "-o", outfile.Name(), pkgName)
var stderr bytes.Buffer
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
log.Fatal(err, ": ", stderr.String())
}
outfile2, err := os.Open(outfile.Name())
if err != nil {
log.Fatal(err, stderr.String())
}
var buf bytes.Buffer
io.Copy(&buf, outfile2)
p.lib = buf.Bytes()
}
func (p *Program) Load(funcNames ...string) []interface{} {
sharedlib, err := ioutil.TempFile("", "out")
if err != nil {
log.Fatal("Unable to create temp lib: ", err)
}
p.Compile()
io.Copy(sharedlib, bytes.NewReader(p.lib))
sharedlib.Close()
// _Do not_ remove file
defer os.Remove(sharedlib.Name())
pg, err := plugin.Open(sharedlib.Name())
if err != nil {
log.Fatal("Unable to open plugin: ", pg, "\t", err)
}
var result []interface{}
for _, funcName := range funcNames {
f, err := pg.Lookup(funcName)
if err != nil {
log.Fatalf("Unable to load function %v: %v", funcName, err)
}
result = append(result, f)
}
return result
}