Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PathAndStruct helper for generated non-leaf PathStruct types. #533

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
74,155 changes: 38,821 additions & 35,334 deletions exampleoc/oc.go

Large diffs are not rendered by default.

15,818 changes: 15,794 additions & 24 deletions exampleoc/ocpath.go

Large diffs are not rendered by default.

22 changes: 19 additions & 3 deletions ypathgen/path_tests/path_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,13 @@ func TestCustomData(t *testing.T) {
}
}

// This test shows ways to reduce typing when creating similar paths.
// This test shows ways to reduce typing when creating paths.
func TestManualShortcuts(t *testing.T) {
// defining short helpers
root := oc.DeviceRoot(deviceId)
preemptDelay := func(intf string, subintf uint32, ip string) ygot.PathStruct {
return root.Interface(intf).Subinterface(subintf).Ipv6().Address(ip).VrrpGroup(1).PreemptDelay()
}

// defining short helpers
verifyPath(t, preemptDelay("eth1", 1, "1::"), "/interfaces/interface[name=eth1]/subinterfaces/subinterface[index=1]/ipv6/addresses/address[ip=1::]/vrrp/vrrp-group[virtual-router-id=1]/config/preempt-delay")
verifyPath(t, preemptDelay("eth1", 2, "2:2:2:2::"), "/interfaces/interface[name=eth1]/subinterfaces/subinterface[index=2]/ipv6/addresses/address[ip=2:2:2:2::]/vrrp/vrrp-group[virtual-router-id=1]/config/preempt-delay")
verifyPath(t, preemptDelay("eth2", 2, "::"), "/interfaces/interface[name=eth2]/subinterfaces/subinterface[index=2]/ipv6/addresses/address[ip=::]/vrrp/vrrp-group[virtual-router-id=1]/config/preempt-delay")
Expand All @@ -111,6 +110,23 @@ func TestManualShortcuts(t *testing.T) {
intf1 := root.InterfaceAny()
verifyPath(t, intf1.Subinterface(3), "/interfaces/interface[name=*]/subinterfaces/subinterface[index=3]")
verifyPath(t, intf1.Subinterface(4), "/interfaces/interface[name=*]/subinterfaces/subinterface[index=4]")

// PathAndStruct helper
root, r := oc.DeviceRoot(deviceId).PathAndStruct()
r.Interface = nil
preemptDelay = func(intf string, subintf uint32, ip string) ygot.PathStruct {
ps, s := root.Interface(intf).Subinterface(subintf).Ipv6().Address(ip).VrrpGroup(1).PathAndStruct()
s.PreemptDelay = nil
return ps.PreemptDelay()
}
verifyPath(t, preemptDelay("eth1", 1, "1::"), "/interfaces/interface[name=eth1]/subinterfaces/subinterface[index=1]/ipv6/addresses/address[ip=1::]/vrrp/vrrp-group[virtual-router-id=1]/config/preempt-delay")
verifyPath(t, preemptDelay("eth1", 2, "2:2:2:2::"), "/interfaces/interface[name=eth1]/subinterfaces/subinterface[index=2]/ipv6/addresses/address[ip=2:2:2:2::]/vrrp/vrrp-group[virtual-router-id=1]/config/preempt-delay")
verifyPath(t, preemptDelay("eth2", 2, "::"), "/interfaces/interface[name=eth2]/subinterfaces/subinterface[index=2]/ipv6/addresses/address[ip=::]/vrrp/vrrp-group[virtual-router-id=1]/config/preempt-delay")

intf1, intf := root.InterfaceAny().PathAndStruct()
verifyPath(t, intf1.Subinterface(3), "/interfaces/interface[name=*]/subinterfaces/subinterface[index=3]")
verifyPath(t, intf1.Subinterface(4), "/interfaces/interface[name=*]/subinterfaces/subinterface[index=4]")
intf.Mtu = nil
}

func TestPathCreation(t *testing.T) {
Expand Down
40 changes: 35 additions & 5 deletions ypathgen/pathgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,11 @@ type {{ .TypeName }} struct {
func DeviceRoot(id string) *{{ .TypeName }} {
return &{{ .TypeName }}{ygot.New{{- .FakeRootBaseTypeName }}(id)}
}

// PathAndStruct returns the path struct and an empty {{ .GoStructTypeName }} for the path "{{ .YANGPath }}".
func (n *{{ .TypeName }}) PathAndStruct() (*{{ .TypeName }}, *{{ .GoStructTypeName }}) {
return n, &{{ .GoStructTypeName }}{}
}
`)

// goPathStructTemplate defines the template for the type definition of
Expand All @@ -499,6 +504,23 @@ type {{ .TypeName }}{{ .WildcardSuffix }} struct {
*ygot.{{ .PathBaseTypeName }}
}
{{- end }}
`)

// goPathAndStructHelperTemplate generates a helper for non-leaves that returns
// the PathStruct and an empty corresponding GoStruct.
goPathAndStructHelperTemplate = mustTemplate("goPathAndStructHelper", `
// PathAndStruct returns the path struct and an empty {{ .GoStructTypeName }} for the path "{{ .YANGPath }}".
func (n *{{ .TypeName }}) PathAndStruct() (*{{ .TypeName }}, *{{ .GoStructTypeName }}) {
return n, &{{ .GoStructTypeName }}{}
}

{{- if .GenerateWildcardPaths }}

// PathAndStruct returns the wildcard path struct and an empty {{ .GoStructTypeName }} for the path "{{ .YANGPath }}".
func (n *{{ .TypeName }}{{ .WildcardSuffix }}) PathAndStruct() (*{{ .TypeName }}{{ .WildcardSuffix }}, *{{ .GoStructTypeName }}) {
return n, &{{ .GoStructTypeName }}{}
}
{{- end }}
`)

// goPathChildConstructorTemplate generates the child constructor method
Expand Down Expand Up @@ -659,6 +681,8 @@ func writeHeader(yangFiles, includePaths []string, cg *GenConfig, genCode *Gener
type goPathStructData struct {
// TypeName is the type name of the struct being output.
TypeName string
// GoStructTypeName is the type name of the corresponding GoStruct.
GoStructTypeName string
// YANGPath is the schema path of the struct being output.
YANGPath string
// PathBaseTypeName is the type name of the common embedded path struct.
Expand All @@ -678,9 +702,10 @@ type goPathStructData struct {
// getStructData returns the goPathStructData corresponding to a Directory,
// which is used to store the attributes of the template for which code is
// being generated.
func getStructData(directory *ygen.Directory, pathStructSuffix string, generateWildcardPaths bool) goPathStructData {
func getStructData(directory *ygen.Directory, pathStructSuffix, schemaStructPkgAccessor string, generateWildcardPaths bool) goPathStructData {
return goPathStructData{
TypeName: directory.Name + pathStructSuffix,
GoStructTypeName: schemaStructPkgAccessor + directory.Name,
YANGPath: util.SlicePathToString(directory.Path),
PathBaseTypeName: ygot.PathBaseTypeName,
FakeRootBaseTypeName: ygot.FakeRootBaseTypeName,
Expand Down Expand Up @@ -718,14 +743,19 @@ func generateDirectorySnippet(directory *ygen.Directory, directories map[string]
var methodBuf strings.Builder

// Output struct snippets.
structData := getStructData(directory, pathStructSuffix, generateWildcardPaths)
structData := getStructData(directory, pathStructSuffix, schemaStructPkgAccessor, generateWildcardPaths)
if ygen.IsFakeRoot(directory.Entry) {
// Fakeroot has its unique output.
if err := goPathFakeRootTemplate.Execute(&structBuf, structData); err != nil {
return GoPathStructCodeSnippet{}, util.AppendErr(errs, err)
}
} else if err := goPathStructTemplate.Execute(&structBuf, structData); err != nil {
return GoPathStructCodeSnippet{}, util.AppendErr(errs, err)
} else {
if err := goPathStructTemplate.Execute(&structBuf, structData); err != nil {
return GoPathStructCodeSnippet{}, util.AppendErr(errs, err)
}
if err := goPathAndStructHelperTemplate.Execute(&structBuf, structData); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should generating the path and struct helper be optional? In general we've tried to have these other features that are new types of output flag-controlled in the library - even if we have it as on by default, it'd probably be nice to have something whereby a user can turn this off if they don't want it to save on generated code size.

return GoPathStructCodeSnippet{}, util.AppendErr(errs, err)
}
}

goFieldNameMap := ygen.GoFieldNameMap(directory)
Expand Down Expand Up @@ -794,7 +824,7 @@ func generateChildConstructors(methodBuf *strings.Builder, directory *ygen.Direc
return []error{err}
}

structData := getStructData(directory, pathStructSuffix, generateWildcardPaths)
structData := getStructData(directory, pathStructSuffix, schemaStructPkgAccessor, generateWildcardPaths)
relPath, err := ygen.FindSchemaPath(directory, directoryFieldName, false)
if err != nil {
return []error{err}
Expand Down
40 changes: 40 additions & 0 deletions ypathgen/pathgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1612,6 +1612,16 @@ type ContainerWithConfigAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty oc.ContainerWithConfig for the path "/root-module/container-with-config".
func (n *ContainerWithConfig) PathAndStruct() (*ContainerWithConfig, *oc.ContainerWithConfig) {
return n, &oc.ContainerWithConfig{}
}

// PathAndStruct returns the wildcard path struct and an empty oc.ContainerWithConfig for the path "/root-module/container-with-config".
func (n *ContainerWithConfigAny) PathAndStruct() (*ContainerWithConfigAny, *oc.ContainerWithConfig) {
return n, &oc.ContainerWithConfig{}
}

// ContainerWithConfig_Leaf represents the /root-module/container-with-config/state/leaf YANG schema element.
type ContainerWithConfig_Leaf struct {
*ygot.NodePath
Expand Down Expand Up @@ -1718,6 +1728,11 @@ type ContainerWithConfig struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty oc.ContainerWithConfig for the path "/root-module/container-with-config".
func (n *ContainerWithConfig) PathAndStruct() (*ContainerWithConfig, *oc.ContainerWithConfig) {
return n, &oc.ContainerWithConfig{}
}

// ContainerWithConfig_Leaf represents the /root-module/container-with-config/state/leaf YANG schema element.
type ContainerWithConfig_Leaf struct {
*ygot.NodePath
Expand Down Expand Up @@ -1785,6 +1800,11 @@ func DeviceRoot(id string) *RootPath {
return &RootPath{ygot.NewDeviceRootBase(id)}
}

// PathAndStruct returns the path struct and an empty oc.Root for the path "/root".
func (n *RootPath) PathAndStruct() (*RootPath, *oc.Root) {
return n, &oc.Root{}
}

// LeafPath represents the /root-module/leaf YANG schema element.
type LeafPath struct {
*ygot.NodePath
Expand Down Expand Up @@ -1866,6 +1886,11 @@ func DeviceRoot(id string) *RootPath {
return &RootPath{ygot.NewDeviceRootBase(id)}
}

// PathAndStruct returns the path struct and an empty oc.Root for the path "/root".
func (n *RootPath) PathAndStruct() (*RootPath, *oc.Root) {
return n, &oc.Root{}
}

// LeafPath represents the /root-module/leaf YANG schema element.
type LeafPath struct {
*ygot.NodePath
Expand Down Expand Up @@ -1934,6 +1959,16 @@ type ListAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty oc.List for the path "/root-module/list-container/list".
func (n *List) PathAndStruct() (*List, *oc.List) {
return n, &oc.List{}
}

// PathAndStruct returns the wildcard path struct and an empty oc.List for the path "/root-module/list-container/list".
func (n *ListAny) PathAndStruct() (*ListAny, *oc.List) {
return n, &oc.List{}
}

// List_Key1 represents the /root-module/list-container/list/key1 YANG schema element.
type List_Key1 struct {
*ygot.NodePath
Expand Down Expand Up @@ -2040,6 +2075,11 @@ type List struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty oc.List for the path "/root-module/list-container/list".
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting -- for YANG container types it seems pretty clear to just return the struct, but in the case I call this with pathlib.ListContainer().ListAny().PathAndStruct() should I get back oc.List{} or map[...]*oc.List{}?

func (n *List) PathAndStruct() (*List, *oc.List) {
return n, &oc.List{}
}

// List_Key1 represents the /root-module/list-container/list/key1 YANG schema element.
type List_Key1 struct {
*ygot.NodePath
Expand Down
35 changes: 35 additions & 0 deletions ypathgen/testdata/structs/choice-case-example.path-txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ type ChoiceCaseAnonymousCasePathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty ChoiceCaseAnonymousCase for the path "/choice-case-example/choice-case-anonymous-case".
func (n *ChoiceCaseAnonymousCasePath) PathAndStruct() (*ChoiceCaseAnonymousCasePath, *ChoiceCaseAnonymousCase) {
return n, &ChoiceCaseAnonymousCase{}
}

// PathAndStruct returns the wildcard path struct and an empty ChoiceCaseAnonymousCase for the path "/choice-case-example/choice-case-anonymous-case".
func (n *ChoiceCaseAnonymousCasePathAny) PathAndStruct() (*ChoiceCaseAnonymousCasePathAny, *ChoiceCaseAnonymousCase) {
return n, &ChoiceCaseAnonymousCase{}
}

// ChoiceCaseAnonymousCase_APath represents the /choice-case-example/choice-case-anonymous-case/foo/a/a YANG schema element.
type ChoiceCaseAnonymousCase_APath struct {
*ygot.NodePath
Expand Down Expand Up @@ -98,6 +108,16 @@ type ChoiceCaseWithLeafrefPathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty ChoiceCaseWithLeafref for the path "/choice-case-example/choice-case-with-leafref".
func (n *ChoiceCaseWithLeafrefPath) PathAndStruct() (*ChoiceCaseWithLeafrefPath, *ChoiceCaseWithLeafref) {
return n, &ChoiceCaseWithLeafref{}
}

// PathAndStruct returns the wildcard path struct and an empty ChoiceCaseWithLeafref for the path "/choice-case-example/choice-case-with-leafref".
func (n *ChoiceCaseWithLeafrefPathAny) PathAndStruct() (*ChoiceCaseWithLeafrefPathAny, *ChoiceCaseWithLeafref) {
return n, &ChoiceCaseWithLeafref{}
}

// ChoiceCaseWithLeafref_PtrPath represents the /choice-case-example/choice-case-with-leafref/foo/bar/ptr YANG schema element.
type ChoiceCaseWithLeafref_PtrPath struct {
*ygot.NodePath
Expand Down Expand Up @@ -172,6 +192,11 @@ func DeviceRoot(id string) *DevicePath {
return &DevicePath{ygot.NewDeviceRootBase(id)}
}

// PathAndStruct returns the path struct and an empty Device for the path "/device".
func (n *DevicePath) PathAndStruct() (*DevicePath, *Device) {
return n, &Device{}
}

// ChoiceCaseAnonymousCase returns from DevicePath the path struct for its child "choice-case-anonymous-case".
func (n *DevicePath) ChoiceCaseAnonymousCase() *ChoiceCaseAnonymousCasePath {
return &ChoiceCaseAnonymousCasePath{
Expand Down Expand Up @@ -215,6 +240,16 @@ type SimpleChoiceCasePathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty SimpleChoiceCase for the path "/choice-case-example/simple-choice-case".
func (n *SimpleChoiceCasePath) PathAndStruct() (*SimpleChoiceCasePath, *SimpleChoiceCase) {
return n, &SimpleChoiceCase{}
}

// PathAndStruct returns the wildcard path struct and an empty SimpleChoiceCase for the path "/choice-case-example/simple-choice-case".
func (n *SimpleChoiceCasePathAny) PathAndStruct() (*SimpleChoiceCasePathAny, *SimpleChoiceCase) {
return n, &SimpleChoiceCase{}
}

// SimpleChoiceCase_APath represents the /choice-case-example/simple-choice-case/foo/bar/a YANG schema element.
type SimpleChoiceCase_APath struct {
*ygot.NodePath
Expand Down
55 changes: 55 additions & 0 deletions ypathgen/testdata/structs/enum-module.path-txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ type AListPathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty AList for the path "/enum-module/a-lists/a-list".
func (n *AListPath) PathAndStruct() (*AListPath, *AList) {
return n, &AList{}
}

// PathAndStruct returns the wildcard path struct and an empty AList for the path "/enum-module/a-lists/a-list".
func (n *AListPathAny) PathAndStruct() (*AListPathAny, *AList) {
return n, &AList{}
}

// AList_ValuePath represents the /enum-module/a-lists/a-list/state/value YANG schema element.
type AList_ValuePath struct {
*ygot.NodePath
Expand Down Expand Up @@ -66,6 +76,16 @@ type BListPathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty BList for the path "/enum-module/b-lists/b-list".
func (n *BListPath) PathAndStruct() (*BListPath, *BList) {
return n, &BList{}
}

// PathAndStruct returns the wildcard path struct and an empty BList for the path "/enum-module/b-lists/b-list".
func (n *BListPathAny) PathAndStruct() (*BListPathAny, *BList) {
return n, &BList{}
}

// BList_ValuePath represents the /enum-module/b-lists/b-list/state/value YANG schema element.
type BList_ValuePath struct {
*ygot.NodePath
Expand Down Expand Up @@ -108,6 +128,16 @@ type CPathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty C for the path "/enum-module/c".
func (n *CPath) PathAndStruct() (*CPath, *C) {
return n, &C{}
}

// PathAndStruct returns the wildcard path struct and an empty C for the path "/enum-module/c".
func (n *CPathAny) PathAndStruct() (*CPathAny, *C) {
return n, &C{}
}

// C_ClPath represents the /enum-module/c/cl YANG schema element.
type C_ClPath struct {
*ygot.NodePath
Expand Down Expand Up @@ -150,6 +180,11 @@ func DeviceRoot(id string) *DevicePath {
return &DevicePath{ygot.NewDeviceRootBase(id)}
}

// PathAndStruct returns the path struct and an empty Device for the path "/device".
func (n *DevicePath) PathAndStruct() (*DevicePath, *Device) {
return n, &Device{}
}

// AListAny returns from DevicePath the path struct for its child "a-list".
func (n *DevicePath) AListAny() *AListPathAny {
return &AListPathAny{
Expand Down Expand Up @@ -228,6 +263,16 @@ type ParentPathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty Parent for the path "/enum-module/parent".
func (n *ParentPath) PathAndStruct() (*ParentPath, *Parent) {
return n, &Parent{}
}

// PathAndStruct returns the wildcard path struct and an empty Parent for the path "/enum-module/parent".
func (n *ParentPathAny) PathAndStruct() (*ParentPathAny, *Parent) {
return n, &Parent{}
}

// Child returns from ParentPath the path struct for its child "child".
func (n *ParentPath) Child() *Parent_ChildPath {
return &Parent_ChildPath{
Expand Down Expand Up @@ -260,6 +305,16 @@ type Parent_ChildPathAny struct {
*ygot.NodePath
}

// PathAndStruct returns the path struct and an empty Parent_Child for the path "/enum-module/parent/child".
func (n *Parent_ChildPath) PathAndStruct() (*Parent_ChildPath, *Parent_Child) {
return n, &Parent_Child{}
}

// PathAndStruct returns the wildcard path struct and an empty Parent_Child for the path "/enum-module/parent/child".
func (n *Parent_ChildPathAny) PathAndStruct() (*Parent_ChildPathAny, *Parent_Child) {
return n, &Parent_Child{}
}

// Parent_Child_EnumPath represents the /enum-module/parent/child/state/enum YANG schema element.
type Parent_Child_EnumPath struct {
*ygot.NodePath
Expand Down
Loading