Compare commits

...

140 Commits

Author SHA1 Message Date
894f202b75 version v2.4.0 (#2595) 2023-04-24 11:44:19 +08:00
9171585b2c improve auto retrieving of ip addresses for service registering (#2593) 2023-04-23 21:58:17 +08:00
23d8ef32a3 fix: fix typo and go-staticcheck S1002 warning (#2590) 2023-04-21 10:13:59 +08:00
a031e112e5 add command gen enums (#2591) 2023-04-20 16:30:42 +08:00
da8297d770 improve AddObject to support Command/*Command parameter for package gcmd (#2587) 2023-04-18 10:09:07 +08:00
3991eb053c fix issue #2584 (#2586) 2023-04-17 17:44:24 +08:00
6fb26c44d7 fix issue converting values to custom type pointers (#2585) 2023-04-17 16:34:36 +08:00
fdc027734c add command make version to in Makefile (#2579) 2023-04-14 10:09:19 +08:00
32a7f6a0f0 feature/v2.4.0-rc4 (#2578)
* v2.4.0-rc3

* v2.4.0-rc4
2023-04-12 22:01:24 +08:00
5bbec48679 v2.4.0-rc2 (#2575) 2023-04-12 21:14:03 +08:00
d4b9ee4c61 version updates to v2.4.0-rc (#2574)
version updates
2023-04-12 20:24:20 +08:00
50b5cd50bc fix issue in New when creating concurrent-safety var for package gvar (#2573) 2023-04-12 17:38:06 +08:00
53afbd0f05 uf case update for contrib/drivers/mysql (#2569) 2023-04-12 15:36:44 +08:00
b6874eb66d update cli build action (#2563) 2023-04-12 11:54:15 +08:00
7ff7de4643 inherit context from http.Request for ghttp.Request (#2550) 2023-04-12 11:54:06 +08:00
5f148632d2 fix missing trace id in gctx.GetInitCtx (#2562) 2023-04-12 10:35:24 +08:00
c1325ef9a3 Add Filter function to garray (#2541) 2023-04-12 10:15:11 +08:00
d788b7ff5e fix issue #2529 #2487 (#2548) 2023-04-12 10:14:14 +08:00
66d0663dc5 add clickhouse support in command gf gen dao (#2557) 2023-04-12 10:14:04 +08:00
a56524ee05 add RemoveValues for package garray (#2568)
add RemoveValues for package garray
2023-04-12 10:12:28 +08:00
1aa9f2809e improve stream response for http (#2564) 2023-04-12 10:12:11 +08:00
261672e84c feat: automatic update gf for contrib (#2551) 2023-04-11 21:13:29 +08:00
6a4e39e815 change temp dir to os.TempDir for package gfile (#2547) 2023-03-29 11:58:20 +08:00
4af9ce8a81 Bump golang.org/x/crypto from 0.0.0-20200622213623-75b288015ac9 to 0.1.0 in /cmd/gf (#2546) 2023-03-28 20:03:07 +08:00
5f146720fe fix: unified go.mod dependent version (#2452) 2023-03-28 09:25:29 +08:00
67e6772d88 comment updates for gdb.Builder (#2513) 2023-03-28 09:23:08 +08:00
12e9febe9e fix issue #2516 (#2531)
* fix issue #2516

* golang ci configuration updates

* add example for default value of http request
2023-03-22 20:14:57 +08:00
676022eeb6 fix issue #2509 (#2530) 2023-03-21 22:10:41 +08:00
XG
3a8fc1e70d optimize the handling of the SIGUSR1 signal (#2532)
optimize the handling of the SIGUSR1 signal
2023-03-21 21:26:49 +08:00
0b6798acb5 add Quick mode for gtimer (#2488) 2023-03-20 10:00:55 +08:00
e721124b6c support microseconds resolution for created_at/updated_at/deleted_at (#2512) 2023-03-20 09:57:37 +08:00
b32eb30212 feat: improve polaris register and upgrade polaris-go version v1.3.0 (#2524) 2023-03-20 09:52:58 +08:00
967a39ecbe feat:upgrade polairs-go sdk version v1.3.0 for config (#2525)
feat:upgrade polairs-go sdk version v1.3.0
2023-03-20 09:52:19 +08:00
dfb7f5abfb improve error message when the router hander definition is not standrad (#2528) 2023-03-20 09:51:43 +08:00
56f5d5125b fix quick exit when double click cli to install/upgrade (#2521) 2023-03-17 17:56:41 +08:00
5083174a92 fix goreport for gofmt (#2523) 2023-03-17 17:54:14 +08:00
4a278dfd79 improve grpcx (#2522) 2023-03-17 17:51:10 +08:00
80d57ed8f9 add postForm with multi data content type support (#2508) 2023-03-14 09:57:22 +08:00
b742e222d6 improve command gen pb by adding controller go files generating (#2518) 2023-03-14 09:47:42 +08:00
ae86f66545 fix issue #2499 #2515 (#2517) 2023-03-13 22:16:57 +08:00
45e4c9e16c add tag value of in support for api definition that has meta info (#2450) 2023-03-13 19:29:30 +08:00
XG
8c07f1a42c feat: support graceful shutdown (#2469) (#2475) 2023-03-13 19:21:56 +08:00
e6c97410ef fix: cli gen service:BUG #2310 (#2485) 2023-03-13 19:17:23 +08:00
b1a55c7a32 improvement for grpcx (#2510) 2023-03-13 18:56:19 +08:00
1cd1449085 add package contrib/rpc/grpcx (#2169) 2023-03-08 14:12:51 +08:00
55690f3738 improve unit testing cases coverage to 80%+ (#2480) 2023-03-07 21:27:23 +08:00
13f6fb1929 fix issue struct attribute converting when has no json name but with omitempty tag (#2486) 2023-03-07 21:26:32 +08:00
e8088a6563 improve command gen dao by removing all dao files if clear option is true (#2502)
* improve command  by removing all dao files if clear option is true

* version updates
2023-03-07 19:32:13 +08:00
e8051bad9a fix issue in empty json name along with omitempty tag in package oai (#2500) 2023-03-07 14:17:14 +08:00
d0d41a63a6 robot translator updates (#2491) 2023-03-07 11:01:01 +08:00
853b038a47 add issue translation robot (#2490) 2023-03-06 09:50:03 +08:00
34946f6105 fix configuration of Namespace for pgsql (#2481) 2023-03-01 19:30:40 +08:00
Gin
15d88c269d fix: gredis maxActive config and duplicate connection bug (#2479) 2023-02-27 22:08:37 +08:00
cbbfd85eeb Protect RemoveValue from race condition (#2472) 2023-02-23 19:47:57 +08:00
adf90c876f improve unit testing cases (#2468) 2023-02-23 10:07:40 +08:00
b4f76b8448 fix: use keyword(like: group) as table name in sqlite (#2461) 2023-02-20 22:03:26 +08:00
ed858ebd4b Bump golang.org/x/net from 0.1.0 to 0.7.0 in /cmd/gf (#2460) 2023-02-20 22:02:31 +08:00
272b9c7afd README update for cmd/gf (#2459) 2023-02-20 22:01:36 +08:00
8dc8dd9756 fix issue #2261 (#2458) 2023-02-20 21:57:49 +08:00
a64d1001e2 improve ci by using cache feature of setup-go (#2463) 2023-02-20 21:51:54 +08:00
ad737ded3c fix issue #2447 (#2448) 2023-02-15 14:13:32 +08:00
ac6b0c0980 fix issue #2427 (#2442) 2023-02-15 09:45:40 +08:00
b69e0ff9f7 fix issue #2338 (#2444) 2023-02-14 09:45:29 +08:00
0361f9f7de fix #2435 (#2437) 2023-02-13 19:18:30 +08:00
005668aca8 gdb error should wrap original underlying database error like MySQLError (#2402) 2023-02-08 19:38:11 +08:00
013f8b216a improve Timezone escape for driver dm/mysql (#2412) 2023-02-08 19:35:48 +08:00
8ecfa91e5d comment updates for with function of package gdb (#2418) 2023-02-08 19:10:03 +08:00
117fc6eda2 fix issue #2339 (#2433) 2023-02-08 19:08:10 +08:00
d66af122c7 fix issue #2331 (#2432) 2023-02-08 19:07:05 +08:00
a7467945ca fix issue #2355 (#2430) 2023-02-08 14:17:21 +08:00
81d8aa55cd fix issue #2371 (#2429) 2023-02-08 14:17:11 +08:00
4a6630138d fix issue 2356 (#2428) 2023-02-08 14:17:00 +08:00
3adae3a9aa fix type of default value in swagger ui for package goai (#2413) 2023-02-08 14:16:12 +08:00
21ebf48072 .gitignore updates (#2426) 2023-02-07 21:13:20 +08:00
2b90bcfab6 fix issue #2050: add -t option support for command gf docker to compatable with older version (#2423) 2023-02-07 17:41:43 +08:00
5f0641f348 fix issue #2015 (#2422) 2023-02-07 14:06:26 +08:00
38c9cac578 fix issue #2011 (#2421) 2023-02-07 11:37:39 +08:00
9ba49fa454 fix issue in gf run failed with arguments passed in windows platform (#2414) 2023-02-06 20:35:11 +08:00
39fede66e6 add label planned for ci to check issue inactive (#2408)
add label planned for ci to check issue inactive
2023-01-18 17:04:26 +08:00
d984f1a9d8 add auto go mod tidy after version upgraded for command up (#2407)
* add cli upgraded supported for command up

* improve unit case for package internal/mutex

* v2.3.1

* add auto  after version upgraded for command

Co-authored-by: houseme <housemecn@gmail.com>
2023-01-18 11:28:55 +08:00
Gin
28b8efe00c fix issue 2403 (#2404) 2023-01-18 10:17:16 +08:00
7b0fd6de9b add cli upgraded supported for command up (#2405)
* add cli upgraded supported for command up

* improve unit case for package internal/mutex

* v2.3.1

Co-authored-by: houseme <housemecn@gmail.com>
2023-01-18 10:12:00 +08:00
c0fa2e3a73 fix issue 2395 (#2399)
* v2.3.0

* fix #2391

* fix issue #2391

* fix issue #2395
2023-01-17 14:51:19 +08:00
3f6669e2b7 fix issue 2391 (#2398)
* v2.3.0

* fix #2391

* fix issue #2391
2023-01-16 16:00:18 +08:00
6ff4ed84e5 version v2.3.0 (#2392)
* v2.3.0

* up

* up

* up
2023-01-11 19:19:41 +08:00
5e72b03b0a feature/v2.3.0 (#2296)
* up

* rename function names for package gtcp/gudp; add proxy example for gtcp.Server (#2295)

* fix  router supported for handler of package ghttp; fix json tag name issue when it contains  for package goai

* add proxy example for http server

* rename function names for package gtcp/gudp; add proxy example for gtcp.Server

* move TX from struct to interface for package gdb (#2247)

* move TX from struct to interface for package gdb

* i updates

* up

* up

* fix comment

Co-authored-by: houseme <housemecn@gmail.com>

* move `go-redis` implements `Adapter` from package `gredis` to `contrib/nosql/redis`; add redis string operation functions for package `gredis` (#2240)

* unify configuration pattern of  for package gdb

* version updates

* improve implements `internal/rwmutex` and `internal/mutex`; add `TablesFields` cache implements in `gdb.Core` instead of `contrib/drivers`; add `ClearTableFields` and `ClearCache` functions for `gdb.Core` (#2128)

* add ClearTableFiels/ClearCache for Core of package gdb

* improve TableFields for contrib/drivers

* fix UT case for contrib/drivers/clickhouse

* remove unecessary attribute state for internal/rwmutex and internal/mutex

* add ClearTableFieldsAll/ClearCacheAll for gdb.Core

* improve clickhouse driver

* improve clickhouse driver

* fix ut

* feat: improve import

Co-authored-by: daguang <daguang830@gmail.com>
Co-authored-by: houseme <housemecn@gmail.com>

* refract builtin rules management mechanism, add `eq/not-eq/gt/gte/lt/lte/before/before-equal/after/after-equal/array/not-regex` rules for for package `gvalid` (#2133)

* refract builtin rules management for package gvalid

* refract builtin rules management for package gvalid

* refract builtin rules management for package gvalid

* add valiation rules  and  implements for package gvalid

* UT cases update for package gvalid

* improve error message of fields validation for package gvalid

* up

* add more validation rules for package gvalid

* add validation rule foreach for package gvalid (#2136)

* add ToSQL/CatchSQL funcions for package gdb (#2137)

* add ToSQL/CatchSQL funcions for package gdb

* Update gdb_core_underlying.go

* fix ci

Co-authored-by: houseme <housemecn@gmail.com>

* add redis interface for package gredis

* up

* remove `FilteredLink` function for DB and all driver implements and improve details for package gdb (#2142)

* fix: pgsql DoExec Transaction checks (#2101)

Co-authored-by: John Guo <john@johng.cn>

* improve package gdb

* up

* up

* up

* up

* up

* add DriverWrapper and DriverWarapperDB for package gdb

* add DriverWrapper and DriverWarapperDB for package gdb

* up

Co-authored-by: HaiLaz <739476267@qq.com>

* add new database driver `dm`

* add drivers dm

* upd go version

* add gf ci yaml

Co-authored-by: Xu <zhenghao.xu>

* move go-redis implements from package gredis to contrib/nosql/redis; add redis string operation functions for package gredis

* improve `contrib/drivers/dm` (#2144)

* improve contrib/drivers/dm

* format TODO list info

* 1) add config.Name is required
2) The upper layer no longer needs to specify the schema
3) Adjust unit tests

Co-authored-by: Xu <zhenghao.xu>
Co-authored-by: houseme <housemecn@gmail.com>

* move redis adapter related ut case from package gcache/gsession to package contrib/nosql/redis

* up

* up

* up

* up

* up

* improve comment

* add implements of `gcfg.Adapter` using kubernetes configmap (#2145)

* remove Logger from kubecm.Client

* README updates for package kubecm

* error message update for package gredis

* comment update for package gdb

* Feature/v2.2.0 gredis (#2155)

* improve package gredis (#2162)

* improve package gredis

* Update gredis_redis_group_list.go

* fix

* up

Co-authored-by: houseme <housemecn@gmail.com>

* up

* up

* up

* up

* up

* up

* add func Test_GroupScript_Eval

* ut cases for group string

* UT cases update for group script

* mv redis operation implements to contrib/nosql/redis from package gredis

* test: add redis group list unit test (#2248)

* test: add redis group list unit test

* improve comment

* test: fix redis group list unit test

Co-authored-by: houseme <housemecn@gmail.com>

* up

* add func Test_GroupGeneric_Copy, Test_GroupGeneric_Exists,Test_GroupGeneric_Type,Test_GroupGeneric_Unlink,Test_GroupGeneric_Rename,Test_GroupGeneric_Move,Test_GroupGeneric_Del

* add Redis GroupGeneric UnitTest (#2253)

add func Test_GroupGeneric_RandomKey,Test_GroupGeneric_DBSize,Test_GroupGeneric_Keys,Test_GroupGeneric_FlushDB,Test_GroupGeneric_FlushAll,Test_GroupGeneric_Expire,Test_GroupGeneric_ExpireAt

* hash test case completed (#2260)

Co-authored-by: junler <sunjun@bookan.com>

* add Redis GroupGeneric Unit Test part2 (#2258)

* up

* ci updates

* ci updates

* up

* Feature/contrib redis fsprouts (#2274)

* Feature/contrib redis starck (#2275)

* up

* up

* fix `/*` router supported for handler of package ghttp; fix json tag name issue when it contains `,` for package goai; add proxy example for http server (#2294)

* fix  router supported for handler of package ghttp; fix json tag name issue when it contains  for package goai

* add proxy example for http server

* fix: update szenius/set-timezone@v1.1 (#2293)

* add Tag* functions to retreive most commonly used tag value from struct field for package gstructs; use description tag as default value if brief is empty for gcmd.Argument (#2299)

* fix cache issue in Count/Value functions for gdb.Model (#2300)

* add Tag* functions to retreive most commonly used tag value from struct field for package gstructs; use description tag as default value if brief is empty for gcmd.Argument

* fix cache issue in Count/Value functions for gdb.Model

* add more ut case for package gdb

* version updates

* add minus of `start` parameter support for `gstr.Substr`, like the `substr` function in `PHP` (#2297)

* Make the substr like the substr in PHP

Make the substr like the substr in PHP

* Update gstr_z_unit_test.go

* Update gstr_z_unit_test.go

* Make the SubStrRune like the mb_substr in PHP

Make the SubStrRune like the mb_substr in PHP

* Update gstr_z_unit_test.go

* Update gstr_z_unit_test.go

* Update gins_z_unit_view_test.go

* Update gview_z_unit_test.go

* add ut cases for package gcode (#2307)

* add ut cases for package gerror (#2304)

* add ut cases for package gerror

* add ut cases for package gerror

* add ut cases for package gtime (#2303)

* add ut cases for package gtime

* add ut cases for package gtime

* add ut cases for package gtime

* add ut cases for package glog (#2302)

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* change result data type of function Count from int to int64 for package gdb (#2298)

* feat: modify model count value int64

* fix

* fix:modify int64

* fix

* feat: cmd gf prebuild suport oracle (#2312)

* add ut cases for package g (#2315)

* add ut cases for package gdebug (#2313)

* add ut cases for package gdebug

* add ut cases for package gdebug

* add ut cases for package gdebug

Co-authored-by: houseme <housemecn@gmail.com>

* add zookeeper registry support (#2284)

* add ut cases for package glog part2 (#2317)

* fix invalid UpdatedAt usage in soft deleting feature for package gdb (#2323)

* fix issue in failed installing when there's shortcut between file paths for command install (#2326)

* fix issue in failed installing when has shortcut between file paths for command install

* version updates

* template for command gf updates

* improve lru clearing for package gcache (#2327)

* add ut cases for package ghttp_middleware and ghttp_request (#2344)

* add ut cases for package ghttp_middleware

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request

* add ut cases for package ghttp_response (#2352)

* add ut cases for package ghttp_response

* add ut cases for package ghttp_response

* add ut cases for package ghttp_response

* add ut cases for package ghttp_request (#2351)

* add ut cases for package ghttp_middleware

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request - form

* add ut cases for package ghttp_request - query

* add ut cases for package ghttp_request - request

* add ut cases for package ghttp_request - router

* add ut cases for package gcache (#2341)

* gTcp Example Function:
1.NewConn 2.NewConnTLS 3.NewConnKeyCrt

* gTcp Example Function:
1.Send

* add example function ExampleConn_Recv and ExampleConn_RecvWithTimeout

* add example function
1. ExampleConn_SendWithTimeout
2. ExampleConn_RecvLine
3. ExampleConn_RecvTill

* add example function
1. ExampleConn_SendRecv
2. ExampleConn_SendRecvWithTimeout
3. ExampleConn_SetDeadline
4. ExampleConn_SetReceiveBufferWait

* add gtcp test function
1. Test_Package_Option_HeadSize4
2. Test_Package_Option_Error

* add gtcp example function
1. ExampleGetFreePorts
2. ExampleSend
3. ExampleSendRecv
4. ExampleSendWithTimeout
5. ExampleSendRecvWithTimeout
6. ExampleMustGetFreePort

* add gtcp example function
1. ExampleSendPkg
2. ExampleSendRecvPkg
3. ExampleSendPkgWithTimeout
4. ExampleSendRecvPkgWithTimeout

* add gtcp test function
1. Test_Pool_Send
2. Test_Pool_Recv
3. Test_Pool_RecvLine
4. Test_Pool_RecvTill
5. Test_Pool_RecvWithTimeout
6. Test_Pool_SendWithTimeout
7. Test_Pool_SendRecvWithTimeout

* fix

* add gtcp example function
1. ExampleGetServer
2. ExampleSetAddress
3. ExampleSetHandler
4. ExampleRun_NilHandle

* exec CI

* exec CI

* exec CI

* modify test server address

* modify and exec CI

* modify and exec CI

* modify and exec CI

* modify and exec CI

* modify and exec CI

* modify and exec CI

* add example funcion ExampleConn_Recv_Once and fix

* fix

* add some error case in example function

* add some error case in example function

* 1.add example function ExampleNewServerKeyCrt
2.add function SendRecvPkgWithTimeout unit test

* add function Test_Server_NewServerKeyCrt unit test

* revert

* add function Test_Package_Timeout, Test_Package_Option_HeadSize3, Test_Conn_RecvPkgError unit test

* fix

* add example function
1.ExampleClient_Clone
2.ExampleLoadKeyCrt

* add example function
1.ExampleNewNetConnKeyCrt

* fix

* add example function
1.ExampleClient_DeleteBytes
2.ExampleClient_HeadBytes
3.ExampleClient_PatchBytes
4.ExampleClient_ConnectBytes
5.ExampleClient_OptionsBytes
6.ExampleClient_TraceBytes
7.ExampleClient_PutBytes

* add example function
1.ExampleClient_Prefix
2.ExampleClient_Retry
3.ExampleClient_RedirectLimit

* add example function
1.ExampleClient_SetBrowserMode
2.ExampleClient_SetHeader
3.ExampleClient_SetRedirectLimit

* add example function
1.ExampleClient_SetTLSKeyCrt
2.ExampleClient_SetTLSConfig
modify example funcion
1.ExampleClient_SetProxy
2.ExampleClient_Proxy

* add example function
1.ExampleClient_PutContent
2.ExampleClient_DeleteContent
3.ExampleClient_HeadContent
4.ExampleClient_PatchContent
5.ExampleClient_ConnectContent
6.ExampleClient_OptionsContent
7.ExampleClient_TraceContent
8.ExampleClient_RequestContent

* add example function
1.ExampleClient_RawRequest

* add unit function
1.TestGetFreePorts
2.TestNewConn
3.TestNewConnTLS
4.TestNewConnKeyCrt
5.TestConn_SendWithTimeout

* add unit function
1.TestConn_Send
2.TestConn_SendRecv
3.TestConn_SendRecvWithTimeout

* modify

* modify

* add example function
1.TestConn_SetReceiveBufferWait
2.TestNewNetConnKeyCrt
3.TestSend

* add example function
1.TestSendRecv
2.TestSendWithTimeout

* add unit function
1.TestMustGetFreePort
2.TestSendRecvWithTimeout
3.TestSendPkg

* add client recevied server's response content assert

* modify

* modify

* add example function
1.TestSendRecvPkg
2.TestSendPkgWithTimeout
3.TestSendRecvPkgWithTimeout

* add GetAddress() function
add unit funciton
1.TestNewServer
2.TestGetServer
3.TestServer_SetAddress
4.TestServer_SetHandler
5.TestServer_Run

* modify

* modify

* add unit funciton
1.TestLoadKeyCrt

* modify

* delete function fromHex

* add gclient dump unit test

* add example function
1.ExampleClient_Put
2.ExampleClient_Delete
3.ExampleClient_Head
4.ExampleClient_Patch
5.ExampleClient_Connect
6.ExampleClient_Options
7.ExampleClient_Trace

* add example function
1.TestClient_DoRequest

* add example function
1.ExampleClient_PutVar
2.ExampleClient_DeleteVar
3.ExampleClient_HeadVar
4.ExampleClient_PatchVar
5.ExampleClient_ConnectVar
6.ExampleClient_OptionsVar
7.ExampleClient_TraceVar

* modify

* modify

* add CustomProvider function

* modify

* add unit funciton
1.Test_NewConn
2.Test_GetFreePorts

* add unit funciton
1.Test_Server

* garray_normal_any code converage

* garray_normal_int code converage

* garray_normal_str code converage

* garray_sorted_any code converage

* garray_sorted_int code converage

* garray_sorted_str code converage

* glist code converage

* gmap, gmap_hash_any_any_map code converage

* gmap_hash_int_any_map code converage

* gmap_hash_int_any_map code converage

* gmap_hash_int_int_map code converage

* gmap_hash_int_str_map code converage

* gmap_hash_str_any_map code converage

* gmap_hash_str_int_map code converage

* gmap_hash_str_str_map code converage

* gmap_list_map code converage

* gmap_list_map code converage

* revert gf.yml

* add gtest unit test function

* add ut cases for package gcache

* add ut cases for package gcache

* add ut cases for package gcache

* add ut cases for package gcache

* add ut cases for package gcache

* modify

Co-authored-by: John Guo <john@johng.cn>

* improve ut case for package internal/rwmutex (#2364)

* fix issue when only one file was uploaded in batch receiver attribute (#2365)

* fix fixed An error occurred when only one file was uploaded in batches and add unit testing(#2092)

* fix issue uploading files for ghttp.Server

Co-authored-by: yxh <yxh1103@qq.com>

* fix issue #2334 when accessing static files with cache time (#2366)

* Solve the problem of error when accessing static files with cache time.
Error message:
2022-11-29 19:40:11.090 [ERRO] http: superfluous response.WriteHeader call from github.com/gogf/gf/v2/net/ghttp.(*ResponseWriter).Flush (ghttp_response_writer.go:58)
Stack:

Verification method:
curl 'http://127.0.0.1:8000/' -H 'If-Modified-Since: Thu, 08 Dec 2022 03:13:55 GMT' --compressed

* Solve the problem of error when accessing static files with cache time.
Error message:
2022-11-29 19:40:11.090 [ERRO] http: superfluous response.WriteHeader call from github.com/gogf/gf/v2/net/ghttp.(*ResponseWriter).Flush (ghttp_response_writer.go:58)
Stack:

Verification method:
curl 'http://127.0.0.1:8000/' -H 'If-Modified-Since: Thu, 08 Dec 2022 03:13:55 GMT' --compressed

* Solve the problem of error when accessing static files with cache time.
Error message:
2022-11-29 19:40:11.090 [ERRO] http: superfluous response.WriteHeader call from github.com/gogf/gf/v2/net/ghttp.(*ResponseWriter).Flush (ghttp_response_writer.go:58)
Stack:

Verification method:
curl 'http://127.0.0.1:8000/' -H 'If-Modified-Since: Thu, 08 Dec 2022 03:13:55 GMT' --compressed

* fix issue #2334 when accessing static files with cache time

* up

Co-authored-by: 曾洪亮 <hongliang.zeng@i-soft.com.cn>
Co-authored-by: houseme <housemecn@gmail.com>

* fix issue in cycle dumping for g.Dump (#2367)

* fix issue in cycle dumping for g.Dump

* up

* up

* up

Co-authored-by: houseme <housemecn@gmail.com>

* 由于 clickhouse 的 position的初始值为 1,导致gdb_core_utility.HasField 中对 fieldsArray 初始化出错 (#2346)

* 由于 clickhouse 的 position的初始值为 1,导致gdb_core_utility.HasField 中对 fieldsArray 初始化出错

* 修复单元测试

* 修复单元测试

* 补充单元测试

* 增加CK防御性代码

Co-authored-by: longl <longlei@dealmap.cloud>
Co-authored-by: houseme <housemecn@gmail.com>

* fix: ghttp server static path config (#2335)

Co-authored-by: daguang <daguang830@gmail.com>
Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: ftl <1139556759@qq.com>
Co-authored-by: HaiLaz <739476267@qq.com>
Co-authored-by: zhonghuaxunGM <50815786+zhonghuaxunGM@users.noreply.github.com>
Co-authored-by: huangqian <huangqian1985@qq.com>
Co-authored-by: junler <827640651@qq.com>
Co-authored-by: junler <sunjun@bookan.com>
Co-authored-by: Starccck <28645972+starccck@users.noreply.github.com>
Co-authored-by: Jinhongyu <30454170+cnjinhy@users.noreply.github.com>
Co-authored-by: YuanXin Hu <huyuanxin1999@outlook.com>
Co-authored-by: yxh <yxh1103@qq.com>
Co-authored-by: 曾洪亮 <hongliang.zeng@i-soft.com.cn>
Co-authored-by: long <48313408+qq375251855@users.noreply.github.com>
Co-authored-by: longl <longlei@dealmap.cloud>

Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: daguang <daguang830@gmail.com>
Co-authored-by: ftl <1139556759@qq.com>
Co-authored-by: HaiLaz <739476267@qq.com>
Co-authored-by: zhonghuaxunGM <50815786+zhonghuaxunGM@users.noreply.github.com>
Co-authored-by: huangqian <huangqian1985@qq.com>
Co-authored-by: junler <827640651@qq.com>
Co-authored-by: junler <sunjun@bookan.com>
Co-authored-by: Starccck <28645972+starccck@users.noreply.github.com>
Co-authored-by: Jinhongyu <30454170+cnjinhy@users.noreply.github.com>
Co-authored-by: YuanXin Hu <huyuanxin1999@outlook.com>
Co-authored-by: yxh <yxh1103@qq.com>
Co-authored-by: 曾洪亮 <hongliang.zeng@i-soft.com.cn>
Co-authored-by: long <48313408+qq375251855@users.noreply.github.com>
Co-authored-by: longl <longlei@dealmap.cloud>
2023-01-09 14:43:10 +08:00
4bb88027d8 improve function SetTimeZone for package gtime (#2389)
* improve logging feature, add LevelPrint configuration for glog.Logger; add package internal/instance

* improve command build

* add default logger for panic message printing if no logger set

* up

* fix scheduler when timer triggers in less than one second for package gcron

* up

* improve function SetTimeZone for package gtime

* improve function SetTimeZone for package gtime

* improve function SetTimeZone for package gtime

* up
2023-01-09 14:36:42 +08:00
ae4f14c2e2 add LevelPrint configuration for glog.Logger; add package internal/instance for grouped instance management feature; add default logger for panic message printing if no logger set in gcron.Cron (#2388)
* improve logging feature, add LevelPrint configuration for glog.Logger; add package internal/instance

* improve command build

* add default logger for panic message printing if no logger set

* up

* fix scheduler when timer triggers in less than one second for package gcron

* up
2023-01-06 14:15:30 +08:00
5a8b33fa09 fix gf.yaml (#2385)
* fix gf.yaml

* up
2023-01-03 14:33:41 +08:00
5884a0e05f fix issue #2381 (#2382)
* fix issue #2381

* up

* up
2023-01-03 11:00:23 +08:00
31e44062a8 revert from int64 to int for returning value of Count (#2378)
* revert from int64 to int for returning value of Count

* up

* up

* up
2022-12-30 16:54:43 +08:00
87cb1c9b8e add security tag support for openapi (#2377)
* support openapi path security

* add security path test case

* go format

* fix test case

* add doc for security
2022-12-29 20:56:20 +08:00
0266d24d0a fix Unknown setting charset for clickhouse driver (#2375) 2022-12-27 14:46:15 +08:00
0876e00eb8 fix issue in NewIntArrayRange function for package garray (#2374) 2022-12-26 19:28:01 +08:00
85c4794ceb fix BuildParams with urlEncode when len(v) <= 6 (#2308)
* fix: check urlEncode when len(v) <= 6

* fix BuildParams with urlEncode when len(v) <= 6

* fix BuildParams with urlEncode when len(v) <= 6

Co-authored-by: Prime Xiao <primexiao.dev@gmail.com>
2022-12-23 10:33:28 +08:00
e007bf35b2 parseConfigNodeLink support Chinese database name #2231 (#2238) 2022-12-22 17:33:51 +08:00
74e968e93b fix: ghttp server static path config (#2335) 2022-12-22 17:21:33 +08:00
18507fb836 由于 clickhouse 的 position的初始值为 1,导致gdb_core_utility.HasField 中对 fieldsArray 初始化出错 (#2346)
* 由于 clickhouse 的 position的初始值为 1,导致gdb_core_utility.HasField 中对 fieldsArray 初始化出错

* 修复单元测试

* 修复单元测试

* 补充单元测试

* 增加CK防御性代码

Co-authored-by: longl <longlei@dealmap.cloud>
Co-authored-by: houseme <housemecn@gmail.com>
2022-12-22 17:00:08 +08:00
3b245837b9 fix issue in cycle dumping for g.Dump (#2367)
* fix issue in cycle dumping for g.Dump

* up

* up

* up

Co-authored-by: houseme <housemecn@gmail.com>
2022-12-22 14:43:02 +08:00
a853984f52 fix issue #2334 when accessing static files with cache time (#2366)
* Solve the problem of error when accessing static files with cache time.
Error message:
2022-11-29 19:40:11.090 [ERRO] http: superfluous response.WriteHeader call from github.com/gogf/gf/v2/net/ghttp.(*ResponseWriter).Flush (ghttp_response_writer.go:58)
Stack:

Verification method:
curl 'http://127.0.0.1:8000/' -H 'If-Modified-Since: Thu, 08 Dec 2022 03:13:55 GMT' --compressed

* Solve the problem of error when accessing static files with cache time.
Error message:
2022-11-29 19:40:11.090 [ERRO] http: superfluous response.WriteHeader call from github.com/gogf/gf/v2/net/ghttp.(*ResponseWriter).Flush (ghttp_response_writer.go:58)
Stack:

Verification method:
curl 'http://127.0.0.1:8000/' -H 'If-Modified-Since: Thu, 08 Dec 2022 03:13:55 GMT' --compressed

* Solve the problem of error when accessing static files with cache time.
Error message:
2022-11-29 19:40:11.090 [ERRO] http: superfluous response.WriteHeader call from github.com/gogf/gf/v2/net/ghttp.(*ResponseWriter).Flush (ghttp_response_writer.go:58)
Stack:

Verification method:
curl 'http://127.0.0.1:8000/' -H 'If-Modified-Since: Thu, 08 Dec 2022 03:13:55 GMT' --compressed

* fix issue #2334 when accessing static files with cache time

* up

Co-authored-by: 曾洪亮 <hongliang.zeng@i-soft.com.cn>
Co-authored-by: houseme <housemecn@gmail.com>
2022-12-22 10:25:30 +08:00
00c544ee99 fix issue when only one file was uploaded in batch receiver attribute (#2365)
* fix fixed An error occurred when only one file was uploaded in batches and add unit testing(#2092)

* fix issue uploading files for ghttp.Server

Co-authored-by: yxh <yxh1103@qq.com>
2022-12-21 10:38:19 +08:00
e7b9e41a5e improve ut case for package internal/rwmutex (#2364) 2022-12-20 15:56:29 +08:00
e254b4f3c0 add ut cases for package gcache (#2341)
* gTcp Example Function:
1.NewConn 2.NewConnTLS 3.NewConnKeyCrt

* gTcp Example Function:
1.Send

* add example function ExampleConn_Recv and ExampleConn_RecvWithTimeout

* add example function
1. ExampleConn_SendWithTimeout
2. ExampleConn_RecvLine
3. ExampleConn_RecvTill

* add example function
1. ExampleConn_SendRecv
2. ExampleConn_SendRecvWithTimeout
3. ExampleConn_SetDeadline
4. ExampleConn_SetReceiveBufferWait

* add gtcp test function
1. Test_Package_Option_HeadSize4
2. Test_Package_Option_Error

* add gtcp example function
1. ExampleGetFreePorts
2. ExampleSend
3. ExampleSendRecv
4. ExampleSendWithTimeout
5. ExampleSendRecvWithTimeout
6. ExampleMustGetFreePort

* add gtcp example function
1. ExampleSendPkg
2. ExampleSendRecvPkg
3. ExampleSendPkgWithTimeout
4. ExampleSendRecvPkgWithTimeout

* add gtcp test function
1. Test_Pool_Send
2. Test_Pool_Recv
3. Test_Pool_RecvLine
4. Test_Pool_RecvTill
5. Test_Pool_RecvWithTimeout
6. Test_Pool_SendWithTimeout
7. Test_Pool_SendRecvWithTimeout

* fix

* add gtcp example function
1. ExampleGetServer
2. ExampleSetAddress
3. ExampleSetHandler
4. ExampleRun_NilHandle

* exec CI

* exec CI

* exec CI

* modify test server address

* modify and exec CI

* modify and exec CI

* modify and exec CI

* modify and exec CI

* modify and exec CI

* modify and exec CI

* add example funcion ExampleConn_Recv_Once and fix

* fix

* add some error case in example function

* add some error case in example function

* 1.add example function ExampleNewServerKeyCrt
2.add function SendRecvPkgWithTimeout unit test

* add function Test_Server_NewServerKeyCrt unit test

* revert

* add function Test_Package_Timeout, Test_Package_Option_HeadSize3, Test_Conn_RecvPkgError unit test

* fix

* add example function
1.ExampleClient_Clone
2.ExampleLoadKeyCrt

* add example function
1.ExampleNewNetConnKeyCrt

* fix

* add example function
1.ExampleClient_DeleteBytes
2.ExampleClient_HeadBytes
3.ExampleClient_PatchBytes
4.ExampleClient_ConnectBytes
5.ExampleClient_OptionsBytes
6.ExampleClient_TraceBytes
7.ExampleClient_PutBytes

* add example function
1.ExampleClient_Prefix
2.ExampleClient_Retry
3.ExampleClient_RedirectLimit

* add example function
1.ExampleClient_SetBrowserMode
2.ExampleClient_SetHeader
3.ExampleClient_SetRedirectLimit

* add example function
1.ExampleClient_SetTLSKeyCrt
2.ExampleClient_SetTLSConfig
modify example funcion
1.ExampleClient_SetProxy
2.ExampleClient_Proxy

* add example function
1.ExampleClient_PutContent
2.ExampleClient_DeleteContent
3.ExampleClient_HeadContent
4.ExampleClient_PatchContent
5.ExampleClient_ConnectContent
6.ExampleClient_OptionsContent
7.ExampleClient_TraceContent
8.ExampleClient_RequestContent

* add example function
1.ExampleClient_RawRequest

* add unit function
1.TestGetFreePorts
2.TestNewConn
3.TestNewConnTLS
4.TestNewConnKeyCrt
5.TestConn_SendWithTimeout

* add unit function
1.TestConn_Send
2.TestConn_SendRecv
3.TestConn_SendRecvWithTimeout

* modify

* modify

* add example function
1.TestConn_SetReceiveBufferWait
2.TestNewNetConnKeyCrt
3.TestSend

* add example function
1.TestSendRecv
2.TestSendWithTimeout

* add unit function
1.TestMustGetFreePort
2.TestSendRecvWithTimeout
3.TestSendPkg

* add client recevied server's response content assert

* modify

* modify

* add example function
1.TestSendRecvPkg
2.TestSendPkgWithTimeout
3.TestSendRecvPkgWithTimeout

* add GetAddress() function
add unit funciton
1.TestNewServer
2.TestGetServer
3.TestServer_SetAddress
4.TestServer_SetHandler
5.TestServer_Run

* modify

* modify

* add unit funciton
1.TestLoadKeyCrt

* modify

* delete function fromHex

* add gclient dump unit test

* add example function
1.ExampleClient_Put
2.ExampleClient_Delete
3.ExampleClient_Head
4.ExampleClient_Patch
5.ExampleClient_Connect
6.ExampleClient_Options
7.ExampleClient_Trace

* add example function
1.TestClient_DoRequest

* add example function
1.ExampleClient_PutVar
2.ExampleClient_DeleteVar
3.ExampleClient_HeadVar
4.ExampleClient_PatchVar
5.ExampleClient_ConnectVar
6.ExampleClient_OptionsVar
7.ExampleClient_TraceVar

* modify

* modify

* add CustomProvider function

* modify

* add unit funciton
1.Test_NewConn
2.Test_GetFreePorts

* add unit funciton
1.Test_Server

* garray_normal_any code converage

* garray_normal_int code converage

* garray_normal_str code converage

* garray_sorted_any code converage

* garray_sorted_int code converage

* garray_sorted_str code converage

* glist code converage

* gmap, gmap_hash_any_any_map code converage

* gmap_hash_int_any_map code converage

* gmap_hash_int_any_map code converage

* gmap_hash_int_int_map code converage

* gmap_hash_int_str_map code converage

* gmap_hash_str_any_map code converage

* gmap_hash_str_int_map code converage

* gmap_hash_str_str_map code converage

* gmap_list_map code converage

* gmap_list_map code converage

* revert gf.yml

* add gtest unit test function

* add ut cases for package gcache

* add ut cases for package gcache

* add ut cases for package gcache

* add ut cases for package gcache

* add ut cases for package gcache

* modify

Co-authored-by: John Guo <john@johng.cn>
2022-12-20 14:49:31 +08:00
b0c9c68c9c add ut cases for package ghttp_request (#2351)
* add ut cases for package ghttp_middleware

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request - form

* add ut cases for package ghttp_request - query

* add ut cases for package ghttp_request - request

* add ut cases for package ghttp_request - router
2022-12-12 10:28:58 +08:00
1030434ce6 add ut cases for package ghttp_response (#2352)
* add ut cases for package ghttp_response

* add ut cases for package ghttp_response

* add ut cases for package ghttp_response
2022-12-12 10:28:35 +08:00
2f08c4b00f add ut cases for package ghttp_middleware and ghttp_request (#2344)
* add ut cases for package ghttp_middleware

* add ut cases for package ghttp_request

* add ut cases for package ghttp_request
2022-12-07 20:02:46 +08:00
4553f90a83 improve lru clearing for package gcache (#2327) 2022-11-25 10:45:56 +08:00
ef7fec7e24 fix issue in failed installing when there's shortcut between file paths for command install (#2326)
* fix issue in failed installing when has shortcut between file paths for command install

* version updates

* template for command gf updates
2022-11-25 10:34:00 +08:00
0a76b9c61b fix invalid UpdatedAt usage in soft deleting feature for package gdb (#2323) 2022-11-24 21:23:15 +08:00
fbeb8f81ac add ut cases for package glog part2 (#2317) 2022-11-21 10:32:08 +08:00
62af4f1c2c add zookeeper registry support (#2284) 2022-11-18 14:07:17 +08:00
ed43efe4fb add ut cases for package gdebug (#2313)
* add ut cases for package gdebug

* add ut cases for package gdebug

* add ut cases for package gdebug

Co-authored-by: houseme <housemecn@gmail.com>
2022-11-18 14:05:39 +08:00
1cb42c32e3 add ut cases for package g (#2315) 2022-11-18 14:05:16 +08:00
628b454ebc feat: cmd gf prebuild suport oracle (#2312) 2022-11-17 21:07:12 +08:00
38a858d7d3 change result data type of function Count from int to int64 for package gdb (#2298)
* feat: modify model count value int64

* fix

* fix:modify int64

* fix
2022-11-17 19:47:17 +08:00
83b92ddfa4 add ut cases for package glog (#2302)
* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog

* add ut cases for package glog
2022-11-17 19:44:48 +08:00
7cd415b1df add ut cases for package gtime (#2303)
* add ut cases for package gtime

* add ut cases for package gtime

* add ut cases for package gtime
2022-11-17 19:44:20 +08:00
d2113b4d23 add ut cases for package gerror (#2304)
* add ut cases for package gerror

* add ut cases for package gerror
2022-11-17 19:43:54 +08:00
d445987f95 add ut cases for package gcode (#2307) 2022-11-17 19:43:04 +08:00
14d2d747f6 add minus of start parameter support for gstr.Substr, like the substr function in PHP (#2297)
* Make the substr like the substr in PHP

Make the substr like the substr in PHP

* Update gstr_z_unit_test.go

* Update gstr_z_unit_test.go

* Make the SubStrRune like the mb_substr in PHP

Make the SubStrRune like the mb_substr in PHP

* Update gstr_z_unit_test.go

* Update gstr_z_unit_test.go

* Update gins_z_unit_view_test.go

* Update gview_z_unit_test.go
2022-11-16 10:10:59 +08:00
73dc8c9c4b fix cache issue in Count/Value functions for gdb.Model (#2300)
* add Tag* functions to retreive most commonly used tag value from struct field for package gstructs; use description tag as default value if brief is empty for gcmd.Argument

* fix cache issue in Count/Value functions for gdb.Model

* add more ut case for package gdb

* version updates
2022-11-16 10:04:49 +08:00
576f1a798c add Tag* functions to retreive most commonly used tag value from struct field for package gstructs; use description tag as default value if brief is empty for gcmd.Argument (#2299) 2022-11-15 17:05:34 +08:00
78fa2d2e3b fix: update szenius/set-timezone@v1.1 (#2293) 2022-11-14 19:58:17 +08:00
9402cc8c6a fix /* router supported for handler of package ghttp; fix json tag name issue when it contains , for package goai; add proxy example for http server (#2294)
* fix  router supported for handler of package ghttp; fix json tag name issue when it contains  for package goai

* add proxy example for http server
2022-11-14 19:57:39 +08:00
7d1a508ea9 improve ut case for package gcache/gpool (#2290)
* improve ut case for package gcache/gpool

* up
2022-11-12 10:49:48 +08:00
b84034b667 fix: gcache MustGetOrSetFunc error (#2291) 2022-11-10 20:34:48 +08:00
84b7cbd992 ci: action update (#2289) 2022-11-10 20:26:57 +08:00
bc8ca912ce fix: gcron check if the predefined patterns fail (#2288) 2022-11-10 19:59:09 +08:00
b61baa1efc add ut cases for package gconv part2 (#2282) 2022-11-10 19:58:03 +08:00
c4a5bc8584 style(test): Unify the indentation format of SQL strings in clickhouse_test (#2277)
style(test): Unify the indentation format of SQL strings
2022-11-10 19:57:15 +08:00
8c71d579b5 add command fix and up (#2280) 2022-11-10 19:56:12 +08:00
2e8d8f63ff fix IsSubDomain method error (#2283)
Co-authored-by: weiwei3 <weiwei3@37.com>
2022-11-10 19:47:43 +08:00
91b94878d3 fix used schema not change in nested transaction when used different schemas (#2279)
* fix used schema not change in nested transaction between different schemas

* up

Co-authored-by: houseme <housemecn@gmail.com>
2022-11-10 09:55:08 +08:00
b000aa3dfe add supervisor for package grpool (#2252)
* add supervisor for package grpool

* up
2022-11-08 19:00:16 +08:00
582c6eaef9 gtest model unit test (#2267) 2022-11-07 17:56:33 +08:00
4f4109cdb6 fix typo for comments (#2268)
* Modify comment syntax error

* Modify comment syntax error
2022-11-07 17:55:49 +08:00
9f12673631 add ut cases for package gconv (#2272)
* improve gconv.go code coverage

* improve gconv_convert.go code coverage

* improve gconv_float.go code coverage

* improve gconv_map.go code coverage

* improve gconv_maps.go code coverage

* improve gconv_maptomap.go code coverage

* improve gconv_maptomaps.go code coverage
2022-11-07 17:53:51 +08:00
d37b75442d feat: modify sql count value int64 (#2266) 2022-11-07 17:52:25 +08:00
ee58255418 move common used tag from packages to package gtag for maintainability (#2256)
* move common used tag from packages to package gtag for maintainability

* move common used tag from packages to package gtag for maintainability

Co-authored-by: houseme <housemecn@gmail.com>
2022-11-07 17:51:37 +08:00
033ba588c9 fix redis ci yaml (#2269) 2022-11-05 10:23:52 +08:00
585 changed files with 26111 additions and 6974 deletions

View File

@ -1,6 +1,5 @@
#!/usr/bin/env bash
GOARCH=${{ matrix.goarch }}
for file in `find . -name go.mod`; do
dirpath=$(dirname $file)
echo $dirpath
@ -29,12 +28,22 @@ for file in `find . -name go.mod`; do
fi
fi
# package cmd/gf needs golang >= v1.18
if [ "gf" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.18"; then
echo "ignore example as go version: $(go version)"
continue 1
fi
fi
cd $dirpath
go mod tidy
go build ./...
go test ./... -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
if grep -q "/gogf/gf/.*/v2" go.mod; then
sed -i "s/gogf\/gf\(\/.*\)\/v2/gogf\/gf\/v2\1/g" coverage.out
fi
cd -
done

View File

@ -16,12 +16,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Github Code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Set Up Golang Environment
uses: actions/setup-go@v2
uses: actions/setup-go@v4
with:
go-version: 1.17
go-version: 1.20.3
- name: Build CLI Binary
run: |
@ -47,18 +47,18 @@ jobs:
- name: Create Github Release
id: create_release
uses: actions/create-release@v1
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: GoFrame Release ${{ github.ref }}
name: GoFrame Release ${{ github.ref }}
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
uses: alexellis/upload-assets@0.2.2
uses: alexellis/upload-assets@0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:

View File

@ -35,9 +35,18 @@ jobs:
# Service containers to run with `code-test`
services:
# Etcd service.
# docker run -d --name etcd -p 2379:2379 -e ALLOW_NONE_AUTHENTICATION=yes loads/etcd:3.4.24
etcd:
image: loads/etcd:3.4.24
env:
ALLOW_NONE_AUTHENTICATION: yes
ports:
- 2379:2379
# Redis backend server.
redis:
image : loads/redis:latest
image : loads/redis:7.0
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
@ -54,11 +63,12 @@ jobs:
MYSQL_DATABASE : test
MYSQL_ROOT_PASSWORD: 12345678
ports:
# Maps tcp port 3306 on service container to the host
- 3306:3306
# PostgreSQL backend server.
# docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test -v postgres:/Users/john/Temp/postgresql/data loads/postgres:13
# docker run -d --name postgres -p 5432:5432 \
# -e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test \
# -v postgres:/Users/john/Temp/postgresql/data loads/postgres:13
postgres:
image: loads/postgres:13
env:
@ -76,8 +86,15 @@ jobs:
--health-retries 5
# MSSQL backend server.
# docker run -d --name mssql -p 1433:1433 \
# -e ACCEPT_EULA=Y \
# -e SA_PASSWORD=LoremIpsum86 \
# -e MSSQL_DB=test \
# -e MSSQL_USER=root \
# -e MSSQL_PASSWORD=LoremIpsum86 \
# loads/mssqldocker:14.0.3391.2
mssql:
image: loads/mssqldocker:latest
image: loads/mssqldocker:14.0.3391.2
env:
ACCEPT_EULA: Y
SA_PASSWORD: LoremIpsum86
@ -94,17 +111,18 @@ jobs:
--health-retries 10
# ClickHouse backend server.
# docker run -d --name clickhouse -p 9000:9000 -p 8123:8123 -p 9001:9001 loads/clickhouse-server:latest
# docker run -d --name clickhouse -p 9000:9000 -p 8123:8123 -p 9001:9001 loads/clickhouse-server:22.1.3.7
clickhouse-server:
image: loads/clickhouse-server:latest
image: loads/clickhouse-server:22.1.3.7
ports:
- 9000:9000
- 8123:8123
- 9001:9001
# Polaris backend server.
# docker run -d --name polaris -p 8090:8090 -p 8091:8091 -p 8093:8093 loads/polaris-server-standalone:1.11.2
polaris:
image: loads/polaris-server-standalone:latest
image: loads/polaris-server-standalone:1.11.2
ports:
- 8090:8090
- 8091:8091
@ -112,7 +130,7 @@ jobs:
# Oracle 11g server
oracle-server:
image: loads/oracle-xe-11g-r2:latest
image: loads/oracle-xe-11g-r2:11.2.0
env:
ORACLE_ALLOW_REMOTE: true
ORACLE_SID: XE
@ -122,24 +140,31 @@ jobs:
- 1521:1521
# dm8 server
# docker run -d --name dm -p 5236:5236 loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
dm-server:
image: loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
ports:
- 5236:5236
zookeeper:
image: loads/zookeeper:3.8
ports:
- 2181:2181
strategy:
matrix:
go-version: [ "1.15", "1.16", "1.17", "1.18" ]
goarch: [ "386", "amd64" ]
steps:
# TODO: szenius/set-timezone update to node16
- name: Setup Timezone
uses: szenius/set-timezone@v1.0
uses: szenius/set-timezone@v1.1
with:
timezoneLinux: "Asia/Shanghai"
- name: Checkout Repository
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Start Apollo Containers
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" up -d --build
@ -154,21 +179,11 @@ jobs:
uses: medyagh/setup-minikube@master
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v2
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Setup Golang caches
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
~/Library/Caches/go-build
~\AppData\Local\go-build
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go-version }}-
cache: true
cache-dependency-path: '**/go.sum'
- name: Before Script
run: bash .github/workflows/before_script.sh
@ -186,7 +201,7 @@ jobs:
run: docker-compose -f ".github/workflows/nacos/docker-compose.yml" down
- name: Report Coverage
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v3
with:
flags: go-${{ matrix.go-version }}-${{ matrix.goarch }}

View File

@ -25,4 +25,4 @@ jobs:
inactive-label: 'inactive'
inactive-day: 7
issue-state: open
exclude-labels: 'bug,$exclude-empty'
exclude-labels: 'bug,planned,$exclude-empty'

19
.github/workflows/issue-translator.yml vendored Normal file
View File

@ -0,0 +1,19 @@
# https://github.com/usthe/issues-translate-action
name: 'Issue Translator'
on:
issue_comment:
types: [created]
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: usthe/issues-translate-action@v2.7
with:
IS_MODIFY_TITLE: true
# not require, default false. Decide whether to modify the issue title
# if true, the robot account @Issues-translate-bot must have modification permissions,
# invite @Issues-translate-bot to your project or use your custom bot.
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿

View File

@ -3,7 +3,7 @@ version: "2"
services:
redis-master:
container_name: redis-master
image: "loads/redis:7.0"
image: "loads/redis:7.0-sentinel"
environment:
- REDIS_REPLICATION_MODE=master
- REDIS_PASSWORD=111111
@ -12,7 +12,7 @@ services:
redis-slave1:
container_name: redis-slave1
image: "loads/redis:7.0"
image: "loads/redis:7.0-sentinel"
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master
@ -27,7 +27,7 @@ services:
redis-slave2:
container_name: redis-slave2
image: "loads/redis:7.0"
image: "loads/redis:7.0-sentinel"
environment:
- REDIS_REPLICATION_MODE=slave
- REDIS_MASTER_HOST=redis-master

View File

@ -17,9 +17,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Github Code
uses: actions/checkout@v2
uses: actions/checkout@v3
- name: Auto Creating Tags
- name: Auto Creating Tags For Contrib Packages
run: |
git config --global user.email "tagrobot@goframe.org"
git config --global user.name "TagRobot"

4
.gitignore vendored
View File

@ -7,14 +7,12 @@
.settings/
.vscode/
vendor/
composer.lock
gitpush.sh
pkg/
bin/
cbuild
**/.DS_Store
.test/
cmd/gf/main
cmd/gf/gf
go.work
go.work.sum
temp/

View File

@ -135,7 +135,7 @@ linters-settings:
goconst:
# Minimal length of string constant.
# Default: 3
min-len: 2
min-len: 4
# Minimum occurrences of constant string count to trigger issue.
# Default: 3
# For subsequent optimization, the value is reduced.
@ -275,9 +275,8 @@ linters-settings:
# Apply the rewrite rules to the source before reformatting.
# https://pkg.go.dev/cmd/gofmt
# Default: []
rewrite-rules:
rewrite-rules: [ ]
# - pattern: 'interface{}'
# replacement: 'any'
# - pattern: 'a[b:len(a)]'
# replacement: 'a[b:]'

View File

@ -1,4 +1,4 @@
SHELL := /bin/bash
.PHONY: tidy
tidy:
@ -13,4 +13,39 @@ tidy:
.PHONY: lint
lint:
golangci-lint run
golangci-lint run
# make version to=v2.4.0
.PHONY: version
version:
$(eval files=$(shell find . -name go.mod))
@set -e; \
newVersion=$(to); \
echo "The version will be set to $$newVersion"; \
if [[ $$newVersion =~ "v" ]]; then \
latestVersion=$$newVersion; \
echo "package gf" > version.go; \
echo "" >> version.go; \
echo "const (" >> version.go; \
echo -e "\t// VERSION is the current GoFrame version." >> version.go; \
echo -e "\tVERSION = \"$$latestVersion\"" >> version.go; \
echo ")" >> version.go; \
else \
latestVersion=latest; \
fi; \
for file in ${files}; do \
goModPath=$$(dirname $$file); \
if [[ $$goModPath =~ "./contrib" || $$goModPath =~ "./cmd/gf" || $$goModPath =~ "./example" ]]; then \
echo ""; \
echo "processing dir: $$goModPath"; \
# Do not modify the order of any of the following sentences \
cd $$goModPath; \
go mod tidy; \
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@$$latestVersion{{end}}" -m all | grep "^github.com/gogf/gf/contrib" | xargs -L1 go get -v; \
go get -v github.com/gogf/gf/v2@$$latestVersion; \
go mod tidy; \
cd -; \
fi \
done

View File

@ -1,18 +1,20 @@
# GoFrame
<div align=center>
<img src="https://goframe.org/statics/image/gf-head-large.png" width="100"/>
[![Go Doc](https://godoc.org/github.com/gogf/gf?status.svg)](https://godoc.org/github.com/gogf/gf)
[![GoFrame CI](https://github.com/gogf/gf/actions/workflows/gf.yml/badge.svg)](https://github.com/gogf/gf/actions/workflows/gf.yml)
[![Go Report](https://goreportcard.com/badge/github.com/gogf/gf?v=1)](https://goreportcard.com/report/github.com/gogf/gf)
[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf/branch/master)
[![Go Report Card](https://goreportcard.com/badge/github.com/gogf/gf/v2)](https://goreportcard.com/report/github.com/gogf/gf/v2)
[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf)
[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg)](https://github.com/gogf/gf)
[![License](https://img.shields.io/github/license/gogf/gf.svg?style=flat)](https://github.com/gogf/gf)
</div>
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
# Features
- modular, loosely coupled design
- rich components, out-of-the-box
- automatic codes generating for efficiency
@ -27,34 +29,37 @@
- much, much more...ready to explore?
# Installation
Enter your repo. directory and execute following command:
## primary module
```bash
go get -u -v github.com/gogf/gf/v2
```
## cli tool
```bash
go install github.com/gogf/gf/cmd/gf/v2
```
# Limitation
```
golang version >= 1.15
```
# Architecture
<div align=center>
<img src="https://goframe.org/download/attachments/1114119/arch.png"/>
</div>
# Documentation
* Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
- Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
- GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
# License
@ -76,32 +81,20 @@ golang version >= 1.15
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://goframe.org/pages/viewpage.action?pageId=1114415).
# Contributors
This project exists thanks to all the people who contribute. [[Contributors](https://github.com/gogf/gf/graphs/contributors)].
<a href="https://github.com/gogf/gf/graphs/contributors"><img src="https://contributors-img.web.app/image?repo=gogf/gf" /></a>
# Donators
If you love `GoFrame`, why not [buy developer a cup of coffee](https://goframe.org/pages/viewpage.action?pageId=1115633)?
# Sponsors
We appreciate any kind of sponsorship for `GoFrame` development. If you've got some interesting, please contact WeChat `389961817` / Email `john@goframe.org`.
# Thanks
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/download/thumbnails/1114119/jetbrains.png" height="120" alt="JetBrains"/></a>
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://goframe.org/download/attachments/1114119/atlassian.jpg" height="120" alt="Atlassian"/></a>

View File

@ -2,54 +2,67 @@
`gf` is a powerful CLI tool for building [GoFrame](https://goframe.org) application with convenience.
## 1. Install
## 1) PreCompiled Binary
You can also install `gf` tool using pre-built binaries: https://github.com/gogf/gf/releases
You can also install `gf` tool using pre-built binaries: <https://github.com/gogf/gf/releases>
1. `Mac` & `Linux`
```shell
```shell
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf
```
```
> If you're using `zsh`, you might need rename your alias by command `alias gf=gf` to resolve the conflicts between `gf` and `git fetch`.
2. `Windows`
Manually download, execute in command line it and then follow the instruction.
Manually download, execute it and then follow the instruction.
3. Database support
3. Database `sqlite` and `oracle` are not support in `gf gen` command in default as it needs `cgo` and `gcc`, you can manually make some changes to the source codes and do the building.
| DB | support | remarks |
| :------: | :------: | :------: |
| mysql | yes | - |
| mariadb | yes | - |
| tidb | yes | - |
| mssql | yes | - |
| oracle | yes | - |
| pgsql | yes | - |
| sqlite | yes | - |
| clickhouse | no | manually make some changes to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
| dm | no | manually make some changes to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
## 2) Manually Install
```shell
```shell
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
```
```
## 2. Commands
```html
$ gf
USAGE
gf COMMAND [OPTION]
COMMAND
env show current Golang environment variables
run running go codes with hot-compiled-like feature
gen automatically generate go files for dao/do/entity/pb/pbentity
tpl template parsing and building commands
init create and initialize an empty GoFrame project
pack packing any file/directory to a resource file, or a go file
build cross-building go project for lots of platforms
docker build docker image for current GoFrame project
install install gf binary to system (might need root/admin permission)
version show version information of current binary
env show current Golang environment variables
run running go codes with hot-compiled-like feature
gen automatically generate go files for dao/do/entity/pb/pbentity
tpl template parsing and building commands
init create and initialize an empty GoFrame project
pack packing any file/directory to a resource file, or a go file
build cross-building go project for lots of platforms
docker build docker image for current GoFrame project
install install gf binary to system (might need root/admin permission)
version show version information of current binary
OPTION
-y, --yes all yes for all command without prompt ask
-v, --version show version information of current binary
-d, --debug show internal detailed debugging information
-h, --help more information about this command
-y, --yes all yes for all command without prompt ask
-v, --version show version information of current binary
-d, --debug show internal detailed debugging information
-h, --help more information about this command
ADDITIONAL
Use "gf COMMAND -h" for details about a command.
@ -60,10 +73,3 @@ ADDITIONAL
### 1). Command `gf run` returns `pipe: too many open files`
Please use `ulimit -n 65535` to enlarge your system configuration for max open files for current terminal shell session, and then `gf run`.

View File

@ -1,20 +1,64 @@
module github.com/gogf/gf/cmd/gf/v2
go 1.16
go 1.18
require (
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/contrib/drivers/sqlite/v2 v2.1.0
github.com/gogf/gf/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.4.0
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.4.0
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.4.0
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.4.0
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.4.0
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.4.0
github.com/gogf/gf/v2 v2.4.0
github.com/olekukonko/tablewriter v0.0.5
golang.org/x/tools v0.1.11
golang.org/x/tools v0.7.0
)
require (
github.com/BurntSushi/toml v1.1.0 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.0.15 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/denisenkom/go-mssqldb v0.11.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/glebarez/go-sqlite v1.17.3 // indirect
github.com/go-logr/logr v1.2.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
github.com/lib/pq v1.10.4 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/paulmach/orb v0.7.1 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sijms/go-ora/v2 v2.4.20 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.8.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.8.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.16.8 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
modernc.org/sqlite v1.17.3 // indirect
)
replace (
github.com/gogf/gf/contrib/drivers/clickhouse/v2 => ../../contrib/drivers/clickhouse/
github.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql/
github.com/gogf/gf/contrib/drivers/mysql/v2 => ../../contrib/drivers/mysql/
github.com/gogf/gf/contrib/drivers/oracle/v2 => ../../contrib/drivers/oracle/
github.com/gogf/gf/contrib/drivers/pgsql/v2 => ../../contrib/drivers/pgsql/
github.com/gogf/gf/contrib/drivers/sqlite/v2 => ../../contrib/drivers/sqlite/
github.com/gogf/gf/v2 => ../../

View File

@ -1,24 +1,20 @@
github.com/BurntSushi/toml v1.1.0 h1:ksErzDEI1khOiGPgpwuI7x2ebx/uXQNw7xJpn9Eq1+I=
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/ClickHouse/clickhouse-go/v2 v2.0.15 h1:lLAZliqrZEygkxosLaW1qHyeTb4Ho7fVCZ0WKCpLocU=
github.com/ClickHouse/clickhouse-go/v2 v2.0.15/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/glebarez/go-sqlite v1.17.3 h1:Rji9ROVSTTfjuWD6j5B+8DtkNvPILoUC3xRhkQzGxvk=
@ -28,39 +24,32 @@ github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
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=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
@ -72,34 +61,40 @@ github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
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.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/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/sijms/go-ora/v2 v2.4.20 h1:9e3z7VLBQXRAHGiIda1GEFtRhfxata0LghyMZqvLKew=
github.com/sijms/go-ora/v2 v2.4.20/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
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=
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=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
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=
@ -110,90 +105,73 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
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/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/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
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/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
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-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
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=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
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-20211007075335-d3039528d8ac/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-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/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=
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/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=
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/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/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/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
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=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
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=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=

View File

@ -1,9 +1,16 @@
// Copyright GoFrame gf 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 cmd
import (
"context"
"strings"
"github.com/gogf/gf/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/util/gtag"
@ -48,17 +55,21 @@ func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error)
_, err = Version.Index(ctx, cVersionInput{})
return
}
answer := "n"
// No argument or option, do installation checks.
if !service.Install.IsInstalled() {
if data, isInstalled := service.Install.IsInstalled(); !isInstalled {
mlog.Print("hi, it seams it's the first time you installing gf cli.")
s := gcmd.Scanf("do you want to install gf binary to your system? [y/n]: ")
if strings.EqualFold(s, "y") {
if err = service.Install.Run(ctx); err != nil {
return
}
gcmd.Scan("press `Enter` to exit...")
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
} else if !data.IsSelf {
mlog.Print("hi, you have installed gf cli.")
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
}
if strings.EqualFold(answer, "y") {
if err = service.Install.Run(ctx); err != nil {
return
}
gcmd.Scan("press `Enter` to exit...")
return
}
// Print help content.
gcmd.CommandFromCtx(ctx).Print()

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (
@ -124,11 +130,17 @@ type cBuildInput struct {
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
DumpENV bool `short:"de" name:"dumpEnv" brief:"dump current go build environment before building binary" orphan:"true"`
}
type cBuildOutput struct{}
func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {
// print used go env
if in.DumpENV {
_, _ = Env.Index(ctx, cEnvInput{})
}
mlog.SetHeaderPrint(true)
mlog.Debugf(`build input: %+v`, in)
@ -236,7 +248,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
continue
}
for arch, _ := range item {
for arch := range item {
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
continue
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (
@ -33,6 +39,7 @@ gf docker main.go
gf docker main.go -t hub.docker.com/john/image:tag
gf docker main.go -t hub.docker.com/john/image:tag
gf docker main.go -p -t hub.docker.com/john/image:tag
gf docker main.go -p -tp ["hub.docker.com/john","hub.docker.com/smith"] -tn image:tag
`
cDockerDc = `
The "docker" command builds the GF project to a docker images.
@ -45,6 +52,7 @@ You should have docker installed, and there must be a Dockerfile in the root of
cDockerFileBrief = `file path of the Dockerfile. it's "manifest/docker/Dockerfile" in default`
cDockerShellBrief = `path of the shell file which is executed before docker build`
cDockerPushBrief = `auto push the docker image to docker registry if "-t" option passed`
cDockerTagBrief = `full tag for this docker, pattern like "xxx.xxx.xxx/image:tag"`
cDockerTagNameBrief = `tag name for this docker, pattern like "image:tag". this option is required with TagPrefixes`
cDockerTagPrefixesBrief = `tag prefixes for this docker, which are used for docker push. this option is required with TagName`
cDockerExtraBrief = `extra build options passed to "docker image"`
@ -61,6 +69,7 @@ func init() {
`cDockerShellBrief`: cDockerShellBrief,
`cDockerBuildBrief`: cDockerBuildBrief,
`cDockerPushBrief`: cDockerPushBrief,
`cDockerTagBrief`: cDockerTagBrief,
`cDockerTagNameBrief`: cDockerTagNameBrief,
`cDockerTagPrefixesBrief`: cDockerTagPrefixesBrief,
`cDockerExtraBrief`: cDockerExtraBrief,
@ -73,6 +82,7 @@ type cDockerInput struct {
File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}" d:"-a amd64 -s linux"`
Tag string `name:"tag" short:"t" brief:"{cDockerTagBrief}"`
TagName string `name:"tagName" short:"tn" brief:"{cDockerTagNameBrief}" v:"required-with:TagPrefixes"`
TagPrefixes []string `name:"tagPrefixes" short:"tp" brief:"{cDockerTagPrefixesBrief}" v:"required-with:TagName"`
Push bool `name:"push" short:"p" brief:"{cDockerPushBrief}" orphan:"true"`
@ -114,7 +124,7 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
}
}
if len(dockerTags) == 0 {
dockerTags = []string{""}
dockerTags = []string{in.Tag}
}
for i, dockerTag := range dockerTags {
if i > 0 {

View File

@ -1,14 +1,21 @@
// Copyright GoFrame gf 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 cmd
import (
"bytes"
"context"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)

View File

@ -0,0 +1,128 @@
// Copyright GoFrame gf 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 cmd
import (
"context"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
)
var (
Fix = cFix{}
)
type cFix struct {
g.Meta `name:"fix" brief:"auto fixing codes after upgrading to new GoFrame version" usage:"gf fix" `
}
type cFixInput struct {
g.Meta `name:"fix"`
Path string `name:"path" short:"p" brief:"directory path, it uses current working directory in default"`
Version string `name:"version" short:"v" brief:"custom specified version to fix, leave it empty to auto detect"`
}
type cFixOutput struct{}
type cFixItem struct {
Version string
Func func(version string) error
}
func (c cFix) Index(ctx context.Context, in cFixInput) (out *cFixOutput, err error) {
if in.Path == "" {
in.Path = gfile.Pwd()
}
if in.Version == "" {
in.Version, err = c.autoDetectVersion(in)
if err != nil {
mlog.Fatal(err)
}
if in.Version == "" {
mlog.Print(`no GoFrame usage found, exit fixing`)
return
}
mlog.Debugf(`current GoFrame version auto detect "%s"`, in.Version)
}
if !gproc.IsChild() {
mlog.Printf(`start auto fixing directory path "%s"...`, in.Path)
defer mlog.Print(`done!`)
}
err = c.doFix(in)
return
}
func (c cFix) doFix(in cFixInput) (err error) {
var items = []cFixItem{
{Version: "v2.3", Func: c.doFixV23},
}
for _, item := range items {
if gstr.CompareVersionGo(in.Version, item.Version) < 0 {
mlog.Debugf(
`current GoFrame or contrib package version "%s" is lesser than "%s", nothing to do`,
in.Version, item.Version,
)
continue
}
if err = item.Func(in.Version); err != nil {
return
}
}
return
}
// doFixV23 fixes code when upgrading to GoFrame v2.3.
func (c cFix) doFixV23(version string) error {
replaceFunc := func(path, content string) string {
// gdb.TX from struct to interface.
content = gstr.Replace(content, "*gdb.TX", "gdb.TX")
// function name changes for package gtcp/gudp.
if gstr.Contains(content, "/gf/v2/net/gtcp") || gstr.Contains(content, "/gf/v2/net/gudp") {
content = gstr.ReplaceByMap(content, g.MapStrStr{
".SetSendDeadline": ".SetDeadlineSend",
".SetReceiveDeadline": ".SetDeadlineRecv",
".SetReceiveBufferWait": ".SetBufferWaitRecv",
})
}
return content
}
return gfile.ReplaceDirFunc(replaceFunc, ".", "*.go", true)
}
func (c cFix) autoDetectVersion(in cFixInput) (string, error) {
var (
err error
path = gfile.Join(in.Path, "go.mod")
version string
)
if !gfile.Exists(path) {
return "", gerror.Newf(`"%s" not found in current working directory`, path)
}
err = gfile.ReadLines(path, func(line string) error {
array := gstr.SplitAndTrim(line, " ")
if len(array) > 0 {
if gstr.HasPrefix(array[0], gfPackage) {
version = array[1]
}
}
return nil
})
if err != nil {
mlog.Fatal(err)
}
return version, nil
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (
@ -12,6 +18,7 @@ var (
type cGen struct {
g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"`
cGenDao
cGenEnums
cGenPb
cGenPbEntity
cGenService

View File

@ -1,8 +1,16 @@
// Copyright GoFrame gf 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 cmd
import (
_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
_ "github.com/gogf/gf/contrib/drivers/mssql/v2"
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"

View File

@ -0,0 +1,15 @@
// Copyright GoFrame gf 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 cmd
import (
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genenums"
)
type (
cGenEnums = genenums.CGenEnums
)

View File

@ -1,79 +1,13 @@
// Copyright GoFrame gf 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 cmd
import (
"context"
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
)
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb"
type (
cGenPb struct{}
cGenPbInput struct {
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
}
cGenPbOutput struct{}
cGenPb = genpb.CGenPb
)
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`)
}
// protocol fold checks.
protoFolder := "protocol"
if !gfile.Exists(protoFolder) {
mlog.Fatalf(`proto files folder "%s" does not exist`, protoFolder)
}
// folder scanning.
files, err := gfile.ScanDirFile(protoFolder, "*.proto", true)
if err != nil {
mlog.Fatal(err)
}
if len(files) == 0 {
mlog.Fatalf(`no proto files found in folder "%s"`, protoFolder)
}
dirSet := gset.NewStrSet()
for _, file := range files {
dirSet.Add(gfile.Dir(file))
}
var (
servicePath = gfile.RealPath(".")
goPathSrc = gfile.RealPath(gfile.Join(genv.Get("GOPATH").String(), "src"))
)
dirSet.Iterator(func(protoDirPath string) bool {
parsingCommand := fmt.Sprintf(
"protoc --gofast_out=plugins=grpc:. %s/*.proto -I%s",
protoDirPath,
servicePath,
)
if goPathSrc != "" {
parsingCommand += " -I" + goPathSrc
}
mlog.Print(parsingCommand)
if output, err := gproc.ShellExec(ctx, parsingCommand); err != nil {
mlog.Print(output)
mlog.Fatal(err)
}
return true
})
// Custom replacement.
//pbFolder := "protobuf"
//_, _ = gfile.ScanDirFileFunc(pbFolder, "*.go", true, func(path string) string {
// content := gfile.GetContents(path)
// content = gstr.ReplaceByArray(content, g.SliceStr{
// `gtime "gtime"`, `gtime "github.com/gogf/gf/v2/os/gtime"`,
// })
// _ = gfile.PutContents(path, content)
// utils.GoFmt(path)
// return path
//})
mlog.Print("done!")
return
}

View File

@ -1,411 +1,13 @@
// Copyright GoFrame gf 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 cmd
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"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/gtag"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity"
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.
}
cGenPbEntity = genpbentity.CGenPbEntity
)
const (
cGenPbEntityConfig = `gfcli.gen.pbentity`
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
cGenPbEntityEg = `
gf gen pbentity
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
gf gen pbentity -r user_
`
cGenPbEntityAd = `
CONFIGURATION SUPPORT
Options are also supported by configuration file.
It's suggested using configuration file instead of command line arguments making producing.
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
gfcli:
gen:
- pbentity:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
path: "protocol/demos/entity"
tables: "order,products"
package: "demos"
- pbentity:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
path: "protocol/demos/entity"
prefix: "primary_"
tables: "user, userDetail"
package: "demos"
option: |
option go_package = "protobuf/demos";
option java_package = "protobuf/demos";
option php_namespace = "protobuf/demos";
`
cGenPbEntityBriefPath = `directory path for generated files`
cGenPbEntityBriefPackage = `package name for all entity proto files`
cGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
cGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
cGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
cGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
cGenPbEntityBriefOption = `extra protobuf options`
cGenPbEntityBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
`
cGenPbEntityBriefNameCase = `
case for message attribute names, default is "Camel":
| Case | Example |
|---------------- |--------------------|
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString | default
| Snake | any_kind_of_string |
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
cGenPbEntityBriefJsonCase = `
case for message json tag, cases are the same as "nameCase", default "CamelLower".
set it to "none" to ignore json tag generating.
`
)
func init() {
gtag.Sets(g.MapStrStr{
`cGenPbEntityConfig`: cGenPbEntityConfig,
`cGenPbEntityBrief`: cGenPbEntityBrief,
`cGenPbEntityEg`: cGenPbEntityEg,
`cGenPbEntityAd`: cGenPbEntityAd,
`cGenPbEntityBriefPath`: cGenPbEntityBriefPath,
`cGenPbEntityBriefPackage`: cGenPbEntityBriefPackage,
`cGenPbEntityBriefLink`: cGenPbEntityBriefLink,
`cGenPbEntityBriefTables`: cGenPbEntityBriefTables,
`cGenPbEntityBriefPrefix`: cGenPbEntityBriefPrefix,
`cGenPbEntityBriefRemovePrefix`: cGenPbEntityBriefRemovePrefix,
`cGenPbEntityBriefGroup`: cGenPbEntityBriefGroup,
`cGenPbEntityBriefNameCase`: cGenPbEntityBriefNameCase,
`cGenPbEntityBriefJsonCase`: cGenPbEntityBriefJsonCase,
`cGenPbEntityBriefOption`: cGenPbEntityBriefOption,
})
}
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
var (
config = g.Cfg()
)
if config.Available(ctx) {
v := config.MustGet(ctx, cGenPbEntityConfig)
if v.IsSlice() {
for i := 0; i < len(v.Interfaces()); i++ {
doGenPbEntityForArray(ctx, i, in)
}
} else {
doGenPbEntityForArray(ctx, -1, in)
}
} else {
doGenPbEntityForArray(ctx, -1, in)
}
mlog.Print("done!")
return
}
func doGenPbEntityForArray(ctx context.Context, index int, in cGenPbEntityInput) {
var (
err error
db gdb.DB
)
if index >= 0 {
err = g.Cfg().MustGet(
ctx,
fmt.Sprintf(`%s.%d`, cGenPbEntityConfig, index),
).Scan(&in)
if err != nil {
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenPbEntityConfig, err)
}
}
if in.Package == "" {
mlog.Fatal("package name should not be empty")
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
// It uses user passed database configuration.
if in.Link != "" {
var (
tempGroup = gtime.TimestampNanoStr()
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
)
if len(match) == 3 {
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
Type: gstr.Trim(match[1]),
Link: gstr.Trim(match[2]),
})
db, _ = gdb.Instance(tempGroup)
}
} else {
db = g.DB()
}
if db == nil {
mlog.Fatal("database initialization failed")
}
tableNames := ([]string)(nil)
if in.Tables != "" {
tableNames = gstr.SplitAndTrim(in.Tables, ",")
} else {
tableNames, err = db.Tables(context.TODO())
if err != nil {
mlog.Fatalf("fetching tables failed: \n %v", err)
}
}
for _, tableName := range tableNames {
newTableName := tableName
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
generatePbEntityContentFile(ctx, db, cGenPbEntityInternalInput{
cGenPbEntityInput: in,
TableName: tableName,
NewTableName: newTableName,
})
}
}
// generatePbEntityContentFile generates the protobuf files for given table.
func generatePbEntityContentFile(ctx context.Context, db gdb.DB, in cGenPbEntityInternalInput) {
fieldMap, err := db.TableFields(ctx, in.TableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
}
// Change the `newTableName` if `Prefix` is given.
newTableName := "Entity_" + in.Prefix + in.NewTableName
var (
tableNameCamelCase = gstr.CaseCamel(newTableName)
tableNameSnakeCase = gstr.CaseSnake(newTableName)
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
path = gfile.Join(in.Path, fileName+".proto")
)
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
"{PackageName}": in.Package,
"{OptionContent}": in.Option,
"{EntityMessage}": entityMessageDefine,
})
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
mlog.Print("generated:", path)
}
}
// generateEntityMessageDefinition generates and returns the message definition for specified table.
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in cGenPbEntityInternalInput) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForPbEntity(fieldMap)
)
for index, name := range names {
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
buffer.Reset()
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
buffer.WriteString(stContent)
buffer.WriteString("}")
return buffer.String()
}
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in cGenPbEntityInternalInput) []string {
var (
typeName string
comment string
jsonTagStr string
)
t, _ := gregex.ReplaceString(`\(.+\)`, "", field.Type)
t = gstr.Split(gstr.Trim(t), " ")[0]
t = gstr.ToLower(t)
switch t {
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
typeName = "bytes"
case "bit", "int", "tinyint", "small_int", "smallint", "medium_int", "mediumint", "serial":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "uint32"
} else {
typeName = "int32"
}
case "int8", "big_int", "bigint", "bigserial":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "uint64"
} else {
typeName = "int64"
}
case "real":
typeName = "float"
case "float", "double", "decimal", "smallmoney":
typeName = "double"
case "bool":
typeName = "bool"
case "datetime", "timestamp", "date", "time":
typeName = "int64"
default:
// Auto detecting type.
switch {
case strings.Contains(t, "int"):
typeName = "int"
case strings.Contains(t, "text") || strings.Contains(t, "char"):
typeName = "string"
case strings.Contains(t, "float") || strings.Contains(t, "double"):
typeName = "double"
case strings.Contains(t, "bool"):
typeName = "bool"
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
typeName = "bytes"
case strings.Contains(t, "date") || strings.Contains(t, "time"):
typeName = "int64"
default:
typeName = "string"
}
}
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
"\n", " ",
"\r", " ",
})
comment = gstr.Trim(comment)
comment = gstr.Replace(comment, `\n`, " ")
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
jsonTagStr = fmt.Sprintf(`[(gogoproto.jsontag) = "%s"]`, jsonTagName)
// beautiful indent.
if index < 10 {
// 3 spaces
jsonTagStr = " " + jsonTagStr
} else if index < 100 {
// 2 spaces
jsonTagStr = " " + jsonTagStr
} else {
// 1 spaces
jsonTagStr = " " + jsonTagStr
}
}
return []string{
" #" + typeName,
" #" + formatCase(field.Name, in.NameCase),
" #= " + gconv.String(index) + jsonTagStr + ";",
" #" + fmt.Sprintf(`// %s`, comment),
}
}
func getTplPbEntityContent(tplEntityPath string) string {
if tplEntityPath != "" {
return gfile.GetContents(tplEntityPath)
}
return consts.TemplatePbEntityMessageContent
}
// formatCase call gstr.Case* function to convert the s to specified case.
func formatCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("Snake"):
return gstr.CaseSnake(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
case "none":
return ""
}
return str
}
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
names := make(map[int]string)
for _, field := range fieldMap {
names[field.Index] = field.Name
}
var (
result = make([]string, len(names))
i = 0
j = 0
)
for {
if len(names) == 0 {
break
}
if val, ok := names[i]; ok {
result[j] = val
j++
delete(names, i)
}
i++
}
return result
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (

View File

@ -1,9 +1,16 @@
// Copyright GoFrame gf 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 cmd
import (
"context"
"fmt"
"runtime"
"strings"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/frame/g"
@ -154,7 +161,7 @@ func (app *cRunApp) Run(ctx context.Context) {
if runtime.GOOS == "windows" {
// Special handling for windows platform.
// DO NOT USE "cmd /c" command.
process = gproc.NewProcess(runCommand, nil)
process = gproc.NewProcess(outputPath, strings.Fields(app.Args))
} else {
process = gproc.NewProcessCmd(runCommand, nil)
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (
@ -33,7 +39,7 @@ like json/xml/yaml/toml/ini.
cTplParseEg = `
gf tpl parse -p ./template -v values.json -r
gf tpl parse -p ./template -v values.json -n *.tpl -r
gf tpl parse -p ./template -v values.json -d '${,}}' -r
gf tpl parse -p ./template -v values.json -d '${{,}}' -r
gf tpl parse -p ./template -v values.json -o ./template.parsed
`
cTplSupportValuesFilePattern = `*.json,*.xml,*.yaml,*.yml,*.toml,*.ini`
@ -63,7 +69,7 @@ func init() {
}
func (c *cTpl) Parse(ctx context.Context, in cTplParseInput) (out *cTplParseOutput, err error) {
if in.Output == "" && in.Replace == false {
if in.Output == "" && !in.Replace {
return nil, gerror.New(`parameter output and replace should not be both empty`)
}
delimiters := gstr.SplitAndTrim(in.Delimiters, ",")

View File

@ -0,0 +1,214 @@
// Copyright GoFrame gf 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 cmd
import (
"context"
"fmt"
"runtime"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
)
var (
Up = cUp{}
)
type cUp struct {
g.Meta `name:"up" brief:"upgrade GoFrame version/tool to latest one in current project" eg:"{cUpEg}" `
}
const (
gfPackage = `github.com/gogf/gf/`
cUpEg = `
gf up
gf up -a
gf up -c
gf up -cf
`
)
func init() {
gtag.Sets(g.MapStrStr{
`cUpEg`: cUpEg,
})
}
type cUpInput struct {
g.Meta `name:"up" config:"gfcli.up"`
All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
}
type cUpOutput struct{}
func (c cUp) Index(ctx context.Context, in cUpInput) (out *cUpOutput, err error) {
defer func() {
if err == nil {
mlog.Print()
mlog.Print(`👏congratulations! you've upgraded to the latest version of GoFrame! enjoy it!👏`)
mlog.Print()
}
}()
var doUpgradeVersionOut *doUpgradeVersionOutput
if in.All {
in.Cli = true
in.Fix = true
}
if doUpgradeVersionOut, err = c.doUpgradeVersion(ctx, in); err != nil {
return nil, err
}
if in.Cli {
if err = c.doUpgradeCLI(ctx); err != nil {
return nil, err
}
}
if in.Cli && in.Fix {
if doUpgradeVersionOut != nil && len(doUpgradeVersionOut.Items) > 0 {
upgradedPathSet := gset.NewStrSet()
for _, item := range doUpgradeVersionOut.Items {
if !upgradedPathSet.AddIfNotExist(item.DirPath) {
continue
}
if err = c.doAutoFixing(ctx, item.DirPath, item.Version); err != nil {
return nil, err
}
}
}
}
return
}
type doUpgradeVersionOutput struct {
Items []doUpgradeVersionOutputItem
}
type doUpgradeVersionOutputItem struct {
DirPath string
Version string
}
func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeVersionOutput, err error) {
mlog.Print(`start upgrading version...`)
out = &doUpgradeVersionOutput{
Items: make([]doUpgradeVersionOutputItem, 0),
}
type Package struct {
Name string
Version string
}
var (
temp string
dirPath = gfile.Pwd()
goModPath = gfile.Join(dirPath, "go.mod")
)
// It recursively upgrades the go.mod from sub folder to its parent folders.
for {
if gfile.Exists(goModPath) {
var packages []Package
err = gfile.ReadLines(goModPath, func(line string) error {
line = gstr.Trim(line)
if gstr.HasPrefix(line, gfPackage) {
array := gstr.SplitAndTrim(line, " ")
packages = append(packages, Package{
Name: array[0],
Version: array[1],
})
}
return nil
})
if err != nil {
return
}
for _, pkg := range packages {
mlog.Printf(`upgrading "%s" from "%s" to "latest"`, pkg.Name, pkg.Version)
// go get -u
command := fmt.Sprintf(`cd %s && go get -u %s@latest`, dirPath, pkg.Name)
if err = gproc.ShellRun(ctx, command); err != nil {
return
}
// go mod tidy
if err = utils.GoModTidy(ctx, dirPath); err != nil {
return nil, err
}
out.Items = append(out.Items, doUpgradeVersionOutputItem{
DirPath: dirPath,
Version: pkg.Version,
})
}
return
}
temp = gfile.Dir(dirPath)
if temp == "" || temp == dirPath {
return
}
dirPath = temp
goModPath = gfile.Join(dirPath, "go.mod")
}
}
// doUpgradeCLI downloads the new version binary with process.
func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
mlog.Print(`start upgrading cli...`)
var (
downloadUrl = fmt.Sprintf(
`https://github.com/gogf/gf/releases/latest/download/gf_%s_%s`,
runtime.GOOS, runtime.GOARCH,
)
localSaveFilePath = gfile.SelfPath() + "~"
)
mlog.Printf(`start downloading "%s" to "%s", it may take some time`, downloadUrl, localSaveFilePath)
err = utils.HTTPDownloadFileWithPercent(downloadUrl, localSaveFilePath)
if err != nil {
return err
}
defer func() {
mlog.Printf(`new version cli binary is successfully installed to "%s"`, gfile.SelfPath())
mlog.Printf(`remove temporary buffer file "%s"`, localSaveFilePath)
_ = gfile.Remove(localSaveFilePath)
}()
// It fails if file not exist or its size is less than 1MB.
if !gfile.Exists(localSaveFilePath) || gfile.Size(localSaveFilePath) < 1024*1024 {
mlog.Fatalf(`download "%s" to "%s" failed`, downloadUrl, localSaveFilePath)
}
// It replaces self binary with new version cli binary.
switch runtime.GOOS {
case "windows":
if err := gfile.Rename(localSaveFilePath, gfile.SelfPath()); err != nil {
mlog.Fatalf(`install failed: %s`, err.Error())
}
default:
if err := gfile.PutBytes(gfile.SelfPath(), gfile.GetBytes(localSaveFilePath)); err != nil {
mlog.Fatalf(`install failed: %s`, err.Error())
}
}
return
}
func (c cUp) doAutoFixing(ctx context.Context, dirPath string, version string) (err error) {
mlog.Printf(`auto fixing directory path "%s" from version "%s" ...`, dirPath, version)
command := fmt.Sprintf(`gf fix -p %s`, dirPath)
_ = gproc.ShellRun(ctx, command)
return
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 cmd
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 gendao
import (
@ -216,6 +222,7 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
if in.ImportPrefix == "" {
mlog.Debug(`import prefix is empty, trying calculating the import package path using go.mod`)
if !gfile.Exists("go.mod") {
mlog.Fatal("go.mod does not exist in current working directory")
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 gendao
import (
@ -9,13 +15,13 @@ import (
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
func doClear(ctx context.Context, dirPath string) {
func doClear(ctx context.Context, dirPath string, force bool) {
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
if err != nil {
mlog.Fatal(err)
}
for _, file := range files {
if utils.IsFileDoNotEdit(file) {
if force || utils.IsFileDoNotEdit(file) {
if err = gfile.Remove(file); err != nil {
mlog.Print(err)
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 gendao
import (
@ -6,12 +12,13 @@ import (
"fmt"
"strings"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
@ -24,7 +31,7 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
)
if in.Clear {
doClear(ctx, dirPathDao)
doClear(ctx, dirPathDao, true)
}
for i := 0; i < len(in.TableNames); i++ {
generateDaoSingle(ctx, generateDaoSingleInput{

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 gendao
import (
@ -18,7 +24,7 @@ import (
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
var dirPathDo = gfile.Join(in.Path, in.DoPath)
if in.Clear {
doClear(ctx, dirPathDo)
doClear(ctx, dirPathDo, false)
}
in.NoJsonTag = true
in.DescriptionTag = false

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 gendao
import (
@ -16,7 +22,7 @@ import (
func generateEntity(ctx context.Context, in CGenDaoInternalInput) {
var dirPathEntity = gfile.Join(in.Path, in.EntityPath)
if in.Clear {
doClear(ctx, dirPathEntity)
doClear(ctx, dirPathEntity, false)
}
// Model content.
for i, tableName := range in.TableNames {

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 gendao
import (
@ -5,11 +11,12 @@ import (
"context"
"fmt"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
)
type generateStructDefinitionInput struct {

View File

@ -0,0 +1,83 @@
// Copyright GoFrame gf 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 genenums
import (
"context"
"golang.org/x/tools/go/packages"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
)
type (
CGenEnums struct{}
CGenEnumsInput struct {
g.Meta `name:"enums" config:"{CGenEnumsConfig}" brief:"{CGenEnumsBrief}" eg:"{CGenEnumsEg}"`
Src string `name:"src" short:"s" dc:"source folder path to be parsed" d:"."`
Path string `name:"path" short:"p" dc:"output go file path storing enums content" d:"internal/boot/boot_enums.go"`
Prefix string `name:"prefix" short:"x" dc:"only exports packages that starts with specified prefix"`
}
CGenEnumsOutput struct{}
)
const (
CGenEnumsConfig = `gfcli.gen.enums`
CGenEnumsBrief = `parse go files in current project and generate enums go file`
CGenEnumsEg = `
gf gen enums
gf gen enums -p internal/boot/boot_enums.go
gf gen enums -p internal/boot/boot_enums.go -s .
gf gen enums -x github.com/gogf
`
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenEnumsEg`: CGenEnumsEg,
`CGenEnumsBrief`: CGenEnumsBrief,
`CGenEnumsConfig`: CGenEnumsConfig,
})
}
func (c CGenEnums) Enums(ctx context.Context, in CGenEnumsInput) (out *CGenEnumsOutput, err error) {
realPath := gfile.RealPath(in.Src)
if realPath == "" {
mlog.Fatalf(`source folder path "%s" does not exist`, in.Src)
}
err = gfile.Chdir(realPath)
if err != nil {
mlog.Fatal(err)
}
mlog.Printf(`scanning: %s`, realPath)
cfg := &packages.Config{
Dir: realPath,
Mode: pkgLoadMode,
Tests: false,
}
pkgs, err := packages.Load(cfg)
if err != nil {
mlog.Fatal(err)
}
p := NewEnumsParser(in.Prefix)
p.ParsePackages(pkgs)
var enumsContent = gstr.ReplaceByMap(consts.TemplateGenEnums, g.MapStrStr{
"{PackageName}": gfile.Basename(gfile.Dir(in.Path)),
"{EnumsJson}": "`" + p.Export() + "`",
})
enumsContent = gstr.Trim(enumsContent)
if err = gfile.PutContents(in.Path, enumsContent); err != nil {
return
}
mlog.Printf(`generated: %s`, in.Path)
mlog.Print("done!")
return
}

View File

@ -0,0 +1,140 @@
// Copyright GoFrame gf 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 genenums
import (
"go/constant"
"go/types"
"golang.org/x/tools/go/packages"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
const pkgLoadMode = 0xffffff
type EnumsParser struct {
enums []EnumItem
parsedPkg map[string]struct{}
prefix string
}
type EnumItem struct {
Name string
Value string
Kind constant.Kind // String/Int/Bool/Float/Complex/Unknown
Type string // Pkg.ID + TypeName
}
var standardPackages = make(map[string]struct{})
func init() {
stdPackages, err := packages.Load(nil, "std")
if err != nil {
panic(err)
}
for _, p := range stdPackages {
standardPackages[p.ID] = struct{}{}
}
}
func NewEnumsParser(prefix string) *EnumsParser {
return &EnumsParser{
enums: make([]EnumItem, 0),
parsedPkg: make(map[string]struct{}),
prefix: prefix,
}
}
func (p *EnumsParser) ParsePackages(pkgs []*packages.Package) {
for _, pkg := range pkgs {
p.ParsePackage(pkg)
}
}
func (p *EnumsParser) ParsePackage(pkg *packages.Package) {
// Ignore std packages.
if _, ok := standardPackages[pkg.ID]; ok {
return
}
// Ignore pared packages.
if _, ok := p.parsedPkg[pkg.ID]; ok {
return
}
p.parsedPkg[pkg.ID] = struct{}{}
// Only parse specified prefix.
if p.prefix != "" {
if !gstr.HasPrefix(pkg.ID, p.prefix) {
return
}
}
var (
scope = pkg.Types.Scope()
names = scope.Names()
)
for _, name := range names {
con, ok := scope.Lookup(name).(*types.Const)
if !ok {
// Only constants can be enums.
continue
}
if !con.Exported() {
// Ignore unexported values.
continue
}
var enumType = con.Type().String()
if !gstr.Contains(enumType, "/") {
// Ignore std types.
continue
}
var (
enumName = con.Name()
enumValue = con.Val().ExactString()
enumKind = con.Val().Kind()
)
if con.Val().Kind() == constant.String {
enumValue = constant.StringVal(con.Val())
}
p.enums = append(p.enums, EnumItem{
Name: enumName,
Value: enumValue,
Type: enumType,
Kind: enumKind,
})
}
for _, im := range pkg.Imports {
p.ParsePackage(im)
}
}
func (p *EnumsParser) Export() string {
var typeEnumMap = make(map[string][]interface{})
for _, enum := range p.enums {
if typeEnumMap[enum.Type] == nil {
typeEnumMap[enum.Type] = make([]interface{}, 0)
}
var value interface{}
switch enum.Kind {
case constant.Int:
value = gconv.Int64(enum.Value)
case constant.String:
value = enum.Value
case constant.Float:
value = gconv.Float64(enum.Value)
case constant.Bool:
value = gconv.Bool(enum.Value)
default:
value = enum.Value
}
typeEnumMap[enum.Type] = append(typeEnumMap[enum.Type], value)
}
return gjson.MustEncodeString(typeEnumMap)
}

View File

@ -0,0 +1,128 @@
// Copyright GoFrame gf 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 genpb
import (
"context"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/util/gtag"
)
type (
CGenPb struct{}
CGenPbInput struct {
g.Meta `name:"pb" config:"{CGenPbConfig}" brief:"{CGenPbBrief}" eg:"{CGenPbEg}"`
Path string `name:"path" short:"p" dc:"protobuf file folder path" d:"manifest/protobuf"`
OutputApi string `name:"api" short:"a" dc:"output folder path storing generated go files of api" d:"api"`
OutputCtrl string `name:"ctrl" short:"c" dc:"output folder path storing generated go files of controller" d:"internal/controller"`
}
CGenPbOutput struct{}
)
const (
CGenPbConfig = `gfcli.gen.pb`
CGenPbBrief = `parse proto files and generate protobuf go files`
CGenPbEg = `
gf gen pb
gf gen pb -p . -a . -p .
`
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenPbEg`: CGenPbEg,
`CGenPbBrief`: CGenPbBrief,
`CGenPbConfig`: CGenPbConfig,
})
}
func (c CGenPb) Pb(ctx context.Context, in CGenPbInput) (out *CGenPbOutput, err error) {
// Necessary check.
protoc := gproc.SearchBinary("protoc")
if protoc == "" {
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first: https://grpc.io/docs/languages/go/quickstart/`)
}
// protocol fold checks.
var (
protoPath = gfile.RealPath(in.Path)
isParsingPWD bool
)
if protoPath == "" {
// Use current working directory as protoPath if there are proto files under.
currentPath := gfile.Pwd()
currentFiles, _ := gfile.ScanDirFile(currentPath, "*.proto")
if len(currentFiles) > 0 {
protoPath = currentPath
isParsingPWD = true
} else {
mlog.Fatalf(`proto files folder "%s" does not exist`, in.Path)
}
}
// output path checks.
outputApiPath := gfile.RealPath(in.OutputApi)
if outputApiPath == "" {
if isParsingPWD {
outputApiPath = protoPath
} else {
mlog.Fatalf(`output api folder "%s" does not exist`, in.OutputApi)
}
}
outputCtrlPath := gfile.RealPath(in.OutputCtrl)
if outputCtrlPath == "" {
if isParsingPWD {
outputCtrlPath = ""
} else {
mlog.Fatalf(`output controller folder "%s" does not exist`, in.OutputCtrl)
}
}
// folder scanning.
files, err := gfile.ScanDirFile(protoPath, "*.proto", true)
if err != nil {
mlog.Fatal(err)
}
if len(files) == 0 {
mlog.Fatalf(`no proto files found in folder "%s"`, in.Path)
}
if err = gfile.Chdir(protoPath); err != nil {
mlog.Fatal(err)
}
for _, file := range files {
var command = gproc.NewProcess(protoc, nil)
command.Args = append(command.Args, "--proto_path="+gfile.Pwd())
command.Args = append(command.Args, "--go_out=paths=source_relative:"+outputApiPath)
command.Args = append(command.Args, "--go-grpc_out=paths=source_relative:"+outputApiPath)
command.Args = append(command.Args, file)
mlog.Print(command.String())
if err = command.Run(ctx); err != nil {
mlog.Fatal(err)
}
}
// Generate struct tag according comment rules.
err = c.generateStructTag(ctx, generateStructTagInput{OutputApiPath: outputApiPath})
if err != nil {
return
}
// Generate controllers according comment rules.
if outputCtrlPath != "" {
err = c.generateController(ctx, generateControllerInput{
OutputApiPath: outputApiPath,
OutputCtrlPath: outputCtrlPath,
})
if err != nil {
return
}
}
mlog.Print("done!")
return
}

View File

@ -0,0 +1,195 @@
// Copyright GoFrame gf 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 genpb
import (
"context"
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
)
type generateControllerInput struct {
OutputApiPath string
OutputCtrlPath string
}
type generateCtrl struct {
Name string
Package string
Version string
Methods []generateCtrlMethod
}
type generateCtrlMethod struct {
Name string
Definition string
}
const (
controllerTemplate = `
package {Package}
type Controller struct {
{Version}.Unimplemented{Name}Server
}
func Register(s *grpcx.GrpcServer) {
{Version}.Register{Name}Server(s.Server, &Controller{})
}
`
controllerMethodTemplate = `
func (*Controller) {Definition} {
return nil, gerror.NewCode(gcode.CodeNotImplemented)
}
`
)
func (c CGenPb) generateController(ctx context.Context, in generateControllerInput) (err error) {
files, err := gfile.ScanDirFile(in.OutputApiPath, "*_grpc.pb.go", true)
if err != nil {
return err
}
var controllers []generateCtrl
for _, file := range files {
fileControllers, err := c.parseControllers(file)
if err != nil {
return err
}
controllers = append(controllers, fileControllers...)
}
if len(controllers) == 0 {
return nil
}
// Generate controller files.
err = c.doGenerateControllers(in, controllers)
return
}
func (c CGenPb) parseControllers(filePath string) ([]generateCtrl, error) {
var (
controllers []generateCtrl
content = gfile.GetContents(filePath)
)
_, err := gregex.ReplaceStringFuncMatch(
`type (\w+)Server interface {([\s\S]+?)}`,
content,
func(match []string) string {
ctrl := generateCtrl{
Name: match[1],
Package: gfile.Basename(gfile.Dir(gfile.Dir(filePath))),
Version: gfile.Basename(gfile.Dir(filePath)),
Methods: make([]generateCtrlMethod, 0),
}
lines := gstr.Split(match[2], "\n")
for _, line := range lines {
line = gstr.Trim(line)
if line == "" || !gstr.IsLetterUpper(line[0]) {
continue
}
// Comment.
if gregex.IsMatchString(`^//.+`, line) {
continue
}
line, _ = gregex.ReplaceStringFuncMatch(
`^(\w+)\(context\.Context, \*(\w+)\) \(\*(\w+), error\)$`,
line,
func(match []string) string {
return fmt.Sprintf(
`%s(ctx context.Context, req *%s.%s) (res *%s.%s, err error)`,
match[1], ctrl.Version, match[2], ctrl.Version, match[3],
)
},
)
ctrl.Methods = append(ctrl.Methods, generateCtrlMethod{
Name: gstr.Split(line, "(")[0],
Definition: line,
})
}
if len(ctrl.Methods) > 0 {
controllers = append(controllers, ctrl)
}
return match[0]
},
)
return controllers, err
}
func (c CGenPb) doGenerateControllers(in generateControllerInput, controllers []generateCtrl) (err error) {
for _, controller := range controllers {
err = c.doGenerateController(in, controller)
if err != nil {
return err
}
}
err = utils.ReplaceGeneratedContentGFV2(in.OutputCtrlPath)
return nil
}
func (c CGenPb) doGenerateController(in generateControllerInput, controller generateCtrl) (err error) {
var (
folderPath = gfile.Join(in.OutputCtrlPath, controller.Package)
filePath = gfile.Join(folderPath, controller.Package+".go")
isDirty bool
)
if !gfile.Exists(folderPath) {
if err = gfile.Mkdir(folderPath); err != nil {
return err
}
}
if !gfile.Exists(filePath) {
templateContent := gstr.ReplaceByMap(controllerTemplate, g.MapStrStr{
"{Name}": controller.Name,
"{Version}": controller.Version,
"{Package}": controller.Package,
})
if err = gfile.PutContents(filePath, templateContent); err != nil {
return err
}
isDirty = true
}
// Exist controller content.
var ctrlContent string
files, err := gfile.ScanDirFile(folderPath, "*.go", false)
if err != nil {
return err
}
for _, file := range files {
if ctrlContent != "" {
ctrlContent += "\n"
}
ctrlContent += gfile.GetContents(file)
}
// Generate method content.
var generatedContent string
for _, method := range controller.Methods {
if gstr.Contains(ctrlContent, fmt.Sprintf(`%s(`, method.Name)) {
continue
}
if generatedContent != "" {
generatedContent += "\n"
}
generatedContent += gstr.ReplaceByMap(controllerMethodTemplate, g.MapStrStr{
"{Definition}": method.Definition,
})
}
if generatedContent != "" {
err = gfile.PutContentsAppend(filePath, generatedContent)
if err != nil {
return err
}
isDirty = true
}
if isDirty {
utils.GoFmt(filePath)
}
return nil
}

View File

@ -0,0 +1,113 @@
// Copyright GoFrame gf 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 genpb
import (
"context"
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
)
type generateStructTagInput struct {
OutputApiPath string
}
func (c CGenPb) generateStructTag(ctx context.Context, in generateStructTagInput) (err error) {
files, err := gfile.ScanDirFile(in.OutputApiPath, "*.pb.go", true)
if err != nil {
return err
}
var content string
for _, file := range files {
content = gfile.GetContents(file)
content, err = c.doTagReplacement(ctx, content)
if err != nil {
return err
}
if err = gfile.PutContents(file, content); err != nil {
return err
}
utils.GoFmt(file)
}
return
}
func (c CGenPb) doTagReplacement(ctx context.Context, content string) (string, error) {
content, err := gregex.ReplaceStringFuncMatch(`type (\w+) struct {([\s\S]+?)}`, content, func(match []string) string {
var (
topCommentMatch []string
tailCommentMatch []string
lines = gstr.Split(match[2], "\n")
lineTagMap = gmap.NewListMap()
)
for index, line := range lines {
line = gstr.Trim(line)
if line == "" {
continue
}
// Top comment.
topCommentMatch, _ = gregex.MatchString(`^/[/|\*](.+)`, line)
if len(topCommentMatch) > 1 {
c.tagCommentIntoListMap(gstr.Trim(topCommentMatch[1]), lineTagMap)
continue
}
// Tail comment.
tailCommentMatch, _ = gregex.MatchString(".+?`.+?`.+?//(.+)", line)
if len(tailCommentMatch) > 1 {
c.tagCommentIntoListMap(gstr.Trim(tailCommentMatch[1]), lineTagMap)
}
// Tag injection.
if !lineTagMap.IsEmpty() {
tagContent := c.listMapToStructTag(lineTagMap)
lineTagMap.Clear()
line, _ = gregex.ReplaceString("`(.+)`", fmt.Sprintf("`$1 %s`", tagContent), line)
}
lines[index] = line
}
match[2] = gstr.Join(lines, "\n")
return fmt.Sprintf("type %s struct {%s}", match[1], match[2])
})
return content, err
}
func (c CGenPb) tagCommentIntoListMap(comment string, lineTagMap *gmap.ListMap) {
tagCommentMatch, _ := gregex.MatchString(`^(\w+):(.+)`, comment)
if len(tagCommentMatch) > 1 {
var (
tagName = gstr.Trim(tagCommentMatch[1])
tagContent = gstr.Trim(tagCommentMatch[2])
)
lineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)
} else {
var (
tagName = "dc"
tagContent = comment
)
lineTagMap.Set(tagName, lineTagMap.GetVar(tagName).String()+tagContent)
}
}
func (c CGenPb) listMapToStructTag(lineTagMap *gmap.ListMap) string {
var tag string
lineTagMap.Iterator(func(key, value interface{}) bool {
if tag != "" {
tag += " "
}
tag += fmt.Sprintf(
`%s:"%s"`,
key, gstr.Replace(gconv.String(value), `"`, `\"`),
)
return true
})
return tag
}

View File

@ -0,0 +1,419 @@
// Copyright GoFrame gf 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 genpbentity
import (
"bytes"
"context"
"fmt"
"github.com/olekukonko/tablewriter"
"strings"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/database/gdb"
"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/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
)
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}" d:"manifest/protobuf/pbentity"`
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
DB gdb.DB
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
}
)
const (
defaultPackageSuffix = `api/pbentity`
CGenPbEntityConfig = `gfcli.gen.pbentity`
CGenPbEntityBrief = `generate entity message files in protobuf3 format`
CGenPbEntityEg = `
gf gen pbentity
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
gf gen pbentity -r user_ -k github.com/gogf/gf/example/protobuf
gf gen pbentity -r user_
`
CGenPbEntityAd = `
CONFIGURATION SUPPORT
Options are also supported by configuration file.
It's suggested using configuration file instead of command line arguments making producing.
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
gfcli:
gen:
- pbentity:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
path: "protocol/demos/entity"
tables: "order,products"
package: "demos"
- pbentity:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
path: "protocol/demos/entity"
prefix: "primary_"
tables: "user, userDetail"
package: "demos"
option: |
option go_package = "protobuf/demos";
option java_package = "protobuf/demos";
option php_namespace = "protobuf/demos";
`
CGenPbEntityBriefPath = `directory path for generated files storing`
CGenPbEntityBriefPackage = `package path for all entity proto files`
CGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
CGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
CGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
CGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
CGenPbEntityBriefOption = `extra protobuf options`
CGenPbEntityBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
`
CGenPbEntityBriefNameCase = `
case for message attribute names, default is "Camel":
| Case | Example |
|---------------- |--------------------|
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString | default
| Snake | any_kind_of_string |
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
CGenPbEntityBriefJsonCase = `
case for message json tag, cases are the same as "nameCase", default "CamelLower".
set it to "none" to ignore json tag generating.
`
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenPbEntityConfig`: CGenPbEntityConfig,
`CGenPbEntityBrief`: CGenPbEntityBrief,
`CGenPbEntityEg`: CGenPbEntityEg,
`CGenPbEntityAd`: CGenPbEntityAd,
`CGenPbEntityBriefPath`: CGenPbEntityBriefPath,
`CGenPbEntityBriefPackage`: CGenPbEntityBriefPackage,
`CGenPbEntityBriefLink`: CGenPbEntityBriefLink,
`CGenPbEntityBriefTables`: CGenPbEntityBriefTables,
`CGenPbEntityBriefPrefix`: CGenPbEntityBriefPrefix,
`CGenPbEntityBriefRemovePrefix`: CGenPbEntityBriefRemovePrefix,
`CGenPbEntityBriefGroup`: CGenPbEntityBriefGroup,
`CGenPbEntityBriefNameCase`: CGenPbEntityBriefNameCase,
`CGenPbEntityBriefJsonCase`: CGenPbEntityBriefJsonCase,
`CGenPbEntityBriefOption`: CGenPbEntityBriefOption,
})
}
func (c CGenPbEntity) PbEntity(ctx context.Context, in CGenPbEntityInput) (out *CGenPbEntityOutput, err error) {
var (
config = g.Cfg()
)
if config.Available(ctx) {
v := config.MustGet(ctx, CGenPbEntityConfig)
if v.IsSlice() {
for i := 0; i < len(v.Interfaces()); i++ {
doGenPbEntityForArray(ctx, i, in)
}
} else {
doGenPbEntityForArray(ctx, -1, in)
}
} else {
doGenPbEntityForArray(ctx, -1, in)
}
mlog.Print("done!")
return
}
func doGenPbEntityForArray(ctx context.Context, index int, in CGenPbEntityInput) {
var (
err error
db gdb.DB
)
if index >= 0 {
err = g.Cfg().MustGet(
ctx,
fmt.Sprintf(`%s.%d`, CGenPbEntityConfig, index),
).Scan(&in)
if err != nil {
mlog.Fatalf(`invalid configuration of "%s": %+v`, CGenPbEntityConfig, err)
}
}
if in.Package == "" {
mlog.Debug(`package parameter is empty, trying calculating the package path using go.mod`)
if !gfile.Exists("go.mod") {
mlog.Fatal("go.mod does not exist in current working directory")
}
var (
modName string
goModContent = gfile.GetContents("go.mod")
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
)
if len(match) > 1 {
modName = gstr.Trim(match[1])
in.Package = modName + "/" + defaultPackageSuffix
} else {
mlog.Fatal("module name does not found in go.mod")
}
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
// It uses user passed database configuration.
if in.Link != "" {
var (
tempGroup = gtime.TimestampNanoStr()
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
)
if len(match) == 3 {
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
Type: gstr.Trim(match[1]),
Link: gstr.Trim(match[2]),
})
db, _ = gdb.Instance(tempGroup)
}
} else {
db = g.DB()
}
if db == nil {
mlog.Fatal("database initialization failed")
}
tableNames := ([]string)(nil)
if in.Tables != "" {
tableNames = gstr.SplitAndTrim(in.Tables, ",")
} else {
tableNames, err = db.Tables(context.TODO())
if err != nil {
mlog.Fatalf("fetching tables failed: \n %v", err)
}
}
for _, tableName := range tableNames {
newTableName := tableName
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
generatePbEntityContentFile(ctx, CGenPbEntityInternalInput{
CGenPbEntityInput: in,
DB: db,
TableName: tableName,
NewTableName: newTableName,
})
}
}
// generatePbEntityContentFile generates the protobuf files for given table.
func generatePbEntityContentFile(ctx context.Context, in CGenPbEntityInternalInput) {
fieldMap, err := in.DB.TableFields(ctx, in.TableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
}
// Change the `newTableName` if `Prefix` is given.
newTableName := in.Prefix + in.NewTableName
var (
imports string
tableNameCamelCase = gstr.CaseCamel(newTableName)
tableNameSnakeCase = gstr.CaseSnake(newTableName)
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
path = gfile.Join(in.Path, fileName+".proto")
)
if gstr.Contains(entityMessageDefine, "google.protobuf.Timestamp") {
imports = `import "google/protobuf/timestamp.proto";`
}
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
"{Imports}": imports,
"{PackageName}": gfile.Basename(in.Package),
"{GoPackage}": in.Package,
"{OptionContent}": in.Option,
"{EntityMessage}": entityMessageDefine,
})
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
mlog.Print("generated:", path)
}
}
// generateEntityMessageDefinition generates and returns the message definition for specified table.
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in CGenPbEntityInternalInput) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForPbEntity(fieldMap)
)
for index, name := range names {
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
buffer.Reset()
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
buffer.WriteString(stContent)
buffer.WriteString("}")
return buffer.String()
}
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in CGenPbEntityInternalInput) []string {
var (
typeName string
comment string
jsonTagStr string
err error
ctx = gctx.GetInitCtx()
)
typeName, err = in.DB.CheckLocalTypeForField(ctx, field.Type, nil)
if err != nil {
panic(err)
}
var typeMapping = map[string]string{
gdb.LocalTypeString: "string",
gdb.LocalTypeDate: "google.protobuf.Timestamp",
gdb.LocalTypeDatetime: "google.protobuf.Timestamp",
gdb.LocalTypeInt: "int32",
gdb.LocalTypeUint: "uint32",
gdb.LocalTypeInt64: "int64",
gdb.LocalTypeUint64: "uint64",
gdb.LocalTypeIntSlice: "repeated int32",
gdb.LocalTypeInt64Slice: "repeated int64",
gdb.LocalTypeUint64Slice: "repeated uint64",
gdb.LocalTypeInt64Bytes: "repeated int64",
gdb.LocalTypeUint64Bytes: "repeated uint64",
gdb.LocalTypeFloat32: "float32",
gdb.LocalTypeFloat64: "float64",
gdb.LocalTypeBytes: "[]byte",
gdb.LocalTypeBool: "bool",
gdb.LocalTypeJson: "string",
gdb.LocalTypeJsonb: "string",
}
typeName = typeMapping[typeName]
if typeName == "" {
typeName = "string"
}
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
"\n", " ",
"\r", " ",
})
comment = gstr.Trim(comment)
comment = gstr.Replace(comment, `\n`, " ")
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
// beautiful indent.
if index < 10 {
// 3 spaces
jsonTagStr = " " + jsonTagStr
} else if index < 100 {
// 2 spaces
jsonTagStr = " " + jsonTagStr
} else {
// 1 spaces
jsonTagStr = " " + jsonTagStr
}
}
return []string{
" #" + typeName,
" #" + formatCase(field.Name, in.NameCase),
" #= " + gconv.String(index) + jsonTagStr + ";",
" #" + fmt.Sprintf(`// %s`, comment),
}
}
func getTplPbEntityContent(tplEntityPath string) string {
if tplEntityPath != "" {
return gfile.GetContents(tplEntityPath)
}
return consts.TemplatePbEntityMessageContent
}
// formatCase call gstr.Case* function to convert the s to specified case.
func formatCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("Snake"):
return gstr.CaseSnake(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
case "none":
return ""
}
return str
}
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
names := make(map[int]string)
for _, field := range fieldMap {
names[field.Index] = field.Name
}
var (
result = make([]string, len(names))
i = 0
j = 0
)
for {
if len(names) == 0 {
break
}
if val, ok := names[i]; ok {
result[j] = val
j++
delete(names, i)
}
i++
}
return result
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 genservice
import (
@ -189,6 +195,10 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
generatedDstFilePathSet.Add(dstFilePath)
for _, file := range files {
fileContent = gfile.GetContents(file)
fileContent, err := gregex.ReplaceString(`/[/|\*](.+)`, "", fileContent)
if err != nil {
return nil, err
}
// Calculate imported packages of source go files.
err = c.calculateImportedPackages(fileContent, srcImportedPackages)
if err != nil {
@ -254,7 +264,7 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
}
// Replace v1 to v2 for GoFrame.
if err = c.replaceGeneratedServiceContentGFV2(in); err != nil {
if err = utils.ReplaceGeneratedContentGFV2(in.DstFolder); err != nil {
return nil, err
}
mlog.Printf(`gofmt go files in "%s"`, in.DstFolder)
@ -264,14 +274,3 @@ func (c CGenService) Service(ctx context.Context, in CGenServiceInput) (out *CGe
mlog.Print(`done!`)
return
}
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"`)
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
return content
}
return content
}, in.DstFolder, "*.go", false)
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 genservice
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 genservice
import (
@ -56,7 +62,7 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
generatingInterfaceCheck string
)
// Variable definitions.
for structName, _ := range in.SrcStructFunctions {
for structName := range in.SrcStructFunctions {
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
continue
@ -75,7 +81,7 @@ func (c CGenService) generateServiceFile(in generateServiceFilesInput) (ok bool,
generatedContent += "\n"
}
// Variable register function definitions.
for structName, _ := range in.SrcStructFunctions {
for structName := range in.SrcStructFunctions {
generatingInterfaceCheck = fmt.Sprintf(`[^\w\d]+%s.I%s[^\w\d]`, in.DstPackageName, structName)
if gregex.IsMatchString(generatingInterfaceCheck, generatedContent) {
continue

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const TemplateGenDaoIndexContent = `
@ -102,7 +108,7 @@ func (dao *{TplTableNameCamelCase}Dao) Ctx(ctx context.Context) *gdb.Model {
//
// Note that, you should not Commit or Rollback the transaction in function f
// as it is automatically handled by this function.
func (dao *{TplTableNameCamelCase}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx *gdb.TX) error) (err error) {
func (dao *{TplTableNameCamelCase}Dao) Transaction(ctx context.Context, f func(ctx context.Context, tx gdb.TX) error) (err error) {
return dao.Ctx(ctx).Transaction(ctx, f)
}
`

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const TemplateGenDaoDoContent = `

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const TemplateGenDaoEntityContent = `

View File

@ -0,0 +1,23 @@
// Copyright GoFrame gf 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 consts
const TemplateGenEnums = `
// ================================================================================
// Code generated by GoFrame CLI tool. DO NOT EDIT.
// ================================================================================
package {PackageName}
import (
"github.com/gogf/gf/v2/util/gtag"
)
func init() {
gtag.SetGlobalEnums({EnumsJson})
}
`

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const TemplatePbEntityMessageContent = `
@ -9,9 +15,9 @@ syntax = "proto3";
package {PackageName};
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
option go_package = "{GoPackage}";
{OptionContent}
{Imports}
{EntityMessage}
`

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const TemplateGenServiceContentHead = `

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 consts
const TemplateGenServiceLogicContent = `

View File

@ -1 +1,7 @@
// Copyright GoFrame gf 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 packed

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 service
import (
@ -29,6 +35,7 @@ type serviceInstallAvailablePath struct {
filePath string
writable bool
installed bool
IsSelf bool
}
func (s serviceInstall) Run(ctx context.Context) (err error) {
@ -119,33 +126,26 @@ func (s serviceInstall) Run(ctx context.Context) (err error) {
dstPath := paths[selectedID]
// Install the new binary.
mlog.Debugf(`copy file from "%s" to "%s"`, gfile.SelfPath(), dstPath.filePath)
err = gfile.CopyFile(gfile.SelfPath(), dstPath.filePath)
if err != nil {
mlog.Printf("install gf binary to '%s' failed: %v", dstPath.dirPath, err)
mlog.Printf("you can manually install gf by copying the binary to folder: %s", dstPath.dirPath)
} else {
mlog.Printf("gf binary is successfully installed to: %s", dstPath.dirPath)
}
// Uninstall the old binary.
for _, path := range paths {
// Do not delete myself.
if path.filePath != "" && path.filePath != dstPath.filePath && gfile.SelfPath() != path.filePath {
_ = gfile.Remove(path.filePath)
}
mlog.Printf("gf binary is successfully installed to: %s", dstPath.filePath)
}
return
}
// IsInstalled checks and returns whether the binary is installed.
func (s serviceInstall) IsInstalled() bool {
func (s serviceInstall) IsInstalled() (*serviceInstallAvailablePath, bool) {
paths := s.getAvailablePaths()
for _, aPath := range paths {
if aPath.installed {
return true
return &aPath, true
}
}
return false
return nil, false
}
// getGoPathBinFilePath retrieves ad returns the GOPATH/bin path for binary.
@ -221,6 +221,7 @@ func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInsta
filePath = gfile.Join(dirPath, binaryFileName)
writable = gfile.IsWritable(dirPath)
installed = gfile.Exists(filePath)
self = gfile.SelfPath() == filePath
)
if !writable && !installed {
return folderPaths
@ -232,5 +233,6 @@ func (s serviceInstall) checkAndAppendToAvailablePath(folderPaths []serviceInsta
writable: writable,
filePath: filePath,
installed: installed,
IsSelf: self,
})
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 allyes
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 mlog
import (

View File

@ -1,12 +1,21 @@
// Copyright GoFrame gf 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 utils
import (
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"context"
"fmt"
"golang.org/x/tools/imports"
"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"
)
// GoFmt formats the source file and adds or removes import statements as necessary.
@ -36,6 +45,13 @@ func GoFmt(path string) {
}
}
// GoModTidy executes `go mod tidy` at specified directory `dirPath`.
func GoModTidy(ctx context.Context, dirPath string) error {
command := fmt.Sprintf(`cd %s && go mod tidy`, dirPath)
err := gproc.ShellRun(ctx, command)
return err
}
// IsFileDoNotEdit checks and returns whether file contains `do not edit` key.
func IsFileDoNotEdit(filePath string) bool {
if !gfile.Exists(filePath) {
@ -43,3 +59,16 @@ func IsFileDoNotEdit(filePath string) bool {
}
return gstr.Contains(gfile.GetContents(filePath), consts.DoNotEditKey)
}
// ReplaceGeneratedContentGFV2 replaces generated go content from goframe v1 to v2.
func ReplaceGeneratedContentGFV2(folderPath string) (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"`)
content = gstr.Replace(content, `"github.com/gogf/gf/`, `"github.com/gogf/gf/v2/`)
content = gstr.Replace(content, `"github.com/gogf/gf/v2/contrib/`, `"github.com/gogf/gf/contrib/`)
return content
}
return content
}, folderPath, "*.go", true)
}

View File

@ -0,0 +1,105 @@
// Copyright GoFrame gf 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 utils
import (
"fmt"
"io"
"net/http"
"os"
"strconv"
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
// HTTPDownloadFileWithPercent downloads target url file to local path with percent process printing.
func HTTPDownloadFileWithPercent(url string, localSaveFilePath string) error {
start := time.Now()
out, err := os.Create(localSaveFilePath)
if err != nil {
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
}
defer out.Close()
headResp, err := http.Head(url)
if err != nil {
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
}
defer headResp.Body.Close()
size, err := strconv.Atoi(headResp.Header.Get("Content-Length"))
if err != nil {
return gerror.Wrap(err, "retrieve Content-Length failed")
}
doneCh := make(chan int64)
go doPrintDownloadPercent(doneCh, localSaveFilePath, int64(size))
resp, err := http.Get(url)
if err != nil {
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
}
defer resp.Body.Close()
wroteBytesCount, err := io.Copy(out, resp.Body)
if err != nil {
return gerror.Wrapf(err, `download "%s" to "%s" failed`, url, localSaveFilePath)
}
doneCh <- wroteBytesCount
elapsed := time.Since(start)
if elapsed > time.Minute {
mlog.Printf(`download completed in %.0fm`, float64(elapsed)/float64(time.Minute))
} else {
mlog.Printf(`download completed in %.0fs`, elapsed.Seconds())
}
return nil
}
func doPrintDownloadPercent(doneCh chan int64, localSaveFilePath string, total int64) {
var (
stop = false
lastPercentFmt string
)
for {
select {
case <-doneCh:
stop = true
default:
file, err := os.Open(localSaveFilePath)
if err != nil {
mlog.Fatal(err)
}
fi, err := file.Stat()
if err != nil {
mlog.Fatal(err)
}
size := fi.Size()
if size == 0 {
size = 1
}
var (
percent = float64(size) / float64(total) * 100
percentFmt = fmt.Sprintf(`%.0f`, percent) + "%"
)
if lastPercentFmt != percentFmt {
lastPercentFmt = percentFmt
mlog.Print(percentFmt)
}
}
if stop {
break
}
time.Sleep(time.Second)
}
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf 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 main
import (
@ -53,7 +59,9 @@ func main() {
panic(err)
}
err = command.AddObject(
cmd.Up,
cmd.Env,
cmd.Fix,
cmd.Run,
cmd.Gen,
cmd.Tpl,
@ -67,7 +75,10 @@ func main() {
if err != nil {
panic(err)
}
command.Run(ctx)
err = command.RunWithError(ctx)
if err != nil {
panic(err)
}
}
// zsh alias "git fetch" conflicts checks.

View File

@ -53,16 +53,16 @@ func NewArraySize(size int, cap int, safe ...bool) *Array {
}
}
// NewArrayRange creates and returns a array by a range from `start` to `end`
// NewArrayRange creates and returns an array by a range from `start` to `end`
// with step value `step`.
func NewArrayRange(start, end, step int, safe ...bool) *Array {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]interface{}, (end-start+1)/step)
slice := make([]interface{}, 0)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
slice = append(slice, i)
index++
}
return NewArrayFrom(slice, safe...)
@ -173,28 +173,28 @@ func (a *Array) SortFunc(less func(v1, v2 interface{}) bool) *Array {
return a
}
// InsertBefore inserts the `value` to the front of `index`.
func (a *Array) InsertBefore(index int, value interface{}) error {
// InsertBefore inserts the `values` to the front of `index`.
func (a *Array) InsertBefore(index int, values ...interface{}) error {
a.mu.Lock()
defer a.mu.Unlock()
if index < 0 || index >= len(a.array) {
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
}
rear := append([]interface{}{}, a.array[index:]...)
a.array = append(a.array[0:index], value)
a.array = append(a.array[0:index], values...)
a.array = append(a.array, rear...)
return nil
}
// InsertAfter inserts the `value` to the back of `index`.
func (a *Array) InsertAfter(index int, value interface{}) error {
// InsertAfter inserts the `values` to the back of `index`.
func (a *Array) InsertAfter(index int, values ...interface{}) error {
a.mu.Lock()
defer a.mu.Unlock()
if index < 0 || index >= len(a.array) {
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
}
rear := append([]interface{}{}, a.array[index+1:]...)
a.array = append(a.array[0:index+1], value)
a.array = append(a.array[0:index+1], values...)
a.array = append(a.array, rear...)
return nil
}
@ -233,13 +233,26 @@ func (a *Array) doRemoveWithoutLock(index int) (value interface{}, found bool) {
// RemoveValue removes an item by value.
// It returns true if value is found in the array, or else false if not found.
func (a *Array) RemoveValue(value interface{}) bool {
if i := a.Search(value); i != -1 {
a.Remove(i)
a.mu.Lock()
defer a.mu.Unlock()
if i := a.doSearchWithoutLock(value); i != -1 {
a.doRemoveWithoutLock(i)
return true
}
return false
}
// RemoveValues removes multiple items by `values`.
func (a *Array) RemoveValues(values ...interface{}) {
a.mu.Lock()
defer a.mu.Unlock()
for _, value := range values {
if i := a.doSearchWithoutLock(value); i != -1 {
a.doRemoveWithoutLock(i)
}
}
}
// PushLeft pushes one or multiple items to the beginning of array.
func (a *Array) PushLeft(value ...interface{}) *Array {
a.mu.Lock()
@ -487,6 +500,10 @@ func (a *Array) Contains(value interface{}) bool {
func (a *Array) Search(value interface{}) int {
a.mu.RLock()
defer a.mu.RUnlock()
return a.doSearchWithoutLock(value)
}
func (a *Array) doSearchWithoutLock(value interface{}) int {
if len(a.array) == 0 {
return -1
}
@ -778,6 +795,22 @@ func (a *Array) UnmarshalValue(value interface{}) error {
return nil
}
// Filter iterates array and filters elements using custom callback function.
// It removes the element from array if callback function `filter` returns true,
// it or else does nothing and continues iterating.
func (a *Array) Filter(filter func(index int, value interface{}) bool) *Array {
a.mu.Lock()
defer a.mu.Unlock()
for i := 0; i < len(a.array); {
if filter(i, a.array[i]) {
a.array = append(a.array[:i], a.array[i+1:]...)
} else {
i++
}
}
return a
}
// FilterNil removes all nil value of the array.
func (a *Array) FilterNil() *Array {
a.mu.Lock()

View File

@ -45,16 +45,16 @@ func NewIntArraySize(size int, cap int, safe ...bool) *IntArray {
}
}
// NewIntArrayRange creates and returns a array by a range from `start` to `end`
// NewIntArrayRange creates and returns an array by a range from `start` to `end`
// with step value `step`.
func NewIntArrayRange(start, end, step int, safe ...bool) *IntArray {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]int, (end-start+1)/step)
slice := make([]int, 0)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
slice = append(slice, i)
index++
}
return NewIntArrayFrom(slice, safe...)
@ -168,28 +168,28 @@ func (a *IntArray) SortFunc(less func(v1, v2 int) bool) *IntArray {
return a
}
// InsertBefore inserts the `value` to the front of `index`.
func (a *IntArray) InsertBefore(index int, value int) error {
// InsertBefore inserts the `values` to the front of `index`.
func (a *IntArray) InsertBefore(index int, values ...int) error {
a.mu.Lock()
defer a.mu.Unlock()
if index < 0 || index >= len(a.array) {
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
}
rear := append([]int{}, a.array[index:]...)
a.array = append(a.array[0:index], value)
a.array = append(a.array[0:index], values...)
a.array = append(a.array, rear...)
return nil
}
// InsertAfter inserts the `value` to the back of `index`.
func (a *IntArray) InsertAfter(index int, value int) error {
func (a *IntArray) InsertAfter(index int, values ...int) error {
a.mu.Lock()
defer a.mu.Unlock()
if index < 0 || index >= len(a.array) {
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
}
rear := append([]int{}, a.array[index+1:]...)
a.array = append(a.array[0:index+1], value)
a.array = append(a.array[0:index+1], values...)
a.array = append(a.array, rear...)
return nil
}
@ -228,13 +228,26 @@ func (a *IntArray) doRemoveWithoutLock(index int) (value int, found bool) {
// RemoveValue removes an item by value.
// It returns true if value is found in the array, or else false if not found.
func (a *IntArray) RemoveValue(value int) bool {
if i := a.Search(value); i != -1 {
_, found := a.Remove(i)
return found
a.mu.Lock()
defer a.mu.Unlock()
if i := a.doSearchWithoutLock(value); i != -1 {
a.doRemoveWithoutLock(i)
return true
}
return false
}
// RemoveValues removes multiple items by `values`.
func (a *IntArray) RemoveValues(values ...int) {
a.mu.Lock()
defer a.mu.Unlock()
for _, value := range values {
if i := a.doSearchWithoutLock(value); i != -1 {
a.doRemoveWithoutLock(i)
}
}
}
// PushLeft pushes one or multiple items to the beginning of array.
func (a *IntArray) PushLeft(value ...int) *IntArray {
a.mu.Lock()
@ -497,6 +510,10 @@ func (a *IntArray) Contains(value int) bool {
func (a *IntArray) Search(value int) int {
a.mu.RLock()
defer a.mu.RUnlock()
return a.doSearchWithoutLock(value)
}
func (a *IntArray) doSearchWithoutLock(value int) int {
if len(a.array) == 0 {
return -1
}
@ -771,6 +788,22 @@ func (a *IntArray) UnmarshalValue(value interface{}) error {
return nil
}
// Filter iterates array and filters elements using custom callback function.
// It removes the element from array if callback function `filter` returns true,
// it or else does nothing and continues iterating.
func (a *IntArray) Filter(filter func(index int, value int) bool) *IntArray {
a.mu.Lock()
defer a.mu.Unlock()
for i := 0; i < len(a.array); {
if filter(i, a.array[i]) {
a.array = append(a.array[:i], a.array[i+1:]...)
} else {
i++
}
}
return a
}
// FilterEmpty removes all zero value of the array.
func (a *IntArray) FilterEmpty() *IntArray {
a.mu.Lock()

View File

@ -155,28 +155,28 @@ func (a *StrArray) SortFunc(less func(v1, v2 string) bool) *StrArray {
return a
}
// InsertBefore inserts the `value` to the front of `index`.
func (a *StrArray) InsertBefore(index int, value string) error {
// InsertBefore inserts the `values` to the front of `index`.
func (a *StrArray) InsertBefore(index int, values ...string) error {
a.mu.Lock()
defer a.mu.Unlock()
if index < 0 || index >= len(a.array) {
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
}
rear := append([]string{}, a.array[index:]...)
a.array = append(a.array[0:index], value)
a.array = append(a.array[0:index], values...)
a.array = append(a.array, rear...)
return nil
}
// InsertAfter inserts the `value` to the back of `index`.
func (a *StrArray) InsertAfter(index int, value string) error {
// InsertAfter inserts the `values` to the back of `index`.
func (a *StrArray) InsertAfter(index int, values ...string) error {
a.mu.Lock()
defer a.mu.Unlock()
if index < 0 || index >= len(a.array) {
return gerror.NewCodef(gcode.CodeInvalidParameter, "index %d out of array range %d", index, len(a.array))
}
rear := append([]string{}, a.array[index+1:]...)
a.array = append(a.array[0:index+1], value)
a.array = append(a.array[0:index+1], values...)
a.array = append(a.array, rear...)
return nil
}
@ -222,6 +222,17 @@ func (a *StrArray) RemoveValue(value string) bool {
return false
}
// RemoveValues removes multiple items by `values`.
func (a *StrArray) RemoveValues(values ...string) {
a.mu.Lock()
defer a.mu.Unlock()
for _, value := range values {
if i := a.doSearchWithoutLock(value); i != -1 {
a.doRemoveWithoutLock(i)
}
}
}
// PushLeft pushes one or multiple items to the beginning of array.
func (a *StrArray) PushLeft(value ...string) *StrArray {
a.mu.Lock()
@ -499,6 +510,10 @@ func (a *StrArray) ContainsI(value string) bool {
func (a *StrArray) Search(value string) int {
a.mu.RLock()
defer a.mu.RUnlock()
return a.doSearchWithoutLock(value)
}
func (a *StrArray) doSearchWithoutLock(value string) int {
if len(a.array) == 0 {
return -1
}
@ -784,6 +799,22 @@ func (a *StrArray) UnmarshalValue(value interface{}) error {
return nil
}
// Filter iterates array and filters elements using custom callback function.
// It removes the element from array if callback function `filter` returns true,
// it or else does nothing and continues iterating.
func (a *StrArray) Filter(filter func(index int, value string) bool) *StrArray {
a.mu.Lock()
defer a.mu.Unlock()
for i := 0; i < len(a.array); {
if filter(i, a.array[i]) {
a.array = append(a.array[:i], a.array[i+1:]...)
} else {
i++
}
}
return a
}
// FilterEmpty removes all empty string value of the array.
func (a *StrArray) FilterEmpty() *StrArray {
a.mu.Lock()

View File

@ -55,16 +55,16 @@ func NewSortedArraySize(cap int, comparator func(a, b interface{}) int, safe ...
}
}
// NewSortedArrayRange creates and returns a array by a range from `start` to `end`
// NewSortedArrayRange creates and returns an array by a range from `start` to `end`
// with step value `step`.
func NewSortedArrayRange(start, end, step int, comparator func(a, b interface{}) int, safe ...bool) *SortedArray {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]interface{}, (end-start+1)/step)
slice := make([]interface{}, 0)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
slice = append(slice, i)
index++
}
return NewSortedArrayFrom(slice, comparator, safe...)
@ -207,13 +207,26 @@ func (a *SortedArray) doRemoveWithoutLock(index int) (value interface{}, found b
// RemoveValue removes an item by value.
// It returns true if value is found in the array, or else false if not found.
func (a *SortedArray) RemoveValue(value interface{}) bool {
if i := a.Search(value); i != -1 {
a.Remove(i)
return true
a.mu.Lock()
defer a.mu.Unlock()
if i, r := a.binSearch(value, false); r == 0 {
_, res := a.doRemoveWithoutLock(i)
return res
}
return false
}
// RemoveValues removes an item by `values`.
func (a *SortedArray) RemoveValues(values ...interface{}) {
a.mu.Lock()
defer a.mu.Unlock()
for _, value := range values {
if i, r := a.binSearch(value, false); r == 0 {
a.doRemoveWithoutLock(i)
}
}
}
// PopLeft pops and returns an item from the beginning of array.
// Note that if the array is empty, the `found` is false.
func (a *SortedArray) PopLeft() (value interface{}, found bool) {
@ -468,7 +481,7 @@ func (a *SortedArray) binSearch(value interface{}, lock bool) (index int, result
// SetUnique sets unique mark to the array,
// which means it does not contain any repeated items.
// It also do unique check, remove all repeated items.
// It also does unique check, remove all repeated items.
func (a *SortedArray) SetUnique(unique bool) *SortedArray {
oldUnique := a.unique
a.unique = unique
@ -748,6 +761,22 @@ func (a *SortedArray) FilterNil() *SortedArray {
return a
}
// Filter iterates array and filters elements using custom callback function.
// It removes the element from array if callback function `filter` returns true,
// it or else does nothing and continues iterating.
func (a *SortedArray) Filter(filter func(index int, value interface{}) bool) *SortedArray {
a.mu.Lock()
defer a.mu.Unlock()
for i := 0; i < len(a.array); {
if filter(i, a.array[i]) {
a.array = append(a.array[:i], a.array[i+1:]...)
} else {
i++
}
}
return a
}
// FilterEmpty removes all empty value of the array.
// Values like: 0, nil, false, "", len(slice/map/chan) == 0 are considered empty.
func (a *SortedArray) FilterEmpty() *SortedArray {

View File

@ -56,16 +56,16 @@ func NewSortedIntArraySize(cap int, safe ...bool) *SortedIntArray {
}
}
// NewSortedIntArrayRange creates and returns a array by a range from `start` to `end`
// NewSortedIntArrayRange creates and returns an array by a range from `start` to `end`
// with step value `step`.
func NewSortedIntArrayRange(start, end, step int, safe ...bool) *SortedIntArray {
if step == 0 {
panic(fmt.Sprintf(`invalid step value: %d`, step))
}
slice := make([]int, (end-start+1)/step)
slice := make([]int, 0)
index := 0
for i := start; i <= end; i += step {
slice[index] = i
slice = append(slice, i)
index++
}
return NewSortedIntArrayFrom(slice, safe...)
@ -193,13 +193,26 @@ func (a *SortedIntArray) doRemoveWithoutLock(index int) (value int, found bool)
// RemoveValue removes an item by value.
// It returns true if value is found in the array, or else false if not found.
func (a *SortedIntArray) RemoveValue(value int) bool {
if i := a.Search(value); i != -1 {
_, found := a.Remove(i)
return found
a.mu.Lock()
defer a.mu.Unlock()
if i, r := a.binSearch(value, false); r == 0 {
_, res := a.doRemoveWithoutLock(i)
return res
}
return false
}
// RemoveValues removes an item by `values`.
func (a *SortedIntArray) RemoveValues(values ...int) {
a.mu.Lock()
defer a.mu.Unlock()
for _, value := range values {
if i, r := a.binSearch(value, false); r == 0 {
a.doRemoveWithoutLock(i)
}
}
}
// PopLeft pops and returns an item from the beginning of array.
// Note that if the array is empty, the `found` is false.
func (a *SortedIntArray) PopLeft() (value int, found bool) {
@ -696,6 +709,22 @@ func (a *SortedIntArray) UnmarshalValue(value interface{}) (err error) {
return err
}
// Filter iterates array and filters elements using custom callback function.
// It removes the element from array if callback function `filter` returns true,
// it or else does nothing and continues iterating.
func (a *SortedIntArray) Filter(filter func(index int, value int) bool) *SortedIntArray {
a.mu.Lock()
defer a.mu.Unlock()
for i := 0; i < len(a.array); {
if filter(i, a.array[i]) {
a.array = append(a.array[:i], a.array[i+1:]...)
} else {
i++
}
}
return a
}
// FilterEmpty removes all zero value of the array.
func (a *SortedIntArray) FilterEmpty() *SortedIntArray {
a.mu.Lock()

View File

@ -179,13 +179,26 @@ func (a *SortedStrArray) doRemoveWithoutLock(index int) (value string, found boo
// RemoveValue removes an item by value.
// It returns true if value is found in the array, or else false if not found.
func (a *SortedStrArray) RemoveValue(value string) bool {
if i := a.Search(value); i != -1 {
a.Remove(i)
return true
a.mu.Lock()
defer a.mu.Unlock()
if i, r := a.binSearch(value, false); r == 0 {
_, res := a.doRemoveWithoutLock(i)
return res
}
return false
}
// RemoveValues removes an item by `values`.
func (a *SortedStrArray) RemoveValues(values ...string) {
a.mu.Lock()
defer a.mu.Unlock()
for _, value := range values {
if i, r := a.binSearch(value, false); r == 0 {
a.doRemoveWithoutLock(i)
}
}
}
// PopLeft pops and returns an item from the beginning of array.
// Note that if the array is empty, the `found` is false.
func (a *SortedStrArray) PopLeft() (value string, found bool) {
@ -709,6 +722,22 @@ func (a *SortedStrArray) UnmarshalValue(value interface{}) (err error) {
return err
}
// Filter iterates array and filters elements using custom callback function.
// It removes the element from array if callback function `filter` returns true,
// it or else does nothing and continues iterating.
func (a *SortedStrArray) Filter(filter func(index int, value string) bool) *SortedStrArray {
a.mu.Lock()
defer a.mu.Unlock()
for i := 0; i < len(a.array); {
if filter(i, a.array[i]) {
a.array = append(a.array[:i], a.array[i+1:]...)
} else {
i++
}
}
return a
}
// FilterEmpty removes all empty string value of the array.
func (a *SortedStrArray) FilterEmpty() *SortedStrArray {
a.mu.Lock()

View File

@ -9,6 +9,8 @@ package garray_test
import (
"fmt"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
)
@ -261,6 +263,21 @@ func ExampleArray_Merge() {
// [1 2 1 2 3 4 5 6 7 8 9 0]
}
func ExampleArray_Filter() {
array1 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
array2 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
fmt.Printf("%#v\n", array1.Filter(func(index int, value interface{}) bool {
return empty.IsNil(value)
}).Slice())
fmt.Printf("%#v\n", array2.Filter(func(index int, value interface{}) bool {
return empty.IsEmpty(value)
}).Slice())
// Output:
// []interface {}{0, 1, 2, "", []interface {}{}, "john"}
// []interface {}{1, 2, "john"}
}
func ExampleArray_FilterEmpty() {
array1 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})
array2 := garray.NewFrom(g.Slice{0, 1, 2, nil, "", g.Slice{}, "john"})

View File

@ -9,6 +9,8 @@ package garray_test
import (
"fmt"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -59,7 +61,7 @@ func ExampleNewIntArrayRange() {
fmt.Println(s.Slice(), s.Len(), cap(s.Slice()))
// Output:
// [1 2 3 4 5] 5 5
// [1 2 3 4 5] 5 8
}
func ExampleNewIntArrayFrom() {
@ -699,6 +701,25 @@ func ExampleIntArray_UnmarshalValue() {
// &{john [96,98,97]}
}
func ExampleIntArray_Filter() {
array1 := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})
array2 := garray.NewIntArrayFrom(g.SliceInt{10, 4, 51, 5, 45, 50, 56})
fmt.Println(array1.Filter(func(index int, value int) bool {
return empty.IsEmpty(value)
}))
fmt.Println(array2.Filter(func(index int, value int) bool {
return value%2 == 0
}))
fmt.Println(array2.Filter(func(index int, value int) bool {
return value%2 == 1
}))
// Output:
// [10,40,50,60]
// [51,5,45]
// []
}
func ExampleIntArray_FilterEmpty() {
s := garray.NewIntArrayFrom(g.SliceInt{10, 40, 50, 0, 0, 0, 60})
fmt.Println(s)

View File

@ -8,6 +8,9 @@ package garray_test
import (
"fmt"
"strings"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
@ -622,6 +625,22 @@ func ExampleStrArray_UnmarshalValue() {
// &{john ["Math","English","Sport"]}
}
func ExampleStrArray_Filter() {
s := garray.NewStrArrayFrom(g.SliceStr{"Math", "English", "Sport"})
s1 := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
fmt.Println(s1.Filter(func(index int, value string) bool {
return empty.IsEmpty(value)
}))
fmt.Println(s.Filter(func(index int, value string) bool {
return strings.Contains(value, "h")
}))
// Output:
// ["a","b","c","d"]
// ["Sport"]
}
func ExampleStrArray_FilterEmpty() {
s := garray.NewStrArrayFrom(g.SliceStr{"a", "b", "", "c", "", "", "d"})
fmt.Println(s.FilterEmpty())

View File

@ -9,6 +9,8 @@ package garray_test
import (
"fmt"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -552,6 +554,18 @@ func ExampleSortedStrArray_UnmarshalValue() {
// &{john ["Math","English","Sport"]}
}
func ExampleSortedStrArray_Filter() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
fmt.Println(s)
fmt.Println(s.Filter(func(index int, value string) bool {
return empty.IsEmpty(value)
}))
// Output:
// ["","","","a","b","c","d"]
// ["a","b","c","d"]
}
func ExampleSortedStrArray_FilterEmpty() {
s := garray.NewSortedStrArrayFrom(g.SliceStr{"b", "a", "", "c", "", "", "d"})
fmt.Println(s)

View File

@ -12,6 +12,8 @@ import (
"testing"
"time"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -750,6 +752,15 @@ func TestArray_RemoveValue(t *testing.T) {
})
}
func TestArray_RemoveValues(t *testing.T) {
slice := g.Slice{"a", "b", "d", "c"}
array := garray.NewArrayFrom(slice)
gtest.C(t, func(t *gtest.T) {
array.RemoveValues("a", "b", "c")
t.Assert(array.Slice(), g.Slice{"d"})
})
}
func TestArray_UnmarshalValue(t *testing.T) {
type V struct {
Name string
@ -791,6 +802,36 @@ func TestArray_FilterNil(t *testing.T) {
})
}
func TestArray_Filter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
values := g.Slice{0, 1, 2, 3, 4, "", g.Slice{}}
array := garray.NewArrayFromCopy(values)
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsNil(value)
}).Slice(), values)
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil})
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsNil(value)
}), g.Slice{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewArrayFrom(g.Slice{0, 1, 2, 3, 4, "", g.Slice{}})
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsEmpty(value)
}), g.Slice{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewArrayFrom(g.Slice{1, 2, 3, 4})
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsEmpty(value)
}), g.Slice{1, 2, 3, 4})
})
}
func TestArray_FilterEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewArrayFrom(g.Slice{0, 1, 2, 3, 4, "", g.Slice{}})

View File

@ -12,6 +12,8 @@ import (
"testing"
"time"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -765,6 +767,15 @@ func TestIntArray_RemoveValue(t *testing.T) {
})
}
func TestIntArray_RemoveValues(t *testing.T) {
slice := g.SliceInt{10, 20, 30, 40}
array := garray.NewIntArrayFrom(slice)
gtest.C(t, func(t *gtest.T) {
array.RemoveValues(10, 20, 40)
t.Assert(array.Slice(), g.SliceInt{30})
})
}
func TestIntArray_UnmarshalValue(t *testing.T) {
type V struct {
Name string
@ -794,6 +805,34 @@ func TestIntArray_UnmarshalValue(t *testing.T) {
// })
}
func TestIntArray_Filter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})
t.Assert(array.Filter(func(index int, value int) bool {
return empty.IsEmpty(value)
}), g.SliceInt{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})
t.Assert(array.Filter(func(index int, value int) bool {
return empty.IsEmpty(value)
}), g.SliceInt{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})
t.Assert(array.Filter(func(index int, value int) bool {
return value%2 == 0
}), g.SliceInt{1, 3})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayFrom(g.SliceInt{1, 2, 3, 4})
t.Assert(array.Filter(func(index int, value int) bool {
return value%2 == 1
}), g.SliceInt{2, 4})
})
}
func TestIntArray_FilterEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})
@ -813,3 +852,14 @@ func TestIntArray_Walk(t *testing.T) {
}), g.Slice{11, 12})
})
}
func TestIntArray_NewIntArrayRange(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayRange(0, 128, 4)
t.Assert(array.String(), `[0,4,8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128]`)
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewIntArrayRange(1, 128, 4)
t.Assert(array.String(), `[1,5,9,13,17,21,25,29,33,37,41,45,49,53,57,61,65,69,73,77,81,85,89,93,97,101,105,109,113,117,121,125]`)
})
}

View File

@ -13,6 +13,8 @@ import (
"testing"
"time"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -776,6 +778,15 @@ func TestStrArray_RemoveValue(t *testing.T) {
})
}
func TestStrArray_RemoveValues(t *testing.T) {
slice := g.SliceStr{"a", "b", "d", "c"}
array := garray.NewStrArrayFrom(slice)
gtest.C(t, func(t *gtest.T) {
array.RemoveValues("a", "b", "c")
t.Assert(array.Slice(), g.SliceStr{"d"})
})
}
func TestStrArray_UnmarshalValue(t *testing.T) {
type V struct {
Name string
@ -804,6 +815,20 @@ func TestStrArray_UnmarshalValue(t *testing.T) {
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
})
}
func TestStrArray_Filter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewStrArrayFrom(g.SliceStr{"", "1", "2", "0"})
t.Assert(array.Filter(func(index int, value string) bool {
return empty.IsEmpty(value)
}), g.SliceStr{"1", "2", "0"})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewStrArrayFrom(g.SliceStr{"1", "2"})
t.Assert(array.Filter(func(index int, value string) bool {
return empty.IsEmpty(value)
}), g.SliceStr{"1", "2"})
})
}
func TestStrArray_FilterEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {

View File

@ -13,6 +13,8 @@ import (
"testing"
"time"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -869,6 +871,15 @@ func TestSortedArray_RemoveValue(t *testing.T) {
})
}
func TestSortedArray_RemoveValues(t *testing.T) {
slice := g.Slice{"a", "b", "d", "c"}
array := garray.NewSortedArrayFrom(slice, gutil.ComparatorString)
gtest.C(t, func(t *gtest.T) {
array.RemoveValues("a", "b", "c")
t.Assert(array.Slice(), g.SliceStr{"d"})
})
}
func TestSortedArray_UnmarshalValue(t *testing.T) {
type V struct {
Name string
@ -897,6 +908,33 @@ func TestSortedArray_UnmarshalValue(t *testing.T) {
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})
}
func TestSortedArray_Filter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
values := g.Slice{0, 1, 2, 3, 4, "", g.Slice{}}
array := garray.NewSortedArrayFromCopy(values, gutil.ComparatorInt)
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsNil(value)
}).Slice(), g.Slice{0, "", g.Slice{}, 1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedArrayFromCopy(g.Slice{nil, 1, 2, 3, 4, nil}, gutil.ComparatorInt)
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsNil(value)
}), g.Slice{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedArrayFrom(g.Slice{0, 1, 2, 3, 4, "", g.Slice{}}, gutil.ComparatorInt)
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsEmpty(value)
}), g.Slice{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedArrayFrom(g.Slice{1, 2, 3, 4}, gutil.ComparatorInt)
t.Assert(array.Filter(func(index int, value interface{}) bool {
return empty.IsEmpty(value)
}), g.Slice{1, 2, 3, 4})
})
}
func TestSortedArray_FilterNil(t *testing.T) {
gtest.C(t, func(t *gtest.T) {

View File

@ -12,6 +12,8 @@ import (
"testing"
"time"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -737,6 +739,15 @@ func TestSortedIntArray_RemoveValue(t *testing.T) {
})
}
func TestSortedIntArray_RemoveValues(t *testing.T) {
slice := g.SliceInt{10, 20, 30, 40}
array := garray.NewSortedIntArrayFrom(slice)
gtest.C(t, func(t *gtest.T) {
array.RemoveValues(10, 40, 20)
t.Assert(array.Slice(), g.SliceInt{30})
})
}
func TestSortedIntArray_UnmarshalValue(t *testing.T) {
type V struct {
Name string
@ -765,6 +776,20 @@ func TestSortedIntArray_UnmarshalValue(t *testing.T) {
t.Assert(v.Array.Slice(), g.Slice{1, 2, 3})
})
}
func TestSortedIntArray_Filter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedIntArrayFrom(g.SliceInt{0, 1, 2, 3, 4, 0})
t.Assert(array.Filter(func(index int, value int) bool {
return empty.IsEmpty(value)
}), g.SliceInt{1, 2, 3, 4})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedIntArrayFrom(g.SliceInt{1, 2, 3, 4})
t.Assert(array.Filter(func(index int, value int) bool {
return empty.IsEmpty(value)
}), g.SliceInt{1, 2, 3, 4})
})
}
func TestSortedIntArray_FilterEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {

View File

@ -12,6 +12,8 @@ import (
"testing"
"time"
"github.com/gogf/gf/v2/internal/empty"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/internal/json"
@ -749,6 +751,15 @@ func TestSortedStrArray_RemoveValue(t *testing.T) {
})
}
func TestSortedStrArray_RemoveValues(t *testing.T) {
slice := g.SliceStr{"a", "b", "d", "c"}
array := garray.NewSortedStrArrayFrom(slice)
gtest.C(t, func(t *gtest.T) {
array.RemoveValues("a", "b", "c")
t.Assert(array.Slice(), g.SliceStr{"d"})
})
}
func TestSortedStrArray_UnmarshalValue(t *testing.T) {
type V struct {
Name string
@ -777,6 +788,20 @@ func TestSortedStrArray_UnmarshalValue(t *testing.T) {
t.Assert(v.Array.Slice(), g.SliceStr{"1", "2", "3"})
})
}
func TestSortedStrArray_Filter(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedStrArrayFrom(g.SliceStr{"", "1", "2", "0"})
t.Assert(array.Filter(func(index int, value string) bool {
return empty.IsEmpty(value)
}), g.SliceStr{"0", "1", "2"})
})
gtest.C(t, func(t *gtest.T) {
array := garray.NewSortedStrArrayFrom(g.SliceStr{"1", "2"})
t.Assert(array.Filter(func(index int, value string) bool {
return empty.IsEmpty(value)
}), g.SliceStr{"1", "2"})
})
}
func TestSortedStrArray_FilterEmpty(t *testing.T) {
gtest.C(t, func(t *gtest.T) {

View File

@ -514,3 +514,24 @@ func (m *AnyAnyMap) DeepCopy() interface{} {
}
return NewFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *AnyAnyMap) IsSubOf(other *AnyAnyMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -16,6 +16,7 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
// IntAnyMap implements map[int]interface{} with RWMutex that has switch.
type IntAnyMap struct {
mu rwmutex.RWMutex
data map[int]interface{}
@ -514,3 +515,24 @@ func (m *IntAnyMap) DeepCopy() interface{} {
}
return NewIntAnyMapFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *IntAnyMap) IsSubOf(other *IntAnyMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -13,6 +13,7 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
// IntIntMap implements map[int]int with RWMutex that has switch.
type IntIntMap struct {
mu rwmutex.RWMutex
data map[int]int
@ -484,3 +485,24 @@ func (m *IntIntMap) DeepCopy() interface{} {
}
return NewIntIntMapFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *IntIntMap) IsSubOf(other *IntIntMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -13,6 +13,7 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
// IntStrMap implements map[int]string with RWMutex that has switch.
type IntStrMap struct {
mu rwmutex.RWMutex
data map[int]string
@ -484,3 +485,24 @@ func (m *IntStrMap) DeepCopy() interface{} {
}
return NewIntStrMapFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *IntStrMap) IsSubOf(other *IntStrMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -501,3 +501,24 @@ func (m *StrAnyMap) DeepCopy() interface{} {
}
return NewStrAnyMapFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *StrAnyMap) IsSubOf(other *StrAnyMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -14,6 +14,7 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
// StrIntMap implements map[string]int with RWMutex that has switch.
type StrIntMap struct {
mu rwmutex.RWMutex
data map[string]int
@ -488,3 +489,24 @@ func (m *StrIntMap) DeepCopy() interface{} {
}
return NewStrIntMapFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *StrIntMap) IsSubOf(other *StrIntMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -14,6 +14,7 @@ import (
"github.com/gogf/gf/v2/util/gconv"
)
// StrStrMap implements map[string]string with RWMutex that has switch.
type StrStrMap struct {
mu rwmutex.RWMutex
data map[string]string
@ -477,3 +478,24 @@ func (m *StrStrMap) DeepCopy() interface{} {
}
return NewStrStrMapFrom(data, m.mu.IsSafe())
}
// IsSubOf checks whether the current map is a sub-map of `other`.
func (m *StrStrMap) IsSubOf(other *StrStrMap) bool {
if m == other {
return true
}
m.mu.RLock()
defer m.mu.RUnlock()
other.mu.RLock()
defer other.mu.RUnlock()
for key, value := range m.data {
otherValue, ok := other.data[key]
if !ok {
return false
}
if otherValue != value {
return false
}
}
return true
}

View File

@ -391,3 +391,18 @@ func Test_AnyAnyMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get("k1"), n.Get("k1"))
})
}
func Test_AnyAnyMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
"k1": "v1",
"k2": "v2",
})
m2 := gmap.NewAnyAnyMapFrom(g.MapAnyAny{
"k2": "v2",
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -375,3 +375,18 @@ func Test_IntAnyMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get(1), n.Get(1))
})
}
func Test_IntAnyMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
1: "v1",
2: "v2",
})
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
2: "v2",
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -383,3 +383,18 @@ func Test_IntIntMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get(1), n.Get(1))
})
}
func Test_IntIntMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewIntAnyMapFrom(g.MapIntAny{
1: 1,
2: 2,
})
m2 := gmap.NewIntAnyMapFrom(g.MapIntAny{
2: 2,
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -447,3 +447,18 @@ func Test_IntStrMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get(1), n.Get(1))
})
}
func Test_IntStrMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewIntStrMapFrom(g.MapIntStr{
1: "v1",
2: "v2",
})
m2 := gmap.NewIntStrMapFrom(g.MapIntStr{
2: "v2",
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -381,3 +381,18 @@ func Test_StrAnyMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get("key1"), n.Get("key1"))
})
}
func Test_StrAnyMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewStrAnyMapFrom(g.MapStrAny{
"k1": "v1",
"k2": "v2",
})
m2 := gmap.NewStrAnyMapFrom(g.MapStrAny{
"k2": "v2",
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -389,3 +389,18 @@ func Test_StrIntMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get("key1"), n.Get("key1"))
})
}
func Test_StrIntMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewStrIntMapFrom(g.MapStrInt{
"k1": 1,
"k2": 2,
})
m2 := gmap.NewStrIntMapFrom(g.MapStrInt{
"k2": 2,
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -388,3 +388,18 @@ func Test_StrStrMap_DeepCopy(t *testing.T) {
t.AssertNE(m.Get("key1"), n.Get("key1"))
})
}
func Test_StrStrMap_IsSubOf(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
m1 := gmap.NewStrStrMapFrom(g.MapStrStr{
"k1": "v1",
"k2": "v2",
})
m2 := gmap.NewStrStrMapFrom(g.MapStrStr{
"k2": "v2",
})
t.Assert(m1.IsSubOf(m2), false)
t.Assert(m2.IsSubOf(m1), true)
t.Assert(m2.IsSubOf(m2), true)
})
}

View File

@ -84,6 +84,13 @@ func (p *Pool) Put(value interface{}) error {
return nil
}
// MustPut puts an item to pool, it panics if any error occurs.
func (p *Pool) MustPut(value interface{}) {
if err := p.Put(value); err != nil {
panic(err)
}
}
// Clear clears pool, which means it will remove all items from pool.
func (p *Pool) Clear() {
if p.ExpireFunc != nil {

View File

@ -61,7 +61,7 @@ func ExamplePool_Put() {
// conn.(*DBConn).Conn.QueryContext(context.Background(), "select * from user")
// put back conn
dbConnPool.Put(conn)
dbConnPool.MustPut(conn)
fmt.Println(conn.(*DBConn).Limit)
@ -88,8 +88,8 @@ func ExamplePool_Clear() {
})
conn, _ := dbConnPool.Get()
dbConnPool.Put(conn)
dbConnPool.Put(conn)
dbConnPool.MustPut(conn)
dbConnPool.MustPut(conn)
fmt.Println(dbConnPool.Size())
dbConnPool.Clear()
fmt.Println(dbConnPool.Size())
@ -144,8 +144,8 @@ func ExamplePool_Size() {
conn, _ := dbConnPool.Get()
fmt.Println(dbConnPool.Size())
dbConnPool.Put(conn)
dbConnPool.Put(conn)
dbConnPool.MustPut(conn)
dbConnPool.MustPut(conn)
fmt.Println(dbConnPool.Size())
// Output:
@ -158,27 +158,28 @@ func ExamplePool_Close() {
Conn *sql.Conn
Limit int
}
dbConnPool := gpool.New(time.Hour,
func() (interface{}, error) {
var (
newFunc = func() (interface{}, error) {
dbConn := new(DBConn)
dbConn.Limit = 10
return dbConn, nil
},
func(i interface{}) {
}
closeFunc = func(i interface{}) {
fmt.Println("Close The Pool")
// sample : close db conn
// i.(DBConn).Conn.Close()
})
}
)
dbConnPool := gpool.New(time.Hour, newFunc, closeFunc)
conn, _ := dbConnPool.Get()
dbConnPool.Put(conn)
dbConnPool.MustPut(conn)
dbConnPool.Close()
// wait for pool close
time.Sleep(time.Second * 1)
// Output:
// May Output:
// Close The Pool
}

View File

@ -57,40 +57,6 @@ func New(limit ...int) *Queue {
return q
}
// asyncLoopFromListToChannel starts an asynchronous goroutine,
// which handles the data synchronization from list `q.list` to channel `q.C`.
func (q *Queue) asyncLoopFromListToChannel() {
defer func() {
if q.closed.Val() {
_ = recover()
}
}()
for !q.closed.Val() {
<-q.events
for !q.closed.Val() {
if length := q.list.Len(); length > 0 {
if length > defaultBatchSize {
length = defaultBatchSize
}
for _, v := range q.list.PopFronts(length) {
// When q.C is closed, it will panic here, especially q.C is being blocked for writing.
// If any error occurs here, it will be caught by recover and be ignored.
q.C <- v
}
} else {
break
}
}
// Clear q.events to remain just one event to do the next synchronization check.
for i := 0; i < len(q.events)-1; i++ {
<-q.events
}
}
// It should be here to close `q.C` if `q` is unlimited size.
// It's the sender's responsibility to close channel when it should be closed.
close(q.C)
}
// Push pushes the data `v` into the queue.
// Note that it would panic if Push is called after the queue is closed.
func (q *Queue) Push(v interface{}) {
@ -114,7 +80,9 @@ func (q *Queue) Pop() interface{} {
// Notice: It would notify all goroutines return immediately,
// which are being blocked reading using Pop method.
func (q *Queue) Close() {
q.closed.Set(true)
if !q.closed.Cas(false, true) {
return
}
if q.events != nil {
close(q.events)
}
@ -128,17 +96,49 @@ func (q *Queue) Close() {
}
// Len returns the length of the queue.
// Note that the result might not be accurate as there's an
// Note that the result might not be accurate if using unlimited queue size as there's an
// asynchronous channel reading the list constantly.
func (q *Queue) Len() (length int) {
if q.list != nil {
length += q.list.Len()
func (q *Queue) Len() (length int64) {
bufferedSize := int64(len(q.C))
if q.limit > 0 {
return bufferedSize
}
length += len(q.C)
return
return int64(q.list.Size()) + bufferedSize
}
// Size is alias of Len.
func (q *Queue) Size() int {
// Deprecated: use Len instead.
func (q *Queue) Size() int64 {
return q.Len()
}
// asyncLoopFromListToChannel starts an asynchronous goroutine,
// which handles the data synchronization from list `q.list` to channel `q.C`.
func (q *Queue) asyncLoopFromListToChannel() {
defer func() {
if q.closed.Val() {
_ = recover()
}
}()
for !q.closed.Val() {
<-q.events
for !q.closed.Val() {
if bufferLength := q.list.Len(); bufferLength > 0 {
// When q.C is closed, it will panic here, especially q.C is being blocked for writing.
// If any error occurs here, it will be caught by recover and be ignored.
for i := 0; i < bufferLength; i++ {
q.C <- q.list.PopFront()
}
} else {
break
}
}
// Clear q.events to remain just one event to do the next synchronization check.
for i := 0; i < len(q.events)-1; i++ {
<-q.events
}
}
// It should be here to close `q.C` if `q` is unlimited size.
// It's the sender's responsibility to close channel when it should be closed.
close(q.C)
}

View File

@ -18,14 +18,31 @@ import (
func TestQueue_Len(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
max := 100
for n := 10; n < max; n++ {
q1 := gqueue.New(max)
for i := 0; i < max; i++ {
var (
maxNum = 100
maxTries = 100
)
for n := 10; n < maxTries; n++ {
q1 := gqueue.New(maxNum)
for i := 0; i < maxNum; i++ {
q1.Push(i)
}
t.Assert(q1.Len(), max)
t.Assert(q1.Size(), max)
t.Assert(q1.Len(), maxNum)
t.Assert(q1.Size(), maxNum)
}
})
gtest.C(t, func(t *gtest.T) {
var (
maxNum = 100
maxTries = 100
)
for n := 10; n < maxTries; n++ {
q1 := gqueue.New()
for i := 0; i < maxNum; i++ {
q1.Push(i)
}
t.AssertLE(q1.Len(), maxNum)
t.AssertLE(q1.Size(), maxNum)
}
})
}
@ -71,3 +88,19 @@ func TestQueue_Close(t *testing.T) {
q1.Close()
})
}
func Test_Issue2509(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
q := gqueue.New()
q.Push(1)
q.Push(2)
q.Push(3)
t.AssertLE(q.Len(), 3)
t.Assert(<-q.C, 1)
t.AssertLE(q.Len(), 2)
t.Assert(<-q.C, 2)
t.AssertLE(q.Len(), 1)
t.Assert(<-q.C, 3)
t.Assert(q.Len(), 0)
})
}

View File

@ -184,7 +184,7 @@ func (set *Set) Clear() {
set.mu.Unlock()
}
// Slice returns the a of items of the set as slice.
// Slice returns the an of items of the set as slice.
func (set *Set) Slice() []interface{} {
set.mu.RLock()
var (

View File

@ -165,7 +165,7 @@ func (set *IntSet) Clear() {
set.mu.Unlock()
}
// Slice returns the a of items of the set as slice.
// Slice returns the an of items of the set as slice.
func (set *IntSet) Slice() []int {
set.mu.RLock()
var (

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