Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to parse URL from hd-home #10

Merged
merged 6 commits into from Jan 30, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/.typo-ci.yml
@@ -0,0 +1,16 @@
dictionaries:
- en
- en_GB
exclude_fiels:
- ".github/**/*"
- "go.mod"
- "go.sum"
- Makefile
excluded_words:
- KubeSphere
- kubespheredev
- minio
- jcli
- ioutil
- Unmarshal
- Errorf
5 changes: 5 additions & 0 deletions Makefile
Expand Up @@ -2,6 +2,11 @@ build: fmt
export GOPROXY=https://goproxy.io
CGO_ENABLE=0 go build -ldflags "-w -s" -o bin/hd

build-linux: fmt
export GOPROXY=https://goproxy.io
CGO_ENABLE=0 GOOS=linux go build -ldflags "-w -s" -o bin/linux/hd
upx bin/linux/hd

run:
go run main.go

Expand Down
94 changes: 94 additions & 0 deletions cmd/get.go
@@ -1,13 +1,19 @@
package cmd

import (
"bytes"
"fmt"
"github.com/ghodss/yaml"
"github.com/linuxsuren/http-downloader/pkg"
"github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"io/ioutil"
"net/url"
"os"
"path"
"runtime"
"strings"
"text/template"
)

// NewGetCmd return the get command
Expand Down Expand Up @@ -52,6 +58,7 @@ type downloadOption struct {

// inner fields
name string
Tar bool
}

const (
Expand Down Expand Up @@ -102,9 +109,72 @@ func (o *downloadOption) providerURLParse(path string) (url string, err error) {
org, repo, version, name, o.OS, o.Arch)
}
o.name = name

// try to parse from config
userHome, _ := homedir.Dir()
configDir := userHome + "/.config/hd-home"
matchedFile := configDir + "/config/" + org + "/" + repo + ".yml"
if ok, _ := pathExists(matchedFile); ok {
var data []byte
if data, err = ioutil.ReadFile(matchedFile); err == nil {
cfg := hdConfig{}

if err = yaml.Unmarshal(data, &cfg); err == nil {
hdPackage := &hdPackage{
Name: o.name,
Version: version,
OS: runtime.GOOS,
Arch: runtime.GOARCH,
}
if version == "latest" {
ghClient := pkg.ReleaseClient{
Org: org,
Repo: repo,
}
ghClient.Init()
if asset, err := ghClient.GetLatestJCLIAsset(); err == nil {
hdPackage.Version = asset.TagName
} else {
fmt.Println(err, "cannot get the asset")
}
}

if cfg.Filename != "" {
tmp, _ := template.New("hd").Parse(cfg.Filename)

var buf bytes.Buffer
if err = tmp.Execute(&buf, hdPackage); err == nil {
url = fmt.Sprintf("https://github.com/%s/%s/releases/%s/download/%s",
org, repo, version, buf.String())

o.Output = buf.String()
}
}

o.Tar = cfg.Tar
if cfg.Binary != "" {
o.name = cfg.Binary
}
}
}
}
return
}

type hdConfig struct {
Name string
Filename string
Binary string
Tar bool
}

type hdPackage struct {
Name string
Version string
OS string
Arch string
}

func (o *downloadOption) preRunE(cmd *cobra.Command, args []string) (err error) {
if len(args) <= 0 {
return fmt.Errorf("no URL provided")
Expand Down Expand Up @@ -143,3 +213,27 @@ func (o *downloadOption) runE(cmd *cobra.Command, args []string) (err error) {
}
return
}

func (o *downloadOption) fetchHomeConfig() (err error) {
userHome, _ := homedir.Dir()
configDir := userHome + "/.config/hd-home"
if ok, _ := pathExists(configDir); ok {
err = execCommand("git", "pull", "-C", configDir)
} else {
if err = os.MkdirAll(configDir, 0644); err == nil {
err = execCommand("git", "clone", "https://github.com/LinuxSuRen/hd-home", configDir)
}
}
return
}

func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
40 changes: 35 additions & 5 deletions cmd/install.go
Expand Up @@ -27,7 +27,7 @@ func NewInstallCmd() (cmd *cobra.Command) {
//flags.StringVarP(&opt.Mode, "mode", "m", "package",
// "If you want to install it via platform package manager")
flags.BoolVarP(&opt.ShowProgress, "show-progress", "", true, "If show the progress of download")
flags.IntVarP(&opt.Thread, "thread", "t", 0,
flags.IntVarP(&opt.Thread, "thread", "t", 4,
`Download file with multi-threads. It only works when its value is bigger than 1`)
flags.BoolVarP(&opt.KeepPart, "keep-part", "", false,
"If you want to keep the part files instead of deleting them")
Expand All @@ -42,22 +42,52 @@ type installOption struct {
Mode string
}

func (o *installOption) preRunE(cmd *cobra.Command, args []string) (err error) {
if err = o.fetchHomeConfig(); err != nil {
// this is not a fatal, don't block the process
cmd.Printf("Failed with fetching home config: %v\n", err)
}
err = o.downloadOption.preRunE(cmd, args)
return
}

func (o *installOption) runE(cmd *cobra.Command, args []string) (err error) {
if err = o.downloadOption.runE(cmd, args); err != nil {
return
}

if err = o.extractFiles(o.Output, o.name); err == nil {
err = o.overWriteBinary(fmt.Sprintf("%s/%s", filepath.Dir(o.Output), o.name), fmt.Sprintf("/usr/local/bin/%s", o.name))
var source string
var target string
if o.Tar {
if err = o.extractFiles(o.Output, o.name); err == nil {
source = fmt.Sprintf("%s/%s", filepath.Dir(o.Output), o.name)
target = fmt.Sprintf("/usr/local/bin/%s", o.name)
} else {
err = fmt.Errorf("cannot extract %s from tar file, error: %v", o.Output, err)
}
} else {
err = fmt.Errorf("cannot extract %s from tar file, error: %v", o.Output, err)
source = o.downloadOption.Output
target = fmt.Sprintf("/usr/local/bin/%s", o.name)
}

if err == nil {
fmt.Println("install", source, "to", target)
err = o.overWriteBinary(source, target)
}
return
}

func (o *installOption) overWriteBinary(sourceFile, targetPath string) (err error) {
switch runtime.GOOS {
case "linux":
case "linux", "darwin":
if err = execCommand("chmod", "u+x", sourceFile); err != nil {
return
}

if err = execCommand("rm", "-rf", targetPath); err != nil {
return
}

var cp string
if cp, err = exec.LookPath("cp"); err == nil {
err = syscall.Exec(cp, []string{"cp", sourceFile, targetPath}, os.Environ())
Expand Down
3 changes: 3 additions & 0 deletions go.mod
Expand Up @@ -3,9 +3,12 @@ module github.com/linuxsuren/http-downloader
go 1.15

require (
github.com/ghodss/yaml v1.0.0
github.com/golang/mock v1.4.4
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/mitchellh/go-homedir v1.1.0
github.com/onsi/ginkgo v1.14.2
github.com/onsi/gomega v1.10.4
github.com/spf13/cobra v1.1.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Expand Up @@ -55,6 +55,7 @@ github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
Expand Down Expand Up @@ -180,6 +181,7 @@ github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyex
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
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/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
Expand Down
71 changes: 71 additions & 0 deletions pkg/release.go
@@ -0,0 +1,71 @@
package pkg

import (
"context"
"github.com/google/go-github/v29/github"
)

// ReleaseClient is the client of jcli github
type ReleaseClient struct {
Client *github.Client
Org string
Repo string
}

// ReleaseAsset is the asset from GitHub release
type ReleaseAsset struct {
TagName string
Body string
}

// Init init the GitHub client
func (g *ReleaseClient) Init() {
g.Client = github.NewClient(nil)
}

// GetLatestJCLIAsset returns the latest jcli asset
func (g *ReleaseClient) GetLatestJCLIAsset() (*ReleaseAsset, error) {
return g.GetLatestReleaseAsset(g.Org, g.Repo)
}

// GetLatestReleaseAsset returns the latest release asset
func (g *ReleaseClient) GetLatestReleaseAsset(owner, repo string) (ra *ReleaseAsset, err error) {
ctx := context.Background()

var release *github.RepositoryRelease
if release, _, err = g.Client.Repositories.GetLatestRelease(ctx, owner, repo); err == nil {
ra = &ReleaseAsset{
TagName: release.GetTagName(),
Body: release.GetBody(),
}
}
return
}

// GetJCLIAsset returns the asset from a tag name
func (g *ReleaseClient) GetJCLIAsset(tagName string) (*ReleaseAsset, error) {
return g.GetReleaseAssetByTagName(g.Org, g.Repo, tagName)
}

// GetReleaseAssetByTagName returns the release asset by tag name
func (g *ReleaseClient) GetReleaseAssetByTagName(owner, repo, tagName string) (ra *ReleaseAsset, err error) {
ctx := context.Background()

opt := &github.ListOptions{
PerPage: 99999,
}

var releaseList []*github.RepositoryRelease
if releaseList, _, err = g.Client.Repositories.ListReleases(ctx, owner, repo, opt); err == nil {
for _, item := range releaseList {
if item.GetTagName() == tagName {
ra = &ReleaseAsset{
TagName: item.GetTagName(),
Body: item.GetBody(),
}
break
}
}
}
return
}