Skip to content

Commit b706d1b

Browse files
authored
feat: support to specific the format of target file (#364)
1 parent 844aa9b commit b706d1b

File tree

13 files changed

+141
-32
lines changed

13 files changed

+141
-32
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ build: fmt test
22
export GOPROXY=https://goproxy.io
33
CGO_ENABLE=0 go build -ldflags "-w -s" -o bin/hd
44

5+
build-windows:
6+
GOOS=windows CGO_ENABLE=0 go build -ldflags "-w -s" -o bin/windows/hd.exe
57
build-linux: fmt lint build-linux-no-check
68
build-linux-no-check:
79
export GOPROXY=https://goproxy.io

cmd/fetch.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ func newFetchCmd(context.Context) (cmd *cobra.Command) {
3434
"If you want to reset the hd-config which means delete and clone it again")
3535
flags.IntVarP(&opt.retry, "retry", "", 6, "Retry times due to timeout error")
3636
flags.DurationVarP(&opt.timeout, "timeout", "", time.Second*10, "Timeout of fetching")
37-
38-
_ = cmd.RegisterFlagCompletionFunc("provider", ArrayCompletion(ProviderGitHub, ProviderGitee))
3937
return
4038
}
4139

cmd/get.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,7 @@ func newGetCmd(ctx context.Context) (cmd *cobra.Command) {
6161
`The default timeout in seconds with the HTTP request`)
6262
flags.IntVarP(&opt.MaxAttempts, "max-attempts", "", 10,
6363
`Max times to attempt to download, zero means there's no retry action'`)
64-
flags.BoolVarP(&opt.NoProxy, "no-proxy", "", false, "Indicate no HTTP proxy taken")
65-
flags.BoolVarP(&opt.ShowProgress, "show-progress", "", true, "If show the progress of download")
6664
flags.Int64VarP(&opt.ContinueAt, "continue-at", "", -1, "ContinueAt")
67-
flags.IntVarP(&opt.Thread, "thread", "t", viper.GetInt("thread"),
68-
`Download file with multi-threads. It only works when its value is bigger than 1`)
6965
flags.BoolVarP(&opt.KeepPart, "keep-part", "", false,
7066
"If you want to keep the part files instead of deleting them")
7167
flags.BoolVarP(&opt.PrintSchema, "print-schema", "", false,
@@ -77,10 +73,7 @@ func newGetCmd(ctx context.Context) (cmd *cobra.Command) {
7773
flags.IntVarP(&opt.PrintVersionCount, "print-version-count", "", 20,
7874
"The number of the version list")
7975
flags.BoolVarP(&opt.Magnet, "magnet", "", false, "Fetch magnet list from a website")
80-
81-
_ = cmd.RegisterFlagCompletionFunc("proxy-github", ArrayCompletion("gh.api.99988866.xyz",
82-
"ghproxy.com", "mirror.ghproxy.com"))
83-
_ = cmd.RegisterFlagCompletionFunc("provider", ArrayCompletion(ProviderGitHub, ProviderGitee))
76+
flags.StringVarP(&opt.Format, "format", "", "", "Specific the file format, for instance: tar, zip, msi")
8477
return
8578
}
8679

@@ -111,6 +104,7 @@ type downloadOption struct {
111104
Force bool
112105
Mod int
113106
SkipTLS bool
107+
Format string
114108

115109
ContinueAt int64
116110

@@ -145,6 +139,10 @@ const (
145139
func (o *downloadOption) addDownloadFlags(flags *pflag.FlagSet) {
146140
flags.IntVarP(&o.Mod, "mod", "", -1, "The file permission, -1 means using the system default")
147141
flags.BoolVarP(&o.SkipTLS, "skip-tls", "k", false, "Skip the TLS")
142+
flags.BoolVarP(&o.ShowProgress, "show-progress", "", true, "If show the progress of download")
143+
flags.IntVarP(&o.Thread, "thread", "t", viper.GetInt("thread"),
144+
`Download file with multi-threads. It only works when its value is bigger than 1`)
145+
flags.BoolVarP(&o.NoProxy, "no-proxy", "", viper.GetBool("no-proxy"), "Indicate no HTTP proxy taken")
148146
}
149147

150148
func (o *downloadOption) fetch() (err error) {
@@ -195,7 +193,11 @@ func (o *downloadOption) preRunE(cmd *cobra.Command, args []string) (err error)
195193
}
196194

197195
targetURL := args[0]
198-
o.Package = &installer.HDConfig{}
196+
o.Package = &installer.HDConfig{
197+
FormatOverrides: installer.PackagingFormat{
198+
Format: o.Format,
199+
},
200+
}
199201
if o.Magnet || strings.HasPrefix(targetURL, "magnet:?") {
200202
// download via external tool
201203
o.URL = targetURL
@@ -206,6 +208,7 @@ func (o *downloadOption) preRunE(cmd *cobra.Command, args []string) (err error)
206208
OS: o.OS,
207209
Arch: o.Arch,
208210
Fetch: o.Fetch,
211+
Package: o.Package,
209212
}
210213
if targetURL, err = ins.ProviderURLParse(targetURL, o.AcceptPreRelease); err != nil {
211214
err = fmt.Errorf("only http:// or https:// supported, error: %v", err)
@@ -351,7 +354,6 @@ func (o *downloadOption) runE(cmd *cobra.Command, args []string) (err error) {
351354
}
352355
var yes bool
353356
if confirmErr := survey.AskOne(confirm, &yes); confirmErr == nil && yes {
354-
fmt.Println("rename")
355357
err = sysos.Rename(o.Output, suggested)
356358
}
357359
}

cmd/install.go

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ Cannot find your desired package? Please run command: hd fetch --reset, then try
4242
opt.addDownloadFlags(flags)
4343
flags.StringVarP(&opt.Category, "category", "c", "",
4444
"The category of the potentials packages")
45-
flags.BoolVarP(&opt.ShowProgress, "show-progress", "", true, "If show the progress of download")
4645
flags.BoolVarP(&opt.AcceptPreRelease, "accept-preRelease", "", false,
4746
"If you accept preRelease as the binary asset from GitHub")
4847
flags.BoolVarP(&opt.AcceptPreRelease, "pre", "", false,
@@ -61,13 +60,8 @@ Cannot find your desired package? Please run command: hd fetch --reset, then try
6160
"Indicate if force to download the package even it is exist")
6261
flags.BoolVarP(&opt.CleanPackage, "clean-package", "", true,
6362
"Clean the package if the installation is success")
64-
flags.IntVarP(&opt.Thread, "thread", "t", viper.GetInt("thread"),
65-
`Download file with multi-threads. It only works when its value is bigger than 1`)
66-
flags.BoolVarP(&opt.NoProxy, "no-proxy", "", viper.GetBool("no-proxy"), "Indicate no HTTP proxy taken")
6763
flags.BoolVarP(&opt.KeepPart, "keep-part", "", false,
6864
"If you want to keep the part files instead of deleting them")
69-
70-
_ = cmd.RegisterFlagCompletionFunc("provider", ArrayCompletion(ProviderGitHub, ProviderGitee))
7165
return
7266
}
7367

cmd/root.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,26 @@ func NewRoot(cxt context.Context) (cmd *cobra.Command) {
4747
newGetCmd(cxt), newInstallCmd(cxt), newFetchCmd(cxt), newSearchCmd(cxt), newSetupCommand(v, stdio),
4848
extver.NewVersionCmd("linuxsuren", "http-downloader", "hd", nil),
4949
extpkg.NewCompletionCmd(cmd))
50+
51+
for _, c := range cmd.Commands() {
52+
registerFlagCompletionFunc(c, "provider", ArrayCompletion(ProviderGitHub, ProviderGitee))
53+
registerFlagCompletionFunc(c, "proxy-github", ArrayCompletion("gh.api.99988866.xyz",
54+
"ghproxy.com", "mirror.ghproxy.com"))
55+
registerFlagCompletionFunc(c, "os", ArrayCompletion("window", "linux", "darwin"))
56+
registerFlagCompletionFunc(c, "arch", ArrayCompletion("amd64", "arm64"))
57+
registerFlagCompletionFunc(c, "format", ArrayCompletion("tar.gz", "zip", "msi"))
58+
}
5059
return
5160
}
5261

62+
func registerFlagCompletionFunc(cmd *cobra.Command, flag string, completionFunc CompletionFunc) {
63+
if p := cmd.Flag(flag); p != nil {
64+
if err := cmd.RegisterFlagCompletionFunc(flag, completionFunc); err != nil {
65+
cmd.Println(err)
66+
}
67+
}
68+
}
69+
5370
func loadConfig() (err error) {
5471
viper.SetConfigName("hd")
5572
viper.SetConfigType("yaml")

cmd/search.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"io"
77

88
"github.com/linuxsuren/http-downloader/pkg/installer"
9+
"github.com/linuxsuren/http-downloader/pkg/log"
910
"github.com/spf13/cobra"
1011
"github.com/spf13/pflag"
1112
"github.com/spf13/viper"
@@ -46,11 +47,13 @@ Thanks to https://github.com/hunshcn/gh-proxy`)
4647
}
4748

4849
func (s *searchOption) runE(c *cobra.Command, args []string) (err error) {
49-
err = search(args[0], s.Fetch, s.fetcher, c.OutOrStdout())
50+
logger := log.GetLoggerFromContextOrDefault(c)
51+
52+
err = search(args[0], s.Fetch, s.fetcher, c.OutOrStdout(), logger)
5053
return
5154
}
5255

53-
func search(keyword string, fetch bool, fetcher installer.Fetcher, writer io.Writer) (err error) {
56+
func search(keyword string, fetch bool, fetcher installer.Fetcher, writer io.Writer, logger *log.LevelLog) (err error) {
5457
if fetch {
5558
if err = fetcher.FetchLatestRepo("", "", writer); err != nil {
5659
return
@@ -62,6 +65,7 @@ func search(keyword string, fetch bool, fetcher installer.Fetcher, writer io.Wri
6265
return
6366
}
6467

68+
logger.Info("start to search in:", configDir)
6569
result := installer.FindByKeyword(keyword, configDir)
6670
for _, item := range result {
6771
fmt.Fprintln(writer, item)

cmd/search_test.go

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,24 @@ import (
99
"testing"
1010

1111
"github.com/linuxsuren/http-downloader/pkg/installer"
12+
"github.com/linuxsuren/http-downloader/pkg/log"
1213
"github.com/stretchr/testify/assert"
1314
)
1415

1516
func Test_search(t *testing.T) {
17+
logger := log.GetLogger()
18+
1619
buf := &bytes.Buffer{}
17-
err := search("keyword", true, &installer.FakeFetcher{}, buf)
20+
err := search("keyword", true, &installer.FakeFetcher{}, buf, logger)
1821
assert.Nil(t, err)
1922
assert.Empty(t, buf.String())
2023

2124
// expect an error with GetConfigDir
22-
err = search("", true, &installer.FakeFetcher{GetConfigDirErr: errors.New("fake")}, buf)
25+
err = search("", true, &installer.FakeFetcher{GetConfigDirErr: errors.New("fake")}, buf, logger)
2326
assert.NotNil(t, err)
2427

2528
// expect an error with FetchLatestRepo
26-
err = search("", true, &installer.FakeFetcher{FetchLatestRepoErr: errors.New("fake")}, buf)
29+
err = search("", true, &installer.FakeFetcher{FetchLatestRepoErr: errors.New("fake")}, buf, logger)
2730
assert.NotNil(t, err)
2831

2932
tempDir, err := os.MkdirTemp("", "config")
@@ -41,7 +44,7 @@ func Test_search(t *testing.T) {
4144
err = os.WriteFile(path.Join(orgDir, "fake.yml"), []byte{}, os.ModeAppend)
4245
assert.Nil(t, err)
4346

44-
err = search("repo", true, &installer.FakeFetcher{ConfigDir: tempDir}, buf)
47+
err = search("repo", true, &installer.FakeFetcher{ConfigDir: tempDir}, buf, logger)
4548
assert.Nil(t, err)
4649
}
4750

cmd/setup.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77

88
"github.com/AlecAivazis/survey/v2"
99
"github.com/AlecAivazis/survey/v2/terminal"
10+
"github.com/linuxsuren/http-downloader/pkg/installer"
1011
"github.com/spf13/cobra"
1112
"github.com/spf13/viper"
1213
)
@@ -52,7 +53,11 @@ func (o *setupOption) runE(cmd *cobra.Command, args []string) (err error) {
5253
return
5354
}
5455

55-
configDir := os.ExpandEnv("$HOME/.config")
56+
var configDir string
57+
fetcher := &installer.DefaultFetcher{}
58+
if configDir, err = fetcher.GetConfigDir(); err != nil {
59+
return
60+
}
5661
if err = os.MkdirAll(configDir, 0750); err != nil {
5762
err = fmt.Errorf("failed to create directory: %s, error: %v", configDir, err)
5863
return

pkg/installer/check.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,13 @@ func (o *Installer) GetVersion(path string) (version string, err error) {
168168
return
169169
}
170170

171-
func getOrgAndRepo(orgAndRepo string) (string, string) {
172-
return strings.Split(orgAndRepo, "/")[0], strings.Split(orgAndRepo, "/")[1]
171+
func getOrgAndRepo(orgAndRepo string) (org string, repo string) {
172+
items := strings.Split(orgAndRepo, "/")
173+
if len(items) >= 2 {
174+
org = items[0]
175+
repo = items[1]
176+
}
177+
return
173178
}
174179

175180
// ProviderURLParse parse the URL
@@ -217,6 +222,7 @@ func (o *Installer) ProviderURLParse(path string, acceptPreRelease bool) (packag
217222
}
218223
cfg.Org = o.Org
219224
cfg.Repo = o.Repo
225+
cfg.FormatOverrides.Format = o.Package.FormatOverrides.Format
220226
o.Package = &cfg
221227
o.AdditionBinaries = cfg.AdditionBinaries
222228
o.Tar = cfg.Tar != "false"
@@ -481,14 +487,17 @@ func chooseOneFromArray(options []string) (result string, err error) {
481487
}
482488

483489
func getPackagingFormat(installer *Installer) string {
490+
if installer.Package != nil && installer.Package.FormatOverrides.Format != "" {
491+
return installer.Package.FormatOverrides.Format
492+
}
484493
platformType := strings.ToLower(installer.OS)
485494
if platformType == "windows" {
486-
if installer.Package != nil {
495+
if installer.Package != nil && installer.Package.FormatOverrides.Windows != "" {
487496
return installer.Package.FormatOverrides.Windows
488497
}
489498
return "zip"
490499
}
491-
if installer.Package != nil {
500+
if installer.Package != nil && installer.Package.FormatOverrides.Linux != "" {
492501
return installer.Package.FormatOverrides.Linux
493502
}
494503
return "tar.gz"

pkg/installer/check_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,3 +507,65 @@ func Test_getVersionOrDefault(t *testing.T) {
507507
})
508508
}
509509
}
510+
511+
func TestGetPackagingFormat(t *testing.T) {
512+
tests := []struct {
513+
name string
514+
installer *Installer
515+
expect string
516+
}{{
517+
name: "have specific format",
518+
installer: &Installer{
519+
OS: "Darwin",
520+
Package: &HDConfig{
521+
FormatOverrides: PackagingFormat{
522+
Format: "msi",
523+
},
524+
},
525+
},
526+
expect: "msi",
527+
}, {
528+
name: "windows with config",
529+
installer: &Installer{
530+
OS: "Windows",
531+
Package: &HDConfig{
532+
FormatOverrides: PackagingFormat{
533+
Windows: "msi",
534+
},
535+
},
536+
},
537+
expect: "msi",
538+
}, {
539+
name: "windows without config",
540+
installer: &Installer{
541+
OS: "Windows",
542+
},
543+
expect: "zip",
544+
}, {
545+
name: "darwin without config",
546+
installer: &Installer{},
547+
expect: "tar.gz",
548+
}, {
549+
name: "linux, and package is not nil, but the override is empty",
550+
installer: &Installer{
551+
Package: &HDConfig{},
552+
},
553+
expect: "tar.gz",
554+
}, {
555+
name: "linux with override",
556+
installer: &Installer{
557+
Package: &HDConfig{
558+
FormatOverrides: PackagingFormat{
559+
Linux: "tar.gz",
560+
},
561+
},
562+
},
563+
expect: "tar.gz",
564+
}}
565+
for _, tt := range tests {
566+
t.Run(tt.name, func(t *testing.T) {
567+
result := getPackagingFormat(tt.installer)
568+
assert.Equal(t, tt.expect, result)
569+
})
570+
}
571+
}

0 commit comments

Comments
 (0)