Skip to content

Commit

Permalink
🤟 trace: wire
Browse files Browse the repository at this point in the history
  • Loading branch information
rjeczalik committed Jun 30, 2024
1 parent 8907865 commit 23e6677
Show file tree
Hide file tree
Showing 11 changed files with 451 additions and 136 deletions.
7 changes: 3 additions & 4 deletions hkt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,10 @@ func newRunCommand(ctx context.Context, app *command.App) *cobra.Command {
}

s, err := app.Engine.Run(ctx, files[0])
if err != nil {
return err
}

return app.Render(s)
app.Render(s.Events)

return err
},
Version: version,
SilenceUsage: true,
Expand Down
84 changes: 83 additions & 1 deletion pkg/check/check.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
package check // import "hookt.dev/cmd/pkg/check"

import "sync"
import (
"context"
"fmt"
"strconv"
"sync"

"github.com/itchyny/gojq"
"hookt.dev/cmd/pkg/trace"
)

type S struct {
mu sync.Mutex

Events Events

Steps struct {
OK int
Fail int
Expand All @@ -22,3 +32,75 @@ func (s *S) Fail() {
s.Steps.Fail++
s.mu.Unlock()
}

func (s *S) Trace() trace.PatternTrace {
return trace.PatternTrace{
ParseKey: func(ctx context.Context, q *gojq.Query, err error) {
if err != nil {
return
}

n, _ := strconv.Atoi(trace.Get(ctx, "step-index"))
desc := trace.Get(ctx, "step-desc")
group := trace.Get(ctx, "pattern-group")
pattern := trace.Get(ctx, "pattern")

s.mu.Lock()
defer s.mu.Unlock()

if n >= len(s.Events) {
for i := len(s.Events); i <= n; i++ {
s.Events = append(s.Events, &Event{})
}
}

s.Events[n].Desc = desc
s.Events[n].MarkPattern(group, pattern, false)
},
EqualMatch: func(ctx context.Context, a, b any, eq bool) {
if !eq {
return
}

n, _ := strconv.Atoi(trace.Get(ctx, "step-index"))
group := trace.Get(ctx, "pattern-group")
pattern := trace.Get(ctx, "pattern")

s.mu.Lock()
defer s.mu.Unlock()

s.Events[n].MarkPattern(group, pattern, eq)
},
}
}

func (e *Event) MarkPattern(group, pattern string, ok bool) {
switch group {
case "match":
if e.Match == nil {
e.Match = make(map[string]bool)
}
e.Match[pattern] = ok
case "pass":
if e.Pass == nil {
e.Pass = make(map[string]bool)
}
e.Pass[pattern] = ok
case "fail":
if e.Fail == nil {
e.Fail = make(map[string]bool)
}
e.Fail[pattern] = ok
default:
panic(fmt.Errorf("unknown group: %q (pattern=%q, ok=%v)", group, pattern, ok))
}
}

type Event struct {
Desc string `json:"desc,omitempty"`
Match map[string]bool `json:"match"`
Pass map[string]bool `json:"pass,omitempty"`
Fail map[string]bool `json:"fail,omitempty"`
}

type Events []*Event
30 changes: 25 additions & 5 deletions pkg/hookt/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import (
"context"
"log/slog"
"os"
"strconv"

"github.com/lmittmann/tint"
"golang.org/x/sync/errgroup"
"hookt.dev/cmd/pkg/check"
"hookt.dev/cmd/pkg/errors"
"hookt.dev/cmd/pkg/plugin/builtin"
"hookt.dev/cmd/pkg/proto"
"hookt.dev/cmd/pkg/trace"
)

var plugins []proto.Interface
Expand Down Expand Up @@ -43,17 +45,24 @@ func (e *Engine) Run(ctx context.Context, file string) (*check.S, error) {
return nil, errors.New("failed to read file: %w", err)
}

var s check.S

ctx = trace.WithPattern(ctx, trace.ContextPattern(ctx).Join(s.Trace()))

w, err := e.p.Parse(ctx, p)
if err != nil {
return nil, errors.New("failed to parse file: %w", err)
}

var s check.S

var g errgroup.Group

for _, job := range w.Jobs {
for _, step := range job.Steps {
for i, job := range w.Jobs {
ctx := trace.With(ctx, "job", job.ID)
ctx = trace.With(ctx, "job-index", strconv.Itoa(i))
for j, step := range job.Steps {
ctx := trace.With(ctx, "step", step.ID)
ctx = trace.With(ctx, "step-desc", step.Desc)
ctx = trace.With(ctx, "step-index", strconv.Itoa(j))
g.Go(func() error {
r, ok := step.With.(proto.Runner)
if !ok {
Expand All @@ -80,5 +89,16 @@ func (e *Engine) Run(ctx context.Context, file string) (*check.S, error) {
}
}

return &s, g.Wait()
done := make(chan error)

go func() {
done <- g.Wait()
}()

select {
case <-ctx.Done():
return &s, ctx.Err()
case err := <-done:
return &s, err
}
}
1 change: 0 additions & 1 deletion pkg/hookt/reflow.go

This file was deleted.

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

import (
"math/rand"
"strings"
)

const (
all = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
)

func Gen(n int) string {
return gen(all, 6, 1<<6-1, 63/6, n)
}

// source: https://stackoverflow.com/questions/22892120/
func gen(chars string, idxBits uint, idxMask int64, idxMax int, n int) string {
var sb strings.Builder

sb.Grow(n)

for i, cache, remain := n-1, rand.Int63(), idxMax; i >= 0; {
if remain == 0 {
cache, remain = rand.Int63(), idxMax
}
if idx := int(cache & idxMask); idx < len(chars) {
sb.WriteByte(chars[idx])
i--
}
cache >>= idxBits
remain--
}

return sb.String()
}
33 changes: 16 additions & 17 deletions pkg/plugin/builtin/event/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package event // import "hookt.dev/cmd/pkg/plugin/builtin/event"

import (
"context"
"encoding/json"
"log/slog"
"time"

"hookt.dev/cmd/pkg/check"
"hookt.dev/cmd/pkg/errors"
"hookt.dev/cmd/pkg/plugin/builtin/event/wire"
"hookt.dev/cmd/pkg/proto"
"hookt.dev/cmd/pkg/trace"
)

type Plugin struct {
Expand Down Expand Up @@ -94,7 +94,7 @@ func (p *Plugin) process() {
}
}

func (p *Plugin) Step(context.Context) any {
func (p *Plugin) Step(ctx context.Context) any {
c := make(chan proto.Message)
p.c[c] = struct{}{}
it, _ := time.ParseDuration(p.Config.InactiveTimeout)
Expand All @@ -113,32 +113,30 @@ type Step struct {
it time.Duration
}

func str(v any) string {
if v == nil {
return ""
}
p, _ := json.Marshal(v)
return string(p)
func group(ctx context.Context, name string) context.Context {
return trace.With(ctx, "pattern-group", name)
}

func (s *Step) Run(ctx context.Context, c *check.S) error {
slog.Debug("event: run",
"match", str(s.Match),
"pass", str(s.Pass),
"fail", str(s.Fail),
"match", s.Match,
"pass", s.Pass,
"fail", s.Fail,
)

match, err := s.p.p.Pattern(ctx, s.Match)
tr := trace.ContextPattern(ctx)

match, err := s.p.p.Patterns(group(ctx, "match"), s.Match)
if err != nil {
return errors.New("failed to parse match pattern: %w", err)
}

pass, err := s.p.p.Pattern(ctx, s.Pass)
pass, err := s.p.p.Patterns(group(ctx, "pass"), s.Pass)
if err != nil {
return errors.New("failed to parse pass pattern: %w", err)
}

fail, err := s.p.p.Pattern(ctx, s.Fail)
fail, err := s.p.p.Patterns(group(ctx, "fail"), s.Fail)
if err != nil {
return errors.New("failed to parse fail pattern: %w", err)
}
Expand All @@ -150,6 +148,7 @@ func (s *Step) Run(ctx context.Context, c *check.S) error {
select {
case <-inactive.C:
c.Fail()
tr.MatchTimeout(ctx)
return errors.New("step has timed out after %v", s.it)
case msg := <-s.c:
if !inactive.Stop() {
Expand All @@ -159,7 +158,7 @@ func (s *Step) Run(ctx context.Context, c *check.S) error {

obj := msg.Object()

match, err := match.Match(ctx, obj)
match, err := match.Match(group(ctx, "match"), obj)
if err != nil {
return errors.New("failed to match on pattern: %w", err)
}
Expand All @@ -168,7 +167,7 @@ func (s *Step) Run(ctx context.Context, c *check.S) error {
continue
}

fail, err := fail.Match(ctx, obj)
fail, err := fail.Match(group(ctx, "fail"), obj)
if err != nil {
return errors.New("failed to match fail pattern: %w", err)
}
Expand All @@ -177,7 +176,7 @@ func (s *Step) Run(ctx context.Context, c *check.S) error {
return errors.New("failure pattern matched")
}

ok, err := pass.Match(ctx, obj)
ok, err := pass.Match(group(ctx, "match"), obj)
if err != nil {
return errors.New("failed to match ok pattern: %w", err)
}
Expand Down
Loading

0 comments on commit 23e6677

Please sign in to comment.