mirror of
https://gitee.com/johng/gf
synced 2026-06-08 10:37:44 +08:00
Compare commits
40 Commits
v2.1.0-rc4
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
| 1ede8c77ba | |||
| 48f95d0009 | |||
| 0bb57b8989 | |||
| 0503c17867 | |||
| 19779cd342 | |||
| 141f3512a9 | |||
| 3b9e5c71bf | |||
| 2bcee014f7 | |||
| f0568b4e22 | |||
| 8670f29c4e | |||
| 33a528af76 | |||
| 52056644d4 | |||
| 3ae23df4b3 | |||
| 1b327b8abd | |||
| bb5cd3e224 | |||
| 1e8237446e | |||
| b2b2044786 | |||
| 64c5222623 | |||
| 1597291ac3 | |||
| c2e742335b | |||
| cf5884bc60 | |||
| cbf5ee9649 | |||
| 8ac177a6de | |||
| cdd4473df5 | |||
| aaebaa7250 | |||
| 7443a8baa1 | |||
| c6ff95a3f4 | |||
| 7957016ae2 | |||
| 17ab0e2ced | |||
| b0650f3402 | |||
| f4f73f2765 | |||
| babc69e13d | |||
| 481c50f233 | |||
| b62b2f3598 | |||
| 4f37abac6a | |||
| 31a23e724d | |||
| 7d5ab1f8db | |||
| 0d8952dcde | |||
| bd7ec5d0b0 | |||
| 9e6e8001ca |
2
.github/workflows/gf.yml
vendored
2
.github/workflows/gf.yml
vendored
@ -92,7 +92,7 @@ jobs:
|
||||
- 9001:9001
|
||||
|
||||
polaris:
|
||||
image: houseme/polaris-server-with-config:latest
|
||||
image: polarismesh/polaris-server-standalone:latest
|
||||
ports:
|
||||
- 8090:8090
|
||||
- 8091:8091
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@ -15,3 +15,5 @@ cbuild
|
||||
**/.DS_Store
|
||||
.test/
|
||||
cmd/gf/main
|
||||
cmd/gf/gf
|
||||
go.work
|
||||
|
||||
@ -3,11 +3,12 @@ module github.com/gogf/gf/cmd/gf/v2
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.0.6
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.0.6
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.0.6
|
||||
github.com/gogf/gf/v2 v2.0.6
|
||||
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.1.0
|
||||
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.1.0
|
||||
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.1.0
|
||||
github.com/gogf/gf/v2 v2.1.0
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
golang.org/x/tools v0.1.11
|
||||
)
|
||||
|
||||
replace (
|
||||
|
||||
@ -91,6 +91,7 @@ github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMT
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
|
||||
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
|
||||
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
|
||||
@ -100,17 +101,22 @@ go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
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/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
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-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -132,8 +138,10 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/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-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0=
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@ -141,12 +149,15 @@ golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9sn
|
||||
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.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2 h1:GLw7MR8AfAG2GmGcmVgObFOHXYypgGjnGno25RDwn3Y=
|
||||
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
|
||||
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.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
|
||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
||||
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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@ -206,11 +206,14 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
}
|
||||
packCmd := fmt.Sprintf(`gf pack %s %s`, in.PackSrc, in.PackDst)
|
||||
mlog.Print(packCmd)
|
||||
gproc.MustShellRun(packCmd)
|
||||
gproc.MustShellRun(ctx, packCmd)
|
||||
}
|
||||
|
||||
// Injected information by building flags.
|
||||
ldFlags := fmt.Sprintf(`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`, c.getBuildInVarStr(in))
|
||||
ldFlags := fmt.Sprintf(
|
||||
`-X 'github.com/gogf/gf/v2/os/gbuild.builtInVarStr=%v'`,
|
||||
c.getBuildInVarStr(ctx, in),
|
||||
)
|
||||
|
||||
// start building
|
||||
mlog.Print("start building...")
|
||||
@ -261,7 +264,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
|
||||
// It's not necessary printing the complete command string.
|
||||
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
|
||||
mlog.Print(cmdShow)
|
||||
if result, err := gproc.ShellExec(cmd); err != nil {
|
||||
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
|
||||
mlog.Printf(
|
||||
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
|
||||
system, arch, gstr.Trim(result),
|
||||
@ -287,12 +290,12 @@ buildDone:
|
||||
|
||||
// getBuildInVarMapJson retrieves and returns the custom build-in variables in configuration
|
||||
// file as json.
|
||||
func (c cBuild) getBuildInVarStr(in cBuildInput) string {
|
||||
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
|
||||
buildInVarMap := in.VarMap
|
||||
if buildInVarMap == nil {
|
||||
buildInVarMap = make(g.Map)
|
||||
}
|
||||
buildInVarMap["builtGit"] = c.getGitCommit()
|
||||
buildInVarMap["builtGit"] = c.getGitCommit(ctx)
|
||||
buildInVarMap["builtTime"] = gtime.Now().String()
|
||||
b, err := json.Marshal(buildInVarMap)
|
||||
if err != nil {
|
||||
@ -302,13 +305,13 @@ func (c cBuild) getBuildInVarStr(in cBuildInput) string {
|
||||
}
|
||||
|
||||
// getGitCommit retrieves and returns the latest git commit hash string if present.
|
||||
func (c cBuild) getGitCommit() string {
|
||||
func (c cBuild) getGitCommit(ctx context.Context) string {
|
||||
if gproc.SearchBinary("git") == "" {
|
||||
return ""
|
||||
}
|
||||
var (
|
||||
cmd = `git log -1 --format="%cd %H" --date=format:"%Y-%m-%d %H:%M:%S"`
|
||||
s, _ = gproc.ShellExec(cmd)
|
||||
s, _ = gproc.ShellExec(ctx, cmd)
|
||||
)
|
||||
mlog.Debug(cmd)
|
||||
if s != "" {
|
||||
|
||||
@ -88,14 +88,14 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
|
||||
// Binary build.
|
||||
in.Build += " --exit"
|
||||
if in.Main != "" {
|
||||
if err = gproc.ShellRun(fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
|
||||
if err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Shell executing.
|
||||
if in.Shell != "" && gfile.Exists(in.Shell) {
|
||||
if err = c.exeDockerShell(in.Shell); err != nil {
|
||||
if err = c.exeDockerShell(ctx, in.Shell); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -116,7 +116,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
|
||||
}
|
||||
for i, dockerTag := range dockerTags {
|
||||
if i > 0 {
|
||||
err = gproc.ShellRun(fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
|
||||
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker tag %s %s`, dockerTagBase, dockerTag))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -130,7 +130,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
|
||||
if in.Extra != "" {
|
||||
dockerBuildOptions = fmt.Sprintf(`%s %s`, dockerBuildOptions, in.Extra)
|
||||
}
|
||||
err = gproc.ShellRun(fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
|
||||
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker build -f %s . %s`, in.File, dockerBuildOptions))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -144,7 +144,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
|
||||
if dockerTag == "" {
|
||||
continue
|
||||
}
|
||||
err = gproc.ShellRun(fmt.Sprintf(`docker push %s`, dockerTag))
|
||||
err = gproc.ShellRun(ctx, fmt.Sprintf(`docker push %s`, dockerTag))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@ -152,10 +152,10 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
|
||||
return
|
||||
}
|
||||
|
||||
func (c cDocker) exeDockerShell(shellFilePath string) error {
|
||||
func (c cDocker) exeDockerShell(ctx context.Context, shellFilePath string) error {
|
||||
if gfile.ExtName(shellFilePath) == "sh" && runtime.GOOS == "windows" {
|
||||
mlog.Debugf(`ignore shell file "%s", as it cannot be run on windows system`, shellFilePath)
|
||||
return nil
|
||||
}
|
||||
return gproc.ShellRun(gfile.GetContents(shellFilePath))
|
||||
return gproc.ShellRun(ctx, gfile.GetContents(shellFilePath))
|
||||
}
|
||||
|
||||
@ -26,7 +26,7 @@ type cEnvInput struct {
|
||||
type cEnvOutput struct{}
|
||||
|
||||
func (c cEnv) Index(ctx context.Context, in cEnvInput) (out *cEnvOutput, err error) {
|
||||
result, err := gproc.ShellExec("go env")
|
||||
result, err := gproc.ShellExec(ctx, "go env")
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
|
||||
@ -11,6 +11,10 @@ var (
|
||||
|
||||
type cGen struct {
|
||||
g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"`
|
||||
cGenDao
|
||||
cGenPb
|
||||
cGenPbEntity
|
||||
cGenService
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@ -138,6 +138,7 @@ func init() {
|
||||
}
|
||||
|
||||
type (
|
||||
cGenDao struct{}
|
||||
cGenDaoInput struct {
|
||||
g.Meta `name:"dao" config:"{cGenDaoConfig}" usage:"{cGenDaoUsage}" brief:"{cGenDaoBrief}" eg:"{cGenDaoEg}" ad:"{cGenDaoAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenDaoBriefPath}" d:"internal"`
|
||||
@ -170,7 +171,7 @@ type (
|
||||
}
|
||||
)
|
||||
|
||||
func (c cGen) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) {
|
||||
func (c cGenDao) Dao(ctx context.Context, in cGenDaoInput) (out *cGenDaoOutput, err error) {
|
||||
if g.Cfg().Available(ctx) {
|
||||
v := g.Cfg().MustGet(ctx, cGenDaoConfig)
|
||||
if v.IsSlice() {
|
||||
|
||||
@ -13,13 +13,14 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
cGenPb struct{}
|
||||
cGenPbInput struct {
|
||||
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
|
||||
}
|
||||
cGenPbOutput struct{}
|
||||
)
|
||||
|
||||
func (c cGen) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
|
||||
func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
|
||||
// Necessary check.
|
||||
if gproc.SearchBinary("protoc") == "" {
|
||||
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`)
|
||||
@ -56,7 +57,7 @@ func (c cGen) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err er
|
||||
parsingCommand += " -I" + goPathSrc
|
||||
}
|
||||
mlog.Print(parsingCommand)
|
||||
if output, err := gproc.ShellExec(parsingCommand); err != nil {
|
||||
if output, err := gproc.ShellExec(ctx, parsingCommand); err != nil {
|
||||
mlog.Print(output)
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
|
||||
@ -19,6 +19,29 @@ import (
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
type (
|
||||
cGenPbEntity struct{}
|
||||
cGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
|
||||
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
|
||||
}
|
||||
cGenPbEntityOutput struct{}
|
||||
|
||||
cGenPbEntityInternalInput struct {
|
||||
cGenPbEntityInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
)
|
||||
|
||||
const (
|
||||
cGenPbEntityConfig = `gfcli.gen.pbentity`
|
||||
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
|
||||
@ -83,28 +106,6 @@ set it to "none" to ignore json tag generating.
|
||||
`
|
||||
)
|
||||
|
||||
type (
|
||||
cGenPbEntityInput struct {
|
||||
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
|
||||
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
|
||||
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
|
||||
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
|
||||
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
|
||||
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
|
||||
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
|
||||
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
|
||||
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
|
||||
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
|
||||
}
|
||||
cGenPbEntityOutput struct{}
|
||||
|
||||
cGenPbEntityInternalInput struct {
|
||||
cGenPbEntityInput
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
gtag.Sets(g.MapStrStr{
|
||||
`cGenPbEntityConfig`: cGenPbEntityConfig,
|
||||
@ -124,7 +125,7 @@ func init() {
|
||||
})
|
||||
}
|
||||
|
||||
func (c cGen) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
|
||||
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
|
||||
var (
|
||||
config = g.Cfg()
|
||||
)
|
||||
|
||||
@ -18,15 +18,16 @@ import (
|
||||
)
|
||||
|
||||
type (
|
||||
cGenService struct{}
|
||||
cGenServiceInput struct {
|
||||
g.Meta `name:"service" config:"gfcli.gen.service" brief:"parse struct and associated functions from packages to generate service go file"`
|
||||
SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"`
|
||||
DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"`
|
||||
WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"`
|
||||
StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\w+)" d:"s([A-Z]\\w+)"`
|
||||
Packages string `short:"p" name:"packages" brief:"produce go files only for given source packages, multiple packages joined with char ','"`
|
||||
ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"`
|
||||
OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"`
|
||||
SrcFolder string `short:"s" name:"srcFolder" brief:"source folder path to be parsed. default: internal/logic" d:"internal/logic"`
|
||||
DstFolder string `short:"d" name:"dstFolder" brief:"destination folder path storing automatically generated go files. default: internal/service" d:"internal/service"`
|
||||
WatchFile string `short:"w" name:"watchFile" brief:"used in file watcher, it generates service go files only if given file is under srcFolder"`
|
||||
StPattern string `short:"a" name:"stPattern" brief:"regular expression matching struct name for generating service. default: s([A-Z]\\\\w+)" d:"s([A-Z]\\w+)"`
|
||||
Packages []string `short:"p" name:"packages" brief:"produce go files only for given source packages"`
|
||||
ImportPrefix string `short:"i" name:"importPrefix" brief:"custom import prefix to calculate import path for generated importing go file of logic"`
|
||||
OverWrite bool `short:"o" name:"overwrite" brief:"overwrite service go files that already exist in generating folder. default: true" d:"true" orphan:"true"`
|
||||
}
|
||||
cGenServiceOutput struct{}
|
||||
)
|
||||
@ -35,7 +36,7 @@ const (
|
||||
genServiceFileLockSeconds = 10
|
||||
)
|
||||
|
||||
func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) {
|
||||
func (c cGenService) Service(ctx context.Context, in cGenServiceInput) (out *cGenServiceOutput, err error) {
|
||||
// File lock to avoid multiple processes.
|
||||
var (
|
||||
flockFilePath = gfile.Temp("gf.cli.gen.service.lock")
|
||||
@ -65,7 +66,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
)
|
||||
mlog.Debug("watchFileDir:", watchFileDir)
|
||||
mlog.Debug("logicFolderDir:", srcFolderDir)
|
||||
if !gstr.HasSuffix(srcFolderDir, in.SrcFolder) {
|
||||
if !gstr.HasSuffix(gstr.Replace(srcFolderDir, `\`, `/`), in.SrcFolder) {
|
||||
mlog.Printf(`ignore watch file "%s", not in source path "%s"`, in.WatchFile, in.SrcFolder)
|
||||
return
|
||||
}
|
||||
@ -79,7 +80,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
`%s gen service -packages=%s`,
|
||||
gfile.SelfName(), gfile.Basename(watchFileDir),
|
||||
)
|
||||
err = gproc.ShellRun(command)
|
||||
err = gproc.ShellRun(ctx, command)
|
||||
return
|
||||
}
|
||||
|
||||
@ -101,13 +102,12 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
}
|
||||
|
||||
var (
|
||||
isDirty bool
|
||||
files []string
|
||||
fileContent string
|
||||
matches [][]string
|
||||
importSrcPackages []string
|
||||
inputPackages = gstr.SplitAndTrim(in.Packages, ",")
|
||||
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder))
|
||||
isDirty bool
|
||||
files []string
|
||||
fileContent string
|
||||
initImportSrcPackages []string
|
||||
inputPackages = in.Packages
|
||||
dstPackageName = gstr.ToLower(gfile.Basename(in.DstFolder))
|
||||
)
|
||||
srcFolders, err := gfile.ScanDir(in.SrcFolder, "*", false)
|
||||
if err != nil {
|
||||
@ -125,56 +125,25 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
}
|
||||
var (
|
||||
// StructName => FunctionDefinitions
|
||||
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
|
||||
srcPkgInterfaceFuncArray *garray.StrArray
|
||||
ok bool
|
||||
srcPkgInterfaceMap = make(map[string]*garray.StrArray)
|
||||
srcImportedPackages = garray.NewSortedStrArray().SetUnique(true)
|
||||
ok bool
|
||||
)
|
||||
for _, file := range files {
|
||||
fileContent = gfile.GetContents(file)
|
||||
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
|
||||
// Calculate imported packages of source go files.
|
||||
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
funcReceiver = gstr.Trim(match[1])
|
||||
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
|
||||
functionHead = gstr.Trim(gstr.Replace(match[2], "\n", ""))
|
||||
)
|
||||
if len(receiverArray) > 1 {
|
||||
structName = receiverArray[1]
|
||||
} else {
|
||||
structName = receiverArray[0]
|
||||
}
|
||||
structName = gstr.Trim(structName, "*")
|
||||
|
||||
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
|
||||
functionHead = gstr.Replace(functionHead, `,)`, `)`)
|
||||
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
|
||||
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
|
||||
if !gstr.IsLetterUpper(functionHead[0]) {
|
||||
continue
|
||||
}
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
|
||||
srcPkgInterfaceMap[structName] = garray.NewStrArray()
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
|
||||
}
|
||||
// Remove package name calls of `dstPackageName` in produced codes.
|
||||
functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead)
|
||||
srcPkgInterfaceFuncArray.Append(functionHead)
|
||||
// Calculate functions and interfaces for service generating.
|
||||
err = c.calculateInterfaceFunctions(in, fileContent, srcPkgInterfaceMap, dstPackageName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
importSrcPackages = append(
|
||||
importSrcPackages,
|
||||
initImportSrcPackages = append(
|
||||
initImportSrcPackages,
|
||||
fmt.Sprintf(`%s/%s`, in.ImportPrefix, gfile.Basename(srcFolder)),
|
||||
)
|
||||
// Ignore source packages if input packages given.
|
||||
@ -186,7 +155,7 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
continue
|
||||
}
|
||||
// Generating go files for service.
|
||||
if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, dstPackageName); err != nil {
|
||||
if ok, err = c.generateServiceFiles(in, srcPkgInterfaceMap, srcImportedPackages.Slice(), dstPackageName); err != nil {
|
||||
return
|
||||
}
|
||||
if ok {
|
||||
@ -196,8 +165,8 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
|
||||
if isDirty {
|
||||
// Generate initialization go file.
|
||||
if len(importSrcPackages) > 0 {
|
||||
if err = c.generateInitializationFile(in, importSrcPackages); err != nil {
|
||||
if len(initImportSrcPackages) > 0 {
|
||||
if err = c.generateInitializationFile(in, initImportSrcPackages); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -218,13 +187,86 @@ func (c cGen) Service(ctx context.Context, in cGenServiceInput) (out *cGenServic
|
||||
return
|
||||
}
|
||||
|
||||
func (c cGen) generateServiceFiles(
|
||||
in cGenServiceInput, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string,
|
||||
func (c cGenService) calculateImportedPackages(fileContent string, srcImportedPackages *garray.SortedStrArray) (err error) {
|
||||
var match []string
|
||||
match, err = gregex.MatchString(`\s+import\s+\(([\s\S]+?)\)`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(match) < 2 {
|
||||
return nil
|
||||
}
|
||||
importPart := gstr.Trim(match[1])
|
||||
srcImportedPackages.Append(gstr.SplitAndTrim(importPart, "\n")...)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cGenService) calculateInterfaceFunctions(
|
||||
in cGenServiceInput, fileContent string, srcPkgInterfaceMap map[string]*garray.StrArray, dstPackageName string,
|
||||
) (err error) {
|
||||
var (
|
||||
ok bool
|
||||
matches [][]string
|
||||
srcPkgInterfaceFuncArray *garray.StrArray
|
||||
)
|
||||
matches, err = gregex.MatchAllString(`func \((.+?)\) ([\s\S]+?) {`, fileContent)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, match := range matches {
|
||||
var (
|
||||
structName string
|
||||
structMatch []string
|
||||
funcReceiver = gstr.Trim(match[1])
|
||||
receiverArray = gstr.SplitAndTrim(funcReceiver, " ")
|
||||
functionHead = gstr.Trim(gstr.Replace(match[2], "\n", ""))
|
||||
)
|
||||
if len(receiverArray) > 1 {
|
||||
structName = receiverArray[1]
|
||||
} else {
|
||||
structName = receiverArray[0]
|
||||
}
|
||||
structName = gstr.Trim(structName, "*")
|
||||
|
||||
// Xxx(\n ctx context.Context, req *v1.XxxReq,\n) -> Xxx(ctx context.Context, req *v1.XxxReq)
|
||||
functionHead = gstr.Replace(functionHead, `,)`, `)`)
|
||||
functionHead, _ = gregex.ReplaceString(`\(\s+`, `(`, functionHead)
|
||||
functionHead, _ = gregex.ReplaceString(`\s{2,}`, ` `, functionHead)
|
||||
if !gstr.IsLetterUpper(functionHead[0]) {
|
||||
continue
|
||||
}
|
||||
if structMatch, err = gregex.MatchString(in.StPattern, structName); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(structMatch) < 1 {
|
||||
continue
|
||||
}
|
||||
structName = gstr.CaseCamel(structMatch[1])
|
||||
if srcPkgInterfaceFuncArray, ok = srcPkgInterfaceMap[structName]; !ok {
|
||||
srcPkgInterfaceMap[structName] = garray.NewStrArray()
|
||||
srcPkgInterfaceFuncArray = srcPkgInterfaceMap[structName]
|
||||
}
|
||||
// Remove package name calls of `dstPackageName` in produced codes.
|
||||
functionHead, _ = gregex.ReplaceString(fmt.Sprintf(`\*{0,1}%s\.`, dstPackageName), ``, functionHead)
|
||||
srcPkgInterfaceFuncArray.Append(functionHead)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cGenService) generateServiceFiles(
|
||||
in cGenServiceInput,
|
||||
srcPkgInterfaceMap map[string]*garray.StrArray,
|
||||
srcImportedPackages []string,
|
||||
dstPackageName string,
|
||||
) (ok bool, err error) {
|
||||
srcImportedPackagesContent := fmt.Sprintf(
|
||||
"import (\n%s\n)", gstr.Join(srcImportedPackages, "\n"),
|
||||
)
|
||||
for structName, funcArray := range srcPkgInterfaceMap {
|
||||
var (
|
||||
filePath = gfile.Join(in.DstFolder, gstr.ToLower(structName)+".go")
|
||||
generatedContent = gstr.ReplaceByMap(consts.TemplateGenServiceContent, g.MapStrStr{
|
||||
"{Imports}": srcImportedPackagesContent,
|
||||
"{StructName}": structName,
|
||||
"{PackageName}": dstPackageName,
|
||||
"{FuncDefinition}": funcArray.Join("\n\t"),
|
||||
@ -250,7 +292,7 @@ func (c cGen) generateServiceFiles(
|
||||
}
|
||||
|
||||
// isToGenerateServiceGoFile checks and returns whether the service content dirty.
|
||||
func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool {
|
||||
func (c cGenService) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrArray) bool {
|
||||
if !utils.IsFileDoNotEdit(filePath) {
|
||||
mlog.Debugf(`ignore file as it is manually maintained: %s`, filePath)
|
||||
return false
|
||||
@ -280,7 +322,7 @@ func (c cGen) isToGenerateServiceGoFile(filePath string, funcArray *garray.StrAr
|
||||
return false
|
||||
}
|
||||
|
||||
func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) {
|
||||
func (c cGenService) generateInitializationFile(in cGenServiceInput, importSrcPackages []string) (err error) {
|
||||
var (
|
||||
srcPackageName = gstr.ToLower(gfile.Basename(in.SrcFolder))
|
||||
srcFilePath = gfile.Join(in.SrcFolder, srcPackageName+".go")
|
||||
@ -306,7 +348,7 @@ func (c cGen) generateInitializationFile(in cGenServiceInput, importSrcPackages
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c cGen) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) {
|
||||
func (c cGenService) replaceGeneratedServiceContentGFV2(in cGenServiceInput) (err error) {
|
||||
return gfile.ReplaceDirFunc(func(path, content string) string {
|
||||
if gstr.Contains(content, `"github.com/gogf/gf`) && !gstr.Contains(content, `"github.com/gogf/gf/v2`) {
|
||||
content = gstr.Replace(content, `"github.com/gogf/gf"`, `"github.com/gogf/gf/v2"`)
|
||||
|
||||
@ -10,6 +10,7 @@ import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/os/gres"
|
||||
"github.com/gogf/gf/v2/util/gtag"
|
||||
)
|
||||
@ -48,7 +49,8 @@ func init() {
|
||||
type cInitInput struct {
|
||||
g.Meta `name:"init"`
|
||||
Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"`
|
||||
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
|
||||
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
|
||||
Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
|
||||
}
|
||||
type cInitOutput struct{}
|
||||
|
||||
@ -89,6 +91,18 @@ func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err
|
||||
return
|
||||
}
|
||||
|
||||
// Update the GoFrame version.
|
||||
if in.Update {
|
||||
mlog.Print("update goframe...")
|
||||
updateCommand := `go get -u github.com/gogf/gf/v2@latest`
|
||||
if in.Name != "." {
|
||||
updateCommand = fmt.Sprintf(`cd %s && %s`, in.Name, updateCommand)
|
||||
}
|
||||
if err = gproc.ShellRun(ctx, updateCommand); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
mlog.Print("initialization done! ")
|
||||
if !in.Mono {
|
||||
enjoyCommand := `gf run main.go`
|
||||
|
||||
@ -99,17 +99,17 @@ func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err err
|
||||
gtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {
|
||||
defer dirty.Set(false)
|
||||
mlog.Printf(`go file changes: %s`, event.String())
|
||||
app.Run()
|
||||
app.Run(ctx)
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
go app.Run()
|
||||
go app.Run(ctx)
|
||||
select {}
|
||||
}
|
||||
|
||||
func (app *cRunApp) Run() {
|
||||
func (app *cRunApp) Run(ctx context.Context) {
|
||||
// Rebuild and run the codes.
|
||||
renamePath := ""
|
||||
mlog.Printf("build: %s", app.File)
|
||||
@ -132,7 +132,7 @@ func (app *cRunApp) Run() {
|
||||
app.File,
|
||||
)
|
||||
mlog.Print(buildCommand)
|
||||
result, err := gproc.ShellExec(buildCommand)
|
||||
result, err := gproc.ShellExec(ctx, buildCommand)
|
||||
if err != nil {
|
||||
mlog.Printf("build error: \n%s%s", result, err.Error())
|
||||
return
|
||||
@ -154,7 +154,7 @@ func (app *cRunApp) Run() {
|
||||
} else {
|
||||
process = gproc.NewProcessCmd(outputPath, gstr.SplitAndTrim(" ", app.Args))
|
||||
}
|
||||
if pid, err := process.Start(); err != nil {
|
||||
if pid, err := process.Start(ctx); err != nil {
|
||||
mlog.Printf("build running error: %s", err.Error())
|
||||
} else {
|
||||
mlog.Printf("build running pid: %d", pid)
|
||||
|
||||
@ -7,6 +7,8 @@ const TemplateGenServiceContent = `
|
||||
|
||||
package {PackageName}
|
||||
|
||||
{Imports}
|
||||
|
||||
type I{StructName} interface {
|
||||
{FuncDefinition}
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,51 +1,24 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"golang.org/x/tools/imports"
|
||||
)
|
||||
|
||||
var (
|
||||
gofmtPath = gproc.SearchBinaryPath("gofmt") // gofmtPath is the binary path of command `gofmt`.
|
||||
goimportsPath = gproc.SearchBinaryPath("goimports") // gofmtPath is the binary path of command `goimports`.
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Wraps the command binary path with char '"' if there's space char in the path.
|
||||
if gstr.Contains(gofmtPath, " ") {
|
||||
gofmtPath = fmt.Sprintf(`"%s"`, gofmtPath)
|
||||
}
|
||||
if gstr.Contains(goimportsPath, " ") {
|
||||
goimportsPath = fmt.Sprintf(`"%s"`, goimportsPath)
|
||||
}
|
||||
}
|
||||
|
||||
// GoFmt formats the source file using command `gofmt -w -s PATH`.
|
||||
// GoFmt formats the source file.
|
||||
func GoFmt(path string) {
|
||||
if gofmtPath == "" {
|
||||
mlog.Fatal(`command "gofmt" not found`)
|
||||
}
|
||||
var command = fmt.Sprintf(`%s -w %s`, gofmtPath, path)
|
||||
result, err := gproc.ShellExec(command)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`error executing command "%s": %s`, command, result)
|
||||
if err := pretty(path, true); err != nil {
|
||||
mlog.Fatalf(`error format "%s" go files: %v`, path, err)
|
||||
}
|
||||
}
|
||||
|
||||
// GoImports formats the source file using command `goimports -w PATH`.
|
||||
// GoImports adds or removes import statements as necessary for the source file.
|
||||
func GoImports(path string) {
|
||||
if goimportsPath == "" {
|
||||
mlog.Fatal(`command "goimports" not found`)
|
||||
}
|
||||
var command = fmt.Sprintf(`%s -w %s`, goimportsPath, path)
|
||||
result, err := gproc.ShellExec(command)
|
||||
if err != nil {
|
||||
mlog.Fatalf(`error executing command "%s": %s`, command, result)
|
||||
if err := pretty(path); err != nil {
|
||||
mlog.Fatalf(`error update "%s" go file imports: %v`, path, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,3 +29,31 @@ func IsFileDoNotEdit(filePath string) bool {
|
||||
}
|
||||
return gstr.Contains(gfile.GetContents(filePath), consts.DoNotEditKey)
|
||||
}
|
||||
|
||||
// pretty format go file and adds or removes import statements as necessary.
|
||||
func pretty(filePath string, formatOnly ...bool) error {
|
||||
var genOpt *imports.Options
|
||||
if len(formatOnly) > 0 {
|
||||
genOpt = &imports.Options{
|
||||
Comments: true,
|
||||
TabIndent: true,
|
||||
TabWidth: 8,
|
||||
FormatOnly: true,
|
||||
}
|
||||
}
|
||||
replaceFunc := func(path, content string) string {
|
||||
res, err := imports.Process(path, []byte(content), genOpt)
|
||||
if err != nil {
|
||||
mlog.Printf(`pretty go file "%s" failed: %v`, path, err)
|
||||
return content
|
||||
}
|
||||
return string(res)
|
||||
}
|
||||
if gfile.IsFile(filePath) {
|
||||
if gfile.ExtName(filePath) != "go" {
|
||||
return nil
|
||||
}
|
||||
return gfile.ReplaceFileFunc(replaceFunc, filePath)
|
||||
}
|
||||
return gfile.ReplaceDirFunc(replaceFunc, filePath, "*.go", true)
|
||||
}
|
||||
|
||||
@ -46,6 +46,8 @@ func ExampleNew() {
|
||||
a.Set(0, 100)
|
||||
fmt.Println(a.Slice())
|
||||
|
||||
fmt.Println(a.At(0))
|
||||
|
||||
// Search item and return its index.
|
||||
fmt.Println(a.Search(5))
|
||||
|
||||
@ -66,6 +68,7 @@ func ExampleNew() {
|
||||
// false
|
||||
// [0 1 2 3 4 5 6 7 8 9 10 11]
|
||||
// [100 1 2 3 4 5 6 7 8 9 10 11]
|
||||
// 100
|
||||
// 5
|
||||
// [1 2 3 4 5 6 7 8 9 10 11]
|
||||
// [1 2 3 4 5 6 7 8 9 10 11]
|
||||
|
||||
@ -54,6 +54,14 @@ func ExampleNewIntArraySize() {
|
||||
// [10 20 15] 3 5
|
||||
}
|
||||
|
||||
func ExampleNewIntArrayRange() {
|
||||
s := garray.NewIntArrayRange(1, 5, 1)
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
|
||||
// Output:
|
||||
// [1 2 3 4 5] 5 5
|
||||
}
|
||||
|
||||
func ExampleNewIntArrayFrom() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
|
||||
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
|
||||
@ -83,9 +91,12 @@ func ExampleIntArray_Get() {
|
||||
s := garray.NewIntArrayFrom(g.SliceInt{10, 20, 15, 30})
|
||||
sGet, sBool := s.Get(3)
|
||||
fmt.Println(sGet, sBool)
|
||||
sGet, sBool = s.Get(99)
|
||||
fmt.Println(sGet, sBool)
|
||||
|
||||
// Output:
|
||||
// 30 true
|
||||
// 0 false
|
||||
}
|
||||
|
||||
func ExampleIntArray_Set() {
|
||||
|
||||
@ -25,9 +25,24 @@ func Test_Array_Basic(t *testing.T) {
|
||||
array := garray.NewArrayFrom(expect)
|
||||
array2 := garray.NewArrayFrom(expect)
|
||||
array3 := garray.NewArrayFrom([]interface{}{})
|
||||
array4 := garray.NewArrayRange(1, 5, 1)
|
||||
|
||||
t.Assert(array.Slice(), expect)
|
||||
t.Assert(array.Interfaces(), expect)
|
||||
array.Set(0, 100)
|
||||
err := array.Set(0, 100)
|
||||
t.AssertNil(err)
|
||||
|
||||
err = array.Set(100, 100)
|
||||
t.AssertNE(err, nil)
|
||||
|
||||
t.Assert(array.IsEmpty(), false)
|
||||
|
||||
copyArray := array.DeepCopy()
|
||||
ca := copyArray.(*garray.Array)
|
||||
ca.Set(0, 1)
|
||||
cval, _ := ca.Get(0)
|
||||
val, _ := array.Get(0)
|
||||
t.AssertNE(cval, val)
|
||||
|
||||
v, ok := array.Get(0)
|
||||
t.Assert(v, 100)
|
||||
@ -37,6 +52,10 @@ func Test_Array_Basic(t *testing.T) {
|
||||
t.Assert(v, 1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array.Get(4)
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.Search(100), 0)
|
||||
t.Assert(array3.Search(100), -1)
|
||||
t.Assert(array.Contains(100), true)
|
||||
@ -71,6 +90,12 @@ func Test_Array_Basic(t *testing.T) {
|
||||
array.InsertAfter(6, 400)
|
||||
t.Assert(array.Slice(), []interface{}{100, 200, 2, 2, 3, 300, 4, 400})
|
||||
t.Assert(array.Clear().Len(), 0)
|
||||
err = array.InsertBefore(99, 9900)
|
||||
t.AssertNE(err, nil)
|
||||
err = array.InsertAfter(99, 9900)
|
||||
t.AssertNE(err, nil)
|
||||
|
||||
t.Assert(array4.String(), "[1,2,3,4,5]")
|
||||
})
|
||||
}
|
||||
|
||||
@ -99,6 +124,11 @@ func TestArray_Unique(t *testing.T) {
|
||||
array := garray.NewArrayFrom(expect)
|
||||
t.Assert(array.Unique().Slice(), []interface{}{1, 2, 3, 4, 5})
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
expect := []interface{}{}
|
||||
array := garray.NewArrayFrom(expect)
|
||||
t.Assert(array.Unique().Slice(), []interface{}{})
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_PushAndPop(t *testing.T) {
|
||||
@ -382,6 +412,21 @@ func TestArray_Rand(t *testing.T) {
|
||||
t.Assert(a1.Contains(i1), true)
|
||||
t.Assert(a1.Len(), 4)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
rand, found := array1.Rand()
|
||||
t.AssertNil(rand)
|
||||
t.Assert(found, false)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
rand := array1.Rands(1)
|
||||
t.AssertNil(rand)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_Shuffle(t *testing.T) {
|
||||
@ -412,6 +457,12 @@ func TestArray_Join(t *testing.T) {
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
t.Assert(array1.Join("."), `0.1."a".\a`)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
t.Assert(len(array1.Join(".")), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestArray_String(t *testing.T) {
|
||||
@ -419,6 +470,8 @@ func TestArray_String(t *testing.T) {
|
||||
a1 := []interface{}{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewArrayFrom(a1)
|
||||
t.Assert(array1.String(), `[0,1,2,3,4,5,6]`)
|
||||
array1 = nil
|
||||
t.Assert(array1.String(), "")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -63,6 +63,19 @@ func Test_IntArray_Basic(t *testing.T) {
|
||||
array.InsertAfter(6, 400)
|
||||
t.Assert(array.Slice(), []int{100, 200, 1, 2, 3, 300, 4, 400})
|
||||
t.Assert(array.Clear().Len(), 0)
|
||||
err := array.InsertBefore(99, 300)
|
||||
t.AssertNE(err, nil)
|
||||
err = array.InsertAfter(99, 400)
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewIntArrayFrom([]int{0, 1, 2, 3})
|
||||
copyArray := array.DeepCopy().(*garray.IntArray)
|
||||
copyArray.Set(0, 1)
|
||||
cval, _ := copyArray.Get(0)
|
||||
val, _ := array.Get(0)
|
||||
t.AssertNE(cval, val)
|
||||
})
|
||||
}
|
||||
|
||||
@ -89,6 +102,8 @@ func TestIntArray_Unique(t *testing.T) {
|
||||
expect := []int{1, 2, 3, 4, 5, 3, 2, 2, 3, 5, 5}
|
||||
array := garray.NewIntArrayFrom(expect)
|
||||
t.Assert(array.Unique().Slice(), []int{1, 2, 3, 4, 5})
|
||||
array2 := garray.NewIntArrayFrom([]int{})
|
||||
t.Assert(array2.Unique().Slice(), []int{})
|
||||
})
|
||||
}
|
||||
|
||||
@ -374,6 +389,14 @@ func TestIntArray_Rand(t *testing.T) {
|
||||
v, ok := array1.Rand()
|
||||
t.AssertIN(v, a1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
array2 := garray.NewIntArrayFrom([]int{})
|
||||
v, ok = array2.Rand()
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
|
||||
intSlices := array2.Rands(1)
|
||||
t.Assert(intSlices, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -420,6 +443,8 @@ func TestIntArray_String(t *testing.T) {
|
||||
a1 := []int{0, 1, 2, 3, 4, 5, 6}
|
||||
array1 := garray.NewIntArrayFrom(a1)
|
||||
t.Assert(array1.String(), "[0,1,2,3,4,5,6]")
|
||||
array1 = nil
|
||||
t.Assert(array1.String(), "")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -34,6 +34,10 @@ func Test_StrArray_Basic(t *testing.T) {
|
||||
t.Assert(v, 100)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array3.Get(0)
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
|
||||
t.Assert(array.Search("100"), 0)
|
||||
t.Assert(array.Contains("100"), true)
|
||||
|
||||
@ -61,12 +65,28 @@ func Test_StrArray_Basic(t *testing.T) {
|
||||
t.Assert(array.Clear().Len(), 0)
|
||||
t.Assert(array2.Slice(), expect)
|
||||
t.Assert(array3.Search("100"), -1)
|
||||
err := array.InsertBefore(99, "300")
|
||||
t.AssertNE(err, nil)
|
||||
array.InsertAfter(99, "400")
|
||||
t.AssertNE(err, nil)
|
||||
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewStrArrayFrom([]string{"0", "1", "2", "3"})
|
||||
|
||||
copyArray := array.DeepCopy().(*garray.StrArray)
|
||||
copyArray.Set(0, "1")
|
||||
cval, _ := copyArray.Get(0)
|
||||
val, _ := array.Get(0)
|
||||
t.AssertNE(cval, val)
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_ContainsI(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s := garray.NewStrArray()
|
||||
t.Assert(s.Contains("A"), false)
|
||||
s.Append("a", "b", "C")
|
||||
t.Assert(s.Contains("A"), false)
|
||||
t.Assert(s.Contains("a"), true)
|
||||
@ -94,6 +114,8 @@ func TestStrArray_Unique(t *testing.T) {
|
||||
expect := []string{"1", "1", "2", "2", "3", "3", "2", "2"}
|
||||
array := garray.NewStrArrayFrom(expect)
|
||||
t.Assert(array.Unique().Slice(), []string{"1", "2", "3"})
|
||||
array1 := garray.NewStrArrayFrom([]string{})
|
||||
t.Assert(array1.Unique().Slice(), []string{})
|
||||
})
|
||||
}
|
||||
|
||||
@ -364,6 +386,13 @@ func TestStrArray_Rand(t *testing.T) {
|
||||
v, ok := array1.Rand()
|
||||
t.Assert(ok, true)
|
||||
t.AssertIN(v, a1)
|
||||
|
||||
array2 := garray.NewStrArrayFrom([]string{})
|
||||
v, ok = array2.Rand()
|
||||
t.Assert(ok, false)
|
||||
t.Assert(v, "")
|
||||
strArray := array2.Rands(1)
|
||||
t.AssertNil(strArray)
|
||||
})
|
||||
}
|
||||
|
||||
@ -406,6 +435,11 @@ func TestStrArray_Join(t *testing.T) {
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
t.Assert(array1.Join("."), `0.1."a".\a`)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
t.Assert(array1.Join("."), "")
|
||||
})
|
||||
}
|
||||
|
||||
func TestStrArray_String(t *testing.T) {
|
||||
@ -413,6 +447,9 @@ func TestStrArray_String(t *testing.T) {
|
||||
a1 := []string{"0", "1", "2", "3", "4", "5", "6"}
|
||||
array1 := garray.NewStrArrayFrom(a1)
|
||||
t.Assert(array1.String(), `["0","1","2","3","4","5","6"]`)
|
||||
|
||||
array1 = nil
|
||||
t.Assert(array1.String(), "")
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@ -61,6 +61,18 @@ func TestNewSortedArrayFromCopy(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedArrayRange(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return gconv.Int(v1) - gconv.Int(v2)
|
||||
}
|
||||
|
||||
array1 := garray.NewSortedArrayRange(1, 5, 1, func1)
|
||||
t.Assert(array1.Len(), 5)
|
||||
t.Assert(array1, []interface{}{1, 2, 3, 4, 5})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_SetArray(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
@ -106,10 +118,26 @@ func TestSortedArray_Get(t *testing.T) {
|
||||
v, ok = array1.Get(1)
|
||||
t.Assert(v, "c")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(99)
|
||||
t.Assert(v, nil)
|
||||
t.Assert(ok, false)
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
func TestSortedArray_At(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{"a", "f", "c"}
|
||||
func1 := func(v1, v2 interface{}) int {
|
||||
return strings.Compare(gconv.String(v1), gconv.String(v2))
|
||||
}
|
||||
array1 := garray.NewSortedArrayFrom(a1, func1)
|
||||
v := array1.At(2)
|
||||
t.Assert(v, "f")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_Remove(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{"a", "d", "c", "b"}
|
||||
@ -461,6 +489,11 @@ func TestSortedArray_Rand(t *testing.T) {
|
||||
t.Assert(ok, true)
|
||||
t.AssertIN(i1, []interface{}{"a", "d", "c"})
|
||||
t.Assert(array1.Len(), 3)
|
||||
|
||||
array2 := garray.NewSortedArrayFrom([]interface{}{}, func1)
|
||||
v, ok := array2.Rand()
|
||||
t.Assert(ok, false)
|
||||
t.Assert(v, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -479,6 +512,10 @@ func TestSortedArray_Rands(t *testing.T) {
|
||||
|
||||
i1 = array1.Rands(4)
|
||||
t.Assert(len(i1), 4)
|
||||
|
||||
array2 := garray.NewSortedArrayFrom([]interface{}{}, func1)
|
||||
v := array2.Rands(1)
|
||||
t.Assert(v, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -498,6 +535,12 @@ func TestSortedArray_Join(t *testing.T) {
|
||||
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
|
||||
t.Assert(array1.Join("."), `"a".0.1.\a`)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []interface{}{}
|
||||
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
|
||||
t.Assert(array1.Join("."), "")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_String(t *testing.T) {
|
||||
@ -505,6 +548,9 @@ func TestSortedArray_String(t *testing.T) {
|
||||
a1 := []interface{}{0, 1, "a", "b"}
|
||||
array1 := garray.NewSortedArrayFrom(a1, gutil.ComparatorString)
|
||||
t.Assert(array1.String(), `[0,1,"a","b"]`)
|
||||
|
||||
array1 = nil
|
||||
t.Assert(array1.String(), "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -541,6 +587,11 @@ func TestSortedArray_Unique(t *testing.T) {
|
||||
array1.Unique()
|
||||
t.Assert(array1.Len(), 5)
|
||||
t.Assert(array1, []interface{}{1, 2, 3, 4, 5})
|
||||
|
||||
array2 := garray.NewSortedArrayFrom([]interface{}{}, gutil.ComparatorInt)
|
||||
array2.Unique()
|
||||
t.Assert(array2.Len(), 0)
|
||||
t.Assert(array2, []interface{}{})
|
||||
})
|
||||
}
|
||||
|
||||
@ -878,3 +929,22 @@ func TestSortedArray_Walk(t *testing.T) {
|
||||
}), g.Slice{"key-1", "key-2"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_IsEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedArrayFrom([]interface{}{}, gutil.ComparatorString)
|
||||
t.Assert(array.IsEmpty(), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedArray_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedArrayFrom([]interface{}{1, 2, 3, 4, 5}, gutil.ComparatorString)
|
||||
copyArray := array.DeepCopy().(*garray.SortedArray)
|
||||
array.Add(6)
|
||||
copyArray.Add(7)
|
||||
cval, _ := copyArray.Get(5)
|
||||
val, _ := array.Get(5)
|
||||
t.AssertNE(cval, val)
|
||||
})
|
||||
}
|
||||
|
||||
@ -19,6 +19,26 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func TestNewSortedIntArrayComparator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{0, 3, 2, 1, 4, 5, 6}
|
||||
array1 := garray.NewSortedIntArrayComparator(func(a, b int) int {
|
||||
return a - b
|
||||
}, true)
|
||||
array1.Append(a1...)
|
||||
t.Assert(array1.Len(), 7)
|
||||
t.Assert(array1.Interfaces(), []int{0, 1, 2, 3, 4, 5, 6})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayRange(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array1 := garray.NewSortedIntArrayRange(1, 5, 1)
|
||||
t.Assert(array1.Len(), 5)
|
||||
t.Assert(array1.Interfaces(), []int{1, 2, 3, 4, 5})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedIntArrayFrom(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{0, 3, 2, 1, 4, 5, 6}
|
||||
@ -37,6 +57,17 @@ func TestNewSortedIntArrayFromCopy(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_At(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{0, 3, 2, 1}
|
||||
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
v := array1.At(1)
|
||||
|
||||
t.Assert(v, 1)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_SetArray(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []int{0, 1, 2, 3}
|
||||
@ -78,6 +109,10 @@ func TestSortedIntArray_Get(t *testing.T) {
|
||||
v, ok = array1.Get(3)
|
||||
t.Assert(v, 5)
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(99)
|
||||
t.Assert(v, 0)
|
||||
t.Assert(ok, false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -294,6 +329,9 @@ func TestSortedIntArray_Join(t *testing.T) {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
t.Assert(array1.Join("."), `1.3.5`)
|
||||
|
||||
array2 := garray.NewSortedIntArrayFrom([]int{})
|
||||
t.Assert(array2.Join("."), "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -302,6 +340,9 @@ func TestSortedIntArray_String(t *testing.T) {
|
||||
a1 := []int{1, 3, 5}
|
||||
array1 := garray.NewSortedIntArrayFrom(a1)
|
||||
t.Assert(array1.String(), `[1,3,5]`)
|
||||
|
||||
array1 = nil
|
||||
t.Assert(array1.String(), "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -406,6 +447,11 @@ func TestSortedIntArray_Rand(t *testing.T) {
|
||||
ns1, ok := array1.Rand()
|
||||
t.AssertIN(ns1, a1)
|
||||
t.Assert(ok, true)
|
||||
|
||||
array2 := garray.NewSortedIntArrayFrom([]int{})
|
||||
ns2, ok := array2.Rand()
|
||||
t.Assert(ns2, 0)
|
||||
t.Assert(ok, false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -419,6 +465,10 @@ func TestSortedIntArray_Rands(t *testing.T) {
|
||||
|
||||
ns2 := array1.Rands(6)
|
||||
t.Assert(len(ns2), 6)
|
||||
|
||||
array2 := garray.NewSortedIntArrayFrom([]int{})
|
||||
val := array2.Rands(1)
|
||||
t.Assert(val, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -450,6 +500,10 @@ func TestSortedIntArray_Unique(t *testing.T) {
|
||||
array1.Unique()
|
||||
t.Assert(array1.Len(), 5)
|
||||
t.Assert(array1, []int{1, 2, 3, 4, 5})
|
||||
|
||||
array2 := garray.NewSortedIntArrayFrom([]int{})
|
||||
array2.Unique()
|
||||
t.Assert(array2.Len(), 0)
|
||||
})
|
||||
}
|
||||
|
||||
@ -731,3 +785,22 @@ func TestSortedIntArray_Walk(t *testing.T) {
|
||||
}), g.Slice{11, 12})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_IsEmpty(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedIntArrayFrom([]int{})
|
||||
t.Assert(array.IsEmpty(), true)
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedIntArray_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedIntArrayFrom([]int{1, 2, 3, 4, 5})
|
||||
copyArray := array.DeepCopy().(*garray.SortedIntArray)
|
||||
array.Add(6)
|
||||
copyArray.Add(7)
|
||||
cval, _ := copyArray.Get(5)
|
||||
val, _ := array.Get(5)
|
||||
t.AssertNE(cval, val)
|
||||
})
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
package garray_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -19,6 +20,18 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
func TestNewSortedStrArrayComparator(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
s1 := garray.NewSortedStrArrayComparator(func(a, b string) int {
|
||||
return gstr.Compare(a, b)
|
||||
})
|
||||
s1.Add(a1...)
|
||||
t.Assert(s1.Len(), 4)
|
||||
t.Assert(s1, []string{"a", "b", "c", "d"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewSortedStrArrayFrom(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
a1 := []string{"a", "d", "c", "b"}
|
||||
@ -58,6 +71,9 @@ func TestSortedStrArray_ContainsI(t *testing.T) {
|
||||
t.Assert(s.Contains("A"), false)
|
||||
t.Assert(s.Contains("a"), true)
|
||||
t.Assert(s.ContainsI("A"), true)
|
||||
|
||||
s = garray.NewSortedStrArray()
|
||||
t.Assert(s.Contains("A"), false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -85,6 +101,10 @@ func TestSortedStrArray_Get(t *testing.T) {
|
||||
v, ok = array1.Get(0)
|
||||
t.Assert(v, "a")
|
||||
t.Assert(ok, true)
|
||||
|
||||
v, ok = array1.Get(99)
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -361,6 +381,11 @@ func TestSortedStrArray_Rand(t *testing.T) {
|
||||
v, ok := array1.Rand()
|
||||
t.AssertIN(v, []string{"e", "a", "d"})
|
||||
t.Assert(ok, true)
|
||||
|
||||
array2 := garray.NewSortedStrArrayFrom([]string{})
|
||||
v, ok = array2.Rand()
|
||||
t.Assert(v, "")
|
||||
t.Assert(ok, false)
|
||||
})
|
||||
}
|
||||
|
||||
@ -375,6 +400,10 @@ func TestSortedStrArray_Rands(t *testing.T) {
|
||||
|
||||
s1 = array1.Rands(4)
|
||||
t.Assert(len(s1), 4)
|
||||
|
||||
array2 := garray.NewSortedStrArrayFrom([]string{})
|
||||
val := array2.Rands(1)
|
||||
t.Assert(val, nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -391,6 +420,11 @@ func TestSortedStrArray_Join(t *testing.T) {
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
t.Assert(array1.Join("."), `"b".\c.a`)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array1 := garray.NewSortedStrArrayFrom([]string{})
|
||||
t.Assert(array1.Join("."), "")
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_String(t *testing.T) {
|
||||
@ -398,6 +432,9 @@ func TestSortedStrArray_String(t *testing.T) {
|
||||
a1 := []string{"e", "a", "d"}
|
||||
array1 := garray.NewSortedStrArrayFrom(a1)
|
||||
t.Assert(array1.String(), `["a","d","e"]`)
|
||||
|
||||
array1 = nil
|
||||
t.Assert(array1.String(), "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -469,6 +506,11 @@ func TestSortedStrArray_Unique(t *testing.T) {
|
||||
array1.Unique()
|
||||
t.Assert(array1.Len(), 3)
|
||||
t.Assert(array1, []string{"1", "2", "3"})
|
||||
|
||||
array2 := garray.NewSortedStrArrayFrom([]string{})
|
||||
array2.Unique()
|
||||
t.Assert(array2.Len(), 0)
|
||||
t.Assert(array2, []string{})
|
||||
})
|
||||
}
|
||||
|
||||
@ -755,3 +797,15 @@ func TestSortedStrArray_Walk(t *testing.T) {
|
||||
}), g.Slice{"key-1", "key-2"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestSortedStrArray_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
array := garray.NewSortedStrArrayFrom([]string{"a", "b", "c", "d"})
|
||||
copyArray := array.DeepCopy().(*garray.SortedStrArray)
|
||||
array.Add("e")
|
||||
copyArray.Add("f")
|
||||
cval, _ := copyArray.Get(4)
|
||||
val, _ := array.Get(4)
|
||||
t.AssertNE(cval, val)
|
||||
})
|
||||
}
|
||||
|
||||
@ -755,3 +755,13 @@ func TestList_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(tlist.List.FrontAll(), []interface{}{1, 2, 3})
|
||||
})
|
||||
}
|
||||
|
||||
func TestList_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
l := NewFrom([]interface{}{1, 2, "a", `"b"`, `\c`})
|
||||
copyList := l.DeepCopy()
|
||||
cl := copyList.(*List)
|
||||
cl.PopBack()
|
||||
t.AssertNE(l.Size(), cl.Size())
|
||||
})
|
||||
}
|
||||
|
||||
@ -602,8 +602,12 @@ func ExampleAnyAnyMap_String() {
|
||||
|
||||
fmt.Println(m.String())
|
||||
|
||||
var m1 *gmap.Map = nil
|
||||
fmt.Println(len(m1.String()))
|
||||
|
||||
// Output:
|
||||
// {"k1":"v1"}
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleAnyAnyMap_MarshalJSON() {
|
||||
|
||||
@ -601,8 +601,12 @@ func ExampleIntAnyMap_String() {
|
||||
|
||||
fmt.Println(m.String())
|
||||
|
||||
var m1 *gmap.IntAnyMap = nil
|
||||
fmt.Println(len(m1.String()))
|
||||
|
||||
// Output:
|
||||
// {"1":"v1"}
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleIntAnyMap_MarshalJSON() {
|
||||
|
||||
@ -529,8 +529,12 @@ func ExampleIntIntMap_String() {
|
||||
|
||||
fmt.Println(m.String())
|
||||
|
||||
var m1 *gmap.IntIntMap = nil
|
||||
fmt.Println(len(m1.String()))
|
||||
|
||||
// Output:
|
||||
// {"1":1}
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleIntIntMap_MarshalJSON() {
|
||||
|
||||
@ -599,8 +599,12 @@ func ExampleStrAnyMap_String() {
|
||||
|
||||
fmt.Println(m.String())
|
||||
|
||||
var m1 *gmap.StrAnyMap = nil
|
||||
fmt.Println(len(m1.String()))
|
||||
|
||||
// Output:
|
||||
// {"k1":"v1"}
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStrAnyMap_MarshalJSON() {
|
||||
|
||||
@ -8,11 +8,10 @@ package gmap_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
|
||||
"github.com/gogf/gf/v2/container/gmap"
|
||||
)
|
||||
|
||||
func ExampleStrIntMap_Iterator() {
|
||||
@ -535,8 +534,12 @@ func ExampleStrIntMap_String() {
|
||||
|
||||
fmt.Println(m.String())
|
||||
|
||||
var m1 *gmap.StrIntMap = nil
|
||||
fmt.Println(len(m1.String()))
|
||||
|
||||
// Output:
|
||||
// {"k1":1}
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStrIntMap_MarshalJSON() {
|
||||
|
||||
@ -531,8 +531,12 @@ func ExampleStrStrMap_String() {
|
||||
|
||||
fmt.Println(m.String())
|
||||
|
||||
var m1 *gmap.StrStrMap = nil
|
||||
fmt.Println(len(m1.String()))
|
||||
|
||||
// Output:
|
||||
// {"k1":"v1"}
|
||||
// 0
|
||||
}
|
||||
|
||||
func ExampleStrStrMap_MarshalJSON() {
|
||||
|
||||
@ -90,7 +90,7 @@ func ExampleNewFrom() {
|
||||
}
|
||||
|
||||
func ExampleNewHashMap() {
|
||||
m := gmap.New()
|
||||
m := gmap.NewHashMap()
|
||||
|
||||
m.Set("key1", "val1")
|
||||
fmt.Println(m)
|
||||
@ -105,7 +105,7 @@ func ExampleNewHashMapFrom() {
|
||||
m.Set("key1", "val1")
|
||||
fmt.Println(m)
|
||||
|
||||
n := gmap.NewFrom(m.MapCopy(), true)
|
||||
n := gmap.NewHashMapFrom(m.MapCopy(), true)
|
||||
fmt.Println(n)
|
||||
|
||||
// Output:
|
||||
|
||||
@ -171,6 +171,9 @@ func Test_AnyAnyMap_Merge(t *testing.T) {
|
||||
m2.Set(2, "2")
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[interface{}]interface{}{1: 1, 2: "2"})
|
||||
m3 := gmap.NewAnyAnyMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -296,6 +299,10 @@ func Test_AnyAnyMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.AssertNil(k3)
|
||||
t.AssertNil(v3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -327,6 +334,11 @@ func Test_AnyAnyMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -365,3 +377,17 @@ func TestAnyAnyMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get("k2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_AnyAnyMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
|
||||
"k1": "v1",
|
||||
"k2": "v2",
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.AnyAnyMap)
|
||||
n.Set("k1", "val1")
|
||||
t.AssertNE(m.Get("k1"), n.Get("k1"))
|
||||
})
|
||||
}
|
||||
|
||||
@ -82,6 +82,12 @@ func Test_IntAnyMap_Basic(t *testing.T) {
|
||||
m2 := gmap.NewIntAnyMapFrom(map[int]interface{}{1: 1, 2: "2"})
|
||||
t.Assert(m2.Map(), map[int]interface{}{1: 1, 2: "2"})
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntAnyMap(true)
|
||||
m.Set(1, 1)
|
||||
t.Assert(m.Map(), map[int]interface{}{1: 1})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_Set_Fun(t *testing.T) {
|
||||
@ -171,6 +177,9 @@ func Test_IntAnyMap_Merge(t *testing.T) {
|
||||
m2.Set(2, "2")
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[int]interface{}{1: 1, 2: "2"})
|
||||
m3 := gmap.NewIntAnyMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -271,6 +280,10 @@ func Test_IntAnyMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.Assert(k3, 0)
|
||||
t.AssertNil(v3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -302,6 +315,11 @@ func Test_IntAnyMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -340,3 +358,17 @@ func TestIntAnyMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get(2), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntAnyMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntAnyMapFrom(g.MapIntAny{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.IntAnyMap)
|
||||
n.Set(1, "val1")
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
@ -86,6 +86,12 @@ func Test_IntIntMap_Basic(t *testing.T) {
|
||||
m2 := gmap.NewIntIntMapFrom(map[int]int{1: 1, 2: 2})
|
||||
t.Assert(m2.Map(), map[int]int{1: 1, 2: 2})
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntIntMap(true)
|
||||
m.Set(1, 1)
|
||||
t.Assert(m.Map(), map[int]int{1: 1})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Set_Fun(t *testing.T) {
|
||||
@ -102,6 +108,11 @@ func Test_IntIntMap_Set_Fun(t *testing.T) {
|
||||
t.Assert(m.SetIfNotExistFuncLock(2, getInt), false)
|
||||
t.Assert(m.SetIfNotExistFuncLock(4, getInt), true)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntIntMapFrom(nil)
|
||||
t.Assert(m.GetOrSetFuncLock(1, getInt), getInt())
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_Batch(t *testing.T) {
|
||||
@ -177,6 +188,9 @@ func Test_IntIntMap_Merge(t *testing.T) {
|
||||
m2.Set(2, 2)
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[int]int{1: 1, 2: 2})
|
||||
m3 := gmap.NewIntIntMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -277,6 +291,10 @@ func Test_IntIntMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.Assert(k3, 0)
|
||||
t.Assert(v3, 0)
|
||||
})
|
||||
}
|
||||
|
||||
@ -308,6 +326,11 @@ func Test_IntIntMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -346,3 +369,17 @@ func TestIntIntMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get(2), "2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntIntMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntIntMapFrom(g.MapIntInt{
|
||||
1: 1,
|
||||
2: 2,
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.IntIntMap)
|
||||
n.Set(1, 2)
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
@ -63,6 +63,7 @@ func Test_IntStrMap_Basic(t *testing.T) {
|
||||
t.Assert(m.Size(), 1)
|
||||
t.Assert(m.IsEmpty(), false)
|
||||
|
||||
t.Assert(m.GetOrSet(1, "a"), "a")
|
||||
t.Assert(m.GetOrSet(2, "b"), "b")
|
||||
t.Assert(m.SetIfNotExist(2, "b"), false)
|
||||
|
||||
@ -90,6 +91,29 @@ func Test_IntStrMap_Basic(t *testing.T) {
|
||||
m2 := gmap.NewIntStrMapFrom(map[int]string{1: "a", 2: "b"})
|
||||
t.Assert(m2.Map(), map[int]string{1: "a", 2: "b"})
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMap(true)
|
||||
m.Set(1, "val1")
|
||||
t.Assert(m.Map(), map[int]string{1: "val1"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntStrMap_MapStrAny(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMap()
|
||||
m.GetOrSetFunc(1, getStr)
|
||||
m.GetOrSetFuncLock(2, getStr)
|
||||
t.Assert(m.MapStrAny(), g.MapStrAny{"1": "z", "2": "z"})
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntStrMap_Sets(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMapFrom(nil)
|
||||
m.Sets(g.MapIntStr{1: "z", 2: "z"})
|
||||
t.Assert(len(m.Map()), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Set_Fun(t *testing.T) {
|
||||
@ -97,6 +121,8 @@ func Test_IntStrMap_Set_Fun(t *testing.T) {
|
||||
m := gmap.NewIntStrMap()
|
||||
m.GetOrSetFunc(1, getStr)
|
||||
m.GetOrSetFuncLock(2, getStr)
|
||||
t.Assert(m.GetOrSetFunc(1, getStr), "z")
|
||||
t.Assert(m.GetOrSetFuncLock(2, getStr), "z")
|
||||
t.Assert(m.Get(1), "z")
|
||||
t.Assert(m.Get(2), "z")
|
||||
t.Assert(m.SetIfNotExistFunc(1, getStr), false)
|
||||
@ -105,6 +131,16 @@ func Test_IntStrMap_Set_Fun(t *testing.T) {
|
||||
t.Assert(m.SetIfNotExistFuncLock(2, getStr), false)
|
||||
t.Assert(m.SetIfNotExistFuncLock(4, getStr), true)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMapFrom(nil)
|
||||
t.Assert(m.GetOrSetFuncLock(1, getStr), "z")
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMapFrom(nil)
|
||||
t.Assert(m.SetIfNotExistFuncLock(1, getStr), true)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_Batch(t *testing.T) {
|
||||
@ -176,6 +212,10 @@ func Test_IntStrMap_Merge(t *testing.T) {
|
||||
m2.Set(2, "b")
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[int]string{1: "a", 2: "b"})
|
||||
|
||||
m3 := gmap.NewIntStrMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -275,6 +315,10 @@ func Test_IntStrMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.Assert(k3, 0)
|
||||
t.Assert(v3, "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -306,6 +350,11 @@ func Test_IntStrMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -344,3 +393,55 @@ func TestIntStrMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get(2), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntStrMap_Replace(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
3: "v3",
|
||||
})
|
||||
|
||||
t.Assert(m.Get(1), "v1")
|
||||
t.Assert(m.Get(2), "v2")
|
||||
t.Assert(m.Get(3), "v3")
|
||||
|
||||
m.Replace(g.MapIntStr{
|
||||
1: "v2",
|
||||
2: "v3",
|
||||
3: "v1",
|
||||
})
|
||||
|
||||
t.Assert(m.Get(1), "v2")
|
||||
t.Assert(m.Get(2), "v3")
|
||||
t.Assert(m.Get(3), "v1")
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntStrMap_String(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "v1",
|
||||
2: "v2",
|
||||
3: "v3",
|
||||
})
|
||||
t.Assert(m.String(), "{\"1\":\"v1\",\"2\":\"v2\",\"3\":\"v3\"}")
|
||||
|
||||
m = nil
|
||||
t.Assert(len(m.String()), 0)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_IntStrMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewIntStrMapFrom(g.MapIntStr{
|
||||
1: "val1",
|
||||
2: "val2",
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.IntStrMap)
|
||||
n.Set(1, "v1")
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
@ -169,6 +169,10 @@ func Test_StrAnyMap_Merge(t *testing.T) {
|
||||
m2.Set("b", "2")
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[string]interface{}{"a": 1, "b": "2"})
|
||||
|
||||
m3 := gmap.NewStrAnyMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -283,6 +287,10 @@ func Test_StrAnyMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.Assert(k3, "")
|
||||
t.Assert(v3, "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -314,6 +322,11 @@ func Test_StrAnyMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -352,3 +365,17 @@ func TestStrAnyMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get("k2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrAnyMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewStrAnyMapFrom(g.MapStrAny{
|
||||
"key1": "val1",
|
||||
"key2": "val2",
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.StrAnyMap)
|
||||
n.Set("key1", "v1")
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
@ -100,6 +100,11 @@ func Test_StrIntMap_Set_Fun(t *testing.T) {
|
||||
t.Assert(m.SetIfNotExistFuncLock("b", getInt), false)
|
||||
t.Assert(m.SetIfNotExistFuncLock("d", getInt), true)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewStrIntMapFrom(nil)
|
||||
t.Assert(m.GetOrSetFuncLock("a", getInt), 123)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_Batch(t *testing.T) {
|
||||
@ -173,6 +178,9 @@ func Test_StrIntMap_Merge(t *testing.T) {
|
||||
m2.Set("b", 2)
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[string]int{"a": 1, "b": 2})
|
||||
m3 := gmap.NewStrIntMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -287,6 +295,10 @@ func Test_StrIntMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.Assert(k3, "")
|
||||
t.Assert(v3, 0)
|
||||
})
|
||||
}
|
||||
|
||||
@ -318,6 +330,11 @@ func Test_StrIntMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -356,3 +373,17 @@ func TestStrIntMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get("k2"), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrIntMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewStrIntMapFrom(g.MapStrInt{
|
||||
"key1": 1,
|
||||
"key2": 2,
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.StrIntMap)
|
||||
n.Set("key1", 2)
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
@ -98,6 +98,12 @@ func Test_StrStrMap_Set_Fun(t *testing.T) {
|
||||
t.Assert(m.SetIfNotExistFuncLock("b", getStr), false)
|
||||
t.Assert(m.SetIfNotExistFuncLock("d", getStr), true)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewStrStrMapFrom(nil)
|
||||
|
||||
t.Assert(m.GetOrSetFuncLock("b", getStr), "z")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_Batch(t *testing.T) {
|
||||
@ -170,6 +176,9 @@ func Test_StrStrMap_Merge(t *testing.T) {
|
||||
m2.Set("b", "b")
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[string]string{"a": "a", "b": "b"})
|
||||
m3 := gmap.NewStrStrMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -284,6 +293,10 @@ func Test_StrStrMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.Assert(k3, "")
|
||||
t.Assert(v3, "")
|
||||
})
|
||||
}
|
||||
|
||||
@ -315,6 +328,11 @@ func Test_StrStrMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -353,3 +371,17 @@ func TestStrStrMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get("k2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_StrStrMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewStrStrMapFrom(g.MapStrStr{
|
||||
"key1": "val1",
|
||||
"key2": "val2",
|
||||
})
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.StrStrMap)
|
||||
n.Set("key1", "v1")
|
||||
t.AssertNE(m.Get("key1"), n.Get("key1"))
|
||||
})
|
||||
}
|
||||
|
||||
@ -154,6 +154,9 @@ func Test_ListMap_Basic_Merge(t *testing.T) {
|
||||
m2.Set("key2", "val2")
|
||||
m1.Merge(m2)
|
||||
t.Assert(m1.Map(), map[interface{}]interface{}{"key1": "val1", "key2": "val2"})
|
||||
m3 := gmap.NewListMapFrom(nil)
|
||||
m3.Merge(m2)
|
||||
t.Assert(m3.Map(), m2.Map())
|
||||
})
|
||||
}
|
||||
|
||||
@ -266,6 +269,10 @@ func Test_ListMap_Pop(t *testing.T) {
|
||||
|
||||
t.AssertNE(k1, k2)
|
||||
t.AssertNE(v1, v2)
|
||||
|
||||
k3, v3 := m.Pop()
|
||||
t.AssertNil(k3)
|
||||
t.AssertNil(v3)
|
||||
})
|
||||
}
|
||||
|
||||
@ -297,6 +304,11 @@ func Test_ListMap_Pops(t *testing.T) {
|
||||
|
||||
t.Assert(kArray.Unique().Len(), 3)
|
||||
t.Assert(vArray.Unique().Len(), 3)
|
||||
|
||||
v := m.Pops(1)
|
||||
t.AssertNil(v)
|
||||
v = m.Pops(-1)
|
||||
t.AssertNil(v)
|
||||
})
|
||||
}
|
||||
|
||||
@ -335,3 +347,44 @@ func TestListMap_UnmarshalValue(t *testing.T) {
|
||||
t.Assert(v.Map.Get("2"), "v2")
|
||||
})
|
||||
}
|
||||
|
||||
func TestListMap_String(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.Set(1, "")
|
||||
m.Set(2, "2")
|
||||
t.Assert(m.String(), "{\"1\":\"\",\"2\":\"2\"}")
|
||||
|
||||
m1 := gmap.NewListMapFrom(nil)
|
||||
t.Assert(m1.String(), "{}")
|
||||
})
|
||||
}
|
||||
|
||||
func TestListMap_MarshalJSON(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.Set(1, "")
|
||||
m.Set(2, "2")
|
||||
res, err := m.MarshalJSON()
|
||||
t.Assert(res, []byte("{\"1\":\"\",\"2\":\"2\"}"))
|
||||
t.AssertNil(err)
|
||||
|
||||
m1 := gmap.NewListMapFrom(nil)
|
||||
res, err = m1.MarshalJSON()
|
||||
t.Assert(res, []byte("{}"))
|
||||
t.AssertNil(err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestListMap_DeepCopy(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := gmap.NewListMap()
|
||||
m.Set(1, "1")
|
||||
m.Set(2, "2")
|
||||
t.Assert(m.Size(), 2)
|
||||
|
||||
n := m.DeepCopy().(*gmap.ListMap)
|
||||
n.Set(1, "val1")
|
||||
t.AssertNE(m.Get(1), n.Get(1))
|
||||
})
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ import _ "github.com/gogf/gf/contrib/drivers/mysql/v2"
|
||||
import _ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
|
||||
```
|
||||
Note:
|
||||
- It does not support `Save/Replace` features.
|
||||
- It does not support `Save` features.
|
||||
|
||||
## PostgreSQL
|
||||
```
|
||||
|
||||
@ -3,13 +3,12 @@ module github.com/gogf/gf/contrib/drivers/clickhouse/v2
|
||||
go 1.15
|
||||
|
||||
require (
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.14
|
||||
github.com/ClickHouse/clickhouse-go/v2 v2.0.15
|
||||
github.com/gogf/gf/v2 v2.0.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
)
|
||||
|
||||
replace (
|
||||
github.com/ClickHouse/clickhouse-go/v2 => github.com/gogf/clickhouse-go/v2 v2.0.14-compatible
|
||||
github.com/ClickHouse/clickhouse-go/v2 => github.com/gogf/clickhouse-go/v2 v2.0.15-compatible
|
||||
github.com/gogf/gf/v2 => ../../../
|
||||
)
|
||||
|
||||
@ -34,8 +34,8 @@ github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/gogf/clickhouse-go/v2 v2.0.14-compatible h1:eTT+USRgOZyTXyHyIFzJU+utFUsNVPmrzmQaKS9zdoM=
|
||||
github.com/gogf/clickhouse-go/v2 v2.0.14-compatible/go.mod h1:NdPxn4Kfffa6Tv14otrFtbV+zH6v2xHVfDf4KICt/0s=
|
||||
github.com/gogf/clickhouse-go/v2 v2.0.15-compatible h1:VYgibtmI/u+hUQmtJpC7zzg1YJsDCXS052R7vCqGpDc=
|
||||
github.com/gogf/clickhouse-go/v2 v2.0.15-compatible/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
@ -96,8 +96,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y
|
||||
github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/paulmach/orb v0.7.0 h1:l6uxkg+vRU9QJkBHtzvYpkVb09tCIRwnEHbY5MNMNqo=
|
||||
github.com/paulmach/orb v0.7.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=
|
||||
github.com/paulmach/orb v0.7.1 h1:Zha++Z5OX/l168sqHK3k4z18LDvr+YAO/VjK0ReQ9rU=
|
||||
github.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=
|
||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
|
||||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||
@ -114,8 +114,9 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@ -173,8 +174,6 @@ golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32 h1:Js08h5hqB5xyWR789+QqueR6sDE8mk+YvpETZ+F6X9Y=
|
||||
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba h1:AyHWHCBVlIYI5rgEM3o+1PLd0sLPcIAoaUckGQMaWtw=
|
||||
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
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=
|
||||
@ -213,5 +212,6 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
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-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
@ -25,6 +25,7 @@ import (
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
// Driver is the driver for sqlite database.
|
||||
@ -35,6 +36,8 @@ type Driver struct {
|
||||
var (
|
||||
// tableFieldsMap caches the table information retrieved from database.
|
||||
tableFieldsMap = gmap.New(true)
|
||||
// Error
|
||||
ErrorSave = gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`)
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -147,10 +150,17 @@ func (d *Driver) TableFields(ctx context.Context, table string, schema ...string
|
||||
}
|
||||
fields = make(map[string]*gdb.TableField)
|
||||
for i, m := range result {
|
||||
mKey := ""
|
||||
if m["pk"].Bool() {
|
||||
mKey = "pri"
|
||||
}
|
||||
fields[strings.ToLower(m["name"].String())] = &gdb.TableField{
|
||||
Index: i,
|
||||
Name: strings.ToLower(m["name"].String()),
|
||||
Type: strings.ToLower(m["type"].String()),
|
||||
Index: i,
|
||||
Name: strings.ToLower(m["name"].String()),
|
||||
Type: strings.ToLower(m["type"].String()),
|
||||
Key: mKey,
|
||||
Default: m["dflt_value"].Val(),
|
||||
Null: !m["notnull"].Bool(),
|
||||
}
|
||||
}
|
||||
return fields
|
||||
@ -166,11 +176,73 @@ func (d *Driver) TableFields(ctx context.Context, table string, schema ...string
|
||||
func (d *Driver) DoInsert(ctx context.Context, link gdb.Link, table string, list gdb.List, option gdb.DoInsertOption) (result sql.Result, err error) {
|
||||
switch option.InsertOption {
|
||||
case gdb.InsertOptionSave:
|
||||
return nil, gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`)
|
||||
|
||||
case gdb.InsertOptionReplace:
|
||||
return nil, gerror.NewCode(gcode.CodeNotSupported, `Replace operation is not supported by sqlite driver`)
|
||||
return nil, ErrorSave
|
||||
case gdb.InsertOptionIgnore, gdb.InsertOptionReplace:
|
||||
var (
|
||||
keys []string // Field names.
|
||||
values []string // Value holder string array, like: (?,?,?)
|
||||
params []interface{} // Values that will be committed to underlying database driver.
|
||||
onDuplicateStr string // onDuplicateStr is used in "ON DUPLICATE KEY UPDATE" statement.
|
||||
)
|
||||
// Handle the field names and placeholders.
|
||||
for k := range list[0] {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
// Prepare the batch result pointer.
|
||||
var (
|
||||
charL, charR = d.GetChars()
|
||||
batchResult = new(gdb.SqlResult)
|
||||
keysStr = charL + strings.Join(keys, charR+","+charL) + charR
|
||||
operation = "INSERT OR IGNORE"
|
||||
)
|
||||
|
||||
if option.InsertOption == gdb.InsertOptionReplace {
|
||||
operation = "INSERT OR REPLACE"
|
||||
}
|
||||
var (
|
||||
listLength = len(list)
|
||||
valueHolder = make([]string, 0)
|
||||
)
|
||||
for i := 0; i < listLength; i++ {
|
||||
values = values[:0]
|
||||
// Note that the map type is unordered,
|
||||
// so it should use slice+key to retrieve the value.
|
||||
for _, k := range keys {
|
||||
if s, ok := list[i][k].(gdb.Raw); ok {
|
||||
values = append(values, gconv.String(s))
|
||||
} else {
|
||||
values = append(values, "?")
|
||||
params = append(params, list[i][k])
|
||||
}
|
||||
}
|
||||
valueHolder = append(valueHolder, "("+gstr.Join(values, ",")+")")
|
||||
// Batch package checks: It meets the batch number, or it is the last element.
|
||||
if len(valueHolder) == option.BatchCount || (i == listLength-1 && len(valueHolder) > 0) {
|
||||
var (
|
||||
stdSqlResult sql.Result
|
||||
affectedRows int64
|
||||
)
|
||||
stdSqlResult, err = d.DoExec(ctx, link, fmt.Sprintf(
|
||||
"%s INTO %s(%s) VALUES%s %s",
|
||||
operation, d.QuotePrefixTableName(table), keysStr,
|
||||
gstr.Join(valueHolder, ","),
|
||||
onDuplicateStr,
|
||||
), params...)
|
||||
if err != nil {
|
||||
return stdSqlResult, err
|
||||
}
|
||||
if affectedRows, err = stdSqlResult.RowsAffected(); err != nil {
|
||||
err = gerror.WrapCode(gcode.CodeDbOperationError, err, `sql.Result.RowsAffected failed`)
|
||||
return stdSqlResult, err
|
||||
} else {
|
||||
batchResult.Result = stdSqlResult
|
||||
batchResult.Affected += affectedRows
|
||||
}
|
||||
params = params[:0]
|
||||
valueHolder = valueHolder[:0]
|
||||
}
|
||||
}
|
||||
return batchResult, nil
|
||||
default:
|
||||
return d.Core.DoInsert(ctx, link, table, list, option)
|
||||
}
|
||||
|
||||
161
contrib/drivers/sqlite/sqlite_0_test.go
Normal file
161
contrib/drivers/sqlite/sqlite_0_test.go
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package sqlite_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/v2/container/garray"
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
var (
|
||||
db gdb.DB
|
||||
dbPrefix gdb.DB
|
||||
dbInvalid gdb.DB
|
||||
configNode gdb.ConfigNode
|
||||
dbDir = gfile.Temp("sqlite")
|
||||
ctx = gctx.New()
|
||||
|
||||
// Error
|
||||
ErrorSave = gerror.NewCode(gcode.CodeNotSupported, `Save operation is not supported by sqlite driver`)
|
||||
)
|
||||
|
||||
const (
|
||||
TableSize = 10
|
||||
TableName = "user"
|
||||
TestSchema1 = "test1"
|
||||
TestSchema2 = "test2"
|
||||
TableNamePrefix = "gf_"
|
||||
CreateTime = "2018-10-24 10:00:00"
|
||||
DBGroupTest = "test"
|
||||
DBGroupPrefix = "prefix"
|
||||
DBGroupInvalid = "invalid"
|
||||
)
|
||||
|
||||
func init() {
|
||||
fmt.Println("init sqlite db start")
|
||||
|
||||
if err := gfile.Mkdir(dbDir); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
|
||||
fmt.Println("init sqlite db dir: ", dbDir)
|
||||
|
||||
configNode = gdb.ConfigNode{
|
||||
Type: "sqlite",
|
||||
Link: gfile.Join(dbDir, "test.db"),
|
||||
Charset: "utf8",
|
||||
}
|
||||
nodePrefix := configNode
|
||||
nodePrefix.Prefix = TableNamePrefix
|
||||
|
||||
nodeInvalid := configNode
|
||||
|
||||
gdb.AddConfigNode(DBGroupTest, configNode)
|
||||
gdb.AddConfigNode(DBGroupPrefix, nodePrefix)
|
||||
gdb.AddConfigNode(DBGroupInvalid, nodeInvalid)
|
||||
gdb.AddConfigNode(gdb.DefaultGroupName, configNode)
|
||||
|
||||
// Default db.
|
||||
if r, err := gdb.NewByGroup(); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
db = r
|
||||
}
|
||||
|
||||
// Prefix db.
|
||||
if r, err := gdb.NewByGroup(DBGroupPrefix); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
dbPrefix = r
|
||||
}
|
||||
|
||||
// Invalid db.
|
||||
if r, err := gdb.NewByGroup(DBGroupInvalid); err != nil {
|
||||
gtest.Error(err)
|
||||
} else {
|
||||
dbInvalid = r
|
||||
}
|
||||
|
||||
fmt.Println("init sqlite db finish")
|
||||
}
|
||||
|
||||
func createTable(table ...string) string {
|
||||
return createTableWithDb(db, table...)
|
||||
}
|
||||
|
||||
func createInitTable(table ...string) string {
|
||||
return createInitTableWithDb(db, table...)
|
||||
}
|
||||
|
||||
func dropTable(table string) {
|
||||
dropTableWithDb(db, table)
|
||||
}
|
||||
|
||||
func createTableWithDb(db gdb.DB, table ...string) (name string) {
|
||||
if len(table) > 0 {
|
||||
name = table[0]
|
||||
} else {
|
||||
name = fmt.Sprintf(`%s_%d`, TableName, gtime.TimestampNano())
|
||||
}
|
||||
dropTableWithDb(db, name)
|
||||
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf(`
|
||||
CREATE TABLE %s (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT
|
||||
UNIQUE
|
||||
NOT NULL,
|
||||
passport VARCHAR(45) NOT NULL
|
||||
DEFAULT passport,
|
||||
password VARCHAR(128) NOT NULL
|
||||
DEFAULT password,
|
||||
nickname VARCHAR(45),
|
||||
create_time DATETIME
|
||||
);
|
||||
`, name,
|
||||
)); err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func createInitTableWithDb(db gdb.DB, table ...string) (name string) {
|
||||
name = createTableWithDb(db, table...)
|
||||
array := garray.New(true)
|
||||
for i := 1; i <= TableSize; i++ {
|
||||
array.Append(g.Map{
|
||||
"id": i,
|
||||
"passport": fmt.Sprintf(`user_%d`, i),
|
||||
"password": fmt.Sprintf(`pass_%d`, i),
|
||||
"nickname": fmt.Sprintf(`name_%d`, i),
|
||||
"create_time": gtime.NewFromStr(CreateTime).String(),
|
||||
})
|
||||
}
|
||||
|
||||
result, err := db.Insert(ctx, name, array.Slice())
|
||||
gtest.AssertNil(err)
|
||||
|
||||
n, e := result.RowsAffected()
|
||||
gtest.Assert(e, nil)
|
||||
gtest.Assert(n, TableSize)
|
||||
return
|
||||
}
|
||||
|
||||
func dropTableWithDb(db gdb.DB, table string) {
|
||||
if _, err := db.Exec(ctx, fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)); err != nil {
|
||||
gtest.Error(err)
|
||||
}
|
||||
}
|
||||
1551
contrib/drivers/sqlite/sqlite_core_test.go
Normal file
1551
contrib/drivers/sqlite/sqlite_core_test.go
Normal file
File diff suppressed because it is too large
Load Diff
4084
contrib/drivers/sqlite/sqlite_model_test.go
Normal file
4084
contrib/drivers/sqlite/sqlite_model_test.go
Normal file
File diff suppressed because it is too large
Load Diff
79
contrib/registry/etcd/README.MD
Normal file
79
contrib/registry/etcd/README.MD
Normal file
@ -0,0 +1,79 @@
|
||||
# GoFrame Etcd Registry
|
||||
|
||||
|
||||
Use `etcd` as service registration and discovery management.
|
||||
|
||||
|
||||
## Installation
|
||||
```
|
||||
go get -u -v github.com/gogf/gf/contrib/registry/etcd/v2
|
||||
```
|
||||
suggested using `go.mod`:
|
||||
```
|
||||
require github.com/gogf/gf/contrib/registry/etcd/v2 latest
|
||||
```
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
### Reference example
|
||||
|
||||
[server](example/registry/etcd/server/main.go)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
|
||||
|
||||
s := g.Server(`hello.svc`)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
g.Log().Info(r.Context(), `request received`)
|
||||
r.Response.Write(`Hello world`)
|
||||
})
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
|
||||
[client](example/registry/etcd/client/main.go)
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/contrib/registry/etcd/v2"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gsel"
|
||||
"github.com/gogf/gf/v2/net/gsvc"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
gsvc.SetRegistry(etcd.New(`127.0.0.1:2379`))
|
||||
gsel.SetBuilder(gsel.NewBuilderRoundRobin())
|
||||
|
||||
client := g.Client()
|
||||
for i := 0; i < 100; i++ {
|
||||
res, err := client.Get(gctx.New(), `http://hello.svc/`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(res.ReadAllString())
|
||||
res.Close()
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
`GoFrame etcd` is licensed under the [MIT License](../../../LICENSE), 100% free and open-source, forever.
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
English | [简体中文](README_ZH.MD)
|
||||
|
||||
Use Polaris mesh as service registration, discovery management and heartbeat reporting
|
||||
Use `PolarisMesh` as service registration, discovery management and heartbeat reporting.
|
||||
|
||||
|
||||
## Installation
|
||||
@ -14,11 +14,6 @@ suggested using `go.mod`:
|
||||
require github.com/gogf/gf/contrib/registry/polaris/v2 latest
|
||||
```
|
||||
|
||||
## Limitation
|
||||
```
|
||||
golang version >= 1.15
|
||||
```
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
@ -50,7 +45,6 @@ func main() {
|
||||
})
|
||||
s.Run()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
[client](example/registry/polaris/client/main.go)
|
||||
@ -85,7 +79,6 @@ func main() {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.MD) | 简体中文
|
||||
|
||||
使用Polarismesh作为服务注册、发现管理和心跳上报
|
||||
使用`PolarisMesh`作为服务注册、发现管理和心跳上报。
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
@ -331,9 +331,6 @@ var (
|
||||
// in the field name as it conflicts with "db.table.field" pattern in SOME situations.
|
||||
regularFieldNameWithoutDotRegPattern = `^[\w\-]+$`
|
||||
|
||||
// tableFieldsMap caches the table information retrieved from database.
|
||||
tableFieldsMap = gmap.New(true)
|
||||
|
||||
// allDryRun sets dry-run feature for all database connections.
|
||||
// It is commonly used for command options for convenience.
|
||||
allDryRun = false
|
||||
@ -399,8 +396,7 @@ func doNewByNode(node ConfigNode, group string) (db DB, err error) {
|
||||
config: &node,
|
||||
}
|
||||
if v, ok := driverMap[node.Type]; ok {
|
||||
c.db, err = v.New(c, &node)
|
||||
if err != nil {
|
||||
if c.db, err = v.New(c, &node); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.db, nil
|
||||
|
||||
@ -13,6 +13,8 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Config is the configuration management object.
|
||||
@ -72,6 +74,12 @@ func SetConfig(config Config) {
|
||||
defer instances.Clear()
|
||||
configs.Lock()
|
||||
defer configs.Unlock()
|
||||
for k, nodes := range config {
|
||||
for i, node := range nodes {
|
||||
nodes[i] = parseConfigNode(node)
|
||||
}
|
||||
config[k] = nodes
|
||||
}
|
||||
configs.config = config
|
||||
}
|
||||
|
||||
@ -80,6 +88,9 @@ func SetConfigGroup(group string, nodes ConfigGroup) {
|
||||
defer instances.Clear()
|
||||
configs.Lock()
|
||||
defer configs.Unlock()
|
||||
for i, node := range nodes {
|
||||
nodes[i] = parseConfigNode(node)
|
||||
}
|
||||
configs.config[group] = nodes
|
||||
}
|
||||
|
||||
@ -88,7 +99,19 @@ func AddConfigNode(group string, node ConfigNode) {
|
||||
defer instances.Clear()
|
||||
configs.Lock()
|
||||
defer configs.Unlock()
|
||||
configs.config[group] = append(configs.config[group], node)
|
||||
configs.config[group] = append(configs.config[group], parseConfigNode(node))
|
||||
}
|
||||
|
||||
// parseConfigNode parses `Link` configuration syntax.
|
||||
func parseConfigNode(node ConfigNode) ConfigNode {
|
||||
if node.Link != "" && node.Type == "" {
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)
|
||||
if len(match) == 3 {
|
||||
node.Type = gstr.Trim(match[1])
|
||||
node.Link = gstr.Trim(match[2])
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
// AddDefaultConfigNode adds one node configuration to configuration of default group.
|
||||
|
||||
@ -72,6 +72,6 @@ func (m *Model) Group(groupBy ...string) *Model {
|
||||
if model.groupBy != "" {
|
||||
model.groupBy += ","
|
||||
}
|
||||
model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ","))
|
||||
model.groupBy += model.db.GetCore().QuoteString(strings.Join(groupBy, ","))
|
||||
return model
|
||||
}
|
||||
|
||||
@ -168,9 +168,13 @@ func Test_Error(t *testing.T) {
|
||||
_, err = conn.Do(ctx, "Subscribe", "gf")
|
||||
t.AssertNil(err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
_, err = redis.Do(ctx, "PUBLISH", "gf", "test")
|
||||
t.AssertNil(err)
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
v, err = conn.Receive(ctx)
|
||||
t.AssertNil(err)
|
||||
t.Assert(v.Val().(*gredis.Subscription).Channel, "gf")
|
||||
|
||||
@ -222,6 +222,9 @@ func Code(err error) gcode.Code {
|
||||
if e, ok := err.(iNext); ok {
|
||||
return Code(e.Next())
|
||||
}
|
||||
if e, ok := err.(iUnwrap); ok {
|
||||
return Code(e.Unwrap())
|
||||
}
|
||||
return gcode.CodeNil
|
||||
}
|
||||
|
||||
@ -236,6 +239,9 @@ func Cause(err error) error {
|
||||
if e, ok := err.(iNext); ok {
|
||||
return Cause(e.Next())
|
||||
}
|
||||
if e, ok := err.(iUnwrap); ok {
|
||||
return Cause(e.Unwrap())
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@ -49,3 +49,9 @@ type iNext interface {
|
||||
Error() string
|
||||
Next() error
|
||||
}
|
||||
|
||||
// iUnwrap is the interface for Unwrap feature.
|
||||
type iUnwrap interface {
|
||||
Error() string
|
||||
Unwrap() error
|
||||
}
|
||||
|
||||
@ -55,3 +55,30 @@ func ExampleWrapCodef() {
|
||||
// It's Custom Error: permission denied
|
||||
// 10000
|
||||
}
|
||||
|
||||
func ExampleEqual() {
|
||||
err1 := errors.New("permission denied")
|
||||
err2 := gerror.New("permission denied")
|
||||
err3 := gerror.NewCode(gcode.CodeNotAuthorized, "permission denied")
|
||||
fmt.Println(gerror.Equal(err1, err2))
|
||||
fmt.Println(gerror.Equal(err2, err3))
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleIs() {
|
||||
err1 := errors.New("permission denied")
|
||||
err2 := gerror.Wrap(err1, "operation failed")
|
||||
fmt.Println(gerror.Is(err1, err1))
|
||||
fmt.Println(gerror.Is(err2, err2))
|
||||
fmt.Println(gerror.Is(err2, err1))
|
||||
fmt.Println(gerror.Is(err1, err2))
|
||||
|
||||
// Output:
|
||||
// false
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
}
|
||||
|
||||
@ -7,8 +7,8 @@ require (
|
||||
github.com/gogf/gf/contrib/registry/etcd/v2 v2.1.0-rc3.0.20220523034830-510fa3faf03f
|
||||
github.com/gogf/gf/contrib/registry/polaris/v2 v2.0.0-rc2
|
||||
github.com/gogf/gf/contrib/trace/jaeger/v2 v2.0.0-rc2
|
||||
github.com/gogf/gf/v2 v2.1.0-rc3.0.20220523034830-510fa3faf03f
|
||||
github.com/gogf/katyusha v0.4.0
|
||||
github.com/gogf/gf/v2 v2.1.0-rc4.0.20220620123459-52056644d499
|
||||
github.com/gogf/katyusha v0.4.1-0.20220620125113-f55d6f739773
|
||||
github.com/gogo/protobuf v1.3.2
|
||||
github.com/golang/protobuf v1.5.2
|
||||
github.com/polarismesh/polaris-go v1.2.0-beta.0.0.20220517041223-596a6a63b00f
|
||||
|
||||
@ -111,8 +111,8 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogf/katyusha v0.4.0 h1:mQVfXHhzC+UQf11Q8HAk9IOhQZ1VMXqGUqezyywZUOs=
|
||||
github.com/gogf/katyusha v0.4.0/go.mod h1:nqsIWBsImnq9+OLlfB6iNef6ZLRyR2L1Bnk9h2aZvKs=
|
||||
github.com/gogf/katyusha v0.4.1-0.20220620125113-f55d6f739773 h1:YQBLawktoymYtPGs9idE9JS5Wqd3SjIzUEZOPKCdSw0=
|
||||
github.com/gogf/katyusha v0.4.1-0.20220620125113-f55d6f739773/go.mod h1:Z0GCeHXz1UI0HtA0K45c6TzEGM4DL/PLatS747/WarI=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
|
||||
25
example/trace/processes/gcmd/main.go
Normal file
25
example/trace/processes/gcmd/main.go
Normal file
@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
)
|
||||
|
||||
var (
|
||||
Main = &gcmd.Command{
|
||||
Name: "main",
|
||||
Brief: "main process",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
g.Log().Debug(ctx, `this is main process`)
|
||||
return gproc.ShellRun(ctx, `go run sub/sub.go`)
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
Main.Run(gctx.New())
|
||||
}
|
||||
24
example/trace/processes/gcmd/sub/sub.go
Normal file
24
example/trace/processes/gcmd/sub/sub.go
Normal file
@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
var (
|
||||
Sub = &gcmd.Command{
|
||||
Name: "sub",
|
||||
Brief: "sub process",
|
||||
Func: func(ctx context.Context, parser *gcmd.Parser) (err error) {
|
||||
g.Log().Debug(ctx, `this is sub process`)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
func main() {
|
||||
Sub.Run(gctx.New())
|
||||
}
|
||||
15
example/trace/processes/gproc/main.go
Normal file
15
example/trace/processes/gproc/main.go
Normal file
@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gproc"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := gctx.New()
|
||||
g.Log().Debug(ctx, `this is main process`)
|
||||
if err := gproc.ShellRun(ctx, `go run sub/sub.go`); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
11
example/trace/processes/gproc/sub/sub.go
Normal file
11
example/trace/processes/gproc/sub/sub.go
Normal file
@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ctx := gctx.New()
|
||||
g.Log().Debug(ctx, `this is sub process`)
|
||||
}
|
||||
@ -63,14 +63,14 @@ func Throw(exception interface{}) {
|
||||
|
||||
// Try implements try... logistics using internal panic...recover.
|
||||
// It returns error if any exception occurs, or else it returns nil.
|
||||
func Try(try func()) (err error) {
|
||||
return gutil.Try(try)
|
||||
func Try(ctx context.Context, try func(ctx context.Context)) (err error) {
|
||||
return gutil.Try(ctx, try)
|
||||
}
|
||||
|
||||
// TryCatch implements try...catch... logistics using internal panic...recover.
|
||||
// It automatically calls function `catch` if any exception occurs ans passes the exception as an error.
|
||||
func TryCatch(try func(), catch ...func(exception error)) {
|
||||
gutil.TryCatch(try, catch...)
|
||||
func TryCatch(ctx context.Context, try func(ctx context.Context), catch ...func(ctx context.Context, exception error)) {
|
||||
gutil.TryCatch(ctx, try, catch...)
|
||||
}
|
||||
|
||||
// IsNil checks whether given `value` is nil.
|
||||
|
||||
@ -16,8 +16,6 @@ import (
|
||||
"github.com/gogf/gf/v2/internal/consts"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
@ -173,13 +171,5 @@ func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
|
||||
if _, v := gutil.MapPossibleItemByKey(nodeMap, "Link"); v != nil {
|
||||
node.Link = gconv.String(v)
|
||||
}
|
||||
// Parse `Link` configuration syntax.
|
||||
if node.Link != "" && node.Type == "" {
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, node.Link)
|
||||
if len(match) == 3 {
|
||||
node.Type = gstr.Trim(match[1])
|
||||
node.Link = gstr.Trim(match[2])
|
||||
}
|
||||
}
|
||||
return node
|
||||
}
|
||||
|
||||
@ -83,6 +83,9 @@ func Server(name ...interface{}) *ghttp.Server {
|
||||
ctx,
|
||||
fmt.Sprintf(`%s.%s.%s`, configNodeName, instanceName, consts.ConfigNodeNameLogger),
|
||||
).Map()
|
||||
if len(serverLoggerConfigMap) == 0 && len(serverConfigMap) > 0 {
|
||||
serverLoggerConfigMap = gconv.Map(serverConfigMap[consts.ConfigNodeNameLogger])
|
||||
}
|
||||
if len(serverLoggerConfigMap) > 0 {
|
||||
if err = server.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil {
|
||||
panic(err)
|
||||
|
||||
@ -79,13 +79,17 @@ func New() *Client {
|
||||
func (c *Client) Clone() *Client {
|
||||
newClient := New()
|
||||
*newClient = *c
|
||||
newClient.header = make(map[string]string)
|
||||
newClient.cookies = make(map[string]string)
|
||||
for k, v := range c.header {
|
||||
newClient.header[k] = v
|
||||
if len(c.header) > 0 {
|
||||
newClient.header = make(map[string]string)
|
||||
for k, v := range c.header {
|
||||
newClient.header[k] = v
|
||||
}
|
||||
}
|
||||
for k, v := range c.cookies {
|
||||
newClient.cookies[k] = v
|
||||
if len(c.cookies) > 0 {
|
||||
newClient.cookies = make(map[string]string)
|
||||
for k, v := range c.cookies {
|
||||
newClient.cookies[k] = v
|
||||
}
|
||||
}
|
||||
return newClient
|
||||
}
|
||||
|
||||
@ -12,6 +12,9 @@ import (
|
||||
|
||||
// Prefix is a chaining function,
|
||||
// which sets the URL prefix for next request of this client.
|
||||
// Eg:
|
||||
// Prefix("http://127.0.0.1:8199/api/v1")
|
||||
// Prefix("http://127.0.0.1:8199/api/v2")
|
||||
func (c *Client) Prefix(prefix string) *Client {
|
||||
newClient := c.Clone()
|
||||
newClient.SetPrefix(prefix)
|
||||
|
||||
@ -37,10 +37,7 @@ func getResponseBody(res *http.Response) string {
|
||||
// RawRequest returns the raw content of the request.
|
||||
func (r *Response) RawRequest() string {
|
||||
// Response can be nil.
|
||||
if r == nil {
|
||||
return ""
|
||||
}
|
||||
if r.request == nil {
|
||||
if r == nil || r.request == nil {
|
||||
return ""
|
||||
}
|
||||
// DumpRequestOut writes more request headers than DumpRequest, such as User-Agent.
|
||||
|
||||
97
net/gclient/gclient_request_obj.go
Normal file
97
net/gclient/gclient_request_obj.go
Normal file
@ -0,0 +1,97 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/goai"
|
||||
"github.com/gogf/gf/v2/text/gregex"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gmeta"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
)
|
||||
|
||||
// DoRequestObj does HTTP request using standard request/response object.
|
||||
// The request object `req` is defined like:
|
||||
// type UseCreateReq struct {
|
||||
// g.Meta `path:"/user" method:"put"`
|
||||
// // other fields....
|
||||
// }
|
||||
// The response object `res` should be a pointer type. It automatically converts result
|
||||
// to given object `res` is success.
|
||||
// Eg:
|
||||
// var (
|
||||
// req = UseCreateReq{}
|
||||
// res *UseCreateRes
|
||||
// )
|
||||
// DoRequestObj(ctx, req, &res)
|
||||
func (c *Client) DoRequestObj(ctx context.Context, req, res interface{}) error {
|
||||
var (
|
||||
method = gmeta.Get(req, goai.TagNameMethod).String()
|
||||
path = gmeta.Get(req, goai.TagNamePath).String()
|
||||
)
|
||||
if method == "" {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`no "%s" tag found in request object: %s`,
|
||||
goai.TagNameMethod, reflect.TypeOf(req).String(),
|
||||
)
|
||||
}
|
||||
if path == "" {
|
||||
return gerror.NewCodef(
|
||||
gcode.CodeInvalidParameter,
|
||||
`no "%s" tag found in request object: %s`,
|
||||
goai.TagNamePath, reflect.TypeOf(req).String(),
|
||||
)
|
||||
}
|
||||
path = c.handlePathForObjRequest(path, req)
|
||||
switch gstr.ToUpper(method) {
|
||||
case
|
||||
http.MethodGet,
|
||||
http.MethodPut,
|
||||
http.MethodPost,
|
||||
http.MethodDelete,
|
||||
http.MethodHead,
|
||||
http.MethodPatch,
|
||||
http.MethodConnect,
|
||||
http.MethodOptions,
|
||||
http.MethodTrace:
|
||||
if result := c.RequestVar(ctx, method, path, req); res != nil && !result.IsEmpty() {
|
||||
return result.Scan(res)
|
||||
}
|
||||
return nil
|
||||
|
||||
default:
|
||||
return gerror.Newf(`invalid HTTP method "%s"`, method)
|
||||
}
|
||||
}
|
||||
|
||||
// handlePathForObjRequest replaces parameters in `path` with parameters from request object.
|
||||
// Eg:
|
||||
// /order/{id} -> /order/1
|
||||
// /user/{name} -> /order/john
|
||||
func (c *Client) handlePathForObjRequest(path string, req interface{}) string {
|
||||
if gstr.Contains(path, "{") {
|
||||
requestParamsMap := gconv.Map(req)
|
||||
if len(requestParamsMap) > 0 {
|
||||
path, _ = gregex.ReplaceStringFuncMatch(`\{(\w+)\}`, path, func(match []string) string {
|
||||
foundKey, foundValue := gutil.MapPossibleItemByKey(requestParamsMap, match[1])
|
||||
if foundKey != "" {
|
||||
return gconv.String(foundValue)
|
||||
}
|
||||
return match[0]
|
||||
})
|
||||
}
|
||||
}
|
||||
return path
|
||||
}
|
||||
@ -7,6 +7,7 @@
|
||||
package gclient
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
||||
@ -69,6 +70,13 @@ func (r *Response) ReadAllString() string {
|
||||
return string(r.ReadAll())
|
||||
}
|
||||
|
||||
// SetBodyContent overwrites response content with custom one.
|
||||
func (r *Response) SetBodyContent(content []byte) {
|
||||
buffer := bytes.NewBuffer(content)
|
||||
r.Body = ioutil.NopCloser(buffer)
|
||||
r.ContentLength = int64(buffer.Len())
|
||||
}
|
||||
|
||||
// Close closes the response when it will never be used.
|
||||
func (r *Response) Close() error {
|
||||
if r == nil || r.Response == nil {
|
||||
|
||||
@ -8,16 +8,27 @@ package gclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/debug/gdebug"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/os/gctx"
|
||||
"github.com/gogf/gf/v2/os/gfile"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
)
|
||||
|
||||
var (
|
||||
crtFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/server.crt"
|
||||
keyFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/server.key"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Default server for client.
|
||||
p := 8999
|
||||
@ -53,10 +64,39 @@ func init() {
|
||||
)
|
||||
})
|
||||
group.HEAD("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("head")
|
||||
r.Response.Writef(
|
||||
"HEAD: form: %d, %s",
|
||||
r.GetForm("id").Int(),
|
||||
r.GetForm("name").String(),
|
||||
)
|
||||
})
|
||||
group.PATCH("/", func(r *ghttp.Request) {
|
||||
r.Response.Writef(
|
||||
"PATCH: form: %d, %s",
|
||||
r.GetForm("id").Int(),
|
||||
r.GetForm("name").String(),
|
||||
)
|
||||
})
|
||||
group.CONNECT("/", func(r *ghttp.Request) {
|
||||
r.Response.Writef(
|
||||
"CONNECT: form: %d, %s",
|
||||
r.GetForm("id").Int(),
|
||||
r.GetForm("name").String(),
|
||||
)
|
||||
})
|
||||
group.OPTIONS("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("options")
|
||||
r.Response.Writef(
|
||||
"OPTIONS: form: %d, %s",
|
||||
r.GetForm("id").Int(),
|
||||
r.GetForm("name").String(),
|
||||
)
|
||||
})
|
||||
group.TRACE("/", func(r *ghttp.Request) {
|
||||
r.Response.Writef(
|
||||
"TRACE: form: %d, %s",
|
||||
r.GetForm("id").Int(),
|
||||
r.GetForm("name").String(),
|
||||
)
|
||||
})
|
||||
})
|
||||
// Client chaining operations handlers.
|
||||
@ -138,6 +178,11 @@ func ExampleClient_Clone() {
|
||||
// {"id":1,"name":"john"}
|
||||
}
|
||||
|
||||
func fromHex(s string) []byte {
|
||||
b, _ := hex.DecodeString(s)
|
||||
return b
|
||||
}
|
||||
|
||||
func ExampleNew_MultiConn_Recommend() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
@ -274,6 +319,71 @@ func ExampleClient_PostBytes() {
|
||||
// POST: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_DeleteBytes() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(string(g.Client().DeleteBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// DELETE: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_HeadBytes() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(string(g.Client().HeadBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleClient_PatchBytes() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(string(g.Client().PatchBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// PATCH: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_ConnectBytes() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(string(g.Client().ConnectBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// CONNECT: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_OptionsBytes() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(string(g.Client().OptionsBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// OPTIONS: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_TraceBytes() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(string(g.Client().TraceBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// TRACE: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_PostContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().PostContent(ctx, url, g.Map{
|
||||
@ -343,6 +453,19 @@ func ExampleClient_Get() {
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_Put() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Put(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
// PUT: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_GetBytes() {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
@ -357,6 +480,20 @@ func ExampleClient_GetBytes() {
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_PutBytes() {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
url = "http://127.0.0.1:8999"
|
||||
)
|
||||
fmt.Println(string(g.Client().PutBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// PUT: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_GetContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().GetContent(ctx, url, g.Map{
|
||||
@ -397,45 +534,52 @@ func ExampleClient_SetProxy() {
|
||||
client := g.Client()
|
||||
client.SetProxy("http://127.0.0.1:1081")
|
||||
client.SetTimeout(5 * time.Second) // it's suggested to set http client timeout
|
||||
response, err := client.Get(ctx, "https://api.ip.sb/ip")
|
||||
resp, err := client.Get(ctx, "http://127.0.0.1:8999")
|
||||
if err != nil {
|
||||
// err is not nil when your proxy server is down.
|
||||
// eg. Get "https://api.ip.sb/ip": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
fmt.Println(err)
|
||||
// eg. Get "http://127.0.0.1:8999": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
}
|
||||
response.RawDump()
|
||||
fmt.Println(err != nil)
|
||||
resp.Close()
|
||||
|
||||
// connect to a http proxy server which needs auth
|
||||
client.SetProxy("http://user:password:127.0.0.1:1081")
|
||||
client.SetTimeout(5 * time.Second) // it's suggested to set http client timeout
|
||||
response, err = client.Get(ctx, "https://api.ip.sb/ip")
|
||||
resp, err = client.Get(ctx, "http://127.0.0.1:8999")
|
||||
if err != nil {
|
||||
// err is not nil when your proxy server is down.
|
||||
// eg. Get "https://api.ip.sb/ip": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
fmt.Println(err)
|
||||
// eg. Get "http://127.0.0.1:8999": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
}
|
||||
response.RawDump()
|
||||
fmt.Println(err != nil)
|
||||
resp.Close()
|
||||
|
||||
// connect to a socks5 proxy server
|
||||
client.SetProxy("socks5://127.0.0.1:1080")
|
||||
client.SetTimeout(5 * time.Second) // it's suggested to set http client timeout
|
||||
response, err = client.Get(ctx, "https://api.ip.sb/ip")
|
||||
resp, err = client.Get(ctx, "http://127.0.0.1:8999")
|
||||
if err != nil {
|
||||
// err is not nil when your proxy server is down.
|
||||
// eg. Get "https://api.ip.sb/ip": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
fmt.Println(err)
|
||||
// eg. Get "http://127.0.0.1:8999": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
}
|
||||
fmt.Println(response.RawResponse())
|
||||
fmt.Println(err != nil)
|
||||
resp.Close()
|
||||
|
||||
// connect to a socks5 proxy server which needs auth
|
||||
client.SetProxy("socks5://user:password@127.0.0.1:1080")
|
||||
client.SetTimeout(5 * time.Second) // it's suggested to set http client timeout
|
||||
response, err = client.Get(ctx, "https://api.ip.sb/ip")
|
||||
resp, err = client.Get(ctx, "http://127.0.0.1:8999")
|
||||
if err != nil {
|
||||
// err is not nil when your proxy server is down.
|
||||
// eg. Get "https://api.ip.sb/ip": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
fmt.Println(err)
|
||||
// eg. Get "http://127.0.0.1:8999": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
}
|
||||
fmt.Println(response.RawResponse())
|
||||
fmt.Println(err != nil)
|
||||
resp.Close()
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
// true
|
||||
}
|
||||
|
||||
// ExampleClientChain_Proxy a chain version of example for `gclient.Client.Proxy` method.
|
||||
@ -448,20 +592,521 @@ func ExampleClient_Proxy() {
|
||||
ctx = context.Background()
|
||||
)
|
||||
client := g.Client()
|
||||
response, err := client.Proxy("http://127.0.0.1:1081").Get(ctx, "https://api.ip.sb/ip")
|
||||
if err != nil {
|
||||
// err is not nil when your proxy server is down.
|
||||
// eg. Get "https://api.ip.sb/ip": proxyconnect tcp: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(response.RawResponse())
|
||||
_, err := client.Proxy("http://127.0.0.1:1081").Get(ctx, "http://127.0.0.1:8999")
|
||||
fmt.Println(err != nil)
|
||||
|
||||
client2 := g.Client()
|
||||
response, err = client2.Proxy("socks5://127.0.0.1:1080").Get(ctx, "https://api.ip.sb/ip")
|
||||
if err != nil {
|
||||
// err is not nil when your proxy server is down.
|
||||
// eg. Get "https://api.ip.sb/ip": socks connect tcp 127.0.0.1:1087->api.ip.sb:443: dial tcp 127.0.0.1:1087: connect: connection refused
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(response.RawResponse())
|
||||
_, err = client2.Proxy("socks5://127.0.0.1:1080").Get(ctx, "http://127.0.0.1:8999")
|
||||
fmt.Println(err != nil)
|
||||
|
||||
client3 := g.Client()
|
||||
_, err = client3.Proxy("").Get(ctx, "http://127.0.0.1:8999")
|
||||
fmt.Println(err != nil)
|
||||
|
||||
client4 := g.Client()
|
||||
url := "http://127.0.0.1:1081" + string([]byte{0x7f})
|
||||
_, err = client4.Proxy(url).Get(ctx, "http://127.0.0.1:8999")
|
||||
fmt.Println(err != nil)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
// true
|
||||
// false
|
||||
// false
|
||||
}
|
||||
|
||||
func ExampleClient_Prefix() {
|
||||
p := gtcp.MustGetFreePort()
|
||||
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
prefix = fmt.Sprintf("http://127.0.0.1:%d/api/v1/", p)
|
||||
)
|
||||
|
||||
s := g.Server(p)
|
||||
// HTTP method handlers.
|
||||
s.Group("/api", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/v1/prefix", func(r *ghttp.Request) {
|
||||
r.Response.Write("this is v1 prefix")
|
||||
})
|
||||
group.GET("/v1/hello", func(r *ghttp.Request) {
|
||||
r.Response.Write("this is v1 hello")
|
||||
})
|
||||
})
|
||||
s.SetAccessLogEnabled(false)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.SetPort(p)
|
||||
s.Start()
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
|
||||
// Add Client URI Prefix
|
||||
client := g.Client().Prefix(prefix)
|
||||
|
||||
fmt.Println(string(client.GetBytes(ctx, "prefix")))
|
||||
fmt.Println(string(client.GetBytes(ctx, "hello")))
|
||||
|
||||
// Output:
|
||||
// this is v1 prefix
|
||||
// this is v1 hello
|
||||
}
|
||||
|
||||
func ExampleClient_Retry() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
url = "http://127.0.0.1:8999"
|
||||
)
|
||||
client := g.Client().Retry(2, time.Second)
|
||||
|
||||
fmt.Println(string(client.GetBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_RedirectLimit() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
url = "http://127.0.0.1:8999"
|
||||
)
|
||||
client := g.Client().RedirectLimit(1)
|
||||
|
||||
fmt.Println(string(client.GetBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_SetBrowserMode() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
url = "http://127.0.0.1:8999"
|
||||
)
|
||||
client := g.Client().SetBrowserMode(true)
|
||||
|
||||
fmt.Println(string(client.GetBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_SetHeader() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
url = "http://127.0.0.1:8999"
|
||||
)
|
||||
client := g.Client()
|
||||
client.SetHeader("Server", "GoFrameServer")
|
||||
client.SetHeader("Client", "g.Client()")
|
||||
|
||||
fmt.Println(string(client.GetBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_SetRedirectLimit() {
|
||||
go func() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/hello", func(r *ghttp.Request) {
|
||||
r.Response.Writeln("hello world")
|
||||
})
|
||||
s.BindHandler("/back", func(r *ghttp.Request) {
|
||||
r.Response.RedirectBack()
|
||||
})
|
||||
s.SetDumpRouterMap(false)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}()
|
||||
|
||||
time.Sleep(time.Second)
|
||||
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
urlHello = "http://127.0.0.1:8199/hello"
|
||||
urlBack = "http://127.0.0.1:8199/back"
|
||||
)
|
||||
client := g.Client().SetRedirectLimit(1)
|
||||
client.SetHeader("Referer", urlHello)
|
||||
|
||||
resp, err := client.DoRequest(ctx, http.MethodGet, urlBack, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
if err == nil {
|
||||
fmt.Println(resp.ReadAllString())
|
||||
resp.Close()
|
||||
}
|
||||
|
||||
client.SetRedirectLimit(2)
|
||||
resp, err = client.DoRequest(ctx, http.MethodGet, urlBack, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
if err == nil {
|
||||
fmt.Println(resp.ReadAllString())
|
||||
resp.Close()
|
||||
}
|
||||
|
||||
// Output:
|
||||
// Found
|
||||
// hello world
|
||||
}
|
||||
|
||||
func ExampleClient_SetTLSKeyCrt() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
url = "http://127.0.0.1:8999"
|
||||
testCrtFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/upload/file1.txt"
|
||||
testKeyFile = gfile.Dir(gdebug.CallerFilePath()) + gfile.Separator + "testdata/upload/file2.txt"
|
||||
)
|
||||
client := g.Client()
|
||||
client.SetTLSKeyCrt(testCrtFile, testKeyFile)
|
||||
client.SetTLSKeyCrt(crtFile, keyFile)
|
||||
fmt.Println(string(client.GetBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_SetTLSConfig() {
|
||||
var (
|
||||
ctx = gctx.New()
|
||||
url = "http://127.0.0.1:8999"
|
||||
tlsConfig = &tls.Config{}
|
||||
)
|
||||
client := g.Client()
|
||||
client.SetTLSConfig(tlsConfig)
|
||||
fmt.Println(string(client.GetBytes(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_PutContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().PutContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// PUT: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_DeleteContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().DeleteContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// DELETE: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_HeadContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().HeadContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
}
|
||||
|
||||
func ExampleClient_PatchContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().PatchContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// PATCH: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_ConnectContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().ConnectContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// CONNECT: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_OptionsContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().OptionsContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// OPTIONS: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_TraceContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().TraceContent(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// TRACE: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_RequestContent() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
fmt.Println(g.Client().RequestContent(ctx, http.MethodGet, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
}))
|
||||
|
||||
// Output:
|
||||
// GET: query: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_RawRequest() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
response, _ := g.Client().Get(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
fmt.Println(len(response.RawResponse()) > 100)
|
||||
|
||||
// Output:
|
||||
// true
|
||||
}
|
||||
|
||||
func ExampleClient_Delete() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Delete(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
// DELETE: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_Head() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Head(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
//
|
||||
}
|
||||
|
||||
func ExampleClient_Patch() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Patch(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
// PATCH: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_Connect() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Connect(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
// CONNECT: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_Options() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Options(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
// OPTIONS: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_Trace() {
|
||||
url := "http://127.0.0.1:8999"
|
||||
r, _ := g.Client().Trace(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
defer r.Close()
|
||||
fmt.Println(r.ReadAllString())
|
||||
|
||||
// Output:
|
||||
// TRACE: form: 10000, john
|
||||
}
|
||||
|
||||
func ExampleClient_PutVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
user *User
|
||||
ctx = context.Background()
|
||||
url = "http://127.0.0.1:8999/var/json"
|
||||
)
|
||||
err := g.Client().PutVar(ctx, url).Scan(&user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(user)
|
||||
|
||||
// Output:
|
||||
// &{1 john}
|
||||
}
|
||||
|
||||
func ExampleClient_DeleteVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().DeleteVar(ctx, url).Scan(&users)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{1 john} {2 smith}]
|
||||
}
|
||||
|
||||
func ExampleClient_HeadVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().HeadVar(ctx, url).Scan(&users)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// []
|
||||
}
|
||||
|
||||
func ExampleClient_PatchVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().PatchVar(ctx, url).Scan(&users)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{1 john} {2 smith}]
|
||||
}
|
||||
|
||||
func ExampleClient_ConnectVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().ConnectVar(ctx, url).Scan(&users)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{1 john} {2 smith}]
|
||||
}
|
||||
|
||||
func ExampleClient_OptionsVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().OptionsVar(ctx, url).Scan(&users)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{1 john} {2 smith}]
|
||||
}
|
||||
|
||||
func ExampleClient_TraceVar() {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().TraceVar(ctx, url).Scan(&users)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(users)
|
||||
|
||||
// Output:
|
||||
// [{1 john} {2 smith}]
|
||||
}
|
||||
|
||||
78
net/gclient/gclient_z_unit_feature_trace_test.go
Normal file
78
net/gclient/gclient_z_unit_feature_trace_test.go
Normal file
@ -0,0 +1,78 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/internal/tracing"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
"go.opentelemetry.io/otel"
|
||||
sdkTrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
type CustomProvider struct {
|
||||
*sdkTrace.TracerProvider
|
||||
}
|
||||
|
||||
func NewCustomProvider() *CustomProvider {
|
||||
return &CustomProvider{
|
||||
TracerProvider: sdkTrace.NewTracerProvider(
|
||||
sdkTrace.WithIDGenerator(NewCustomIDGenerator()),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
type CustomIDGenerator struct{}
|
||||
|
||||
func NewCustomIDGenerator() *CustomIDGenerator {
|
||||
return &CustomIDGenerator{}
|
||||
}
|
||||
|
||||
func (id *CustomIDGenerator) NewIDs(ctx context.Context) (traceID trace.TraceID, spanID trace.SpanID) {
|
||||
return tracing.NewIDs()
|
||||
}
|
||||
|
||||
func (id *CustomIDGenerator) NewSpanID(ctx context.Context, traceID trace.TraceID) (spanID trace.SpanID) {
|
||||
return tracing.NewSpanID()
|
||||
}
|
||||
|
||||
func TestClient_CustomProvider(t *testing.T) {
|
||||
provider := otel.GetTracerProvider()
|
||||
defer otel.SetTracerProvider(provider)
|
||||
|
||||
otel.SetTracerProvider(NewCustomProvider())
|
||||
|
||||
p, _ := gtcp.GetFreePort()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/hello", func(r *ghttp.Request) {
|
||||
r.Response.WriteHeader(200)
|
||||
r.Response.WriteJson(g.Map{"field": "test_for_response_body"})
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c := g.Client()
|
||||
url := fmt.Sprintf("127.0.0.1:%d/hello", p)
|
||||
resp, err := c.DoRequest(ctx, http.MethodGet, url)
|
||||
t.AssertNil(err)
|
||||
t.AssertNE(resp, nil)
|
||||
t.Assert(resp.ReadAllString(), "{\"field\":\"test_for_response_body\"}")
|
||||
})
|
||||
}
|
||||
81
net/gclient/gclient_z_unit_request_obj_test.go
Normal file
81
net/gclient/gclient_z_unit_request_obj_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the MIT License.
|
||||
// If a copy of the MIT was not distributed with this file,
|
||||
// You can obtain one at https://github.com/gogf/gf.
|
||||
|
||||
package gclient_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/ghttp"
|
||||
"github.com/gogf/gf/v2/net/gtcp"
|
||||
"github.com/gogf/gf/v2/test/gtest"
|
||||
)
|
||||
|
||||
func Test_Client_DoRequestObj(t *testing.T) {
|
||||
type UserCreateReq struct {
|
||||
g.Meta `path:"/user" method:"post"`
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
type UserCreateRes struct {
|
||||
Id int
|
||||
}
|
||||
type UserQueryReq struct {
|
||||
g.Meta `path:"/user/{id}" method:"get"`
|
||||
Id int
|
||||
}
|
||||
type UserQueryRes struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
p, _ := gtcp.GetFreePort()
|
||||
s := g.Server(p)
|
||||
s.Group("/user", func(group *ghttp.RouterGroup) {
|
||||
group.GET("/{id}", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(g.Map{"id": r.Get("id").Int(), "name": "john"})
|
||||
})
|
||||
group.POST("/", func(r *ghttp.Request) {
|
||||
r.Response.WriteJson(g.Map{"id": r.Get("Id")})
|
||||
})
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d", p)
|
||||
client := g.Client().SetPrefix(url).ContentJson()
|
||||
var (
|
||||
createRes *UserCreateRes
|
||||
createReq = UserCreateReq{
|
||||
Id: 1,
|
||||
Name: "john",
|
||||
}
|
||||
)
|
||||
err := client.DoRequestObj(ctx, createReq, &createRes)
|
||||
t.AssertNil(err)
|
||||
t.Assert(createRes.Id, 1)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d", p)
|
||||
client := g.Client().SetPrefix(url).ContentJson()
|
||||
var (
|
||||
queryRes *UserQueryRes
|
||||
queryReq = UserQueryReq{
|
||||
Id: 1,
|
||||
}
|
||||
)
|
||||
err := client.DoRequestObj(ctx, queryReq, &queryRes)
|
||||
t.AssertNil(err)
|
||||
t.Assert(queryRes.Id, 1)
|
||||
t.Assert(queryRes.Name, "john")
|
||||
})
|
||||
}
|
||||
@ -11,12 +11,13 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/v2/debug/gdebug"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/debug/gdebug"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"github.com/gogf/gf/v2/net/gclient"
|
||||
@ -488,6 +489,28 @@ func Test_Client_Request_13_Dump(t *testing.T) {
|
||||
t.Assert(gstr.Contains(dumpedText3, "test_for_request_body"), true)
|
||||
dumpedText4 := r2.RawResponse()
|
||||
t.Assert(gstr.Contains(dumpedText4, "test_for_request_body"), false)
|
||||
r2 = nil
|
||||
t.Assert(r2.RawRequest(), "")
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d", p)
|
||||
response, _ := g.Client().Get(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
response = nil
|
||||
t.Assert(response.RawRequest(), "")
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
url := fmt.Sprintf("http://127.0.0.1:%d", p)
|
||||
response, _ := g.Client().Get(ctx, url, g.Map{
|
||||
"id": 10000,
|
||||
"name": "john",
|
||||
})
|
||||
response.RawDump()
|
||||
t.AssertGT(len(response.Raw()), 0)
|
||||
})
|
||||
}
|
||||
|
||||
@ -558,3 +581,86 @@ func TestLoadKeyCrt(t *testing.T) {
|
||||
t.AssertNE(tlsConfig, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_DoRequest(t *testing.T) {
|
||||
p, _ := gtcp.GetFreePort()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/hello", func(r *ghttp.Request) {
|
||||
r.Response.WriteHeader(200)
|
||||
r.Response.WriteJson(g.Map{"field": "test_for_response_body"})
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c := g.Client()
|
||||
url := fmt.Sprintf("127.0.0.1:%d/hello", p)
|
||||
resp, err := c.DoRequest(ctx, http.MethodGet, url)
|
||||
t.AssertNil(err)
|
||||
t.AssertNE(resp, nil)
|
||||
t.Assert(resp.ReadAllString(), "{\"field\":\"test_for_response_body\"}")
|
||||
|
||||
resp.Response = nil
|
||||
bytes := resp.ReadAll()
|
||||
t.Assert(bytes, []byte{})
|
||||
resp.Close()
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c := g.Client()
|
||||
url := "127.0.0.1:99999/hello"
|
||||
resp, err := c.DoRequest(ctx, http.MethodGet, url)
|
||||
t.AssertNil(resp.Response)
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_RequestVar(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
var (
|
||||
url = "http://127.0.0.1:99999/var/jsons"
|
||||
)
|
||||
varValue := g.Client().RequestVar(ctx, http.MethodGet, url)
|
||||
t.AssertNil(varValue)
|
||||
})
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
type User struct {
|
||||
Id int
|
||||
Name string
|
||||
}
|
||||
var (
|
||||
users []User
|
||||
url = "http://127.0.0.1:8999/var/jsons"
|
||||
)
|
||||
err := g.Client().RequestVar(ctx, http.MethodGet, url).Scan(&users)
|
||||
t.AssertNil(err)
|
||||
t.AssertNE(users, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestClient_SetBodyContent(t *testing.T) {
|
||||
p, _ := gtcp.GetFreePort()
|
||||
s := g.Server(p)
|
||||
s.BindHandler("/", func(r *ghttp.Request) {
|
||||
r.Response.Write("hello")
|
||||
})
|
||||
s.SetPort(p)
|
||||
s.SetDumpRouterMap(false)
|
||||
s.Start()
|
||||
defer s.Shutdown()
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
c := g.Client()
|
||||
c.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
|
||||
res, err := c.Get(ctx, "/")
|
||||
t.AssertNil(err)
|
||||
defer res.Close()
|
||||
t.Assert(res.ReadAllString(), "hello")
|
||||
res.SetBodyContent([]byte("world"))
|
||||
t.Assert(res.ReadAllString(), "world")
|
||||
})
|
||||
}
|
||||
|
||||
@ -117,21 +117,22 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
defaultMethod = "ALL"
|
||||
exceptionExit = "exit"
|
||||
exceptionExitAll = "exit_all"
|
||||
exceptionExitHook = "exit_hook"
|
||||
routeCacheDuration = time.Hour
|
||||
ctxKeyForRequest = "gHttpRequestObject"
|
||||
contentTypeXml = "text/xml"
|
||||
contentTypeHtml = "text/html"
|
||||
contentTypeJson = "application/json"
|
||||
swaggerUIPackedPath = "/goframe/swaggerui"
|
||||
responseTraceIDHeader = "Trace-ID"
|
||||
specialMethodNameInit = "Init"
|
||||
specialMethodNameShut = "Shut"
|
||||
specialMethodNameIndex = "Index"
|
||||
supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
|
||||
defaultMethod = "ALL"
|
||||
exceptionExit = "exit"
|
||||
exceptionExitAll = "exit_all"
|
||||
exceptionExitHook = "exit_hook"
|
||||
routeCacheDuration = time.Hour
|
||||
ctxKeyForRequest = "gHttpRequestObject"
|
||||
contentTypeXml = "text/xml"
|
||||
contentTypeHtml = "text/html"
|
||||
contentTypeJson = "application/json"
|
||||
swaggerUIPackedPath = "/goframe/swaggerui"
|
||||
responseTraceIDHeader = "Trace-ID"
|
||||
specialMethodNameInit = "Init"
|
||||
specialMethodNameShut = "Shut"
|
||||
specialMethodNameIndex = "Index"
|
||||
gracefulShutdownTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
@ -11,7 +11,6 @@ import (
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
)
|
||||
|
||||
// DefaultHandlerResponse is the default implementation of HandlerResponse.
|
||||
@ -32,7 +31,6 @@ func MiddlewareHandlerResponse(r *Request) {
|
||||
|
||||
var (
|
||||
msg string
|
||||
ctx = r.Context()
|
||||
err = r.GetError()
|
||||
res = r.GetHandlerResponse()
|
||||
code = gerror.Code(err)
|
||||
@ -55,12 +53,9 @@ func MiddlewareHandlerResponse(r *Request) {
|
||||
} else {
|
||||
code = gcode.CodeOK
|
||||
}
|
||||
internalErr := r.Response.WriteJson(DefaultHandlerResponse{
|
||||
r.Response.WriteJson(DefaultHandlerResponse{
|
||||
Code: code.Code(),
|
||||
Message: msg,
|
||||
Data: res,
|
||||
})
|
||||
if internalErr != nil {
|
||||
intlog.Errorf(ctx, `%+v`, internalErr)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
package ghttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"reflect"
|
||||
|
||||
@ -44,8 +45,8 @@ func (m *middleware) Next() {
|
||||
|
||||
// Router values switching.
|
||||
m.request.routerMap = item.Values
|
||||
|
||||
gutil.TryCatch(func() {
|
||||
ctx := m.request.context
|
||||
gutil.TryCatch(ctx, func(ctx context.Context) {
|
||||
// Execute bound middleware array of the item if it's not empty.
|
||||
if m.handlerMDIndex < len(item.Handler.Middleware) {
|
||||
md := item.Handler.Middleware[m.handlerMDIndex]
|
||||
@ -98,7 +99,7 @@ func (m *middleware) Next() {
|
||||
// There should be a "Next" function to be called in the middleware in order to manage the workflow.
|
||||
loop = false
|
||||
}
|
||||
}, func(exception error) {
|
||||
}, func(ctx context.Context, exception error) {
|
||||
if v, ok := exception.(error); ok && gerror.HasStack(v) {
|
||||
// It's already an error that has stack info.
|
||||
m.request.error = v
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gogf/gf/v2/encoding/gjson"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/json"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
@ -102,48 +103,44 @@ func (r *Response) WriteflnExit(format string, params ...interface{}) {
|
||||
}
|
||||
|
||||
// WriteJson writes `content` to the response with JSON format.
|
||||
func (r *Response) WriteJson(content interface{}) error {
|
||||
func (r *Response) WriteJson(content interface{}) {
|
||||
r.Header().Set("Content-Type", contentTypeJson)
|
||||
// If given string/[]byte, response it directly to the client.
|
||||
switch content.(type) {
|
||||
case string, []byte:
|
||||
r.Write(gconv.String(content))
|
||||
return nil
|
||||
return
|
||||
}
|
||||
// Else use json.Marshal function to encode the parameter.
|
||||
if b, err := json.Marshal(content); err != nil {
|
||||
return err
|
||||
panic(gerror.Wrap(err, `WriteJson failed`))
|
||||
} else {
|
||||
r.Write(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteJsonExit writes `content` to the response with JSON format and exits executing
|
||||
// of current handler if success. The "Exit" feature is commonly used to replace usage of
|
||||
// return statements in the handler, for convenience.
|
||||
func (r *Response) WriteJsonExit(content interface{}) error {
|
||||
if err := r.WriteJson(content); err != nil {
|
||||
return err
|
||||
}
|
||||
func (r *Response) WriteJsonExit(content interface{}) {
|
||||
r.WriteJson(content)
|
||||
r.Request.Exit()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteJsonP writes `content` to the response with JSONP format.
|
||||
//
|
||||
// Note that there should be a "callback" parameter in the request for JSONP format.
|
||||
func (r *Response) WriteJsonP(content interface{}) error {
|
||||
func (r *Response) WriteJsonP(content interface{}) {
|
||||
r.Header().Set("Content-Type", contentTypeJson)
|
||||
// If given string/[]byte, response it directly to client.
|
||||
switch content.(type) {
|
||||
case string, []byte:
|
||||
r.Write(gconv.String(content))
|
||||
return nil
|
||||
return
|
||||
}
|
||||
// Else use json.Marshal function to encode the parameter.
|
||||
if b, err := json.Marshal(content); err != nil {
|
||||
return err
|
||||
panic(gerror.Wrap(err, `WriteJsonP failed`))
|
||||
} else {
|
||||
// r.Header().Set("Content-Type", "application/json")
|
||||
if callback := r.Request.Get("callback").String(); callback != "" {
|
||||
@ -156,7 +153,6 @@ func (r *Response) WriteJsonP(content interface{}) error {
|
||||
r.Write(b)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteJsonPExit writes `content` to the response with JSONP format and exits executing
|
||||
@ -164,40 +160,33 @@ func (r *Response) WriteJsonP(content interface{}) error {
|
||||
// return statements in the handler, for convenience.
|
||||
//
|
||||
// Note that there should be a "callback" parameter in the request for JSONP format.
|
||||
func (r *Response) WriteJsonPExit(content interface{}) error {
|
||||
if err := r.WriteJsonP(content); err != nil {
|
||||
return err
|
||||
}
|
||||
func (r *Response) WriteJsonPExit(content interface{}) {
|
||||
r.WriteJsonP(content)
|
||||
r.Request.Exit()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteXml writes `content` to the response with XML format.
|
||||
func (r *Response) WriteXml(content interface{}, rootTag ...string) error {
|
||||
func (r *Response) WriteXml(content interface{}, rootTag ...string) {
|
||||
r.Header().Set("Content-Type", contentTypeXml)
|
||||
// If given string/[]byte, response it directly to clients.
|
||||
switch content.(type) {
|
||||
case string, []byte:
|
||||
r.Write(gconv.String(content))
|
||||
return nil
|
||||
return
|
||||
}
|
||||
if b, err := gjson.New(content).ToXml(rootTag...); err != nil {
|
||||
return err
|
||||
panic(gerror.Wrap(err, `WriteXml failed`))
|
||||
} else {
|
||||
r.Write(b)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteXmlExit writes `content` to the response with XML format and exits executing
|
||||
// of current handler if success. The "Exit" feature is commonly used to replace usage
|
||||
// of return statements in the handler, for convenience.
|
||||
func (r *Response) WriteXmlExit(content interface{}, rootTag ...string) error {
|
||||
if err := r.WriteXml(content, rootTag...); err != nil {
|
||||
return err
|
||||
}
|
||||
func (r *Response) WriteXmlExit(content interface{}, rootTag ...string) {
|
||||
r.WriteXml(content, rootTag...)
|
||||
r.Request.Exit()
|
||||
return nil
|
||||
}
|
||||
|
||||
// WriteStatus writes HTTP `status` and `content` to the response.
|
||||
|
||||
@ -144,7 +144,7 @@ func forkReloadProcess(ctx context.Context, newExeFilePath ...string) error {
|
||||
}
|
||||
buffer, _ := gjson.Encode(sfm)
|
||||
p.Env = append(p.Env, adminActionReloadEnvKey+"="+string(buffer))
|
||||
if _, err := p.Start(); err != nil {
|
||||
if _, err := p.Start(ctx); err != nil {
|
||||
glog.Errorf(
|
||||
ctx,
|
||||
"%d: fork process failed, error:%s, %s",
|
||||
@ -169,7 +169,7 @@ func forkRestartProcess(ctx context.Context, newExeFilePath ...string) error {
|
||||
env := os.Environ()
|
||||
env = append(env, adminActionRestartEnvKey+"=1")
|
||||
p := gproc.NewProcess(path, os.Args, env)
|
||||
if _, err := p.Start(); err != nil {
|
||||
if _, err := p.Start(ctx); err != nil {
|
||||
glog.Errorf(
|
||||
ctx,
|
||||
`%d: fork process failed, error:%s, are you running using "go run"?`,
|
||||
|
||||
@ -215,7 +215,9 @@ func (s *gracefulServer) shutdown(ctx context.Context) {
|
||||
if s.status == ServerStatusStopped {
|
||||
return
|
||||
}
|
||||
if err := s.httpServer.Shutdown(context.Background()); err != nil {
|
||||
timeoutCtx, cancelFunc := context.WithTimeout(ctx, gracefulShutdownTimeout)
|
||||
defer cancelFunc()
|
||||
if err := s.httpServer.Shutdown(timeoutCtx); err != nil {
|
||||
s.server.Logger().Errorf(
|
||||
ctx,
|
||||
"%d: %s server [%s] shutdown error: %v",
|
||||
|
||||
@ -9,7 +9,6 @@ package ghttp
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/net/goai"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
@ -48,16 +47,9 @@ func (s *Server) initOpenApi() {
|
||||
|
||||
// openapiSpec is a build-in handler automatic producing for openapi specification json file.
|
||||
func (s *Server) openapiSpec(r *Request) {
|
||||
var (
|
||||
err error
|
||||
)
|
||||
if s.config.OpenApiPath == "" {
|
||||
r.Response.Write(`OpenApi specification file producing is disabled`)
|
||||
} else {
|
||||
err = r.Response.WriteJson(s.openapi)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
intlog.Errorf(r.Context(), `%+v`, err)
|
||||
r.Response.WriteJson(s.openapi)
|
||||
}
|
||||
}
|
||||
|
||||
@ -81,9 +81,9 @@ func watchAndUpdateService(watcher Watcher, service Service, watchFunc ServiceWa
|
||||
if len(services) > 0 {
|
||||
watchedServiceMap.Set(service.GetName(), services[0])
|
||||
if watchFunc != nil {
|
||||
gutil.TryCatch(func() {
|
||||
gutil.TryCatch(ctx, func(ctx context.Context) {
|
||||
watchFunc(services[0])
|
||||
}, func(exception error) {
|
||||
}, func(ctx context.Context, exception error) {
|
||||
intlog.Errorf(ctx, `%+v`, exception)
|
||||
})
|
||||
}
|
||||
|
||||
@ -196,7 +196,13 @@ func GetFreePort() (port int, err error) {
|
||||
)
|
||||
}
|
||||
port = l.Addr().(*net.TCPAddr).Port
|
||||
err = l.Close()
|
||||
if err = l.Close(); err != nil {
|
||||
err = gerror.Wrapf(
|
||||
err,
|
||||
`close listening failed for network "%s", address "%s", port "%d"`,
|
||||
network, resolvedAddr.String(), port,
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
@ -145,7 +147,11 @@ func GetBaggageVar(ctx context.Context, key string) *gvar.Var {
|
||||
}
|
||||
|
||||
// WithTraceID injects custom trace id into context to propagate.
|
||||
func WithTraceID(ctx context.Context, traceID trace.TraceID) context.Context {
|
||||
func WithTraceID(ctx context.Context, traceID string) (context.Context, error) {
|
||||
generatedTraceID, err := trace.TraceIDFromHex(traceID)
|
||||
if err != nil {
|
||||
return nil, gerror.WrapCodef(gcode.CodeInvalidParameter, err, `invalid traceID: %s`, traceID)
|
||||
}
|
||||
sc := trace.SpanContextFromContext(ctx)
|
||||
if !sc.HasTraceID() {
|
||||
var (
|
||||
@ -156,11 +162,11 @@ func WithTraceID(ctx context.Context, traceID trace.TraceID) context.Context {
|
||||
sc = trace.SpanContextFromContext(ctx)
|
||||
}
|
||||
ctx = trace.ContextWithRemoteSpanContext(ctx, trace.NewSpanContext(trace.SpanContextConfig{
|
||||
TraceID: traceID,
|
||||
TraceID: generatedTraceID,
|
||||
SpanID: sc.SpanID(),
|
||||
TraceFlags: sc.TraceFlags(),
|
||||
TraceState: sc.TraceState(),
|
||||
Remote: sc.IsRemote(),
|
||||
}))
|
||||
return ctx
|
||||
return ctx, nil
|
||||
}
|
||||
|
||||
@ -61,7 +61,8 @@ func Test_WithTraceID(t *testing.T) {
|
||||
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
ctx := gtrace.WithTraceID(context.TODO(), traceID)
|
||||
ctx, err := gtrace.WithTraceID(context.TODO(), traceID.String())
|
||||
t.AssertNil(err)
|
||||
|
||||
prefix := fmt.Sprintf("http://127.0.0.1:%d", p)
|
||||
client := g.Client()
|
||||
|
||||
@ -18,6 +18,27 @@ import (
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
var (
|
||||
simpleTimeout = time.Millisecond * 100
|
||||
sendData = []byte("hello")
|
||||
invalidAddr = "127.0.0.1:99999"
|
||||
)
|
||||
|
||||
func startUDPServer(addr string) {
|
||||
s := gudp.NewServer(addr, func(conn *gudp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
data, err := conn.Recv(-1)
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
conn.Send(data)
|
||||
}
|
||||
})
|
||||
go s.Run()
|
||||
time.Sleep(simpleTimeout)
|
||||
}
|
||||
|
||||
func Test_Basic(t *testing.T) {
|
||||
var (
|
||||
ctx = context.TODO()
|
||||
@ -46,6 +67,11 @@ func Test_Basic(t *testing.T) {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
t.AssertNil(err)
|
||||
t.Assert(conn.Send([]byte(gconv.String(i))), nil)
|
||||
t.AssertNil(conn.RemoteAddr())
|
||||
result, err := conn.Recv(-1)
|
||||
t.AssertNil(err)
|
||||
t.AssertNE(conn.RemoteAddr(), nil)
|
||||
t.Assert(string(result), fmt.Sprintf(`> %d`, i))
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
@ -60,6 +86,41 @@ func Test_Basic(t *testing.T) {
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
// gudp.Conn.SendWithTimeout
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
t.AssertNil(err)
|
||||
err = conn.SendWithTimeout([]byte(gconv.String(i)), time.Second)
|
||||
t.AssertNil(err)
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
// gudp.Conn.RecvWithTimeout
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
t.AssertNil(err)
|
||||
err = conn.Send([]byte(gconv.String(i)))
|
||||
t.AssertNil(err)
|
||||
conn.SetRecvBufferWait(time.Millisecond * 100)
|
||||
result, err := conn.RecvWithTimeout(-1, time.Second)
|
||||
t.AssertNil(err)
|
||||
t.Assert(string(result), fmt.Sprintf(`> %d`, i))
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
// gudp.Conn.SendRecvWithTimeout
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", p))
|
||||
t.AssertNil(err)
|
||||
result, err := conn.SendRecvWithTimeout([]byte(gconv.String(i)), -1, time.Second)
|
||||
t.AssertNil(err)
|
||||
t.Assert(string(result), fmt.Sprintf(`> %d`, i))
|
||||
conn.Close()
|
||||
}
|
||||
})
|
||||
// gudp.Send
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
@ -112,3 +173,69 @@ func Test_Buffer(t *testing.T) {
|
||||
t.Assert(string(result), "4")
|
||||
})
|
||||
}
|
||||
|
||||
func Test_NewConn(t *testing.T) {
|
||||
var (
|
||||
port, _ = gudp.GetFreePort()
|
||||
)
|
||||
|
||||
startUDPServer(fmt.Sprintf("127.0.0.1:%d", port))
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", port), fmt.Sprintf("127.0.0.1:%d", port+1))
|
||||
t.AssertNil(err)
|
||||
conn.SetDeadline(time.Now().Add(time.Second))
|
||||
t.Assert(conn.Send(sendData), nil)
|
||||
conn.Close()
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", port), fmt.Sprintf("127.0.0.1:%d", 99999))
|
||||
t.AssertNil(conn)
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
conn, err := gudp.NewConn(fmt.Sprintf("127.0.0.1:%d", 99999))
|
||||
t.AssertNil(conn)
|
||||
t.AssertNE(err, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_GetFreePorts(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
ports, err := gudp.GetFreePorts(2)
|
||||
t.AssertNil(err)
|
||||
t.AssertEQ(len(ports), 2)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Server(t *testing.T) {
|
||||
p, _ := gudp.GetFreePort()
|
||||
gudp.NewServer(fmt.Sprintf("127.0.0.1:%d", p), func(conn *gudp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
data, err := conn.Recv(1)
|
||||
if len(data) > 0 {
|
||||
conn.Send(data)
|
||||
}
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
}, "GoFrameUDPServer")
|
||||
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
server := gudp.GetServer("GoFrameUDPServer")
|
||||
t.AssertNE(server, nil)
|
||||
server = gudp.GetServer("TestUDPServer")
|
||||
t.AssertNE(server, nil)
|
||||
server.SetAddress("127.0.0.1:8888")
|
||||
server.SetHandler(func(conn *gudp.Conn) {
|
||||
defer conn.Close()
|
||||
for {
|
||||
conn.Send([]byte("OtherHandle"))
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -24,9 +24,10 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
helpOptionName = "help"
|
||||
helpOptionNameShort = "h"
|
||||
maxLineChars = 120
|
||||
helpOptionName = "help"
|
||||
helpOptionNameShort = "h"
|
||||
maxLineChars = 120
|
||||
tracingInstrumentName = "github.com/gogf/gf/v2/os/gcmd.Command"
|
||||
)
|
||||
|
||||
// Init does custom initialization.
|
||||
|
||||
@ -11,12 +11,19 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
)
|
||||
|
||||
// Print prints help info to stdout for current command.
|
||||
func (c *Command) Print() {
|
||||
c.PrintTo(os.Stdout)
|
||||
}
|
||||
|
||||
// PrintTo prints help info to custom io.Writer.
|
||||
func (c *Command) PrintTo(writer io.Writer) {
|
||||
var (
|
||||
prefix = gstr.Repeat(" ", 4)
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
@ -191,7 +198,7 @@ func (c *Command) Print() {
|
||||
}
|
||||
content := buffer.String()
|
||||
content = gstr.Replace(content, "\t", " ")
|
||||
fmt.Println(content)
|
||||
_, _ = writer.Write([]byte(content))
|
||||
}
|
||||
|
||||
type printLineBriefInput struct {
|
||||
|
||||
@ -8,16 +8,24 @@
|
||||
package gcmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/gogf/gf/v2"
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"github.com/gogf/gf/v2/os/gcfg"
|
||||
"github.com/gogf/gf/v2/os/genv"
|
||||
"github.com/gogf/gf/v2/os/glog"
|
||||
"github.com/gogf/gf/v2/text/gstr"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
"github.com/gogf/gf/v2/util/gutil"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
|
||||
// Run calls custom function that bound to this command.
|
||||
@ -34,18 +42,23 @@ func (c *Command) RunWithValue(ctx context.Context) (value interface{}) {
|
||||
var (
|
||||
code = gerror.Code(err)
|
||||
detail = code.Detail()
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
if code.Code() == gcode.CodeNotFound.Code() {
|
||||
fmt.Printf("ERROR: %s\n", gstr.Trim(err.Error()))
|
||||
buffer.WriteString(fmt.Sprintf("ERROR: %s\n", gstr.Trim(err.Error())))
|
||||
if lastCmd, ok := detail.(*Command); ok {
|
||||
lastCmd.Print()
|
||||
lastCmd.PrintTo(buffer)
|
||||
} else {
|
||||
c.Print()
|
||||
c.PrintTo(buffer)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("%+v\n", err)
|
||||
buffer.WriteString(fmt.Sprintf("%+v\n", err))
|
||||
}
|
||||
os.Exit(1)
|
||||
if gtrace.GetTraceID(ctx) == "" {
|
||||
fmt.Println(buffer.String())
|
||||
os.Exit(1)
|
||||
}
|
||||
glog.Stack(false).Fatal(ctx, buffer.String())
|
||||
}
|
||||
return value
|
||||
}
|
||||
@ -107,6 +120,24 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{},
|
||||
}
|
||||
return nil, c.defaultHelpFunc(ctx, parser)
|
||||
}
|
||||
// OpenTelemetry for command.
|
||||
var (
|
||||
span trace.Span
|
||||
tr = otel.GetTracerProvider().Tracer(
|
||||
tracingInstrumentName,
|
||||
trace.WithInstrumentationVersion(gf.VERSION),
|
||||
)
|
||||
)
|
||||
ctx, span = tr.Start(
|
||||
otel.GetTextMapPropagator().Extract(
|
||||
ctx,
|
||||
propagation.MapCarrier(genv.Map()),
|
||||
),
|
||||
gstr.Join(os.Args, " "),
|
||||
trace.WithSpanKind(trace.SpanKindServer),
|
||||
)
|
||||
defer span.End()
|
||||
span.SetAttributes(gtrace.CommonLabels()...)
|
||||
// Reparse the arguments for current command configuration.
|
||||
parser, err = c.reParse(ctx, parser)
|
||||
if err != nil {
|
||||
@ -126,7 +157,7 @@ func (c *Command) doRun(ctx context.Context, parser *Parser) (value interface{},
|
||||
return nil, c.defaultHelpFunc(ctx, parser)
|
||||
}
|
||||
|
||||
// reParse re-parses the arguments using option configuration of current command.
|
||||
// reParse parses the arguments using option configuration of current command.
|
||||
func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error) {
|
||||
if len(c.Arguments) == 0 {
|
||||
return parser, nil
|
||||
|
||||
@ -9,8 +9,12 @@ package gctx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gogf/gf/v2/net/gtrace"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -18,13 +22,36 @@ type (
|
||||
StrKey string // StrKey is a type for warps basic type string as context key.
|
||||
)
|
||||
|
||||
var (
|
||||
// processCtx is the context initialized from process environment.
|
||||
processCtx context.Context
|
||||
)
|
||||
|
||||
func init() {
|
||||
// All environment key-value pairs.
|
||||
m := make(map[string]string)
|
||||
i := 0
|
||||
for _, s := range os.Environ() {
|
||||
i = strings.IndexByte(s, '=')
|
||||
m[s[0:i]] = s[i+1:]
|
||||
}
|
||||
// OpenTelemetry from environments.
|
||||
processCtx = otel.GetTextMapPropagator().Extract(
|
||||
context.Background(),
|
||||
propagation.MapCarrier(m),
|
||||
)
|
||||
}
|
||||
|
||||
// New creates and returns a context which contains context id.
|
||||
func New() context.Context {
|
||||
return WithCtx(context.Background())
|
||||
return WithCtx(processCtx)
|
||||
}
|
||||
|
||||
// WithCtx creates and returns a context containing context id upon given parent context `ctx`.
|
||||
func WithCtx(ctx context.Context) context.Context {
|
||||
if CtxId(ctx) != "" {
|
||||
return ctx
|
||||
}
|
||||
if gtrace.IsUsingDefaultProvider() {
|
||||
var span *gtrace.Span
|
||||
ctx, span = gtrace.NewSpan(ctx, "gctx.WithCtx")
|
||||
|
||||
@ -8,6 +8,7 @@
|
||||
package genv
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@ -25,13 +26,7 @@ func All() []string {
|
||||
|
||||
// Map returns a copy of strings representing the environment as a map.
|
||||
func Map() map[string]string {
|
||||
m := make(map[string]string)
|
||||
i := 0
|
||||
for _, s := range os.Environ() {
|
||||
i = strings.IndexByte(s, '=')
|
||||
m[s[0:i]] = s[i+1:]
|
||||
}
|
||||
return m
|
||||
return MapFromEnv(os.Environ())
|
||||
}
|
||||
|
||||
// Get creates and returns a Var with the value of the environment variable
|
||||
@ -117,3 +112,28 @@ func Build(m map[string]string) []string {
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
// MapFromEnv converts environment variables from slice to map.
|
||||
func MapFromEnv(envs []string) map[string]string {
|
||||
m := make(map[string]string)
|
||||
i := 0
|
||||
for _, s := range envs {
|
||||
i = strings.IndexByte(s, '=')
|
||||
m[s[0:i]] = s[i+1:]
|
||||
}
|
||||
return m
|
||||
}
|
||||
|
||||
// MapToEnv converts environment variables from map to slice.
|
||||
func MapToEnv(m map[string]string) []string {
|
||||
envs := make([]string, 0)
|
||||
for k, v := range m {
|
||||
envs = append(envs, fmt.Sprintf(`%s=%s`, k, v))
|
||||
}
|
||||
return envs
|
||||
}
|
||||
|
||||
// Filter filters repeated items from given environment variables.
|
||||
func Filter(envs []string) []string {
|
||||
return MapToEnv(MapFromEnv(envs))
|
||||
}
|
||||
|
||||
@ -121,3 +121,24 @@ func Test_GetWithCmd(t *testing.T) {
|
||||
t.Assert(genv.GetWithCmd("test"), 1)
|
||||
})
|
||||
}
|
||||
|
||||
func Test_MapFromEnv(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
m := genv.MapFromEnv([]string{"a=1", "b=2"})
|
||||
t.Assert(m, g.Map{"a": 1, "b": 2})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_MapToEnv(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s := genv.MapToEnv(g.MapStrStr{"a": "1"})
|
||||
t.Assert(s, []string{"a=1"})
|
||||
})
|
||||
}
|
||||
|
||||
func Test_Filter(t *testing.T) {
|
||||
gtest.C(t, func(t *gtest.T) {
|
||||
s := genv.Filter([]string{"a=1", "a=3"})
|
||||
t.Assert(s, []string{"a=3"})
|
||||
})
|
||||
}
|
||||
|
||||
@ -10,6 +10,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/v2/errors/gcode"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/internal/intlog"
|
||||
"github.com/gogf/gf/v2/os/gcache"
|
||||
@ -17,22 +19,28 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
defaultCacheExpire = "1m" // defaultCacheExpire is the expire time for file content caching in seconds.
|
||||
defaultCacheDuration = "1m" // defaultCacheExpire is the expire time for file content caching in seconds.
|
||||
commandEnvKeyForCache = "gf.gfile.cache" // commandEnvKeyForCache is the configuration key for command argument or environment configuring cache expire duration.
|
||||
)
|
||||
|
||||
var (
|
||||
// Default expire time for file content caching.
|
||||
cacheExpire = getCacheExpire()
|
||||
cacheDuration = getCacheDuration()
|
||||
|
||||
// internalCache is the memory cache for internal usage.
|
||||
internalCache = gcache.New()
|
||||
)
|
||||
|
||||
func getCacheExpire() time.Duration {
|
||||
d, err := time.ParseDuration(command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheExpire))
|
||||
func getCacheDuration() time.Duration {
|
||||
cacheDurationConfigured := command.GetOptWithEnv(commandEnvKeyForCache, defaultCacheDuration)
|
||||
d, err := time.ParseDuration(cacheDurationConfigured)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
panic(gerror.WrapCodef(
|
||||
gcode.CodeInvalidConfiguration,
|
||||
err,
|
||||
`error parsing string "%s" to time duration`,
|
||||
cacheDurationConfigured,
|
||||
))
|
||||
}
|
||||
return d
|
||||
}
|
||||
@ -50,7 +58,7 @@ func GetContentsWithCache(path string, duration ...time.Duration) string {
|
||||
func GetBytesWithCache(path string, duration ...time.Duration) []byte {
|
||||
var (
|
||||
ctx = context.Background()
|
||||
expire = cacheExpire
|
||||
expire = cacheDuration
|
||||
cacheKey = commandEnvKeyForCache + path
|
||||
)
|
||||
|
||||
|
||||
@ -39,6 +39,23 @@ func Open(path string, flag int, perm os.FileMode, ttl ...time.Duration) (file *
|
||||
return pool.File()
|
||||
}
|
||||
|
||||
// Get returns a file item with given file path, flag and opening permission.
|
||||
// It retrieves a file item from the file pointer pool after then.
|
||||
func Get(path string, flag int, perm os.FileMode, ttl ...time.Duration) (file *File) {
|
||||
var fpTTL time.Duration
|
||||
if len(ttl) > 0 {
|
||||
fpTTL = ttl[0]
|
||||
}
|
||||
|
||||
f, found := pools.Search(fmt.Sprintf("%s&%d&%d&%d", path, flag, fpTTL, perm))
|
||||
if !found {
|
||||
return nil
|
||||
}
|
||||
|
||||
fp, _ := f.(*Pool).pool.Get()
|
||||
return fp.(*File)
|
||||
}
|
||||
|
||||
// Stat returns the FileInfo structure describing file.
|
||||
func (f *File) Stat() (os.FileInfo, error) {
|
||||
if f.stat == nil {
|
||||
@ -48,7 +65,11 @@ func (f *File) Stat() (os.FileInfo, error) {
|
||||
}
|
||||
|
||||
// Close puts the file pointer back to the file pointer pool.
|
||||
func (f *File) Close() error {
|
||||
func (f *File) Close(close ...bool) error {
|
||||
if len(close) > 0 && close[0] {
|
||||
f.File.Close()
|
||||
}
|
||||
|
||||
if f.pid == f.pool.id.Val() {
|
||||
return f.pool.pool.Put(f)
|
||||
}
|
||||
|
||||
@ -120,7 +120,7 @@ func (w *Watcher) eventLoop() {
|
||||
|
||||
}
|
||||
// Calling the callbacks in order.
|
||||
for _, v := range callbacks {
|
||||
for _, callback := range callbacks {
|
||||
go func(callback *Callback) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
@ -133,7 +133,7 @@ func (w *Watcher) eventLoop() {
|
||||
}
|
||||
}()
|
||||
callback.Func(event)
|
||||
}(v)
|
||||
}(callback)
|
||||
}
|
||||
} else {
|
||||
break
|
||||
|
||||
@ -8,8 +8,9 @@
|
||||
package glog
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/v2/os/gcmd"
|
||||
"github.com/gogf/gf/v2/internal/command"
|
||||
"github.com/gogf/gf/v2/os/grpool"
|
||||
"github.com/gogf/gf/v2/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -30,7 +31,7 @@ var (
|
||||
)
|
||||
|
||||
func init() {
|
||||
defaultDebug = gcmd.GetOptWithEnv(commandEnvKeyForDebug, true).Bool()
|
||||
defaultDebug = gconv.Bool(command.GetOptWithEnv(commandEnvKeyForDebug, "true"))
|
||||
SetDebug(defaultDebug)
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@ -309,10 +310,27 @@ func (l *Logger) printToFile(ctx context.Context, t time.Time, in *HandlerInput)
|
||||
defer gmlock.Unlock(memoryLockKey)
|
||||
|
||||
// Rotation file size checks.
|
||||
if l.config.RotateSize > 0 {
|
||||
if gfile.Size(logFilePath) > l.config.RotateSize {
|
||||
if l.config.RotateSize > 0 && gfile.Size(logFilePath) > l.config.RotateSize {
|
||||
if runtime.GOOS == "windows" {
|
||||
file := l.getFilePointer(ctx, logFilePath)
|
||||
if file == nil {
|
||||
intlog.Errorf(ctx, `got nil file pointer for: %s`, logFilePath)
|
||||
return buffer
|
||||
}
|
||||
|
||||
if _, err := file.Write(buffer.Bytes()); err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
}
|
||||
|
||||
if err := file.Close(true); err != nil {
|
||||
intlog.Errorf(ctx, `%+v`, err)
|
||||
}
|
||||
l.rotateFileBySize(ctx, t)
|
||||
|
||||
return buffer
|
||||
}
|
||||
|
||||
l.rotateFileBySize(ctx, t)
|
||||
}
|
||||
// Logging content outputting to disk file.
|
||||
if file := l.getFilePointer(ctx, logFilePath); file == nil {
|
||||
@ -343,6 +361,21 @@ func (l *Logger) getFilePointer(ctx context.Context, path string) *gfpool.File {
|
||||
return file
|
||||
}
|
||||
|
||||
// getFilePointer retrieves and returns a file pointer from file pool.
|
||||
func (l *Logger) getOpenedFilePointer(ctx context.Context, path string) *gfpool.File {
|
||||
|
||||
file := gfpool.Get(
|
||||
path,
|
||||
defaultFileFlags,
|
||||
defaultFilePerm,
|
||||
defaultFileExpire,
|
||||
)
|
||||
if file == nil {
|
||||
intlog.Errorf(ctx, `can not find the file, path:%s`, path)
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
// printStd prints content `s` without stack.
|
||||
func (l *Logger) printStd(ctx context.Context, level int, value ...interface{}) {
|
||||
l.print(ctx, level, "", value...)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user