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

feat: per OS/arch archive exe path #22

Merged
merged 1 commit into from
Nov 16, 2023
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ with the same one command for multiple OS/architectures.
```shellsession
$ wrun -help
Usage of wrun:
-archive-exe-path string
Path to executable within archive (separator always /, implies archive processing)
-archive-exe-path value
[<OS>/<architecture>=]path to executable within archive (separator always /, implies archive processing)
-http-timeout duration
HTTP client timeout (default 5m0s)
-url value
Expand Down
59 changes: 50 additions & 9 deletions wrun.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,11 +117,16 @@ type urlMatch struct {
url *url.URL
}

type archiveExePathMatch struct {
pattern string
exePath string
}

type config struct {
urlMatches []urlMatch
archiveExePath string
usePreCommitCache bool
httpTimeout time.Duration
urlMatches []urlMatch
archiveExePathMatches []archiveExePathMatch
usePreCommitCache bool
httpTimeout time.Duration
}

// parseFlags parses command line flags using the given flag set.
Expand Down Expand Up @@ -149,7 +154,22 @@ func parseFlags(set *flag.FlagSet, args []string) (config, error) {
return nil
}
})
set.StringVar(&cfg.archiveExePath, "archive-exe-path", "", "Path to executable within archive (separator always /, implies archive processing)")
set.Func("archive-exe-path", "[<OS>/<architecture>=]path to executable within archive (separator always /, implies archive processing)", func(s string) error {
pattern, pth, found := strings.Cut(s, "=")
if found {
if pattern == "" {
pattern = "*/*"
}
if pth == "" {
return fmt.Errorf("missing path in %q", s)
}
} else {
pth = pattern
pattern = "*/*"
}
cfg.archiveExePathMatches = append(cfg.archiveExePathMatches, archiveExePathMatch{pattern, pth})
return nil
})
set.BoolVar(&cfg.usePreCommitCache, "use-pre-commit-cache", false, "Use pre-commit's cache dir")
set.DurationVar(&cfg.httpTimeout, "http-timeout", defaultHttpTimeout, "HTTP client timeout")
if err := set.Parse(args); err != nil {
Expand All @@ -172,6 +192,20 @@ func selectURL(s string, matches []urlMatch) (*url.URL, error) {
return nil, nil
}

// selectArchiveExePath selects an archive exe path for a system from the given matches.
func selectArchiveExePath(s string, matches []archiveExePathMatch) (string, error) {
for _, m := range matches {
match, err := filepath.Match(m.pattern, s)
if err != nil {
return "", err
}
if match {
return m.exePath, nil
}
}
return "", nil
}

func resolveCacheDir(usePreCommitCache bool) (string, error) {
var (
cacheDir string
Expand Down Expand Up @@ -276,7 +310,7 @@ Environment variables:
return
}

// Figure out download URL
// Figure out download URL and exe path in archive

osArch := runtime.GOOS + "/" + runtime.GOARCH
ur, err := selectURL(osArch, cfg.urlMatches)
Expand All @@ -292,6 +326,13 @@ Environment variables:
}
infoOut("URL: %s", ur)

archiveExePath, err := selectArchiveExePath(osArch, cfg.archiveExePathMatches)
if err != nil {
errorOut("select archive exe path: %v", err)
rc = 2 // usage, bad pattern
return
}

// Set up hashing

hshType, expectedDigest, err := prepareHash(ur.Fragment)
Expand All @@ -311,11 +352,11 @@ Environment variables:
return
}
// Here's hoping we don't hit path too long errors with this implementation anywhere
ps := make([]string, 0, strings.Count(cfg.archiveExePath, "/")+3)
ps := make([]string, 0, strings.Count(archiveExePath, "/")+3)
_, dlBase := path.Split(ur.Path)
ps = append(ps, cacheDir, urlDir(ur, hshType, expectedDigest), dlBase)
dlPath := filepath.Join(ps...)
ps = append(ps, strings.Split(cfg.archiveExePath, "/")...)
ps = append(ps, strings.Split(archiveExePath, "/")...)
exePath := filepath.Join(ps...)
err = os.MkdirAll(filepath.Dir(exePath), 0o777)
if err != nil {
Expand Down Expand Up @@ -430,7 +471,7 @@ Environment variables:

// Move to final location, make executable

if cfg.archiveExePath == "" {
if archiveExePath == "" {
if err = os.Rename(tmpf.Name(), exePath); err != nil {
errorOut("rename tempfile: %v", err)
rc = 1
Expand Down
4 changes: 2 additions & 2 deletions wrun_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,8 @@ func Test_parseFlags(t *testing.T) {
url: mustParseURL(t, urld),
},
},
archiveExePath: "",
httpTimeout: defaultHttpTimeout,
archiveExePathMatches: nil,
httpTimeout: defaultHttpTimeout,
}
got, err := parseFlags(set, args)
require.NoError(t, err)
Expand Down