diff --git a/generator/golang/backend.go b/generator/golang/backend.go index f2729d84..c6883af1 100644 --- a/generator/golang/backend.go +++ b/generator/golang/backend.go @@ -89,7 +89,10 @@ func (g *GoBackend) Generate(req *plugin.Request, log backend.LogFunc) *plugin.R g.prepareUtilities() if g.utils.Features().TrimIDL { g.log.Warn("You Are Using IDL Trimmer") - structureTrimmed, fieldTrimmed, err := trim.TrimAST(&trim.TrimASTArg{Ast: req.AST, TrimMethods: nil, Preserve: nil}) + structureTrimmed, fieldTrimmed, err := trim.TrimASTWithCompose(&trim.TrimASTWithComposeArg{ + TargetAST: req.AST, + ReadCfgFromLocal: true, + }) if err != nil { g.log.Warn("trim error:", err.Error()) } diff --git a/tool/trimmer/compose_args.go b/tool/trimmer/compose_args.go deleted file mode 100644 index 9bab9527..00000000 --- a/tool/trimmer/compose_args.go +++ /dev/null @@ -1,148 +0,0 @@ -// Copyright 2024 CloudWeGo Authors -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package main - -import ( - "errors" - "flag" - "fmt" - "github.com/cloudwego/thriftgo/parser" - "gopkg.in/yaml.v3" - "io/ioutil" -) - -var DefaultIDLComposeFileName = "idl_compose.yaml" - -type IDLComposeArguments struct { - IDLs map[string]*IDLArguments `yaml:"idls,omitempty"` -} - -type IDLArguments struct { - Trimmer *TrimmerYamlArguments `yaml:"trimmer,omitempty"` -} - -type TrimmerYamlArguments struct { - Methods []string `yaml:"methods,omitempty"` - Preserve *bool `yaml:"preserve,omitempty"` - PreservedStructs []string `yaml:"preserved_structs,omitempty"` - MatchGoName *bool `yaml:"match_go_name,omitempty"` -} - -func ParseYamlConfig(path string) *IDLComposeArguments { - cfg := IDLComposeArguments{} - data, err := ioutil.ReadFile(path) - if err != nil { - return nil - } - fmt.Println("using idl_compose config:", path) - err = yaml.Unmarshal(data, &cfg) - if err != nil { - fmt.Println("unmarshal idl_compose config fail:", err) - return nil - } - // set default value - for _, idl := range cfg.IDLs { - if idl.Trimmer == nil { - idl.Trimmer = &TrimmerYamlArguments{} - } - if idl.Trimmer.Preserve == nil { - t := true - idl.Trimmer.Preserve = &t - } - if idl.Trimmer.MatchGoName == nil { - t := false - idl.Trimmer.MatchGoName = &t - } - } - - return &cfg -} - -type ComposeArguments struct { - Config string -} - -func (a *ComposeArguments) BuildFlags() *flag.FlagSet { - f := flag.NewFlagSet("trimmer compose", flag.ContinueOnError) - - f.StringVar(&a.Config, "c", "", "") - f.StringVar(&a.Config, "config", "", "") - - // todo: write help - f.Usage = help - return f -} - -func (a *ComposeArguments) Parse(argv []string) error { - f := a.BuildFlags() - if err := f.Parse(argv[1:]); err != nil { - return err - } - return nil -} - -func (a *ComposeArguments) run() error { - if a.Config == "" { - a.Config = DefaultIDLComposeFileName - } - - cfg := ParseYamlConfig(a.Config) - if cfg == nil { - // todo: more detailed information - return errors.New("failed to parse idl_compose config") - } - ancestor, err := createAncestor(cfg) - if err != nil { - return err - } - // todo: deal with ancestor - ancestor.String() - return nil -} - -const ( - ancestorFmt = `namespace go test.all - -%s - -%s -` -) - -func createAncestor(cfg *IDLComposeArguments) (*parser.Thrift, error) { - var svcs []string - for path := range cfg.IDLs { - // todo: deal with includes - child, err := parser.ParseFile(path, nil, true) - if err != nil { - // todo: deal with error - return nil, err - } - child.ForEachService(func(v *parser.Service) bool { - svcs = append(svcs, v.Name) - return true - }) - } - ancestorStr := fmt.Sprintf(ancestorFmt, getImports(), getFakeServices()) - return parser.ParseString("./all.thrift", ancestorStr) -} - -func getImports() string { - return "" -} - -func getFakeServices() string { - return "" -} diff --git a/tool/trimmer/test_cases/config/idl_compose/idl_compose.yaml b/tool/trimmer/test_cases/config/idl_compose/idl_compose.yaml new file mode 100644 index 00000000..2dd2fda4 --- /dev/null +++ b/tool/trimmer/test_cases/config/idl_compose/idl_compose.yaml @@ -0,0 +1,25 @@ +# Copyright 2024 CloudWeGo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +idls: + test1.thrift: + trimmer: + methods: + - "TestService.func1" + - "TestService.func3" + preserve: true + preserved_structs: + - "useless" + match_go_name: true + test2.thrift: \ No newline at end of file diff --git a/tool/trimmer/test_cases/config/trim_config/trim_config.yaml b/tool/trimmer/test_cases/config/trim_config/trim_config.yaml new file mode 100644 index 00000000..9f975f5f --- /dev/null +++ b/tool/trimmer/test_cases/config/trim_config/trim_config.yaml @@ -0,0 +1,21 @@ +# Copyright 2024 CloudWeGo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +methods: + - "TestService.func1" + - "TestService.func3" +preserve: true +preserved_structs: + - "useless" +match_go_name: true \ No newline at end of file diff --git a/tool/trimmer/test_cases/config/trim_config_and_idl_compose/idl_compose.yaml b/tool/trimmer/test_cases/config/trim_config_and_idl_compose/idl_compose.yaml new file mode 100644 index 00000000..2dd2fda4 --- /dev/null +++ b/tool/trimmer/test_cases/config/trim_config_and_idl_compose/idl_compose.yaml @@ -0,0 +1,25 @@ +# Copyright 2024 CloudWeGo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +idls: + test1.thrift: + trimmer: + methods: + - "TestService.func1" + - "TestService.func3" + preserve: true + preserved_structs: + - "useless" + match_go_name: true + test2.thrift: \ No newline at end of file diff --git a/tool/trimmer/test_cases/config/trim_config_and_idl_compose/trim_config.yaml b/tool/trimmer/test_cases/config/trim_config_and_idl_compose/trim_config.yaml new file mode 100644 index 00000000..9f975f5f --- /dev/null +++ b/tool/trimmer/test_cases/config/trim_config_and_idl_compose/trim_config.yaml @@ -0,0 +1,21 @@ +# Copyright 2024 CloudWeGo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +methods: + - "TestService.func1" + - "TestService.func3" +preserve: true +preserved_structs: + - "useless" +match_go_name: true \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/common1.thrift b/tool/trimmer/test_cases/multiple_idls/common1.thrift new file mode 100644 index 00000000..04e4ce29 --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/common1.thrift @@ -0,0 +1,35 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go tests.multiple.common + +enum Common1Enum1 { + ONE + TWO + THREE +} + +enum Common1Enum2 { + ONE + TWO + THERR +} + +struct Common1Struct1 { + 1: required string field +} + +struct Common1Struct2 { + 1: required string field +} diff --git a/tool/trimmer/test_cases/multiple_idls/common2.thrift b/tool/trimmer/test_cases/multiple_idls/common2.thrift new file mode 100644 index 00000000..a27ed62a --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/common2.thrift @@ -0,0 +1,35 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go tests.multiple.common + +enum Common2Enum1 { + ONE + TWO + THREE +} + +enum Common2Enum2 { + ONE + TWO + THERR +} + +struct Common2Struct1 { + 1: required string field +} + +struct Common2Struct2 { + 1: required string field +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test1.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test1.thrift new file mode 100644 index 00000000..44e20603 --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test1.thrift @@ -0,0 +1,26 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" + +struct Test1Struct1 { + 1: required common1.Common1Enum1 enumField + 2: required common1.Common1Struct1 structField +} + +service Test1 { + string Process(1: Test1Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test2.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test2.thrift new file mode 100644 index 00000000..8e5af4ae --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test2.thrift @@ -0,0 +1,26 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" + +struct Test2Struct1 { + 1: required common1.Common1Enum2 enumField + 2: required common1.Common1Struct2 structField +} + +service Test2 { + string Process(1: Test2Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test3.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test3.thrift new file mode 100644 index 00000000..41b84b55 --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test3.thrift @@ -0,0 +1,29 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" +include "../common2.thrift" + +struct Test3Struct1 { + 1: required common1.Common1Enum1 enumField1 + 2: required common1.Common1Struct1 structField1 + 3: required common2.Common2Enum1 enumField2 + 4: required common2.Common2Struct1 structField2 +} + +service Test3 { + string Process(1: Test3Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test4.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test4.thrift new file mode 100644 index 00000000..e07393ca --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test4.thrift @@ -0,0 +1,29 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" +include "../common2.thrift" + +struct Test4Struct1 { + 1: required common1.Common1Enum2 enumField1 + 2: required common1.Common1Struct2 structField1 + 3: required common2.Common2Enum2 enumField2 + 4: required common2.Common2Struct2 structField2 +} + +service Test4 { + string Process(1: Test4Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test5.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test5.thrift new file mode 100644 index 00000000..214b776d --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test5.thrift @@ -0,0 +1,33 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" +include "../common2.thrift" + +struct Test5Struct1 { + 1: required common1.Common1Enum1 enumField1 + 2: required common1.Common1Struct1 structField1 + 3: required common2.Common2Enum1 enumField2 + 4: required common2.Common2Struct1 structField2 +} + +struct Test5Struct2 { + 1: required string stringField +} + +service Test5 { + string Process(1: Test5Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test6.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test6.thrift new file mode 100644 index 00000000..763c8975 --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test6.thrift @@ -0,0 +1,31 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" +include "../common2.thrift" +include "test5.thrift" + +struct Test6Struct1 { + 1: required common1.Common1Enum2 enumField1 + 2: required common1.Common1Struct2 structField1 + 3: required common2.Common2Enum2 enumField2 + 4: required common2.Common2Struct2 structField2 +} + +service Test6 { + string Process(1: Test6Struct1 req) + string ProcessAnotherIDL(1: test5.Test5Struct2 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test7.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test7.thrift new file mode 100644 index 00000000..b4f1b56e --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test7.thrift @@ -0,0 +1,39 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" +include "../common2.thrift" + +struct Test7Struct1 { + 1: required common1.Common1Enum1 enumField1 + 2: required common1.Common1Struct1 structField1 + 3: required common2.Common2Enum1 enumField2 + 4: required common2.Common2Struct1 structField2 +} + +// @preserve +struct Test7Struct2 { + 1: required string stringField +} + +struct Test7Struct3 { + 1: required string stringField +} + +service Test7 { + string Process(1: Test7Struct1 req) + string Echo(1: string req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test8.thrift b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test8.thrift new file mode 100644 index 00000000..d58127f0 --- /dev/null +++ b/tool/trimmer/test_cases/multiple_idls/multiple_idls_include_common/test8.thrift @@ -0,0 +1,29 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go multiple.include.common + +include "../common1.thrift" +include "../common2.thrift" + +struct Test8Struct1 { + 1: required common1.Common1Enum2 enumField1 + 2: required common1.Common1Struct2 structField1 + 3: required common2.Common2Enum2 enumField2 + 4: required common2.Common2Struct2 structField2 +} + +service Test8 { + string Process(1: Test8Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/test_extend/common1.thrift b/tool/trimmer/test_cases/test_extend/common1.thrift new file mode 100644 index 00000000..d973fedd --- /dev/null +++ b/tool/trimmer/test_cases/test_extend/common1.thrift @@ -0,0 +1,25 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go tests.extend.common + +include "common2.thrift" + +struct Common1Struct1 { + 1: required string stringField +} + +service Common1 extends common2.Common2 { + string ProcessCommon1(1: Common1Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/test_extend/common2.thrift b/tool/trimmer/test_cases/test_extend/common2.thrift new file mode 100644 index 00000000..b5829e64 --- /dev/null +++ b/tool/trimmer/test_cases/test_extend/common2.thrift @@ -0,0 +1,25 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go tests.extend.common + +include "common3.thrift" + +struct Common2Struct1 { + 1: required string stringField +} + +service Common2 extends common3.Common3 { + string ProcessCommon2(1: Common2Struct1 req) +} \ No newline at end of file diff --git a/tool/trimmer/test_cases/test_extend/common3.thrift b/tool/trimmer/test_cases/test_extend/common3.thrift new file mode 100644 index 00000000..6d795050 --- /dev/null +++ b/tool/trimmer/test_cases/test_extend/common3.thrift @@ -0,0 +1,28 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +namespace go tests.extend.common + +struct Common3Struct1 { + 1: required string stringField +} + +struct Commmon3Struct2 { + 1: required string stringField +} + +service Common3 { + string ProcessCommon3(1: Common3Struct1 req) + string Echo(1: Commmon3Struct2 req) +} \ No newline at end of file diff --git a/tool/trimmer/trim/config.go b/tool/trimmer/trim/config.go index e5d3493e..bbc02bf0 100644 --- a/tool/trimmer/trim/config.go +++ b/tool/trimmer/trim/config.go @@ -27,13 +27,23 @@ var ( DefaultIDLComposeFileName = "idl_compose.yaml" ) -// TrimmerYamlArguments is the alias to YamlArguments -type TrimmerYamlArguments YamlArguments - // IDLArguments contains all arguments about the IDL. -// For now, it only contains TrimmerYamlArguments. +// For now, it only contains YamlArguments. type IDLArguments struct { - Trimmer *TrimmerYamlArguments `yaml:"trimmer,omitempty"` + Trimmer *YamlArguments `yaml:"trimmer,omitempty"` +} + +func (args *IDLArguments) setDefault() { + if args == nil { + return + } + if args.Trimmer != nil { + args.Trimmer.setDefault() + } else { + trimArgs := &YamlArguments{} + trimArgs.setDefault() + args.Trimmer = trimArgs + } } // IDLComposeArguments contains all IDLs and their arguments. @@ -43,6 +53,21 @@ type IDLComposeArguments struct { IDLs map[string]*IDLArguments `yaml:"idls,omitempty"` } +func (args *IDLComposeArguments) setDefault() { + if args == nil { + return + } + for filename, idlArgs := range args.IDLs { + if idlArgs != nil { + idlArgs.setDefault() + } else { + newIDLArgs := &IDLArguments{} + newIDLArgs.setDefault() + args.IDLs[filename] = newIDLArgs + } + } +} + type YamlArguments struct { Methods []string `yaml:"methods,omitempty"` Preserve *bool `yaml:"preserve,omitempty"` @@ -50,8 +75,10 @@ type YamlArguments struct { MatchGoName *bool `yaml:"match_go_name,omitempty"` } -// todo: deal with this function with TrimmerYamlArguments func (arg *YamlArguments) setDefault() { + if arg == nil { + return + } if arg.Preserve == nil { t := true arg.Preserve = &t @@ -78,19 +105,9 @@ func ParseYamlConfig(path string) *YamlArguments { return &cfg } -func (arg *TrimmerYamlArguments) setDefault() { - if arg.Preserve == nil { - t := true - arg.Preserve = &t - } - if arg.MatchGoName == nil { - t := false - arg.MatchGoName = &t - } -} - -func ParseIDLComposeConfig(path string) *IDLComposeArguments { +func ParseIDLComposeConfig(dir string) *IDLComposeArguments { cfg := IDLComposeArguments{} + path := filepath.Join(dir, DefaultIDLComposeFileName) data, err := ioutil.ReadFile(path) if err != nil { return nil @@ -102,12 +119,52 @@ func ParseIDLComposeConfig(path string) *IDLComposeArguments { return nil } // set default value - for _, idl := range cfg.IDLs { + for filename, idl := range cfg.IDLs { + if idl == nil { + newIdl := &IDLArguments{} + cfg.IDLs[filename] = newIdl + idl = newIdl + } if idl.Trimmer == nil { - idl.Trimmer = &TrimmerYamlArguments{} + idl.Trimmer = &YamlArguments{} } idl.Trimmer.setDefault() } return &cfg } + +func newIDLComposeArgumentsWithTargetAST(filename string) *IDLComposeArguments { + trimCfg := &YamlArguments{} + trimCfg.setDefault() + return &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + filename: { + Trimmer: trimCfg, + }, + }, + } +} + +func extractIDLComposeConfigFromDir(dir string, targetAST string) *IDLComposeArguments { + var cfg *IDLComposeArguments + cfg = ParseIDLComposeConfig(dir) + // idl_compose.yaml has higher priority + if cfg != nil { + return cfg + } + // if there is no idl_compose.yaml, use trim_config.yaml + trimCfg := ParseYamlConfig(dir) + if trimCfg != nil { + cfg = &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + targetAST: { + Trimmer: trimCfg, + }, + }, + } + return cfg + } + + return nil +} diff --git a/tool/trimmer/trim/config_test.go b/tool/trimmer/trim/config_test.go new file mode 100644 index 00000000..dd65d71a --- /dev/null +++ b/tool/trimmer/trim/config_test.go @@ -0,0 +1,132 @@ +// Copyright 2024 CloudWeGo Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package trim + +import ( + "github.com/cloudwego/thriftgo/pkg/test" + "testing" +) + +func Test_extractIDLComposeConfigFromDir(t *testing.T) { + testcases := []struct { + desc string + dir string + targetAST string + expect func(t *testing.T, cfg *IDLComposeArguments) + }{ + { + desc: "only trim_config.yaml", + dir: "../test_cases/config/trim_config", + targetAST: "test.thrift", + expect: func(t *testing.T, cfg *IDLComposeArguments) { + preserve := true + matchGoName := true + expect := &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + "test.thrift": { + Trimmer: &YamlArguments{ + Methods: []string{ + "TestService.func1", + "TestService.func3", + }, + Preserve: &preserve, + PreservedStructs: []string{ + "useless", + }, + MatchGoName: &matchGoName, + }, + }, + }, + } + test.DeepEqual(t, cfg, expect) + }, + }, + { + desc: "only idl_compose.yaml", + dir: "../test_cases/config/idl_compose", + targetAST: "test1.thrift", + expect: func(t *testing.T, cfg *IDLComposeArguments) { + preserve := true + matchGoNameTrue := true + matchGoNameFalse := false + expect := &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + "test1.thrift": { + Trimmer: &YamlArguments{ + Methods: []string{ + "TestService.func1", + "TestService.func3", + }, + Preserve: &preserve, + PreservedStructs: []string{ + "useless", + }, + MatchGoName: &matchGoNameTrue, + }, + }, + "test2.thrift": { + Trimmer: &YamlArguments{ + Preserve: &preserve, + MatchGoName: &matchGoNameFalse, + }, + }, + }, + } + test.DeepEqual(t, cfg, expect) + }, + }, + { + desc: "both trim_config.yaml and idl_compose.yaml, only idl_compose.yaml will be used", + dir: "../test_cases/config/trim_config_and_idl_compose", + targetAST: "test1.thrift", + expect: func(t *testing.T, cfg *IDLComposeArguments) { + preserve := true + matchGoNameTrue := true + matchGoNameFalse := false + expect := &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + "test1.thrift": { + Trimmer: &YamlArguments{ + Methods: []string{ + "TestService.func1", + "TestService.func3", + }, + Preserve: &preserve, + PreservedStructs: []string{ + "useless", + }, + MatchGoName: &matchGoNameTrue, + }, + }, + "test2.thrift": { + Trimmer: &YamlArguments{ + Preserve: &preserve, + MatchGoName: &matchGoNameFalse, + }, + }, + }, + } + test.DeepEqual(t, cfg, expect) + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + cfg := extractIDLComposeConfigFromDir(tc.dir, tc.targetAST) + tc.expect(t, cfg) + }) + } +} diff --git a/tool/trimmer/trim/idl_compose.yaml b/tool/trimmer/trim/idl_compose.yaml new file mode 100644 index 00000000..cef5a98f --- /dev/null +++ b/tool/trimmer/trim/idl_compose.yaml @@ -0,0 +1,17 @@ +# Copyright 2024 CloudWeGo Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +idls: + ../test_cases/multiple_idls/multiple_idls_include_common/test1.thrift: + ../test_cases/multiple_idls/multiple_idls_include_common/test2.thrift: \ No newline at end of file diff --git a/tool/trimmer/trim/mark.go b/tool/trimmer/trim/mark.go index 36cfa732..5ca3efde 100644 --- a/tool/trimmer/trim/mark.go +++ b/tool/trimmer/trim/mark.go @@ -21,9 +21,13 @@ import ( "github.com/cloudwego/thriftgo/parser" ) +const ( + includePrefix = "trimmer_include_prefix_" +) + // refresh initialize the trimMethods, preservedStructs and trimmed statistical data. // this function must be called before markAST -func (t *Trimmer) refresh(ast *parser.Thrift, arg *TrimmerYamlArguments) { +func (t *Trimmer) refresh(ast *parser.Thrift, arg *YamlArguments) { if arg == nil { return } @@ -51,14 +55,10 @@ func (t *Trimmer) refresh(ast *parser.Thrift, arg *TrimmerYamlArguments) { if len(t.preservedStructs) <= 0 { t.forceTrimming = true } - // deal with trimmed statistical data - t.fieldsTrimmed = 0 - t.structsTrimmed = 0 - t.countStructs(ast) } // mark the used part of ast -func (t *Trimmer) markAST(ast *parser.Thrift, arg *TrimmerYamlArguments) { +func (t *Trimmer) markAST(ast *parser.Thrift, arg *YamlArguments) { t.refresh(ast, arg) t.preProcess(ast) for _, service := range ast.Services { @@ -195,7 +195,7 @@ func (t *Trimmer) markType(theType *parser.Type, ast *parser.Thrift) { } else if theType.Category.IsEnum() { for _, enum := range baseAST.Enums { if enum.Name == theType.Name || (theType.Reference != nil && enum.Name == theType.Reference.Name) { - t.markEnum(enum, filename) + t.markEnum(enum, baseAST) break } } @@ -212,8 +212,8 @@ func (t *Trimmer) markStructLike(str *parser.StructLike, ast *parser.Thrift) { } } -func (t *Trimmer) markEnum(enum *parser.Enum, filename string) { - t.marks[filename][enum.Name] = true +func (t *Trimmer) markEnum(enum *parser.Enum, ast *parser.Thrift) { + t.marks[ast.Filename][enum.Name] = true } func (t *Trimmer) markTypeDef(theType *parser.Type, ast *parser.Thrift) { @@ -294,7 +294,6 @@ func (t *Trimmer) markKeptPart(ast *parser.Thrift) bool { return ret } -// todo: figure out this // for -m, trace the extends and find specified method to base on func (t *Trimmer) traceExtendMethod(father, svc *parser.Service, ast *parser.Thrift) (ret bool) { filename := ast.Filename @@ -356,8 +355,3 @@ func (t *Trimmer) checkPreserve(theStruct *parser.StructLike) bool { } return t.preserveRegex.MatchString(strings.ToLower(theStruct.ReservedComments)) } - -const ( - includePrefix = "includeXXX_prefix" - functionPrefix = "functionXXX_prefix" -) diff --git a/tool/trimmer/trim/traversal.go b/tool/trimmer/trim/traversal.go index e808d068..3a55bcf5 100644 --- a/tool/trimmer/trim/traversal.go +++ b/tool/trimmer/trim/traversal.go @@ -20,12 +20,18 @@ import ( // traverse and remove the unmarked part of ast func (t *Trimmer) traversal(ast *parser.Thrift) { + t.countStructs(ast) + t.doTraversal(ast) +} + +func (t *Trimmer) doTraversal(ast *parser.Thrift) { + // deal with trimmed statistical data filename := ast.Filename var listInclude []*parser.Include for i := range ast.Includes { if t.marks[filename][includePrefix+ast.Includes[i].Path] || len(ast.Includes[i].Reference.Constants)+ len(ast.Includes[i].Reference.Enums)+len(ast.Includes[i].Reference.Typedefs) > 0 { - t.traversal(ast.Includes[i].Reference) + t.doTraversal(ast.Includes[i].Reference) listInclude = append(listInclude, ast.Includes[i]) } } @@ -61,15 +67,13 @@ func (t *Trimmer) traversal(ast *parser.Thrift) { var listService []*parser.Service for i := range ast.Services { if t.marks[filename][ast.Services[i].Name] { - if len(t.trimMethods) != 0 { - var trimmedMethods []*parser.Function - for j := range ast.Services[i].Functions { - if t.marks[filename][ast.Services[i].Functions[j].Name] { - trimmedMethods = append(trimmedMethods, ast.Services[i].Functions[j]) - } + var trimmedMethods []*parser.Function + for j := range ast.Services[i].Functions { + if t.marks[filename][ast.Services[i].Name+"."+ast.Services[i].Functions[j].Name] { + trimmedMethods = append(trimmedMethods, ast.Services[i].Functions[j]) } - ast.Services[i].Functions = trimmedMethods } + ast.Services[i].Functions = trimmedMethods listService = append(listService, ast.Services[i]) t.fieldsTrimmed -= len(ast.Services[i].Functions) } diff --git a/tool/trimmer/trim/trimmer.go b/tool/trimmer/trim/trimmer.go index 5b39e7ef..98d28d4d 100644 --- a/tool/trimmer/trim/trimmer.go +++ b/tool/trimmer/trim/trimmer.go @@ -15,7 +15,7 @@ package trim import ( - "fmt" + "errors" "github.com/cloudwego/thriftgo/utils/dir_utils" "os" "regexp" @@ -23,7 +23,6 @@ import ( "github.com/dlclark/regexp2" "github.com/cloudwego/thriftgo/parser" - "github.com/cloudwego/thriftgo/semantic" ) type Trimmer struct { @@ -54,8 +53,9 @@ type TrimASTArg struct { } type TrimASTWithComposeArg struct { - Cfg *IDLComposeArguments - TargetAST *parser.Thrift + Cfg *IDLComposeArguments + TargetAST *parser.Thrift + ReadCfgFromLocal bool } // TrimAST parse the cfg and trim the single AST @@ -86,86 +86,60 @@ func TrimAST(arg *TrimASTArg) (structureTrimmed int, fieldTrimmed int, err error if arg.MatchGoName != nil { matchGoName = *arg.MatchGoName } - return doTrimAST(arg.Ast, &TrimmerYamlArguments{ - Methods: arg.TrimMethods, - Preserve: &preserve, - PreservedStructs: preservedStructs, - MatchGoName: &matchGoName, + return TrimASTWithCompose(&TrimASTWithComposeArg{ + Cfg: &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + arg.Ast.Filename: { + Trimmer: &YamlArguments{ + Methods: arg.TrimMethods, + Preserve: &preserve, + PreservedStructs: preservedStructs, + MatchGoName: &matchGoName, + }, + }, + }, + }, + TargetAST: arg.Ast, }) } func TrimASTWithCompose(arg *TrimASTWithComposeArg) (structureTrimmed int, fieldTrimmed int, err error) { - // todo: 读取本地配置文件 + if arg == nil { + return structureTrimmed, fieldTrimmed, errors.New("TrimASTWithCompose is nil") + } + if arg.TargetAST == nil { + return structureTrimmed, fieldTrimmed, errors.New("TrimASTWithCompose.TargetAST is nil") + } cfg := arg.Cfg - //if wd, err := dir_utils.Getwd(); err == nil { - // localCfg := ParseIDLComposeConfig(wd) - // if localCfg != nil { - // if len(arg.TrimMethods) == 0 && len(cfg.Methods) > 0 { - // arg.TrimMethods = cfg.Methods - // } - // if arg.Preserve == nil && !(*cfg.Preserve) { - // preserve := false - // arg.Preserve = &preserve - // } - // if arg.MatchGoName == nil && cfg.MatchGoName != nil { - // arg.MatchGoName = cfg.MatchGoName - // } - // preservedStructs = cfg.PreservedStructs - // } - //} + // When ReadCfgFromLocal is set, local cfg has higher priority and the passed cfg would be ignored + if arg.ReadCfgFromLocal { + wd, err := dir_utils.Getwd() + if err == nil { + cfg = extractIDLComposeConfigFromDir(wd, arg.TargetAST.Filename) + } + } + if cfg == nil { + cfg = newIDLComposeArgumentsWithTargetAST(arg.TargetAST.Filename) + } + cfg.setDefault() + trimmer, err := newTrimmer(nil, "") if err != nil { return structureTrimmed, fieldTrimmed, err } + for path, idlArg := range cfg.IDLs { - trimArg := idlArg.Trimmer var ast *parser.Thrift if arg.TargetAST.Filename == path { ast = arg.TargetAST } else { - ast = parseAndCheckAST(path) + ast = parseAndCheckAST(path, nil, true) } - // todo: deal with trimArg - trimmer.markAST(ast, trimArg) + trimmer.markAST(ast, idlArg.Trimmer) } // trimmer.marks now have the complete context, we can traverse the target AST trimmer.traversal(arg.TargetAST) - if path := parser.CircleDetect(arg.TargetAST); len(path) > 0 { - check(fmt.Errorf("found include circle:\n\t%s", path)) - } - checker := semantic.NewChecker(semantic.Options{FixWarnings: true}) - _, err = checker.CheckAll(arg.TargetAST) - check(err) - check(semantic.ResolveSymbols(arg.TargetAST)) - - return trimmer.structsTrimmed, trimmer.fieldsTrimmed, nil -} - -// doTrimAST trim the single AST, pass method names if -m specified -func doTrimAST(ast *parser.Thrift, arg *TrimmerYamlArguments) ( - structureTrimmed int, fieldTrimmed int, err error) { - trimmer, err := newTrimmer(nil, "") - if err != nil { - return 0, 0, err - } - trimmer.asts[ast.Filename] = ast - trimmer.markAST(ast, arg) - trimmer.traversal(ast) - if path := parser.CircleDetect(ast); len(path) > 0 { - check(fmt.Errorf("found include circle:\n\t%s", path)) - } - checker := semantic.NewChecker(semantic.Options{FixWarnings: true}) - _, err = checker.CheckAll(ast) - check(err) - check(semantic.ResolveSymbols(ast)) - - // todo: deal with this - //for i, method := range trimMethods { - // if !trimmer.trimMethodValid[i] { - // println("err: method", method, "not found!") - // os.Exit(2) - // } - //} + checkAST(arg.TargetAST) return trimmer.structsTrimmed, trimmer.fieldsTrimmed, nil } @@ -179,15 +153,7 @@ func Trim(files, includeDir []string, outDir string) error { for _, filename := range files { // go through parse process - ast, err := parser.ParseFile(filename, includeDir, true) - check(err) - if path := parser.CircleDetect(ast); len(path) > 0 { - check(fmt.Errorf("found include circle:\n\t%s", path)) - } - checker := semantic.NewChecker(semantic.Options{FixWarnings: true}) - _, err = checker.CheckAll(ast) - check(err) - check(semantic.ResolveSymbols(ast)) + ast := parseAndCheckAST(filename, includeDir, true) trimmer.asts[filename] = ast trimmer.markAST(ast, nil) // TODO: handle multi files and dump to 'xxx.thrift' @@ -197,6 +163,13 @@ func Trim(files, includeDir []string, outDir string) error { } func (t *Trimmer) countStructs(ast *parser.Thrift) { + // refresh + t.fieldsTrimmed = 0 + t.structsTrimmed = 0 + t.doCountStructs(ast) +} + +func (t *Trimmer) doCountStructs(ast *parser.Thrift) { t.structsTrimmed += len(ast.Structs) + len(ast.Includes) + len(ast.Services) + len(ast.Unions) + len(ast.Exceptions) for _, v := range ast.Structs { t.fieldsTrimmed += len(v.Fields) @@ -211,7 +184,7 @@ func (t *Trimmer) countStructs(ast *parser.Thrift) { t.fieldsTrimmed += len(v.Fields) } for _, v := range ast.Includes { - t.countStructs(v.Reference) + t.doCountStructs(v.Reference) } } @@ -228,7 +201,6 @@ func newTrimmer(files []string, outDir string) (*Trimmer, error) { return trimmer, nil } -// todo: remove this function func check(err error) { if err != nil { println(err.Error()) diff --git a/tool/trimmer/trim/trimmer_test.go b/tool/trimmer/trim/trimmer_test.go index b6f044ae..f4dbdcbf 100644 --- a/tool/trimmer/trim/trimmer_test.go +++ b/tool/trimmer/trim/trimmer_test.go @@ -105,6 +105,45 @@ func TestTrimMethod(t *testing.T) { test.Assert(t, len(ast.Services[0].Functions) == 1) } +func TestTrimMethodWithExtend(t *testing.T) { + filename := filepath.Join("..", "test_cases", "test_extend", "common1.thrift") + ast, err := parser.ParseFile(filename, nil, true) + check(err) + if path := parser.CircleDetect(ast); len(path) > 0 { + check(fmt.Errorf("found include circle:\n\t%s", path)) + } + checker := semantic.NewChecker(semantic.Options{FixWarnings: true}) + _, err = checker.CheckAll(ast) + check(err) + check(semantic.ResolveSymbols(ast)) + + methods := make([]string, 1) + methods[0] = "Echo" + + _, _, err = TrimAST(&TrimASTArg{ + Ast: ast, + TrimMethods: methods, + Preserve: nil, + }) + check(err) + // for common1.thrift, Common1Struct1 and ProcessCommon1 are trimmed + test.Assert(t, len(ast.Structs) <= 0) + test.Assert(t, len(ast.Services) == 1) + test.Assert(t, len(ast.Services[0].Functions) <= 0) + + // for common2.thrift, Common2Struct1 and ProcessCommon2 are trimmed + common2AST := ast.Includes[0].Reference + test.Assert(t, len(common2AST.Structs) <= 0) + test.Assert(t, len(common2AST.Services) == 1) + test.Assert(t, len(common2AST.Services[0].Functions) <= 0) + + // for common3.thrift, Common3Struct1 and ProcessCommon3 are trimmed, Echo and Common3Struct2 are preserved + common3AST := common2AST.Includes[0].Reference + test.Assert(t, len(common3AST.Structs) == 1) + test.Assert(t, len(common3AST.Services) == 1) + test.Assert(t, len(common3AST.Services[0].Functions) == 1) +} + func TestPreserve(t *testing.T) { filename := filepath.Join("..", "test_cases", "tests", "dir", "dir2", "test.thrift") ast, err := parser.ParseFile(filename, nil, true) @@ -129,30 +168,163 @@ func TestPreserve(t *testing.T) { } func TestTrimASTWithCompose(t *testing.T) { - filename := filepath.Join("..", "idl", "sample.thrift") - ast := parseAndCheckAST(filename) - preserve := false - matchGoName := false - st, ft, err := TrimASTWithCompose(&TrimASTWithComposeArg{ - Cfg: &IDLComposeArguments{ - IDLs: map[string]*IDLArguments{ - "../idl/sample.thrift": { - Trimmer: &TrimmerYamlArguments{ - Preserve: &preserve, - MatchGoName: &matchGoName, + testcases := []struct { + desc string + composeArg func() *TrimASTWithComposeArg + expect func(t *testing.T, ast *parser.Thrift, structureTrimmed int, fieldTrimmed int, err error) + }{ + { + desc: "two unrelated idls refer to a common idl", + composeArg: func() *TrimASTWithComposeArg { + test1 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test1.thrift") + test2 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test2.thrift") + test1AST := parseAndCheckAST(test1, nil, true) + return &TrimASTWithComposeArg{ + Cfg: &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + test1: nil, + test2: nil, + }, }, - }, - "../idl/ref_idl/sample_another.thrift": { - Trimmer: &TrimmerYamlArguments{ - Preserve: &preserve, - MatchGoName: &matchGoName, + TargetAST: test1AST, + } + }, + expect: func(t *testing.T, ast *parser.Thrift, structureTrimmed int, fieldTrimmed int, err error) { + // all the elements have been preserved + test.Assert(t, structureTrimmed == 0) + test.Assert(t, fieldTrimmed == 0) + test.Assert(t, err == nil) + // all the content in common.thrift has been marked to be preserved + commonAst1 := ast.Includes[0].Reference + test.Assert(t, len(commonAst1.Enums) == 2) + test.Assert(t, len(commonAst1.Structs) == 2) + }, + }, + { + desc: "two unrelated idls refer to two common idls", + composeArg: func() *TrimASTWithComposeArg { + test3 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test3.thrift") + test4 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test4.thrift") + test3AST := parseAndCheckAST(test3, nil, true) + return &TrimASTWithComposeArg{ + Cfg: &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + test3: nil, + test4: nil, + }, }, - }, + TargetAST: test3AST, + } + }, + expect: func(t *testing.T, ast *parser.Thrift, structureTrimmed int, fieldTrimmed int, err error) { + // all the elements have been preserved + test.Assert(t, structureTrimmed == 0) + test.Assert(t, fieldTrimmed == 0) + test.Assert(t, err == nil) + commonAst1 := ast.Includes[0].Reference + test.Assert(t, len(commonAst1.Enums) == 2) + test.Assert(t, len(commonAst1.Structs) == 2) + commonAst2 := ast.Includes[1].Reference + test.Assert(t, len(commonAst2.Enums) == 2) + test.Assert(t, len(commonAst2.Structs) == 2) + }, }, - TargetAST: ast, - }) - t.Log(st) - t.Log(ft) - t.Log(err) + { + desc: "use local idl_compose.yaml", + composeArg: func() *TrimASTWithComposeArg { + test1 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test1.thrift") + test1Ast := parseAndCheckAST(test1, nil, true) + return &TrimASTWithComposeArg{ + TargetAST: test1Ast, + ReadCfgFromLocal: true, + } + }, + expect: func(t *testing.T, ast *parser.Thrift, structureTrimmed int, fieldTrimmed int, err error) { + // all the elements have been preserved + test.Assert(t, structureTrimmed == 0) + test.Assert(t, fieldTrimmed == 0) + test.Assert(t, err == nil) + // all the content in common.thrift has been marked to be preserved + commonAst1 := ast.Includes[0].Reference + test.Assert(t, len(commonAst1.Enums) == 2) + test.Assert(t, len(commonAst1.Structs) == 2) + }, + }, + { + desc: "test5.thrift refer to test6.thrift, they both refer to two common idls", + composeArg: func() *TrimASTWithComposeArg { + test5 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test5.thrift") + test6 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test6.thrift") + test5AST := parseAndCheckAST(test5, nil, true) + return &TrimASTWithComposeArg{ + Cfg: &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + test5: nil, + test6: nil, + }, + }, + TargetAST: test5AST, + } + }, + expect: func(t *testing.T, ast *parser.Thrift, structureTrimmed int, fieldTrimmed int, err error) { + // all the elements have been preserved + test.Assert(t, structureTrimmed == 0) + test.Assert(t, fieldTrimmed == 0) + test.Assert(t, err == nil) + // common parts + commonAST1 := ast.Includes[0].Reference + test.Assert(t, len(commonAST1.Enums) == 2) + test.Assert(t, len(commonAST1.Structs) == 2) + commonAST2 := ast.Includes[1].Reference + test.Assert(t, len(commonAST2.Enums) == 2) + test.Assert(t, len(commonAST2.Structs) == 2) + // self + test.Assert(t, len(ast.Structs) == 2) + }, + }, + { + desc: "two unrelated idls refer to two common idls with preserved methods and structs", + composeArg: func() *TrimASTWithComposeArg { + test7 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test7.thrift") + test8 := filepath.Join("..", "test_cases", "multiple_idls", "multiple_idls_include_common", "test8.thrift") + test7AST := parseAndCheckAST(test7, nil, true) + return &TrimASTWithComposeArg{ + Cfg: &IDLComposeArguments{ + IDLs: map[string]*IDLArguments{ + test7: { + Trimmer: &YamlArguments{ + Methods: []string{"Process"}, + PreservedStructs: []string{"Test7Struct3"}, + }, + }, + test8: nil, + }, + }, + TargetAST: test7AST, + } + }, + expect: func(t *testing.T, ast *parser.Thrift, structureTrimmed int, fieldTrimmed int, err error) { + test.Assert(t, structureTrimmed == 0) + // Echo Method has been trimmed + test.Assert(t, fieldTrimmed == 1) + test.Assert(t, err == nil) + commonAst1 := ast.Includes[0].Reference + test.Assert(t, len(commonAst1.Enums) == 2) + test.Assert(t, len(commonAst1.Structs) == 2) + commonAst2 := ast.Includes[1].Reference + test.Assert(t, len(commonAst2.Enums) == 2) + test.Assert(t, len(commonAst2.Structs) == 2) + + }, + }, + } + + for _, tc := range testcases { + t.Run(tc.desc, func(t *testing.T) { + arg := tc.composeArg() + st, ft, err := TrimASTWithCompose(arg) + tc.expect(t, arg.TargetAST, st, ft, err) + }) + } } diff --git a/tool/trimmer/trim/util.go b/tool/trimmer/trim/util.go index e685a0ff..5c99cc91 100644 --- a/tool/trimmer/trim/util.go +++ b/tool/trimmer/trim/util.go @@ -20,15 +20,19 @@ import ( "github.com/cloudwego/thriftgo/semantic" ) -func parseAndCheckAST(path string) *parser.Thrift { - ast, err := parser.ParseFile(path, nil, true) +func parseAndCheckAST(path string, includeDirs []string, recursive bool) *parser.Thrift { + ast, err := parser.ParseFile(path, includeDirs, recursive) check(err) + checkAST(ast) + return ast +} + +func checkAST(ast *parser.Thrift) { if path := parser.CircleDetect(ast); len(path) > 0 { check(fmt.Errorf("found include circle:\n\t%s", path)) } checker := semantic.NewChecker(semantic.Options{FixWarnings: true}) - _, err = checker.CheckAll(ast) + _, err := checker.CheckAll(ast) check(err) check(semantic.ResolveSymbols(ast)) - return ast }