diff --git a/ypathgen/pathgen.go b/ypathgen/pathgen.go index 0b9636245..cea4bff67 100644 --- a/ypathgen/pathgen.go +++ b/ypathgen/pathgen.go @@ -228,11 +228,12 @@ func (goLangMapper) PopulateFieldFlags(nd ygen.NodeDetails, field *yang.Entry) m // a map of package names to GeneratedPathCode structs. Each struct contains // all the generated code of that package needed support the path-creation API. // The important components of the generated code are listed below: -// 1. Struct definitions for each container, list, or leaf schema node, -// as well as the fakeroot. -// 2. Next-level methods for the fakeroot and each non-leaf schema node, -// which instantiate and return the next-level structs corresponding to -// its child schema nodes. +// 1. Struct definitions for each container, list, or leaf schema node, +// as well as the fakeroot. +// 2. Next-level methods for the fakeroot and each non-leaf schema node, +// which instantiate and return the next-level structs corresponding to +// its child schema nodes. +// // With these components, the generated API is able to support absolute path // creation of any node of the input schema. // Also returned is the NodeDataMap of the schema, i.e. information about each @@ -392,33 +393,31 @@ func (genCode GeneratedPathCode) String() string { // output files can be roughly controlled. func (genCode GeneratedPathCode) SplitFiles(fileN int) ([]string, error) { structN := len(genCode.Structs) - if fileN < 1 || fileN > structN { + if fileN < 1 { return nil, fmt.Errorf("requested %d files, but must be between 1 and %d (number of structs)", fileN, structN) } - files := make([]string, 0, fileN) + files := []string{} structsPerFile := int(math.Ceil(float64(structN) / float64(fileN))) - // Empty files could appear with certain structN/fileN combinations due - // to the ceiling numbers being used for structsPerFile. - // e.g. 4/3 gives two files of two structs. - // This is a little more complex, but spreads out the structs more evenly. - // If we instead use the floor number, and put all remainder structs in - // the last file, we might double the last file's number of structs if we get unlucky. - // e.g. 99/10 assigns 18 structs to the last file. - emptyFiles := fileN - int(math.Ceil(float64(structN)/float64(structsPerFile))) - var gotCode strings.Builder - gotCode.WriteString(genCode.CommonHeader) + + fileContent := [][]string{} + structs := []string{} for i, gotStruct := range genCode.Structs { - gotCode.WriteString(gotStruct.String()) - // The last file contains the remainder of the structs. - if i == structN-1 || (i+1)%structsPerFile == 0 { - files = append(files, gotCode.String()) - gotCode.Reset() - gotCode.WriteString(genCode.CommonHeader) + if i != 0 && i%structsPerFile == 0 { + fileContent = append(fileContent, structs) + structs = []string{} } + structs = append(structs, gotStruct.String()) } - for i := 0; i != emptyFiles; i++ { - files = append(files, genCode.CommonHeader) + fileContent = append(fileContent, structs) + var gotCode strings.Builder + for _, f := range fileContent { + gotCode.WriteString(genCode.CommonHeader) + for _, s := range f { + gotCode.WriteString(s) + } + files = append(files, gotCode.String()) + gotCode.Reset() } return files, nil @@ -1258,18 +1257,19 @@ type keyParam struct { // list of each parameter's types as a comment string. // It outputs the parameters in the same order as in the given keyNames. // e.g. -// in: &map[string]*ygen.ListKey{ -// "fluorine": &ygen.ListKey{ -// Name: "Fluorine", LangType: &ygen.MappedType{NativeType: "string"} -// }, -// "iodine-liquid": &ygen.ListKey{ -// Name: "IodineLiquid", LangType: &ygen.MappedType{NativeType: "A_Union", UnionTypes: {"Binary": 0, "uint64": 1}} -// }, -// } -// KeyNames: []string{"fluorine", "iodine-liquid"}, // -// {name, varName, typeName} out: [{"fluroine", "Fluorine", "string"}, {"iodine-liquid", "IodineLiquid", "oc.A_Union"}] -// docstring out: ["string", "[oc.Binary, oc.UnionUint64]"] +// in: &map[string]*ygen.ListKey{ +// "fluorine": &ygen.ListKey{ +// Name: "Fluorine", LangType: &ygen.MappedType{NativeType: "string"} +// }, +// "iodine-liquid": &ygen.ListKey{ +// Name: "IodineLiquid", LangType: &ygen.MappedType{NativeType: "A_Union", UnionTypes: {"Binary": 0, "uint64": 1}} +// }, +// } +// KeyNames: []string{"fluorine", "iodine-liquid"}, +// +// {name, varName, typeName} out: [{"fluroine", "Fluorine", "string"}, {"iodine-liquid", "IodineLiquid", "oc.A_Union"}] +// docstring out: ["string", "[oc.Binary, oc.UnionUint64]"] func makeKeyParams(keys map[string]*ygen.ListKey, keyNames []string, schemaStructPkgAccessor string) ([]keyParam, error) { if len(keys) == 0 { return nil, fmt.Errorf("makeKeyParams: invalid list - has no key; cannot process param list string") diff --git a/ypathgen/pathgen_test.go b/ypathgen/pathgen_test.go index 044a564b5..72f48e0bc 100644 --- a/ypathgen/pathgen_test.go +++ b/ypathgen/pathgen_test.go @@ -1013,9 +1013,9 @@ func TestGeneratePathCodeSplitFiles(t *testing.T) { }{{ name: "fileNumber is higher than total number of structs", inFiles: []string{filepath.Join(datapath, "openconfig-simple.yang")}, - inFileNumber: 5, - inSchemaStructPkgPath: "", - wantErr: true, + inFileNumber: 100, + inSchemaStructPkgPath: "github.com/openconfig/ygot/ypathgen/testdata/exampleoc", + wantStructsCodeFiles: []string{filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple.higher-0.path-txt"), filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple.higher-1.path-txt"), filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple.higher-2.path-txt"), filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple.higher-3.path-txt")}, }, { name: "fileNumber is exactly the total number of structs", inFiles: []string{filepath.Join(datapath, "openconfig-simple.yang")}, @@ -1027,7 +1027,7 @@ func TestGeneratePathCodeSplitFiles(t *testing.T) { inFiles: []string{filepath.Join(datapath, "openconfig-simple.yang")}, inFileNumber: 3, inSchemaStructPkgPath: "", - wantStructsCodeFiles: []string{filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple-30.path-txt"), filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple-31.path-txt"), filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple-32.path-txt")}, + wantStructsCodeFiles: []string{filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple-30.path-txt"), filepath.Join(TestRoot, "testdata/splitstructs/openconfig-simple-31.path-txt")}, }, { name: "fileNumber is half the total number of structs", inFiles: []string{filepath.Join(datapath, "openconfig-simple.yang")}, @@ -1940,27 +1940,30 @@ func TestGetNodeDataMap(t *testing.T) { // trimDocComments removes doc comments from the input code snippet string. // Example: -// // foo does bar -// func foo() { -// // baz is need to do boo. -// baz() -// } // -// // foo2 does bar2 -// func foo2() { -// // baz2 is need to do boo2. -// baz2() -// } +// // foo does bar +// func foo() { +// // baz is need to do boo. +// baz() +// } +// +// // foo2 does bar2 +// func foo2() { +// // baz2 is need to do boo2. +// baz2() +// } +// // After: -// func foo() { -// // baz is need to do boo. -// baz() -// } // -// func foo2() { -// // baz2 is need to do boo2. -// baz2() -// } +// func foo() { +// // baz is need to do boo. +// baz() +// } +// +// func foo2() { +// // baz2 is need to do boo2. +// baz2() +// } func trimDocComments(snippet string) string { var b strings.Builder for i, line := range strings.Split(snippet, "\n") { diff --git a/ypathgen/testdata/splitstructs/openconfig-simple-32.path-txt b/ypathgen/testdata/splitstructs/openconfig-simple-32.path-txt deleted file mode 100644 index 9001b7f38..000000000 --- a/ypathgen/testdata/splitstructs/openconfig-simple-32.path-txt +++ /dev/null @@ -1,15 +0,0 @@ -/* -Package ocstructs is a generated package which contains definitions -of structs which generate gNMI paths for a YANG schema. The generated paths are -based on a compressed form of the schema. - -This package was generated by pathgen-tests -using the following YANG input files: - - ../testdata/modules/openconfig-simple.yang -Imported modules were sourced from: -*/ -package ocstructs - -import ( - "github.com/openconfig/ygot/ygot" -) diff --git a/ypathgen/testdata/splitstructs/openconfig-simple.higher-0.path-txt b/ypathgen/testdata/splitstructs/openconfig-simple.higher-0.path-txt new file mode 100644 index 000000000..c8a3b115a --- /dev/null +++ b/ypathgen/testdata/splitstructs/openconfig-simple.higher-0.path-txt @@ -0,0 +1,59 @@ +/* +Package ocstructs is a generated package which contains definitions +of structs which generate gNMI paths for a YANG schema. The generated paths are +based on a compressed form of the schema. + +This package was generated by pathgen-tests +using the following YANG input files: + - ../testdata/modules/openconfig-simple.yang +Imported modules were sourced from: +*/ +package ocstructs + +import ( + oc "github.com/openconfig/ygot/ypathgen/testdata/exampleoc" + "github.com/openconfig/ygot/ygot" +) + +// Device represents the /device YANG schema element. +type Device struct { + *ygot.DeviceRootBase +} + +// DeviceRoot returns a new path object from which YANG paths can be constructed. +func DeviceRoot(id string) *Device { + return &Device{ygot.NewDeviceRootBase(id)} +} + +// Parent (container): I am a parent container +// that has 4 children. +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "parent" +// Path from root: "/parent" +func (n *Device) Parent() *Parent { + return &Parent{ + NodePath: ygot.NewNodePath( + []string{"parent"}, + map[string]interface{}{}, + n, + ), + } +} + +// RemoteContainer (container): +// ---------------------------------------- +// Defining module: "openconfig-remote" +// Instantiating module: "openconfig-simple" +// Path from parent: "remote-container" +// Path from root: "/remote-container" +func (n *Device) RemoteContainer() *RemoteContainer { + return &RemoteContainer{ + NodePath: ygot.NewNodePath( + []string{"remote-container"}, + map[string]interface{}{}, + n, + ), + } +} diff --git a/ypathgen/testdata/splitstructs/openconfig-simple.higher-1.path-txt b/ypathgen/testdata/splitstructs/openconfig-simple.higher-1.path-txt new file mode 100644 index 000000000..a3a255b26 --- /dev/null +++ b/ypathgen/testdata/splitstructs/openconfig-simple.higher-1.path-txt @@ -0,0 +1,58 @@ +/* +Package ocstructs is a generated package which contains definitions +of structs which generate gNMI paths for a YANG schema. The generated paths are +based on a compressed form of the schema. + +This package was generated by pathgen-tests +using the following YANG input files: + - ../testdata/modules/openconfig-simple.yang +Imported modules were sourced from: +*/ +package ocstructs + +import ( + oc "github.com/openconfig/ygot/ypathgen/testdata/exampleoc" + "github.com/openconfig/ygot/ygot" +) + +// Parent represents the /openconfig-simple/parent YANG schema element. +type Parent struct { + *ygot.NodePath +} + +// ParentAny represents the wildcard version of the /openconfig-simple/parent YANG schema element. +type ParentAny struct { + *ygot.NodePath +} + +// Child (container): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "child" +// Path from root: "/parent/child" +func (n *Parent) Child() *Parent_Child { + return &Parent_Child{ + NodePath: ygot.NewNodePath( + []string{"child"}, + map[string]interface{}{}, + n, + ), + } +} + +// Child (container): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "child" +// Path from root: "/parent/child" +func (n *ParentAny) Child() *Parent_ChildAny { + return &Parent_ChildAny{ + NodePath: ygot.NewNodePath( + []string{"child"}, + map[string]interface{}{}, + n, + ), + } +} diff --git a/ypathgen/testdata/splitstructs/openconfig-simple.higher-2.path-txt b/ypathgen/testdata/splitstructs/openconfig-simple.higher-2.path-txt new file mode 100644 index 000000000..33d19a59c --- /dev/null +++ b/ypathgen/testdata/splitstructs/openconfig-simple.higher-2.path-txt @@ -0,0 +1,194 @@ +/* +Package ocstructs is a generated package which contains definitions +of structs which generate gNMI paths for a YANG schema. The generated paths are +based on a compressed form of the schema. + +This package was generated by pathgen-tests +using the following YANG input files: + - ../testdata/modules/openconfig-simple.yang +Imported modules were sourced from: +*/ +package ocstructs + +import ( + oc "github.com/openconfig/ygot/ypathgen/testdata/exampleoc" + "github.com/openconfig/ygot/ygot" +) + +// Parent_Child represents the /openconfig-simple/parent/child YANG schema element. +type Parent_Child struct { + *ygot.NodePath +} + +// Parent_ChildAny represents the wildcard version of the /openconfig-simple/parent/child YANG schema element. +type Parent_ChildAny struct { + *ygot.NodePath +} + +// Parent_Child_Four represents the /openconfig-simple/parent/child/state/four YANG schema element. +type Parent_Child_Four struct { + *ygot.NodePath +} + +// Parent_Child_FourAny represents the wildcard version of the /openconfig-simple/parent/child/state/four YANG schema element. +type Parent_Child_FourAny struct { + *ygot.NodePath +} + +// Parent_Child_One represents the /openconfig-simple/parent/child/state/one YANG schema element. +type Parent_Child_One struct { + *ygot.NodePath +} + +// Parent_Child_OneAny represents the wildcard version of the /openconfig-simple/parent/child/state/one YANG schema element. +type Parent_Child_OneAny struct { + *ygot.NodePath +} + +// Parent_Child_Three represents the /openconfig-simple/parent/child/state/three YANG schema element. +type Parent_Child_Three struct { + *ygot.NodePath +} + +// Parent_Child_ThreeAny represents the wildcard version of the /openconfig-simple/parent/child/state/three YANG schema element. +type Parent_Child_ThreeAny struct { + *ygot.NodePath +} + +// Parent_Child_Two represents the /openconfig-simple/parent/child/state/two YANG schema element. +type Parent_Child_Two struct { + *ygot.NodePath +} + +// Parent_Child_TwoAny represents the wildcard version of the /openconfig-simple/parent/child/state/two YANG schema element. +type Parent_Child_TwoAny struct { + *ygot.NodePath +} + +// Four (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/four" +// Path from root: "/parent/child/state/four" +func (n *Parent_Child) Four() *Parent_Child_Four { + return &Parent_Child_Four{ + NodePath: ygot.NewNodePath( + []string{"state", "four"}, + map[string]interface{}{}, + n, + ), + } +} + +// Four (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/four" +// Path from root: "/parent/child/state/four" +func (n *Parent_ChildAny) Four() *Parent_Child_FourAny { + return &Parent_Child_FourAny{ + NodePath: ygot.NewNodePath( + []string{"state", "four"}, + map[string]interface{}{}, + n, + ), + } +} + +// One (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/one" +// Path from root: "/parent/child/state/one" +func (n *Parent_Child) One() *Parent_Child_One { + return &Parent_Child_One{ + NodePath: ygot.NewNodePath( + []string{"state", "one"}, + map[string]interface{}{}, + n, + ), + } +} + +// One (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/one" +// Path from root: "/parent/child/state/one" +func (n *Parent_ChildAny) One() *Parent_Child_OneAny { + return &Parent_Child_OneAny{ + NodePath: ygot.NewNodePath( + []string{"state", "one"}, + map[string]interface{}{}, + n, + ), + } +} + +// Three (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/three" +// Path from root: "/parent/child/state/three" +func (n *Parent_Child) Three() *Parent_Child_Three { + return &Parent_Child_Three{ + NodePath: ygot.NewNodePath( + []string{"state", "three"}, + map[string]interface{}{}, + n, + ), + } +} + +// Three (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/three" +// Path from root: "/parent/child/state/three" +func (n *Parent_ChildAny) Three() *Parent_Child_ThreeAny { + return &Parent_Child_ThreeAny{ + NodePath: ygot.NewNodePath( + []string{"state", "three"}, + map[string]interface{}{}, + n, + ), + } +} + +// Two (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/two" +// Path from root: "/parent/child/state/two" +func (n *Parent_Child) Two() *Parent_Child_Two { + return &Parent_Child_Two{ + NodePath: ygot.NewNodePath( + []string{"state", "two"}, + map[string]interface{}{}, + n, + ), + } +} + +// Two (leaf): +// ---------------------------------------- +// Defining module: "openconfig-simple" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/two" +// Path from root: "/parent/child/state/two" +func (n *Parent_ChildAny) Two() *Parent_Child_TwoAny { + return &Parent_Child_TwoAny{ + NodePath: ygot.NewNodePath( + []string{"state", "two"}, + map[string]interface{}{}, + n, + ), + } +} diff --git a/ypathgen/testdata/splitstructs/openconfig-simple.higher-3.path-txt b/ypathgen/testdata/splitstructs/openconfig-simple.higher-3.path-txt new file mode 100644 index 000000000..89a37606e --- /dev/null +++ b/ypathgen/testdata/splitstructs/openconfig-simple.higher-3.path-txt @@ -0,0 +1,68 @@ +/* +Package ocstructs is a generated package which contains definitions +of structs which generate gNMI paths for a YANG schema. The generated paths are +based on a compressed form of the schema. + +This package was generated by pathgen-tests +using the following YANG input files: + - ../testdata/modules/openconfig-simple.yang +Imported modules were sourced from: +*/ +package ocstructs + +import ( + oc "github.com/openconfig/ygot/ypathgen/testdata/exampleoc" + "github.com/openconfig/ygot/ygot" +) + +// RemoteContainer represents the /openconfig-simple/remote-container YANG schema element. +type RemoteContainer struct { + *ygot.NodePath +} + +// RemoteContainerAny represents the wildcard version of the /openconfig-simple/remote-container YANG schema element. +type RemoteContainerAny struct { + *ygot.NodePath +} + +// RemoteContainer_ALeaf represents the /openconfig-simple/remote-container/state/a-leaf YANG schema element. +type RemoteContainer_ALeaf struct { + *ygot.NodePath +} + +// RemoteContainer_ALeafAny represents the wildcard version of the /openconfig-simple/remote-container/state/a-leaf YANG schema element. +type RemoteContainer_ALeafAny struct { + *ygot.NodePath +} + +// ALeaf (leaf): +// ---------------------------------------- +// Defining module: "openconfig-remote" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/a-leaf" +// Path from root: "/remote-container/state/a-leaf" +func (n *RemoteContainer) ALeaf() *RemoteContainer_ALeaf { + return &RemoteContainer_ALeaf{ + NodePath: ygot.NewNodePath( + []string{"state", "a-leaf"}, + map[string]interface{}{}, + n, + ), + } +} + +// ALeaf (leaf): +// ---------------------------------------- +// Defining module: "openconfig-remote" +// Instantiating module: "openconfig-simple" +// Path from parent: "state/a-leaf" +// Path from root: "/remote-container/state/a-leaf" +func (n *RemoteContainerAny) ALeaf() *RemoteContainer_ALeafAny { + return &RemoteContainer_ALeafAny{ + NodePath: ygot.NewNodePath( + []string{"state", "a-leaf"}, + map[string]interface{}{}, + n, + ), + } +}