shad-go/distbuild/pkg/client/build.go

115 lines
2.5 KiB
Go
Raw Normal View History

2020-03-10 12:08:59 +00:00
package client
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
2020-03-11 22:46:45 +00:00
"go.uber.org/zap"
2020-03-10 12:08:59 +00:00
"gitlab.com/slon/shad-go/distbuild/pkg/build"
"gitlab.com/slon/shad-go/distbuild/pkg/proto"
)
type Client struct {
CoordinatorEndpoint string
2020-03-11 22:46:45 +00:00
SourceDir string
Log *zap.Logger
2020-03-10 12:08:59 +00:00
}
type BuildListener interface {
OnJobStdout(jobID build.ID, stdout []byte) error
2020-03-11 22:46:45 +00:00
OnJobStderr(jobID build.ID, stderr []byte) error
2020-03-10 12:08:59 +00:00
OnJobFinished(jobID build.ID) error
OnJobFailed(jobID build.ID, code int, error string) error
}
func (c *Client) uploadSources(ctx context.Context, src proto.MissingSources) error {
2020-03-11 22:46:45 +00:00
return nil
2020-03-10 12:08:59 +00:00
}
func (c *Client) Build(ctx context.Context, graph build.Graph, lsn BuildListener) error {
graphJS, err := json.Marshal(graph)
if err != nil {
return err
}
req, err := http.NewRequest("POST", c.CoordinatorEndpoint+"/build", bytes.NewBuffer(graphJS))
if err != nil {
return err
}
req.Header.Add("Content-Type", "application/json")
req = req.WithContext(ctx)
2020-03-11 22:46:45 +00:00
c.Log.Debug("sending build request", zap.String("url", req.URL.String()))
2020-03-10 12:08:59 +00:00
rsp, err := http.DefaultClient.Do(req)
if err != nil {
return fmt.Errorf("build failed: %w", err)
}
defer rsp.Body.Close()
if rsp.StatusCode != 200 {
errorMsg, _ := ioutil.ReadAll(rsp.Body)
return fmt.Errorf("build failed: %s", errorMsg)
}
d := json.NewDecoder(rsp.Body)
var missing proto.MissingSources
if err := d.Decode(&missing); err != nil {
2020-03-11 22:46:45 +00:00
return fmt.Errorf("error receiving source list: %w", err)
2020-03-10 12:08:59 +00:00
}
if err := c.uploadSources(ctx, missing); err != nil {
return err
}
for {
var update proto.StatusUpdate
if err := d.Decode(&update); err != nil {
2020-03-11 22:46:45 +00:00
return fmt.Errorf("error receiving status update: %w", err)
2020-03-10 12:08:59 +00:00
}
switch {
case update.BuildFailed != nil:
return fmt.Errorf("build failed: %s", update.BuildFailed.Error)
2020-03-14 10:24:44 +00:00
case update.BuildFinished != nil:
return nil
2020-03-10 12:08:59 +00:00
case update.JobFinished != nil:
jf := update.JobFinished
if jf.Stdout != nil {
if err := lsn.OnJobStdout(jf.ID, jf.Stdout); err != nil {
return err
}
}
if jf.Stderr != nil {
if err := lsn.OnJobStderr(jf.ID, jf.Stderr); err != nil {
return err
}
}
if jf.Error != nil {
if err := lsn.OnJobFailed(jf.ID, jf.ExitCode, *jf.Error); err != nil {
return err
}
} else {
if err := lsn.OnJobFinished(jf.ID); err != nil {
return err
}
}
default:
return fmt.Errorf("build failed: unexpected status update")
}
}
}