func (cli *MakisuClient) prepareContext(context string) (string, error) {
	context, err := filepath.Abs(context)
	if err != nil {
		return "", err
	}
	rand := rand.New(rand.NewSource(time.Now().Unix()))
	targetContext := fmt.Sprintf("context-%d", rand.Intn(10000))
	targetPath := filepath.Join(cli.LocalSharedPath, targetContext)
	log.Infof("Copying context to worker filesystem: %s => %s", context, targetPath)
	start := time.Now()
	if err := fileio.NewCopier([]string{}).CopyDir(context, targetPath); err != nil {
		return "", err
	}
	log.Infow("Copied context", "duration", time.Since(start))
	return targetContext, nil
}
Takes in the local path of the context, copies the files to a new directory inside the worker's
mount namespace and returns the context path inside the shared mount location.
Example: prepareContext("/home/joe/test/context") => context-12345
This means that the context was copied over to <cmd.LocalSharedPath>/context-12345
package client
import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"math/rand"
	"net"
	"net/http"
	"os"
	"path/filepath"
	"strconv"
	"time"
	"github.com/uber/makisu/lib/fileio"
	"github.com/uber/makisu/lib/log"
)
type MakisuClient struct {
	LocalSharedPath  string
	WorkerSharedPath string
	WorkerLog func(line string)
	HTTPDo    func(req *http.Request) (*http.Response, error)
}
func New(socket, localPath, workerPath string) *MakisuClient {
	cli := &http.Client{
		Transport: &http.Transport{
			Dial: func(p, a string) (net.Conn, error) {
				return net.Dial("unix", socket)
			},
		},
	}
	return &MakisuClient{
		LocalSharedPath:  localPath,
		WorkerSharedPath: workerPath,
		WorkerLog: func(line string) { fmt.Fprintf(os.Stderr, line+"\n") },
		HTTPDo:    cli.Do,
	}
}
func (cli *MakisuClient) SetWorkerLog(fn func(line string)) {
	cli.WorkerLog = fn
}
func (cli *MakisuClient) Ready() (bool, error) {
	req, err := http.NewRequest("GET", "http://localhost/ready", nil)
	if err != nil {
		return false, err
	}
	resp, err := cli.HTTPDo(req)
	if err != nil {
		return false, err
	}
	defer resp.Body.Close()
	return resp.StatusCode == http.StatusOK, nil
}
func (cli *MakisuClient) Exit() error {
	req, err := http.NewRequest("GET", "http://localhost/exit", nil)
	if err != nil {
		return err
	}
	resp, err := cli.HTTPDo(req)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad status code from worker: %v", resp.StatusCode)
	}
	return nil
}
func (cli *MakisuClient) Build(flags []string, context string) error {
	context, err := cli.prepareContext(context)
	if err != nil {
		return err
	}
	localContext := filepath.Join(cli.LocalSharedPath, context)
	workerContext := filepath.Join(cli.WorkerSharedPath, context)
	defer func() {
		log.Infof("Removing context after build: %s", localContext)
		os.RemoveAll(localContext)
	}()
	args := append(flags, workerContext)
	args = append([]string{"build"}, args...)
	log.Infof("Arguments passed to Makisu worker: %v", args)
	content, _ := json.Marshal(args)
	reader := bytes.NewBuffer(content)
	req, err := http.NewRequest("POST", "http://localhost/build", reader)
	if err != nil {
		return err
	}
	resp, err := cli.HTTPDo(req)
	if err != nil {
		return err
	}
	log.Infof("Status code from Makisu worker: %v", resp.StatusCode)
	if err := cli.readLines(resp.Body); err != nil {
		return err
	} else if resp.StatusCode != http.StatusOK {
		return fmt.Errorf("bad http status code from Makisu worker: %v", resp.StatusCode)
	}
	return nil
}