From 36bdf3249af53996132f9e969a29c1af3263d68f Mon Sep 17 00:00:00 2001 From: Ryan Fowler Date: Mon, 26 Jan 2026 18:13:00 -0800 Subject: [PATCH] Force required dependencies for runtime flags --- integration/integration_test.go | 2 +- internal/aws/sigv4.go | 12 ++-- internal/cli/app.go | 85 ++++++++++++++-------------- internal/cli/cli.go | 29 +++++++++- internal/cli/errors.go | 46 +++++++++++++++ internal/client/client.go | 8 +-- internal/complete/complete.go | 32 +++++------ internal/complete/shells.go | 6 +- internal/config/config.go | 8 +-- internal/core/core.go | 5 +- internal/fetch/fetch.go | 20 +++---- internal/fetch/print.go | 8 +-- internal/multipart/multipart.go | 2 +- internal/multipart/multipart_test.go | 10 ++-- main.go | 7 --- 15 files changed, 175 insertions(+), 105 deletions(-) diff --git a/integration/integration_test.go b/integration/integration_test.go index e1561c2..0112a01 100644 --- a/integration/integration_test.go +++ b/integration/integration_test.go @@ -557,7 +557,7 @@ func TestMain(t *testing.T) { t.Run("remote-header-name requires remote-name", func(t *testing.T) { res := runFetch(t, fetchPath, "http://example.com", "-J") assertExitCode(t, 1, res) - assertBufContains(t, res.stderr, "--remote-header-name (-J) requires --remote-name (-O)") + assertBufContains(t, res.stderr, "flag '--remote-header-name' requires '--remote-name'") }) t.Run("file exists error", func(t *testing.T) { diff --git a/internal/aws/sigv4.go b/internal/aws/sigv4.go index 9a72df7..50bb4ae 100644 --- a/internal/aws/sigv4.go +++ b/internal/aws/sigv4.go @@ -130,12 +130,12 @@ func getPayloadHash(req *http.Request, service string) (string, error) { return hexSha256Reader(bytes.NewReader(body)) } -func getSignedHeaders(req *http.Request) []core.KeyVal { - out := make([]core.KeyVal, 0, len(req.Header)+1) +func getSignedHeaders(req *http.Request) []core.KeyVal[string] { + out := make([]core.KeyVal[string], 0, len(req.Header)+1) // Host header is required to be signed. if _, ok := req.Header["Host"]; !ok { - out = append(out, core.KeyVal{Key: "host", Val: req.URL.Host}) + out = append(out, core.KeyVal[string]{Key: "host", Val: req.URL.Host}) } for key, vals := range req.Header { @@ -146,16 +146,16 @@ func getSignedHeaders(req *http.Request) []core.KeyVal { } key = strings.ToLower(strings.TrimSpace(key)) val := strings.TrimSpace(strings.Join(vals, ",")) - out = append(out, core.KeyVal{Key: key, Val: val}) + out = append(out, core.KeyVal[string]{Key: key, Val: val}) } // Headers should be ordered by key. - slices.SortFunc(out, func(a, b core.KeyVal) int { + slices.SortFunc(out, func(a, b core.KeyVal[string]) int { return strings.Compare(a.Key, b.Key) }) return out } -func buildCanonicalRequest(req *http.Request, headers []core.KeyVal, payload string) []byte { +func buildCanonicalRequest(req *http.Request, headers []core.KeyVal[string], payload string) []byte { var buf bytes.Buffer buf.Grow(512) diff --git a/internal/cli/app.go b/internal/cli/app.go index 68913c9..ef17162 100644 --- a/internal/cli/app.go +++ b/internal/cli/app.go @@ -21,7 +21,7 @@ type App struct { Cfg config.Config AWSSigv4 *aws.Config - Basic *core.KeyVal + Basic *core.KeyVal[string] Bearer string BuildInfo bool Clobber bool @@ -31,10 +31,10 @@ type App struct { Data io.Reader DryRun bool Edit bool - Form []core.KeyVal + Form []core.KeyVal[string] Help bool Method string - Multipart []core.KeyVal + Multipart []core.KeyVal[string] Output string Range []string RemoteHeaderName bool @@ -103,6 +103,9 @@ func (a *App) CLI() *CLI { {"data", "form", "json", "multipart", "xml"}, {"output", "remote-name"}, }, + RequiredFlags: []core.KeyVal[[]string]{ + {Key: "remote-header-name", Val: []string{"remote-name"}}, + }, Flags: []Flag{ { Short: "", @@ -167,7 +170,7 @@ func (a *App) CLI() *CLI { const usage = "format must be " return core.NewValueError("basic", value, usage, false) } - a.Basic = &core.KeyVal{Key: user, Val: pass} + a.Basic = &core.KeyVal[string]{Key: user, Val: pass} return nil }, }, @@ -219,7 +222,7 @@ func (a *App) CLI() *CLI { Description: "Enable/disable color", Default: "", Aliases: []string{"colour"}, - Values: []core.KeyVal{ + Values: []core.KeyVal[string]{ { Key: "auto", Val: "Automatically determine color", @@ -260,7 +263,7 @@ func (a *App) CLI() *CLI { Args: "SHELL", Description: "Output shell completion", Default: "", - Values: []core.KeyVal{ + Values: []core.KeyVal[string]{ {Key: "fish"}, {Key: "zsh"}, }, @@ -361,7 +364,7 @@ func (a *App) CLI() *CLI { }, Fn: func(value string) error { key, val, _ := cut(value, "=") - a.Form = append(a.Form, core.KeyVal{Key: key, Val: val}) + a.Form = append(a.Form, core.KeyVal[string]{Key: key, Val: val}) return nil }, }, @@ -371,7 +374,7 @@ func (a *App) CLI() *CLI { Args: "OPTION", Description: "Enable/disable formatting", Default: "", - Values: []core.KeyVal{ + Values: []core.KeyVal[string]{ { Key: "auto", Val: "Automatically determine whether to format", @@ -425,7 +428,7 @@ func (a *App) CLI() *CLI { Args: "VERSION", Description: "HTTP version to use", Default: "", - Values: []core.KeyVal{ + Values: []core.KeyVal[string]{ { Key: "1", Val: "HTTP/1.1", @@ -467,7 +470,7 @@ func (a *App) CLI() *CLI { Args: "OPTION", Description: "Image rendering", Default: "", - Values: []core.KeyVal{ + Values: []core.KeyVal[string]{ { Key: "auto", Val: "Automatically decide image display", @@ -574,7 +577,7 @@ func (a *App) CLI() *CLI { return fmt.Errorf("file is a directory: '%s'", path) } } - a.Multipart = append(a.Multipart, core.KeyVal{Key: key, Val: val}) + a.Multipart = append(a.Multipart, core.KeyVal[string]{Key: key, Val: val}) return nil }, }, @@ -622,35 +625,6 @@ func (a *App) CLI() *CLI { return nil }, }, - { - Short: "O", - Long: "remote-name", - Aliases: []string{"output-current-dir"}, - Args: "", - Description: "Use URL path component as output filename", - Default: "", - IsSet: func() bool { - return a.RemoteName - }, - Fn: func(value string) error { - a.RemoteName = true - return nil - }, - }, - { - Short: "J", - Long: "remote-header-name", - Args: "", - Description: "Use content-disposition header filename", - Default: "", - IsSet: func() bool { - return a.RemoteHeaderName - }, - Fn: func(value string) error { - a.RemoteHeaderName = true - return nil - }, - }, { Short: "", Long: "proxy", @@ -721,6 +695,35 @@ func (a *App) CLI() *CLI { return a.Cfg.ParseRedirects(value) }, }, + { + Short: "J", + Long: "remote-header-name", + Args: "", + Description: "Use content-disposition header filename", + Default: "", + IsSet: func() bool { + return a.RemoteHeaderName + }, + Fn: func(value string) error { + a.RemoteHeaderName = true + return nil + }, + }, + { + Short: "O", + Long: "remote-name", + Aliases: []string{"output-current-dir"}, + Args: "", + Description: "Use URL path component as output filename", + Default: "", + IsSet: func() bool { + return a.RemoteName + }, + Fn: func(value string) error { + a.RemoteName = true + return nil + }, + }, { Short: "s", Long: "silent", @@ -755,7 +758,7 @@ func (a *App) CLI() *CLI { Args: "VERSION", Description: "Minimum TLS version", Default: "", - Values: []core.KeyVal{ + Values: []core.KeyVal[string]{ { Key: "1.0", Val: "TLS v1.0", diff --git a/internal/cli/cli.go b/internal/cli/cli.go index af5dcdc..0af42da 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -17,6 +17,7 @@ type CLI struct { Args []Arguments Flags []Flag ExclusiveFlags [][]string + RequiredFlags []core.KeyVal[[]string] } type Arguments struct { @@ -31,7 +32,7 @@ type Flag struct { Args string Description string Default string - Values []core.KeyVal + Values []core.KeyVal[string] HideValues bool IsHidden bool IsSet func() bool @@ -128,6 +129,14 @@ func parse(cli *CLI, args []string) error { } } + // Check required flags. + for _, req := range cli.RequiredFlags { + err = validateRequired(req, long) + if err != nil { + return err + } + } + return nil } @@ -219,6 +228,24 @@ func validateExclusives(exc []string, long map[string]Flag) error { return nil } +func validateRequired(req core.KeyVal[[]string], long map[string]Flag) error { + flag := long[req.Key] + if !flag.IsSet() { + return nil + } + + // Check if ANY of the required flags is set (OR logic). + for _, required := range req.Val { + requiredFlag := long[required] + if requiredFlag.IsSet() { + return nil + } + } + + // None of the required flags are set. + return newRequiredFlagError(req.Key, req.Val) +} + func isFlagVisibleOnOS(flagOS []string) bool { return len(flagOS) == 0 || slices.Contains(flagOS, runtime.GOOS) } diff --git a/internal/cli/errors.go b/internal/cli/errors.go index baaac08..f6a2727 100644 --- a/internal/cli/errors.go +++ b/internal/cli/errors.go @@ -2,6 +2,7 @@ package cli import ( "fmt" + "strings" "github.com/ryanfowler/fetch/internal/core" ) @@ -73,3 +74,48 @@ func (err argRequiredError) PrintTo(p *core.Printer) { p.Reset() p.WriteString("'") } + +type requiredFlagError struct { + flag string + required []string +} + +func newRequiredFlagError(flag string, required []string) requiredFlagError { + return requiredFlagError{flag: flag, required: required} +} + +func (err requiredFlagError) Error() string { + if len(err.required) == 1 { + return fmt.Sprintf("flag '--%s' requires '--%s'", err.flag, err.required[0]) + } + return fmt.Sprintf("flag '--%s' requires one of '--%s'", err.flag, strings.Join(err.required, "', '--")) +} + +func (err requiredFlagError) PrintTo(p *core.Printer) { + p.WriteString("flag '") + p.Set(core.Bold) + p.WriteString("--") + p.WriteString(err.flag) + p.Reset() + + if len(err.required) == 1 { + p.WriteString("' requires '") + p.Set(core.Bold) + p.WriteString("--") + p.WriteString(err.required[0]) + p.Reset() + p.WriteString("'") + } else { + p.WriteString("' requires one of '") + for i, req := range err.required { + if i > 0 { + p.WriteString("', '") + } + p.Set(core.Bold) + p.WriteString("--") + p.WriteString(req) + p.Reset() + } + p.WriteString("'") + } +} diff --git a/internal/client/client.go b/internal/client/client.go index 4cab7fa..054cbea 100644 --- a/internal/client/client.go +++ b/internal/client/client.go @@ -303,17 +303,17 @@ func (t *http3TimingTransport) RoundTrip(req *http.Request) (*http.Response, err // RequestConfig represents the configuration for creating an HTTP request. type RequestConfig struct { AWSSigV4 *aws.Config - Basic *core.KeyVal + Basic *core.KeyVal[string] Bearer string ContentType string Data io.Reader - Form []core.KeyVal - Headers []core.KeyVal + Form []core.KeyVal[string] + Headers []core.KeyVal[string] HTTP core.HTTPVersion Method string Multipart *multipart.Multipart NoEncode bool - QueryParams []core.KeyVal + QueryParams []core.KeyVal[string] Range []string URL *url.URL } diff --git a/internal/complete/complete.go b/internal/complete/complete.go index 63f3b3b..f876d90 100644 --- a/internal/complete/complete.go +++ b/internal/complete/complete.go @@ -141,7 +141,7 @@ func getFlagMaps(flags []cli.Flag) (map[string]cli.Flag, map[string]cli.Flag) { return short, long } -func completeLongFlag(flags []cli.Flag, long map[string]cli.Flag, value string) []core.KeyVal { +func completeLongFlag(flags []cli.Flag, long map[string]cli.Flag, value string) []core.KeyVal[string] { if key, val, ok := strings.Cut(value, "="); ok { flag, ok := long[key] if !ok { @@ -151,10 +151,10 @@ func completeLongFlag(flags []cli.Flag, long map[string]cli.Flag, value string) return completeValue(flag, prefix, val) } - var out []core.KeyVal + var out []core.KeyVal[string] for _, flag := range flags { if strings.HasPrefix(flag.Long, value) { - out = append(out, core.KeyVal{ + out = append(out, core.KeyVal[string]{ Key: "--" + flag.Long, Val: flag.Description, }) @@ -163,7 +163,7 @@ func completeLongFlag(flags []cli.Flag, long map[string]cli.Flag, value string) return out } -func completeShortFlag(flags []cli.Flag, short map[string]cli.Flag, value string) []core.KeyVal { +func completeShortFlag(flags []cli.Flag, short map[string]cli.Flag, value string) []core.KeyVal[string] { values := make(map[string]struct{}) for i := range value { name := value[i : i+1] @@ -183,7 +183,7 @@ func completeShortFlag(flags []cli.Flag, short map[string]cli.Flag, value string values[value[i:i+1]] = struct{}{} } - var out []core.KeyVal + var out []core.KeyVal[string] for _, flag := range flags { if flag.Short == "" { continue @@ -191,7 +191,7 @@ func completeShortFlag(flags []cli.Flag, short map[string]cli.Flag, value string if _, ok := values[flag.Short]; ok { continue } - out = append(out, core.KeyVal{ + out = append(out, core.KeyVal[string]{ Key: "-" + value + flag.Short, Val: flag.Description, }) @@ -199,7 +199,7 @@ func completeShortFlag(flags []cli.Flag, short map[string]cli.Flag, value string return out } -func completeValue(flag cli.Flag, prefix, value string) []core.KeyVal { +func completeValue(flag cli.Flag, prefix, value string) []core.KeyVal[string] { if flag.Args == "" { // This flag doesn't take any arguments. return nil @@ -207,10 +207,10 @@ func completeValue(flag cli.Flag, prefix, value string) []core.KeyVal { if len(flag.Values) > 0 { // There are specific values for this flag. - var kvs []core.KeyVal + var kvs []core.KeyVal[string] for _, fv := range flag.Values { if strings.HasPrefix(fv.Key, value) { - kvs = append(kvs, core.KeyVal{ + kvs = append(kvs, core.KeyVal[string]{ Key: prefix + fv.Key, Val: fv.Val, }) @@ -237,12 +237,12 @@ func completeValue(flag cli.Flag, prefix, value string) []core.KeyVal { return nil } -func completePath(prefix, orig string) []core.KeyVal { +func completePath(prefix, orig string) []core.KeyVal[string] { path := os.ExpandEnv(orig) if orig == "~" { // Special case when path is '~'. - return []core.KeyVal{{Key: prefix + "~/", Val: "File"}} + return []core.KeyVal[string]{{Key: prefix + "~/", Val: "File"}} } if len(path) >= 2 && path[0] == '~' && path[1] == os.PathSeparator { @@ -266,7 +266,7 @@ func completePath(prefix, orig string) []core.KeyVal { base = filepath.Base(path) } - var out []core.KeyVal + var out []core.KeyVal[string] for _, entry := range entries { name := entry.Name() @@ -285,7 +285,7 @@ func completePath(prefix, orig string) []core.KeyVal { if entry.IsDir() { file = file + string(os.PathSeparator) } - out = append(out, core.KeyVal{ + out = append(out, core.KeyVal[string]{ Key: prefix + file, Val: "File", }) @@ -293,13 +293,13 @@ func completePath(prefix, orig string) []core.KeyVal { return out } -func allFlags(flags []cli.Flag) []core.KeyVal { - kvs := make([]core.KeyVal, 0, len(flags)) +func allFlags(flags []cli.Flag) []core.KeyVal[string] { + kvs := make([]core.KeyVal[string], 0, len(flags)) for _, flag := range flags { if flag.IsHidden { continue } - kvs = append(kvs, core.KeyVal{ + kvs = append(kvs, core.KeyVal[string]{ Key: "--" + flag.Long, Val: flag.Description, }) diff --git a/internal/complete/shells.go b/internal/complete/shells.go index 59e7992..6b58b27 100644 --- a/internal/complete/shells.go +++ b/internal/complete/shells.go @@ -10,7 +10,7 @@ import ( type Shell interface { Name() string Register() string - Complete([]core.KeyVal) string + Complete([]core.KeyVal[string]) string } // GetShell returns the shell matching the provided name. If no shell matches, @@ -36,7 +36,7 @@ func (f Fish) Register() string { return `complete --keep-order --exclusive --command fetch --arguments "(fetch --complete=fish -- (commandline --current-process --tokens-expanded --cut-at-cursor) (commandline --cut-at-cursor --current-token))"` } -func (f Fish) Complete(vals []core.KeyVal) string { +func (f Fish) Complete(vals []core.KeyVal[string]) string { var sb strings.Builder for _, kv := range vals { sb.WriteString(kv.Key) @@ -76,7 +76,7 @@ _fetch_complete() { compdef _fetch_complete fetch` } -func (z Zsh) Complete(vals []core.KeyVal) string { +func (z Zsh) Complete(vals []core.KeyVal[string]) string { var sb strings.Builder for i, kv := range vals { if i > 0 { diff --git a/internal/config/config.go b/internal/config/config.go index 149f9a6..77e4d83 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -25,7 +25,7 @@ type Config struct { Color core.Color DNSServer *url.URL Format core.Format - Headers []core.KeyVal + Headers []core.KeyVal[string] HTTP core.HTTPVersion IgnoreStatus *bool Image core.ImageSetting @@ -33,7 +33,7 @@ type Config struct { NoEncode *bool NoPager *bool Proxy *url.URL - QueryParams []core.KeyVal + QueryParams []core.KeyVal[string] Redirects *int Silent *bool Timeout *time.Duration @@ -266,7 +266,7 @@ func (c *Config) ParseFormat(value string) error { func (c *Config) ParseHeader(value string) error { key, val, _ := cut(value, ":") - c.Headers = append(c.Headers, core.KeyVal{Key: key, Val: val}) + c.Headers = append(c.Headers, core.KeyVal[string]{Key: key, Val: val}) return nil } @@ -348,7 +348,7 @@ func (c *Config) ParseProxy(value string) error { func (c *Config) ParseQuery(value string) error { key, val, _ := cut(value, "=") - c.QueryParams = append(c.QueryParams, core.KeyVal{Key: key, Val: val}) + c.QueryParams = append(c.QueryParams, core.KeyVal[string]{Key: key, Val: val}) return nil } diff --git a/internal/core/core.go b/internal/core/core.go index b716c6e..da2117d 100644 --- a/internal/core/core.go +++ b/internal/core/core.go @@ -52,8 +52,9 @@ const ( ) // KeyVal represents a generic key & value struct. -type KeyVal struct { - Key, Val string +type KeyVal[T any] struct { + Key string + Val T } // PointerTo returns a pointer to the value provided. diff --git a/internal/fetch/fetch.go b/internal/fetch/fetch.go index 61fca96..5d78180 100644 --- a/internal/fetch/fetch.go +++ b/internal/fetch/fetch.go @@ -41,7 +41,7 @@ const ( type Request struct { AWSSigv4 *aws.Config - Basic *core.KeyVal + Basic *core.KeyVal[string] Bearer string CACerts []*x509.Certificate Clobber bool @@ -50,9 +50,9 @@ type Request struct { DNSServer *url.URL DryRun bool Edit bool - Form []core.KeyVal + Form []core.KeyVal[string] Format core.Format - Headers []core.KeyVal + Headers []core.KeyVal[string] HTTP core.HTTPVersion IgnoreStatus bool Image core.ImageSetting @@ -64,7 +64,7 @@ type Request struct { Output string PrinterHandle *core.Handle Proxy *url.URL - QueryParams []core.KeyVal + QueryParams []core.KeyVal[string] Range []string Redirects *int RemoteHeaderName bool @@ -420,20 +420,20 @@ func getExitCodeForStatus(status int) int { } } -func getHeaders(headers http.Header) []core.KeyVal { - out := make([]core.KeyVal, 0, len(headers)) +func getHeaders(headers http.Header) []core.KeyVal[string] { + out := make([]core.KeyVal[string], 0, len(headers)) for k, v := range headers { k = strings.ToLower(k) - out = append(out, core.KeyVal{Key: k, Val: strings.Join(v, ",")}) + out = append(out, core.KeyVal[string]{Key: k, Val: strings.Join(v, ",")}) } - slices.SortFunc(out, func(a, b core.KeyVal) int { + slices.SortFunc(out, func(a, b core.KeyVal[string]) int { return strings.Compare(a.Key, b.Key) }) return out } -func addHeader(headers []core.KeyVal, h core.KeyVal) []core.KeyVal { - i, _ := slices.BinarySearchFunc(headers, h, func(a, b core.KeyVal) int { +func addHeader(headers []core.KeyVal[string], h core.KeyVal[string]) []core.KeyVal[string] { + i, _ := slices.BinarySearchFunc(headers, h, func(a, b core.KeyVal[string]) int { return strings.Compare(a.Key, b.Key) }) return slices.Insert(headers, i, h) diff --git a/internal/fetch/print.go b/internal/fetch/print.go index 80a4cc2..7109256 100644 --- a/internal/fetch/print.go +++ b/internal/fetch/print.go @@ -57,10 +57,10 @@ func printRequestMetadata(p *core.Printer, req *http.Request, v core.HTTPVersion headers := getHeaders(req.Header) if req.Body != nil && req.ContentLength > 0 { val := strconv.FormatInt(req.ContentLength, 10) - headers = addHeader(headers, core.KeyVal{Key: "content-length", Val: val}) + headers = addHeader(headers, core.KeyVal[string]{Key: "content-length", Val: val}) } if req.Header.Get("Host") == "" { - headers = addHeader(headers, core.KeyVal{Key: "host", Val: req.URL.Host}) + headers = addHeader(headers, core.KeyVal[string]{Key: "host", Val: req.URL.Host}) } for _, h := range headers { @@ -108,11 +108,11 @@ func printResponseHeaders(p *core.Printer, resp *http.Response) { headers := getHeaders(resp.Header) if method != "HEAD" && resp.ContentLength >= 0 && resp.Header.Get("Content-Length") == "" { val := strconv.FormatInt(resp.ContentLength, 10) - headers = addHeader(headers, core.KeyVal{Key: "content-length", Val: val}) + headers = addHeader(headers, core.KeyVal[string]{Key: "content-length", Val: val}) } if len(resp.TransferEncoding) > 0 && resp.Header.Get("Transfer-Encoding") == "" { val := strings.Join(resp.TransferEncoding, ",") - headers = addHeader(headers, core.KeyVal{Key: "transfer-encoding", Val: val}) + headers = addHeader(headers, core.KeyVal[string]{Key: "transfer-encoding", Val: val}) } for _, h := range headers { diff --git a/internal/multipart/multipart.go b/internal/multipart/multipart.go index 08b5a2e..05038d6 100644 --- a/internal/multipart/multipart.go +++ b/internal/multipart/multipart.go @@ -17,7 +17,7 @@ type Multipart struct { } // NewMultipart returns a Multipart using the provided key/values. -func NewMultipart(kvs []core.KeyVal) *Multipart { +func NewMultipart(kvs []core.KeyVal[string]) *Multipart { if len(kvs) == 0 { return nil } diff --git a/internal/multipart/multipart_test.go b/internal/multipart/multipart_test.go index fdebec5..cde2ec6 100644 --- a/internal/multipart/multipart_test.go +++ b/internal/multipart/multipart_test.go @@ -13,12 +13,12 @@ import ( func TestMultipart(t *testing.T) { tests := []struct { name string - fnPre func(*testing.T) ([]core.KeyVal, func()) + fnPre func(*testing.T) ([]core.KeyVal[string], func()) fnPost func(*testing.T, *multipart.Form) }{ { name: "small json file", - fnPre: func(t *testing.T) ([]core.KeyVal, func()) { + fnPre: func(t *testing.T) ([]core.KeyVal[string], func()) { t.Helper() f, err := os.CreateTemp("", "*.json") @@ -28,7 +28,7 @@ func TestMultipart(t *testing.T) { defer f.Close() f.WriteString(`{"key":"val"}`) - return []core.KeyVal{{Key: "key1", Val: "@" + f.Name()}}, func() { + return []core.KeyVal[string]{{Key: "key1", Val: "@" + f.Name()}}, func() { os.Remove(f.Name()) } }, @@ -55,7 +55,7 @@ func TestMultipart(t *testing.T) { }, { name: "file longer than 512 bytes with no extension", - fnPre: func(t *testing.T) ([]core.KeyVal, func()) { + fnPre: func(t *testing.T) ([]core.KeyVal[string], func()) { t.Helper() f, err := os.CreateTemp("", "") @@ -67,7 +67,7 @@ func TestMultipart(t *testing.T) { f.WriteString("\xFF\xD8\xFF") // JPEG signature. f.Write(make([]byte, 512)) - return []core.KeyVal{{Key: "key1", Val: "@" + f.Name()}}, func() { + return []core.KeyVal[string]{{Key: "key1", Val: "@" + f.Name()}}, func() { os.Remove(f.Name()) } }, diff --git a/main.go b/main.go index 7a42716..55cc44c 100644 --- a/main.go +++ b/main.go @@ -120,13 +120,6 @@ func main() { os.Exit(1) } - // Respond with an error if -J is specified without -O. - if app.RemoteHeaderName && !app.RemoteName { - p := handle.Stderr() - writeCLIErr(p, errors.New("--remote-header-name (-J) requires --remote-name (-O)")) - os.Exit(1) - } - // Make the HTTP request using the parsed configuration. req := fetch.Request{ AWSSigv4: app.AWSSigv4,