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 17, 2024
1 parent c2e7990 commit bd75b32
Show file tree
Hide file tree
Showing 63 changed files with 3,645 additions and 318 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"fieldalignment",
"fortytw",
"fsys",
"Fugazi",
"goconst",
"gocritic",
"gocyclo",
Expand All @@ -48,12 +49,14 @@
"hiber",
"icase",
"ineffassign",
"Innerworld",
"jibberjabber",
"Kontroller",
"leaktest",
"linecomment",
"linters",
"lorax",
"Marillion",
"mattn",
"musico",
"Mutables",
Expand Down
29 changes: 23 additions & 6 deletions builders.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package tv

import (
"github.com/snivilised/traverse/core"
"github.com/snivilised/traverse/enums"
"github.com/snivilised/traverse/internal/kernel"
"github.com/snivilised/traverse/internal/lo"
"github.com/snivilised/traverse/internal/override"
"github.com/snivilised/traverse/internal/types"
"github.com/snivilised/traverse/measure"
"github.com/snivilised/traverse/pref"
Expand Down Expand Up @@ -42,13 +44,26 @@ func (bs *Builders) buildAll() (*buildArtefacts, error) {

// BUILD NAVIGATOR
//
actions := &override.Actions{
HandleChildren: override.NewActionCtrl[override.HandleChildrenInterceptor](
func(inspection core.Inspection, mums measure.MutableMetrics) {
// [KEEP-FILTER-IN-SYNC] keep this in sync with filter plugin.Init
files := inspection.Sort(enums.EntryTypeFile)
inspection.AssignChildren(files)
mums[enums.MetricNoChildFilesFound].Times(uint(len(files)))
},
),
}

artefacts, navErr := bs.navigator.Build(o, &types.Resources{
FS: types.FileSystems{
N: ext.navFS(),
R: ext.resFS(),
},
Supervisor: measure.New(),
Actions: actions,
})

if navErr != nil {
return &buildArtefacts{
o: o,
Expand All @@ -75,14 +90,16 @@ func (bs *Builders) buildAll() (*buildArtefacts, error) {

// INIT PLUGINS
//
roles := lo.Map(plugins, func(plugin types.Plugin, _ int) enums.Role {
return plugin.Role()
})

artefacts.Mediator.Arrange(roles)
artefacts.Mediator.Arrange(lo.Map(plugins,
func(plugin types.Plugin, _ int) enums.Role {
return plugin.Role()
},
))

for _, p := range plugins {
if bindErr := p.Init(); bindErr != nil {
if bindErr := p.Init(&types.PluginInit{
Actions: actions,
}); bindErr != nil {
return &buildArtefacts{
o: o,
kc: artefacts.Kontroller,
Expand Down
4 changes: 2 additions & 2 deletions collections/positional-set.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (ps *PositionalSet[T]) Insert(item T) bool {
return false
}

// Add insert multiple items into the set under the same conditions as
// All inserts multiple items into the set under the same conditions as
// Insert
func (ps *PositionalSet[T]) All(items ...T) bool {
result := true
Expand All @@ -72,7 +72,7 @@ func (ps *PositionalSet[T]) All(items ...T) bool {
return result
}

// Delete removes an item from the set
// Delete removes an item from the set. Removing the anchor is prohibited.
func (ps *PositionalSet[T]) Delete(item T) {
if item == ps.anchor {
return
Expand Down
24 changes: 19 additions & 5 deletions core/directory-contents.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,28 @@ package core

import (
"io/fs"

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

// DirectoryContents represents the contents of a directory's contents and
// handles sorting order which by default is different between various
// operating systems. This abstraction removes the differences in sorting
// behaviour on different platforms.
type DirectoryContents interface {
All() []fs.DirEntry
Folders() []fs.DirEntry
Files() []fs.DirEntry
}
type (
DirectoryContents interface {
All() []fs.DirEntry
Folders() []fs.DirEntry
Files() []fs.DirEntry
}

// Inspection
Inspection interface {
Current() *Node
Contents() DirectoryContents
Entries() []fs.DirEntry
Sort(et enums.EntryType) []fs.DirEntry
Pick(et enums.EntryType)
AssignChildren(children []fs.DirEntry)
}
)
107 changes: 106 additions & 1 deletion core/filtering.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,109 @@
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 true).
IfNotApplicable enums.TriStateBool

// 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
}

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
Loading

0 comments on commit bd75b32

Please sign in to comment.