Skip to content

Commit

Permalink
feat: base proto & module generation (#39)
Browse files Browse the repository at this point in the history
* wip proto

* rename tweaks (untested)

* proto renames to `module` and `simapp`

* get example module setup with proto & script

* create new module base template cmd

* fix namespace overlap for depinject module

* fix straggling loggers

* replace all with example -> new x/ name

* simplify

* cleanup

* already exist TODO
  • Loading branch information
Reecepbcups authored Feb 15, 2024
1 parent 9d72f60 commit 7d7ee94
Show file tree
Hide file tree
Showing 17 changed files with 355 additions and 19 deletions.
1 change: 1 addition & 0 deletions cmd/spawn/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func main() {
rootCmd.AddCommand(newChain)
rootCmd.AddCommand(LocalICCmd)
rootCmd.AddCommand(versionCmd)
rootCmd.AddCommand(moduleCmd)

rootCmd.PersistentFlags().String(LogLevelFlag, "info", "log level (debug, info, warn, error)")

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

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

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

var moduleCmd = &cobra.Command{
Use: "module [name]",
Short: "Create a new module scaffolding",
Example: `spawn module mymodule`,
Args: cobra.ExactArgs(1),
Aliases: []string{"m", "mod", "proto"},
Run: func(cmd *cobra.Command, args []string) {
logger := GetLogger()

// ext name is the x/ 'module' name.
extName := strings.ToLower(args[0])

specialChars := "!@#$%^&*()_+{}|-:<>?`=[]\\;',./~"
for _, char := range specialChars {
if strings.Contains(extName, string(char)) {
logger.Error("Special characters are not allowed in module names")
return
}
}

cwd, err := os.Getwd()
if err != nil {
logger.Error("Error getting current working directory", err)
return
}

// see if cwd/x/extName exists
if _, err := os.Stat(path.Join(cwd, "x", extName)); err == nil {
logger.Error("TODO: Module already exists in x/. (Prompt UI to perform actions? (protoc-gen, generate keeper, setup to app.go, etc?))", "module", extName)
return
}

SetupModule(GetLogger(), extName)

// Announce the new module & how to code gen
fmt.Printf("\n🎉 New Module '%s' generated!\n", extName)
fmt.Println("🏅Generate Go Code:")
fmt.Println(" - $ make proto-gen # convert proto -> code and depinject")
},
}

func SetupModule(logger *slog.Logger, extName string) error {
protoFS := simapp.ProtoModuleFS

if err := os.MkdirAll("proto", 0755); err != nil {
panic(err)
}

cwd, err := os.Getwd()
if err != nil {
fmt.Println("Error getting current working directory", err)
return err
}

moduleName := readCurrentModuleName(path.Join(cwd, "go.mod"))
moduleNameProto := convertModuleNameToProto(moduleName)

return fs.WalkDir(protoFS, ".", func(relPath string, d fs.DirEntry, e error) error {
newPath := path.Join(cwd, relPath)
fc, err := spawn.GetFileContent(logger, newPath, protoFS, relPath, d)
if err != nil {
return err
} else if fc == nil {
return nil
}

// rename proto path for the new module
exampleProtoPath := path.Join("proto", "example")
if fc.ContainsPath(exampleProtoPath) {
newBinPath := path.Join("proto", extName)
fc.NewPath = strings.ReplaceAll(fc.NewPath, exampleProtoPath, newBinPath)
}

// any file content that has github.com/strangelove-ventures/simapp replace to moduleName

fc.ReplaceAll("github.com/strangelove-ventures/simapp", moduleName)
fc.ReplaceAll("strangelove_ventures.simapp", moduleNameProto)

// replace example -> the new x/ name
fc.ReplaceAll("example", extName)

// TODO: set the values in the keepers / msg server automatically

return fc.Save()
})
}

// readCurrentModuleName reads the module name from the go.mod file on the host machine.
func readCurrentModuleName(loc string) string {
if !strings.HasSuffix(loc, "go.mod") {
loc = path.Join(loc, "go.mod")
}

// read file from path into a []byte
var fileContent []byte
fileContent, err := os.ReadFile(loc)
if err != nil {
fmt.Println("Error reading file", err)
return ""
}

lines := strings.Split(string(fileContent), "\n")
for _, line := range lines {
if strings.Contains(line, "module") {
return strings.Split(line, " ")[1]
}
}

return ""
}

func convertModuleNameToProto(moduleName string) string {
// github.com/rollchains/myproject -> rollchains.myproject
text := strings.Replace(moduleName, "github.com/", "", 1)
return strings.Replace(text, "/", ".", -1)
}
4 changes: 2 additions & 2 deletions simapp/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SIMAPP = ./app

# for dockerized protobuf tools
DOCKER := $(shell which docker)
HTTPS_GIT := https://github.com/CosmWasm/wasmd.git
HTTPS_GIT := github.com/strangelove-ventures/simapp.git

export GO111MODULE = on

Expand Down Expand Up @@ -173,7 +173,7 @@ format: format-tools
###############################################################################
### Protobuf ###
###############################################################################
protoVer=0.14.0
protoVer=0.13.2
protoImageName=ghcr.io/cosmos/proto-builder:$(protoVer)
protoImage=$(DOCKER) run --rm -v $(CURDIR):/workspace --workdir /workspace $(protoImageName)

Expand Down
2 changes: 1 addition & 1 deletion simapp/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ import (
globalfeetypes "github.com/reecepbcups/globalfee/x/globalfee/types"
)

const appName = "WasmApp"
const appName = "CosmWasmApp"

var (
NodeDir = ".wasmd"
Expand Down
3 changes: 3 additions & 0 deletions simapp/embed.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ var SimAppFS embed.FS

//go:embed interchaintest/*
var ICTestFS embed.FS

//go:embed proto/*
var ProtoModuleFS embed.FS
8 changes: 8 additions & 0 deletions simapp/proto/buf.gen.gogo.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
version: v1
plugins:
- name: gocosmos
out: ..
opt: plugins=grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types,Mcosmos/orm/v1/orm.proto=cosmossdk.io/orm
- name: grpc-gateway
out: ..
opt: logtostderr=true,allow_colon_final_segments=true
20 changes: 20 additions & 0 deletions simapp/proto/buf.gen.pulsar.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
version: v1
managed:
enabled: true
go_package_prefix:
default: github.com/strangelove-ventures/simapp/api
except:
- buf.build/googleapis/googleapis
- buf.build/cosmos/gogo-proto
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/cosmos-sdk
plugins:
- name: go-pulsar
out: ..
opt: paths=source_relative,Mcosmos/app/v1alpha1/module.proto=cosmossdk.io/api/cosmos/app/v1alpha1
- name: go-grpc
out: ..
opt: paths=source_relative,Mcosmos/app/v1alpha1/module.proto=cosmossdk.io/api/cosmos/app/v1alpha1
- name: go-cosmos-orm
out: ..
opt: paths=source_relative,Mcosmos/app/v1alpha1/module.proto=cosmossdk.io/api/cosmos/app/v1alpha1
19 changes: 19 additions & 0 deletions simapp/proto/buf.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Generated by buf. DO NOT EDIT.
version: v1
deps:
- remote: buf.build
owner: cosmos
repository: cosmos-proto
commit: 1935555c206d4afb9e94615dfd0fad31
- remote: buf.build
owner: cosmos
repository: cosmos-sdk
commit: d5661b4f6ef64bb1b5beb6cb7bd705b7
- remote: buf.build
owner: cosmos
repository: gogo-proto
commit: 5e5b9fdd01804356895f8f79a6f1ddc1
- remote: buf.build
owner: googleapis
repository: googleapis
commit: cc916c31859748a68fd229a3c8d7a2e8
17 changes: 17 additions & 0 deletions simapp/proto/buf.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
version: v1
deps:
- buf.build/cosmos/cosmos-sdk # pin the Cosmos SDK version
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/gogo-proto
- buf.build/googleapis/googleapis
lint:
use:
- DEFAULT
- COMMENTS
- FILE_LOWER_SNAKE_CASE
except:
- UNARY_RPC
- COMMENT_FIELD
- SERVICE_SUFFIX
- PACKAGE_VERSION_SUFFIX
- RPC_REQUEST_STANDARD_NAME
13 changes: 13 additions & 0 deletions simapp/proto/example/module/v1/module.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
syntax = "proto3";

package strangelove_ventures.simapp.example.module.v1;

import "cosmos/app/v1alpha1/module.proto";

// Module is the app config object of the module.
// Learn more: https://docs.cosmos.network/main/building-modules/depinject
message Module {
option (cosmos.app.v1alpha1.module) = {
go_import : "github.com/strangelove-ventures/simapp"
};
}
22 changes: 22 additions & 0 deletions simapp/proto/example/v1/genesis.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
syntax = "proto3";
package example.v1;

import "gogoproto/gogo.proto";
import "amino/amino.proto";

option go_package = "github.com/strangelove-ventures/simapp/x/example/types";

// GenesisState defines the module genesis state
message GenesisState {
// Params defines all the paramaters of the module.
Params params = 1 [(gogoproto.nullable) = false];
}

// Params defines the set of module parameters.
message Params {
option (amino.name) = "example/params";
option (gogoproto.equal) = true;
option (gogoproto.goproto_stringer) = false;

bool some_value = 2;
}
24 changes: 24 additions & 0 deletions simapp/proto/example/v1/query.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
syntax = "proto3";
package example.v1;

import "google/api/annotations.proto";
import "example/v1/genesis.proto";

option go_package = "github.com/strangelove-ventures/simapp/x/example/types";

// Query provides defines the gRPC querier service.
service Query {
// Params queries all parameters of the module.
rpc Params(QueryParamsRequest) returns (QueryParamsResponse) {
option (google.api.http).get = "/example/v1/params";
}
}

// QueryParamsRequest is the request type for the Query/Params RPC method.
message QueryParamsRequest {}

// QueryParamsResponse is the response type for the Query/Params RPC method.
message QueryParamsResponse {
// params defines the parameters of the module.
Params params = 1;
}
40 changes: 40 additions & 0 deletions simapp/proto/example/v1/tx.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
syntax = "proto3";
package example.v1;

import "cosmos/msg/v1/msg.proto";
import "example/v1/genesis.proto";
import "gogoproto/gogo.proto";
import "cosmos_proto/cosmos.proto";

option go_package = "github.com/strangelove-ventures/simapp/x/example/types";

// Msg defines the Msg service.
service Msg {
option (cosmos.msg.v1.service) = true;

// UpdateParams defines a governance operation for updating the parameters.
//
// Since: cosmos-sdk 0.47
rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse);
}

// MsgUpdateParams is the Msg/UpdateParams request type.
//
// Since: cosmos-sdk 0.47
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";

// authority is the address of the governance account.
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];

// params defines the parameters to update.
//
// NOTE: All parameters must be supplied.
Params params = 2 [(gogoproto.nullable) = false];
}

// MsgUpdateParamsResponse defines the response structure for executing a
// MsgUpdateParams message.
//
// Since: cosmos-sdk 0.47
message MsgUpdateParamsResponse {}
37 changes: 37 additions & 0 deletions simapp/scripts/protocgen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
#!/usr/bin/env bash

set -e

echo "Generating gogo proto code"
cd proto
proto_dirs=$(find . -path -prune -o -name '*.proto' -print0 | xargs -0 -n1 dirname | sort | uniq)
for dir in $proto_dirs; do
for file in $(find "${dir}" -maxdepth 1 -name '*.proto'); do
# this regex checks if a proto file has its go_package set to github.com/strangelove-ventures/poa/...
# gogo proto files SHOULD ONLY be generated if this is false
# we don't want gogo proto to run for proto files which are natively built for google.golang.org/protobuf
if grep -q "option go_package" "$file" && grep -H -o -c 'option go_package.*github.com/strangelove-ventures/simapp/api' "$file" | grep -q ':0$'; then
buf generate --template buf.gen.gogo.yaml $file
fi
done
done

echo "Generating pulsar proto code"
buf generate --template buf.gen.pulsar.yaml

cd ..

mv github.com/strangelove-ventures/simapp/* ./
rm -rf github.com

# Copy files over for dep injection
rm -rf api && mkdir api
custom_modules=$(find . -name 'module' -type d -not -path "./proto/*")
for module in $custom_modules; do
dirPath=`basename $(dirname $module)`
mkdir -p api/$dirPath

mv $dirPath/* ./api/$dirPath/
rm -rf $dirPath
done

Loading

0 comments on commit 7d7ee94

Please sign in to comment.