diff --git a/Makefile b/Makefile index ed20992..f934e01 100644 --- a/Makefile +++ b/Makefile @@ -1,12 +1,15 @@ -build: fmt +build: fmt test export GOPROXY=https://goproxy.io CGO_ENABLE=0 go build -ldflags "-w -s" -o bin/hd -build-linux: fmt +build-linux: fmt test export GOPROXY=https://goproxy.io CGO_ENABLE=0 GOOS=linux go build -ldflags "-w -s" -o bin/linux/hd upx bin/linux/hd +test: + go test ./cmd/... + run: go run main.go diff --git a/cmd/get.go b/cmd/get.go index 5a8232d..28145c4 100644 --- a/cmd/get.go +++ b/cmd/get.go @@ -121,11 +121,13 @@ func (o *downloadOption) providerURLParse(path string) (url string, err error) { if err = yaml.Unmarshal(data, &cfg); err == nil { hdPackage := &hdPackage{ - Name: o.name, - Version: version, - OS: runtime.GOOS, - Arch: runtime.GOARCH, + Name: o.name, + Version: version, + OS: getReplacement(runtime.GOOS, cfg.Replacements), + Arch: getReplacement(runtime.GOARCH, cfg.Replacements), + VersionNum: strings.TrimPrefix(version, "v"), } + if version == "latest" { ghClient := pkg.ReleaseClient{ Org: org, @@ -134,6 +136,7 @@ func (o *downloadOption) providerURLParse(path string) (url string, err error) { ghClient.Init() if asset, err := ghClient.GetLatestJCLIAsset(); err == nil { hdPackage.Version = asset.TagName + hdPackage.VersionNum = strings.TrimPrefix(asset.TagName, "v") } else { fmt.Println(err, "cannot get the asset") } @@ -148,10 +151,12 @@ func (o *downloadOption) providerURLParse(path string) (url string, err error) { org, repo, version, buf.String()) o.Output = buf.String() + } else { + return } } - o.Tar = cfg.Tar + o.Tar = cfg.Tar != "false" if cfg.Binary != "" { o.name = cfg.Binary } @@ -162,17 +167,19 @@ func (o *downloadOption) providerURLParse(path string) (url string, err error) { } type hdConfig struct { - Name string - Filename string - Binary string - Tar bool + Name string + Filename string + Binary string + Tar string + Replacements map[string]string } type hdPackage struct { - Name string - Version string - OS string - Arch string + Name string + Version string // e.g. v1.0.1 + VersionNum string // e.g. 1.0.1 + OS string // e.g. linux, darwin + Arch string // e.g. amd64 } func (o *downloadOption) preRunE(cmd *cobra.Command, args []string) (err error) { diff --git a/cmd/install.go b/cmd/install.go index 6c14d01..375dc53 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -10,6 +10,7 @@ import ( "os/exec" "path/filepath" "runtime" + "strings" "sync" "syscall" ) @@ -118,6 +119,7 @@ func (o *installOption) extractFiles(tarFile, targetName string) (err error) { tarReader := tar.NewReader(gzf) var header *tar.Header + var found bool for { if header, err = tarReader.Next(); err == io.EOF { err = nil @@ -129,20 +131,26 @@ func (o *installOption) extractFiles(tarFile, targetName string) (err error) { switch header.Typeflag { case tar.TypeReg: - if name != targetName { + if name != targetName && !strings.HasSuffix(name, "/"+targetName) { continue } var targetFile *os.File - if targetFile, err = os.OpenFile(fmt.Sprintf("%s/%s", filepath.Dir(tarFile), name), + if targetFile, err = os.OpenFile(fmt.Sprintf("%s/%s", filepath.Dir(tarFile), targetName), os.O_CREATE|os.O_RDWR, os.FileMode(header.Mode)); err != nil { break } if _, err = io.Copy(targetFile, tarReader); err != nil { break } + fmt.Println("found ", targetName, header) + found = true _ = targetFile.Close() } } + + if err == nil && !found { + err = fmt.Errorf("cannot found item '%s' from '%s'", targetName, tarFile) + } return } diff --git a/cmd/util.go b/cmd/util.go new file mode 100644 index 0000000..c24bcc4 --- /dev/null +++ b/cmd/util.go @@ -0,0 +1,13 @@ +package cmd + +func getOrDefault(key, def string, data map[string]string) (result string) { + var ok bool + if result, ok = data[key]; !ok { + result = def + } + return +} + +func getReplacement(key string, data map[string]string) (result string) { + return getOrDefault(key, key, data) +} diff --git a/cmd/util_test.go b/cmd/util_test.go new file mode 100644 index 0000000..061db1a --- /dev/null +++ b/cmd/util_test.go @@ -0,0 +1,44 @@ +package cmd + +import ( + "fmt" + "github.com/magiconair/properties/assert" + "testing" +) + +func TestGetOrDefault(t *testing.T) { + table := []testCase{ + {key: "fake", def: "def", data: map[string]string{}, expected: "def"}, + {key: "fake", def: "def", data: nil, expected: "def"}, + {key: "fake", def: "def", data: map[string]string{ + "fake": "good", + }, expected: "good"}, + } + + for index, item := range table { + result := getOrDefault(item.key, item.def, item.data) + assert.Equal(t, result, item.expected, fmt.Sprintf("test failed with '%d'", index)) + } +} + +func TestGetReplacement(t *testing.T) { + table := []testCase{ + {key: "fake", data: map[string]string{}, expected: "fake"}, + {key: "fake", data: nil, expected: "fake"}, + {key: "fake", data: map[string]string{ + "fake": "good", + }, expected: "good"}, + } + + for index, item := range table { + result := getReplacement(item.key, item.data) + assert.Equal(t, result, item.expected, fmt.Sprintf("test failed with '%d'", index)) + } +} + +type testCase struct { + key string + def string + data map[string]string + expected string +} diff --git a/go.mod b/go.mod index 2f11b30..6177557 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,7 @@ require ( github.com/google/go-github/v29 v29.0.3 github.com/gosuri/uiprogress v0.0.1 github.com/linuxsuren/cobra-extension v0.0.10 + github.com/magiconair/properties v1.8.1 github.com/mitchellh/go-homedir v1.1.0 github.com/onsi/ginkgo v1.14.2 github.com/onsi/gomega v1.10.4 diff --git a/go.sum b/go.sum index f67fd54..f56c694 100644 --- a/go.sum +++ b/go.sum @@ -168,6 +168,7 @@ github.com/linuxsuren/cobra-extension v0.0.10/go.mod h1:nDsXgvm0lSWVV+byAEfwhIGF github.com/linuxsuren/http-downloader v0.0.2-0.20201207132639-19888a6beaec/go.mod h1:zRZY9FCDBuYNDxbI2Ny5suasZsMk7J6q9ecQ3V3PIqI= github.com/linuxsuren/http-downloader v0.0.6/go.mod h1:xxgh2OE7WGL9TwDE9L8Gh7Lqq9fFPuHbh5tofUitEfE= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= +github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=