Skip to content

Commit

Permalink
parsing proto files
Browse files Browse the repository at this point in the history
  • Loading branch information
Reecepbcups committed Feb 29, 2024
1 parent 556d8c1 commit 0b95d09
Show file tree
Hide file tree
Showing 3 changed files with 173 additions and 0 deletions.
1 change: 1 addition & 0 deletions cmd/spawn/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ func main() {
rootCmd.AddCommand(LocalICCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(ModuleCmd())
rootCmd.AddCommand(ProtoServiceGenerate())

applyPluginCmds()

Expand Down
103 changes: 103 additions & 0 deletions cmd/spawn/proto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package main

import (
"fmt"
"io/fs"
"os"
"path"
"strings"

"github.com/spf13/cobra"
"gitub.com/strangelove-ventures/spawn/spawn"
)

func ProtoServiceGenerate() *cobra.Command {
cmd := &cobra.Command{
// TODO: this name is ew
// TODO: Put this in the make file on proto-gen? (after)
Use: "service-generate [module]",
Short: "Auto generate the MsgService stubs from proto -> Cosmos-SDK",
Example: `spawn service-generate mymodule`,
Args: cobra.MaximumNArgs(1),
Aliases: []string{"sg"},
Run: func(cmd *cobra.Command, args []string) {
fmt.Println("service-generate called")

cwd, err := os.Getwd()
if err != nil {
fmt.Println("Error: ", err)
}

protoPath := path.Join(cwd, "proto")

dirs, err := os.ReadDir(protoPath)
if err != nil {
fmt.Println("Error: ", err)
}

absDirs := make([]string, 0)
for _, dir := range dirs {
if !dir.IsDir() {
continue
}

if len(args) > 0 && dir.Name() != args[0] {
continue
}

absDirs = append(absDirs, path.Join(protoPath, dir.Name()))
}

fmt.Println("Found dirs: ", absDirs)

// walk it

modules := make(map[string]map[spawn.FileType][]spawn.ProtoService)

fs.WalkDir(os.DirFS(protoPath), ".", func(relPath string, d fs.DirEntry, e error) error {
if !strings.HasSuffix(relPath, ".proto") {
return nil
}

// read file content
content, err := os.ReadFile(path.Join(protoPath, relPath))
if err != nil {
fmt.Println("Error: ", err)
}

fileType := spawn.SortContentToFileType(content)

parent := path.Dir(relPath)
parent = strings.Split(parent, "/")[0]

// add/append to modules
if _, ok := modules[parent]; !ok {
modules[parent] = make(map[spawn.FileType][]spawn.ProtoService)
}

fmt.Println("debugging... : ", parent, relPath, fileType)

switch fileType {
case spawn.Tx:
fmt.Println("File is a transaction")
tx := spawn.ProtoServiceParser(content)
modules[parent][spawn.Tx] = append(modules[parent][spawn.Tx], tx...)

case spawn.Query:
fmt.Println("File is a query")
query := spawn.ProtoServiceParser(content)
modules[parent][spawn.Query] = append(modules[parent][spawn.Query], query...)
case spawn.None:
fmt.Println("File is neither a transaction nor a query")
}

return nil
})

fmt.Printf("Modules: %+v\n", modules)

},
}

return cmd
}
69 changes: 69 additions & 0 deletions spawn/proto_parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package spawn

import (
"fmt"
"strings"
)

// The Name, RequestMsg, and ResponseMsg fields of rpc services
type ProtoService struct {
Name string
Req string
Res string
}

// ProtoServiceParser parses out a proto file and returns all the services within it.
func ProtoServiceParser(content []byte) []ProtoService {
qss := make([]ProtoService, 0)
c := strings.Split(string(content), "\n")

for idx, line := range c {
if strings.Contains(line, "rpc ") {
fmt.Println("Found rpc line: ", strings.Trim(line, " "))

// if line does not end with {, we also need to load the next line
if !strings.HasSuffix(line, "{") {
line = line + c[idx+1]
}

line = strings.Trim(line, " ")

line = strings.NewReplacer("rpc", "", "returns", "", "(", " ", ")", " ", "{", "", "}", "").Replace(line)

words := strings.Fields(line)
qss = append(qss, ProtoService{
Name: words[0],
Req: words[1],
Res: words[2],
})
}
}

return qss
}

// FileType tells the application which type of proto file is it so we can sort Txs from Queries
type FileType string

const (
Tx FileType = "tx"
Query FileType = "query"
None FileType = "none"
)

// returns "tx" or "query" depending on the content of the file
func SortContentToFileType(bz []byte) FileType {
res := string(bz)

// if `service Query` or `message Query` found in the file, it's a query
if strings.Contains(res, "service Query") || strings.Contains(res, "message Query") {
return Query
}

// if `service Msg` or `service Tx` or `message Msg`
if strings.Contains(res, "service Msg") || strings.Contains(res, "service Tx") || strings.Contains(res, "message Msg") {
return Tx
}

return None
}

0 comments on commit 0b95d09

Please sign in to comment.