Skip to content
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
3 changes: 2 additions & 1 deletion Runfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ tasks:
echo "DONE"

example:
dir: ./examples
cmd:
- |+
run -f ./examples/Runfile cook
run cook clean
71 changes: 62 additions & 9 deletions cmd/run/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"path/filepath"
"syscall"

"github.com/nxtcoder17/fwatcher/pkg/logging"
"github.com/nxtcoder17/runfile/pkg/runfile"
"github.com/urfave/cli/v3"
)
Expand All @@ -26,6 +27,23 @@ func main() {
Aliases: []string{"f"},
Value: "",
},

&cli.BoolFlag{
Name: "parallel",
Aliases: []string{"p"},
Value: false,
},

&cli.BoolFlag{
Name: "watch",
Aliases: []string{"w"},
Value: false,
},

&cli.BoolFlag{
Name: "debug",
Value: false,
},
},
EnableShellCompletion: true,
ShellComplete: func(ctx context.Context, c *cli.Command) {
Expand All @@ -38,7 +56,7 @@ func main() {
panic(err)
}

runfile, err := runfile.ParseRunFile(runfilePath)
runfile, err := runfile.Parse(runfilePath)
if err != nil {
panic(err)
}
Expand All @@ -48,25 +66,60 @@ func main() {
}
},
Action: func(ctx context.Context, c *cli.Command) error {
if c.Args().Len() > 1 {
return fmt.Errorf("too many arguments")
}
if c.Args().Len() != 1 {
return fmt.Errorf("missing argument")
parallel := c.Bool("parallel")
watch := c.Bool("watch")
debug := c.Bool("debug")

logging.NewSlogLogger(logging.SlogOptions{
ShowCaller: debug,
ShowDebugLogs: debug,
SetAsDefaultLogger: true,
})

if c.Args().Len() < 1 {
return fmt.Errorf("missing argument, at least one argument is required")
}

runfilePath, err := locateRunfile(c)
if err != nil {
return err
}

runfile, err := runfile.ParseRunFile(runfilePath)
rf, err := runfile.Parse(runfilePath)
if err != nil {
panic(err)
}

s := c.Args().First()
return runfile.Run(ctx, s)
args := make([]string, 0, len(c.Args().Slice()))
for _, arg := range c.Args().Slice() {
if arg == "-p" || arg == "--parallel" {
parallel = true
continue
}

if arg == "-w" || arg == "--watch" {
watch = true
continue
}

if arg == "--debug" {
debug = true
continue
}

args = append(args, arg)
}

if parallel && watch {
return fmt.Errorf("parallel and watch can't be set together")
}

return rf.Run(ctx, runfile.RunArgs{
Tasks: args,
ExecuteInParallel: parallel,
Watch: watch,
Debug: debug,
})
},
}

Expand Down
9 changes: 6 additions & 3 deletions examples/Runfile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ tasks:
k3:
sh: echo -n "hello"
dotenv:
- .secrets/env
- ../.secrets/env
cmd:
# - sleep 5
- echo "hi hello"
- echo "value of k1 is '$k1'"
- echo "value of k2 is '$k2'"
Expand All @@ -21,13 +22,15 @@ tasks:
name: clean
shell: ["python", "-c"]
dotenv:
- .secrets/env
- ../.secrets/env
cmd:
- |+
import secrets
import os
import time
print(os.environ['key_id'])
# print(secrets.token_hex(32))
time.sleep(6)
print(secrets.token_hex(32))
laundry:
name: laundry
shell: ["node", "-e"]
Expand Down
19 changes: 18 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,25 @@ module github.com/nxtcoder17/runfile
go 1.22.7

require (
github.com/joho/godotenv v1.5.1
github.com/nxtcoder17/fwatcher v1.0.1
github.com/urfave/cli/v3 v3.0.0-alpha9
golang.org/x/sync v0.8.0
sigs.k8s.io/yaml v1.4.0
)

require github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
require (
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/lipgloss v0.13.0 // indirect
github.com/charmbracelet/log v0.4.0 // indirect
github.com/charmbracelet/x/ansi v0.1.4 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/muesli/termenv v0.15.2 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect
golang.org/x/sys v0.19.0 // indirect
)
36 changes: 34 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,15 +1,47 @@
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
github.com/charmbracelet/lipgloss v0.13.0 h1:4X3PPeoWEDCMvzDvGmTajSyYPcZM4+y8sCA/SsA3cjw=
github.com/charmbracelet/lipgloss v0.13.0/go.mod h1:nw4zy0SBX/F/eAO1cWdcvy6qnkDUxr8Lw7dvFrAIbbY=
github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM=
github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM=
github.com/charmbracelet/x/ansi v0.1.4 h1:IEU3D6+dWwPSgZ6HBH+v6oUuZ/nVawMiWj5831KfiLM=
github.com/charmbracelet/x/ansi v0.1.4/go.mod h1:dk73KoMTT5AX5BsX0KrqhsTqAnhZZoCBjs7dGWp4Ktw=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4=
github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
github.com/nxtcoder17/fwatcher v1.0.1 h1:Rqy+7etcGv9L1KIoK8YGGpAhdXW/pkfkXQwdlJzL1a8=
github.com/nxtcoder17/fwatcher v1.0.1/go.mod h1:MNmSwXYOrqp7U1pUxh0GWB5skpjFTWTQXhAA0+sPJcU=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/urfave/cli/v3 v3.0.0-alpha9 h1:P0RMy5fQm1AslQS+XCmy9UknDXctOmG/q/FZkUFnJSo=
github.com/urfave/cli/v3 v3.0.0-alpha9/go.mod h1:0kK/RUFHyh+yIKSfWxwheGndfnrvYSmYFVeKCh03ZUc=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI=
golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
7 changes: 0 additions & 7 deletions main.go

This file was deleted.

18 changes: 18 additions & 0 deletions pkg/functions/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package functions

func DefaultIfNil[T any](v *T, dv T) T {
if v == nil {
return dv
}
return *v
}

// Must panics if err is not nil
// It is intended to be used very sparingly, and only in cases where the caller is
// certain that the error will never be nil in ideal scenarios
func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
50 changes: 18 additions & 32 deletions pkg/runfile/parser.go
Original file line number Diff line number Diff line change
@@ -1,55 +1,41 @@
package runfile

import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
"path/filepath"

"sigs.k8s.io/yaml"
"github.com/joho/godotenv"
)

func ParseRunFile(file string) (*RunFile, error) {
var runfile RunFile
f, err := os.ReadFile(file)
if err != nil {
return &runfile, err
}
err = yaml.Unmarshal(f, &runfile)
if err != nil {
return &runfile, err
}
return &runfile, nil
func parseDotEnv(reader io.Reader) (map[string]string, error) {
return godotenv.Parse(reader)
}

// parseDotEnv parses the .env file and returns a slice of strings as in os.Environ()
func parseDotEnv(files ...string) ([]string, error) {
results := make([]string, 0, 5)
func parseDotEnvFiles(files ...string) (map[string]string, error) {
results := make(map[string]string)

for i := range files {
if !filepath.IsAbs(files[i]) {
return nil, fmt.Errorf("dotenv file path %s, must be absolute", files[i])
}

f, err := os.Open(files[i])
if err != nil {
return nil, err
}
m, err := parseDotEnv(f)
if err != nil {
return nil, err
}
f.Close()

s := bufio.NewScanner(f)
for s.Scan() {
s2 := strings.SplitN(s.Text(), "=", 2)
if len(s2) != 2 {
continue
}
s, _ := strconv.Unquote(string(s2[1]))

// os.Setenv(s2[0], s2[1])
os.Setenv(s2[0], s)
results = append(results, s2[0])
for k, v := range m {
results[k] = v
}
}

for i := range results {
v := os.Getenv(results[i])
results[i] = fmt.Sprintf("%s=%v", results[i], v)
}

return results, nil
Expand Down
Loading