From 8a78907977f9784c3d431bd5b8bc451ca843810a Mon Sep 17 00:00:00 2001 From: James Shubin Date: Wed, 20 Mar 2024 17:37:45 -0400 Subject: [PATCH] engine: autogroup, traits, graph: Extend autogroup API This extends the autogrouping API so that a child can easily get a reference to the parent that it is autogrouped in. This can simplify the API for some resources when it makes sense to allow them access to the parent handle. Use sparingly and intelligently! --- engine/autogroup.go | 12 ++++++++++-- engine/copy.go | 1 + engine/graph/autogroup.go | 1 + engine/graph/autogroup/autogroup_test.go | 2 ++ engine/traits/autogroup.go | 17 +++++++++++++++-- 5 files changed, 29 insertions(+), 4 deletions(-) diff --git a/engine/autogroup.go b/engine/autogroup.go index 1e205330..4f17ce97 100644 --- a/engine/autogroup.go +++ b/engine/autogroup.go @@ -54,7 +54,8 @@ type GroupableRes interface { // grouping. This usually needs to be unique to your resource. GroupCmp(res GroupableRes) error - // GroupRes groups resource argument (res) into self. + // GroupRes groups resource argument (res) into self. Callers of this + // method should probably also run SetParent. GroupRes(res GroupableRes) error // IsGrouped determines if we are grouped. @@ -66,8 +67,15 @@ type GroupableRes interface { // GetGroup returns everyone grouped inside me. GetGroup() []GroupableRes // return everyone grouped inside me - // SetGroup sets the grouped resources into me. + // SetGroup sets the grouped resources into me. Callers of this method + // should probably also run SetParent. SetGroup([]GroupableRes) + + // Parent returns the parent groupable resource that I am inside of. + Parent() GroupableRes + + // SetParent tells a particular grouped resource who their parent is. + SetParent(res GroupableRes) } // AutoGroupMeta provides some parameters specific to automatic grouping. diff --git a/engine/copy.go b/engine/copy.go index e273074a..2f69dd7b 100644 --- a/engine/copy.go +++ b/engine/copy.go @@ -93,6 +93,7 @@ func ResCopy(r CopyableRes) (CopyableRes, error) { if !ok { return nil, fmt.Errorf("resource wasn't groupable") } + g2.SetParent(dst) // store who my parent is grouped = append(grouped, g2) } dst.SetGroup(grouped) diff --git a/engine/graph/autogroup.go b/engine/graph/autogroup.go index 0c6afc81..6c393ded 100644 --- a/engine/graph/autogroup.go +++ b/engine/graph/autogroup.go @@ -121,6 +121,7 @@ func (obj *wrappedGrouper) VertexMerge(v1, v2 pgraph.Vertex) (v pgraph.Vertex, e if err = r1.GroupRes(r2); err != nil { // GroupRes skips stupid groupings return // return early on error } + r2.SetParent(r1) // store who my parent is // merging two resources into one should yield the sum of their semas if semas := r2.MetaParams().Sema; len(semas) > 0 { diff --git a/engine/graph/autogroup/autogroup_test.go b/engine/graph/autogroup/autogroup_test.go index 1ad1551f..96236892 100644 --- a/engine/graph/autogroup/autogroup_test.go +++ b/engine/graph/autogroup/autogroup_test.go @@ -202,6 +202,8 @@ func (obj *testGrouper) VertexMerge(v1, v2 pgraph.Vertex) (v pgraph.Vertex, err if err := r1.GroupRes(r2); err != nil { // group them first return nil, err } + r2.SetParent(r1) // store who my parent is + // HACK: update the name so it matches full list of self+grouped res := v1.(engine.GroupableRes) names := strings.Split(res.Name(), ",") // load in stored names diff --git a/engine/traits/autogroup.go b/engine/traits/autogroup.go index 4a014e5e..82cb5635 100644 --- a/engine/traits/autogroup.go +++ b/engine/traits/autogroup.go @@ -45,6 +45,7 @@ type Groupable struct { isGrouped bool // am i contained within a group? grouped []engine.GroupableRes // list of any grouped resources + parent engine.GroupableRes // resource i am grouped inside of // Bug5819 works around issue https://github.com/golang/go/issues/5819 Bug5819 interface{} // XXX: workaround @@ -74,7 +75,8 @@ func (obj *Groupable) GroupCmp(res engine.GroupableRes) error { return fmt.Errorf("the default grouping compare is not nil") } -// GroupRes groups resource argument (res) into self. +// GroupRes groups resource argument (res) into self. Callers of this method +// should probably also run SetParent. func (obj *Groupable) GroupRes(res engine.GroupableRes) error { if l := len(res.GetGroup()); l > 0 { return fmt.Errorf("the `%s` resource already contains %d grouped resources", res, l) @@ -103,7 +105,18 @@ func (obj *Groupable) GetGroup() []engine.GroupableRes { return obj.grouped } -// SetGroup sets the grouped resources into me. +// SetGroup sets the grouped resources into me. Callers of this method should +// probably also run SetParent. func (obj *Groupable) SetGroup(grouped []engine.GroupableRes) { obj.grouped = grouped } + +// Parent returns the parent groupable resource that I am inside of. +func (obj *Groupable) Parent() engine.GroupableRes { + return obj.parent +} + +// SetParent tells a particular grouped resource who their parent is. +func (obj *Groupable) SetParent(res engine.GroupableRes) { + obj.parent = res +}