Start packer/plugin. Big WiP

This commit is contained in:
Mitchell Hashimoto 2013-05-04 21:26:30 -07:00
parent 01405c864b
commit 3370c55e2c
6 changed files with 147 additions and 0 deletions

13
packer/plugin/client.go Normal file
View File

@ -0,0 +1,13 @@
package plugin
import (
"os/exec"
)
type Client struct {
cmd *exec.Cmd
}
func NewClient(cmd *exec.Cmd) *Client {
return &Client{cmd}
}

49
packer/plugin/command.go Normal file
View File

@ -0,0 +1,49 @@
package plugin
import (
"bytes"
"github.com/mitchellh/packer/packer"
"net/rpc"
"os/exec"
packrpc "github.com/mitchellh/packer/packer/rpc"
"strings"
"time"
)
type processCommand struct {
cmd *exec.Cmd
}
func (c *processCommand) Run(e packer.Environment, args []string) int {
return 0
}
func (c *processCommand) Synopsis() string {
out := new(bytes.Buffer)
c.cmd.Stdout = out
c.cmd.Start()
defer c.cmd.Process.Kill()
// TODO: timeout
// TODO: check that command is even running
address := ""
for {
line, err := out.ReadBytes('\n')
if err == nil {
address = strings.TrimSpace(string(line))
break
}
time.Sleep(10 * time.Millisecond)
}
client, _ := rpc.Dial("tcp", address)
defer client.Close()
realCommand := packrpc.Command(client)
return realCommand.Synopsis()
}
func Command(cmd *exec.Cmd) packer.Command {
return &processCommand{cmd}
}

31
packer/plugin/plugin.go Normal file
View File

@ -0,0 +1,31 @@
// The packer/plugin package provides the functionality required for writing
// Packer plugins in the form of static binaries that are then executed and
// run. It also contains the functions necessary to run these external plugins.
package plugin
import (
"fmt"
"github.com/mitchellh/packer/packer"
"os"
packrpc "github.com/mitchellh/packer/packer/rpc"
)
// This serves the plugin by starting the RPC server and serving requests.
// This function never returns.
func serve(server *packrpc.Server) {
// Start up the server
server.Start()
// Output the address to stdout
fmt.Println(server.Address())
os.Stdout.Sync()
// Never return, wait on a channel that never gets a message
<-make(chan bool)
}
func ServeCommand(command packer.Command) {
server := packrpc.NewServer()
server.RegisterCommand(command)
serve(server)
}

View File

@ -0,0 +1,46 @@
package plugin
import (
"cgl.tideland.biz/asserts"
"github.com/mitchellh/packer/packer"
"os"
"os/exec"
"testing"
)
type helperCommand byte
func (helperCommand) Run(packer.Environment, []string) int {
return 42
}
func (helperCommand) Synopsis() string {
return "1"
}
func helperProcess(s... string) *exec.Cmd {
cs := []string{"-test.run=TestHelperProcess", "--"}
cs = append(cs, s...)
cmd := exec.Command(os.Args[0], cs...)
cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS=1"}, os.Environ()...)
return cmd
}
func TestClient(t *testing.T) {
assert := asserts.NewTestingAsserts(t, true)
command := Command(helperProcess("command"))
result := command.Synopsis()
assert.Equal(result, "1", "should return result")
}
// This is not a real test. This is just a helper process kicked off by
// tests.
func TestHelperProcess(*testing.T) {
if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" {
return
}
ServeCommand(new(helperCommand))
}

View File

@ -24,6 +24,10 @@ type CommandRunArgs struct {
type CommandSynopsisArgs byte
func Command(client *rpc.Client) *ClientCommand {
return &ClientCommand{client}
}
func (c *ClientCommand) Run(env packer.Environment, args []string) (result int) {
// TODO: Environment
rpcArgs := &CommandRunArgs{nil, args}

View File

@ -41,6 +41,10 @@ func (s *Server) RegisterBuilderFactory(b packer.BuilderFactory) {
s.server.RegisterName("BuilderFactory", &BuilderFactoryServer{b})
}
func (s *Server) RegisterCommand(c packer.Command) {
s.server.RegisterName("Command", &ServerCommand{c})
}
func (s *Server) RegisterEnvironment(e packer.Environment) {
s.server.RegisterName("Environment", &EnvironmentServer{e})
}