remove gf cli from basic framework

This commit is contained in:
John Guo
2021-06-30 20:43:49 +08:00
parent d5fad88c56
commit 1e78734f2c
31 changed files with 4 additions and 3184 deletions

5
go.mod
View File

@ -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
View File

@ -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=

View File

@ -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`.

View File

@ -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")
}
}
}
}

View File

@ -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 ""
}

View File

@ -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
}
}

View File

@ -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())
}

View File

@ -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")
}

View File

@ -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()
}
}

View File

@ -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
}

View File

@ -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}",
}
}
`

View File

@ -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}
`

View File

@ -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!")
}

View File

@ -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
}

View File

@ -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}
`

View File

@ -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")
}
}

View File

@ -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!")
}

View File

@ -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!")
}

View File

@ -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!")
}

View File

@ -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)
}
}

View File

@ -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
}

View File

@ -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")
}

View File

@ -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/"
]

View File

@ -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
)

View File

@ -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=

View File

@ -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"
}

View File

@ -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...)
}

View File

@ -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")
}
}

View File

@ -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))
}
}

View File

@ -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")
}
}

View File

@ -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())
}
}