Compare commits

..

2 Commits
main ... cache

Author SHA1 Message Date
chenzhihui f9825cb900 fix ttl 2 years ago
chenzhihui 315d3048bf add cache interface 2 years ago
  1. 8
      .github/pull_request_template.md
  2. 12
      .github/stable.yml
  3. 21
      .github/workflows/go.yml
  4. 16
      .github/workflows/issue-translator.yml
  5. 2
      .golangci.yml
  6. 30
      Makefile
  7. 2
      README.md
  8. 8
      SECURITY.md
  9. 7
      api/metadata/server.go
  10. 37
      app.go
  11. 20
      app_test.go
  12. 13
      cache/cache.go
  13. 10
      cmd/kratos/go.mod
  14. 38
      cmd/kratos/go.sum
  15. 6
      cmd/kratos/internal/base/mod_test.go
  16. 23
      cmd/kratos/internal/base/path.go
  17. 7
      cmd/kratos/internal/base/repo.go
  18. 2
      cmd/kratos/internal/base/vcs_url.go
  19. 2
      cmd/kratos/internal/change/change.go
  20. 4
      cmd/kratos/internal/change/get.go
  21. 10
      cmd/kratos/internal/project/add.go
  22. 16
      cmd/kratos/internal/project/new.go
  23. 70
      cmd/kratos/internal/project/project.go
  24. 29
      cmd/kratos/internal/project/project_linux_test.go
  25. 144
      cmd/kratos/internal/project/project_test.go
  26. 30
      cmd/kratos/internal/project/project_windows_test.go
  27. 7
      cmd/kratos/internal/proto/add/add.go
  28. 6
      cmd/kratos/internal/proto/add/proto.go
  29. 6
      cmd/kratos/internal/proto/client/client.go
  30. 4
      cmd/kratos/internal/proto/proto.go
  31. 18
      cmd/kratos/internal/proto/server/server.go
  32. 40
      cmd/kratos/internal/proto/server/server_test.go
  33. 18
      cmd/kratos/internal/run/run.go
  34. 6
      cmd/kratos/internal/upgrade/upgrade.go
  35. 4
      cmd/kratos/main.go
  36. 2
      cmd/kratos/version.go
  37. 2
      cmd/protoc-gen-go-errors/errors.go
  38. 17
      cmd/protoc-gen-go-errors/errorsTemplate.tpl
  39. 2
      cmd/protoc-gen-go-errors/go.mod
  40. 24
      cmd/protoc-gen-go-errors/go.sum
  41. 22
      cmd/protoc-gen-go-errors/template.go
  42. 2
      cmd/protoc-gen-go-errors/version.go
  43. 46
      cmd/protoc-gen-go-http/http.go
  44. 93
      cmd/protoc-gen-go-http/httpTemplate.tpl
  45. 7
      cmd/protoc-gen-go-http/main.go
  46. 96
      cmd/protoc-gen-go-http/template.go
  47. 2
      cmd/protoc-gen-go-http/version.go
  48. 14
      config/config.go
  49. 41
      config/config_test.go
  50. 6
      config/env/env.go
  51. 4
      config/env/watcher.go
  52. 14
      config/file/file_test.go
  53. 4
      config/file/format_test.go
  54. 4
      config/file/watcher.go
  55. 2
      config/options.go
  56. 14
      config/options_test.go
  57. 20
      config/reader.go
  58. 46
      config/reader_test.go
  59. 64
      config/value.go
  60. 71
      config/value_test.go
  61. 1
      contrib/config/apollo/README.md
  62. 60
      contrib/config/apollo/apollo.go
  63. 90
      contrib/config/apollo/apollo_test.go
  64. 9
      contrib/config/apollo/go.mod
  65. 992
      contrib/config/apollo/go.sum
  66. 9
      contrib/config/apollo/watcher.go
  67. 11
      contrib/config/consul/README.md
  68. 9
      contrib/config/consul/go.mod
  69. 1473
      contrib/config/consul/go.sum
  70. 2
      contrib/config/consul/watcher.go
  71. 15
      contrib/config/etcd/README.md
  72. 6
      contrib/config/etcd/go.mod
  73. 1460
      contrib/config/etcd/go.sum
  74. 4
      contrib/config/kubernetes/config_test.go
  75. 8
      contrib/config/kubernetes/go.mod
  76. 1229
      contrib/config/kubernetes/go.sum
  77. 3
      contrib/config/nacos/README.md
  78. 3
      contrib/config/nacos/go.mod
  79. 1462
      contrib/config/nacos/go.sum
  80. 29
      contrib/config/polaris/README.md
  81. 4
      contrib/config/polaris/config.go
  82. 170
      contrib/config/polaris/config_test.go
  83. 6
      contrib/config/polaris/go.mod
  84. 1191
      contrib/config/polaris/go.sum
  85. 10
      contrib/config/polaris/watcher.go
  86. 2
      contrib/encoding/msgpack/go.mod
  87. 1460
      contrib/encoding/msgpack/go.sum
  88. 36
      contrib/log/aliyun/aliyun.go
  89. 62
      contrib/log/aliyun/aliyun_test.go
  90. 6
      contrib/log/aliyun/go.mod
  91. 1432
      contrib/log/aliyun/go.sum
  92. 21
      contrib/log/fluent/fluent_test.go
  93. 3
      contrib/log/fluent/go.mod
  94. 1442
      contrib/log/fluent/go.sum
  95. 2
      contrib/log/logrus/go.mod
  96. 1459
      contrib/log/logrus/go.sum
  97. 4
      contrib/log/tencent/go.mod
  98. 1462
      contrib/log/tencent/go.sum
  99. 37
      contrib/log/tencent/tencent.go
  100. 45
      contrib/log/tencent/tencent_test.go
  101. Some files were not shown because too many files have changed in this diff Show More

@ -3,20 +3,22 @@
1. If this is your first time contributing to Kratos, please read our contribution guide: https://go-kratos.dev/en/docs/community/contribution/
2. Ensure you have added or ran the appropriate tests and lint for your PR, please use `make lint` and `make test` before filing your PR, use `make clean` to tidy your go mod.
3. If the PR is unfinished, you may need to mark it as a WIP(Work In Progress) PR or Draft PR
3. If the PR is unfinished, you may need to mark it as a WIP(Work In Progress) PR or draft PR
4. Please use a semantic commits format title, such as `<type>[optional scope]: <description>`, see: https://go-kratos.dev/docs/community/contribution#type
5. at the same time, please note that similar work should be submitted in one PR as far as possible to reduce the workload of reviewers. Do not split a work into multiple PR unless it should.
-->
<!--
🎉 感谢您向 Kratos 发送 PR!以下是一些提示:
🎉 感谢您向 Kratos 发送 PR 请求!以下是一些提示:
如果这是你第一次为 Kratos 贡献,请阅读我们的贡献指南:https://go-kratos.dev/en/docs/community/contribution/
2、确保您已经为您的 PR 添加或运行了适当的测试和lint,请在提交PR之前使用“make lint”和“make test”,使用“make clean”整理您的 go.mod。
3、如果 PR 未完成,您可能需要将其标记为 WIP(Work In Progress)PR 或 Draft PR
3、如果请购单未完成,您可能需要将其标记为 WIP(在制品)PR 或 draft PR
4、请使用语义提交格式标题,如“<类型>[可选范围]:<说明>`,请参阅:https://go-kratos.dev/docs/community/contribution#type
5. 同时请注意,同类的工作请尽量在一个PR中提交,以减轻 review 者的工作负担,不要把一项工作拆分成很多个PR,除非它应该这样做。
-->
<!--
-->
#### Description (what this PR does / why we need it):
<!--

@ -1,12 +0,0 @@
daysUntilStale: 30
daysUntilClose: 3
exemptLabels:
- pinned
- security
- bug
staleLabel: wontfix
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
closeComment: true

@ -13,7 +13,7 @@ jobs:
build:
strategy:
matrix:
go: [1.19,1.20.x]
go: [1.16, 1.17, 1.18, 1.19]
name: build & test
runs-on: ubuntu-latest
services:
@ -36,7 +36,7 @@ jobs:
- "8848:8848"
- "9848:9848"
polaris:
image: polarismesh/polaris-standalone:latest
image: polarismesh/polaris-server-standalone:v1.9.0
ports:
- 8090:8090
- 8091:8091
@ -44,25 +44,10 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4.0.1
uses: actions/setup-go@v3.3.0
with:
go-version: ${{ matrix.go }}
- name: Setup Environment
run: |
echo "GOPATH=$(go env GOPATH)" >> $GITHUB_ENV
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Module cache
uses: actions/cache@v3
with:
path: |
~/.cache/go-build
~/go/pkg/mod
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go
- name: Build
run: go build ./...

@ -1,16 +0,0 @@
name: 'issue-translator'
on:
issue_comment:
types: [created]
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: usthe/issues-translate-action@v2.7
with:
IS_MODIFY_TITLE: true
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑🤝🧑👫🧑🏿🤝🧑🏻👩🏾🤝👨🏿👬🏿
BOT_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }}

@ -68,4 +68,4 @@ linters-settings:
# recommend 10-20
min-complexity: 50
goimports:
local-prefixes: github.com/go-kratos # Put imports beginning with prefix after 3rd-party packages
local-prefixes: github.com/go-kratos/kratos # Put imports beginning with prefix after 3rd-party packages

@ -1,27 +1,9 @@
user := $(shell whoami)
rev := $(shell git rev-parse --short HEAD)
os := $(shell expr substr $(shell uname -s) 1 5)
# GOBIN > GOPATH > INSTALLDIR
# Mac OS X
ifeq ($(shell uname),Darwin)
GOBIN := $(shell echo ${GOBIN} | cut -d':' -f1)
GOPATH := $(shell echo $(GOPATH) | cut -d':' -f1)
endif
# Linux
ifeq ($(os),Linux)
GOBIN := $(shell echo ${GOBIN} | cut -d':' -f1)
GOPATH := $(shell echo $(GOPATH) | cut -d':' -f1)
endif
# Windows
ifeq ($(os),MINGW)
GOBIN := $(subst \,/,$(GOBIN))
GOPATH := $(subst \,/,$(GOPATH))
GOBIN :=/$(shell echo "$(GOBIN)" | cut -d';' -f1 | sed 's/://g')
GOPATH :=/$(shell echo "$(GOPATH)" | cut -d';' -f1 | sed 's/://g')
endif
BIN := ""
TOOLS_SHELL="./hack/tools.sh"
@ -32,7 +14,7 @@ LINTER := bin/golangci-lint
ifneq ($(GOBIN),)
BIN=$(GOBIN)
else
# check GOPATH
# check GOPATH
ifneq ($(GOPATH),)
BIN=$(GOPATH)/bin
endif
@ -55,9 +37,9 @@ ifeq ($(user),root)
@cp ./cmd/protoc-gen-go-http/protoc-gen-go-http /usr/bin
else
#!root, install for current user
$(shell if [ -z '$(BIN)' ]; then read -p "Please select installdir: " REPLY; mkdir -p $${REPLY};\
cp ./cmd/kratos/kratos $${REPLY}/;cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors $${REPLY}/;cp ./cmd/protoc-gen-go-http/protoc-gen-go-http $${REPLY}/;else mkdir -p '$(BIN)';\
cp ./cmd/kratos/kratos '$(BIN)';cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors '$(BIN)';cp ./cmd/protoc-gen-go-http/protoc-gen-go-http '$(BIN)'; fi)
$(shell if [ -z $(BIN) ]; then read -p "Please select installdir: " REPLY; mkdir -p $${REPLY};\
cp ./cmd/kratos/kratos $${REPLY}/;cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors $${REPLY}/;cp ./cmd/protoc-gen-go-http/protoc-gen-go-http $${REPLY}/;else mkdir -p $(BIN);\
cp ./cmd/kratos/kratos $(BIN);cp ./cmd/protoc-gen-go-errors/protoc-gen-go-errors $(BIN);cp ./cmd/protoc-gen-go-http/protoc-gen-go-http $(BIN); fi)
endif
@which protoc-gen-go &> /dev/null || go get google.golang.org/protobuf/cmd/protoc-gen-go
@which protoc-gen-go-grpc &> /dev/null || go get google.golang.org/grpc/cmd/protoc-gen-go-grpc
@ -89,7 +71,7 @@ test:
.PHONY: test-coverage
test-coverage:
@${TOOLS_SHELL} test_coverage
@echo "go test with coverage finished"
@echo "go test with coverage finished"
.PHONY: lint
lint: $(LINTER)
@ -99,4 +81,4 @@ lint: $(LINTER)
.PHONY: proto
proto:
protoc --proto_path=./api --proto_path=./third_party --go_out=paths=source_relative:./api --go-grpc_out=paths=source_relative:./api --go-http_out=paths=source_relative:./api metadata/metadata.proto
protoc --proto_path=./third_party --go_out=paths=source_relative:./errors/errors.proto
protoc --proto_path=./third_party --go_out=paths=source_relative:./ errors/errors.proto

@ -110,5 +110,5 @@ The following project had particular influence on kratos's design.
- [go-kit/kit](https://github.com/go-kit/kit) is a programming toolkit for building microservices in go.
- [asim/go-micro](https://github.com/asim/go-micro) a distributed systems development framework.
- [google/go-cloud](https://github.com/google/go-cloud) is go cloud development kit.
- [zeromicro/go-zero](https://github.com/zeromicro/go-zero) is a web and rpc framework with lots of builtin engineering practices.
- [tal-tech/go-zero](https://github.com/tal-tech/go-zero) is a web and rpc framework with lots of builtin engineering practices.
- [beego/beego](https://github.com/beego/beego) is a web framework including RESTful APIs, web apps and backend services.

@ -5,10 +5,10 @@
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
|-------------|--------------------|
| 2.0.rc1 | :white_check_mark: |
| < 2.0.beta3 | :x: |
| Version | Supported |
| ------- | ------------------ |
| 2.0.rc1 | :white_check_mark: |
| < 2.0.beta3 | :x: |
## Reporting a Vulnerability

@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"io"
"sort"
"sync"
"google.golang.org/grpc"
@ -98,7 +97,7 @@ func (s *Server) load() error {
}
// ListServices return all services
func (s *Server) ListServices(_ context.Context, _ *ListServicesRequest) (*ListServicesReply, error) {
func (s *Server) ListServices(ctx context.Context, in *ListServicesRequest) (*ListServicesReply, error) {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.load(); err != nil {
@ -116,13 +115,11 @@ func (s *Server) ListServices(_ context.Context, _ *ListServicesRequest) (*ListS
reply.Methods = append(reply.Methods, fmt.Sprintf("/%s/%s", name, method))
}
}
sort.Strings(reply.Services)
sort.Strings(reply.Methods)
return reply, nil
}
// GetServiceDesc return service meta by name
func (s *Server) GetServiceDesc(_ context.Context, in *GetServiceDescRequest) (*GetServiceDescReply, error) {
func (s *Server) GetServiceDesc(ctx context.Context, in *GetServiceDescRequest) (*GetServiceDescReply, error) {
s.lock.Lock()
defer s.lock.Unlock()
if err := s.load(); err != nil {

@ -89,15 +89,8 @@ func (a *App) Run() error {
a.mu.Lock()
a.instance = instance
a.mu.Unlock()
sctx := NewContext(a.ctx, a)
eg, ctx := errgroup.WithContext(sctx)
eg, ctx := errgroup.WithContext(NewContext(a.ctx, a))
wg := sync.WaitGroup{}
for _, fn := range a.opts.beforeStart {
if err = fn(sctx); err != nil {
return err
}
}
for _, srv := range a.opts.servers {
srv := srv
eg.Go(func() error {
@ -109,23 +102,17 @@ func (a *App) Run() error {
wg.Add(1)
eg.Go(func() error {
wg.Done() // here is to ensure server start has begun running before register, so defer is not needed
return srv.Start(sctx)
return srv.Start(NewContext(a.opts.ctx, a))
})
}
wg.Wait()
if a.opts.registrar != nil {
rctx, rcancel := context.WithTimeout(ctx, a.opts.registrarTimeout)
defer rcancel()
if err = a.opts.registrar.Register(rctx, instance); err != nil {
return err
}
}
for _, fn := range a.opts.afterStart {
if err = fn(sctx); err != nil {
if err := a.opts.registrar.Register(rctx, instance); err != nil {
return err
}
}
c := make(chan os.Signal, 1)
signal.Notify(c, a.opts.sigs...)
eg.Go(func() error {
@ -136,36 +123,28 @@ func (a *App) Run() error {
return a.Stop()
}
})
if err = eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
if err := eg.Wait(); err != nil && !errors.Is(err, context.Canceled) {
return err
}
for _, fn := range a.opts.afterStop {
err = fn(sctx)
}
return err
return nil
}
// Stop gracefully stops the application.
func (a *App) Stop() (err error) {
sctx := NewContext(a.ctx, a)
for _, fn := range a.opts.beforeStop {
err = fn(sctx)
}
func (a *App) Stop() error {
a.mu.Lock()
instance := a.instance
a.mu.Unlock()
if a.opts.registrar != nil && instance != nil {
ctx, cancel := context.WithTimeout(NewContext(a.ctx, a), a.opts.registrarTimeout)
defer cancel()
if err = a.opts.registrar.Deregister(ctx, instance); err != nil {
if err := a.opts.registrar.Deregister(ctx, instance); err != nil {
return err
}
}
if a.cancel != nil {
a.cancel()
}
return err
return nil
}
func (a *App) buildInstance() (*registry.ServiceInstance, error) {

@ -19,7 +19,7 @@ type mockRegistry struct {
service map[string]*registry.ServiceInstance
}
func (r *mockRegistry) Register(_ context.Context, service *registry.ServiceInstance) error {
func (r *mockRegistry) Register(ctx context.Context, service *registry.ServiceInstance) error {
if service == nil || service.ID == "" {
return errors.New("no service id")
}
@ -30,7 +30,7 @@ func (r *mockRegistry) Register(_ context.Context, service *registry.ServiceInst
}
// Deregister the registration.
func (r *mockRegistry) Deregister(_ context.Context, service *registry.ServiceInstance) error {
func (r *mockRegistry) Deregister(ctx context.Context, service *registry.ServiceInstance) error {
r.lk.Lock()
defer r.lk.Unlock()
if r.service[service.ID] == nil {
@ -47,22 +47,6 @@ func TestApp(t *testing.T) {
Name("kratos"),
Version("v1.0.0"),
Server(hs, gs),
BeforeStart(func(_ context.Context) error {
t.Log("BeforeStart...")
return nil
}),
BeforeStop(func(_ context.Context) error {
t.Log("BeforeStop...")
return nil
}),
AfterStart(func(_ context.Context) error {
t.Log("AfterStart...")
return nil
}),
AfterStop(func(_ context.Context) error {
t.Log("AfterStop...")
return nil
}),
Registrar(&mockRegistry{service: make(map[string]*registry.ServiceInstance)}),
)
time.AfterFunc(time.Second, func() {

13
cache/cache.go vendored

@ -0,0 +1,13 @@
package cache
import (
"context"
"time"
)
// Cache is a generic key value cache interface.
type Cache interface {
Get(ctx context.Context, key string) (interface{}, error)
Put(ctx context.Context, key string, value interface{}, ttl time.Duration) error
Delete(ctx context.Context, key string) error
}

@ -3,13 +3,15 @@ module github.com/go-kratos/kratos/cmd/kratos/v2
go 1.16
require (
github.com/AlecAivazis/survey/v2 v2.3.7
github.com/AlecAivazis/survey/v2 v2.3.4
github.com/emicklei/proto v1.10.0
github.com/fatih/color v1.13.0
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/spf13/cobra v1.4.0
github.com/stretchr/testify v1.7.0 // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4
golang.org/x/text v0.4.0
gopkg.in/yaml.v3 v3.0.0 // indirect
golang.org/x/mod v0.5.1
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/text v0.3.7
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
)

@ -1,5 +1,5 @@
github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ=
github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo=
github.com/AlecAivazis/survey/v2 v2.3.4 h1:pchTU9rsLUSvWEl2Aq9Pv3k0IE2fkqtGxazskAMd9Ng=
github.com/AlecAivazis/survey/v2 v2.3.4/go.mod h1:hrV6Y/kQCLhIZXGcriDCUBtB3wnN7156gMXJ3+b23xM=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s=
github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w=
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
@ -39,41 +39,37 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f h1:v4INt8xihDGvnrfjMDVXGxw9wrfxYyCjk0KbXjhR55s=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

@ -18,6 +18,8 @@ func TestModulePath(t *testing.T) {
t.Fatal(err)
}
defer os.RemoveAll("/tmp/test_mod")
f, err := os.Create("/tmp/test_mod/go.mod")
if err != nil {
t.Fatal(err)
@ -36,8 +38,6 @@ go 1.16`
t.Fatal(err)
}
if p != "github.com/go-kratos/kratos/v2" {
t.Fatalf("want: %s, got: %s", "github.com/go-kratos/kratos/v2", p)
t.Fatalf("want: %s, got: %s", "module github.com/go-kratos/kratos/v2", p)
}
t.Cleanup(func() { os.RemoveAll("/tmp/test_mod") })
}

@ -5,6 +5,7 @@ import (
"fmt"
"log"
"os"
"path"
"path/filepath"
"strings"
@ -16,7 +17,7 @@ func kratosHome() string {
if err != nil {
log.Fatal(err)
}
home := filepath.Join(dir, ".kratos")
home := path.Join(dir, ".kratos")
if _, err := os.Stat(home); os.IsNotExist(err) {
if err := os.MkdirAll(home, 0o700); err != nil {
log.Fatal(err)
@ -26,7 +27,7 @@ func kratosHome() string {
}
func kratosHomeWithDir(dir string) string {
home := filepath.Join(kratosHome(), dir)
home := path.Join(kratosHome(), dir)
if _, err := os.Stat(home); os.IsNotExist(err) {
if err := os.MkdirAll(home, 0o700); err != nil {
log.Fatal(err)
@ -36,6 +37,7 @@ func kratosHomeWithDir(dir string) string {
}
func copyFile(src, dst string, replaces []string) error {
var err error
srcinfo, err := os.Stat(src)
if err != nil {
return err
@ -56,26 +58,27 @@ func copyFile(src, dst string, replaces []string) error {
}
func copyDir(src, dst string, replaces, ignores []string) error {
srcinfo, err := os.Stat(src)
if err != nil {
var err error
var fds []os.DirEntry
var srcinfo os.FileInfo
if srcinfo, err = os.Stat(src); err != nil {
return err
}
err = os.MkdirAll(dst, srcinfo.Mode())
if err != nil {
if err = os.MkdirAll(dst, srcinfo.Mode()); err != nil {
return err
}
fds, err := os.ReadDir(src)
if err != nil {
if fds, err = os.ReadDir(src); err != nil {
return err
}
for _, fd := range fds {
if hasSets(fd.Name(), ignores) {
continue
}
srcfp := filepath.Join(src, fd.Name())
dstfp := filepath.Join(dst, fd.Name())
srcfp := path.Join(src, fd.Name())
dstfp := path.Join(dst, fd.Name())
var e error
if fd.IsDir() {
e = copyDir(srcfp, dstfp, replaces, ignores)

@ -7,7 +7,6 @@ import (
"os"
"os/exec"
"path"
"path/filepath"
"strings"
)
@ -69,7 +68,7 @@ func (r *Repo) Pull(ctx context.Context) error {
cmd.Dir = r.Path()
_, err := cmd.CombinedOutput()
if err != nil {
return err
return nil
}
cmd = exec.CommandContext(ctx, "git", "pull")
cmd.Dir = r.Path()
@ -105,7 +104,7 @@ func (r *Repo) CopyTo(ctx context.Context, to string, modPath string, ignores []
if err := r.Clone(ctx); err != nil {
return err
}
mod, err := ModulePath(filepath.Join(r.Path(), "go.mod"))
mod, err := ModulePath(path.Join(r.Path(), "go.mod"))
if err != nil {
return err
}
@ -117,7 +116,7 @@ func (r *Repo) CopyToV2(ctx context.Context, to string, modPath string, ignores,
if err := r.Clone(ctx); err != nil {
return err
}
mod, err := ModulePath(filepath.Join(r.Path(), "go.mod"))
mod, err := ModulePath(path.Join(r.Path(), "go.mod"))
if err != nil {
return err
}

@ -8,7 +8,7 @@ import (
)
var (
scpSyntaxRe = regexp.MustCompile(`^(\w+)@([\w.-]+):(.*)$`)
scpSyntaxRe = regexp.MustCompile(`^([a-zA-Z0-9_]+)@([a-zA-Z0-9._-]+):(.*)$`)
scheme = []string{"git", "https", "http", "git+ssh", "ssh", "file", "ftp", "ftps"}
)

@ -28,7 +28,7 @@ func init() {
token = os.Getenv("GITHUB_TOKEN")
}
func run(_ *cobra.Command, args []string) {
func run(cmd *cobra.Command, args []string) {
owner, repo := ParseGithubURL(repoURL)
api := GithubAPI{Owner: owner, Repo: repo, Token: token}
version := "latest"

@ -43,7 +43,7 @@ func (g *GithubAPI) GetReleaseInfo(version string) ReleaseInfo {
if version != "latest" {
api = fmt.Sprintf("https://api.github.com/repos/%s/%s/releases/tags/%s", g.Owner, g.Repo, version)
}
resp, code := requestGithubAPI(api, http.MethodGet, nil, g.Token)
resp, code := requestGithubAPI(api, "GET", nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}
@ -63,7 +63,7 @@ func (g *GithubAPI) GetCommitsInfo() []CommitInfo {
var list []CommitInfo
for {
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/commits?pre_page=%d&page=%d&since=%s", g.Owner, g.Repo, prePage, page, info.PublishedAt)
resp, code := requestGithubAPI(url, http.MethodGet, nil, g.Token)
resp, code := requestGithubAPI(url, "GET", nil, g.Token)
if code != http.StatusOK {
printGithubErrorInfo(resp)
}

@ -4,7 +4,7 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"path"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
@ -17,7 +17,7 @@ var repoAddIgnores = []string{
}
func (p *Project) Add(ctx context.Context, dir string, layout string, branch string, mod string) error {
to := filepath.Join(dir, p.Name)
to := path.Join(dir, p.Path)
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Printf("🚫 %s already exists\n", p.Name)
@ -40,13 +40,13 @@ func (p *Project) Add(ctx context.Context, dir string, layout string, branch str
repo := base.NewRepo(layout, branch)
if err := repo.CopyToV2(ctx, to, filepath.Join(mod, p.Path), repoAddIgnores, []string{filepath.Join(p.Path, "api"), "api"}); err != nil {
if err := repo.CopyToV2(ctx, to, path.Join(mod, p.Path), repoAddIgnores, []string{path.Join(p.Path, "api"), "api"}); err != nil {
return err
}
e := os.Rename(
filepath.Join(to, "cmd", "server"),
filepath.Join(to, "cmd", p.Name),
path.Join(to, "cmd", "server"),
path.Join(to, "cmd", p.Name),
)
if e != nil {
return e

@ -4,12 +4,12 @@ import (
"context"
"fmt"
"os"
"path/filepath"
"path"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/AlecAivazis/survey/v2"
"github.com/fatih/color"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// Project is a project template.
@ -20,14 +20,14 @@ type Project struct {
// New new a project from remote repo.
func (p *Project) New(ctx context.Context, dir string, layout string, branch string) error {
to := filepath.Join(dir, p.Name)
to := path.Join(dir, p.Name)
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Printf("🚫 %s already exists\n", p.Name)
override := false
prompt := &survey.Confirm{
Message: "📂 Do you want to override the folder ?",
Help: "Delete the existing folder and create the project.",
}
var override bool
e := survey.AskOne(prompt, &override)
if e != nil {
return e
@ -39,12 +39,12 @@ func (p *Project) New(ctx context.Context, dir string, layout string, branch str
}
fmt.Printf("🚀 Creating service %s, layout repo is %s, please wait a moment.\n\n", p.Name, layout)
repo := base.NewRepo(layout, branch)
if err := repo.CopyTo(ctx, to, p.Name, []string{".git", ".github"}); err != nil {
if err := repo.CopyTo(ctx, to, p.Path, []string{".git", ".github"}); err != nil {
return err
}
e := os.Rename(
filepath.Join(to, "cmd", "server"),
filepath.Join(to, "cmd", p.Name),
path.Join(to, "cmd", "server"),
path.Join(to, "cmd", p.Name),
)
if e != nil {
return e

@ -5,8 +5,7 @@ import (
"errors"
"fmt"
"os"
"path/filepath"
"strings"
"path"
"time"
"github.com/AlecAivazis/survey/v2"
@ -41,7 +40,7 @@ func init() {
CmdNew.Flags().BoolVarP(&nomod, "nomod", "", nomod, "retain go mod")
}
func run(_ *cobra.Command, args []string) {
func run(cmd *cobra.Command, args []string) {
wd, err := os.Getwd()
if err != nil {
panic(err)
@ -65,34 +64,23 @@ func run(_ *cobra.Command, args []string) {
} else {
name = args[0]
}
projectName, workingDir := processProjectParams(name, wd)
p := &Project{Name: projectName}
p := &Project{Name: path.Base(name), Path: name}
done := make(chan error, 1)
go func() {
if !nomod {
done <- p.New(ctx, workingDir, repoURL, branch)
done <- p.New(ctx, wd, repoURL, branch)
return
}
projectRoot := getgomodProjectRoot(workingDir)
if gomodIsNotExistIn(projectRoot) {
done <- fmt.Errorf("🚫 go.mod don't exists in %s", projectRoot)
if _, e := os.Stat(path.Join(wd, "go.mod")); os.IsNotExist(e) {
done <- fmt.Errorf("🚫 go.mod don't exists in %s", wd)
return
}
p.Path, err = filepath.Rel(projectRoot, filepath.Join(workingDir, projectName))
if err != nil {
done <- fmt.Errorf("🚫 failed to get relative path: %v", err)
return
}
mod, e := base.ModulePath(filepath.Join(projectRoot, "go.mod"))
mod, e := base.ModulePath(path.Join(wd, "go.mod"))
if e != nil {
done <- fmt.Errorf("🚫 failed to parse `go.mod`: %v", e)
return
panic(e)
}
// Get the relative path for adding a project based on Go modules
p.Path = filepath.Join(strings.TrimPrefix(workingDir, projectRoot+"/"), p.Name)
done <- p.Add(ctx, workingDir, repoURL, branch, mod)
done <- p.Add(ctx, wd, repoURL, branch, mod)
}()
select {
case <-ctx.Done():
@ -107,43 +95,3 @@ func run(_ *cobra.Command, args []string) {
}
}
}
func processProjectParams(projectName string, workingDir string) (projectNameResult, workingDirResult string) {
_projectDir := projectName
_workingDir := workingDir
// Process ProjectName with system variable
if strings.HasPrefix(projectName, "~") {
homeDir, err := os.UserHomeDir()
if err != nil {
// cannot get user home return fallback place dir
return _projectDir, _workingDir
}
_projectDir = filepath.Join(homeDir, projectName[2:])
}
// check path is relative
if !filepath.IsAbs(projectName) {
absPath, err := filepath.Abs(projectName)
if err != nil {
return _projectDir, _workingDir
}
_projectDir = absPath
}
return filepath.Base(_projectDir), filepath.Dir(_projectDir)
}
func getgomodProjectRoot(dir string) string {
if dir == filepath.Dir(dir) {
return dir
}
if gomodIsNotExistIn(dir) {
return getgomodProjectRoot(filepath.Dir(dir))
}
return dir
}
func gomodIsNotExistIn(dir string) bool {
_, e := os.Stat(filepath.Join(dir, "go.mod"))
return os.IsNotExist(e)
}

@ -1,29 +0,0 @@
//go:build linux
// +build linux
package project
import (
"testing"
)
func Test_processProjectParams(t *testing.T) {
type args struct {
projectName string
fallbackPlaceDir string
}
tests := []struct {
name string
args args
want string
}{
{"absLinux", args{projectName: "/home/kratos/awesome/go/demo", fallbackPlaceDir: ""}, "/home/kratos/awesome/go"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if _, got := processProjectParams(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
t.Errorf("processProjectParams() = %v, want %v", got, tt.want)
}
})
}
}

@ -1,144 +0,0 @@
package project
import (
"fmt"
"go/parser"
"go/token"
"os"
"path/filepath"
"testing"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
)
// TestCmdNew tests the `kratos new` command.
func TestCmdNew(t *testing.T) {
cwd := changeCurrentDir(t)
projectName := "helloworld"
// create a new project
CmdNew.SetArgs([]string{projectName})
if err := CmdNew.Execute(); err != nil {
t.Fatalf("executing command: %v", err)
}
// check that the expected files were created
for _, file := range []string{
"go.mod",
"go.sum",
"README.md",
"cmd/helloworld/main.go",
} {
if _, err := os.Stat(filepath.Join(cwd, projectName, file)); err != nil {
t.Errorf("expected file %s to exist", file)
}
}
// check that the go.mod file contains the expected module name
assertGoMod(t, filepath.Join(cwd, projectName, "go.mod"), projectName)
assertImportsInclude(t, filepath.Join(cwd, projectName, "cmd", projectName, "wire.go"), fmt.Sprintf(`"%s/internal/biz"`, projectName))
}
// TestCmdNewNoMod tests the `kratos new` command with the --nomod flag.
func TestCmdNewNoMod(t *testing.T) {
cwd := changeCurrentDir(t)
// create a new project
CmdNew.SetArgs([]string{"project"})
if err := CmdNew.Execute(); err != nil {
t.Fatalf("executing command: %v", err)
}
// add new app with --nomod flag
CmdNew.SetArgs([]string{"--nomod", "project/app/user"})
if err := CmdNew.Execute(); err != nil {
t.Fatalf("executing command: %v", err)
}
// check that the expected files were created
for _, file := range []string{
"go.mod",
"go.sum",
"README.md",
"cmd/project/main.go",
"app/user/cmd/user/main.go",
} {
if _, err := os.Stat(filepath.Join(cwd, "project", file)); err != nil {
t.Errorf("expected file %s to exist", file)
}
}
assertImportsInclude(t, filepath.Join(cwd, "project/app/user/cmd/user/wire.go"), `"project/app/user/internal/biz"`)
}
// assertImportsInclude checks that the file at path contains the expected import.
func assertImportsInclude(t *testing.T, path, expected string) {
t.Helper()
got, err := imports(path)
if err != nil {
t.Fatalf("getting imports: %v", err)
}
for _, imp := range got {
if imp == expected {
return
}
}
t.Errorf("expected imports to include %s, got %v", expected, got)
}
// imports returns the imports in the file at path.
func imports(path string) ([]string, error) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly)
if err != nil {
return nil, err
}
imports := make([]string, 0, len(f.Imports))
for _, s := range f.Imports {
imports = append(imports, s.Path.Value)
}
return imports, nil
}
// assertGoMod checks that the go.mod file contains the expected module name.
func assertGoMod(t *testing.T, path, expected string) {
t.Helper()
got, err := base.ModulePath(path)
if err != nil {
t.Fatalf("getting module path: %v", err)
}
if got != expected {
t.Errorf("expected module name %s, got %s", expected, got)
}
}
// change the working directory to the tempdir
func changeCurrentDir(t *testing.T) string {
t.Helper()
tmp := t.TempDir()
oldCWD, err := os.Getwd()
if err != nil {
t.Fatalf("getting working directory: %v", err)
}
if err := os.Chdir(tmp); err != nil {
t.Fatalf("changing working directory: %v", err)
}
t.Cleanup(func() {
if err := os.Chdir(oldCWD); err != nil {
t.Fatalf("restoring working directory: %v", err)
}
})
return tmp
}

@ -1,30 +0,0 @@
//go:build windows
// +build windows
package project
import (
"testing"
)
func Test_processProjectParams(t *testing.T) {
type args struct {
projectName string
fallbackPlaceDir string
}
tests := []struct {
name string
args args
want string
}{
{"absWindows", args{projectName: "c:\\kratos\\awesome\\go\\demo", fallbackPlaceDir: ""}, "c:\\kratos\\awesome\\go"},
//{"relativeWindows", args{projectName: "/home/kratos/awesome/go/demo", fallbackPlaceDir: ""}, "/home/kratos/awesome/go"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if _, got := processProjectParams(tt.args.projectName, tt.args.fallbackPlaceDir); got != tt.want {
t.Errorf("getProjectPlaceDir() = %v, want %v", got, tt.want)
}
})
}
}

@ -19,11 +19,8 @@ var CmdAdd = &cobra.Command{
Run: run,
}
func run(_ *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Please enter the proto file or directory")
return
}
func run(cmd *cobra.Command, args []string) {
// kratos proto add helloworld/v1/helloworld.proto
input := args[0]
n := strings.LastIndex(input, "/")
if n == -1 {

@ -3,7 +3,7 @@ package add
import (
"fmt"
"os"
"path/filepath"
"path"
)
// Proto is a proto generator.
@ -26,13 +26,13 @@ func (p *Proto) Generate() error {
if err != nil {
panic(err)
}
to := filepath.Join(wd, p.Path)
to := path.Join(wd, p.Path)
if _, err := os.Stat(to); os.IsNotExist(err) {
if err := os.MkdirAll(to, 0o700); err != nil {
return err
}
}
name := filepath.Join(to, p.Name)
name := path.Join(to, p.Name)
if _, err := os.Stat(name); !os.IsNotExist(err) {
return fmt.Errorf("%s already exists", p.Name)
}

@ -8,9 +8,9 @@ import (
"regexp"
"strings"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
)
// CmdClient represents the source command.
@ -30,7 +30,7 @@ func init() {
CmdClient.Flags().StringVarP(&protoPath, "proto_path", "p", protoPath, "proto path")
}
func run(_ *cobra.Command, args []string) {
func run(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Println("Please enter the proto file or directory")
return

@ -1,11 +1,11 @@
package proto
import (
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/add"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/client"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto/server"
"github.com/spf13/cobra"
)
// CmdProto represents the proto command.

@ -4,7 +4,7 @@ import (
"fmt"
"log"
"os"
"path/filepath"
"path"
"strings"
"github.com/emicklei/proto"
@ -16,8 +16,8 @@ import (
// CmdServer the service command.
var CmdServer = &cobra.Command{
Use: "server",
Short: "Generate the proto server implementations",
Long: "Generate the proto server implementations. Example: kratos proto server api/xxx.proto --target-dir=internal/service",
Short: "Generate the proto Server implementations",
Long: "Generate the proto Server implementations. Example: kratos proto server api/xxx.proto -target-dir=internal/service",
Run: run,
}
var targetDir string
@ -26,7 +26,7 @@ func init() {
CmdServer.Flags().StringVarP(&targetDir, "target-dir", "t", "internal/service", "generate target directory")
}
func run(_ *cobra.Command, args []string) {
func run(cmd *cobra.Command, args []string) {
if len(args) == 0 {
fmt.Fprintln(os.Stderr, "Please specify the proto file. Example: kratos proto server api/xxx.proto")
return
@ -64,8 +64,8 @@ func run(_ *cobra.Command, args []string) {
continue
}
cs.Methods = append(cs.Methods, &Method{
Service: serviceName(s.Name), Name: serviceName(r.Name), Request: parametersName(r.RequestType),
Reply: parametersName(r.ReturnsType), Type: getMethodType(r.StreamsRequest, r.StreamsReturns),
Service: serviceName(s.Name), Name: serviceName(r.Name), Request: r.RequestType,
Reply: r.ReturnsType, Type: getMethodType(r.StreamsRequest, r.StreamsReturns),
})
}
res = append(res, cs)
@ -76,7 +76,7 @@ func run(_ *cobra.Command, args []string) {
return
}
for _, s := range res {
to := filepath.Join(targetDir, strings.ToLower(s.Service)+".go")
to := path.Join(targetDir, strings.ToLower(s.Service)+".go")
if _, err := os.Stat(to); !os.IsNotExist(err) {
fmt.Fprintf(os.Stderr, "%s already exists: %s\n", s.Service, to)
continue
@ -105,10 +105,6 @@ func getMethodType(streamsRequest, streamsReturns bool) MethodType {
return unaryType
}
func parametersName(name string) string {
return strings.ReplaceAll(name, ".", "_")
}
func serviceName(name string) string {
return toUpperCamelCase(strings.Split(name, ".")[0])
}

@ -60,43 +60,3 @@ func Test_serviceName(t *testing.T) {
})
}
}
func Test_parametersName(t *testing.T) {
type args struct {
name string
}
tests := []struct {
name string
args args
want string
}{
{
name: "parametersName on not nested",
args: args{
name: "MessageResponse",
},
want: "MessageResponse",
},
{
name: "parametersName on One layer of nesting",
args: args{
name: "Message.Response",
},
want: "Message_Response",
},
{
name: "parametersName on Two layer of nesting",
args: args{
name: "Message.Message2.Response",
},
want: "Message_Message2_Response",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := parametersName(tt.args.name); got != tt.want {
t.Errorf("parametersName() = %v, want %v", got, tt.want)
}
})
}
}

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"os/exec"
"path"
"path/filepath"
"strings"
@ -18,11 +19,6 @@ var CmdRun = &cobra.Command{
Long: "Run project. Example: kratos run",
Run: Run,
}
var targetDir string
func init() {
CmdRun.Flags().StringVarP(&targetDir, "work", "w", "", "target working directory")
}
// Run run project.
func Run(cmd *cobra.Command, args []string) {
@ -68,11 +64,10 @@ func Run(cmd *cobra.Command, args []string) {
dir = cmdPath[dir]
}
}
fd := exec.Command("go", append([]string{"run", dir}, programArgs...)...)
fd := exec.Command("go", append([]string{"run", "."}, programArgs...)...)
fd.Stdout = os.Stdout
fd.Stderr = os.Stderr
fd.Dir = dir
changeWorkingDirectory(fd, targetDir)
if err := fd.Run(); err != nil {
fmt.Fprintf(os.Stderr, "\033[31mERROR: %s\033[m\n", err.Error())
return
@ -107,7 +102,7 @@ func findCMD(base string) (map[string]string, error) {
}
for _, fileInfo := range paths {
if fileInfo.IsDir() {
abs := filepath.Join(walkPath, fileInfo.Name())
abs := path.Join(walkPath, fileInfo.Name())
cmdPath[strings.TrimPrefix(abs, wd)] = abs
}
}
@ -136,10 +131,3 @@ func findCMD(base string) (map[string]string, error) {
}
return map[string]string{"": base}, nil
}
func changeWorkingDirectory(cmd *exec.Cmd, targetDir string) {
targetDir = strings.TrimSpace(targetDir)
if targetDir != "" {
cmd.Dir = targetDir
}
}

@ -3,9 +3,9 @@ package upgrade
import (
"fmt"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/base"
"github.com/spf13/cobra"
)
// CmdUpgrade represents the upgrade command.
@ -17,7 +17,7 @@ var CmdUpgrade = &cobra.Command{
}
// Run upgrade the kratos tools.
func Run(_ *cobra.Command, _ []string) {
func Run(cmd *cobra.Command, args []string) {
err := base.GoInstall(
"github.com/go-kratos/kratos/cmd/kratos/v2@latest",
"github.com/go-kratos/kratos/cmd/protoc-gen-go-http/v2@latest",

@ -3,13 +3,13 @@ package main
import (
"log"
"github.com/spf13/cobra"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/change"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/project"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/proto"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/run"
"github.com/go-kratos/kratos/cmd/kratos/v2/internal/upgrade"
"github.com/spf13/cobra"
)
var rootCmd = &cobra.Command{

@ -1,4 +1,4 @@
package main
// release is the current kratos tool version.
const release = "v2.6.3"
const release = "v2.5.1"

@ -59,7 +59,7 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.
}
}
func genErrorsReason(_ *protogen.Plugin, _ *protogen.File, g *protogen.GeneratedFile, enum *protogen.Enum) bool {
func genErrorsReason(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, enum *protogen.Enum) bool {
defaultCode := proto.GetExtension(enum.Desc.Options(), errors.E_DefaultCode)
code := 0
if ok := defaultCode.(int32); ok != 0 {

@ -1,17 +0,0 @@
{{ range .Errors }}
{{ if .HasComment }}{{ .Comment }}{{ end -}}
func Is{{.CamelValue}}(err error) bool {
if err == nil {
return false
}
e := errors.FromError(err)
return e.Reason == {{ .Name }}_{{ .Value }}.String() && e.Code == {{ .HTTPCode }}
}
{{ if .HasComment }}{{ .Comment }}{{ end -}}
func Error{{ .CamelValue }}(format string, args ...interface{}) *errors.Error {
return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf(format, args...))
}
{{- end }}

@ -3,6 +3,6 @@ module github.com/go-kratos/kratos/cmd/protoc-gen-go-errors/v2
go 1.16
require (
golang.org/x/text v0.3.8
golang.org/x/text v0.3.7
google.golang.org/protobuf v1.28.0
)

@ -1,31 +1,9 @@
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.3.8 h1:nAL+RVCQ9uMn3vJZbV+MRnydTJFPf8qqY42YiA6MrqY=
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=

@ -2,12 +2,28 @@ package main
import (
"bytes"
_ "embed"
"text/template"
)
//go:embed errorsTemplate.tpl
var errorsTemplate string
var errorsTemplate = `
{{ range .Errors }}
{{ if .HasComment }}{{ .Comment }}{{ end -}}
func Is{{.CamelValue}}(err error) bool {
if err == nil {
return false
}
e := errors.FromError(err)
return e.Reason == {{ .Name }}_{{ .Value }}.String() && e.Code == {{ .HTTPCode }}
}
{{ if .HasComment }}{{ .Comment }}{{ end -}}
func Error{{ .CamelValue }}(format string, args ...interface{}) *errors.Error {
return errors.New({{ .HTTPCode }}, {{ .Name }}_{{ .Value }}.String(), fmt.Sprintf(format, args...))
}
{{- end }}
`
type errorInfo struct {
Name string

@ -1,4 +1,4 @@
package main
// release is the current protoc-gen-go-errors version.
const release = "v2.6.3"
const release = "v2.5.1"

@ -2,7 +2,6 @@ package main
import (
"fmt"
"net/http"
"os"
"regexp"
"strings"
@ -24,7 +23,7 @@ const (
var methodSets = make(map[string]int)
// generateFile generates a _http.pb.go file containing kratos errors definitions.
func generateFile(gen *protogen.Plugin, file *protogen.File, omitempty bool, omitemptyPrefix string) *protogen.GeneratedFile {
func generateFile(gen *protogen.Plugin, file *protogen.File, omitempty bool) *protogen.GeneratedFile {
if len(file.Services) == 0 || (omitempty && !hasHTTPRule(file.Services)) {
return nil
}
@ -42,12 +41,12 @@ func generateFile(gen *protogen.Plugin, file *protogen.File, omitempty bool, omi
g.P()
g.P("package ", file.GoPackageName)
g.P()
generateFileContent(gen, file, g, omitempty, omitemptyPrefix)
generateFileContent(gen, file, g, omitempty)
return g
}
// generateFileContent generates the kratos errors definitions, excluding the package statement.
func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, omitempty bool, omitemptyPrefix string) {
func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, omitempty bool) {
if len(file.Services) == 0 {
return
}
@ -59,11 +58,11 @@ func generateFileContent(gen *protogen.Plugin, file *protogen.File, g *protogen.
g.P()
for _, service := range file.Services {
genService(gen, file, g, service, omitempty, omitemptyPrefix)
genService(gen, file, g, service, omitempty)
}
}
func genService(_ *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service, omitempty bool, omitemptyPrefix string) {
func genService(gen *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFile, service *protogen.Service, omitempty bool) {
if service.Desc.Options().(*descriptorpb.ServiceOptions).GetDeprecated() {
g.P("//")
g.P(deprecationComment)
@ -81,12 +80,12 @@ func genService(_ *protogen.Plugin, file *protogen.File, g *protogen.GeneratedFi
rule, ok := proto.GetExtension(method.Desc.Options(), annotations.E_Http).(*annotations.HttpRule)
if rule != nil && ok {
for _, bind := range rule.AdditionalBindings {
sd.Methods = append(sd.Methods, buildHTTPRule(g, service, method, bind, omitemptyPrefix))
sd.Methods = append(sd.Methods, buildHTTPRule(g, method, bind))
}
sd.Methods = append(sd.Methods, buildHTTPRule(g, service, method, rule, omitemptyPrefix))
sd.Methods = append(sd.Methods, buildHTTPRule(g, method, rule))
} else if !omitempty {
path := fmt.Sprintf("%s/%s/%s", omitemptyPrefix, service.Desc.FullName(), method.Desc.Name())
sd.Methods = append(sd.Methods, buildMethodDesc(g, method, http.MethodPost, path))
path := fmt.Sprintf("/%s/%s", service.Desc.FullName(), method.Desc.Name())
sd.Methods = append(sd.Methods, buildMethodDesc(g, method, "POST", path))
}
}
if len(sd.Methods) != 0 {
@ -109,7 +108,7 @@ func hasHTTPRule(services []*protogen.Service) bool {
return false
}
func buildHTTPRule(g *protogen.GeneratedFile, service *protogen.Service, m *protogen.Method, rule *annotations.HttpRule, omitemptyPrefix string) *methodDesc {
func buildHTTPRule(g *protogen.GeneratedFile, m *protogen.Method, rule *annotations.HttpRule) *methodDesc {
var (
path string
method string
@ -120,33 +119,27 @@ func buildHTTPRule(g *protogen.GeneratedFile, service *protogen.Service, m *prot
switch pattern := rule.Pattern.(type) {
case *annotations.HttpRule_Get:
path = pattern.Get
method = http.MethodGet
method = "GET"
case *annotations.HttpRule_Put:
path = pattern.Put
method = http.MethodPut
method = "PUT"
case *annotations.HttpRule_Post:
path = pattern.Post
method = http.MethodPost
method = "POST"
case *annotations.HttpRule_Delete:
path = pattern.Delete
method = http.MethodDelete
method = "DELETE"
case *annotations.HttpRule_Patch:
path = pattern.Patch
method = http.MethodPatch
method = "PATCH"
case *annotations.HttpRule_Custom:
path = pattern.Custom.Path
method = pattern.Custom.Kind
}
if method == "" {
method = http.MethodPost
}
if path == "" {
path = fmt.Sprintf("%s/%s/%s", omitemptyPrefix, service.Desc.FullName(), m.Desc.Name())
}
body = rule.Body
responseBody = rule.ResponseBody
md := buildMethodDesc(g, m, method, path)
if method == http.MethodGet || method == http.MethodDelete {
if method == "GET" || method == "DELETE" {
if body != "" {
_, _ = fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: %s %s body should not be declared.\n", method, path)
}
@ -204,17 +197,12 @@ func buildMethodDesc(g *protogen.GeneratedFile, m *protogen.Method, method, path
}
}
}
comment := m.Comments.Leading.String() + m.Comments.Trailing.String()
if comment != "" {
comment = "// " + m.GoName + strings.TrimPrefix(strings.TrimSuffix(comment, "\n"), "//")
}
return &methodDesc{
Name: m.GoName,
OriginalName: string(m.Desc.Name()),
Num: methodSets[m.GoName],
Request: g.QualifiedGoIdent(m.Input.GoIdent),
Reply: g.QualifiedGoIdent(m.Output.GoIdent),
Comment: comment,
Path: path,
Method: method,
HasVars: len(vars) > 0,
@ -225,7 +213,7 @@ func buildPathVars(path string) (res map[string]*string) {
if strings.HasSuffix(path, "/") {
fmt.Fprintf(os.Stderr, "\u001B[31mWARN\u001B[m: Path %s should not end with \"/\" \n", path)
}
pattern := regexp.MustCompile(`(?i){([a-z.0-9_\s]*)=?([^{}]*)}`)
pattern := regexp.MustCompile(`(?i){([a-z\.0-9_\s]*)=?([^{}]*)}`)
matches := pattern.FindAllStringSubmatch(path, -1)
res = make(map[string]*string, len(matches))
for _, m := range matches {

@ -1,93 +0,0 @@
{{$svrType := .ServiceType}}
{{$svrName := .ServiceName}}
{{- range .MethodSets}}
const Operation{{$svrType}}{{.OriginalName}} = "/{{$svrName}}/{{.OriginalName}}"
{{- end}}
type {{.ServiceType}}HTTPServer interface {
{{- range .MethodSets}}
{{- if ne .Comment ""}}
{{.Comment}}
{{- end}}
{{.Name}}(context.Context, *{{.Request}}) (*{{.Reply}}, error)
{{- end}}
}
func Register{{.ServiceType}}HTTPServer(s *http.Server, srv {{.ServiceType}}HTTPServer) {
r := s.Route("/")
{{- range .Methods}}
r.{{.Method}}("{{.Path}}", _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv))
{{- end}}
}
{{range .Methods}}
func _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv {{$svrType}}HTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in {{.Request}}
{{- if .HasBody}}
if err := ctx.Bind(&in{{.Body}}); err != nil {
return err
}
{{- if not (eq .Body "")}}
if err := ctx.BindQuery(&in); err != nil {
return err
}
{{- end}}
{{- else}}
if err := ctx.BindQuery(&in{{.Body}}); err != nil {
return err
}
{{- end}}
{{- if .HasVars}}
if err := ctx.BindVars(&in); err != nil {
return err
}
{{- end}}
http.SetOperation(ctx,Operation{{$svrType}}{{.OriginalName}})
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.{{.Name}}(ctx, req.(*{{.Request}}))
})
out, err := h(ctx, &in)
if err != nil {
return err
}
reply := out.(*{{.Reply}})
return ctx.Result(200, reply{{.ResponseBody}})
}
}
{{end}}
type {{.ServiceType}}HTTPClient interface {
{{- range .MethodSets}}
{{.Name}}(ctx context.Context, req *{{.Request}}, opts ...http.CallOption) (rsp *{{.Reply}}, err error)
{{- end}}
}
type {{.ServiceType}}HTTPClientImpl struct{
cc *http.Client
}
func New{{.ServiceType}}HTTPClient (client *http.Client) {{.ServiceType}}HTTPClient {
return &{{.ServiceType}}HTTPClientImpl{client}
}
{{range .MethodSets}}
func (c *{{$svrType}}HTTPClientImpl) {{.Name}}(ctx context.Context, in *{{.Request}}, opts ...http.CallOption) (*{{.Reply}}, error) {
var out {{.Reply}}
pattern := "{{.Path}}"
path := binding.EncodeURL(pattern, in, {{not .HasBody}})
opts = append(opts, http.Operation(Operation{{$svrType}}{{.OriginalName}}))
opts = append(opts, http.PathTemplate(pattern))
{{if .HasBody -}}
err := c.cc.Invoke(ctx, "{{.Method}}", path, in{{.Body}}, &out{{.ResponseBody}}, opts...)
{{else -}}
err := c.cc.Invoke(ctx, "{{.Method}}", path, nil, &out{{.ResponseBody}}, opts...)
{{end -}}
if err != nil {
return nil, err
}
return &out, err
}
{{end}}

@ -9,9 +9,8 @@ import (
)
var (
showVersion = flag.Bool("version", false, "print the version and exit")
omitempty = flag.Bool("omitempty", true, "omit if google.api is empty")
omitemptyPrefix = flag.String("omitempty_prefix", "", "omit if google.api is empty")
showVersion = flag.Bool("version", false, "print the version and exit")
omitempty = flag.Bool("omitempty", true, "omit if google.api is empty")
)
func main() {
@ -28,7 +27,7 @@ func main() {
if !f.Generate {
continue
}
generateFile(gen, f, *omitempty, *omitemptyPrefix)
generateFile(gen, f, *omitempty)
}
return nil
})

@ -2,13 +2,102 @@ package main
import (
"bytes"
_ "embed"
"strings"
"text/template"
)
//go:embed httpTemplate.tpl
var httpTemplate string
var httpTemplate = `
{{$svrType := .ServiceType}}
{{$svrName := .ServiceName}}
{{- range .MethodSets}}
const Operation{{$svrType}}{{.OriginalName}} = "/{{$svrName}}/{{.OriginalName}}"
{{- end}}
type {{.ServiceType}}HTTPServer interface {
{{- range .MethodSets}}
{{.Name}}(context.Context, *{{.Request}}) (*{{.Reply}}, error)
{{- end}}
}
func Register{{.ServiceType}}HTTPServer(s *http.Server, srv {{.ServiceType}}HTTPServer) {
r := s.Route("/")
{{- range .Methods}}
r.{{.Method}}("{{.Path}}", _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv))
{{- end}}
}
{{range .Methods}}
func _{{$svrType}}_{{.Name}}{{.Num}}_HTTP_Handler(srv {{$svrType}}HTTPServer) func(ctx http.Context) error {
return func(ctx http.Context) error {
var in {{.Request}}
{{- if .HasBody}}
if err := ctx.Bind(&in{{.Body}}); err != nil {
return err
}
{{- if not (eq .Body "")}}
if err := ctx.BindQuery(&in); err != nil {
return err
}
{{- end}}
{{- else}}
if err := ctx.BindQuery(&in{{.Body}}); err != nil {
return err
}
{{- end}}
{{- if .HasVars}}
if err := ctx.BindVars(&in); err != nil {
return err
}
{{- end}}
http.SetOperation(ctx,Operation{{$svrType}}{{.OriginalName}})
h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.{{.Name}}(ctx, req.(*{{.Request}}))
})
out, err := h(ctx, &in)
if err != nil {
return err
}
reply := out.(*{{.Reply}})
return ctx.Result(200, reply{{.ResponseBody}})
}
}
{{end}}
type {{.ServiceType}}HTTPClient interface {
{{- range .MethodSets}}
{{.Name}}(ctx context.Context, req *{{.Request}}, opts ...http.CallOption) (rsp *{{.Reply}}, err error)
{{- end}}
}
type {{.ServiceType}}HTTPClientImpl struct{
cc *http.Client
}
func New{{.ServiceType}}HTTPClient (client *http.Client) {{.ServiceType}}HTTPClient {
return &{{.ServiceType}}HTTPClientImpl{client}
}
{{range .MethodSets}}
func (c *{{$svrType}}HTTPClientImpl) {{.Name}}(ctx context.Context, in *{{.Request}}, opts ...http.CallOption) (*{{.Reply}}, error) {
var out {{.Reply}}
pattern := "{{.Path}}"
path := binding.EncodeURL(pattern, in, {{not .HasBody}})
opts = append(opts, http.Operation(Operation{{$svrType}}{{.OriginalName}}))
opts = append(opts, http.PathTemplate(pattern))
{{if .HasBody -}}
err := c.cc.Invoke(ctx, "{{.Method}}", path, in{{.Body}}, &out{{.ResponseBody}}, opts...)
{{else -}}
err := c.cc.Invoke(ctx, "{{.Method}}", path, nil, &out{{.ResponseBody}}, opts...)
{{end -}}
if err != nil {
return nil, err
}
return &out, err
}
{{end}}
`
type serviceDesc struct {
ServiceType string // Greeter
@ -25,7 +114,6 @@ type methodDesc struct {
Num int
Request string
Reply string
Comment string
// http_rule
Path string
Method string

@ -1,4 +1,4 @@
package main
// release is the current protoc-gen-go-http version.
const release = "v2.6.3"
const release = "v2.5.1"

@ -15,13 +15,13 @@ import (
"github.com/go-kratos/kratos/v2/log"
)
var _ Config = (*config)(nil)
var (
// ErrNotFound is key not found.
ErrNotFound = errors.New("key not found")
// ErrTypeAssert is type assert error.
ErrTypeAssert = errors.New("type assert error")
_ Config = (*config)(nil)
)
// Observer is config observer.
@ -44,7 +44,7 @@ type config struct {
watchers []Watcher
}
// New a config with options.
// New new a config with options.
func New(opts ...Option) Config {
o := options{
decoder: defaultDecoder,
@ -62,11 +62,11 @@ func New(opts ...Option) Config {
func (c *config) watch(w Watcher) {
for {
kvs, err := w.Next()
if errors.Is(err, context.Canceled) {
log.Infof("watcher's ctx cancel : %v", err)
return
}
if err != nil {
if errors.Is(err, context.Canceled) {
log.Infof("watcher's ctx cancel : %v", err)
return
}
time.Sleep(time.Second)
log.Errorf("failed to watch next config: %v", err)
continue

@ -2,6 +2,7 @@ package config
import (
"errors"
"reflect"
"testing"
)
@ -123,7 +124,7 @@ func TestConfig(t *testing.T) {
)
err = c.Close()
if err != nil {
t.Fatal(err)
t.Fatal("t is not nil")
}
jSource := newTestJSONSource(_testJSON)
@ -138,21 +139,21 @@ func TestConfig(t *testing.T) {
err = cf.Load()
if err != nil {
t.Fatal(err)
t.Fatal("t is not nil")
}
driver, err := cf.Value("data.database.driver").String()
val, err := cf.Value("data.database.driver").String()
if err != nil {
t.Fatal(err)
t.Fatal("t is not nil")
}
if databaseDriver != driver {
t.Fatal("databaseDriver is not equal to val")
if !reflect.DeepEqual(databaseDriver, val) {
t.Fatal(`databaseDriver is not equal to val`)
}
err = cf.Watch("endpoints", func(key string, value Value) {
})
if err != nil {
t.Fatal(err)
t.Fatal("t is not nil")
}
jSource.sig <- struct{}{}
@ -161,24 +162,24 @@ func TestConfig(t *testing.T) {
var testConf testConfigStruct
err = cf.Scan(&testConf)
if err != nil {
t.Fatal(err)
t.Fatal("t is not nil")
}
if httpAddr != testConf.Server.HTTP.Addr {
t.Errorf("testConf.Server.HTTP.Addr want: %s, got: %s", httpAddr, testConf.Server.HTTP.Addr)
if !reflect.DeepEqual(httpAddr, testConf.Server.HTTP.Addr) {
t.Fatal(`httpAddr is not equal to testConf.Server.HTTP.Addr`)
}
if httpTimeout != testConf.Server.HTTP.Timeout {
t.Errorf("testConf.Server.HTTP.Timeout want: %.1f, got: %.1f", httpTimeout, testConf.Server.HTTP.Timeout)
if !reflect.DeepEqual(httpTimeout, testConf.Server.HTTP.Timeout) {
t.Fatal(`httpTimeout is not equal to testConf.Server.HTTP.Timeout`)
}
if !testConf.Server.HTTP.EnableSSL {
t.Error("testConf.Server.HTTP.EnableSSL is not equal to true")
if !reflect.DeepEqual(true, testConf.Server.HTTP.EnableSSL) {
t.Fatal(`testConf.Server.HTTP.EnableSSL is not equal to true`)
}
if grpcPort != testConf.Server.GRPC.Port {
t.Errorf("testConf.Server.GRPC.Port want: %d, got: %d", grpcPort, testConf.Server.GRPC.Port)
if !reflect.DeepEqual(grpcPort, testConf.Server.GRPC.Port) {
t.Fatal(`grpcPort is not equal to testConf.Server.GRPC.Port`)
}
if endpoint1 != testConf.Endpoints[0] {
t.Errorf("testConf.Endpoints[0] want: %s, got: %s", endpoint1, testConf.Endpoints[0])
if !reflect.DeepEqual(endpoint1, testConf.Endpoints[0]) {
t.Fatal(`endpoint1 is not equal to testConf.Endpoints[0]`)
}
if len(testConf.Endpoints) != 2 {
t.Error("len(testConf.Endpoints) is not equal to 2")
if !reflect.DeepEqual(len(testConf.Endpoints), 2) {
t.Fatal(`len(testConf.Endpoints) is not equal to 2`)
}
}

6
config/env/env.go vendored

@ -19,11 +19,11 @@ func (e *env) Load() (kv []*config.KeyValue, err error) {
return e.load(os.Environ()), nil
}
func (e *env) load(envs []string) []*config.KeyValue {
func (e *env) load(envStrings []string) []*config.KeyValue {
var kv []*config.KeyValue
for _, env := range envs {
for _, envstr := range envStrings {
var k, v string
subs := strings.SplitN(env, "=", 2) //nolint:gomnd
subs := strings.SplitN(envstr, "=", 2) //nolint:gomnd
k = subs[0]
if len(subs) > 1 {
v = subs[1]

@ -6,13 +6,13 @@ import (
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Watcher = (*watcher)(nil)
type watcher struct {
ctx context.Context
cancel context.CancelFunc
}
var _ config.Watcher = (*watcher)(nil)
func NewWatcher() (config.Watcher, error) {
ctx, cancel := context.WithCancel(context.Background())
return &watcher{ctx: ctx, cancel: cancel}, nil

@ -121,10 +121,10 @@ func testWatchFile(t *testing.T, path string) {
}
kvs, err := watch.Next()
if err != nil {
t.Errorf("watch.Next() error(%v)", err)
t.Errorf(`watch.Next() error(%v)`, err)
}
if !reflect.DeepEqual(string(kvs[0].Value), _testJSONUpdate) {
t.Errorf("string(kvs[0].Value(%v) is not equal to _testJSONUpdate(%v)", kvs[0].Value, _testJSONUpdate)
t.Errorf(`string(kvs[0].Value(%v) is not equal to _testJSONUpdate(%v)`, kvs[0].Value, _testJSONUpdate)
}
newFilepath := filepath.Join(filepath.Dir(path), "test1.json")
@ -133,15 +133,15 @@ func testWatchFile(t *testing.T, path string) {
}
kvs, err = watch.Next()
if err == nil {
t.Errorf("watch.Next() error(%v)", err)
t.Errorf(`watch.Next() error(%v)`, err)
}
if kvs != nil {
t.Errorf("watch.Next() error(%v)", err)
t.Errorf(`watch.Next() error(%v)`, err)
}
err = watch.Stop()
if err != nil {
t.Errorf("watch.Stop() error(%v)", err)
t.Errorf(`watch.Stop() error(%v)`, err)
}
if err := os.Rename(newFilepath, path); err != nil {
@ -171,10 +171,10 @@ func testWatchDir(t *testing.T, path, file string) {
kvs, err := watch.Next()
if err != nil {
t.Errorf("watch.Next() error(%v)", err)
t.Errorf(`watch.Next() error(%v)`, err)
}
if !reflect.DeepEqual(string(kvs[0].Value), _testJSONUpdate) {
t.Errorf("string(kvs[0].Value(%s) is not equal to _testJSONUpdate(%v)", kvs[0].Value, _testJSONUpdate)
t.Errorf(`string(kvs[0].Value(%v) is not equal to _testJSONUpdate(%v)`, kvs[0].Value, _testJSONUpdate)
}
}

@ -1,8 +1,6 @@
package file
import (
"testing"
)
import "testing"
func TestFormat(t *testing.T) {
tests := []struct {

@ -10,8 +10,6 @@ import (
"github.com/go-kratos/kratos/v2/config"
)
var _ config.Watcher = (*watcher)(nil)
type watcher struct {
f *file
fw *fsnotify.Watcher
@ -20,6 +18,8 @@ type watcher struct {
cancel context.CancelFunc
}
var _ config.Watcher = (*watcher)(nil)
func newWatcher(f *file) (config.Watcher, error) {
fw, err := fsnotify.NewWatcher()
if err != nil {

@ -51,7 +51,7 @@ func WithResolver(r Resolver) Option {
// WithLogger with config logger.
// Deprecated: use global logger instead.
func WithLogger(_ log.Logger) Option {
func WithLogger(l log.Logger) Option {
return func(o *options) {}
}

@ -15,7 +15,7 @@ func TestDefaultDecoder(t *testing.T) {
target := make(map[string]interface{})
err := defaultDecoder(src, target)
if err != nil {
t.Fatal(err)
t.Fatal("err is not nil")
}
if !reflect.DeepEqual(target, map[string]interface{}{"service": []byte("config")}) {
t.Fatal(`target is not equal to map[string]interface{}{"service": "config"}`)
@ -29,7 +29,7 @@ func TestDefaultDecoder(t *testing.T) {
target = make(map[string]interface{})
err = defaultDecoder(src, target)
if err != nil {
t.Fatal(err)
t.Fatal("err is not nil")
}
if !reflect.DeepEqual(map[string]interface{}{
"service": map[string]interface{}{
@ -150,7 +150,7 @@ func TestDefaultResolver(t *testing.T) {
t.Run(test.name, func(t *testing.T) {
err := defaultResolver(data)
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
rd := reader{
values: data,
@ -161,25 +161,25 @@ func TestDefaultResolver(t *testing.T) {
case int:
if actual, err = v.Int(); err == nil {
if !reflect.DeepEqual(test.expect.(int), int(actual.(int64))) {
t.Fatal("expect is not equal to actual")
t.Fatal(`expect is not equal to actual`)
}
}
case string:
if actual, err = v.String(); err == nil {
if !reflect.DeepEqual(test.expect, actual) {
t.Fatal("expect is not equal to actual")
t.Fatal(`expect is not equal to actual`)
}
}
case bool:
if actual, err = v.Bool(); err == nil {
if !reflect.DeepEqual(test.expect, actual) {
t.Fatal("expect is not equal to actual")
t.Fatal(`expect is not equal to actual`)
}
}
case float64:
if actual, err = v.Float(); err == nil {
if !reflect.DeepEqual(test.expect, actual) {
t.Fatal("expect is not equal to actual")
t.Fatal(`expect is not equal to actual`)
}
}
default:

@ -8,11 +8,11 @@ import (
"strings"
"sync"
"github.com/go-kratos/kratos/v2/log"
"github.com/imdario/mergo"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"github.com/go-kratos/kratos/v2/log"
)
// Reader is config reader.
@ -38,7 +38,9 @@ func newReader(opts options) Reader {
}
func (r *reader) Merge(kvs ...*KeyValue) error {
merged, err := r.cloneMap()
r.lock.Lock()
merged, err := cloneMap(r.values)
r.lock.Unlock()
if err != nil {
return err
}
@ -77,12 +79,6 @@ func (r *reader) Resolve() error {
return r.opts.resolver(r.values)
}
func (r *reader) cloneMap() (map[string]interface{}, error) {
r.lock.Lock()
defer r.lock.Unlock()
return cloneMap(r.values)
}
func cloneMap(src map[string]interface{}) (map[string]interface{}, error) {
// https://gist.github.com/soroushjp/0ec92102641ddfc3ad5515ca76405f4d
var buf bytes.Buffer
@ -94,12 +90,12 @@ func cloneMap(src map[string]interface{}) (map[string]interface{}, error) {
if err != nil {
return nil, err
}
var clone map[string]interface{}
err = dec.Decode(&clone)
var copy map[string]interface{}
err = dec.Decode(&copy)
if err != nil {
return nil, err
}
return clone, nil
return copy, nil
}
func convertMap(src interface{}) interface{} {

@ -29,7 +29,7 @@ func TestReader_Merge(t *testing.T) {
Format: "json",
})
if err == nil {
t.Fatal("err is nil")
t.Fatal(`err is nil`)
}
err = r.Merge(&KeyValue{
@ -38,15 +38,15 @@ func TestReader_Merge(t *testing.T) {
Format: "json",
})
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
vv, ok := r.Value("nice")
if !ok {
t.Fatal("ok is false")
t.Fatal(`ok is false`)
}
vvv, err := vv.String()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if vvv != "boat" {
t.Fatal(`vvv is not equal to "boat"`)
@ -58,18 +58,18 @@ func TestReader_Merge(t *testing.T) {
Format: "json",
})
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
vv, ok = r.Value("x")
if !ok {
t.Fatal("ok is false")
t.Fatal(`ok is false`)
}
vvx, err := vv.Int()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if vvx != 2 {
t.Fatal("vvx is not equal to 2")
if int64(2) != vvx {
t.Fatal(`vvx is not equal to 2`)
}
}
@ -118,27 +118,27 @@ a:
r := newReader(opts)
err := r.Merge(&test.kv)
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
vv, ok := r.Value("a.b.X")
if !ok {
t.Fatal("ok is false")
t.Fatal(`ok is false`)
}
vvv, err := vv.Int()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if int64(1) != vvv {
t.Fatal("vvv is not equal to 1")
t.Fatal(`vvv is not equal to 1`)
}
vv, ok = r.Value("a.b.Y")
if !ok {
t.Fatal("ok is false")
t.Fatal(`ok is false`)
}
vvy, err := vv.String()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if vvy != "lol" {
t.Fatal(`vvy is not equal to "lol"`)
@ -146,29 +146,29 @@ a:
vv, ok = r.Value("a.b.z")
if !ok {
t.Fatal("ok is false")
t.Fatal(`ok is false`)
}
vvz, err := vv.Bool()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if !vvz {
t.Fatal("vvz is not equal to true")
t.Fatal(`vvz is not equal to true`)
}
_, ok = r.Value("aasasdg=234l.asdfk,")
if ok {
t.Fatal("ok is true")
t.Fatal(`ok is true`)
}
_, ok = r.Value("aas......asdg=234l.asdfk,")
if ok {
t.Fatal("ok is true")
t.Fatal(`ok is true`)
}
_, ok = r.Value("a.b.Y.")
if ok {
t.Fatal("ok is true")
t.Fatal(`ok is true`)
}
})
}
@ -192,11 +192,11 @@ func TestReader_Source(t *testing.T) {
Format: "json",
})
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
b, err := r.Source()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if !reflect.DeepEqual([]byte(`{"a":{"b":{"X":1}}}`), b) {
t.Fatal("[]byte(`{\"a\":{\"b\":{\"X\":1}}}`) is not equal to b")

@ -1,7 +1,7 @@
package config
import (
"encoding/json"
stdjson "encoding/json"
"fmt"
"reflect"
"strconv"
@ -10,7 +10,7 @@ import (
"google.golang.org/protobuf/proto"
kratosjson "github.com/go-kratos/kratos/v2/encoding/json"
"github.com/go-kratos/kratos/v2/encoding/json"
)
var (
@ -36,10 +36,6 @@ type atomicValue struct {
atomic.Value
}
func (v *atomicValue) typeAssertError() error {
return fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Bool() (bool, error) {
switch val := v.Load().(type) {
case bool:
@ -47,7 +43,7 @@ func (v *atomicValue) Bool() (bool, error) {
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, float32, float64, string:
return strconv.ParseBool(fmt.Sprint(val))
}
return false, v.typeAssertError()
return false, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Int() (int64, error) {
@ -77,37 +73,35 @@ func (v *atomicValue) Int() (int64, error) {
case float64:
return int64(val), nil
case string:
return strconv.ParseInt(val, 10, 64)
return strconv.ParseInt(val, 10, 64) //nolint:gomnd
}
return 0, v.typeAssertError()
return 0, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Slice() ([]Value, error) {
vals, ok := v.Load().([]interface{})
if !ok {
return nil, v.typeAssertError()
if vals, ok := v.Load().([]interface{}); ok {
var slices []Value
for _, val := range vals {
a := &atomicValue{}
a.Store(val)
slices = append(slices, a)
}
return slices, nil
}
slices := make([]Value, 0, len(vals))
for _, val := range vals {
a := new(atomicValue)
a.Store(val)
slices = append(slices, a)
}
return slices, nil
return nil, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Map() (map[string]Value, error) {
vals, ok := v.Load().(map[string]interface{})
if !ok {
return nil, v.typeAssertError()
}
m := make(map[string]Value, len(vals))
for key, val := range vals {
a := new(atomicValue)
a.Store(val)
m[key] = a
if vals, ok := v.Load().(map[string]interface{}); ok {
m := make(map[string]Value, len(vals))
for key, val := range vals {
a := new(atomicValue)
a.Store(val)
m[key] = a
}
return m, nil
}
return m, nil
return nil, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Float() (float64, error) {
@ -137,9 +131,9 @@ func (v *atomicValue) Float() (float64, error) {
case float64:
return val, nil
case string:
return strconv.ParseFloat(val, 64)
return strconv.ParseFloat(val, 64) //nolint:gomnd
}
return 0.0, v.typeAssertError()
return 0.0, fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) String() (string, error) {
@ -153,7 +147,7 @@ func (v *atomicValue) String() (string, error) {
case fmt.Stringer:
return val.String(), nil
}
return "", v.typeAssertError()
return "", fmt.Errorf("type assert to %v failed", reflect.TypeOf(v.Load()))
}
func (v *atomicValue) Duration() (time.Duration, error) {
@ -165,14 +159,14 @@ func (v *atomicValue) Duration() (time.Duration, error) {
}
func (v *atomicValue) Scan(obj interface{}) error {
data, err := json.Marshal(v.Load())
data, err := stdjson.Marshal(v.Load())
if err != nil {
return err
}
if pb, ok := obj.(proto.Message); ok {
return kratosjson.UnmarshalOptions.Unmarshal(data, pb)
return json.UnmarshalOptions.Unmarshal(data, pb)
}
return json.Unmarshal(data, obj)
return stdjson.Unmarshal(data, obj)
}
type errValue struct {

@ -6,17 +6,17 @@ import (
"time"
)
func TestAtomicValue_Bool(t *testing.T) {
func Test_atomicValue_Bool(t *testing.T) {
vlist := []interface{}{"1", "t", "T", "true", "TRUE", "True", true, 1, int32(1)}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Bool()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if !b {
t.Fatal("b is not equal to true")
t.Fatal(`b is not equal to true`)
}
}
@ -26,10 +26,10 @@ func TestAtomicValue_Bool(t *testing.T) {
v.Store(x)
b, err := v.Bool()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b {
t.Fatal("b is not equal to false")
t.Fatal(`b is not equal to false`)
}
}
@ -39,22 +39,22 @@ func TestAtomicValue_Bool(t *testing.T) {
v.Store(x)
_, err := v.Bool()
if err == nil {
t.Fatal("err is nil")
t.Fatal(`err is nil`)
}
}
}
func TestAtomicValue_Int(t *testing.T) {
func Test_atomicValue_Int(t *testing.T) {
vlist := []interface{}{"123123", float64(123123), int64(123123), int32(123123), 123123}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Int()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != 123123 {
t.Fatal("b is not equal to 123123")
t.Fatal(`b is not equal to 123123`)
}
}
@ -64,22 +64,22 @@ func TestAtomicValue_Int(t *testing.T) {
v.Store(x)
_, err := v.Int()
if err == nil {
t.Fatal("err is nil")
t.Fatal(`err is nil`)
}
}
}
func TestAtomicValue_Float(t *testing.T) {
func Test_atomicValue_Float(t *testing.T) {
vlist := []interface{}{"123123.1", 123123.1}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Float()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != 123123.1 {
t.Fatal("b is not equal to 123123.1")
t.Fatal(`b is not equal to 123123.1`)
}
}
@ -89,7 +89,7 @@ func TestAtomicValue_Float(t *testing.T) {
v.Store(x)
_, err := v.Float()
if err == nil {
t.Fatal("err is nil")
t.Fatal(`err is nil`)
}
}
}
@ -103,17 +103,17 @@ func (t ts) String() string {
return fmt.Sprintf("%s%d", t.Name, t.Age)
}
func TestAtomicValue_String(t *testing.T) {
func Test_atomicValue_String(t *testing.T) {
vlist := []interface{}{"1", float64(1), int64(1), 1, int64(1)}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.String()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != "1" {
t.Fatal("b is not equal to 1")
t.Fatal(`b is not equal to 1`)
}
}
@ -121,7 +121,7 @@ func TestAtomicValue_String(t *testing.T) {
v.Store(true)
b, err := v.String()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != "true" {
t.Fatal(`b is not equal to "true"`)
@ -134,48 +134,48 @@ func TestAtomicValue_String(t *testing.T) {
})
b, err = v.String()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != "test10" {
t.Fatal(`b is not equal to "test10"`)
}
}
func TestAtomicValue_Duration(t *testing.T) {
func Test_atomicValue_Duration(t *testing.T) {
vlist := []interface{}{int64(5)}
for _, x := range vlist {
v := atomicValue{}
v.Store(x)
b, err := v.Duration()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != time.Duration(5) {
t.Fatal("b is not equal to time.Duration(5)")
t.Fatal(`b is not equal to time.Duration(5)`)
}
}
}
func TestAtomicValue_Slice(t *testing.T) {
func Test_atomicValue_Slice(t *testing.T) {
vlist := []interface{}{int64(5)}
v := atomicValue{}
v.Store(vlist)
slices, err := v.Slice()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
for _, v := range slices {
b, err := v.Duration()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != time.Duration(5) {
t.Fatal("b is not equal to time.Duration(5)")
t.Fatal(`b is not equal to time.Duration(5)`)
}
}
}
func TestAtomicValue_Map(t *testing.T) {
func Test_atomicValue_Map(t *testing.T) {
vlist := make(map[string]interface{})
vlist["5"] = int64(5)
vlist["text"] = "text"
@ -183,21 +183,21 @@ func TestAtomicValue_Map(t *testing.T) {
v.Store(vlist)
m, err := v.Map()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
for k, v := range m {
if k == "5" {
b, err := v.Duration()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != time.Duration(5) {
t.Fatal("b is not equal to time.Duration(5)")
t.Fatal(`b is not equal to time.Duration(5)`)
}
} else {
b, err := v.String()
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
if b != "text" {
t.Fatal(`b is not equal to "text"`)
@ -206,19 +206,20 @@ func TestAtomicValue_Map(t *testing.T) {
}
}
func TestAtomicValue_Scan(t *testing.T) {
func Test_atomicValue_Scan(t *testing.T) {
var err error
v := atomicValue{}
err := v.Scan(&struct {
err = v.Scan(&struct {
A string `json:"a"`
}{"a"})
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
err = v.Scan(&struct {
A string `json:"a"`
}{"a"})
if err != nil {
t.Fatal(err)
t.Fatal(`err is not nil`)
}
}

@ -97,4 +97,5 @@ config := map[string]interface{}{
}
}
}
_ = config
```

@ -3,14 +3,15 @@ package apollo
import (
"strings"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4"
"github.com/apolloconfig/agollo/v4/constant"
apolloconfig "github.com/apolloconfig/agollo/v4/env/config"
apolloConfig "github.com/apolloconfig/agollo/v4/env/config"
"github.com/apolloconfig/agollo/v4/extension"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
)
type apollo struct {
@ -25,8 +26,6 @@ const (
properties = "properties"
)
var formats map[string]struct{}
// Option is apollo option
type Option func(*options)
@ -112,8 +111,8 @@ func NewSource(opts ...Option) config.Source {
for _, o := range opts {
o(&op)
}
client, err := agollo.StartWithConfig(func() (*apolloconfig.AppConfig, error) {
return &apolloconfig.AppConfig{
client, err := agollo.StartWithConfig(func() (*apolloConfig.AppConfig, error) {
return &apolloConfig.AppConfig{
AppID: op.appid,
Cluster: op.cluster,
NamespaceName: op.namespace,
@ -131,16 +130,10 @@ func NewSource(opts ...Option) config.Source {
func format(ns string) string {
arr := strings.Split(ns, ".")
suffix := arr[len(arr)-1]
if len(arr) <= 1 || suffix == properties {
if len(arr) <= 1 || arr[len(arr)-1] == properties {
return json
}
if _, ok := formats[suffix]; !ok {
// fallback
return json
}
return suffix
return arr[len(arr)-1]
}
func (e *apollo) load() []*config.KeyValue {
@ -157,7 +150,7 @@ func (e *apollo) load() []*config.KeyValue {
kvs = append(kvs, kv)
continue
}
if strings.Contains(ns, ".") && !strings.HasSuffix(ns, "."+properties) &&
if strings.Contains(ns, ".") && !strings.Contains(ns, properties) &&
(format(ns) == yaml || format(ns) == yml || format(ns) == json) {
kv, err := e.getOriginConfig(ns)
if err != nil {
@ -166,13 +159,14 @@ func (e *apollo) load() []*config.KeyValue {
}
kvs = append(kvs, kv)
continue
} else {
kv, err := e.getConfig(ns)
if err != nil {
log.Errorf("apollo get config failed,err:%v", err)
continue
}
kvs = append(kvs, kv)
}
kv, err := e.getConfig(ns)
if err != nil {
log.Errorf("apollo get config failed,err:%v", err)
continue
}
kvs = append(kvs, kv)
}
return kvs
}
@ -259,28 +253,16 @@ func resolve(key string, value interface{}, target map[string]interface{}) {
// eg: namespace.ext with subKey got namespace.subKey
func genKey(ns, sub string) string {
arr := strings.Split(ns, ".")
if len(arr) < 1 {
return sub
}
if len(arr) == 1 {
if ns == "" {
return sub
}
return ns + "." + sub
}
suffix := arr[len(arr)-1]
_, ok := formats[suffix]
if ok {
return strings.Join(arr[:len(arr)-1], ".") + "." + sub
}
return ns + "." + sub
}
func init() {
formats = make(map[string]struct{})
formats[yaml] = struct{}{}
formats[yml] = struct{}{}
formats[json] = struct{}{}
formats[properties] = struct{}{}
return strings.Join(arr[:len(arr)-1], ".") + "." + sub
}

@ -1,90 +0,0 @@
package apollo
import (
"testing"
)
func Test_genKey(t *testing.T) {
type args struct {
ns string
sub string
}
tests := []struct {
name string
args args
want string
}{
{
name: "blank namespace",
args: args{
ns: "",
sub: "x.y",
},
want: "x.y",
},
{
name: "properties namespace",
args: args{
ns: "application",
sub: "x.y",
},
want: "application.x.y",
},
{
name: "namespace with format",
args: args{
ns: "app.yaml",
sub: "x.y",
},
want: "app.x.y",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := genKey(tt.args.ns, tt.args.sub); got != tt.want {
t.Errorf("genKey() = %v, want %v", got, tt.want)
}
})
}
}
func Test_format(t *testing.T) {
tests := []struct {
name string
namespace string
want string
}{
{
name: "properties namespace",
namespace: "application",
want: "json",
},
{
name: "properties namespace #1",
namespace: "app.setting",
want: "json",
},
{
name: "namespace with format[yaml]",
namespace: "app.yaml",
want: "yaml",
},
{
name: "namespace with format[yml]",
namespace: "app.yml",
want: "yml",
},
{
name: "namespace with format[json]",
namespace: "app.json",
want: "json",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := format(tt.namespace); got != tt.want {
t.Errorf("format() = %v, want %v", got, tt.want)
}
})
}
}

@ -3,10 +3,13 @@ module github.com/go-kratos/kratos/contrib/config/apollo/v2
go 1.16
require (
github.com/apolloconfig/agollo/v4 v4.3.0
github.com/go-kratos/kratos/v2 v2.6.3
github.com/apolloconfig/agollo/v4 v4.2.0
github.com/go-kratos/kratos/v2 v2.4.0
)
require github.com/spf13/viper v1.11.0 // indirect
require (
github.com/spf13/viper v1.11.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -4,11 +4,12 @@ import (
"context"
"strings"
"github.com/apolloconfig/agollo/v4/storage"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/encoding"
"github.com/go-kratos/kratos/v2/log"
"github.com/apolloconfig/agollo/v4/storage"
)
type watcher struct {
@ -25,7 +26,7 @@ type customChangeListener struct {
func (c *customChangeListener) onChange(namespace string, changes map[string]*storage.ConfigChange) []*config.KeyValue {
kv := make([]*config.KeyValue, 0, 2)
if strings.Contains(namespace, ".") && !strings.HasSuffix(namespace, "."+properties) &&
if strings.Contains(namespace, ".") && !strings.Contains(namespace, properties) &&
(format(namespace) == yaml || format(namespace) == yml || format(namespace) == json) {
value, err := c.apollo.client.GetConfigCache(namespace).Get("content")
if err != nil {
@ -72,7 +73,7 @@ func (c *customChangeListener) OnChange(changeEvent *storage.ChangeEvent) {
c.in <- change
}
func (c *customChangeListener) OnNewestChange(_ *storage.FullChangeEvent) {}
func (c *customChangeListener) OnNewestChange(changeEvent *storage.FullChangeEvent) {}
func newWatcher(a *apollo) (config.Watcher, error) {
changeCh := make(chan []*config.KeyValue)

@ -2,21 +2,20 @@
```go
import (
"github.com/hashicorp/consul/api"
"github.com/go-kratos/kratos/contrib/config/consul/v2"
"github.com/hashicorp/consul/api"
)
func main() {
consulClient, err := api.NewClient(&api.Config{
Address: "127.0.0.1:8500",
Address: "127.0.0.1:8500",
})
if err != nil {
panic(err)
}
cs, err := consul.New(consulClient, consul.WithPath("app/cart/configs/"))
// consul中需要标注文件后缀,kratos读取配置需要适配文件后缀
// The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration.
//consul中需要标注文件后缀,kratos读取配置需要适配文件后缀
//The file suffix needs to be marked, and kratos needs to adapt the file suffix to read the configuration.
if err != nil {
panic(err)
}

@ -3,13 +3,8 @@ module github.com/go-kratos/kratos/contrib/config/consul/v2
go 1.15
require (
github.com/armon/go-metrics v0.3.10 // indirect
github.com/go-kratos/kratos/v2 v2.6.3
github.com/hashicorp/consul/api v1.20.0
github.com/hashicorp/go-hclog v0.14.1 // indirect
github.com/hashicorp/go-immutable-radix v1.3.0 // indirect
github.com/hashicorp/go-msgpack v0.5.5 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/go-kratos/kratos/v2 v2.4.0
github.com/hashicorp/consul/api v1.14.0
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -18,7 +18,7 @@ type watcher struct {
cancel context.CancelFunc
}
func (w *watcher) handle(_ uint64, data interface{}) {
func (w *watcher) handle(idx uint64, data interface{}) {
if data == nil {
return
}

@ -4,11 +4,10 @@
import (
"log"
clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc"
cfg "github.com/go-kratos/kratos/contrib/config/etcd/v2"
"github.com/go-kratos/kratos/v2/config"
clientv3 "go.etcd.io/etcd/client/v3"
"google.golang.org/grpc"
)
// create an etcd client
@ -31,16 +30,12 @@ if err != nil {
c := config.New(config.WithSource(source))
defer c.Close()
// load sources before get
if err := c.Load(); err != nil {
log.Fatalln(err)
}
// acquire config value
foo, err := c.Value("/app-config").String()
if err != nil {
log.Fatalln(err)
log.Println(err)
}
println(foo)
log.Println(foo)
```

@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/config/etcd/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
go.etcd.io/etcd/client/v3 v3.5.8
google.golang.org/grpc v1.56.1
github.com/go-kratos/kratos/v2 v2.4.0
go.etcd.io/etcd/client/v3 v3.5.4
google.golang.org/grpc v1.46.2
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -8,14 +8,14 @@ import (
"strings"
"testing"
"github.com/go-kratos/kratos/v2/config"
v1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"github.com/go-kratos/kratos/v2/config"
)
const (

@ -3,10 +3,10 @@ module github.com/go-kratos/kratos/contrib/config/kubernetes/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
k8s.io/api v0.26.3
k8s.io/apimachinery v0.26.3
k8s.io/client-go v0.26.3
github.com/go-kratos/kratos/v2 v2.4.0
k8s.io/api v0.24.3
k8s.io/apimachinery v0.24.3
k8s.io/client-go v0.24.3
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -2,10 +2,9 @@
```go
import (
kconfig "github.com/go-kratos/kratos/v2/config"
"github.com/nacos-group/nacos-sdk-go/clients"
"github.com/nacos-group/nacos-sdk-go/common/constant"
kconfig "github.com/go-kratos/kratos/v2/config"
)

@ -3,8 +3,9 @@ module github.com/go-kratos/kratos/contrib/config/nacos/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
github.com/go-kratos/kratos/v2 v2.4.0
github.com/nacos-group/nacos-sdk-go v1.0.9
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -2,23 +2,24 @@
```go
import (
"log"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/contrib/config/polaris/v2"
"log"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/contrib/config/polaris/v2"
)
func main() {
configApi, err := polaris.NewConfigAPI()
if err != nil {
log.Fatalln(err)
}
source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml"))
if err != nil {
log.Fatalln(err)
}
source.Load()
configApi, err := polaris.NewConfigAPI()
if err != nil {
log.Fatalln(err)
}
source, err := New(&configApi, WithNamespace("default"), WithFileGroup("default"), WithFileName("default.yaml"))
if err != nil {
log.Fatalln(err)
}
source.Load()
}
```

@ -6,9 +6,9 @@ import (
"path/filepath"
"strings"
"github.com/polarismesh/polaris-go"
"github.com/go-kratos/kratos/v2/config"
"github.com/polarismesh/polaris-go"
)
// Option is polaris config option.

@ -1,28 +1,26 @@
package polaris
package config
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"reflect"
"strings"
"testing"
"time"
"github.com/go-kratos/kratos/v2/config"
"github.com/polarismesh/polaris-go"
)
var (
testNamespace = "default"
testFileGroup = "test"
testOriginContent = `server:
namespace = "default"
fileGroup = "test"
originContent = `server:
port: 8080`
testUpdatedContent = `server:
updatedContent = `server:
port: 8090`
testCenterURL = "http://127.0.0.1:8090"
configCenterURL = "http://127.0.0.1:8090"
)
func makeJSONRequest(uri string, data string, method string, headers map[string]string) ([]byte, error) {
@ -59,7 +57,7 @@ type configClient struct {
}
func newConfigClient() (*configClient, error) {
token, err := getToken(testCenterURL)
token, err := getToken()
if err != nil {
return nil, err
}
@ -68,7 +66,7 @@ func newConfigClient() (*configClient, error) {
}, nil
}
func getToken(testCenterURL string) (string, error) {
func getToken() (string, error) {
data, err := json.Marshal(map[string]string{
"name": "polaris",
"password": "polaris",
@ -77,7 +75,7 @@ func getToken(testCenterURL string) (string, error) {
return "", err
}
// login use default user
res, err := makeJSONRequest(fmt.Sprintf("%s/core/v1/user/login", testCenterURL), string(data), http.MethodPost, map[string]string{})
res, err := makeJSONRequest(fmt.Sprintf("%s/core/v1/user/login", configCenterURL), string(data), http.MethodPost, map[string]string{})
if err != nil {
return "", nil
}
@ -91,16 +89,16 @@ func getToken(testCenterURL string) (string, error) {
func (client *configClient) createConfigFile(name string) error {
data, err := json.Marshal(map[string]string{
"name": name,
"namespace": testNamespace,
"group": testFileGroup,
"content": testOriginContent,
"namespace": namespace,
"group": fileGroup,
"content": originContent,
"modifyBy": "polaris",
"format": "yaml",
})
if err != nil {
return err
}
res, err := makeJSONRequest(fmt.Sprintf("%s/config/v1/configfiles", testCenterURL), string(data), http.MethodPost, map[string]string{
res, err := makeJSONRequest(fmt.Sprintf("%s/config/v1/configfiles", configCenterURL), string(data), http.MethodPost, map[string]string{
"X-Polaris-Token": client.token,
})
if err != nil {
@ -113,7 +111,7 @@ func (client *configClient) createConfigFile(name string) error {
return err
}
if resJSON.Code != 200000 {
return fmt.Errorf("create error, res: %s", string(res))
return errors.New("create error")
}
return nil
}
@ -121,16 +119,16 @@ func (client *configClient) createConfigFile(name string) error {
func (client *configClient) updateConfigFile(name string) error {
data, err := json.Marshal(map[string]string{
"name": name,
"namespace": testNamespace,
"group": testFileGroup,
"content": testUpdatedContent,
"namespace": namespace,
"group": fileGroup,
"content": updatedContent,
"modifyBy": "polaris",
"format": "yaml",
})
if err != nil {
return err
}
res, err := makeJSONRequest(fmt.Sprintf("%s/config/v1/configfiles", testCenterURL), string(data), http.MethodPut, map[string]string{
res, err := makeJSONRequest(fmt.Sprintf("%s/config/v1/configfiles", configCenterURL), string(data), http.MethodPut, map[string]string{
"X-Polaris-Token": client.token,
})
if err != nil {
@ -142,7 +140,7 @@ func (client *configClient) updateConfigFile(name string) error {
return err
}
if resJSON.Code != 200000 {
return fmt.Errorf("update error, res: %s", string(res))
return errors.New("update error")
}
return nil
}
@ -152,7 +150,7 @@ func (client *configClient) deleteConfigFile(name string) error {
if err != nil {
return err
}
url := fmt.Sprintf("%s/config/v1/configfiles?namespace=%s&group=%s&name=%s", testCenterURL, testNamespace, testFileGroup, name)
url := fmt.Sprintf("%s/config/v1/configfiles?namespace=%s&group=%s&name=%s", configCenterURL, namespace, fileGroup, name)
res, err := makeJSONRequest(url, string(data), http.MethodDelete, map[string]string{
"X-Polaris-Token": client.token,
})
@ -165,22 +163,22 @@ func (client *configClient) deleteConfigFile(name string) error {
return err
}
if resJSON.Code != 200000 {
return fmt.Errorf("delete error, res: %s", string(res))
return errors.New("delete error")
}
return nil
}
func (client *configClient) publishConfigFile(name string) error {
data, err := json.Marshal(map[string]string{
"namespace": testNamespace,
"group": testFileGroup,
"namespace": namespace,
"group": fileGroup,
"fileName": name,
"name": name,
})
if err != nil {
return err
}
res, err := makeJSONRequest(fmt.Sprintf("%s/config/v1/configfiles/release", testCenterURL), string(data), http.MethodPost, map[string]string{
res, err := makeJSONRequest(fmt.Sprintf("%s/config/v1/configfiles/release", configCenterURL), string(data), http.MethodPost, map[string]string{
"X-Polaris-Token": client.token,
})
if err != nil {
@ -192,35 +190,30 @@ func (client *configClient) publishConfigFile(name string) error {
return err
}
if resJSON.Code != 200000 {
return fmt.Errorf("publish error, res: %s", string(res))
return errors.New("publish error")
}
return nil
}
func TestConfig(t *testing.T) {
name := "kratos-polaris-test.yaml"
name := "test.yaml"
client, err := newConfigClient()
if err != nil {
t.Fatal(err)
}
_ = client.deleteConfigFile(name)
if err = client.createConfigFile(name); err != nil {
t.Fatal(err)
}
time.Sleep(5 * time.Second)
if err = client.publishConfigFile(name); err != nil {
t.Fatal(err)
}
time.Sleep(5 * time.Second)
// Always remember clear test resource
sdk, err := polaris.NewSDKContextByAddress("127.0.0.1:8091")
configAPI, err := polaris.NewConfigAPI()
if err != nil {
t.Fatal(err)
}
p := New(sdk)
config, err := p.Config(WithConfigFile(File{Name: name, Group: testFileGroup}))
config, err := New(configAPI, WithNamespace(namespace), WithFileGroup(fileGroup), WithFileName(name))
if err != nil {
t.Fatal(err)
}
@ -229,10 +222,7 @@ func TestConfig(t *testing.T) {
t.Fatal(err)
}
for _, value := range kv {
t.Logf("key: %s, value: %s", value.Key, value.Value)
}
if len(kv) != 1 || kv[0].Key != name || string(kv[0].Value) != testOriginContent {
if len(kv) != 1 || kv[0].Key != name || string(kv[0].Value) != originContent {
t.Fatal("config error")
}
@ -240,13 +230,18 @@ func TestConfig(t *testing.T) {
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
defer func() {
err = client.deleteConfigFile(name)
if err != nil {
t.Fatal(err)
}
})
if _, err = w.Next(); err != nil {
t.Fatal(err)
}
if err = w.Stop(); err != nil {
t.Fatal(err)
}
}()
if err = client.updateConfigFile(name); err != nil {
t.Fatal(err)
@ -260,22 +255,17 @@ func TestConfig(t *testing.T) {
t.Fatal(err)
}
for _, value := range kv {
t.Log(value.Key, string(value.Value))
}
if len(kv) != 1 || kv[0].Key != name || string(kv[0].Value) != testUpdatedContent {
if len(kv) != 1 || kv[0].Key != name || string(kv[0].Value) != updatedContent {
t.Fatal("config error")
}
}
func TestExtToFormat(t *testing.T) {
name := "kratos-polaris-ext.yaml"
name := "ext.yaml"
client, err := newConfigClient()
if err != nil {
t.Fatal(err)
}
_ = client.deleteConfigFile(name)
if err = client.createConfigFile(name); err != nil {
t.Fatal(err)
}
@ -284,24 +274,22 @@ func TestExtToFormat(t *testing.T) {
}
// Always remember clear test resource
t.Cleanup(func() {
defer func() {
if err = client.deleteConfigFile(name); err != nil {
t.Fatal(err)
}
})
}()
sdk, err := polaris.NewSDKContextByAddress("127.0.0.1:8091")
configAPI, err := polaris.NewConfigAPI()
if err != nil {
t.Fatal(err)
}
p := New(sdk)
cfg, err := p.Config(WithConfigFile(File{Name: name, Group: testFileGroup}))
config, err := New(configAPI, WithNamespace(namespace), WithFileGroup(fileGroup), WithFileName(name))
if err != nil {
t.Fatal(err)
}
kv, err := cfg.Load()
kv, err := config.Load()
if err != nil {
t.Fatal(err)
}
@ -311,76 +299,10 @@ func TestExtToFormat(t *testing.T) {
if !reflect.DeepEqual(name, kv[0].Key) {
t.Errorf("kvs[0].Key is %s", kv[0].Key)
}
if !reflect.DeepEqual(testOriginContent, string(kv[0].Value)) {
if !reflect.DeepEqual(originContent, string(kv[0].Value)) {
t.Errorf("kvs[0].Value is %s", kv[0].Value)
}
if !reflect.DeepEqual("yaml", kv[0].Format) {
t.Errorf("kvs[0].Format is %s", kv[0].Format)
}
}
func TestGetMultipleConfig(t *testing.T) {
client, err := newConfigClient()
files := make([]File, 0, 3)
for i := 0; i < 3; i++ {
name := fmt.Sprintf("kratos-polaris-test-%d.yaml", i)
if err != nil {
t.Fatal(err)
}
_ = client.deleteConfigFile(name)
if err = client.createConfigFile(name); err != nil {
t.Fatal(err)
}
if err = client.publishConfigFile(name); err != nil {
t.Fatal(err)
}
files = append(files, File{Name: name, Group: testFileGroup})
}
sdk, err := polaris.NewSDKContextByAddress("127.0.0.1:8091")
if err != nil {
t.Fatal(err)
}
p := New(sdk, WithNamespace("default"))
cfg, err := p.Config(WithConfigFile(files...))
if err != nil {
t.Fatal(err)
}
kvs, err := cfg.Load()
if err != nil {
t.Fatal(err)
}
for _, kv := range kvs {
t.Logf("key: %s, value: %s", kv.Key, kv.Value)
}
w, err := cfg.Watch()
if err != nil {
t.Fatal(err)
}
for _, file := range files {
if err = client.publishConfigFile(file.Name); err != nil {
t.Fatal(err)
}
kvs, err := w.Next()
if err != nil {
t.Fatal(err)
}
m := make(map[string]*config.KeyValue)
for _, kv := range kvs {
m[kv.Key] = kv
}
if !reflect.DeepEqual(file.Name, m[file.Name].Key) {
t.Errorf("m[file.Name].Key is %s", m[file.Name].Key)
}
if !reflect.DeepEqual(testOriginContent, string(m[file.Name].Value)) {
t.Errorf("m[file.Name].Value is %s", m[file.Name].Value)
}
if !reflect.DeepEqual("yaml", m[file.Name].Format) {
t.Errorf("m[file.Name].Format is %s", m[file.Name].Format)
}
}
}

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/polaris/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
github.com/go-kratos/kratos/v2 v2.4.0
github.com/polarismesh/polaris-go v1.1.0
)
@ -14,6 +14,10 @@ require (
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
go.uber.org/zap v1.21.0 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b // indirect
google.golang.org/genproto v0.0.0-20220628213854-d9e0b6570c03 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -5,11 +5,11 @@ import (
"path/filepath"
"strings"
"github.com/polarismesh/polaris-go"
"github.com/polarismesh/polaris-go/pkg/model"
"github.com/go-kratos/kratos/v2/config"
"github.com/go-kratos/kratos/v2/log"
"github.com/polarismesh/polaris-go"
"github.com/polarismesh/polaris-go/pkg/model"
)
type Watcher struct {
@ -28,7 +28,7 @@ func getFullPath(namespace string, fileGroup string, fileName string) string {
return fmt.Sprintf("%s/%s/%s", namespace, fileGroup, fileName)
}
func receive(event model.ConfigFileChangeEvent) {
func recieve(event model.ConfigFileChangeEvent) {
meta := event.ConfigFileMetadata
ec := eventChanMap[getFullPath(meta.GetNamespace(), meta.GetFileGroup(), meta.GetFileName())]
defer func() {
@ -42,7 +42,7 @@ func receive(event model.ConfigFileChangeEvent) {
}
func newWatcher(configFile polaris.ConfigFile) *Watcher {
configFile.AddChangeListener(receive)
configFile.AddChangeListener(recieve)
fullPath := getFullPath(configFile.GetNamespace(), configFile.GetFileGroup(), configFile.GetFileName())
if _, ok := eventChanMap[fullPath]; !ok {

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
github.com/go-kratos/kratos/v2 v2.5.1
github.com/vmihailenco/msgpack/v5 v5.3.5
)

File diff suppressed because it is too large Load Diff

@ -16,7 +16,6 @@ import (
// Logger see more detail https://github.com/aliyun/aliyun-log-go-sdk
type Logger interface {
log.Logger
GetProducer() *producer.Producer
Close() error
}
@ -82,16 +81,22 @@ func (a *aliyunLog) Close() error {
}
func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error {
contents := make([]*sls.LogContent, 0, len(keyvals)/2+1)
buf := level.String()
levelTitle := "level"
contents := make([]*sls.LogContent, 0)
contents = append(contents, &sls.LogContent{
Key: newString(level.Key()),
Value: newString(level.String()),
Key: &levelTitle,
Value: &buf,
})
for i := 0; i < len(keyvals); i += 2 {
key := toString(keyvals[i])
value := toString(keyvals[i+1])
contents = append(contents, &sls.LogContent{
Key: newString(toString(keyvals[i])),
Value: newString(toString(keyvals[i+1])),
Key: &key,
Value: &value,
})
}
@ -99,7 +104,9 @@ func (a *aliyunLog) Log(level log.Level, keyvals ...interface{}) error {
Time: proto.Uint32(uint32(time.Now().Unix())),
Contents: contents,
}
return a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst)
err := a.producer.SendLog(a.opts.project, a.opts.logstore, "", "", logInst)
return err
}
// NewAliyunLog new a aliyun logger with options.
@ -121,11 +128,6 @@ func NewAliyunLog(options ...Option) Logger {
}
}
// newString string convert to *string
func newString(s string) *string {
return &s
}
// toString convert any type to string
func toString(v interface{}) string {
var key string
@ -136,23 +138,23 @@ func toString(v interface{}) string {
case float64:
key = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
key = strconv.FormatFloat(float64(v), 'f', -1, 32)
key = strconv.FormatFloat(float64(v), 'f', -1, 64)
case int:
key = strconv.Itoa(v)
case uint:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int8:
key = strconv.Itoa(int(v))
case uint8:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int16:
key = strconv.Itoa(int(v))
case uint16:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int32:
key = strconv.Itoa(int(v))
case uint32:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int64:
key = strconv.FormatInt(v, 10)
case uint64:

@ -2,7 +2,6 @@ package aliyun
import (
"math"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/log"
@ -58,7 +57,7 @@ func TestWithAccessSecret(t *testing.T) {
}
}
func TestLogger(_ *testing.T) {
func TestLogger(t *testing.T) {
project := "foo"
logger := NewAliyunLog(WithProject(project))
defer logger.Close()
@ -100,45 +99,34 @@ func TestLog(t *testing.T) {
}
}
func TestNewString(t *testing.T) {
ptr := newString("")
if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr {
t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind)
}
}
func TestToString(t *testing.T) {
tests := []struct {
name string
in interface{}
out string
in interface{}
out string
}{
{"float64", 6.66, "6.66"},
{"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
{"float32", float32(6.66), "6.66"},
{"max float32", float32(math.MaxFloat32), "340282350000000000000000000000000000000"},
{"int", math.MaxInt64, "9223372036854775807"},
{"uint", uint(math.MaxUint64), "18446744073709551615"},
{"int8", int8(math.MaxInt8), "127"},
{"uint8", uint8(math.MaxUint8), "255"},
{"int16", int16(math.MaxInt16), "32767"},
{"uint16", uint16(math.MaxUint16), "65535"},
{"int32", int32(math.MaxInt32), "2147483647"},
{"uint32", uint32(math.MaxUint32), "4294967295"},
{"int64", int64(math.MaxInt64), "9223372036854775807"},
{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{"string", "abc", "abc"},
{"bool", false, "false"},
{"[]byte", []byte("abc"), "abc"},
{"struct", struct{ Name string }{}, `{"Name":""}`},
{"nil", nil, ""},
{math.MaxFloat64, "17976931348623157000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"000000000000000000000000000000000000000000000000000000000000000000000000000" +
"0000000000000000000000000000000"},
{math.MaxFloat32, "340282346638528860000000000000000000000"},
{1<<((32<<(^uint(0)>>63))-1) - 1, "9223372036854775807"},
{uint(1<<(32<<(^uint(0)>>63)) - 1), "-1"},
{math.MaxInt8, "127"},
{math.MaxUint8, "255"},
{math.MaxInt16, "32767"},
{math.MaxUint16, "65535"},
{math.MaxInt32, "2147483647"},
{math.MaxUint32, "4294967295"},
{math.MaxInt64, "9223372036854775807"},
{uint64(math.MaxUint64), "18446744073709551615"},
{"abc", "abc"},
{false, "false"},
{[]byte("abc"), "abc"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
out := toString(test.in)
if test.out != out {
t.Fatalf("want: %s, got: %s", test.out, out)
}
})
if toString(test.in) != test.out {
t.Fatalf("want: %s, got: %s", test.out, toString(test.in))
}
}
}

@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/log/aliyun/v2
go 1.16
require (
github.com/aliyun/aliyun-log-go-sdk v0.1.44
github.com/go-kratos/kratos/v2 v2.6.3
google.golang.org/protobuf v1.31.0
github.com/aliyun/aliyun-log-go-sdk v0.1.37
github.com/go-kratos/kratos/v2 v2.5.1
google.golang.org/protobuf v1.28.1
)
replace (

File diff suppressed because it is too large Load Diff

@ -11,23 +11,18 @@ import (
)
func TestMain(m *testing.M) {
listener := func(ln net.Listener) {
conn, err := ln.Accept()
if err != nil {
return
}
defer conn.Close()
_, err = io.ReadAll(conn)
if err != nil {
return
}
}
if ln, err := net.Listen("tcp", ":24224"); err == nil {
defer ln.Close()
go func() {
for {
listener(ln)
conn, err := ln.Accept()
if err != nil {
return
}
defer conn.Close()
if _, err = io.ReadAll(conn); err != nil {
continue
}
}
}()
}

@ -5,7 +5,8 @@ go 1.16
require (
github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 // indirect
github.com/fluent/fluent-logger-golang v1.9.0
github.com/go-kratos/kratos/v2 v2.6.3
github.com/go-kratos/kratos/v2 v2.5.1
github.com/kr/pretty v0.3.0 // indirect
github.com/tinylib/msgp v1.1.6 // indirect
)

File diff suppressed because it is too large Load Diff

@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/logrus/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
github.com/go-kratos/kratos/v2 v2.5.1
github.com/sirupsen/logrus v1.8.1
)

File diff suppressed because it is too large Load Diff

@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2
go 1.16
require (
github.com/go-kratos/kratos/v2 v2.6.3
github.com/go-kratos/kratos/v2 v2.5.1
github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2
google.golang.org/protobuf v1.31.0
google.golang.org/protobuf v1.28.0
)
replace github.com/go-kratos/kratos/v2 => ../../../

File diff suppressed because it is too large Load Diff

@ -14,8 +14,8 @@ import (
type Logger interface {
log.Logger
GetProducer() *cls.AsyncProducerClient
Close() error
}
@ -66,20 +66,25 @@ func WithAccessSecret(as string) Option {
type Option func(cls *options)
func (log *tencentLog) Close() error {
return log.producer.Close(5000)
err := log.producer.Close(5000)
return err
}
func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error {
contents := make([]*cls.Log_Content, 0, len(keyvals)/2+1)
buf := level.String()
levelTitle := "level"
contents := make([]*cls.Log_Content, 0)
contents = append(contents, &cls.Log_Content{
Key: newString(level.Key()),
Value: newString(level.String()),
Key: &levelTitle,
Value: &buf,
})
for i := 0; i < len(keyvals); i += 2 {
key := toString(keyvals[i])
value := toString(keyvals[i+1])
contents = append(contents, &cls.Log_Content{
Key: newString(toString(keyvals[i])),
Value: newString(toString(keyvals[i+1])),
Key: &key,
Value: &value,
})
}
@ -87,7 +92,8 @@ func (log *tencentLog) Log(level log.Level, keyvals ...interface{}) error {
Time: proto.Int64(time.Now().Unix()),
Contents: contents,
}
return log.producer.SendLog(log.opts.topicID, logInst, nil)
err := log.producer.SendLog(log.opts.topicID, logInst, nil)
return err
}
func NewLogger(options ...Option) (Logger, error) {
@ -103,17 +109,12 @@ func NewLogger(options ...Option) (Logger, error) {
if err != nil {
return nil, err
}
producerInst.Start()
return &tencentLog{
producer: producerInst,
opts: opts,
}, nil
}
func newString(s string) *string {
return &s
}
// toString convert any type to string
func toString(v interface{}) string {
var key string
@ -124,23 +125,23 @@ func toString(v interface{}) string {
case float64:
key = strconv.FormatFloat(v, 'f', -1, 64)
case float32:
key = strconv.FormatFloat(float64(v), 'f', -1, 32)
key = strconv.FormatFloat(float64(v), 'f', -1, 64)
case int:
key = strconv.Itoa(v)
case uint:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int8:
key = strconv.Itoa(int(v))
case uint8:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int16:
key = strconv.Itoa(int(v))
case uint16:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int32:
key = strconv.Itoa(int(v))
case uint32:
key = strconv.FormatUint(uint64(v), 10)
key = strconv.Itoa(int(v))
case int64:
key = strconv.FormatInt(v, 10)
case uint64:

@ -1,8 +1,6 @@
package tencent
import (
"math"
"reflect"
"testing"
"github.com/go-kratos/kratos/v2/log"
@ -103,46 +101,3 @@ func TestLog(t *testing.T) {
t.Errorf("Log() returns error:%v", err)
}
}
func TestNewString(t *testing.T) {
ptr := newString("")
if kind := reflect.TypeOf(ptr).Kind(); kind != reflect.Ptr {
t.Errorf("want type: %v, got type: %v", reflect.Ptr, kind)
}
}
func TestToString(t *testing.T) {
tests := []struct {
name string
in interface{}
out string
}{
{"float64", 6.66, "6.66"},
{"max float64", math.MaxFloat64, "179769313486231570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"}, //nolint:lll
{"float32", float32(6.66), "6.66"},
{"max float32", float32(math.MaxFloat32), "340282350000000000000000000000000000000"},
{"int", math.MaxInt64, "9223372036854775807"},
{"uint", uint(math.MaxUint64), "18446744073709551615"},
{"int8", int8(math.MaxInt8), "127"},
{"uint8", uint8(math.MaxUint8), "255"},
{"int16", int16(math.MaxInt16), "32767"},
{"uint16", uint16(math.MaxUint16), "65535"},
{"int32", int32(math.MaxInt32), "2147483647"},
{"uint32", uint32(math.MaxUint32), "4294967295"},
{"int64", int64(math.MaxInt64), "9223372036854775807"},
{"uint64", uint64(math.MaxUint64), "18446744073709551615"},
{"string", "abc", "abc"},
{"bool", false, "false"},
{"[]byte", []byte("abc"), "abc"},
{"struct", struct{ Name string }{}, `{"Name":""}`},
{"nil", nil, ""},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
out := toString(test.in)
if test.out != out {
t.Fatalf("want: %s, got: %s", test.out, out)
}
})
}
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save