diff --git a/go.mod b/go.mod index b9f0c810..186a9b5c 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/wader/fq go 1.18 // fork of github.com/itchyny/gojq, see github.com/wader/gojq fq branch -require github.com/wader/gojq v0.12.1-0.20240118170525-e920352821d6 +require github.com/wader/gojq v0.12.1-0.20240324083939-2b4dc721594a require ( // bump: gomod-BurntSushi/toml /github\.com\/BurntSushi\/toml v(.*)/ https://github.com/BurntSushi/toml.git|^1 diff --git a/go.sum b/go.sum index ac93e029..2b71e88c 100644 --- a/go.sum +++ b/go.sum @@ -23,8 +23,8 @@ github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zx github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/wader/gojq v0.12.1-0.20240118170525-e920352821d6 h1:0zhn+HFzBP6i4XjyR+OMKauJ9zOZROpJCW9D75Z0fRE= -github.com/wader/gojq v0.12.1-0.20240118170525-e920352821d6/go.mod h1:E7walEZ03d5WBrEMutC7+tagVBDdtNTDe0jRxMCC6N0= +github.com/wader/gojq v0.12.1-0.20240324083939-2b4dc721594a h1:8SdZghxMYax232ktkzCOqtjnIQ9hO7sP7AXJipAZh8o= +github.com/wader/gojq v0.12.1-0.20240324083939-2b4dc721594a/go.mod h1:gPc2V6SapmFtdvALwJRg9WKk97piqkagc6vW6PoPqM4= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa h1:FRnLl4eNAQl8hwxVVC17teOw8kdjVDVAiFMtgUdTSRQ= diff --git a/pkg/interp/init.jq b/pkg/interp/init.jq index b4a63129..d8387074 100644 --- a/pkg/interp/init.jq +++ b/pkg/interp/init.jq @@ -123,13 +123,13 @@ def _cli_eval_on_expr_error: # other expr error, other errors then cancel should not happen, report and halt def _cli_eval_on_error: if .error | _is_context_canceled_error then (null | halt_error(_exit_code_expr_error)) - else halt_error(_exit_code_expr_error) + else _fatal_error(_exit_code_expr_error) end; # could not compile expr, report and halt def _cli_eval_on_compile_error: ( .error | _eval_compile_error_tostring - | halt_error(_exit_code_compile_error) + | _fatal_error(_exit_code_compile_error) ); def _cli_repl_error($_): _eval_error("compile"; "repl can only be used from interactive repl"); @@ -164,7 +164,7 @@ def _main: try (open | decode) catch ( "--argdecode \($a[0]): \(.)" - | halt_error(_exit_code_args_error) + | _fatal_error(_exit_code_args_error) ) ) ); @@ -172,7 +172,7 @@ def _main: # make sure we don't unintentionally use . to make things clearer | null | ( try _args_parse($args[1:]; _opt_cli_opts) - catch halt_error(_exit_code_args_error) + catch _fatal_error(_exit_code_args_error) ) as {parsed: $parsed_args, $rest} # combine default fixed opt, parsed args and -o key=value opts | _options_stack([ diff --git a/pkg/interp/internal.jq b/pkg/interp/internal.jq index fba25bd5..48435959 100644 --- a/pkg/interp/internal.jq +++ b/pkg/interp/internal.jq @@ -40,6 +40,8 @@ def stderr: , . ); +def _fatal_error($code): "error: \(.)\n" | halt_error($code); + # try to be same exit codes as jq # TODO: jq seems to halt processing inputs on JSON decode error but not IO errors, # seems strange. diff --git a/pkg/interp/interp.go b/pkg/interp/interp.go index bbca4b4c..490b855b 100644 --- a/pkg/interp/interp.go +++ b/pkg/interp/interp.go @@ -115,11 +115,6 @@ type Exiter interface { ExitCode() int } -// gojq halt_error uses this -type IsEmptyErrorer interface { - IsEmptyError() bool -} - type Terminal interface { Size() (int, int) IsTerminal() bool @@ -403,8 +398,25 @@ func (i *Interp) Main(ctx context.Context, output Output, versionStr string) err switch v := v.(type) { case error: - if emptyErr, ok := v.(IsEmptyErrorer); ok && emptyErr.IsEmptyError() { - // no output + var haltErr gojq.HaltError + if errors.As(v, &haltErr) { + if haltErrV := haltErr.Value(); haltErrV != nil { + if str, ok := haltErrV.(string); ok { + if _, err := i.OS.Stderr().Write([]byte(str)); err != nil { + return err + } + } else { + bs, _ := gojq.Marshal(haltErrV) + if _, err := i.OS.Stderr().Write(bs); err != nil { + return err + } + if _, err := i.OS.Stderr().Write([]byte{'\n'}); err != nil { + return err + } + } + } + + return haltErr } else if errors.Is(v, context.Canceled) { // ignore context cancel here for now, which means user somehow interrupted the interpreter // TODO: handle this inside interp.jq instead but then we probably have to do nested @@ -413,8 +425,6 @@ func (i *Interp) Main(ctx context.Context, output Output, versionStr string) err fmt.Fprintln(i.OS.Stderr(), v) } return v - case [2]any: - fmt.Fprintln(i.OS.Stderr(), v[:]...) default: // TODO: can this happen? fmt.Fprintln(i.OS.Stderr(), v) diff --git a/pkg/interp/options.jq b/pkg/interp/options.jq index 08736831..4f2d562e 100644 --- a/pkg/interp/options.jq +++ b/pkg/interp/options.jq @@ -126,7 +126,7 @@ def _opt_eval($rest): ) catch ( "-o \($opt)=@\($v[1:]): \(.)" - | halt_error(_exit_code_args_error) + | _fatal_error(_exit_code_args_error) ) ) ) @@ -140,7 +140,7 @@ def _opt_eval($rest): try fromjson catch ( "--argjson \($a[0]): \(.)" - | halt_error(_exit_code_args_error) + | _fatal_error(_exit_code_args_error) ) ) ) @@ -160,7 +160,7 @@ def _opt_eval($rest): | . as $expr_file | if . then try (open | tobytes | tostring) - catch ("\($expr_file): \(.)" | halt_error(_exit_code_args_error)) + catch ("\($expr_file): \(.)" | _fatal_error(_exit_code_args_error)) else $rest[0] // null end ) @@ -201,7 +201,7 @@ def _opt_eval($rest): ( map(.[1] |= ( . as $f | try (open | tobytes | tostring) - catch ("\($f): \(.)" | halt_error(_exit_code_args_error)) + catch ("\($f): \(.)" | _fatal_error(_exit_code_args_error)) ) ) ) diff --git a/pkg/interp/repl.jq b/pkg/interp/repl.jq index 507bbad0..df3a6015 100644 --- a/pkg/interp/repl.jq +++ b/pkg/interp/repl.jq @@ -195,7 +195,7 @@ def _repl_on_expr_error: def _repl_on_error: # was interrupted by user, just ignore if .error | _is_context_canceled_error then empty - else halt_error(_exit_code_expr_error) + else _fatal_error(_exit_code_expr_error) end; # compile error def _repl_on_compile_error: diff --git a/pkg/interp/testdata/exitcode.fqtest b/pkg/interp/testdata/exitcode.fqtest index 90f421b4..17c3affa 100644 --- a/pkg/interp/testdata/exitcode.fqtest +++ b/pkg/interp/testdata/exitcode.fqtest @@ -6,10 +6,10 @@ $ fq -n '1+"a"' exitcode: 5 stderr: error: cannot add: number (1) and string ("a") -$ fq -n '"abc" | halt_error(123)' +$ fq -n '"abc\n" | halt_error(123)' exitcode: 123 stderr: -error: abc +abc $ fq -n 'null | halt_error(123)' exitcode: 123 $ fq -n invalid