Skip to content

Commit

Permalink
feat: implement filtering (#74)
Browse files Browse the repository at this point in the history
  • Loading branch information
plastikfan committed Jul 12, 2024
1 parent c2e7990 commit 098d292
Show file tree
Hide file tree
Showing 35 changed files with 1,762 additions and 59 deletions.
117 changes: 116 additions & 1 deletion core/filtering.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,119 @@
package core

type FilterDef struct {
import (
"io/fs"

"github.com/snivilised/traverse/enums"
)

// TraverseFilter filter that can be applied to file system entries. When specified,
// the callback will only be invoked for file system nodes that pass the filter.
type (
TraverseFilter interface {
// Description describes filter
Description() string

// Validate ensures the filter definition is valid, panics when invalid
Validate()

// Source, filter definition (comes from filter definition Pattern)
Source() string

// IsMatch does this item match the filter
IsMatch(item *Node) bool

// IsApplicable is this filter applicable to this item's scope
IsApplicable(item *Node) bool

// Scope, what items this filter applies to
Scope() enums.FilterScope
}

FilterDef struct {
// Type specifies the type of filter (mandatory)
Type enums.FilterType

// Description describes filter (optional)
Description string

// Pattern filter definition (mandatory)
Pattern string

// Scope which file system entries this filter applies to (defaults
// to ScopeAllEn)
Scope enums.FilterScope

// Negate, reverses the applicability of the filter (Defaults to false)
Negate bool

// IfNotApplicable, when the filter does not apply to a directory entry,
// this value determines whether the callback is invoked for this entry
// or not (defaults to TriStateBoolTrueEn/true).
IfNotApplicable enums.TriStateBool

// Custom client define-able filter. When restoring for resume feature,
// its the client's responsibility to restore this themselves (see
// PersistenceRestorer)
Custom TraverseFilter `json:"-"`

// Poly allows for the definition of a PolyFilter which contains separate
// filters that target files and folders separately. If present, then
// all other fields are redundant, since the filter definitions inside
// Poly should be referred to instead.
Poly *PolyFilterDef
}

PolyFilterDef struct {
File FilterDef
Folder FilterDef
}

// ChildTraverseFilter filter that can be applied to a folder's collection of entries
// when subscription is

ChildTraverseFilter interface {
// Description describes filter
Description() string

// Validate ensures the filter definition is valid, panics when invalid
Validate()

// Source, filter definition (comes from filter definition Pattern)
Source() string

// Matching returns the collection of files contained within this
// item's folder that matches this filter.
Matching(children []fs.DirEntry) []fs.DirEntry
}

ChildFilterDef struct {
// Type specifies the type of filter (mandatory)
Type enums.FilterType

// Description describes filter (optional)
Description string

// Pattern filter definition (mandatory)
Pattern string

// Negate, reverses the applicability of the filter (Defaults to false)
Negate bool

// Custom client define-able filter. When restoring for resume feature,
// its the client's responsibility to restore this themselves (see
// PersistenceRestorer)
Custom ChildTraverseFilter `json:"-"`
}

compoundCounters struct {
filteredIn uint
filteredOut uint
}
)

var BenignNodeFilterDef = FilterDef{
Type: enums.FilterTypeRegex,
Description: "benign allow all",
Pattern: ".",
Scope: enums.ScopeRoot,
}
6 changes: 5 additions & 1 deletion cycle/cycle-defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ type (
// be used by any notification with this signature.
SimpleHandler func()

BeginState struct {
Root string
}

// BeginHandler invoked before traversal begins
BeginHandler func(root string)
BeginHandler func(state *BeginState)

// EndHandler invoked at the end of traversal
EndHandler func(result core.TraverseResult)
Expand Down
43 changes: 29 additions & 14 deletions cycle/event-begin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
. "github.com/onsi/ginkgo/v2" //nolint:revive // ok
. "github.com/onsi/gomega" //nolint:revive // ok

"github.com/snivilised/traverse/cycle"
"github.com/snivilised/traverse/pref"
)

Expand All @@ -15,10 +16,12 @@ var _ = Describe("event", func() {
invoked := false
o, _ := pref.Get()

o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
invoked = true
})
o.Binder.Controls.Begin.Dispatch()(traversalRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: traversalRoot,
})

Expect(invoked).To(BeTrue())
})
Expand All @@ -29,16 +32,20 @@ var _ = Describe("event", func() {
invoked := false
o, _ := pref.Get()

o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
invoked = true
})
o.Binder.Controls.Begin.Mute()
o.Binder.Controls.Begin.Dispatch()(traversalRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: traversalRoot,
})
Expect(invoked).To(BeFalse(), "notification not muted")

invoked = false
o.Binder.Controls.Begin.Unmute()
o.Binder.Controls.Begin.Dispatch()(traversalRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: traversalRoot,
})
Expect(invoked).To(BeTrue(), "notification not muted")
})
})
Expand All @@ -50,21 +57,25 @@ var _ = Describe("event", func() {
count := 0
o, _ := pref.Get()

o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
count++
})
o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
count++
})
o.Binder.Controls.Begin.Dispatch()(traversalRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: traversalRoot,
})
Expect(count).To(Equal(2), "not all listeners were invoked for first notification")

count = 0
o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
count++
})

o.Binder.Controls.Begin.Dispatch()(anotherRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: anotherRoot,
})
Expect(count).To(Equal(3), "not all listeners were invoked for second notification")
})
})
Expand All @@ -74,15 +85,17 @@ var _ = Describe("event", func() {
count := 0
o, _ := pref.Get()

o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
count++
})
o.Events.Begin.On(func(_ string) {
o.Events.Begin.On(func(_ *cycle.BeginState) {
count++
})

o.Binder.Controls.Begin.Mute()
o.Binder.Controls.Begin.Dispatch()(anotherRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: anotherRoot,
})

Expect(count).To(Equal(0), "notification not muted")
})
Expand All @@ -93,7 +106,9 @@ var _ = Describe("event", func() {
It("🧪 should: invoke no-op", func() {
o, _ := pref.Get()

o.Binder.Controls.Begin.Dispatch()(traversalRoot)
o.Binder.Controls.Begin.Dispatch()(&cycle.BeginState{
Root: traversalRoot,
})
})
})
})
Expand Down
6 changes: 3 additions & 3 deletions cycle/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,14 +140,14 @@ func (c *NotificationCtrl[F]) Unmute() {
}

func broadcastBegin(listeners []BeginHandler) BeginHandler {
return func(root string) {
return func(state *BeginState) {
for _, listener := range listeners {
listener(root)
listener(state)
}
}
}

func nopBegin(_ string) {}
func nopBegin(*BeginState) {}

func broadcastEnd(listeners []EndHandler) EndHandler {
return func(result core.TraverseResult) {
Expand Down
8 changes: 5 additions & 3 deletions cycle/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ var _ = Describe("controls", func() {

// client:
//
events.Begin.On(func(root string) {
events.Begin.On(func(state *cycle.BeginState) {
begun = true
Expect(root).To(Equal(path))
Expect(state.Root).To(Equal(path))
})

events.End.On(func(_ core.TraverseResult) {
Expand All @@ -37,7 +37,9 @@ var _ = Describe("controls", func() {

// component side:
//
controls.Begin.Dispatch()(path)
controls.Begin.Dispatch()(&cycle.BeginState{
Root: path,
})
controls.End.Dispatch()(nil)

Expect(begun).To(BeTrue(), "begin notification handler not invoked")
Expand Down
5 changes: 3 additions & 2 deletions director-prime_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
. "github.com/onsi/gomega" //nolint:revive // ok
tv "github.com/snivilised/traverse"
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/cycle"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/pref"
)
Expand Down Expand Up @@ -90,7 +91,7 @@ var _ = Describe("Director(Prime)", func() {
Subscription: tv.SubscribeFiles,
Handler: noOpHandler,
},
tv.WithOnBegin(func(_ string) {}),
tv.WithOnBegin(func(state *cycle.BeginState) {}),

Check warning on line 94 in director-prime_test.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'state' seems to be unused, consider removing or renaming it as _ (revive)
)).Navigate(ctx)

wg.Wait()
Expand Down Expand Up @@ -140,7 +141,7 @@ var _ = Describe("Director(Prime)", func() {
Subscription: tv.SubscribeFiles,
Handler: noOpHandler,
},
tv.WithFilter(&core.FilterDef{}),
tv.WithFilter(&pref.FilterOptions{}),
tv.WithOnStart(func(_ string) {}),
)).Navigate(ctx)

Expand Down
5 changes: 3 additions & 2 deletions director-resume_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (

tv "github.com/snivilised/traverse"
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/cycle"
"github.com/snivilised/traverse/internal/services"
"github.com/snivilised/traverse/pref"
)
Expand All @@ -19,7 +20,7 @@ var _ = Describe("Director(Resume)", Ordered, func() {

BeforeAll(func() {
restore = func(o *tv.Options) error {
o.Events.Begin.On(func(_ string) {})
o.Events.Begin.On(func(state *cycle.BeginState) {})

Check warning on line 23 in director-resume_test.go

View workflow job for this annotation

GitHub Actions / lint

unused-parameter: parameter 'state' seems to be unused, consider removing or renaming it as _ (revive)

return nil
}
Expand Down Expand Up @@ -105,7 +106,7 @@ var _ = Describe("Director(Resume)", Ordered, func() {
From: RestorePath,
Strategy: tv.ResumeStrategySpawn,
},
tv.WithFilter(&core.FilterDef{}),
tv.WithFilter(&pref.FilterOptions{}),
restore,
)).Navigate(ctx)

Expand Down
6 changes: 6 additions & 0 deletions internal/helpers/test-utilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,12 @@ func Reason(name string) string {
return fmt.Sprintf("❌ for item named: '%v'", name)
}

func BecauseQuantity(name string, expected, actual int) string {
return fmt.Sprintf("❌ incorrect no of items for: '%v', expected: '%v', actual: '%v'",
name, expected, actual,
)
}

func JoinCwd(segments ...string) string {
if current, err := os.Getwd(); err == nil {
parent, _ := filepath.Split(current)
Expand Down
2 changes: 2 additions & 0 deletions internal/kernel/base-plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ package kernel
import (
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/internal/types"
"github.com/snivilised/traverse/pref"
)

type BasePlugin struct {
O *pref.Options
Mediator types.Mediator
Kontroller types.KernelController
ActivatedRole enums.Role
Expand Down
Loading

0 comments on commit 098d292

Please sign in to comment.