Skip to content

Commit 35b235a

Browse files
authored
feat: enable js proto generation (#751)
* refactor(protoc): wrap protoc cmd as a pkg * enable js code generation for build & server out dir can be configured via `build.proto.js.out`. * generate js per module * change cosmosprotoc name to cosmosproto * docs
1 parent 5e1b795 commit 35b235a

File tree

15 files changed

+436
-219
lines changed

15 files changed

+436
-219
lines changed

go.mod

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,16 +42,17 @@ require (
4242
github.com/rdegges/go-ipify v0.0.0-20150526035502-2d94a6a86c40
4343
github.com/rogpeppe/go-internal v1.7.0 // indirect
4444
github.com/rs/cors v1.7.0
45-
github.com/sirupsen/logrus v1.7.1 // indirect
45+
github.com/sirupsen/logrus v1.8.0 // indirect
4646
github.com/spf13/cobra v1.1.3
4747
github.com/spf13/pflag v1.0.5
4848
github.com/stretchr/testify v1.7.0
4949
github.com/tendermint/spn v0.0.0-20201215081711-b9ec9286ed83
5050
github.com/tendermint/tendermint v0.34.3
51+
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df // indirect
5152
golang.org/x/mod v0.4.1
5253
golang.org/x/net v0.0.0-20210119194325-5f4716e94777 // indirect
5354
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
54-
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac // indirect
55+
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b // indirect
5556
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf // indirect
5657
google.golang.org/grpc v1.35.0
5758
)

go.sum

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -725,8 +725,8 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
725725
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
726726
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
727727
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
728-
github.com/sirupsen/logrus v1.7.1 h1:rsizeFmZP+GYwyb4V6t6qpG7ZNWzA2bvgW/yC2xHCcg=
729-
github.com/sirupsen/logrus v1.7.1/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
728+
github.com/sirupsen/logrus v1.8.0 h1:nfhvjKcUMhBMVqbKHJlk5RPrrfYr/NMo3692g0dwfWU=
729+
github.com/sirupsen/logrus v1.8.0/go.mod h1:4GuYW9TZmE769R5STWrRakJc4UqQ3+QQ95fyz7ENv1A=
730730
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
731731
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
732732
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
@@ -868,8 +868,9 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh
868868
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
869869
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
870870
golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
871-
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad h1:DN0cp81fZ3njFcrLCytUHRSUkqBjfTo4Tx9RJTWs0EY=
872871
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
872+
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df h1:y7QZzfUiTwWam+xBn29Ulb8CBwVN5UdzmMDavl9Whlw=
873+
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
873874
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
874875
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
875876
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -999,8 +1000,8 @@ golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7w
9991000
golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10001001
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10011002
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1002-
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac h1:9glrpwtNjBYgRpb67AZJKHfzj1stG/8BL5H7In2oTC4=
1003-
golang.org/x/sys v0.0.0-20210216224549-f992740a1bac/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
1003+
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b h1:lAZ0/chPUDWwjqosYR0X4M490zQhMsiJ4K3DbA7o+3g=
1004+
golang.org/x/sys v0.0.0-20210218155724-8ebf48af031b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
10041005
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
10051006
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
10061007
golang.org/x/term v0.0.0-20201210144234-2321bbc49cbf h1:MZ2shdL+ZM/XzY3ZGOnh4Nlpnxz5GSOhOmtHo3iPU6M=

starport/chainconf/config.go

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,6 @@ var (
2020

2121
// DefaultConf holds default configuration.
2222
DefaultConf = Config{
23-
Servers: Servers{
24-
RPCAddr: "0.0.0.0:26657",
25-
P2PAddr: "0.0.0.0:26656",
26-
ProfAddr: "0.0.0.0:6060",
27-
GRPCAddr: "0.0.0.0:9090",
28-
APIAddr: "0.0.0.0:1317",
29-
FrontendAddr: "0.0.0.0:8080",
30-
DevUIAddr: "0.0.0.0:12345",
31-
},
3223
Build: Build{
3324
Proto: Proto{
3425
Path: "proto",
@@ -41,6 +32,15 @@ var (
4132
Faucet: Faucet{
4233
Port: 4500,
4334
},
35+
Servers: Servers{
36+
RPCAddr: "0.0.0.0:26657",
37+
P2PAddr: "0.0.0.0:26656",
38+
ProfAddr: "0.0.0.0:6060",
39+
GRPCAddr: "0.0.0.0:9090",
40+
APIAddr: "0.0.0.0:1317",
41+
FrontendAddr: "0.0.0.0:8080",
42+
DevUIAddr: "0.0.0.0:12345",
43+
},
4444
}
4545
)
4646

@@ -50,6 +50,7 @@ type Config struct {
5050
Accounts []Account `yaml:"accounts"`
5151
Validator Validator `yaml:"validator"`
5252
Faucet Faucet `yaml:"faucet"`
53+
Client Client `yaml:"client"`
5354
Build Build `yaml:"build"`
5455
Init Init `yaml:"init"`
5556
Genesis map[string]interface{} `yaml:"genesis"`
@@ -99,6 +100,18 @@ type Proto struct {
99100
ThirdPartyPaths []string `yaml:"third_party_paths"`
100101
}
101102

103+
// Client configures code generation for clients.
104+
type Client struct {
105+
// Vuex configures code generation for Vuex.
106+
Vuex Vuex `yaml:"vuex"`
107+
}
108+
109+
// Vuex configures code generation for Vuex.
110+
type Vuex struct {
111+
// Path configures out location for generated Vuex code.
112+
Path string `yaml:"path"`
113+
}
114+
102115
// Faucet configuration.
103116
type Faucet struct {
104117
// Port number for faucet server to listen at.
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package cosmosproto
2+
3+
import (
4+
"context"
5+
"io/ioutil"
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
10+
"github.com/otiai10/copy"
11+
"github.com/pkg/errors"
12+
"github.com/tendermint/starport/starport/pkg/cmdrunner"
13+
"github.com/tendermint/starport/starport/pkg/cmdrunner/step"
14+
"github.com/tendermint/starport/starport/pkg/gomodule"
15+
"github.com/tendermint/starport/starport/pkg/nodetime/protobufjs"
16+
"github.com/tendermint/starport/starport/pkg/protoanalysis"
17+
"github.com/tendermint/starport/starport/pkg/protoc"
18+
"github.com/tendermint/starport/starport/pkg/protopath"
19+
"golang.org/x/mod/modfile"
20+
)
21+
22+
var (
23+
protocOuts = []string{
24+
"--gocosmos_out=plugins=interfacetype+grpc,Mgoogle/protobuf/any.proto=github.com/cosmos/cosmos-sdk/codec/types:.",
25+
"--grpc-gateway_out=logtostderr=true:.",
26+
}
27+
28+
sdkImport = "github.com/cosmos/cosmos-sdk"
29+
sdkProto = "proto"
30+
sdkProtoThirdParty = "third_party/proto"
31+
32+
fileTypes = "types"
33+
)
34+
35+
type generateOptions struct {
36+
gomodPath string
37+
jsOut func(protoanalysis.Package, string) string
38+
}
39+
40+
// Target adds a new code generation target to Generate.
41+
type Target func(*generateOptions)
42+
43+
// WithJSGeneration adds JS code generation.
44+
func WithJSGeneration(out func(pkg protoanalysis.Package, moduleName string) (path string)) Target {
45+
return func(o *generateOptions) {
46+
o.jsOut = out
47+
}
48+
}
49+
50+
// WithGoGeneration adds Go code generation.
51+
func WithGoGeneration(gomodPath string) Target {
52+
return func(o *generateOptions) {
53+
o.gomodPath = gomodPath
54+
}
55+
}
56+
57+
// generator generates code for sdk and sdk apps.
58+
type generator struct {
59+
ctx context.Context
60+
projectPath string
61+
protoPath string
62+
includePaths []string
63+
o *generateOptions
64+
modfile *modfile.File
65+
}
66+
67+
// Generate generates code from proto app's proto files.
68+
// make sure that all paths are absolute.
69+
func Generate(
70+
ctx context.Context,
71+
projectPath,
72+
protoPath string,
73+
includePaths []string,
74+
target Target,
75+
otherTargets ...Target,
76+
) error {
77+
g := &generator{
78+
ctx: ctx,
79+
projectPath: projectPath,
80+
protoPath: protoPath,
81+
includePaths: includePaths,
82+
o: &generateOptions{},
83+
}
84+
85+
for _, target := range append(otherTargets, target) {
86+
target(g.o)
87+
}
88+
89+
if err := g.setup(); err != nil {
90+
return err
91+
}
92+
93+
if g.o.jsOut != nil {
94+
if err := g.generateJS(); err != nil {
95+
return err
96+
}
97+
}
98+
99+
if g.o.gomodPath != "" {
100+
if err := g.generateGo(); err != nil {
101+
return err
102+
}
103+
}
104+
105+
return nil
106+
}
107+
108+
func (g *generator) setup() (err error) {
109+
// Cosmos SDK hosts proto files of own x/ modules and some third party ones needed by itself and
110+
// blockchain apps. Generate should be aware of these and make them available to the blockchain
111+
// app that wants to generate code for its own proto.
112+
//
113+
// blockchain apps may use different versions of the SDK. following code first makes sure that
114+
// app's dependencies are download by 'go mod' and cached under the local filesystem.
115+
// and then, it determines which version of the SDK is used by the app and what is the absolute path
116+
// of its source code.
117+
if err := cmdrunner.
118+
New(cmdrunner.DefaultWorkdir(g.projectPath)).
119+
Run(g.ctx, step.New(step.Exec("go", "mod", "download"))); err != nil {
120+
return err
121+
}
122+
123+
// parse the go.mod of the app.
124+
g.modfile, err = gomodule.ParseAt(g.projectPath)
125+
126+
return
127+
}
128+
129+
func (g *generator) generateGo() error {
130+
includePaths, err := g.resolveInclude(protopath.NewModule(sdkImport, sdkProto, sdkProtoThirdParty))
131+
if err != nil {
132+
return err
133+
}
134+
135+
// created a temporary dir to locate generated code under which later only some of them will be moved to the
136+
// app's source code. this also prevents having leftover files in the app's source code or its parent dir -when
137+
// command executed directly there- in case of an interrupt.
138+
tmp, err := ioutil.TempDir("", "")
139+
if err != nil {
140+
return err
141+
}
142+
defer os.RemoveAll(tmp)
143+
144+
if err := protoc.Generate(g.ctx, tmp, g.protoPath, append(g.includePaths, includePaths...), protocOuts); err != nil {
145+
return err
146+
}
147+
148+
// move generated code for the app under the relative locations in its source code.
149+
generatedPath := filepath.Join(tmp, g.o.gomodPath)
150+
err = copy.Copy(generatedPath, g.projectPath)
151+
return errors.Wrap(err, "cannot copy path")
152+
}
153+
154+
func (g *generator) generateJS() error {
155+
includePaths, err := g.resolveInclude(protopath.NewModule(sdkImport, sdkProto))
156+
if err != nil {
157+
return err
158+
}
159+
160+
pkgs, err := protoanalysis.DiscoverPackages(g.protoPath)
161+
if err != nil {
162+
return err
163+
}
164+
165+
for _, pkg := range pkgs {
166+
msp := strings.Split(pkg.Name, ".")
167+
moduleName := msp[len(msp)-1]
168+
169+
if err := protobufjs.Generate(
170+
g.ctx,
171+
g.o.jsOut(pkg, moduleName),
172+
fileTypes,
173+
pkg.Path,
174+
append(g.includePaths, includePaths...),
175+
); err != nil {
176+
return err
177+
}
178+
}
179+
180+
return nil
181+
}
182+
183+
func (g *generator) resolveInclude(modules ...protopath.Module) (paths []string, err error) {
184+
return protopath.ResolveDependencyPaths(g.modfile.Require, modules...)
185+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package cosmosproto
2+
3+
import (
4+
"bytes"
5+
"context"
6+
7+
"github.com/pkg/errors"
8+
"github.com/tendermint/starport/starport/pkg/cmdrunner"
9+
"github.com/tendermint/starport/starport/pkg/cmdrunner/step"
10+
"github.com/tendermint/starport/starport/pkg/xexec"
11+
)
12+
13+
// ErrProtocNotInstalled is returned when protoc isn't installed on the system.
14+
var ErrProtocNotInstalled = errors.New("protoc is not installed")
15+
16+
// InstallDependencies installs protoc dependencies needed by Cosmos ecosystem.
17+
func InstallDependencies(ctx context.Context, appPath string) error {
18+
if !xexec.IsCommandAvailable("protoc") {
19+
return ErrProtocNotInstalled
20+
}
21+
22+
errb := &bytes.Buffer{}
23+
err := cmdrunner.
24+
New(
25+
cmdrunner.DefaultStderr(errb),
26+
cmdrunner.DefaultWorkdir(appPath),
27+
).
28+
Run(ctx,
29+
// installs the gocosmos plugin with the version specified under the
30+
// go.mod of the app.
31+
step.New(
32+
step.Exec(
33+
"go",
34+
"get",
35+
"github.com/regen-network/cosmos-proto/protoc-gen-gocosmos@v0.3.1",
36+
),
37+
),
38+
// install grpc-gateway.
39+
step.New(
40+
step.Exec(
41+
"go",
42+
"get",
43+
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-grpc-gateway@v1.16.0",
44+
"github.com/grpc-ecosystem/grpc-gateway/protoc-gen-swagger@v1.16.0",
45+
"github.com/golang/protobuf/protoc-gen-go@v1.4.3",
46+
),
47+
),
48+
)
49+
return errors.Wrap(err, errb.String())
50+
}

0 commit comments

Comments
 (0)