Skip to content

Commit 3968a84

Browse files
authored
Merge pull request #33 from nxtcoder17/feat/improve-error-handling
feat: improves error handling and visibility
2 parents 0c23e0e + 146d2a5 commit 3968a84

15 files changed

+205
-116
lines changed

cmd/run/completions.go

+4-24
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,13 @@ import (
66
"io"
77
"log/slog"
88

9+
"github.com/nxtcoder17/go.pkgs/log"
910
"github.com/nxtcoder17/runfile/parser"
11+
"github.com/nxtcoder17/runfile/types"
1012
)
1113

12-
func generateShellCompletion(_ context.Context, writer io.Writer, rfpath string) error {
13-
// if c.NArg() > 0 {
14-
// return nil
15-
// }
16-
17-
// runfilePath, err := locateRunfile(c)
18-
// if err != nil {
19-
// slog.Error("locating runfile", "err", err)
20-
// panic(err)
21-
// }
22-
23-
runfile, err := parser.ParseRunfile(rfpath)
14+
func generateShellCompletion(ctx context.Context, writer io.Writer, rfpath string) error {
15+
runfile, err := parser.ParseRunfile(types.NewContext(ctx, log.New()), rfpath)
2416
if err != nil {
2517
slog.Error("parsing, got", "err", err)
2618
panic(err)
@@ -30,17 +22,5 @@ func generateShellCompletion(_ context.Context, writer io.Writer, rfpath string)
3022
fmt.Fprintf(writer, "%s\n", k)
3123
}
3224

33-
// m, err := runfile.ParseIncludes()
34-
// if err != nil {
35-
// slog.Error("parsing, got", "err", err)
36-
// panic(err)
37-
// }
38-
39-
// for k, v := range m {
40-
// for tn := range v.Runfile.Tasks {
41-
// fmt.Fprintf(writer, "%s:%s\n", k, tn)
42-
// }
43-
// }
44-
4525
return nil
4626
}

cmd/run/main.go

+38-33
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/nxtcoder17/go.pkgs/log"
1616
"github.com/nxtcoder17/runfile/errors"
1717
"github.com/nxtcoder17/runfile/runner"
18+
"github.com/nxtcoder17/runfile/types"
1819

1920
"github.com/nxtcoder17/runfile/parser"
2021
"github.com/urfave/cli/v3"
@@ -68,6 +69,14 @@ func main() {
6869
&cli.BoolFlag{
6970
Name: "debug",
7071
Value: false,
72+
Action: func(ctx context.Context, c *cli.Command, b bool) error {
73+
v := "false"
74+
if b {
75+
v = "true"
76+
}
77+
os.Setenv("RUNFILE_DEBUG", v)
78+
return nil
79+
},
7180
},
7281

7382
&cli.BoolFlag{
@@ -146,18 +155,6 @@ func main() {
146155
return nil
147156
}
148157

149-
runfilePath, err := locateRunfile(c)
150-
if err != nil {
151-
slog.Error("locating runfile, got", "err", err)
152-
return err
153-
}
154-
155-
rf, err2 := parser.ParseRunfile(runfilePath)
156-
if err2 != nil {
157-
slog.Error("parsing runfile, got", "err", err2)
158-
panic(err2)
159-
}
160-
161158
kv := make(map[string]string)
162159

163160
// INFO: for supporting flags that have been suffixed post arguments
@@ -197,21 +194,40 @@ func main() {
197194
ShowDebugLogs: debug,
198195
})
199196

200-
return runner.Run(runner.NewContext(ctx, logger), rf, runner.RunArgs{
197+
runfilePath, err := locateRunfile(c)
198+
if err != nil {
199+
slog.Error("locating runfile, got", "err", err)
200+
return err
201+
}
202+
203+
rf, err2 := parser.ParseRunfile(types.NewContext(ctx, logger), runfilePath)
204+
if err2 != nil {
205+
slog.Error("parsing runfile, got", "err", err2)
206+
panic(err2)
207+
}
208+
209+
if err := runner.Run(types.NewContext(ctx, logger), rf, runner.RunArgs{
201210
Tasks: args,
202211
ExecuteInParallel: parallel,
203212
Watch: watch,
204213
Debug: debug,
205214
KVs: kv,
206-
})
215+
}); err != nil {
216+
errm, ok := err.(*errors.Error)
217+
slog.Debug("got", "err", err)
218+
if ok {
219+
if errm != nil {
220+
// errm.Error()
221+
// TODO: change it to a better logging
222+
// slog.Error("got", "err", errm)
223+
errm.Log()
224+
}
225+
} else {
226+
slog.Error("got", "err", err)
227+
}
228+
}
207229

208-
// return rf.Run(runfile.NewContext(ctx, logger), runfile.RunArgs{
209-
// Tasks: args,
210-
// ExecuteInParallel: parallel,
211-
// Watch: watch,
212-
// Debug: debug,
213-
// KVs: kv,
214-
// })
230+
return nil
215231
},
216232
}
217233

@@ -224,18 +240,7 @@ func main() {
224240
}()
225241

226242
if err := cmd.Run(ctx, os.Args); err != nil {
227-
errm, ok := err.(*errors.Error)
228-
slog.Debug("got", "err", err)
229-
if ok {
230-
if errm != nil {
231-
// errm.Error()
232-
// TODO: change it to a better logging
233-
// slog.Error("got", "err", errm)
234-
errm.Log()
235-
}
236-
} else {
237-
slog.Error("got", "err", err)
238-
}
243+
slog.Error("while running cmd, got", "err", err)
239244
}
240245
}
241246

errors/errors.go

+85-10
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,112 @@
11
package errors
22

33
import (
4+
"errors"
45
"fmt"
56
"log/slog"
7+
"os"
68
"runtime"
9+
10+
"github.com/nxtcoder17/runfile/types"
711
)
812

913
type Error struct {
1014
msg string
11-
// kv is a slice of slog Attributes i.e. ("key", "value")
12-
keys []string
13-
// kv map[string]any
15+
16+
taskName string
17+
1418
kv []any
1519

1620
traces []string
1721

1822
err error
1923
}
2024

25+
func (e *Error) GetWrappedErrorString() string {
26+
if e.err == nil {
27+
return ""
28+
}
29+
30+
return "\nfailed with error:\n" + e.err.Error()
31+
}
32+
33+
func (e *Error) resolveTaskName() string {
34+
if e.taskName != "" {
35+
return e.taskName
36+
}
37+
for i := 0; i < len(e.kv)-1; i += 2 { // assume kv is key/value pairs
38+
if key, ok := e.kv[i].(string); ok && key == "task" {
39+
if val, ok := e.kv[i+1].(string); ok {
40+
return val
41+
}
42+
}
43+
}
44+
return ""
45+
}
46+
2147
// Error implements error.
2248
func (e *Error) Error() string {
23-
return fmt.Sprintf("%v {%#v}", e.err, e.kv)
49+
return e.err.Error()
50+
// return fmt.Sprintf("%v {%#v}", e.err, e.kv)
51+
}
52+
53+
func (e *Error) WithTaskName(tn string) *Error {
54+
e.taskName = tn
55+
return e
56+
}
57+
58+
func (e *Error) WithCtx(ctx types.Context) *Error {
59+
return e.WithTaskName(ctx.TaskName)
60+
}
61+
62+
func (e *Error) GetTaskName() string {
63+
return e.taskName
2464
}
2565

2666
func (e *Error) Log() {
67+
fmt.Fprintf(os.Stderr, "%s%s%s\n", types.GetErrorStyledPrefix(e.resolveTaskName()), e.msg, e.GetWrappedErrorString())
68+
if os.Getenv("RUNFILE_DEBUG") == "true" {
69+
e.InspectLog()
70+
}
71+
}
72+
73+
func (e *Error) InspectLog() {
2774
args := make([]any, 0, len(e.kv))
2875
args = append(args, e.kv...)
76+
77+
// b, _ := json.MarshalIndent(e.traces, "", " ")
78+
// args = append(args, "traces", string(b))
79+
2980
args = append(args, "traces", e.traces)
3081
slog.Error(e.msg, args...)
3182
}
3283

3384
var _ error = (*Error)(nil)
3485

3586
func Err(msg string) *Error {
36-
return &Error{msg: msg}
87+
_, file, line, _ := runtime.Caller(1)
88+
e := &Error{msg: msg}
89+
e.traces = append(e.traces, fmt.Sprintf("%s:%d", file, line))
90+
return e
3791
}
3892

3993
func (e *Error) Wrap(err error) *Error {
4094
_, file, line, _ := runtime.Caller(1)
4195
e.traces = append(e.traces, fmt.Sprintf("%s:%d", file, line))
42-
e.err = err
96+
if e.err != nil {
97+
e.err = errors.Join(e.err, err)
98+
} else {
99+
e.err = err
100+
}
43101
return e
44102
}
45103

46104
func (e *Error) WrapStr(msg string) *Error {
47-
e.err = fmt.Errorf(msg)
105+
if e.err != nil {
106+
e.err = errors.Join(e.err, fmt.Errorf(msg))
107+
} else {
108+
e.err = fmt.Errorf(msg)
109+
}
48110
return e
49111
}
50112

@@ -57,7 +119,12 @@ func (e *Error) KV(kv ...any) *Error {
57119
// // e.keys = append(e.keys, kv[i].(string))
58120
// e.kv[kv[i].(string)] = kv[i+1]
59121
// }
122+
if len(kv) == 0 {
123+
return e
124+
}
125+
_, file, line, _ := runtime.Caller(1)
60126
e.kv = append(e.kv, kv...)
127+
e.traces = append(e.traces, fmt.Sprintf("%s:%d", file, line))
61128

62129
return e
63130
}
@@ -82,9 +149,17 @@ var (
82149
ErrParseDotEnv = Err("failed to parse dotenv file")
83150
ErrInvalidDotEnv = Err("invalid dotenv file")
84151

85-
ErrInvalidEnvVar = Err("invalid env var")
86-
ErrRequiredEnvVar = Err("required env var")
87-
ErrInvalidDefaultValue = Err("invalid default value for env var")
152+
ErrInvalidEnvVar = func(k string) *Error {
153+
return Err(fmt.Sprintf("invalid env var (%s)", k))
154+
}
155+
156+
ErrRequiredEnvVar = func(k string) *Error {
157+
return Err(fmt.Sprintf("required env var (%s)", k))
158+
}
159+
160+
ErrInvalidDefaultValue = func(k string, v any) *Error {
161+
return Err(fmt.Sprintf("invalid default value for env var (%s),default: %v", k, v))
162+
}
88163

89164
ErrEvalEnvVarSh = Err("failed while executing env-var sh script")
90165

examples/Runfile.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ tasks:
6666
k4:
6767
default:
6868
sh: |+
69-
console.log('1234' == '23344')
69+
echo "1234"
70+
# console.log('1234' == '23344')
7071
cmd:
7172
- run: cook
7273
- console.log(process.env.k4)

examples/run1/Runfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ tasks:
55
echo:
66
cmd:
77
- echo "hello from run1"
8-
- if: gt 1 0
9-
cmd: echo "hello after condition check"
8+
# - if: gt 1 0
9+
- echo "hello after condition check"
1010

1111
node:shell:
1212
interactive: true

0 commit comments

Comments
 (0)