Skip to content

Commit

Permalink
Display a download progress bar for arkade get
Browse files Browse the repository at this point in the history
Signed-off-by: Ramiro Berrelleza <[email protected]>
  • Loading branch information
rberrelleza authored and alexellis committed Sep 22, 2020
1 parent 9211417 commit af87452
Show file tree
Hide file tree
Showing 9 changed files with 113 additions and 44 deletions.
2 changes: 1 addition & 1 deletion cmd/apps/linkerd_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func downloadLinkerd(userPath, arch, clientOS string) error {

if _, err := os.Stat(fmt.Sprintf("%s", env.LocalBinary(tool.Name, ""))); errors.Is(err, os.ErrNotExist) {

outPath, finalName, err := get.Download(tool, arch, clientOS, tool.Version, get.DownloadArkadeDir)
outPath, finalName, err := get.Download(tool, arch, clientOS, tool.Version, get.DownloadArkadeDir, false)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/apps/osm_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func downloadOSM(userPath, arch, clientOS string) error {

if _, err := os.Stat(fmt.Sprintf("%s", env.LocalBinary(tool.Name, ""))); errors.Is(err, os.ErrNotExist) {

outPath, finalName, err := get.Download(tool, arch, clientOS, tool.Version, get.DownloadArkadeDir)
outPath, finalName, err := get.Download(tool, arch, clientOS, tool.Version, get.DownloadArkadeDir, false)
if err != nil {
return err
}
Expand Down
27 changes: 26 additions & 1 deletion cmd/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ package cmd

import (
"fmt"
"os"
"os/signal"
"strconv"
"syscall"

"github.com/alexellis/arkade/pkg/env"
"github.com/alexellis/arkade/pkg/get"
Expand All @@ -27,6 +31,7 @@ and provides a fast and easy alternative to a package manager.`,
SilenceUsage: true,
}

command.Flags().Bool("progress", true, "Display a progress bar")
command.Flags().Bool("stash", true, "When set to true, stash binary in HOME/.arkade/bin/, otherwise store in /tmp/")
command.Flags().StringP("version", "v", "", "Download a specific version")

Expand Down Expand Up @@ -66,12 +71,32 @@ and provides a fast and easy alternative to a package manager.`,
}

stash, _ := command.Flags().GetBool("stash")
progress, _ := command.Flags().GetBool("progress")
if p, ok := os.LookupEnv("ARKADE_PROGRESS"); ok {
b, err := strconv.ParseBool(p)
if err != nil {
return fmt.Errorf("ARKADE_PROGRESS is not a valid boolean")
}

progress = b
}

dlMode := get.DownloadTempDir
if stash {
dlMode = get.DownloadArkadeDir
}

outFilePath, finalName, err := get.Download(tool, arch, operatingSystem, version, dlMode)
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)

go func() {
select {
case <-signalChan:
os.Exit(2)
}
}()

outFilePath, finalName, err := get.Download(tool, arch, operatingSystem, version, dlMode, progress)

if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ go 1.13

require (
github.com/alexellis/go-execute v0.0.0-20191207085904-961405ea7544
github.com/cheggaaa/pb/v3 v3.0.5
github.com/fatih/color v1.9.0 // indirect
github.com/morikuni/aec v1.0.0
github.com/sethvargo/go-password v0.1.2
github.com/spf13/cobra v0.0.5
Expand Down
25 changes: 23 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,17 +1,35 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/VividCortex/ewma v1.1.1 h1:MnEK4VOv6n0RSY4vtRe3h11qjxL3+t0B8yOL8iMXdcM=
github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA=
github.com/alexellis/go-execute v0.0.0-20191207085904-961405ea7544 h1:KjtKgzxk/0wfp7vZxWUYPMiEJKep7FJ7C7o/vtHyc/Q=
github.com/alexellis/go-execute v0.0.0-20191207085904-961405ea7544/go.mod h1:zfRbgnPVxXCSpiKrg1CE72hNUWInqxExiaz2D9ppTts=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/cheggaaa/pb/v3 v3.0.5 h1:lmZOti7CraK9RSjzExsY53+WWfub9Qv13B5m4ptEoPE=
github.com/cheggaaa/pb/v3 v3.0.5/go.mod h1:X1L61/+36nz9bjIsrDU52qHKOQukUQe2Ge+YvGuquCw=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.7 h1:Ei8KR0497xHyKJPAv59M1dkC+rOZCMBJ+t3fZ+twI54=
github.com/mattn/go-runewidth v0.0.7/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
Expand All @@ -37,18 +55,21 @@ github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljT
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 h1:ObdrDkeb4kJdCP557AjRjq69pTHfNouLtWZG7j9rPN8=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
Expand Down
2 changes: 1 addition & 1 deletion pkg/archive/unzip.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
func Unzip(reader io.ReaderAt, size int64, dir string) error {
zipReader, err := zip.NewReader(reader, size)
if err != nil {
return fmt.Errorf("error creating zip reader")
return fmt.Errorf("error creating zip reader: %s", err)
}

return unzip(*zipReader, dir)
Expand Down
93 changes: 57 additions & 36 deletions pkg/get/download.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
package get

import (
"bytes"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
"path"
Expand All @@ -14,85 +12,66 @@ import (
"github.com/alexellis/arkade/pkg/archive"
"github.com/alexellis/arkade/pkg/config"
"github.com/alexellis/arkade/pkg/env"
"github.com/cheggaaa/pb/v3"
)

const (
DownloadTempDir = iota
DownloadArkadeDir = iota
)

func Download(tool *Tool, arch, operatingSystem, version string, downloadMode int) (string, string, error) {
func Download(tool *Tool, arch, operatingSystem, version string, downloadMode int, displayProgress bool) (string, string, error) {

downloadURL, err := GetDownloadURL(tool, strings.ToLower(operatingSystem), strings.ToLower(arch), version)
if err != nil {
return "", "", err
}

fmt.Println(downloadURL)

res, err := http.DefaultClient.Get(downloadURL)
outFilePath, err := downloadFile(downloadURL, displayProgress)
if err != nil {
return "", "", err
}

if res.Body != nil {
defer res.Body.Close()
}

if res.StatusCode != http.StatusOK {
return "", "", fmt.Errorf("incorrect status for downloading tool: %d", res.StatusCode)
}

_, fileName := path.Split(downloadURL)
tmp := os.TempDir()

outFilePath := path.Join(tmp, fileName)

if tool.IsArchive() {
archiveFile, err := os.Open(outFilePath)
if err != nil {
return "", "", err
}

outFilePathDir := filepath.Dir(outFilePath)
if len(tool.BinaryTemplate) > 0 {
fileName, err = GetBinaryName(tool, strings.ToLower(operatingSystem), strings.ToLower(arch), version)
fileName, err := GetBinaryName(tool, strings.ToLower(operatingSystem), strings.ToLower(arch), version)
if err != nil {
return "", "", err
}
outFilePath = path.Join(outFilePathDir, fileName)
} else {
outFilePath = path.Join(outFilePathDir, tool.Name)
}

if strings.Contains(strings.ToLower(operatingSystem), "mingw") && tool.NoExtension == false {
outFilePath += ".exe"
}
r := ioutil.NopCloser(res.Body)

if strings.HasSuffix(downloadURL, "tar.gz") || strings.HasSuffix(downloadURL, "tgz") {
untarErr := archive.Untar(r, outFilePathDir)
untarErr := archive.Untar(archiveFile, outFilePathDir)
if untarErr != nil {
return "", "", untarErr
}
} else if strings.HasSuffix(downloadURL, "zip") {
buff := bytes.NewBuffer([]byte{})
size, err := io.Copy(buff, res.Body)
fInfo, err := archiveFile.Stat()
if err != nil {
return "", "", err
}

reader := bytes.NewReader(buff.Bytes())
fmt.Println("name", fInfo.Name(), "size: ", fInfo.Size())

unzipErr := archive.Unzip(reader, size, outFilePathDir)
unzipErr := archive.Unzip(archiveFile, fInfo.Size(), outFilePathDir)
if unzipErr != nil {
return "", "", unzipErr
}
}

} else {
out, err := os.Create(outFilePath)
if err != nil {
return "", "", err
}
defer out.Close()

if _, err = io.Copy(out, res.Body); err != nil {
return "", "", err
}
}

finalName := tool.Name
Expand All @@ -119,6 +98,39 @@ func Download(tool *Tool, arch, operatingSystem, version string, downloadMode in
return outFilePath, finalName, nil
}

func downloadFile(downloadURL string, displayProgress bool) (string, error) {
res, err := http.DefaultClient.Get(downloadURL)
if err != nil {
return "", err
}

if res.Body != nil {
defer res.Body.Close()
}

if res.StatusCode != http.StatusOK {
return "", fmt.Errorf("incorrect status for downloading tool: %d", res.StatusCode)
}

_, fileName := path.Split(downloadURL)
tmp := os.TempDir()
outFilePath := path.Join(tmp, fileName)
wrappedReader := withProgressBar(res.Body, int(res.ContentLength), displayProgress)
out, err := os.Create(outFilePath)
if err != nil {
return "", err
}

defer out.Close()
defer wrappedReader.Close()

if _, err := io.Copy(out, wrappedReader); err != nil {
return "", err
}

return outFilePath, nil
}

func copyFile(src, dst string) (int64, error) {
sourceFileStat, err := os.Stat(src)
if err != nil {
Expand All @@ -144,3 +156,12 @@ func copyFile(src, dst string) (int64, error) {
nBytes, err := io.Copy(destination, source)
return nBytes, err
}

func withProgressBar(r io.ReadCloser, length int, displayProgress bool) io.ReadCloser {
if !displayProgress {
return r
}

bar := pb.Simple.New(length).Start()
return bar.NewProxyReader(r)
}
2 changes: 1 addition & 1 deletion pkg/get/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"testing"
)

const faasCLIVersion = "0.12.9"
const faasCLIVersion = "0.12.13"
const arch64bit = "x86_64"
const archARM7 = "armv7l"

Expand Down
2 changes: 1 addition & 1 deletion pkg/helm/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func DownloadHelm(userPath, clientArch, clientOS, subdir string) error {

if _, err := os.Stat(fmt.Sprintf("%s", env.LocalBinary(tool.Name, ""))); errors.Is(err, os.ErrNotExist) {

outPath, finalName, err := get.Download(tool, clientArch, clientOS, tool.Version, get.DownloadArkadeDir)
outPath, finalName, err := get.Download(tool, clientArch, clientOS, tool.Version, get.DownloadArkadeDir, false)
if err != nil {
return err
}
Expand Down

0 comments on commit af87452

Please sign in to comment.