diff --git a/api/cmd/build/main.go b/api/cmd/build/main.go index 842ea49520..1c545c66a8 100644 --- a/api/cmd/build/main.go +++ b/api/cmd/build/main.go @@ -28,6 +28,7 @@ func main() { id := flag.String("id", "", "tag the build with this id") push := flag.String("push", "", "push build to this prefix when done") auth := flag.String("auth", "", "auth token for push") + noCache := flag.Bool("no-cache", false, "skip the docker cache") flag.Parse() @@ -78,7 +79,9 @@ func main() { die(err) } - errors := m.Build(app, dir) + cache := !*noCache + + errors := m.Build(app, dir, cache) if len(errors) > 0 { die(errors[0]) diff --git a/api/controllers/builds.go b/api/controllers/builds.go index 66d3f03703..4ab06add29 100644 --- a/api/controllers/builds.go +++ b/api/controllers/builds.go @@ -91,6 +91,8 @@ func BuildCreate(rw http.ResponseWriter, r *http.Request) error { return err } + cache := !(r.FormValue("cache") == "false") + if source != nil { err = models.S3PutFile(resources["RegistryBucket"].Id, fmt.Sprintf("builds/%s.tgz", build.Id), source, false) @@ -98,7 +100,7 @@ func BuildCreate(rw http.ResponseWriter, r *http.Request) error { return err } - go build.ExecuteLocal(source, ch) + go build.ExecuteLocal(source, cache, ch) err = <-ch @@ -110,7 +112,7 @@ func BuildCreate(rw http.ResponseWriter, r *http.Request) error { } if repo := r.FormValue("repo"); repo != "" { - go build.ExecuteRemote(repo, ch) + go build.ExecuteRemote(repo, cache, ch) err = <-ch diff --git a/api/manifest.yml b/api/manifest.yml index ccfe7b1070..beb745dcaa 100644 --- a/api/manifest.yml +++ b/api/manifest.yml @@ -106,6 +106,11 @@ paths: type: string in: path required: true + - name: cache + description: set to false to avoid cache + type: boolean + in: formData + required: false - name: repo description: repository type: string diff --git a/api/manifest/manifest.go b/api/manifest/manifest.go index 448d0dab92..f2f148e0e5 100644 --- a/api/manifest/manifest.go +++ b/api/manifest/manifest.go @@ -136,26 +136,22 @@ func Read(dir string) (*Manifest, error) { return &m, nil } -func buildAsync(source, tag string, ch chan error) { - ch <- buildSync(source, tag) -} +func buildSync(source, tag string, cache bool) error { + args := []string{"build", "-t", tag} -func buildSync(source, tag string) error { - return run("docker", "build", "-t", tag, source) -} + if !cache { + args = append(args, "--no-cache") + } -func pullAsync(image string, ch chan error) { - ch <- pullSync(image) + args = append(args, source) + + return run("docker", args...) } func pullSync(image string) error { return run("docker", "pull", image) } -func pushAsync(local, remote string, ch chan error) { - ch <- pushSync(local, remote) -} - func pushSync(local, remote string) error { err := run("docker", "tag", "-f", local, remote) @@ -172,7 +168,7 @@ func pushSync(local, remote string) error { return nil } -func (m *Manifest) Build(app, dir string) []error { +func (m *Manifest) Build(app, dir string, cache bool) []error { builds := map[string]string{} pulls := []string{} tags := map[string]string{} @@ -207,7 +203,7 @@ func (m *Manifest) Build(app, dir string) []error { errors := []error{} for source, tag := range builds { - err := buildSync(source, tag) + err := buildSync(source, tag, cache) if err != nil { return []error{err} diff --git a/api/manifest/manifest_test.go b/api/manifest/manifest_test.go index 75d9aa268c..afc6090996 100644 --- a/api/manifest/manifest_test.go +++ b/api/manifest/manifest_test.go @@ -226,7 +226,7 @@ func _assert(t *testing.T, cases Cases) { type runnerFn func() func testBuild(m *Manifest, app string) (string, string) { - return testRunner(m, app, func() { m.Build(app, ".") }) + return testRunner(m, app, func() { m.Build(app, ".", true) }) } func testRun(m *Manifest, app string) (string, string) { diff --git a/api/models/build.go b/api/models/build.go index d70d03af25..81a046fdde 100644 --- a/api/models/build.go +++ b/api/models/build.go @@ -144,7 +144,7 @@ func (b *Build) Cleanup() error { return nil } -func (b *Build) ExecuteLocal(r io.Reader, ch chan error) { +func (b *Build) ExecuteLocal(r io.Reader, cache bool, ch chan error) { b.Status = "building" b.Save() @@ -156,6 +156,10 @@ func (b *Build) ExecuteLocal(r io.Reader, ch chan error) { args = append(args, "-auth", pw) } + if !cache { + args = append(args, "-no-cache") + } + args = append(args, name, "-") err := b.execute(args, r, ch) @@ -169,7 +173,7 @@ func (b *Build) ExecuteLocal(r io.Reader, ch chan error) { } } -func (b *Build) ExecuteRemote(repo string, ch chan error) { +func (b *Build) ExecuteRemote(repo string, cache bool, ch chan error) { b.Status = "building" b.Save() @@ -181,6 +185,10 @@ func (b *Build) ExecuteRemote(repo string, ch chan error) { args = append(args, "-auth", pw) } + if !cache { + args = append(args, "-no-cache") + } + args = append(args, name) parts := strings.Split(repo, "#") diff --git a/client/builds.go b/client/builds.go index 7f2c6a4ee3..fe982ec43c 100644 --- a/client/builds.go +++ b/client/builds.go @@ -32,14 +32,18 @@ func (c *Client) GetBuilds(app string) (Builds, error) { return builds, nil } -func (c *Client) CreateBuildSource(app string, source []byte) (*Build, error) { +func (c *Client) CreateBuildSource(app string, source []byte, cache bool) (*Build, error) { var build Build files := map[string][]byte{ "source": source, } - err := c.PostMultipart(fmt.Sprintf("/apps/%s/builds", app), files, &build) + params := map[string]string{ + "cache": fmt.Sprintf("%t", cache), + } + + err := c.PostMultipart(fmt.Sprintf("/apps/%s/builds", app), files, params, &build) if err != nil { return nil, err @@ -48,7 +52,7 @@ func (c *Client) CreateBuildSource(app string, source []byte) (*Build, error) { return &build, nil } -func (c *Client) CreateBuildUrl(app string, url string) (*Build, error) { +func (c *Client) CreateBuildUrl(app string, url string, cache bool) (*Build, error) { var build Build params := map[string]string{ diff --git a/client/client.go b/client/client.go index 179006f373..2b9c706c50 100644 --- a/client/client.go +++ b/client/client.go @@ -129,7 +129,7 @@ func (c *Client) PostBody(path string, body io.Reader, out interface{}) error { return nil } -func (c *Client) PostMultipart(path string, files map[string][]byte, out interface{}) error { +func (c *Client) PostMultipart(path string, files map[string][]byte, params Params, out interface{}) error { err := c.versionCheck() if err != nil { @@ -152,12 +152,16 @@ func (c *Client) PostMultipart(path string, files map[string][]byte, out interfa if err != nil { return err } + } - err = writer.Close() + for name, value := range params { + writer.WriteField(name, value) + } - if err != nil { - return err - } + err = writer.Close() + + if err != nil { + return err } req, err := c.request("POST", path, body) diff --git a/cmd/convox/builds.go b/cmd/convox/builds.go index 1438626506..d0569496fe 100644 --- a/cmd/convox/builds.go +++ b/cmd/convox/builds.go @@ -19,7 +19,13 @@ func init() { Description: "create a new build", Usage: "", Action: cmdBuildsCreate, - Flags: []cli.Flag{appFlag}, + Flags: []cli.Flag{ + appFlag, + cli.BoolFlag{ + Name: "no-cache", + Usage: "Do not use Docker cache during build.", + }, + }, }) stdcli.RegisterCommand(cli.Command{ Name: "builds", @@ -177,7 +183,9 @@ func executeBuildDir(c *cli.Context, dir string, app string) (string, error) { fmt.Println("OK") - build, err := rackClient(c).CreateBuildSource(app, tar) + cache := !c.Bool("no-cache") + + build, err := rackClient(c).CreateBuildSource(app, tar, cache) if err != nil { return "", err @@ -203,7 +211,9 @@ func executeBuildDir(c *cli.Context, dir string, app string) (string, error) { } func executeBuildUrl(c *cli.Context, url string, app string) (string, error) { - build, err := rackClient(c).CreateBuildUrl(app, url) + cache := !c.Bool("no-cache") + + build, err := rackClient(c).CreateBuildUrl(app, url, cache) if err != nil { return "", err diff --git a/cmd/convox/deploy.go b/cmd/convox/deploy.go index 7f05cbfd8a..a7763ac461 100644 --- a/cmd/convox/deploy.go +++ b/cmd/convox/deploy.go @@ -14,9 +14,10 @@ func init() { Usage: "", Action: cmdDeploy, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "app", - Usage: "App name. Inferred from current directory if not specified.", + appFlag, + cli.BoolFlag{ + Name: "no-cache", + Usage: "Do not use Docker cache during build.", }, }, }) diff --git a/cmd/convox/start.go b/cmd/convox/start.go index ba1b4fe742..b50ef5a82f 100644 --- a/cmd/convox/start.go +++ b/cmd/convox/start.go @@ -110,7 +110,7 @@ func cmdStart(c *cli.Context) { return } - errors := m.Build(app, dir) + errors := m.Build(app, dir, true) if len(errors) != 0 { fmt.Printf("errors: %+v\n", errors)