Skip to content

Commit

Permalink
Merge pull request #2 from etsy/write-executable-atomically
Browse files Browse the repository at this point in the history
fix: write downloaded executable atomically
  • Loading branch information
ericnorris authored Nov 1, 2021
2 parents f92d3bd + 0566733 commit 4f8b1f0
Show file tree
Hide file tree
Showing 3 changed files with 21 additions and 29 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/google/btree v1.0.1 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79
github.com/hashicorp/terraform-config-inspect v0.0.0-20210318070130-9a80970d6b34
github.com/natefinch/atomic v1.0.1 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1
)
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
Expand All @@ -54,10 +56,8 @@ github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6Ac
github.com/zclconf/go-cty v1.1.0 h1:uJwc9HiBOCpoKIObTQaLR+tsEXx1HBHnOsOOpcdhZgw=
github.com/zclconf/go-cty v1.1.0/go.mod h1:xnAOWiHeOqg2nWS62VtQ7pbOu17FtxJNW8RLEih+O3s=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down
45 changes: 18 additions & 27 deletions internal/releaseapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/Masterminds/semver/v3"
"github.com/gregjones/httpcache"
"github.com/gregjones/httpcache/diskcache"
"github.com/natefinch/atomic"
"github.com/pkg/errors"
)

Expand Down Expand Up @@ -122,47 +123,39 @@ func (c *Client) downloadBuild(build Build) (string, error) {
return "", err
}

defer zipFile.Close()

zipReader, err := zip.NewReader(zipFile, zipLength)

if err != nil {
return "", errors.Wrap(err, "could not unzip release archive")
}

destination, err := os.OpenFile(path, os.O_RDWR|os.O_CREATE, 0755)

defer destination.Close()

if err != nil {
return "", errors.Wrap(err, "could not create destination file for executable")
}

var found bool

for _, f := range zipReader.File {
if filepath.Base(f.Name) != "terraform" {
continue
}

source, err := f.Open()

defer source.Close()

if err != nil {
return "", errors.Wrap(err, "could not read executable in release archive")
return "", errors.Wrap(err, "could not read binary in release archive")
}

if _, err := io.Copy(destination, source); err != nil {
return "", errors.Wrap(err, "could not copy executable to destination")
defer source.Close()

if err := atomic.WriteFile(path, source); err != nil {
return "", errors.Wrap(err, "could not write binary to the cache directory")
}

found = true
}
if err := os.Chmod(path, 0700); err != nil {
return "", errors.Wrap(err, "could not make binary executable")
}

if !found {
return "", errors.New("could not find executable named 'terraform' in release archive")
return path, nil
}

return path, nil
return "", errors.New("could not find executable named 'terraform' in release archive")
}

func (c *Client) downloadReleaseArchive(build Build) (*os.File, int64, error) {
Expand All @@ -176,11 +169,13 @@ func (c *Client) downloadReleaseArchive(build Build) (*os.File, int64, error) {

response, err := c.httpClient.Do(request)

defer response.Body.Close()

if err != nil {
return nil, 0, errors.Wrap(err, "could not download release archive")
} else if response.StatusCode != http.StatusOK {
}

defer response.Body.Close()

if response.StatusCode != http.StatusOK {
return nil, 0, errors.Errorf("unexpected status code '%s' in response", response.StatusCode)
}

Expand All @@ -197,10 +192,6 @@ func (c *Client) downloadReleaseArchive(build Build) (*os.File, int64, error) {
return tmp, response.ContentLength, nil
}

func cachedReleaseListPath(cacheDir string) string {
return filepath.Join(cacheDir, "terraform-releases")
}

func cachedExecutablePath(cacheDir string, b Build) string {
return filepath.Join(cacheDir, executableName(b))
}
Expand Down

0 comments on commit 4f8b1f0

Please sign in to comment.