mirror of
https://gitee.com/johng/gf
synced 2026-06-06 02:25:47 +08:00
remove gf cli from basic framework
This commit is contained in:
5
go.mod
5
go.mod
@ -5,17 +5,20 @@ go 1.14
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.4.9
|
||||
github.com/gogf/gf/tool/gf v0.0.0-20210629161552-1e628b9edb8e // indirect
|
||||
github.com/gogf/mysql v1.6.1-0.20210603073548-16164ae25579
|
||||
github.com/gomodule/redigo v2.0.0+incompatible
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20200322061010-ea0c1cf2f119
|
||||
github.com/mattn/go-runewidth v0.0.10 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
go.opentelemetry.io/otel v1.0.0-RC1
|
||||
go.opentelemetry.io/otel/oteltest v1.0.0-RC1
|
||||
go.opentelemetry.io/otel/trace v1.0.0-RC1
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102
|
||||
golang.org/x/text v0.3.4
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
)
|
||||
|
||||
36
go.sum
36
go.sum
@ -2,53 +2,29 @@ github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
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.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||
github.com/gogf/gf v1.13.8-0.20201010060010-09ce105eeeab/go.mod h1:nGAMjE4ohU2bwj4Gk3h25K6rEkPZMDdvsmyifpFcuMQ=
|
||||
github.com/gogf/gf v1.16.1/go.mod h1:5eEgE9fWeRQW8dJE3GLpCy0KkNitXh6POesdJiBE/lw=
|
||||
github.com/gogf/gf/tool/gf v0.0.0-20210629161552-1e628b9edb8e h1:0yamWn3TAI/nFVDI9pwofWDekdMt4qQLwQdMmE59TNA=
|
||||
github.com/gogf/gf/tool/gf v0.0.0-20210629161552-1e628b9edb8e/go.mod h1:bCukUi4KQbIKZ4W5xLPKHe3eYparuvqfqBn8ZiYeCnY=
|
||||
github.com/gogf/mysql v1.6.1-0.20210603073548-16164ae25579 h1:pP/uEy52biKDytlgK/ug8kiYPAiYu6KajKVUHfGrtyw=
|
||||
github.com/gogf/mysql v1.6.1-0.20210603073548-16164ae25579/go.mod h1:52e6mXyNnHAsFrXrSnj5JPRSKsZKpHylVtA3j4AtMz8=
|
||||
github.com/gogf/swagger v1.0.4 h1:MILniFKPh52/26s+z8taSh8thn1tq2RaeWM7rYX1dRw=
|
||||
github.com/gogf/swagger v1.0.4/go.mod h1:4rD12TCoDz60jmgtuFnx7ZBWUM92tXc/qtrIrkBIp5Q=
|
||||
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/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gqcn/structs v1.1.1/go.mod h1:/aBhTBSsKQ2Ec9pbnYdGphtdWXHFn4KrCL0fXM/Adok=
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20200322061010-ea0c1cf2f119 h1:h3iGUlU8HyW4baKd6D+h1mwOHnM2kwskSuG6Bv4tSbc=
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20200322061010-ea0c1cf2f119/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
@ -56,43 +32,31 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg=
|
||||
go.opentelemetry.io/otel v1.0.0-RC1 h1:4CeoX93DNTWt8awGK9JmNXzF9j7TyOu9upscEdtcdXc=
|
||||
go.opentelemetry.io/otel v1.0.0-RC1/go.mod h1:x9tRa9HK4hSSq7jf2TKbqFbtt58/TGk0f9XiEYISI1I=
|
||||
go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc=
|
||||
go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA=
|
||||
go.opentelemetry.io/otel/oteltest v1.0.0-RC1 h1:G685iP3XiskCwk/z0eIabL55XUl2gk0cljhGk9sB0Yk=
|
||||
go.opentelemetry.io/otel/oteltest v1.0.0-RC1/go.mod h1:+eoIG0gdEOaPNftuy1YScLr1Gb4mL/9lpDkZ0JjMRq4=
|
||||
go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg=
|
||||
go.opentelemetry.io/otel/trace v1.0.0-RC1 h1:jrjqKJZEibFrDz+umEASeU3LvdVyWKlnTh7XEfwrT58=
|
||||
go.opentelemetry.io/otel/trace v1.0.0-RC1/go.mod h1:86UHmyHWFEtWjfWPSbu0+d0Pf9Q6e1U+3ViBOc+NXAg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
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/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
|
||||
@ -1,70 +0,0 @@
|
||||
# GoFrame CLI Tool
|
||||
|
||||
Powerful CLI tool for building [GoFrame](https://goframe.org) application with convenience.
|
||||
|
||||
## 1. Install
|
||||
|
||||
> You might need setting the goproxy to make through building.
|
||||
|
||||
1. Latest version
|
||||
|
||||
> Go version >= v1.16
|
||||
```
|
||||
go install github.com/gogf/gf/tool/gf@latest
|
||||
```
|
||||
> Go version <= v1.15
|
||||
```
|
||||
go install github.com/gogf/gf/tool/gf
|
||||
```
|
||||
|
||||
1. Specified version
|
||||
|
||||
> Go version >= v1.16
|
||||
```
|
||||
go install github.com/gogf/gf/tool/gf@v1.16.0
|
||||
```
|
||||
1. 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.
|
||||
|
||||
## 2. Commands
|
||||
```html
|
||||
$ gf
|
||||
USAGE
|
||||
gf COMMAND [ARGUMENT] [OPTION]
|
||||
|
||||
COMMAND
|
||||
env show current Golang environment variables
|
||||
get install or update GF to system in default...
|
||||
gen automatically generate go files for ORM models...
|
||||
mod extra features for go modules...
|
||||
run running go codes with hot-compiled-like feature...
|
||||
init initialize an empty GF project at current working directory...
|
||||
help show more information about a specified command
|
||||
pack packing any file/directory to a resource file, or a go file...
|
||||
build cross-building go project for lots of platforms...
|
||||
docker create a docker image for current GF project...
|
||||
swagger swagger feature for current project...
|
||||
update update current gf binary to latest one
|
||||
version show current binary version info
|
||||
|
||||
OPTION
|
||||
-y all yes for all command without prompt ask
|
||||
-?,-h show this help or detail for specified command
|
||||
-v,-i show version information
|
||||
|
||||
ADDITIONAL
|
||||
Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '...'
|
||||
in the tail of their comments.
|
||||
```
|
||||
|
||||
## 3. FAQ
|
||||
|
||||
### 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`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -1,31 +0,0 @@
|
||||
package boot
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/genv"
|
||||
_ "github.com/gogf/gf/tool/gf/packed"
|
||||
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Force using configuration file in current working directory.
|
||||
// In case of source environment.
|
||||
genv.Set("GF_GCFG_PATH", gfile.Pwd())
|
||||
handleZshAlias()
|
||||
}
|
||||
|
||||
// zsh alias "git fetch" conflicts checks.
|
||||
func handleZshAlias() {
|
||||
home, err := gfile.Home()
|
||||
if err == nil {
|
||||
zshPath := gfile.Join(home, ".zshrc")
|
||||
if gfile.Exists(zshPath) {
|
||||
aliasCommand := `alias gf=gf`
|
||||
content := gfile.GetContents(zshPath)
|
||||
if !gstr.Contains(content, aliasCommand) {
|
||||
_ = gfile.PutContentsAppend(zshPath, "\n"+aliasCommand+"\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,341 +0,0 @@
|
||||
package build
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/encoding/gbase64"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/gogf/gf/util/gutil"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// https://golang.google.cn/doc/install/source
|
||||
const platforms = `
|
||||
darwin amd64
|
||||
darwin arm64
|
||||
ios amd64
|
||||
ios arm64
|
||||
freebsd 386
|
||||
freebsd amd64
|
||||
freebsd arm
|
||||
linux 386
|
||||
linux amd64
|
||||
linux arm
|
||||
linux arm64
|
||||
linux ppc64
|
||||
linux ppc64le
|
||||
linux mips
|
||||
linux mipsle
|
||||
linux mips64
|
||||
linux mips64le
|
||||
netbsd 386
|
||||
netbsd amd64
|
||||
netbsd arm
|
||||
openbsd 386
|
||||
openbsd amd64
|
||||
openbsd arm
|
||||
windows 386
|
||||
windows amd64
|
||||
android arm
|
||||
dragonfly amd64
|
||||
plan9 386
|
||||
plan9 amd64
|
||||
solaris amd64
|
||||
`
|
||||
|
||||
const (
|
||||
nodeNameInConfigFile = "gfcli.build" // nodeNameInConfigFile is the node name for compiler configurations in configuration file.
|
||||
packedGoFileName = "build_pack_data.go" // packedGoFileName specifies the file name for packing common folders into one single go file.
|
||||
)
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf build FILE [OPTION]
|
||||
|
||||
ARGUMENT
|
||||
FILE building file path.
|
||||
|
||||
OPTION
|
||||
-n, --name output binary name
|
||||
-v, --version output binary version
|
||||
-a, --arch output binary architecture, multiple arch separated with ','
|
||||
-s, --system output binary system, multiple os separated with ','
|
||||
-o, --output output binary path, used when building single binary file
|
||||
-p, --path output binary directory path, default is './bin'
|
||||
-e, --extra extra custom "go build" options
|
||||
-m, --mod like "-mod" option of "go build", use "-m none" to disable go module
|
||||
-c, --cgo enable or disable cgo feature, it's disabled in default
|
||||
--pack pack specified folder into packed/data.go before building.
|
||||
--swagger auto parse and pack swagger into packed/swagger.go before building.
|
||||
|
||||
EXAMPLES
|
||||
gf build main.go
|
||||
gf build main.go --swagger
|
||||
gf build main.go --pack public,template
|
||||
gf build main.go --cgo
|
||||
gf build main.go -m none
|
||||
gf build main.go -n my-app -a all -s all
|
||||
gf build main.go -n my-app -a amd64,386 -s linux -p .
|
||||
gf build main.go -n my-app -v 1.0 -a amd64,386 -s linux,windows,darwin -p ./docker/bin
|
||||
|
||||
DESCRIPTION
|
||||
The "build" command is most commonly used command, which is designed as a powerful wrapper for
|
||||
"go build" command for convenience cross-compiling usage.
|
||||
It provides much more features for building binary:
|
||||
1. Cross-Compiling for many platforms and architectures.
|
||||
2. Configuration file support for compiling.
|
||||
3. Build-In Variables.
|
||||
|
||||
PLATFORMS
|
||||
darwin amd64,arm64
|
||||
freebsd 386,amd64,arm
|
||||
linux 386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le
|
||||
netbsd 386,amd64,arm
|
||||
openbsd 386,amd64,arm
|
||||
windows 386,amd64
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
mlog.SetHeaderPrint(true)
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"n,name": true,
|
||||
"v,version": true,
|
||||
"a,arch": true,
|
||||
"s,system": true,
|
||||
"o,output": true,
|
||||
"p,path": true,
|
||||
"e,extra": true,
|
||||
"m,mod": true,
|
||||
"pack": true,
|
||||
"c,cgo": false,
|
||||
"swagger": false,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
file := parser.GetArg(2)
|
||||
if len(file) < 1 {
|
||||
// Check and use the main.go file.
|
||||
if gfile.Exists("main.go") {
|
||||
file = "main.go"
|
||||
} else {
|
||||
mlog.Fatal("build file path cannot be empty")
|
||||
}
|
||||
}
|
||||
path := getOption(parser, "path", "./bin")
|
||||
name := getOption(parser, "name", gfile.Name(file))
|
||||
if len(name) < 1 || name == "*" {
|
||||
mlog.Fatal("name cannot be empty")
|
||||
}
|
||||
var (
|
||||
mod = getOption(parser, "mod")
|
||||
extra = getOption(parser, "extra")
|
||||
)
|
||||
if mod != "" && mod != "none" {
|
||||
mlog.Debugf(`mod is %s`, mod)
|
||||
if extra == "" {
|
||||
extra = fmt.Sprintf(`-mod=%s`, mod)
|
||||
} else {
|
||||
extra = fmt.Sprintf(`-mod=%s %s`, mod, extra)
|
||||
}
|
||||
}
|
||||
if extra != "" {
|
||||
extra += " "
|
||||
}
|
||||
var (
|
||||
cgoEnabled = gconv.Bool(getOption(parser, "cgo"))
|
||||
version = getOption(parser, "version")
|
||||
outputPath = getOption(parser, "output")
|
||||
archOption = getOption(parser, "arch")
|
||||
systemOption = getOption(parser, "system")
|
||||
packStr = getOption(parser, "pack")
|
||||
customSystems = gstr.SplitAndTrim(systemOption, ",")
|
||||
customArches = gstr.SplitAndTrim(archOption, ",")
|
||||
)
|
||||
if !cgoEnabled {
|
||||
cgoEnabled = parser.ContainsOpt("cgo")
|
||||
}
|
||||
if len(version) > 0 {
|
||||
path += "/" + version
|
||||
}
|
||||
// System and arch checks.
|
||||
var (
|
||||
spaceRegex = regexp.MustCompile(`\s+`)
|
||||
platformMap = make(map[string]map[string]bool)
|
||||
)
|
||||
for _, line := range strings.Split(strings.TrimSpace(platforms), "\n") {
|
||||
line = gstr.Trim(line)
|
||||
line = spaceRegex.ReplaceAllString(line, " ")
|
||||
var (
|
||||
array = strings.Split(line, " ")
|
||||
system = strings.TrimSpace(array[0])
|
||||
arch = strings.TrimSpace(array[1])
|
||||
)
|
||||
if platformMap[system] == nil {
|
||||
platformMap[system] = make(map[string]bool)
|
||||
}
|
||||
platformMap[system][arch] = true
|
||||
}
|
||||
// Auto swagger.
|
||||
if containsOption(parser, "swagger") {
|
||||
if err := gproc.ShellRun(`gf swagger`); err != nil {
|
||||
return
|
||||
}
|
||||
if gfile.Exists("swagger") {
|
||||
packCmd := fmt.Sprintf(`gf pack %s packed/%s`, "swagger", packedGoFileName)
|
||||
mlog.Print(packCmd)
|
||||
if err := gproc.ShellRun(packCmd); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Auto packing.
|
||||
if len(packStr) > 0 {
|
||||
dataFilePath := fmt.Sprintf(`packed/%s`, packedGoFileName)
|
||||
if !gfile.Exists(dataFilePath) {
|
||||
// Remove the go file that is automatically packed resource.
|
||||
defer func() {
|
||||
gfile.Remove(dataFilePath)
|
||||
mlog.Printf(`remove the automatically generated resource go file: %s`, dataFilePath)
|
||||
}()
|
||||
}
|
||||
packCmd := fmt.Sprintf(`gf pack %s %s`, packStr, dataFilePath)
|
||||
mlog.Print(packCmd)
|
||||
gproc.ShellRun(packCmd)
|
||||
}
|
||||
|
||||
// Injected information by building flags.
|
||||
ldFlags := fmt.Sprintf(`-X 'github.com/gogf/gf/os/gbuild.builtInVarStr=%v'`, getBuildInVarStr())
|
||||
|
||||
// start building
|
||||
mlog.Print("start building...")
|
||||
if cgoEnabled {
|
||||
genv.Set("CGO_ENABLED", "1")
|
||||
} else {
|
||||
genv.Set("CGO_ENABLED", "0")
|
||||
}
|
||||
var (
|
||||
cmd = ""
|
||||
ext = ""
|
||||
)
|
||||
for system, item := range platformMap {
|
||||
cmd = ""
|
||||
ext = ""
|
||||
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
|
||||
continue
|
||||
}
|
||||
for arch, _ := range item {
|
||||
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
|
||||
continue
|
||||
}
|
||||
if len(customSystems) == 0 && len(customArches) == 0 {
|
||||
if runtime.GOOS == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
// Single binary building, output the binary to current working folder.
|
||||
output := ""
|
||||
if len(outputPath) > 0 {
|
||||
output = "-o " + outputPath + ext
|
||||
} else {
|
||||
output = "-o " + name + ext
|
||||
}
|
||||
cmd = fmt.Sprintf(`go build %s -ldflags "%s" %s %s`, output, ldFlags, extra, file)
|
||||
} else {
|
||||
// Cross-building, output the compiled binary to specified path.
|
||||
if system == "windows" {
|
||||
ext = ".exe"
|
||||
}
|
||||
genv.Set("GOOS", system)
|
||||
genv.Set("GOARCH", arch)
|
||||
cmd = fmt.Sprintf(
|
||||
`go build -o %s/%s/%s%s -ldflags "%s" %s%s`,
|
||||
path, system+"_"+arch, name, ext, ldFlags, extra, file,
|
||||
)
|
||||
}
|
||||
// It's not necessary printing the complete command string.
|
||||
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
|
||||
mlog.Print(cmdShow)
|
||||
if _, err := gproc.ShellExec(cmd); err != nil {
|
||||
mlog.Printf("failed to build, os:%s, arch:%s", system, arch)
|
||||
}
|
||||
// single binary building.
|
||||
if len(customSystems) == 0 && len(customArches) == 0 {
|
||||
goto buildDone
|
||||
}
|
||||
}
|
||||
}
|
||||
buildDone:
|
||||
mlog.Print("done!")
|
||||
}
|
||||
|
||||
// getOption retrieves option value from parser and configuration file.
|
||||
// It returns the default value specified by parameter <value> is no value found.
|
||||
func getOption(parser *gcmd.Parser, name string, value ...string) (result string) {
|
||||
result = parser.GetOpt(name)
|
||||
if result == "" && g.Config().Available() {
|
||||
result = g.Config().GetString(nodeNameInConfigFile + "." + name)
|
||||
}
|
||||
if result == "" && len(value) > 0 {
|
||||
result = value[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// containsOption checks whether the command option or the configuration file containing
|
||||
// given option name.
|
||||
func containsOption(parser *gcmd.Parser, name string) bool {
|
||||
result := parser.ContainsOpt(name)
|
||||
if !result && g.Config().Available() {
|
||||
result = g.Config().Contains(nodeNameInConfigFile + "." + name)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getBuildInVarMapJson retrieves and returns the custom build-in variables in configuration
|
||||
// file as json.
|
||||
func getBuildInVarStr() string {
|
||||
buildInVarMap := g.Map{}
|
||||
if g.Config().Available() {
|
||||
configMap := g.Config().GetMap(nodeNameInConfigFile)
|
||||
if len(configMap) > 0 {
|
||||
_, v := gutil.MapPossibleItemByKey(configMap, "VarMap")
|
||||
if v != nil {
|
||||
buildInVarMap = gconv.Map(v)
|
||||
}
|
||||
}
|
||||
}
|
||||
buildInVarMap["builtGit"] = getGitCommit()
|
||||
buildInVarMap["builtTime"] = gtime.Now().String()
|
||||
b, err := json.Marshal(buildInVarMap)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
return gbase64.EncodeToString(b)
|
||||
}
|
||||
|
||||
// getGitCommit retrieves and returns the latest git commit hash string if present.
|
||||
func getGitCommit() string {
|
||||
if gproc.SearchBinary("git") == "" {
|
||||
return ""
|
||||
}
|
||||
if s, _ := gproc.ShellExec("git rev-list -1 HEAD"); s != "" {
|
||||
if !gstr.Contains(s, " ") && !gstr.Contains(s, "fatal") {
|
||||
return gstr.Trim(s)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
@ -1,99 +0,0 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf docker [FILE] [OPTION]
|
||||
|
||||
ARGUMENT
|
||||
FILE file path for "gf build", it's "main.go" in default.
|
||||
OPTION the same options as "docker build" except some options as follows defined
|
||||
|
||||
OPTION
|
||||
-p, --push auto push the docker image to docker registry if "-t" option passed
|
||||
|
||||
EXAMPLES
|
||||
gf docker
|
||||
gf docker -t hub.docker.com/john/image:tag
|
||||
gf docker -p -t hub.docker.com/john/image:tag
|
||||
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
|
||||
|
||||
DESCRIPTION
|
||||
The "docker" command builds the GF project to a docker images.
|
||||
It runs "gf build" firstly to compile the project to binary file.
|
||||
It then runs "docker build" command automatically to generate the docker image.
|
||||
You should have docker installed, and there must be a Dockerfile in the root of the project.
|
||||
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
var err error
|
||||
autoPush := false
|
||||
array := garray.NewStrArrayFromCopy(os.Args)
|
||||
index := array.Search("--push")
|
||||
if index < 0 {
|
||||
index = array.Search("-p")
|
||||
}
|
||||
if index != -1 {
|
||||
array.Remove(index)
|
||||
autoPush = true
|
||||
}
|
||||
file := "main.go"
|
||||
extraOptions := ""
|
||||
if array.Len() > 2 {
|
||||
v, _ := array.Get(2)
|
||||
if gfile.ExtName(v) == "go" {
|
||||
file, _ = array.Get(2)
|
||||
if array.Len() > 3 {
|
||||
extraOptions = strings.Join(array.SubSlice(3), " ")
|
||||
}
|
||||
} else {
|
||||
extraOptions = strings.Join(array.SubSlice(2), " ")
|
||||
}
|
||||
}
|
||||
// Binary build.
|
||||
err = gproc.ShellRun(fmt.Sprintf(`gf build %s -a amd64 -s linux`, file))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Docker build.
|
||||
err = gproc.ShellRun(fmt.Sprintf(`docker build . %s`, extraOptions))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// Docker push.
|
||||
if !autoPush {
|
||||
return
|
||||
}
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"t,tag": true,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
tag := parser.GetOpt("t")
|
||||
if tag == "" {
|
||||
return
|
||||
}
|
||||
err = gproc.ShellRun(fmt.Sprintf(`docker push %s`, tag))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
44
tool/gf/commands/env/env.go
vendored
44
tool/gf/commands/env/env.go
vendored
@ -1,44 +0,0 @@
|
||||
package env
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
)
|
||||
|
||||
func Run() {
|
||||
result, err := gproc.ShellExec("go env")
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
if result == "" {
|
||||
mlog.Fatal(`retrieving Golang environment variables failed, did you install Golang?`)
|
||||
}
|
||||
var (
|
||||
lines = gstr.Split(result, "\n")
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
)
|
||||
array := make([][]string, 0)
|
||||
for _, line := range lines {
|
||||
line = gstr.Trim(line)
|
||||
if line == "" {
|
||||
continue
|
||||
}
|
||||
if gstr.Pos(line, "set ") == 0 {
|
||||
line = line[4:]
|
||||
}
|
||||
match, _ := gregex.MatchString(`(.+?)=(.*)`, line)
|
||||
if len(match) < 3 {
|
||||
mlog.Fatalf(`invalid Golang environment variable: "%s"`, line)
|
||||
}
|
||||
array = append(array, []string{gstr.Trim(match[1]), gstr.Trim(match[2])})
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT})
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
mlog.Print(buffer.String())
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
package fix
|
||||
|
||||
import "github.com/gogf/gf/tool/gf/library/mlog"
|
||||
|
||||
func Run() {
|
||||
mlog.Print("this feature is not completed yet")
|
||||
}
|
||||
@ -1,54 +0,0 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
)
|
||||
|
||||
func Help() {
|
||||
switch gcmd.GetArg(2) {
|
||||
case "dao":
|
||||
HelpDao()
|
||||
|
||||
case "pb":
|
||||
HelpPb()
|
||||
|
||||
case "pbentity":
|
||||
HelpPbEntity()
|
||||
|
||||
default:
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf gen TYPE [OPTION]
|
||||
|
||||
TYPE
|
||||
dao generate dao and model files.
|
||||
pb parse proto files and generate protobuf go files.
|
||||
pbentity generate entity message files in protobuf3 format.
|
||||
|
||||
DESCRIPTION
|
||||
The "gen" command is designed for multiple generating purposes.
|
||||
It's currently supporting generating go files for ORM models, protobuf and protobuf entity files.
|
||||
Please use "gf gen dao -h" or "gf gen model -h" for specified type help.
|
||||
`))
|
||||
}
|
||||
}
|
||||
|
||||
func Run() {
|
||||
genType := gcmd.GetArg(2)
|
||||
if genType == "" {
|
||||
mlog.Print("generating type cannot be empty")
|
||||
return
|
||||
}
|
||||
switch genType {
|
||||
case "dao":
|
||||
doGenDao()
|
||||
|
||||
case "pb":
|
||||
doGenPb()
|
||||
|
||||
case "pbentity":
|
||||
doGenPbEntity()
|
||||
}
|
||||
}
|
||||
@ -1,699 +0,0 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"github.com/gogf/gf/tool/gf/library/utils"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"strings"
|
||||
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
_ "github.com/lib/pq"
|
||||
//_ "github.com/mattn/go-oci8"
|
||||
//_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// generateDaoReq is the input parameter for generating dao.
|
||||
type generateDaoReq struct {
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
PrefixName string // PrefixName specifies the custom prefix name for generated dao and model struct.
|
||||
GroupName string // GroupName specifies the group name of database configuration node for generated DAO.
|
||||
ModName string // ModName specifies the module name of current golang project, which is used for import purpose.
|
||||
JsonCase string // JsonCase specifies the case of generated 'json' tag for model struct, value from gstr.Case* function names.
|
||||
DirPath string // DirPath specifies the directory path for generated files.
|
||||
StdTime bool // StdTime defines using time.Time from stdlib instead of gtime.Time for generated time/date fields of tables.
|
||||
ModelIndexFileName string // Custom name for storing generated model content.
|
||||
TplDaoIndexPath string // TplDaoIndexPath specifies the file path for generating dao index files.
|
||||
TplDaoInternalPath string // TplDaoInternalPath specifies the file path for generating dao internal files.
|
||||
TplModelIndexPath string // TplModelIndexPath specifies the file path for generating model index content.
|
||||
TplModelStructPath string // TplModelStructPath specifies the file path for generating model struct content.
|
||||
}
|
||||
|
||||
const (
|
||||
genDaoDefaultPath = "./app"
|
||||
nodeNameGenDaoInConfigFile = "gfcli.gen.dao"
|
||||
defaultModelIndexFileName = "model.go"
|
||||
)
|
||||
|
||||
func HelpDao() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf gen dao [OPTION]
|
||||
|
||||
OPTION
|
||||
-/--path directory path for generated files.
|
||||
-l, --link database configuration, the same as the ORM configuration of GoFrame.
|
||||
-t, --tables generate models only for given tables, multiple table names separated with ','
|
||||
-e, --tablesEx generate models excluding given tables, multiple table names separated with ','
|
||||
-g, --group specifying the configuration group name of database for generated ORM instance,
|
||||
it's not necessary and the default value is "default"
|
||||
-p, --prefix add prefix for all table of specified link/database tables.
|
||||
-r, --removePrefix remove specified prefix of the table, multiple prefix separated with ','
|
||||
-m, --mod module name for generated golang file imports.
|
||||
-j, --jsonCase generated json tag case for model struct, cases are as follows:
|
||||
| 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 |
|
||||
-/--stdTime use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables.
|
||||
-/--modelFile custom file name for storing generated model content.
|
||||
-/--tplDaoIndex template content for Dao index files generating.
|
||||
-/--tplDaoInternal template content for Dao internal files generating.
|
||||
-/--tplModelIndex template content for Model index files generating.
|
||||
-/--tplModelStruct template content for Model internal files generating.
|
||||
|
||||
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.dao", which also supports multiple databases, for example:
|
||||
[gfcli]
|
||||
[[gfcli.gen.dao]]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
tables = "order,products"
|
||||
jsonCase = "CamelLower"
|
||||
[[gfcli.gen.dao]]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
|
||||
path = "./my-app"
|
||||
prefix = "primary_"
|
||||
tables = "user, userDetail"
|
||||
|
||||
EXAMPLES
|
||||
gf gen dao
|
||||
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen dao -path ./model -c config.yaml -g user-center -t user,user_detail,user_login
|
||||
gf gen dao -r user_
|
||||
`))
|
||||
}
|
||||
|
||||
// doGenDao implements the "gen dao" command.
|
||||
func doGenDao() {
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"path": true,
|
||||
"m,mod": true,
|
||||
"l,link": true,
|
||||
"t,tables": true,
|
||||
"e,tablesEx": true,
|
||||
"g,group": true,
|
||||
"c,config": true,
|
||||
"p,prefix": true,
|
||||
"r,removePrefix": true,
|
||||
"j,jsonCase": true,
|
||||
"stdTime": false,
|
||||
"modelFile": true,
|
||||
"tplDaoIndex": true,
|
||||
"tplDaoInternal": true,
|
||||
"tplModelIndex": true,
|
||||
"tplModelStruct": true,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
config := g.Cfg()
|
||||
if config.Available() {
|
||||
v := config.GetVar(nodeNameGenDaoInConfigFile)
|
||||
if v.IsEmpty() && g.IsEmpty(parser.GetOptAll()) {
|
||||
mlog.Fatal(`command arguments and configurations not found for generating dao files`)
|
||||
}
|
||||
if v.IsSlice() {
|
||||
for i := 0; i < len(v.Interfaces()); i++ {
|
||||
doGenDaoForArray(i, parser)
|
||||
}
|
||||
} else {
|
||||
doGenDaoForArray(-1, parser)
|
||||
}
|
||||
} else {
|
||||
doGenDaoForArray(-1, parser)
|
||||
}
|
||||
mlog.Print("done!")
|
||||
}
|
||||
|
||||
// doGenDaoForArray implements the "gen dao" command for configuration array.
|
||||
func doGenDaoForArray(index int, parser *gcmd.Parser) {
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
modName = getOptionOrConfigForDao(index, parser, "mod") // Go module name, eg: github.com/gogf/gf.
|
||||
dirPath = getOptionOrConfigForDao(index, parser, "path", genDaoDefaultPath) // Generated directory path.
|
||||
tablesStr = getOptionOrConfigForDao(index, parser, "tables") // Tables that will be generated.
|
||||
tablesEx = getOptionOrConfigForDao(index, parser, "tablesEx") // Tables that will be excluded for generating.
|
||||
prefixName = getOptionOrConfigForDao(index, parser, "prefix") // Add prefix to DAO and Model struct name.
|
||||
linkInfo = getOptionOrConfigForDao(index, parser, "link") // Custom database link.
|
||||
configPath = getOptionOrConfigForDao(index, parser, "config") // Config file path, eg: ./config/db.toml.
|
||||
configGroup = getOptionOrConfigForDao(index, parser, "group", "default") // Group name of database configuration node for generated DAO.
|
||||
removePrefix = getOptionOrConfigForDao(index, parser, "removePrefix") // Remove prefix from table name.
|
||||
jsonCase = getOptionOrConfigForDao(index, parser, "jsonCase", "CamelLower") // Case configuration for 'json' tag.
|
||||
stdTime = getOptionOrConfigForDao(index, parser, "stdTime", "false") // Use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables.
|
||||
modelFileName = getOptionOrConfigForDao(index, parser, "modelFile", defaultModelIndexFileName) // Custom file name for storing generated model content.
|
||||
tplDaoIndexPath = getOptionOrConfigForDao(index, parser, "tplDaoIndex") // Template file path for generating dao index files.
|
||||
tplDaoInternalPath = getOptionOrConfigForDao(index, parser, "tplDaoInternal") // Template file path for generating dao internal files.
|
||||
tplModelIndexPath = getOptionOrConfigForDao(index, parser, "tplModelIndex") // Template file path for generating model index files.
|
||||
tplModelStructPath = getOptionOrConfigForDao(index, parser, "tplModelStruct") // Template file path for generating model internal files.
|
||||
)
|
||||
if tplDaoIndexPath != "" && (!gfile.Exists(tplDaoIndexPath) || !gfile.IsReadable(tplDaoIndexPath)) {
|
||||
mlog.Fatalf("template file for dao index files generating does not exist or is not readable: %s", tplDaoIndexPath)
|
||||
}
|
||||
if tplDaoInternalPath != "" && (!gfile.Exists(tplDaoInternalPath) || !gfile.IsReadable(tplDaoInternalPath)) {
|
||||
mlog.Fatalf("template internal for dao internal files generating does not exist or is not readable: %s: %s", tplDaoInternalPath)
|
||||
}
|
||||
if tplModelIndexPath != "" && (!gfile.Exists(tplModelIndexPath) || !gfile.IsReadable(tplModelIndexPath)) {
|
||||
mlog.Fatalf("template file for model index files generating does not exist or is not readable: %s: %s", tplModelIndexPath)
|
||||
}
|
||||
if tplModelStructPath != "" && (!gfile.Exists(tplModelStructPath) || !gfile.IsReadable(tplModelStructPath)) {
|
||||
mlog.Fatalf("template file for model internal files generating does not exist or is not readable: %s: %s", tplModelStructPath)
|
||||
}
|
||||
// Make it compatible with old CLI version for option name: remove-prefix
|
||||
if removePrefix == "" {
|
||||
removePrefix = getOptionOrConfigForDao(index, parser, "remove-prefix")
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(removePrefix, ",")
|
||||
if modName == "" {
|
||||
if !gfile.Exists("go.mod") {
|
||||
mlog.Fatal("go.mod does not exist in current working directory")
|
||||
}
|
||||
var (
|
||||
goModContent = gfile.GetContents("go.mod")
|
||||
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
|
||||
)
|
||||
if len(match) > 1 {
|
||||
modName = gstr.Trim(match[1])
|
||||
} else {
|
||||
mlog.Fatal("module name does not found in go.mod")
|
||||
}
|
||||
}
|
||||
// It reads database configuration from project configuration file.
|
||||
if configPath != "" {
|
||||
path, err := gfile.Search(configPath)
|
||||
if err != nil {
|
||||
mlog.Fatalf("search configuration file '%s' failed: %v", configPath, err)
|
||||
}
|
||||
if err := g.Cfg().SetPath(gfile.Dir(path)); err != nil {
|
||||
mlog.Fatalf("set configuration path '%s' failed: %v", path, err)
|
||||
}
|
||||
g.Cfg().SetFileName(gfile.Basename(path))
|
||||
}
|
||||
// It uses user passed database configuration.
|
||||
if linkInfo != "" {
|
||||
tempGroup := gtime.TimestampNanoStr()
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, linkInfo)
|
||||
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(configGroup)
|
||||
}
|
||||
if db == nil {
|
||||
mlog.Fatal("database initialization failed")
|
||||
}
|
||||
|
||||
var tableNames []string
|
||||
if tablesStr != "" {
|
||||
tableNames = gstr.SplitAndTrim(tablesStr, ",")
|
||||
} else {
|
||||
tableNames, err = db.Tables(context.TODO())
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables failed: \n %v", err)
|
||||
}
|
||||
}
|
||||
// Table excluding.
|
||||
if tablesEx != "" {
|
||||
array := garray.NewStrArrayFrom(tableNames)
|
||||
for _, v := range gstr.SplitAndTrim(tablesEx, ",") {
|
||||
array.RemoveValue(v)
|
||||
}
|
||||
tableNames = array.Slice()
|
||||
}
|
||||
|
||||
// Generating dao & model go files one by one according to given table name.
|
||||
newTableNames := make([]string, len(tableNames))
|
||||
for i, tableName := range tableNames {
|
||||
newTableName := tableName
|
||||
for _, v := range removePrefixArray {
|
||||
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
|
||||
}
|
||||
newTableNames[i] = newTableName
|
||||
generateDaoContentFile(db, generateDaoReq{
|
||||
TableName: tableName,
|
||||
NewTableName: newTableName,
|
||||
PrefixName: prefixName,
|
||||
GroupName: configGroup,
|
||||
ModName: modName,
|
||||
JsonCase: jsonCase,
|
||||
DirPath: dirPath,
|
||||
StdTime: gconv.Bool(stdTime),
|
||||
TplDaoIndexPath: tplDaoIndexPath,
|
||||
TplDaoInternalPath: tplDaoInternalPath,
|
||||
TplModelIndexPath: tplModelIndexPath,
|
||||
TplModelStructPath: tplModelStructPath,
|
||||
})
|
||||
}
|
||||
generateDaoModelContentFile(db, tableNames, newTableNames, generateDaoReq{
|
||||
JsonCase: jsonCase,
|
||||
DirPath: dirPath,
|
||||
StdTime: gconv.Bool(stdTime),
|
||||
ModelIndexFileName: modelFileName,
|
||||
TplModelIndexPath: tplModelIndexPath,
|
||||
TplModelStructPath: tplModelStructPath,
|
||||
})
|
||||
}
|
||||
|
||||
// generateDaoContentFile generates the dao and model content of given table.
|
||||
func generateDaoContentFile(db gdb.DB, req generateDaoReq) {
|
||||
// Generating table data preparing.
|
||||
fieldMap, err := db.TableFields(context.TODO(), req.TableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", req.TableName, err)
|
||||
}
|
||||
// Change the `newTableName` if `prefixName` is given.
|
||||
newTableName := req.PrefixName + req.NewTableName
|
||||
var (
|
||||
dirPathDao = gstr.Trim(gfile.Join(req.DirPath, "dao"), "./")
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameCamelLowerCase = gstr.CaseCamelLower(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
importPrefix = ""
|
||||
dirRealPath = gfile.RealPath(req.DirPath)
|
||||
)
|
||||
if dirRealPath == "" {
|
||||
dirRealPath = req.DirPath
|
||||
importPrefix = dirRealPath
|
||||
importPrefix = gstr.Trim(dirRealPath, "./")
|
||||
} else {
|
||||
importPrefix = gstr.Replace(dirRealPath, gfile.Pwd(), "")
|
||||
}
|
||||
importPrefix = gstr.Replace(importPrefix, gfile.Separator, "/")
|
||||
importPrefix = gstr.Join(g.SliceStr{req.ModName, importPrefix}, "/")
|
||||
importPrefix, _ = gregex.ReplaceString(`\/{2,}`, `/`, gstr.Trim(importPrefix, "/"))
|
||||
|
||||
fileName := gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
if len(fileName) > 5 && fileName[len(fileName)-5:] == "_test" {
|
||||
// Add suffix to avoid the table name which contains "_test",
|
||||
// which would make the go file a testing file.
|
||||
fileName += "_table"
|
||||
}
|
||||
|
||||
// dao - index
|
||||
generateDaoIndex(tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName, req)
|
||||
|
||||
// dao - internal
|
||||
generateDaoInternal(tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName, fieldMap, req)
|
||||
}
|
||||
|
||||
func generateDaoModelContentFile(db gdb.DB, tableNames, newTableNames []string, req generateDaoReq) {
|
||||
var (
|
||||
modelContent string
|
||||
packageImports string
|
||||
dirPathModel = gstr.Trim(gfile.Join(req.DirPath, "model"), "./")
|
||||
)
|
||||
|
||||
// Model content.
|
||||
for i, tableName := range tableNames {
|
||||
fieldMap, err := db.TableFields(context.TODO(), tableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", req.TableName, err)
|
||||
}
|
||||
modelContent += generateDaoModelStructContent(
|
||||
tableName,
|
||||
gstr.CaseCamel(newTableNames[i]),
|
||||
req.TplModelStructPath,
|
||||
generateStructDefinitionForModel(gstr.CaseCamel(newTableNames[i]), fieldMap, req),
|
||||
)
|
||||
modelContent += "\n"
|
||||
}
|
||||
|
||||
// Time package recognition.
|
||||
if strings.Contains(modelContent, "gtime.Time") {
|
||||
packageImports = gstr.Trim(`
|
||||
import (
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
)`)
|
||||
} else if strings.Contains(modelContent, "time.Time") {
|
||||
packageImports = gstr.Trim(`
|
||||
import (
|
||||
"time"
|
||||
)`)
|
||||
} else {
|
||||
packageImports = ""
|
||||
}
|
||||
|
||||
// Generate and write content to golang file.
|
||||
modelContent = gstr.ReplaceByMap(getTplModelIndexContent(req.TplModelIndexPath), g.MapStrStr{
|
||||
"{TplPackageImports}": packageImports,
|
||||
"{TplModelStructs}": modelContent,
|
||||
})
|
||||
path := gfile.Join(dirPathModel, req.ModelIndexFileName)
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
utils.GoFmt(path)
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
|
||||
func generateDaoModelStructContent(tableName, tableNameCamelCase, tplModelStructPath, structDefine string) string {
|
||||
return gstr.ReplaceByMap(getTplModelStructContent(tplModelStructPath), g.MapStrStr{
|
||||
"{TplTableName}": tableName,
|
||||
"{TplTableNameCamelCase}": tableNameCamelCase,
|
||||
"{TplStructDefine}": structDefine,
|
||||
})
|
||||
}
|
||||
|
||||
func generateDaoIndex(tableNameCamelCase, tableNameCamelLowerCase, importPrefix, dirPathDao, fileName string, req generateDaoReq) {
|
||||
path := gfile.Join(dirPathDao, fileName+".go")
|
||||
if !gfile.Exists(path) {
|
||||
indexContent := gstr.ReplaceByMap(getTplDaoIndexContent(req.TplDaoIndexPath), g.MapStrStr{
|
||||
"{TplImportPrefix}": importPrefix,
|
||||
"{TplTableName}": req.TableName,
|
||||
"{TplTableNameCamelCase}": tableNameCamelCase,
|
||||
"{TplTableNameCamelLowerCase}": tableNameCamelLowerCase,
|
||||
})
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
utils.GoFmt(path)
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateDaoInternal(
|
||||
tableNameCamelCase, tableNameCamelLowerCase, importPrefix string,
|
||||
dirPathDao, fileName string,
|
||||
fieldMap map[string]*gdb.TableField,
|
||||
req generateDaoReq,
|
||||
) {
|
||||
path := gfile.Join(dirPathDao, "internal", fileName+".go")
|
||||
modelContent := gstr.ReplaceByMap(getTplDaoInternalContent(req.TplDaoInternalPath), g.MapStrStr{
|
||||
"{TplImportPrefix}": importPrefix,
|
||||
"{TplTableName}": req.TableName,
|
||||
"{TplGroupName}": req.GroupName,
|
||||
"{TplTableNameCamelCase}": tableNameCamelCase,
|
||||
"{TplTableNameCamelLowerCase}": tableNameCamelLowerCase,
|
||||
"{TplColumnDefine}": gstr.Trim(generateColumnDefinitionForDao(fieldMap)),
|
||||
"{TplColumnNames}": gstr.Trim(generateColumnNamesForDao(fieldMap)),
|
||||
})
|
||||
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
|
||||
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
|
||||
} else {
|
||||
utils.GoFmt(path)
|
||||
mlog.Print("generated:", path)
|
||||
}
|
||||
}
|
||||
|
||||
// generateStructDefinitionForModel generates and returns the struct definition for specified table.
|
||||
func generateStructDefinitionForModel(structName string, fieldMap map[string]*gdb.TableField, req generateDaoReq) string {
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
array := make([][]string, len(fieldMap))
|
||||
names := sortFieldKeyForDao(fieldMap)
|
||||
for index, name := range names {
|
||||
field := fieldMap[name]
|
||||
array[index] = generateStructFieldForModel(field, req)
|
||||
}
|
||||
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("type %s struct {\n", structName))
|
||||
buffer.WriteString(stContent)
|
||||
buffer.WriteString("}")
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateStructFieldForModel generates and returns the attribute definition for specified field.
|
||||
func generateStructFieldForModel(field *gdb.TableField, req generateDaoReq) []string {
|
||||
var typeName, ormTag, jsonTag 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 = "[]byte"
|
||||
|
||||
case "bit", "int", "int2", "tinyint", "small_int", "smallint", "medium_int", "mediumint", "serial":
|
||||
if gstr.ContainsI(field.Type, "unsigned") {
|
||||
typeName = "uint"
|
||||
} else {
|
||||
typeName = "int"
|
||||
}
|
||||
|
||||
case "int4", "int8", "big_int", "bigint", "bigserial":
|
||||
if gstr.ContainsI(field.Type, "unsigned") {
|
||||
typeName = "uint64"
|
||||
} else {
|
||||
typeName = "int64"
|
||||
}
|
||||
|
||||
case "real":
|
||||
typeName = "float32"
|
||||
|
||||
case "float", "double", "decimal", "smallmoney", "numeric":
|
||||
typeName = "float64"
|
||||
|
||||
case "bool":
|
||||
typeName = "bool"
|
||||
|
||||
case "datetime", "timestamp", "date", "time":
|
||||
if req.StdTime {
|
||||
typeName = "time.Time"
|
||||
} else {
|
||||
typeName = "*gtime.Time"
|
||||
}
|
||||
|
||||
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 = "float64"
|
||||
case strings.Contains(t, "bool"):
|
||||
typeName = "bool"
|
||||
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
|
||||
typeName = "[]byte"
|
||||
case strings.Contains(t, "date") || strings.Contains(t, "time"):
|
||||
if req.StdTime {
|
||||
typeName = "time.Time"
|
||||
} else {
|
||||
typeName = "*gtime.Time"
|
||||
}
|
||||
default:
|
||||
typeName = "string"
|
||||
}
|
||||
}
|
||||
ormTag = field.Name
|
||||
jsonTag = getJsonTagFromCase(field.Name, req.JsonCase)
|
||||
if gstr.ContainsI(field.Key, "pri") {
|
||||
ormTag += ",primary"
|
||||
}
|
||||
if gstr.ContainsI(field.Key, "uni") {
|
||||
ormTag += ",unique"
|
||||
}
|
||||
return []string{
|
||||
" #" + gstr.CaseCamel(field.Name),
|
||||
" #" + typeName,
|
||||
" #" + fmt.Sprintf("`"+`orm:"%s"`, ormTag),
|
||||
" #" + fmt.Sprintf(`json:"%s"`+"`", jsonTag),
|
||||
" #" + fmt.Sprintf(`// %s`, formatComment(field.Comment)),
|
||||
}
|
||||
}
|
||||
|
||||
// formatComment formats the comment string to fit the golang code without any lines.
|
||||
func formatComment(comment string) string {
|
||||
comment = gstr.ReplaceByArray(comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
})
|
||||
comment = gstr.Trim(comment)
|
||||
comment = gstr.Replace(comment, `\n`, " ")
|
||||
return comment
|
||||
}
|
||||
|
||||
// generateColumnDefinitionForDao generates and returns the column names definition for specified table.
|
||||
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForDao(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
field := fieldMap[name]
|
||||
comment := gstr.Trim(gstr.ReplaceByArray(field.Comment, g.SliceStr{
|
||||
"\n", " ",
|
||||
"\r", " ",
|
||||
}))
|
||||
array[index] = []string{
|
||||
" #" + gstr.CaseCamel(field.Name),
|
||||
" # " + "string",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
defineContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
defineContent = gstr.Replace(defineContent, " #", "")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(defineContent)
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// generateColumnNamesForDao generates and returns the column names assignment content of column struct
|
||||
// for specified table.
|
||||
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
|
||||
var (
|
||||
buffer = bytes.NewBuffer(nil)
|
||||
array = make([][]string, len(fieldMap))
|
||||
names = sortFieldKeyForDao(fieldMap)
|
||||
)
|
||||
for index, name := range names {
|
||||
field := fieldMap[name]
|
||||
array[index] = []string{
|
||||
" #" + gstr.CaseCamel(field.Name) + ":",
|
||||
fmt.Sprintf(` #"%s",`, field.Name),
|
||||
}
|
||||
}
|
||||
tw := tablewriter.NewWriter(buffer)
|
||||
tw.SetBorder(false)
|
||||
tw.SetRowLine(false)
|
||||
tw.SetAutoWrapText(false)
|
||||
tw.SetColumnSeparator("")
|
||||
tw.AppendBulk(array)
|
||||
tw.Render()
|
||||
namesContent := buffer.String()
|
||||
// Let's do this hack of table writer for indent!
|
||||
namesContent = gstr.Replace(namesContent, " #", "")
|
||||
buffer.Reset()
|
||||
buffer.WriteString(namesContent)
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
func getTplDaoIndexContent(tplDaoIndexPath string) string {
|
||||
if tplDaoIndexPath != "" {
|
||||
return gfile.GetContents(tplDaoIndexPath)
|
||||
}
|
||||
return templateDaoDaoIndexContent
|
||||
}
|
||||
|
||||
func getTplDaoInternalContent(tplDaoInternalPath string) string {
|
||||
if tplDaoInternalPath != "" {
|
||||
return gfile.GetContents(tplDaoInternalPath)
|
||||
}
|
||||
return templateDaoDaoInternalContent
|
||||
}
|
||||
|
||||
func getTplModelIndexContent(tplModelIndexPath string) string {
|
||||
if tplModelIndexPath != "" {
|
||||
return gfile.GetContents(tplModelIndexPath)
|
||||
}
|
||||
return templateDaoModelIndexContent
|
||||
}
|
||||
|
||||
func getTplModelStructContent(tplModelStructPath string) string {
|
||||
if tplModelStructPath != "" {
|
||||
return gfile.GetContents(tplModelStructPath)
|
||||
}
|
||||
return templateDaoModelStructContent
|
||||
}
|
||||
|
||||
// getJsonTagFromCase call gstr.Case* function to convert the s to specified case.
|
||||
func getJsonTagFromCase(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)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
func sortFieldKeyForDao(fieldMap map[string]*gdb.TableField) []string {
|
||||
names := make(map[int]string)
|
||||
for _, field := range fieldMap {
|
||||
names[field.Index] = field.Name
|
||||
}
|
||||
var (
|
||||
i = 0
|
||||
j = 0
|
||||
result = make([]string, len(names))
|
||||
)
|
||||
for {
|
||||
if len(names) == 0 {
|
||||
break
|
||||
}
|
||||
if val, ok := names[i]; ok {
|
||||
result[j] = val
|
||||
j++
|
||||
delete(names, i)
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// getOptionOrConfigForDao retrieves option value from parser and configuration file.
|
||||
// It returns the default value specified by parameter <value> is no value found.
|
||||
func getOptionOrConfigForDao(index int, parser *gcmd.Parser, name string, defaultValue ...string) (result string) {
|
||||
result = parser.GetOpt(name)
|
||||
if result == "" && g.Config().Available() {
|
||||
g.Cfg().SetViolenceCheck(true)
|
||||
if index >= 0 {
|
||||
result = g.Cfg().GetString(fmt.Sprintf(`%s.%d.%s`, nodeNameGenDaoInConfigFile, index, name))
|
||||
} else {
|
||||
result = g.Cfg().GetString(fmt.Sprintf(`%s.%s`, nodeNameGenDaoInConfigFile, name))
|
||||
}
|
||||
}
|
||||
if result == "" && len(defaultValue) > 0 {
|
||||
result = defaultValue[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -1,73 +0,0 @@
|
||||
package gen
|
||||
|
||||
const templateDaoDaoIndexContent = `
|
||||
// =================================================================================
|
||||
// This is auto-generated by GoFrame CLI tool only once. Fill this file as you wish.
|
||||
// =================================================================================
|
||||
|
||||
package dao
|
||||
|
||||
import (
|
||||
"{TplImportPrefix}/dao/internal"
|
||||
)
|
||||
|
||||
// {TplTableNameCamelLowerCase}Dao is the manager for logic model data accessing and custom defined data operations functions management.
|
||||
// You can define custom methods on it to extend its functionality as you wish.
|
||||
type {TplTableNameCamelLowerCase}Dao struct {
|
||||
*internal.{TplTableNameCamelCase}Dao
|
||||
}
|
||||
|
||||
var (
|
||||
// {TplTableNameCamelCase} is globally public accessible object for table {TplTableName} operations.
|
||||
{TplTableNameCamelCase} {TplTableNameCamelLowerCase}Dao
|
||||
)
|
||||
|
||||
func init() {
|
||||
{TplTableNameCamelCase} = {TplTableNameCamelLowerCase}Dao{
|
||||
internal.New{TplTableNameCamelCase}Dao(),
|
||||
}
|
||||
}
|
||||
|
||||
// Fill with you ideas below.
|
||||
|
||||
`
|
||||
|
||||
const templateDaoDaoInternalContent = `
|
||||
// ==========================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
package internal
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/frame/gmvc"
|
||||
)
|
||||
|
||||
// {TplTableNameCamelCase}Dao is the manager for logic model data accessing and custom defined data operations functions management.
|
||||
type {TplTableNameCamelCase}Dao struct {
|
||||
gmvc.M // M is the core and embedded struct that inherits all chaining operations from gdb.Model.
|
||||
C {TplTableNameCamelLowerCase}Columns // C is the short type for Columns, which contains all the column names of Table for convenient usage.
|
||||
DB gdb.DB // DB is the raw underlying database management object.
|
||||
Table string // Table is the underlying table name of the DAO.
|
||||
}
|
||||
|
||||
// {TplTableNameCamelCase}Columns defines and stores column names for table {TplTableName}.
|
||||
type {TplTableNameCamelLowerCase}Columns struct {
|
||||
{TplColumnDefine}
|
||||
}
|
||||
|
||||
// New{TplTableNameCamelCase}Dao creates and returns a new DAO object for table data access.
|
||||
func New{TplTableNameCamelCase}Dao() *{TplTableNameCamelCase}Dao {
|
||||
columns := {TplTableNameCamelLowerCase}Columns{
|
||||
{TplColumnNames}
|
||||
}
|
||||
return &{TplTableNameCamelCase}Dao{
|
||||
C: columns,
|
||||
M: g.DB("{TplGroupName}").Model("{TplTableName}").Safe(),
|
||||
DB: g.DB("{TplGroupName}"),
|
||||
Table: "{TplTableName}",
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -1,18 +0,0 @@
|
||||
package gen
|
||||
|
||||
const templateDaoModelIndexContent = `
|
||||
// =================================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// =================================================================================
|
||||
|
||||
package model
|
||||
|
||||
{TplPackageImports}
|
||||
|
||||
{TplModelStructs}
|
||||
`
|
||||
|
||||
const templateDaoModelStructContent = `
|
||||
// {TplTableNameCamelCase} is the golang structure for table {TplTableName}.
|
||||
{TplStructDefine}
|
||||
`
|
||||
@ -1,77 +0,0 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gset"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
)
|
||||
|
||||
func HelpPb() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf gen pb
|
||||
|
||||
`))
|
||||
}
|
||||
|
||||
// doGenPb parses current `proto` files in folder `protocol` and generates `pb` files to `protobuf`.
|
||||
func doGenPb() {
|
||||
// protoc search.
|
||||
protocBinPath := gproc.SearchBinary("protoc")
|
||||
if protocBinPath == "" {
|
||||
mlog.Fatal(`"protoc" command not found, install it first to proceed proto files parsing`)
|
||||
}
|
||||
// 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"), "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(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/os/gtime"`,
|
||||
// })
|
||||
// _ = gfile.PutContents(path, content)
|
||||
// utils.GoFmt(path)
|
||||
// return path
|
||||
//})
|
||||
mlog.Print("done!")
|
||||
}
|
||||
@ -1,447 +0,0 @@
|
||||
package gen
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
_ "github.com/denisenkom/go-mssqldb"
|
||||
"github.com/gogf/gf/database/gdb"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"github.com/gogf/gf/util/gconv"
|
||||
_ "github.com/lib/pq"
|
||||
//_ "github.com/mattn/go-oci8"
|
||||
//_ "github.com/mattn/go-sqlite3"
|
||||
"github.com/olekukonko/tablewriter"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// generatePbEntityReq is the input parameter for generating entity protobuf files.
|
||||
type generatePbEntityReq struct {
|
||||
TableName string // TableName specifies the table name of the table.
|
||||
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
|
||||
PrefixName string // PrefixName specifies the custom prefix name for generated protobuf entity.
|
||||
GroupName string // GroupName specifies the group name of database configuration node for generated protobuf entity.
|
||||
PkgName string // PkgName specifies package name for generated protobuf.
|
||||
NameCase string // NameCase specifies the case of generated attribute name for entity message, value from gstr.Case* function names.
|
||||
JsonCase string // JsonCase specifies the case of json tag for attribute name of entity message, value from gstr.Case* function names.
|
||||
DirPath string // DirPath specifies the directory path for generated files.
|
||||
OptionContent string // OptionContent specifies the extra option configuration content for protobuf.
|
||||
TplEntityPath string // TplEntityPath specifies the file path for generating protobuf entity files.
|
||||
}
|
||||
|
||||
const (
|
||||
nodeNameGenPbEntityInConfigFile = "gfcli.gen.pbentity"
|
||||
)
|
||||
|
||||
func HelpPbEntity() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf gen pbentity [OPTION]
|
||||
|
||||
OPTION
|
||||
-/--path directory path for generated files.
|
||||
-/--package package name for all entity proto files.
|
||||
-l, --link database configuration, the same as the ORM configuration of GoFrame.
|
||||
-t, --tables generate models only for given tables, multiple table names separated with ','
|
||||
-c, --config used to specify the configuration file for database, it's commonly not necessary.
|
||||
If "-l" is not passed, it will search "./config.toml" and "./config/config.toml"
|
||||
in current working directory in default.
|
||||
-p, --prefix add specified prefix for all entity names and entity proto files.
|
||||
-r, --removePrefix remove specified prefix of the table, multiple prefix separated with ','
|
||||
-n, --nameCase case for message attribute names, default is "Camel":
|
||||
| Case | Example |
|
||||
|---------------- |--------------------|
|
||||
| Camel | AnyKindOfString | default
|
||||
| CamelLower | anyKindOfString |
|
||||
| Snake | any_kind_of_string |
|
||||
| SnakeScreaming | ANY_KIND_OF_STRING |
|
||||
| SnakeFirstUpper | rgb_code_md5 |
|
||||
| Kebab | any-kind-of-string |
|
||||
| KebabScreaming | ANY-KIND-OF-STRING |
|
||||
-j, --jsonCase case for message json tag, cases are the same as "nameCase", default "CamelLower".
|
||||
set it to "none" to ignore json tag generating.
|
||||
-o, --option extra protobuf options.
|
||||
-/--tplEntity template content for protobuf entity files generating.
|
||||
|
||||
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:
|
||||
[gfcli]
|
||||
[[gfcli.gen.pbentity]]
|
||||
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
path = "protocol/demos/entity"
|
||||
tables = "order,products"
|
||||
package = "demos"
|
||||
[[gfcli.gen.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";
|
||||
"""
|
||||
|
||||
EXAMPLES
|
||||
gf gen pbentity
|
||||
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
|
||||
gf gen pbentity -path ./protocol/demos/entity -c config.yaml -g user-center -t user,user_detail,user_login
|
||||
gf gen pbentity -r user_
|
||||
`))
|
||||
}
|
||||
|
||||
// doGenPbEntity implements the "gen pbentity" command.
|
||||
func doGenPbEntity() {
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"path": true,
|
||||
"package": true,
|
||||
"l,link": true,
|
||||
"t,tables": true,
|
||||
"c,config": true,
|
||||
"p,prefix": true,
|
||||
"r,removePrefix": true,
|
||||
"o,option": true,
|
||||
"n,nameCase": true,
|
||||
"j,jsonCase": true,
|
||||
"tplEntity": true,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
config := g.Cfg()
|
||||
if config.Available() {
|
||||
v := config.GetVar(nodeNameGenPbEntityInConfigFile)
|
||||
if v.IsEmpty() && g.IsEmpty(parser.GetOptAll()) {
|
||||
mlog.Fatal(`command arguments and configurations not found for generating protobuf entity files`)
|
||||
}
|
||||
if v.IsSlice() {
|
||||
for i := 0; i < len(v.Interfaces()); i++ {
|
||||
doGenPbEntityForArray(i, parser)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(-1, parser)
|
||||
}
|
||||
} else {
|
||||
doGenPbEntityForArray(-1, parser)
|
||||
}
|
||||
mlog.Print("done!")
|
||||
}
|
||||
|
||||
// doGenPbEntityForArray implements the "gen pbentity" command for configuration array.
|
||||
func doGenPbEntityForArray(index int, parser *gcmd.Parser) {
|
||||
var (
|
||||
err error
|
||||
db gdb.DB
|
||||
dirPath = getOptionOrConfigForPbEntity(index, parser, "path") // Generated directory path.
|
||||
pkgName = getOptionOrConfigForPbEntity(index, parser, "package") // Package name for protobuf.
|
||||
tablesStr = getOptionOrConfigForPbEntity(index, parser, "tables") // Tables that will be generated.
|
||||
prefixName = getOptionOrConfigForPbEntity(index, parser, "prefix") // Add prefix to entity name.
|
||||
linkInfo = getOptionOrConfigForPbEntity(index, parser, "link") // Custom database link.
|
||||
configPath = getOptionOrConfigForPbEntity(index, parser, "config") // Config file path, eg: ./config/db.toml.
|
||||
configGroup = getOptionOrConfigForPbEntity(index, parser, "group", "default") // Group name of database configuration node for generated protobuf entity.
|
||||
removePrefix = getOptionOrConfigForPbEntity(index, parser, "removePrefix") // Remove prefix from table name.
|
||||
nameCase = getOptionOrConfigForPbEntity(index, parser, "nameCase", "Camel") // Case configuration for message name.
|
||||
jsonCase = getOptionOrConfigForPbEntity(index, parser, "jsonCase", "CamelLower") // Case configuration for message json tag.
|
||||
optionContent = getOptionOrConfigForPbEntity(index, parser, "option") // Option content for protobuf.
|
||||
tplEntityPath = getOptionOrConfigForPbEntity(index, parser, "tplEntity") // Specifies the file path for generating protobuf entity files.
|
||||
)
|
||||
if tplEntityPath != "" && (!gfile.Exists(tplEntityPath) || !gfile.IsReadable(tplEntityPath)) {
|
||||
mlog.Fatalf("template file for entity files generating does not exist or is not readable: %s", tplEntityPath)
|
||||
}
|
||||
// Make it compatible with old CLI version for option name: remove-prefix
|
||||
if removePrefix == "" {
|
||||
removePrefix = getOptionOrConfigForPbEntity(index, parser, "remove-prefix")
|
||||
}
|
||||
removePrefixArray := gstr.SplitAndTrim(removePrefix, ",")
|
||||
if pkgName == "" {
|
||||
mlog.Fatal("package name should not be empty")
|
||||
}
|
||||
// It reads database configuration from project configuration file.
|
||||
if configPath != "" {
|
||||
path, err := gfile.Search(configPath)
|
||||
if err != nil {
|
||||
mlog.Fatalf("search configuration file '%s' failed: %v", configPath, err)
|
||||
}
|
||||
if err := g.Cfg().SetPath(gfile.Dir(path)); err != nil {
|
||||
mlog.Fatalf("set configuration path '%s' failed: %v", path, err)
|
||||
}
|
||||
g.Cfg().SetFileName(gfile.Basename(path))
|
||||
}
|
||||
// It uses user passed database configuration.
|
||||
if linkInfo != "" {
|
||||
tempGroup := gtime.TimestampNanoStr()
|
||||
match, _ := gregex.MatchString(`([a-z]+):(.+)`, linkInfo)
|
||||
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(configGroup)
|
||||
}
|
||||
if db == nil {
|
||||
mlog.Fatal("database initialization failed")
|
||||
}
|
||||
|
||||
tableNames := ([]string)(nil)
|
||||
if tablesStr != "" {
|
||||
tableNames = gstr.SplitAndTrim(tablesStr, ",")
|
||||
} 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)
|
||||
}
|
||||
req := &generatePbEntityReq{
|
||||
TableName: tableName,
|
||||
NewTableName: newTableName,
|
||||
PrefixName: prefixName,
|
||||
GroupName: configGroup,
|
||||
PkgName: pkgName,
|
||||
NameCase: nameCase,
|
||||
JsonCase: jsonCase,
|
||||
DirPath: dirPath,
|
||||
OptionContent: gstr.Trim(optionContent),
|
||||
TplEntityPath: tplEntityPath,
|
||||
}
|
||||
generatePbEntityContentFile(db, req)
|
||||
}
|
||||
}
|
||||
|
||||
// generatePbEntityContentFile generates the protobuf files for given table.
|
||||
func generatePbEntityContentFile(db gdb.DB, req *generatePbEntityReq) {
|
||||
fieldMap, err := db.TableFields(db.GetCtx(), req.TableName)
|
||||
if err != nil {
|
||||
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", req.TableName, err)
|
||||
}
|
||||
// Change the `newTableName` if `prefixName` is given.
|
||||
newTableName := "Entity_" + req.PrefixName + req.NewTableName
|
||||
var (
|
||||
tableNameCamelCase = gstr.CaseCamel(newTableName)
|
||||
tableNameSnakeCase = gstr.CaseSnake(newTableName)
|
||||
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, req)
|
||||
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
|
||||
path = gfile.Join(req.DirPath, fileName+".proto")
|
||||
)
|
||||
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(req.TplEntityPath), g.MapStrStr{
|
||||
"{PackageName}": req.PkgName,
|
||||
"{OptionContent}": req.OptionContent,
|
||||
"{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(name string, fieldMap map[string]*gdb.TableField, req *generatePbEntityReq) 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], req)
|
||||
}
|
||||
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", name))
|
||||
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, req *generatePbEntityReq) []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, req.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, req.NameCase),
|
||||
" #= " + gconv.String(index) + jsonTagStr + ";",
|
||||
" #" + fmt.Sprintf(`// %s`, comment),
|
||||
}
|
||||
}
|
||||
|
||||
func getTplPbEntityContent(tplEntityPath string) string {
|
||||
if tplEntityPath != "" {
|
||||
return gfile.GetContents(tplEntityPath)
|
||||
}
|
||||
return 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
|
||||
}
|
||||
|
||||
// getOptionOrConfigForPbEntity retrieves option value from parser and configuration file.
|
||||
// It returns the default value specified by parameter <value> is no value found.
|
||||
func getOptionOrConfigForPbEntity(index int, parser *gcmd.Parser, name string, defaultValue ...string) (result string) {
|
||||
result = parser.GetOpt(name)
|
||||
if result == "" && g.Config().Available() {
|
||||
g.Cfg().SetViolenceCheck(true)
|
||||
if index >= 0 {
|
||||
result = g.Cfg().GetString(fmt.Sprintf(`%s.%d.%s`, nodeNameGenPbEntityInConfigFile, index, name))
|
||||
} else {
|
||||
result = g.Cfg().GetString(fmt.Sprintf(`%s.%s`, nodeNameGenPbEntityInConfigFile, name))
|
||||
}
|
||||
}
|
||||
if result == "" && len(defaultValue) > 0 {
|
||||
result = defaultValue[0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package gen
|
||||
|
||||
const templatePbEntityMessageContent = `
|
||||
// ==========================================================================
|
||||
// Code generated by GoFrame CLI tool. DO NOT EDIT.
|
||||
// ==========================================================================
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package {PackageName};
|
||||
|
||||
import "github.com/gogo/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
{OptionContent}
|
||||
|
||||
{EntityMessage}
|
||||
`
|
||||
@ -1,33 +0,0 @@
|
||||
package get
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"os"
|
||||
)
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf get PACKAGE
|
||||
|
||||
ARGUMENT
|
||||
PACKAGE remote golang package path, eg: github.com/gogf/gf
|
||||
|
||||
EXAMPLES
|
||||
gf get github.com/gogf/gf
|
||||
gf get github.com/gogf/gf@latest
|
||||
gf get github.com/gogf/gf@master
|
||||
gf get golang.org/x/sys
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
if len(os.Args) > 2 {
|
||||
gproc.ShellRun(fmt.Sprintf(`go get -u %s`, gstr.Join(os.Args[2:], " ")))
|
||||
} else {
|
||||
mlog.Fatal("please input the package path for get")
|
||||
}
|
||||
}
|
||||
@ -1,110 +0,0 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/encoding/gcompress"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/allyes"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
emptyProject = "github.com/gogf/gf-empty"
|
||||
emptyProjectName = "gf-empty"
|
||||
)
|
||||
|
||||
var (
|
||||
cdnUrl = g.Config("url").GetString("cdn.url")
|
||||
homeUrl = g.Config("url").GetString("home.url")
|
||||
)
|
||||
|
||||
func init() {
|
||||
if cdnUrl == "" {
|
||||
mlog.Fatal("CDN configuration cannot be empty")
|
||||
}
|
||||
if homeUrl == "" {
|
||||
mlog.Fatal("Home configuration cannot be empty")
|
||||
}
|
||||
}
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf init NAME
|
||||
|
||||
ARGUMENT
|
||||
NAME name for the project. It will create a folder with NAME in current directory.
|
||||
The NAME will also be the module name for the project.
|
||||
|
||||
EXAMPLES
|
||||
gf init my-app
|
||||
gf init my-project-name
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
parser, err := gcmd.Parse(nil)
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
projectName := parser.GetArg(2)
|
||||
if projectName == "" {
|
||||
mlog.Fatal("project name should not be empty")
|
||||
}
|
||||
dirPath := projectName
|
||||
if !gfile.IsEmpty(dirPath) && !allyes.Check() {
|
||||
s := gcmd.Scanf(`the folder "%s" is not empty, files might be overwrote, continue? [y/n]: `, projectName)
|
||||
if strings.EqualFold(s, "n") {
|
||||
return
|
||||
}
|
||||
}
|
||||
mlog.Print("initializing...")
|
||||
// MD5 retrieving.
|
||||
respMd5, err := g.Client().Get(homeUrl + "/cli/project/md5")
|
||||
if err != nil {
|
||||
mlog.Fatalf("get the project zip md5 failed: %s", err.Error())
|
||||
}
|
||||
if respMd5 == nil {
|
||||
mlog.Fatal("got the project zip md5 failed")
|
||||
}
|
||||
defer respMd5.Close()
|
||||
md5DataStr := respMd5.ReadAllString()
|
||||
if md5DataStr == "" {
|
||||
mlog.Fatal("get the project zip md5 failed: empty md5 value. maybe network issue, try again?")
|
||||
}
|
||||
|
||||
// Zip data retrieving.
|
||||
respData, err := g.Client().Get(cdnUrl + "/cli/project/zip?" + md5DataStr)
|
||||
if err != nil {
|
||||
mlog.Fatalf("got the project zip data failed: %s", err.Error())
|
||||
}
|
||||
if respData == nil {
|
||||
mlog.Fatal("got the project zip data failed")
|
||||
}
|
||||
defer respData.Close()
|
||||
zipData := respData.ReadAll()
|
||||
if len(zipData) == 0 {
|
||||
mlog.Fatal("get the project data failed: empty data value. maybe network issue, try again?")
|
||||
}
|
||||
// Current folder.
|
||||
replacedProjectName := projectName
|
||||
if replacedProjectName == "." {
|
||||
replacedProjectName = gfile.Name(gfile.RealPath("."))
|
||||
}
|
||||
// Unzip the zip data.
|
||||
if err = gcompress.UnZipContent(zipData, dirPath, emptyProjectName+"-master"); err != nil {
|
||||
mlog.Fatal("unzip project data failed,", err.Error())
|
||||
}
|
||||
// Replace project name.
|
||||
if err = gfile.ReplaceDir(emptyProject, replacedProjectName, dirPath, "Dockerfile,*.go,*.MD,*.mod", true); err != nil {
|
||||
mlog.Fatal("content replacing failed,", err.Error())
|
||||
}
|
||||
if err = gfile.ReplaceDir(emptyProjectName, replacedProjectName, dirPath, "Dockerfile,*.go,*.MD,*.mod", true); err != nil {
|
||||
mlog.Fatal("content replacing failed,", err.Error())
|
||||
}
|
||||
mlog.Print("initialization done! ")
|
||||
mlog.Print("you can now run 'gf run main.go' to start your journey, enjoy!")
|
||||
}
|
||||
@ -1,113 +0,0 @@
|
||||
package mod
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gmap"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
)
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf mod ARGUMENT
|
||||
|
||||
ARGUMENT
|
||||
path copy all packages with its latest version in Go modules, which does not exist
|
||||
in GOPATH, to GOPATH. This enables your project using GOPATH building, but you
|
||||
should have GOPATH environment variable configured.
|
||||
|
||||
EXAMPLES
|
||||
gf mod path
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
argument := gcmd.GetArg(2)
|
||||
switch argument {
|
||||
case "path":
|
||||
doPath()
|
||||
|
||||
default:
|
||||
mlog.Print("argument cannot be empty")
|
||||
Help()
|
||||
}
|
||||
}
|
||||
|
||||
// doPath copies all packages in Go modules, which does not exist in GOPATH, to GOPATH.
|
||||
// This enables your project using GOPATH building, but you should have GOPATH
|
||||
// environment variable configured.
|
||||
func doPath() {
|
||||
goPathEnv := genv.Get("GOPATH")
|
||||
if goPathEnv == "" {
|
||||
mlog.Fatal("GOPATH is not found in your environment")
|
||||
}
|
||||
mlog.Print("scanning...")
|
||||
var (
|
||||
copied = false
|
||||
haveCount = 0
|
||||
)
|
||||
for _, goPath := range gstr.SplitAndTrim(goPathEnv, ";") {
|
||||
goModPath := gfile.Join(goPath, "pkg", "mod")
|
||||
if !gfile.Exists(goModPath) {
|
||||
continue
|
||||
}
|
||||
pathMap := gmap.NewStrStrMap()
|
||||
_, err := gfile.ScanDirFunc(goModPath, "*.*", true, func(path string) string {
|
||||
// Ignore the cache folder.
|
||||
if gstr.Contains(path, gfile.Join(goModPath, "cache")) {
|
||||
return ""
|
||||
}
|
||||
name := gfile.Name(path)
|
||||
if name == "" {
|
||||
return ""
|
||||
}
|
||||
if !gstr.Contains(name, "@") {
|
||||
return ""
|
||||
}
|
||||
if n := gstr.Count(path, "@"); n > 1 {
|
||||
return ""
|
||||
}
|
||||
if !gfile.IsDir(path) {
|
||||
return ""
|
||||
}
|
||||
array := gstr.Split(path, "@")
|
||||
if v := pathMap.Get(array[0]); v == "" {
|
||||
pathMap.Set(array[0], array[1])
|
||||
} else {
|
||||
if gstr.CompareVersionGo(v, array[1]) < 0 {
|
||||
pathMap.Set(array[0], array[1])
|
||||
}
|
||||
}
|
||||
return path
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
haveCount += pathMap.Size()
|
||||
pathMap.Iterator(func(k string, v string) bool {
|
||||
src := fmt.Sprintf(`%s@%s`, k, v)
|
||||
dst := gfile.Join(goPath, "src", gstr.Trim(gstr.Replace(k, goModPath, ""), "\\/"))
|
||||
if !gfile.Exists(dst) {
|
||||
mlog.Printf(`copying %s to %s`, src, dst)
|
||||
if err := gfile.Copy(src, dst); err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
copied = true
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
if !copied {
|
||||
if haveCount > 0 {
|
||||
mlog.Print(`all packages of go modules already exist in GOPATH`)
|
||||
} else {
|
||||
mlog.Printf(`no packages found in go module path: %s`, goPathEnv)
|
||||
}
|
||||
return
|
||||
}
|
||||
mlog.Print("done!")
|
||||
}
|
||||
@ -1,80 +0,0 @@
|
||||
package pack
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gres"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/allyes"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf pack SRC DST
|
||||
|
||||
ARGUMENT
|
||||
SRC source path for packing, which can be multiple source paths.
|
||||
DST destination file path for packed file. if extension of the filename is ".go" and "-n" option is given,
|
||||
it enables packing SRC to go file, or else it packs SRC into a binary file.
|
||||
|
||||
OPTION
|
||||
-n, --name package name for output go file, it's set as its directory name if no name passed
|
||||
-p, --prefix prefix for each file packed into the resource file
|
||||
|
||||
EXAMPLES
|
||||
gf pack public data.bin
|
||||
gf pack public,template data.bin
|
||||
gf pack public,template packed/data.go
|
||||
gf pack public,template,config packed/data.go
|
||||
gf pack public,template,config packed/data.go -n=packed -p=/var/www/my-app
|
||||
gf pack /var/www/public packed/data.go -n=packed
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"n,name": true,
|
||||
"p,prefix": true,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
srcPath := parser.GetArg(2)
|
||||
dstPath := parser.GetArg(3)
|
||||
if srcPath == "" {
|
||||
mlog.Fatal("SRC path cannot be empty")
|
||||
}
|
||||
if dstPath == "" {
|
||||
mlog.Fatal("DST path cannot be empty")
|
||||
}
|
||||
if gfile.Exists(dstPath) && gfile.IsDir(dstPath) {
|
||||
mlog.Fatalf("DST path '%s' cannot be a directory", dstPath)
|
||||
}
|
||||
if !gfile.IsEmpty(dstPath) && !allyes.Check() {
|
||||
s := gcmd.Scanf("path '%s' is not empty, files might be overwrote, continue? [y/n]: ", dstPath)
|
||||
if strings.EqualFold(s, "n") {
|
||||
return
|
||||
}
|
||||
}
|
||||
var (
|
||||
name = parser.GetOpt("name")
|
||||
prefix = parser.GetOpt("prefix")
|
||||
)
|
||||
if name == "" && gfile.ExtName(dstPath) == "go" {
|
||||
name = gfile.Basename(gfile.Dir(dstPath))
|
||||
}
|
||||
if name != "" {
|
||||
if err := gres.PackToGoFile(srcPath, dstPath, name, prefix); err != nil {
|
||||
mlog.Fatalf("pack failed: %v", err)
|
||||
}
|
||||
} else {
|
||||
if err := gres.PackToFile(srcPath, dstPath, prefix); err != nil {
|
||||
mlog.Fatalf("pack failed: %v", err)
|
||||
}
|
||||
}
|
||||
mlog.Print("done!")
|
||||
}
|
||||
@ -1,212 +0,0 @@
|
||||
package run
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/garray"
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gfsnotify"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/os/gtimer"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/commands/swagger"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type App struct {
|
||||
File string // Go run file name/path.
|
||||
Options string // Extra "go run" options.
|
||||
Args string // Auto parse and pack swagger files.
|
||||
Swagger bool // Auto parse and pack swagger files.
|
||||
}
|
||||
|
||||
const (
|
||||
gPROXY_CHECK_TIMEOUT = time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
process *gproc.Process
|
||||
httpClient = ghttp.NewClient()
|
||||
)
|
||||
|
||||
func init() {
|
||||
httpClient.SetTimeout(gPROXY_CHECK_TIMEOUT)
|
||||
}
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf run FILE [OPTION]
|
||||
|
||||
ARGUMENT
|
||||
FILE building file path.
|
||||
OPTION the same options as "go run"/"go build" except some options as follows defined
|
||||
|
||||
OPTION
|
||||
-/--args custom process arguments.
|
||||
-/--swagger auto parse and pack swagger into packed/data-swagger.go before running.
|
||||
|
||||
EXAMPLES
|
||||
gf run main.go
|
||||
gf run main.go --swagger
|
||||
gf run main.go --args "server -p 8080"
|
||||
gf run main.go -mod=vendor
|
||||
|
||||
DESCRIPTION
|
||||
The "run" command is used for running go codes with hot-compiled-like feature,
|
||||
which compiles and runs the go codes asynchronously when codes change.
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"args": true,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
mlog.SetHeaderPrint(true)
|
||||
file := gcmd.GetArg(2)
|
||||
if len(file) < 1 {
|
||||
mlog.Fatal("file path cannot be empty")
|
||||
}
|
||||
app := &App{
|
||||
File: file,
|
||||
}
|
||||
// ================================================================================
|
||||
// This command is very special that it supports options of "go run" and "go build"
|
||||
// from the third parameter of os.Args. That means, we should filter any parameter
|
||||
// that "go run" and "go build" do not allow.
|
||||
// ================================================================================
|
||||
// Swagger checks.
|
||||
array := garray.NewStrArrayFrom(os.Args)
|
||||
index := array.Search("--swagger")
|
||||
if index < 0 {
|
||||
index = array.Search("-swagger")
|
||||
}
|
||||
if index != -1 {
|
||||
app.Swagger = true
|
||||
array.Remove(index)
|
||||
}
|
||||
// args checks.
|
||||
args := parser.GetOpt("args")
|
||||
if args != "" {
|
||||
app.Args = args
|
||||
index := -1
|
||||
array.Iterator(func(k int, v string) bool {
|
||||
if gstr.Contains(v, "-args") {
|
||||
index = k
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if index != -1 {
|
||||
v, _ := array.Get(index)
|
||||
if gstr.Contains(v, "=") {
|
||||
array.Remove(index)
|
||||
} else {
|
||||
array.Remove(index)
|
||||
array.Remove(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
// -y checks
|
||||
array.RemoveValue("-y")
|
||||
array.RemoveValue("--y")
|
||||
if array.Len() > 3 {
|
||||
app.Options = strings.Join(array.SubSlice(3), " ")
|
||||
}
|
||||
dirty := gtype.NewBool()
|
||||
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
|
||||
if gfile.ExtName(event.Path) != "go" {
|
||||
return
|
||||
}
|
||||
// Ignore swagger file.
|
||||
if gfile.Basename(event.Path) == "data-swagger.go" {
|
||||
return
|
||||
}
|
||||
// Variable <dirty> is used for running the changes only one in one second.
|
||||
if !dirty.Cas(false, true) {
|
||||
return
|
||||
}
|
||||
// With some delay in case of multiple code changes in very short interval.
|
||||
gtimer.SetTimeout(1500*gtime.MS, func() {
|
||||
defer dirty.Set(false)
|
||||
mlog.Printf(`go file changes: %s`, event.String())
|
||||
app.Run()
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
go app.Run()
|
||||
select {}
|
||||
}
|
||||
|
||||
func (app *App) Run() {
|
||||
// Rebuild and run the codes.
|
||||
renamePath := ""
|
||||
mlog.Printf("build: %s", app.File)
|
||||
outputPath := gfile.Join("bin", gfile.Name(app.File))
|
||||
if runtime.GOOS == "windows" {
|
||||
outputPath += ".exe"
|
||||
if gfile.Exists(outputPath) {
|
||||
renamePath = outputPath + "~"
|
||||
if err := gfile.Rename(outputPath, renamePath); err != nil {
|
||||
mlog.Print(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Auto swagger.
|
||||
if app.Swagger {
|
||||
if err := gproc.ShellRun(`gf swagger`); err != nil {
|
||||
return
|
||||
}
|
||||
if gfile.Exists("swagger") {
|
||||
packCmd := fmt.Sprintf(`gf pack %s packed/%s -n packed -y`, "swagger", swagger.PackedGoFileName)
|
||||
mlog.Print(packCmd)
|
||||
if err := gproc.ShellRun(packCmd); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
// In case of `pipe: too many open files` error.
|
||||
// Build the app.
|
||||
buildCommand := fmt.Sprintf(`go build -o %s %s %s`, outputPath, app.Options, app.File)
|
||||
mlog.Print(buildCommand)
|
||||
result, err := gproc.ShellExec(buildCommand)
|
||||
if err != nil {
|
||||
mlog.Printf("build error: \n%s%s", result, err.Error())
|
||||
return
|
||||
}
|
||||
// Kill the old process if build successfully.
|
||||
if process != nil {
|
||||
if err := process.Kill(); err != nil {
|
||||
mlog.Debugf("kill process error: %s", err.Error())
|
||||
//return
|
||||
}
|
||||
}
|
||||
// Run the binary file.
|
||||
runCommand := fmt.Sprintf(`%s %s`, outputPath, app.Args)
|
||||
mlog.Print(runCommand)
|
||||
if runtime.GOOS == "windows" {
|
||||
// Special handling for windows platform.
|
||||
// DO NOT USE "cmd /c" command.
|
||||
process = gproc.NewProcess(runCommand, nil)
|
||||
} else {
|
||||
process = gproc.NewProcessCmd(runCommand, nil)
|
||||
}
|
||||
if pid, err := process.Start(); err != nil {
|
||||
mlog.Printf("build running error: %s", err.Error())
|
||||
} else {
|
||||
mlog.Printf("build running pid: %d", pid)
|
||||
}
|
||||
}
|
||||
@ -1,154 +0,0 @@
|
||||
package swagger
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/container/gtype"
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/os/gfsnotify"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/os/gtime"
|
||||
"github.com/gogf/gf/os/gtimer"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"github.com/gogf/swagger"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultOutput = "./swagger"
|
||||
swaggoRepoPath = "github.com/swaggo/swag/cmd/swag"
|
||||
PackedGoFileName = "swagger.go"
|
||||
)
|
||||
|
||||
func Help() {
|
||||
mlog.Print(gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf swagger [OPTION]
|
||||
|
||||
OPTION
|
||||
-s, --server start a swagger server at specified address after swagger files
|
||||
produced
|
||||
-o, --output the output directory for storage parsed swagger files,
|
||||
the default output directory is "./swagger"
|
||||
-/--pack auto parses and packs swagger into packed/swagger.go.
|
||||
|
||||
EXAMPLES
|
||||
gf swagger
|
||||
gf swagger --pack
|
||||
gf swagger -s 8080
|
||||
gf swagger -s 127.0.0.1:8080
|
||||
gf swagger -o ./document/swagger
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
The "swagger" command parses the current project and produces swagger API description
|
||||
files, which can be used in swagger API server. If used with "-s/--server" option, it
|
||||
watches the changes of go files of current project and reproduces the swagger files,
|
||||
which is quite convenient for local API development.
|
||||
If it fails in command "swag", please firstly check your system PATH whether containing
|
||||
go binary path, or you can install the "swag" tool manually referring to:
|
||||
https://github.com/swaggo/swag
|
||||
`))
|
||||
}
|
||||
|
||||
func Run() {
|
||||
mlog.SetHeaderPrint(true)
|
||||
parser, err := gcmd.Parse(g.MapStrBool{
|
||||
"s,server": true,
|
||||
"o,output": true,
|
||||
"pack": false,
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
server := parser.GetOpt("server")
|
||||
output := parser.GetOpt("output", defaultOutput)
|
||||
// Generate swagger files.
|
||||
if err := generateSwaggerFiles(output, parser.ContainsOpt("pack")); err != nil {
|
||||
mlog.Print(err)
|
||||
}
|
||||
// Watch the go file changes and regenerate the swagger files.
|
||||
dirty := gtype.NewBool()
|
||||
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
|
||||
if gfile.ExtName(event.Path) != "go" || gstr.Contains(event.Path, "swagger") {
|
||||
return
|
||||
}
|
||||
// Variable <dirty> is used for running the changes only one in one second.
|
||||
if !dirty.Cas(false, true) {
|
||||
return
|
||||
}
|
||||
// With some delay in case of multiple code changes in very short interval.
|
||||
gtimer.SetTimeout(1500*gtime.MS, func() {
|
||||
mlog.Printf(`go file changes: %s`, event.String())
|
||||
mlog.Print(`reproducing swagger files...`)
|
||||
if err := generateSwaggerFiles(output, parser.ContainsOpt("pack")); err != nil {
|
||||
mlog.Print(err)
|
||||
} else {
|
||||
mlog.Print(`done!`)
|
||||
}
|
||||
dirty.Set(false)
|
||||
})
|
||||
})
|
||||
if err != nil {
|
||||
mlog.Fatal(err)
|
||||
}
|
||||
// Swagger server starts.
|
||||
if server != "" {
|
||||
if gstr.IsNumeric(server) {
|
||||
server = ":" + server
|
||||
}
|
||||
s := g.Server()
|
||||
s.Plugin(&swagger.Swagger{})
|
||||
s.SetAddr(server)
|
||||
s.Run()
|
||||
}
|
||||
}
|
||||
|
||||
// generateSwaggerFiles generates necessary swagger files.
|
||||
func generateSwaggerFiles(output string, pack bool) error {
|
||||
mlog.Print(`producing swagger files...`)
|
||||
// Temporary storing swagger files directory.
|
||||
tempOutputPath := gfile.Join(gfile.TempDir(), "swagger")
|
||||
if gfile.Exists(tempOutputPath) {
|
||||
gfile.Remove(tempOutputPath)
|
||||
}
|
||||
gfile.Mkdir(tempOutputPath)
|
||||
// Check and install swag tool.
|
||||
swag := gproc.SearchBinary("swag")
|
||||
if swag == "" {
|
||||
err := gproc.ShellRun(fmt.Sprintf(`go get -u -v %s`, swaggoRepoPath))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Generate swagger files using swag.
|
||||
command := fmt.Sprintf(`swag init -o %s`, tempOutputPath)
|
||||
result, err := gproc.ShellExec(command)
|
||||
if err != nil {
|
||||
return errors.New(result + err.Error())
|
||||
}
|
||||
if !gfile.Exists(gfile.Join(tempOutputPath, "swagger.json")) {
|
||||
return errors.New("make swagger files failed")
|
||||
}
|
||||
if !gfile.Exists(output) {
|
||||
gfile.Mkdir(output)
|
||||
}
|
||||
if err = gfile.CopyFile(
|
||||
gfile.Join(tempOutputPath, "swagger.json"),
|
||||
gfile.Join(output, "swagger.json"),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
mlog.Print(`done!`)
|
||||
// Auto pack into go file.
|
||||
if pack && gfile.Exists("swagger") {
|
||||
packCmd := fmt.Sprintf(`gf pack %s packed/%s -n packed`, "swagger", PackedGoFileName)
|
||||
mlog.Print(packCmd)
|
||||
if err := gproc.ShellRun(packCmd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
package update
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func Run() {
|
||||
goBinPath := gproc.SearchBinary("go")
|
||||
if goBinPath == "" {
|
||||
mlog.Fatal(`"go" command not found, install it first to step further`)
|
||||
}
|
||||
var err error
|
||||
if gstr.CompareVersionGo(runtime.Version(), "go1.16.0") >= 0 {
|
||||
err = gproc.ShellRun(`go install github.com/gogf/gf/tool/gf@latest`)
|
||||
} else {
|
||||
err = gproc.ShellRun(`go install github.com/gogf/gf/tool/gf`)
|
||||
}
|
||||
if err != nil {
|
||||
mlog.Fatalf(`gf binary installation failed: %+v`, err)
|
||||
}
|
||||
mlog.Print("gf binary is now updated to the latest version")
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
# gf pack config packed/config.go
|
||||
|
||||
|
||||
# gf home site cdn.
|
||||
[cdn]
|
||||
url = "https://gfcdn.johng.cn"
|
||||
|
||||
# home site url.
|
||||
[home]
|
||||
url = "https://goframe.org"
|
||||
|
||||
# go proxy for gf get.
|
||||
[proxy]
|
||||
urls = [
|
||||
"https://goproxy.io/",
|
||||
"https://goproxy.cn/"
|
||||
]
|
||||
@ -1,15 +0,0 @@
|
||||
module github.com/gogf/gf/tool/gf
|
||||
|
||||
go 1.11
|
||||
|
||||
require (
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e
|
||||
github.com/gogf/gf v1.16.4
|
||||
github.com/gogf/swagger v1.3.0
|
||||
github.com/gorilla/websocket v1.4.2 // indirect
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20200322061010-ea0c1cf2f119 // indirect
|
||||
github.com/lib/pq v1.2.0
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||
)
|
||||
@ -1,79 +0,0 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
|
||||
github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
|
||||
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/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e h1:LzwWXEScfcTu7vUZNlDDWDARoSGEtvlDKK2BYHowNeE=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200206145737-bbfc9a55622e/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gogf/gf v1.16.4 h1:1Y8/P1UMp9BmrtUn0wAg3g6ElRAO0R9QHCdUNt9Z5L4=
|
||||
github.com/gogf/gf v1.16.4/go.mod h1:EjnxZXddTwfFoLPofDE3NokFWx+immofINtSyFCj280=
|
||||
github.com/gogf/mysql v1.6.1-0.20210603073548-16164ae25579 h1:pP/uEy52biKDytlgK/ug8kiYPAiYu6KajKVUHfGrtyw=
|
||||
github.com/gogf/mysql v1.6.1-0.20210603073548-16164ae25579/go.mod h1:52e6mXyNnHAsFrXrSnj5JPRSKsZKpHylVtA3j4AtMz8=
|
||||
github.com/gogf/swagger v1.3.0 h1:McpIEwj2DXLF3/ZNN9h9LKza/fsjtHP54nMTYVSCQ74=
|
||||
github.com/gogf/swagger v1.3.0/go.mod h1:VDpNntu8+8NTTJ3sLOZNPO1LUbfW/ZA84IFJhhrlpoM=
|
||||
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/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
|
||||
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20200322061010-ea0c1cf2f119 h1:h3iGUlU8HyW4baKd6D+h1mwOHnM2kwskSuG6Bv4tSbc=
|
||||
github.com/grokify/html-strip-tags-go v0.0.0-20200322061010-ea0c1cf2f119/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||
github.com/mattn/go-runewidth v0.0.10 h1:CoZ3S2P7pvtP45xOtBw+/mDL2z0RKI576gSkzRRpdGg=
|
||||
github.com/mattn/go-runewidth v0.0.10/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
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/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rivo/uniseg v0.1.0 h1:+2KBaVoUmb9XzDsrx/Ct0W/EYOSFf/nWTauy++DprtY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.opentelemetry.io/otel v0.19.0 h1:Lenfy7QHRXPZVsw/12CWpxX6d/JkrX8wrx2vO8G80Ng=
|
||||
go.opentelemetry.io/otel v0.19.0/go.mod h1:j9bF567N9EfomkSidSfmMwIwIBuP37AMAIzVW85OxSg=
|
||||
go.opentelemetry.io/otel/metric v0.19.0 h1:dtZ1Ju44gkJkYvo+3qGqVXmf88tc+a42edOywypengg=
|
||||
go.opentelemetry.io/otel/metric v0.19.0/go.mod h1:8f9fglJPRnXuskQmKpnad31lcLJ2VmNNqIsx/uIwBSc=
|
||||
go.opentelemetry.io/otel/oteltest v0.19.0 h1:YVfA0ByROYqTwOxqHVZYZExzEpfZor+MU1rU+ip2v9Q=
|
||||
go.opentelemetry.io/otel/oteltest v0.19.0/go.mod h1:tI4yxwh8U21v7JD6R3BcA/2+RBoTKFexE/PJ/nSO7IA=
|
||||
go.opentelemetry.io/otel/trace v0.19.0 h1:1ucYlenXIDA1OlHVLDZKX0ObXV5RLaq06DtUKz5e5zc=
|
||||
go.opentelemetry.io/otel/trace v0.19.0/go.mod h1:4IXiNextNOpPnRlI4ryK69mn5iC84bjBWZQA5DXz/qg=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 h1:42cLlJJdEh+ySyeUUbEQ5bsTiq8voBeTuweGVkY6Puw=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
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-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@ -1,22 +0,0 @@
|
||||
package allyes
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
)
|
||||
|
||||
const (
|
||||
EnvName = "GF_CLI_ALL_YES"
|
||||
)
|
||||
|
||||
// Init initializes the package manually.
|
||||
func Init() {
|
||||
if gcmd.ContainsOpt("y") {
|
||||
genv.Set(EnvName, "1")
|
||||
}
|
||||
}
|
||||
|
||||
// Check checks whether option allow all yes for command.
|
||||
func Check() bool {
|
||||
return genv.Get(EnvName) == "1"
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
package mlog
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/frame/g"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
"github.com/gogf/gf/os/glog"
|
||||
)
|
||||
|
||||
const (
|
||||
headerPrintEnvName = "GF_CLI_MLOG_HEADER"
|
||||
)
|
||||
|
||||
var (
|
||||
logger = glog.New()
|
||||
)
|
||||
|
||||
func init() {
|
||||
logger.SetStack(false)
|
||||
logger.SetDebug(false)
|
||||
if genv.Get(headerPrintEnvName) == "1" {
|
||||
logger.SetHeaderPrint(true)
|
||||
} else {
|
||||
logger.SetHeaderPrint(false)
|
||||
}
|
||||
if gcmd.ContainsOpt("debug") {
|
||||
logger.SetDebug(true)
|
||||
}
|
||||
}
|
||||
|
||||
// SetHeaderPrint enables/disables header printing to stdout.
|
||||
func SetHeaderPrint(enabled bool) {
|
||||
logger.SetHeaderPrint(enabled)
|
||||
if enabled {
|
||||
genv.Set(headerPrintEnvName, "1")
|
||||
} else {
|
||||
genv.Set(headerPrintEnvName, "0")
|
||||
}
|
||||
}
|
||||
|
||||
func Print(v ...interface{}) {
|
||||
logger.Print(v...)
|
||||
}
|
||||
|
||||
func Printf(format string, v ...interface{}) {
|
||||
logger.Printf(format, v...)
|
||||
}
|
||||
|
||||
func Fatal(v ...interface{}) {
|
||||
logger.Fatal(append(g.Slice{"Error:"}, v...)...)
|
||||
}
|
||||
|
||||
func Fatalf(format string, v ...interface{}) {
|
||||
logger.Fatalf("Error: "+format, v...)
|
||||
}
|
||||
|
||||
func Debug(v ...interface{}) {
|
||||
logger.Debug(append(g.Slice{"Debug:"}, v...)...)
|
||||
}
|
||||
|
||||
func Debugf(format string, v ...interface{}) {
|
||||
logger.Debugf("Debug: "+format, v...)
|
||||
}
|
||||
@ -1,33 +0,0 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/net/ghttp"
|
||||
"github.com/gogf/gf/os/genv"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"time"
|
||||
)
|
||||
|
||||
var (
|
||||
httpClient = ghttp.NewClient()
|
||||
)
|
||||
|
||||
func init() {
|
||||
httpClient.SetTimeout(time.Second)
|
||||
}
|
||||
|
||||
// AutoSet automatically checks and sets the golang proxy.
|
||||
func AutoSet() {
|
||||
SetGoModuleEnabled(true)
|
||||
genv.Set("GOPROXY", "https://goproxy.cn")
|
||||
}
|
||||
|
||||
// SetGoModuleEnabled enables/disables the go module feature.
|
||||
func SetGoModuleEnabled(enabled bool) {
|
||||
if enabled {
|
||||
mlog.Debug("set GO111MODULE=on")
|
||||
genv.Set("GO111MODULE", "on")
|
||||
} else {
|
||||
mlog.Debug("set GO111MODULE=off")
|
||||
genv.Set("GO111MODULE", "off")
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gogf/gf/os/gproc"
|
||||
)
|
||||
|
||||
var (
|
||||
// gofmtPath is the binary path of command `gofmt`.
|
||||
gofmtPath = gproc.SearchBinaryPath("gofmt")
|
||||
)
|
||||
|
||||
// GoFmt formats the source file using command `gofmt -w -s PATH`.
|
||||
func GoFmt(path string) {
|
||||
if gofmtPath != "" {
|
||||
gproc.ShellExec(fmt.Sprintf(`%s -w -s %s`, gofmtPath, path))
|
||||
}
|
||||
}
|
||||
187
tool/gf/main.go
187
tool/gf/main.go
@ -1,187 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "github.com/gogf/gf/tool/gf/boot"
|
||||
|
||||
"github.com/gogf/gf"
|
||||
"github.com/gogf/gf/errors/gerror"
|
||||
"github.com/gogf/gf/os/gbuild"
|
||||
"github.com/gogf/gf/os/gcmd"
|
||||
"github.com/gogf/gf/os/gfile"
|
||||
"github.com/gogf/gf/text/gregex"
|
||||
"github.com/gogf/gf/text/gstr"
|
||||
"github.com/gogf/gf/tool/gf/commands/build"
|
||||
"github.com/gogf/gf/tool/gf/commands/docker"
|
||||
"github.com/gogf/gf/tool/gf/commands/env"
|
||||
"github.com/gogf/gf/tool/gf/commands/fix"
|
||||
"github.com/gogf/gf/tool/gf/commands/gen"
|
||||
"github.com/gogf/gf/tool/gf/commands/get"
|
||||
"github.com/gogf/gf/tool/gf/commands/initialize"
|
||||
"github.com/gogf/gf/tool/gf/commands/mod"
|
||||
"github.com/gogf/gf/tool/gf/commands/pack"
|
||||
"github.com/gogf/gf/tool/gf/commands/run"
|
||||
"github.com/gogf/gf/tool/gf/commands/swagger"
|
||||
"github.com/gogf/gf/tool/gf/commands/update"
|
||||
"github.com/gogf/gf/tool/gf/library/allyes"
|
||||
"github.com/gogf/gf/tool/gf/library/mlog"
|
||||
"github.com/gogf/gf/tool/gf/library/proxy"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Automatically sets the golang proxy for all commands.
|
||||
proxy.AutoSet()
|
||||
}
|
||||
|
||||
var (
|
||||
helpContent = gstr.TrimLeft(`
|
||||
USAGE
|
||||
gf COMMAND [ARGUMENT] [OPTION]
|
||||
|
||||
COMMAND
|
||||
env show current Golang environment variables
|
||||
get install or update GF to system in default...
|
||||
gen automatically generate go files for ORM models...
|
||||
mod extra features for go modules...
|
||||
run running go codes with hot-compiled-like feature...
|
||||
init create and initialize an empty GF project...
|
||||
help show more information about a specified command
|
||||
pack packing any file/directory to a resource file, or a go file...
|
||||
build cross-building go project for lots of platforms...
|
||||
docker create a docker image for current GF project...
|
||||
swagger swagger feature for current project...
|
||||
update update current gf binary to latest one
|
||||
version show current binary version info
|
||||
|
||||
OPTION
|
||||
-y all yes for all command without prompt ask
|
||||
-?,-h show this help or detail for specified command
|
||||
-v,-i show version information
|
||||
|
||||
ADDITIONAL
|
||||
Use 'gf help COMMAND' or 'gf COMMAND -h' for detail about a command, which has '...'
|
||||
in the tail of their comments.
|
||||
`)
|
||||
)
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
if exception := recover(); exception != nil {
|
||||
if err, ok := exception.(error); ok {
|
||||
mlog.Print(gerror.Current(err).Error())
|
||||
} else {
|
||||
panic(exception)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
allyes.Init()
|
||||
|
||||
command := gcmd.GetArg(1)
|
||||
// Help information
|
||||
if gcmd.ContainsOpt("h") && command != "" {
|
||||
help(command)
|
||||
return
|
||||
}
|
||||
switch command {
|
||||
case "help":
|
||||
help(gcmd.GetArg(2))
|
||||
case "version":
|
||||
version()
|
||||
case "env":
|
||||
env.Run()
|
||||
case "get":
|
||||
get.Run()
|
||||
case "gen":
|
||||
gen.Run()
|
||||
case "fix":
|
||||
fix.Run()
|
||||
case "mod":
|
||||
mod.Run()
|
||||
case "init":
|
||||
initialize.Run()
|
||||
case "pack":
|
||||
pack.Run()
|
||||
case "docker":
|
||||
docker.Run()
|
||||
case "swagger":
|
||||
swagger.Run()
|
||||
case "update":
|
||||
update.Run()
|
||||
case "build":
|
||||
build.Run()
|
||||
case "run":
|
||||
run.Run()
|
||||
default:
|
||||
for k := range gcmd.GetOptAll() {
|
||||
switch k {
|
||||
case "?", "h":
|
||||
mlog.Print(helpContent)
|
||||
return
|
||||
case "i", "v":
|
||||
version()
|
||||
return
|
||||
}
|
||||
}
|
||||
mlog.Print(helpContent)
|
||||
}
|
||||
}
|
||||
|
||||
// help shows more information for specified command.
|
||||
func help(command string) {
|
||||
switch command {
|
||||
case "get":
|
||||
get.Help()
|
||||
case "gen":
|
||||
gen.Help()
|
||||
case "init":
|
||||
initialize.Help()
|
||||
case "docker":
|
||||
docker.Help()
|
||||
case "swagger":
|
||||
swagger.Help()
|
||||
case "build":
|
||||
build.Help()
|
||||
case "pack":
|
||||
pack.Help()
|
||||
case "run":
|
||||
run.Help()
|
||||
case "mod":
|
||||
mod.Help()
|
||||
default:
|
||||
mlog.Print(helpContent)
|
||||
}
|
||||
}
|
||||
|
||||
// version prints the version information of the cli tool.
|
||||
func version() {
|
||||
info := gbuild.Info()
|
||||
if info["git"] == "" {
|
||||
info["git"] = "none"
|
||||
}
|
||||
mlog.Printf(`GoFrame CLI Tool %s, https://goframe.org`, gf.VERSION)
|
||||
gfVersion, err := getGFVersionOfCurrentProject()
|
||||
if err != nil {
|
||||
gfVersion = err.Error()
|
||||
} else {
|
||||
gfVersion = gfVersion + " in current go.mod"
|
||||
}
|
||||
mlog.Printf(`GoFrame Version: %s`, gfVersion)
|
||||
mlog.Printf(`CLI Installed At: %s`, gfile.SelfPath())
|
||||
}
|
||||
|
||||
// getGFVersionOfCurrentProject checks and returns the GoFrame version current project using.
|
||||
func getGFVersionOfCurrentProject() (string, error) {
|
||||
goModPath := gfile.Join(gfile.Pwd(), "go.mod")
|
||||
if gfile.Exists(goModPath) {
|
||||
match, err := gregex.MatchString(`github.com/gogf/gf\s+([\w\d\.]+)`, gfile.GetContents(goModPath))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if len(match) > 1 {
|
||||
return match[1], nil
|
||||
}
|
||||
return "", gerror.New("cannot find goframe requirement in go.mod")
|
||||
} else {
|
||||
return "", gerror.New("cannot find go.mod in current directory")
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
package packed
|
||||
|
||||
import "github.com/gogf/gf/os/gres"
|
||||
|
||||
func init() {
|
||||
if err := gres.Add("H4sIAAAAAAAC/wrwZmYRYeBg4GBIi7kQwIAE+Bk4GZLz89Iy0/VLi3L0SvJzc0JDWBkYC9a9iMvpc+xrNuBxvf5DJH7m2xM3+494KolpqLRpHtFgWbm3dmpI1u6E5+//z3sq73HE7pf0nmU7PGYfTonvdO1cYbg5j/F4ENOfKTPmzL/kwFDwTNT2TMypuj+R2hu//bdST5zvs9X+1cxwtfDPW1cb9kcnnL3kEvgm8j2/y9mv7JytJ7devW1/4XDg9VrZTAb9rLPvQx9ONr3Ce56BgeH//wBvdo4D12YyTmNgYPjFwMAA8xsDw+EMwUBkv7HB/Qb20v4Gq3iQZmQlAd6MTCLMiKBBNhgUNDCwpBFE4goohCnYHQEBAgz/He/ATUFyEisbSJqJgYmhmYGBQZIRxAMEAAD//5uozoWyAQAA"); err != nil {
|
||||
panic("add binary content to resource manager failed: " + err.Error())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user