Skip to content

Commit 0b95d09

Browse files
committed
parsing proto files
1 parent 556d8c1 commit 0b95d09

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

cmd/spawn/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ func main() {
2828
rootCmd.AddCommand(LocalICCmd)
2929
rootCmd.AddCommand(versionCmd)
3030
rootCmd.AddCommand(ModuleCmd())
31+
rootCmd.AddCommand(ProtoServiceGenerate())
3132

3233
applyPluginCmds()
3334

cmd/spawn/proto.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"io/fs"
6+
"os"
7+
"path"
8+
"strings"
9+
10+
"github.com/spf13/cobra"
11+
"gitub.com/strangelove-ventures/spawn/spawn"
12+
)
13+
14+
func ProtoServiceGenerate() *cobra.Command {
15+
cmd := &cobra.Command{
16+
// TODO: this name is ew
17+
// TODO: Put this in the make file on proto-gen? (after)
18+
Use: "service-generate [module]",
19+
Short: "Auto generate the MsgService stubs from proto -> Cosmos-SDK",
20+
Example: `spawn service-generate mymodule`,
21+
Args: cobra.MaximumNArgs(1),
22+
Aliases: []string{"sg"},
23+
Run: func(cmd *cobra.Command, args []string) {
24+
fmt.Println("service-generate called")
25+
26+
cwd, err := os.Getwd()
27+
if err != nil {
28+
fmt.Println("Error: ", err)
29+
}
30+
31+
protoPath := path.Join(cwd, "proto")
32+
33+
dirs, err := os.ReadDir(protoPath)
34+
if err != nil {
35+
fmt.Println("Error: ", err)
36+
}
37+
38+
absDirs := make([]string, 0)
39+
for _, dir := range dirs {
40+
if !dir.IsDir() {
41+
continue
42+
}
43+
44+
if len(args) > 0 && dir.Name() != args[0] {
45+
continue
46+
}
47+
48+
absDirs = append(absDirs, path.Join(protoPath, dir.Name()))
49+
}
50+
51+
fmt.Println("Found dirs: ", absDirs)
52+
53+
// walk it
54+
55+
modules := make(map[string]map[spawn.FileType][]spawn.ProtoService)
56+
57+
fs.WalkDir(os.DirFS(protoPath), ".", func(relPath string, d fs.DirEntry, e error) error {
58+
if !strings.HasSuffix(relPath, ".proto") {
59+
return nil
60+
}
61+
62+
// read file content
63+
content, err := os.ReadFile(path.Join(protoPath, relPath))
64+
if err != nil {
65+
fmt.Println("Error: ", err)
66+
}
67+
68+
fileType := spawn.SortContentToFileType(content)
69+
70+
parent := path.Dir(relPath)
71+
parent = strings.Split(parent, "/")[0]
72+
73+
// add/append to modules
74+
if _, ok := modules[parent]; !ok {
75+
modules[parent] = make(map[spawn.FileType][]spawn.ProtoService)
76+
}
77+
78+
fmt.Println("debugging... : ", parent, relPath, fileType)
79+
80+
switch fileType {
81+
case spawn.Tx:
82+
fmt.Println("File is a transaction")
83+
tx := spawn.ProtoServiceParser(content)
84+
modules[parent][spawn.Tx] = append(modules[parent][spawn.Tx], tx...)
85+
86+
case spawn.Query:
87+
fmt.Println("File is a query")
88+
query := spawn.ProtoServiceParser(content)
89+
modules[parent][spawn.Query] = append(modules[parent][spawn.Query], query...)
90+
case spawn.None:
91+
fmt.Println("File is neither a transaction nor a query")
92+
}
93+
94+
return nil
95+
})
96+
97+
fmt.Printf("Modules: %+v\n", modules)
98+
99+
},
100+
}
101+
102+
return cmd
103+
}

spawn/proto_parser.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package spawn
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
// The Name, RequestMsg, and ResponseMsg fields of rpc services
9+
type ProtoService struct {
10+
Name string
11+
Req string
12+
Res string
13+
}
14+
15+
// ProtoServiceParser parses out a proto file and returns all the services within it.
16+
func ProtoServiceParser(content []byte) []ProtoService {
17+
qss := make([]ProtoService, 0)
18+
c := strings.Split(string(content), "\n")
19+
20+
for idx, line := range c {
21+
if strings.Contains(line, "rpc ") {
22+
fmt.Println("Found rpc line: ", strings.Trim(line, " "))
23+
24+
// if line does not end with {, we also need to load the next line
25+
if !strings.HasSuffix(line, "{") {
26+
line = line + c[idx+1]
27+
}
28+
29+
line = strings.Trim(line, " ")
30+
31+
line = strings.NewReplacer("rpc", "", "returns", "", "(", " ", ")", " ", "{", "", "}", "").Replace(line)
32+
33+
words := strings.Fields(line)
34+
qss = append(qss, ProtoService{
35+
Name: words[0],
36+
Req: words[1],
37+
Res: words[2],
38+
})
39+
}
40+
}
41+
42+
return qss
43+
}
44+
45+
// FileType tells the application which type of proto file is it so we can sort Txs from Queries
46+
type FileType string
47+
48+
const (
49+
Tx FileType = "tx"
50+
Query FileType = "query"
51+
None FileType = "none"
52+
)
53+
54+
// returns "tx" or "query" depending on the content of the file
55+
func SortContentToFileType(bz []byte) FileType {
56+
res := string(bz)
57+
58+
// if `service Query` or `message Query` found in the file, it's a query
59+
if strings.Contains(res, "service Query") || strings.Contains(res, "message Query") {
60+
return Query
61+
}
62+
63+
// if `service Msg` or `service Tx` or `message Msg`
64+
if strings.Contains(res, "service Msg") || strings.Contains(res, "service Tx") || strings.Contains(res, "message Msg") {
65+
return Tx
66+
}
67+
68+
return None
69+
}

0 commit comments

Comments
 (0)