Skip to content

Commit b93d6c5

Browse files
committed
refactor: better package separation with spec and resolver
1 parent 7b255f2 commit b93d6c5

17 files changed

Lines changed: 676 additions & 281 deletions

File tree

cmd/run/main.go

Lines changed: 63 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"time"
1414

1515
"github.com/nxtcoder17/fastlog"
16-
"github.com/nxtcoder17/runfile/pkg/errors"
16+
"github.com/nxtcoder17/go.errors"
1717
"github.com/nxtcoder17/runfile/pkg/runfile"
1818
"github.com/urfave/cli/v3"
1919
)
@@ -131,6 +131,26 @@ func main() {
131131
return nil
132132
},
133133
},
134+
{
135+
Name: "init",
136+
EnableShellCompletion: false,
137+
Action: func(ctx context.Context, c *cli.Command) error {
138+
dir, err := os.Getwd()
139+
if err != nil {
140+
return err
141+
}
142+
143+
_, err = getRunfilePath(dir)
144+
if err == nil {
145+
slog.Info("Runfile already exists in current directory")
146+
return nil
147+
}
148+
149+
// TODO: implement init command to create a sample Runfile
150+
slog.Info("init command not yet implemented")
151+
return nil
152+
},
153+
},
134154
},
135155

136156
Suggest: true,
@@ -188,18 +208,15 @@ func main() {
188208
}
189209

190210
logger := fastlog.New(fastlog.Console(), fastlog.ShowDebugLogs(debug), fastlog.WithoutTimestamp())
211+
slog.SetDefault(logger.Slog())
191212

192213
runfilePath, err := locateRunfile(c)
193214
if err != nil {
194215
slog.Error("locating runfile, got", "err", err)
195216
return err
196217
}
197218

198-
if err := runfile.RunTask(ctx, runfilePath, args[0]); err != nil {
199-
logger.Error("ERRORED", "err", err)
200-
if err2, ok := err.(*errors.Error); ok {
201-
logger.Error(err2.Error(), err2.SlogAttrs()...)
202-
}
219+
if err := runfile.RunTask(ctx, runfilePath, args[0], kv); err != nil {
203220
return err
204221
}
205222

@@ -216,8 +233,40 @@ func main() {
216233
}()
217234

218235
if err := cmd.Run(ctx, os.Args); err != nil {
219-
slog.Error("while running cmd, got", "err", err)
236+
if err2, ok := err.(*errors.Error); ok {
237+
slog.Error("failed to run task", err2.AsKeyValues()...)
238+
return
239+
}
240+
slog.Error("failed to run task", "err", err)
241+
}
242+
}
243+
244+
var ErrRunfileNotFound = fmt.Errorf("failed to locate your nearest Runfile")
245+
246+
func getRunfilePath(dir string) (string, error) {
247+
runfileNames := []string{
248+
"Runfile",
249+
"Runfile.yml",
250+
"Runfile.yaml",
251+
}
252+
253+
for _, f := range runfileNames {
254+
stat, err := os.Stat(filepath.Join(dir, f))
255+
if err != nil {
256+
if !os.IsNotExist(err) {
257+
return "", err
258+
}
259+
continue
260+
}
261+
262+
if stat.IsDir() {
263+
return "", fmt.Errorf("Runfile.yml is a directory")
264+
}
265+
266+
return filepath.Join(dir, f), nil
220267
}
268+
269+
return "", ErrRunfileNotFound
221270
}
222271

223272
func locateRunfile(c *cli.Command) (string, error) {
@@ -232,28 +281,17 @@ func locateRunfile(c *cli.Command) (string, error) {
232281

233282
oldDir := ""
234283

235-
runfileNames := []string{
236-
"Runfile",
237-
"Runfile.yml",
238-
"Runfile.yaml",
239-
}
240-
241284
for oldDir != dir {
242-
for _, fn := range runfileNames {
243-
if _, err := os.Stat(filepath.Join(dir, fn)); err != nil {
244-
if !os.IsNotExist(err) {
245-
return "", err
246-
}
247-
continue
248-
}
249-
250-
return filepath.Join(dir, fn), nil
285+
fp, err := getRunfilePath(dir)
286+
if err != nil && !errors.Is(err, ErrRunfileNotFound) {
287+
oldDir = dir
288+
dir = filepath.Dir(dir)
289+
continue
251290
}
252291

253-
oldDir = dir
254-
dir = filepath.Dir(dir)
292+
return fp, nil
255293
}
256294

257-
return "", fmt.Errorf("failed to locate your nearest Runfile")
295+
return "", ErrRunfileNotFound
258296
}
259297
}

examples/Runfile.yml

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,35 +42,32 @@ tasks:
4242
# - echo "k5 is $k5"
4343

4444
clean:
45-
name: clean
4645
# shell: ["python", "-c"]
4746
shell: python
4847
# dotenv:
4948
# - ../.secrets/env
5049
cmd:
5150
- run: laundry
52-
# vars:
53-
# k1: v1
54-
- |+
55-
import secrets
56-
import os
57-
import time
58-
# print("key_id from env: ", os.environ['key_id'])
59-
# time.sleep(2)
60-
print("hello from clean")
61-
print(secrets.token_hex(32))
51+
env:
52+
k4: "HELLO"
53+
# - |+
54+
# import secrets
55+
# import os
56+
# import time
57+
# # print("key_id from env: ", os.environ['key_id'])
58+
# # time.sleep(2)
59+
# print("hello from clean")
60+
# print(secrets.token_hex(32))
6261

6362
laundry:
6463
name: laundry
6564
shell: ["node", "-e"]
65+
silent: true
6666
env:
6767
k4:
68-
default:
69-
sh: |+
70-
echo "1234"
71-
# console.log('1234' == '23344')
68+
sh: echo "1234"
7269
cmd:
73-
- run: cook
70+
# - run: cook
7471
- console.log(process.env.k4)
7572
- console.log("hello from laundry")
7673

go.mod

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,32 +11,27 @@ require (
1111
github.com/muesli/termenv v0.15.2
1212
github.com/nxtcoder17/fastlog v0.0.0-20251112144402-5324a708e570
1313
github.com/nxtcoder17/fwatcher v1.2.2-0.20250804201159-543ad31be162
14-
github.com/stretchr/testify v1.9.0
14+
github.com/nxtcoder17/go.errors v0.0.0-20251116060059-d31bd582d4c8
1515
github.com/urfave/cli/v3 v3.0.0-beta1
16-
golang.org/x/sync v0.10.0
1716
golang.org/x/term v0.32.0
18-
sigs.k8s.io/yaml v1.4.0
17+
gopkg.in/yaml.v3 v3.0.1
1918
)
2019

2120
require (
2221
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
2322
github.com/charmbracelet/x/ansi v0.4.2 // indirect
24-
github.com/davecgh/go-spew v1.1.1 // indirect
2523
github.com/dlclark/regexp2 v1.11.4 // indirect
2624
github.com/fsnotify/fsnotify v1.8.0 // indirect
27-
github.com/google/go-cmp v0.6.0 // indirect
2825
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
2926
github.com/mattn/go-colorable v0.1.13 // indirect
3027
github.com/mattn/go-isatty v0.0.20 // indirect
3128
github.com/mattn/go-runewidth v0.0.16 // indirect
3229
github.com/nxtcoder17/go.pkgs v0.0.0-20250216034729-39e2d2cd48da // indirect
33-
github.com/pmezard/go-difflib v1.0.0 // indirect
3430
github.com/rivo/uniseg v0.4.7 // indirect
3531
github.com/rs/zerolog v1.33.0 // indirect
3632
github.com/samber/lo v1.47.0 // indirect
3733
github.com/samber/slog-common v0.18.1 // indirect
3834
github.com/samber/slog-zerolog/v2 v2.7.3 // indirect
3935
golang.org/x/sys v0.33.0 // indirect
4036
golang.org/x/text v0.16.0 // indirect
41-
gopkg.in/yaml.v3 v3.0.1 // indirect
4237
)

go.sum

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,6 @@ github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cn
1818
github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/8M=
1919
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
2020
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
21-
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
22-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
23-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
2421
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
2522
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
2623
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
@@ -37,12 +34,18 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
3734
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
3835
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
3936
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
40-
github.com/nxtcoder17/fastlog v0.0.0-20250702035423-1739653a5c24 h1:oLLpFv1p7jRRrrsZzyf77pECLAMKrTxzHRSoHNRoELw=
41-
github.com/nxtcoder17/fastlog v0.0.0-20250702035423-1739653a5c24/go.mod h1:x6o+8WEHRGaWu9XEhSdTrjmDjKhVnKNXd/XZ56bNN/o=
4237
github.com/nxtcoder17/fastlog v0.0.0-20251112144402-5324a708e570 h1:uiafpAq+4R/W7QcDJ8GiM7feWHBuojrekKNxiX+POis=
4338
github.com/nxtcoder17/fastlog v0.0.0-20251112144402-5324a708e570/go.mod h1:x6o+8WEHRGaWu9XEhSdTrjmDjKhVnKNXd/XZ56bNN/o=
4439
github.com/nxtcoder17/fwatcher v1.2.2-0.20250804201159-543ad31be162 h1:7EHTiBm6MVUMzT8pdeavpXcxwzzIbDC0QJwre6OvGAk=
4540
github.com/nxtcoder17/fwatcher v1.2.2-0.20250804201159-543ad31be162/go.mod h1:SMwIdCpyi5fBygrkCX8hIIUeILzgoxJFaDSlhFBOWWQ=
41+
github.com/nxtcoder17/go.errors v0.0.0-20251113120002-a0f554f5bc7e h1:CaipKbo8QLN+xmebk7JUy+HJE6v6KjCyVHRuNSBVV8Q=
42+
github.com/nxtcoder17/go.errors v0.0.0-20251113120002-a0f554f5bc7e/go.mod h1:9gp0I4JikKZGKflgPqqXCPZlIznVzlPWmnv+CWIrdxE=
43+
github.com/nxtcoder17/go.errors v0.0.0-20251116055045-656c03e9c6a6 h1:KzDMvpFNcEtd0Pbsun6qPkUg+lHKovDmUYsldlnCFWk=
44+
github.com/nxtcoder17/go.errors v0.0.0-20251116055045-656c03e9c6a6/go.mod h1:9gp0I4JikKZGKflgPqqXCPZlIznVzlPWmnv+CWIrdxE=
45+
github.com/nxtcoder17/go.errors v0.0.0-20251116055423-b54e4f346408 h1:uiAn9JS/vVvFtnEissR0sSIduvz+W2jQ9bdvwbvlBfo=
46+
github.com/nxtcoder17/go.errors v0.0.0-20251116055423-b54e4f346408/go.mod h1:9gp0I4JikKZGKflgPqqXCPZlIznVzlPWmnv+CWIrdxE=
47+
github.com/nxtcoder17/go.errors v0.0.0-20251116060059-d31bd582d4c8 h1:C1vUEvYbbpofqK4xnbEU1htxZl66myq6ZJfHpcdA/GQ=
48+
github.com/nxtcoder17/go.errors v0.0.0-20251116060059-d31bd582d4c8/go.mod h1:9gp0I4JikKZGKflgPqqXCPZlIznVzlPWmnv+CWIrdxE=
4649
github.com/nxtcoder17/go.pkgs v0.0.0-20250216034729-39e2d2cd48da h1:Y6GILHFlrihVfDqDPQ98y2kdUeI0SQc8tnoXh2NbEIA=
4750
github.com/nxtcoder17/go.pkgs v0.0.0-20250216034729-39e2d2cd48da/go.mod h1:raSGHj5CMHNHZf4fCV9CWpFk0hsb2CSKFZSPd4zW8JM=
4851
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -64,8 +67,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
6467
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
6568
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
6669
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
67-
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
68-
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
6970
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7071
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
7172
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -79,5 +80,3 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+
7980
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
8081
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
8182
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
82-
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
83-
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

nixy.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ nixpkgs:
33

44
packages:
55
- go
6+
67
- pre-commit
78
- gotestfmt

pkg/errors/constants.go

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,74 @@ package errors
22

33
import (
44
"fmt"
5+
6+
"github.com/nxtcoder17/go.errors"
57
)
68

7-
func ErrReadRunfile(err error) *Error {
8-
return WrapErr(err).Msg("failed to read runfile")
9+
func ErrReadRunfile(err error) *errors.Error {
10+
return errors.New("failed to read runfile").Wrap(err)
911
}
1012

11-
func ErrParseRunfile(err error) *Error {
12-
return WrapErr(err).Msg("failed to parse runfile")
13+
func ErrParseRunfile(err error) *errors.Error {
14+
return errors.New("failed to parse runfile").Wrap(err)
1315
}
1416

15-
func ErrParseIncludes(err error) *Error {
16-
return WrapErr(err).Msg("failed to parse includes")
17+
func ErrParseIncludes(err error) *errors.Error {
18+
return errors.New("failed to parse includes").Wrap(err)
1719
}
1820

19-
func ErrParseDotEnv(err error) *Error {
20-
return WrapErr(err).Msg("failed to parse dotenv file")
21+
func ErrParseDotEnv(err error) *errors.Error {
22+
return errors.New("failed to parse dotenv file").Wrap(err)
2123
}
2224

23-
func ErrInvalidDotEnv(err error) *Error {
24-
return WrapErr(err).Msg("invalid dotenv file")
25+
func ErrInvalidDotEnv(err error) *errors.Error {
26+
return errors.New("invalid dotenv file").Wrap(err)
2527
}
2628

27-
func ErrInvalidEnvVar(key string, err error) *Error {
28-
return WrapErr(err).Msg("invalid env var (" + key + ")")
29+
func ErrInvalidEnvVar(key string, err error) *errors.Error {
30+
return errors.New("invalid env var (" + key + ")").Wrap(err)
2931
}
3032

31-
func ErrRequiredEnvVar(key string) *Error {
32-
return WrapStr("required env var (" + key + ")")
33+
func ErrRequiredEnvVar(key string) *errors.Error {
34+
return errors.New("required env var (" + key + ")")
3335
}
3436

35-
func ErrInvalidDefaultValue(err error, key string, value any) *Error {
36-
return WrapErr(err).Msg("invalid default value for env var (" + key + "), default: " + fmt.Sprint(value))
37+
func ErrInvalidDefaultValue(err error, key string, value any) *errors.Error {
38+
return errors.New("invalid default value for env var (" + key + "), default: " + fmt.Sprint(value)).Wrap(err)
3739
}
3840

39-
func ErrEvalEnvVarSh(err error) *Error {
40-
return WrapErr(err).Msg("failed while executing env-var sh script")
41+
func ErrEvalEnvVarSh(err error) *errors.Error {
42+
return errors.New("failed while executing env-var sh script").Wrap(err)
4143
}
4244

43-
func ErrTaskNotFound(taskName string) *Error {
44-
return WrapStr("task not found").KV("task", taskName)
45+
func ErrTaskNotFound(taskName string) *errors.Error {
46+
return errors.New("task not found").KV("task", taskName)
4547
}
4648

47-
func ErrTaskFailed(err error) *Error {
48-
return WrapErr(err).Msg("task failed")
49+
func ErrTaskFailed(err error) *errors.Error {
50+
return errors.New("task failed").Wrap(err)
4951
}
5052

51-
func ErrTaskParsingFailed(err error) *Error {
52-
return WrapErr(err).Msg("task parsing failed")
53+
func ErrTaskParsingFailed(err error) *errors.Error {
54+
return errors.New("task parsing failed").Wrap(err)
5355
}
5456

55-
func ErrTaskRequirementNotMet(requirement string, err error) *Error {
56-
return WrapErr(err).Msg("task requirements not met").KV("requirement", requirement)
57+
func ErrTaskRequirementNotMet(requirement string, err error) *errors.Error {
58+
return errors.New("task requirements not met").Wrap(err).KV("requirement", requirement)
5759
}
5860

59-
func ErrTaskInvalidWorkingDir(workingDir string, err error) *Error {
60-
return WrapErr(err).Msg("task invalid working directory").KV("working-dir", workingDir)
61+
func ErrTaskInvalidWorkingDir(workingDir string, err error) *errors.Error {
62+
return errors.New("task invalid working directory").Wrap(err).KV("working-dir", workingDir)
6163
}
6264

63-
func ErrTaskInvalidCommand(command any, err error) *Error {
64-
return WrapErr(err).Msg("task invalid command").KV("command", command)
65+
func ErrTaskInvalidCommand(command any, err error) *errors.Error {
66+
return errors.New("task invalid command").Wrap(err).KV("command", command)
6567
}
6668

67-
func ErrInvalidShellAlias(alias string) *Error {
68-
return WrapStr("invalid shell alias").KV("alias", alias)
69+
func ErrInvalidShellAlias(alias string) *errors.Error {
70+
return errors.New("invalid shell alias").KV("alias", alias)
6971
}
7072

71-
func ErrCircularDependency(taskName string) *Error {
72-
return WrapStr("circular dependency detected").KV("task", taskName)
73+
func ErrCircularDependency(taskName string) *errors.Error {
74+
return errors.New("invalid shell alias").KV("task", taskName)
7375
}

0 commit comments

Comments
 (0)