blob: 2ef2585bd233ce9ee4fe6f60428db6af9cf81d8b [file] [log] [blame]
Jiri Simsa2e7dd712014-07-11 16:19:47 -07001package impl
2
3import (
Jiri Simsa2f8bc272014-07-16 12:29:15 -07004 "bytes"
Jiri Simsa2e7dd712014-07-11 16:19:47 -07005 "errors"
6 "io"
7 "io/ioutil"
8 "os"
9 "os/exec"
10 "path/filepath"
11
12 "veyron2/ipc"
13 "veyron2/services/mgmt/binary"
14 "veyron2/services/mgmt/build"
15 "veyron2/vlog"
16)
17
18var (
Jiri Simsa2f8bc272014-07-16 12:29:15 -070019 errBuildFailed = errors.New("build failed")
20 errInternalError = errors.New("internal error")
Jiri Simsa2e7dd712014-07-11 16:19:47 -070021)
22
23// invoker holds the state of a build server invocation.
24type invoker struct {
25 // gobin is the path to the Go compiler binary.
26 gobin string
27}
28
29// NewInvoker is the invoker factory.
30func NewInvoker(gobin string) *invoker {
31 return &invoker{
32 gobin: gobin,
33 }
34}
35
36// BUILD INTERFACE IMPLEMENTATION
37
Jiri Simsa2f8bc272014-07-16 12:29:15 -070038// TODO(jsimsa): Add support for building for a specific profile
39// specified as a suffix the Build().
Jiri Simsa2e7dd712014-07-11 16:19:47 -070040func (i *invoker) Build(_ ipc.ServerContext, stream build.BuildServiceBuildStream) ([]byte, error) {
Jiri Simsa2f8bc272014-07-16 12:29:15 -070041 vlog.VI(1).Infof("Build() called.")
Jiri Simsa2e7dd712014-07-11 16:19:47 -070042 dir, prefix := "", ""
43 dirPerm, filePerm := os.FileMode(0700), os.FileMode(0600)
44 root, err := ioutil.TempDir(dir, prefix)
45 if err != nil {
46 vlog.Errorf("TempDir(%v, %v) failed: %v", dir, prefix, err)
Jiri Simsa2f8bc272014-07-16 12:29:15 -070047 return nil, errInternalError
Jiri Simsa2e7dd712014-07-11 16:19:47 -070048 }
49 defer os.RemoveAll(root)
50 srcDir := filepath.Join(root, "go", "src")
51 if err := os.MkdirAll(srcDir, dirPerm); err != nil {
52 vlog.Errorf("MkdirAll(%v, %v) failed: %v", srcDir, dirPerm, err)
Jiri Simsa2f8bc272014-07-16 12:29:15 -070053 return nil, errInternalError
Jiri Simsa2e7dd712014-07-11 16:19:47 -070054 }
55 for {
56 srcFile, err := stream.Recv()
57 if err != nil && err != io.EOF {
58 vlog.Errorf("Recv() failed: %v", err)
Jiri Simsa2f8bc272014-07-16 12:29:15 -070059 return nil, errInternalError
Jiri Simsa2e7dd712014-07-11 16:19:47 -070060 }
61 if err == io.EOF {
62 break
63 }
64 filePath := filepath.Join(srcDir, filepath.FromSlash(srcFile.Name))
65 dir := filepath.Dir(filePath)
66 if err := os.MkdirAll(dir, dirPerm); err != nil {
67 vlog.Errorf("MkdirAll(%v, %v) failed: %v", dir, dirPerm, err)
Jiri Simsa2f8bc272014-07-16 12:29:15 -070068 return nil, errInternalError
Jiri Simsa2e7dd712014-07-11 16:19:47 -070069 }
70 if err := ioutil.WriteFile(filePath, srcFile.Contents, filePerm); err != nil {
71 vlog.Errorf("WriteFile(%v, %v) failed: %v", filePath, filePerm, err)
Jiri Simsa2f8bc272014-07-16 12:29:15 -070072 return nil, errInternalError
Jiri Simsa2e7dd712014-07-11 16:19:47 -070073 }
74 }
Jiri Simsa2f8bc272014-07-16 12:29:15 -070075 cmd := exec.Command(i.gobin, "install", "-v", "...")
Jiri Simsa2e7dd712014-07-11 16:19:47 -070076 cmd.Env = append(cmd.Env, "GOPATH="+filepath.Dir(srcDir))
Jiri Simsa2f8bc272014-07-16 12:29:15 -070077 var output bytes.Buffer
78 cmd.Stdout = &output
79 cmd.Stderr = &output
80 if err := cmd.Run(); err != nil {
81 vlog.Errorf("Run() failed: %v", err)
82 if output.Len() != 0 {
83 vlog.Errorf("%v", output.String())
84 }
85 return output.Bytes(), errBuildFailed
Jiri Simsa2e7dd712014-07-11 16:19:47 -070086 }
Jiri Simsa2f8bc272014-07-16 12:29:15 -070087 binDir := filepath.Join(root, "go", "bin")
88 files, err := ioutil.ReadDir(binDir)
89 if err != nil {
90 vlog.Errorf("ReadDir(%v) failed: %v", binDir, err)
91 return nil, errInternalError
92 }
93 // TODO(jsimsa): Analyze the binary files for non-standard shared
94 // library dependencies.
95 for _, file := range files {
96 binPath := filepath.Join(root, "go", "bin", file.Name())
97 bytes, err := ioutil.ReadFile(binPath)
98 if err != nil {
99 vlog.Errorf("ReadFile(%v) failed: %v", binPath, err)
100 return nil, errInternalError
101 }
102 result := build.File{
103 Name: "bin/" + file.Name(),
104 Contents: bytes,
105 }
106 if err := stream.Send(result); err != nil {
107 vlog.Errorf("Send() failed: %v", err)
108 return nil, errInternalError
109 }
110 }
111 return output.Bytes(), nil
Jiri Simsa2e7dd712014-07-11 16:19:47 -0700112}
113
114func (i *invoker) Describe(_ ipc.ServerContext, name string) (binary.Description, error) {
115 // TODO(jsimsa): Implement.
116 return binary.Description{}, nil
117}