mirror of
https://github.com/beego/bee.git
synced 2024-11-23 01:30:55 +00:00
commit
8058ab37b8
517
README.md
517
README.md
@ -1,18 +1,17 @@
|
|||||||
bee
|
bee
|
||||||
===
|
===
|
||||||
|
|
||||||
[![Build Status](https://drone.io/github.com/beego/bee/status.png)](https://drone.io/github.com/beego/bee/latest)
|
Bee is a command-line tool facilitating development of Beego-based application.
|
||||||
|
|
||||||
Bee is a command line tool facilitating development with beego framework.
|
[![Build Status](https://drone.io/github.com/beego/bee/status.png)](https://drone.io/github.com/beego/bee/latest)
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- Go version >= 1.3.
|
- Go version >= 1.3.
|
||||||
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
Begin by installing `bee` using `go get` command.
|
To install `bee` use the `go get` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go get github.com/beego/bee
|
go get github.com/beego/bee
|
||||||
@ -32,242 +31,225 @@ go get -u github.com/beego/bee
|
|||||||
|
|
||||||
## Basic commands
|
## Basic commands
|
||||||
|
|
||||||
Bee provides a variety of commands which can be helpful at various stage of development. The top level commands include:
|
Bee provides a variety of commands which can be helpful at various stages of development. The top level commands include:
|
||||||
```base
|
|
||||||
new create an application base on beego framework
|
|
||||||
run run the app which can hot compile
|
|
||||||
pack compress an beego project
|
|
||||||
api create an api application base on beego framework
|
|
||||||
bale packs non-Go files to Go source files
|
|
||||||
version show the bee & beego version
|
|
||||||
generate source code generator
|
|
||||||
migrate run database migrations
|
|
||||||
hprose create an rpc application use hprose base on beego framework
|
|
||||||
```
|
```
|
||||||
## bee version
|
new Create a Beego application
|
||||||
|
run Run the app and start a Web server for development
|
||||||
|
pack Compress a beego project into a single file
|
||||||
|
api Create an API beego application
|
||||||
|
hprose Create an rpc application use hprose base on beego framework
|
||||||
|
bale Packs non-Go files to Go source files
|
||||||
|
version Prints the current Bee version
|
||||||
|
generate Source code generator
|
||||||
|
migrate Run database migrations
|
||||||
|
fix Fix the Beego application to make it compatible with Beego 1.6
|
||||||
|
```
|
||||||
|
### bee version
|
||||||
|
|
||||||
The first command is the easiest: displaying which version of `bee`, `beego` and `go` is installed on your machine:
|
To display the current version of `bee`, `beego` and `go` installed on your machine:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ bee version
|
$ bee version
|
||||||
bee :1.2.2
|
______
|
||||||
beego :1.4.0
|
| ___ \
|
||||||
Go :go version go1.2.1 linux/amd64
|
| |_/ / ___ ___
|
||||||
|
| ___ \ / _ \ / _ \
|
||||||
|
| |_/ /| __/| __/
|
||||||
|
\____/ \___| \___| v1.5.0
|
||||||
|
|
||||||
|
├── Beego : 1.7.0
|
||||||
|
├── GoVersion : go1.6.2
|
||||||
|
├── GOOS : windows
|
||||||
|
├── GOARCH : amd64
|
||||||
|
├── NumCPU : 4
|
||||||
|
├── GOPATH : C:\Users\beeuser\go
|
||||||
|
├── GOROOT : C:\go
|
||||||
|
├── Compiler : gc
|
||||||
|
└── Date : Monday, 22 Aug 2016
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee new
|
### bee new
|
||||||
|
|
||||||
Creating a new beego web application is no big deal, too.
|
To create a new Beego web application:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ bee new myapp
|
$ bee new my-web-app
|
||||||
[INFO] Creating application...
|
______
|
||||||
/home/zheng/gopath/src/myapp/
|
| ___ \
|
||||||
/home/zheng/gopath/src/myapp/conf/
|
| |_/ / ___ ___
|
||||||
/home/zheng/gopath/src/myapp/controllers/
|
| ___ \ / _ \ / _ \
|
||||||
/home/zheng/gopath/src/myapp/models/
|
| |_/ /| __/| __/
|
||||||
/home/zheng/gopath/src/myapp/routers/
|
\____/ \___| \___| v1.5.0
|
||||||
/home/zheng/gopath/src/myapp/tests/
|
2016/08/22 14:53:45 [INFO] Creating application...
|
||||||
/home/zheng/gopath/src/myapp/static/
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\
|
||||||
/home/zheng/gopath/src/myapp/static/js/
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\conf\
|
||||||
/home/zheng/gopath/src/myapp/static/css/
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\controllers\
|
||||||
/home/zheng/gopath/src/myapp/static/img/
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\models\
|
||||||
/home/zheng/gopath/src/myapp/views/
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\routers\
|
||||||
/home/zheng/gopath/src/myapp/conf/app.conf
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\tests\
|
||||||
/home/zheng/gopath/src/myapp/controllers/default.go
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\static\
|
||||||
/home/zheng/gopath/src/myapp/views/index.tpl
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\static\js\
|
||||||
/home/zheng/gopath/src/myapp/routers/router.go
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\static\css\
|
||||||
/home/zheng/gopath/src/myapp/tests/default_test.go
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\static\img\
|
||||||
/home/zheng/gopath/src/myapp/main.go
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\views\
|
||||||
2014/08/29 15:45:47 [SUCC] New application successfully created!
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\conf\app.conf
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\controllers\default.go
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\views\index.tpl
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\routers\router.go
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\tests\default_test.go
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app\main.go
|
||||||
|
2016/08/22 14:53:45 [SUCC] New application successfully created!
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee run
|
For more information on the usage, run `bee help new`.
|
||||||
|
|
||||||
To run the application we just created, navigate to the application folder and execute `bee run`.
|
### bee run
|
||||||
|
|
||||||
|
To run the application we just created, you can navigate to the application folder and execute:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ cd myapp
|
$ cd my-web-app && bee run
|
||||||
$ bee run
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee pack
|
Or from anywhere in your machine:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ bee run github.com/user/my-web-app
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information on the usage, run `bee help run`.
|
||||||
|
|
||||||
|
### bee pack
|
||||||
|
|
||||||
|
To compress a Beego application into a single deployable file:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
usage: bee pack
|
$ bee pack
|
||||||
|
______
|
||||||
compress an beego project
|
| ___ \
|
||||||
|
| |_/ / ___ ___
|
||||||
-p app path. default is current path
|
| ___ \ / _ \ / _ \
|
||||||
-b build specify platform app. default true
|
| |_/ /| __/| __/
|
||||||
-ba additional args of go build
|
\____/ \___| \___| v1.5.0
|
||||||
-be=[] additional ENV Variables of go build. eg: GOARCH=arm
|
2016/08/22 15:11:01 Packaging application: C:\Users\beeuser\go\src\github.com\user\my-web-app
|
||||||
-o compressed file output dir. default use current path
|
2016/08/22 15:11:01 Building application...
|
||||||
-f="" format. [ tar.gz / zip ]. default tar.gz
|
2016/08/22 15:11:01 Env: GOOS=windows GOARCH=amd64
|
||||||
-exp="" relpath exclude prefix. default: .
|
2016/08/22 15:11:08 Build successful
|
||||||
-exs="" relpath exclude suffix. default: .go:.DS_Store:.tmp
|
2016/08/22 15:11:08 Excluding relpath prefix: .
|
||||||
all path use : as separator
|
2016/08/22 15:11:08 Excluding relpath suffix: .go:.DS_Store:.tmp
|
||||||
-exr=[] file/directory name exclude by Regexp. default: ^.
|
2016/08/22 15:11:10 Writing to output: `C:\Users\beeuser\go\src\github.com\user\my-web-app\my-web-app.tar.gz`
|
||||||
-fs=false follow symlink. default false
|
|
||||||
-ss=false skip symlink. default false
|
|
||||||
default embed symlink into compressed file
|
|
||||||
-v=false verbose
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee api
|
For more information on the usage, run `bee help pack`.
|
||||||
|
|
||||||
|
### bee api
|
||||||
|
|
||||||
|
To create a Beego API application:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
usage: bee api [appname]
|
$ bee api my-api
|
||||||
|
______
|
||||||
create an api application base on beego framework
|
| ___ \
|
||||||
|
| |_/ / ___ ___
|
||||||
bee api [appname] [-tables=""] [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
|
| ___ \ / _ \ / _ \
|
||||||
-tables: a list of table names separated by ',', default is empty, indicating all tables
|
| |_/ /| __/| __/
|
||||||
-driver: [mysql | postgres | sqlite], the default is mysql
|
\____/ \___| \___| v1.5.0
|
||||||
-conn: the connection string used by the driver, the default is ''
|
2016/08/22 15:14:10 [INFO] Creating API...
|
||||||
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
|
create C:\Users\beeuser\go\src\github.com\user\my-api
|
||||||
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
|
create C:\Users\beeuser\go\src\github.com\user\my-api\conf
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-api\controllers
|
||||||
if conn is empty will create a example api application. otherwise generate api application based on an existing database.
|
create C:\Users\beeuser\go\src\github.com\user\my-api\tests
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-api\conf\app.conf
|
||||||
In the current path, will create a folder named [appname]
|
create C:\Users\beeuser\go\src\github.com\user\my-api\models
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-api\routers\
|
||||||
In the appname folder has the follow struct:
|
create C:\Users\beeuser\go\src\github.com\user\my-api\controllers\object.go
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-api\controllers\user.go
|
||||||
├── conf
|
create C:\Users\beeuser\go\src\github.com\user\my-api\tests\default_test.go
|
||||||
│ └── app.conf
|
create C:\Users\beeuser\go\src\github.com\user\my-api\routers\router.go
|
||||||
├── controllers
|
create C:\Users\beeuser\go\src\github.com\user\my-api\models\object.go
|
||||||
│ └── object.go
|
create C:\Users\beeuser\go\src\github.com\user\my-api\models\user.go
|
||||||
│ └── user.go
|
create C:\Users\beeuser\go\src\github.com\user\my-api\main.go
|
||||||
├── routers
|
2016/08/22 15:14:10 [SUCC] New API successfully created!
|
||||||
│ └── router.go
|
|
||||||
├── tests
|
|
||||||
│ └── default_test.go
|
|
||||||
├── main.go
|
|
||||||
└── models
|
|
||||||
└── object.go
|
|
||||||
└── user.go
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee hprose
|
For more information on the usage, run `bee help api`.
|
||||||
|
|
||||||
|
### bee hprose
|
||||||
|
|
||||||
|
To create an Hprose RPC application based on Beego:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
usage: bee hprose [appname]
|
$ bee hprose my-rpc-app
|
||||||
|
______
|
||||||
create an rpc application use hprose base on beego framework
|
| ___ \
|
||||||
|
| |_/ / ___ ___
|
||||||
bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
|
| ___ \ / _ \ / _ \
|
||||||
-tables: a list of table names separated by ',', default is empty, indicating all tables
|
| |_/ /| __/| __/
|
||||||
-driver: [mysql | postgres | sqlite], the default is mysql
|
\____/ \___| \___| v1.5.0
|
||||||
-conn: the connection string used by the driver, the default is ''
|
2016/08/22 16:09:13 [INFO] Creating Hprose application...
|
||||||
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app
|
||||||
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app\conf
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app\conf\app.conf
|
||||||
if conn is empty will create a example rpc application. otherwise generate rpc application use hprose based on an existing database.
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app\models
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app\models\object.go
|
||||||
In the current path, will create a folder named [appname]
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app\models\user.go
|
||||||
|
create C:\Users\beeuser\go\src\github.com\user\my-rpc-app\main.go
|
||||||
In the appname folder has the follow struct:
|
2016/08/22 16:09:13 [SUCC] New Hprose application successfully created!
|
||||||
|
|
||||||
├── conf
|
|
||||||
│ └── app.conf
|
|
||||||
├── main.go
|
|
||||||
└── models
|
|
||||||
└── object.go
|
|
||||||
└── user.go
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee bale
|
For more information on the usage, run `bee help hprose`.
|
||||||
|
|
||||||
|
### bee bale
|
||||||
|
|
||||||
|
To pack all the static files into Go source files:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
usage: bee bale
|
$ bee bale
|
||||||
|
______
|
||||||
bale packs non-Go files to Go source files and
|
| ___ \
|
||||||
|
| |_/ / ___ ___
|
||||||
auto-generate unpack function to main package then run it
|
| ___ \ / _ \ / _ \
|
||||||
|
| |_/ /| __/| __/
|
||||||
during the runtime.
|
\____/ \___| \___| v1.5.0
|
||||||
|
2016/08/22 16:37:24 [INFO] Detected bee.json
|
||||||
This is mainly used for zealots who are requiring 100% Go code.
|
2016/08/22 16:37:24 [INFO] Packaging directory(static/js)
|
||||||
|
2016/08/22 16:37:24 [INFO] Packaging directory(static/css)
|
||||||
|
2016/08/22 16:37:24 [SUCC] Baled resources successfully!
|
||||||
```
|
```
|
||||||
|
|
||||||
## bee migrate
|
For more information on the usage, run `bee help bale`.
|
||||||
|
|
||||||
|
### bee migrate
|
||||||
|
|
||||||
|
For database migrations, use `bee migrate`.
|
||||||
|
|
||||||
|
For more information on the usage, run `bee help migrate`.
|
||||||
|
|
||||||
|
### bee generate
|
||||||
|
|
||||||
|
Bee also comes with a source code generator which speeds up the development.
|
||||||
|
|
||||||
|
For example, to generate a new controller named `hello`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
usage: bee migrate [Command]
|
$ bee generate controller hello
|
||||||
|
______
|
||||||
bee migrate [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
|
| ___ \
|
||||||
run all outstanding migrations
|
| |_/ / ___ ___
|
||||||
-driver: [mysql | postgres | sqlite], the default is mysql
|
| ___ \ / _ \ / _ \
|
||||||
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
|
| |_/ /| __/| __/
|
||||||
|
\____/ \___| \___| v1.5.0
|
||||||
bee migrate rollback [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
|
2016/08/22 16:55:30 [INFO] Using 'Hello' as controller name
|
||||||
rollback the last migration operation
|
2016/08/22 16:55:30 [INFO] Using 'controllers' as package name
|
||||||
-driver: [mysql | postgres | sqlite], the default is mysql
|
create C:\Users\beeuser\go\src\github.com\user\my-web-app/controllers/hello.go
|
||||||
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
|
2016/08/22 16:55:30 [SUCC] Controller successfully generated!
|
||||||
|
|
||||||
bee migrate reset [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
|
|
||||||
rollback all migrations
|
|
||||||
-driver: [mysql | postgres| sqlite], the default is mysql
|
|
||||||
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
|
|
||||||
|
|
||||||
bee migrate refresh [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
|
|
||||||
rollback all migrations and run them all again
|
|
||||||
-driver: [mysql | postgresql | sqlite], the default is mysql
|
|
||||||
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
## bee generate
|
|
||||||
|
|
||||||
Bee also comes with a souce code generator which speeds up the development.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
usage: bee generate [Command]
|
|
||||||
|
|
||||||
bee generate scaffold [scaffoldname] [-fields=""] [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
|
|
||||||
The generate scaffold command will do a number of things for you.
|
|
||||||
-fields: a list of table fields. Format: field:type, ...
|
|
||||||
-driver: [mysql | postgres | sqlite], the default is mysql
|
|
||||||
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
|
|
||||||
example: bee generate scaffold post -fields="title:string,body:text"
|
|
||||||
|
|
||||||
bee generate model [modelname] [-fields=""]
|
|
||||||
generate RESTFul model based on fields
|
|
||||||
-fields: a list of table fields. Format: field:type, ...
|
|
||||||
|
|
||||||
bee generate controller [controllerfile]
|
|
||||||
generate RESTFul controllers
|
|
||||||
|
|
||||||
bee generate view [viewpath]
|
|
||||||
generate CRUD view in viewpath
|
|
||||||
|
|
||||||
bee generate migration [migrationfile] [-fields=""]
|
|
||||||
generate migration file for making database schema update
|
|
||||||
-fields: a list of table fields. Format: field:type, ...
|
|
||||||
|
|
||||||
bee generate docs
|
|
||||||
generate swagger doc file
|
|
||||||
|
|
||||||
bee generate test [routerfile]
|
|
||||||
generate testcase
|
|
||||||
|
|
||||||
bee generate appcode [-tables=""] [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3]
|
|
||||||
generate appcode based on an existing database
|
|
||||||
-tables: a list of table names separated by ',', default is empty, indicating all tables
|
|
||||||
-driver: [mysql | postgres | sqlite], the default is mysql
|
|
||||||
-conn: the connection string used by the driver.
|
|
||||||
default for mysql: root:@tcp(127.0.0.1:3306)/test
|
|
||||||
default for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
|
|
||||||
-level: [1 | 2 | 3], 1 = models; 2 = models,controllers; 3 = models,controllers,router
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
For more information on the usage, run `bee help generate`.
|
||||||
|
|
||||||
## Shortcuts
|
## Shortcuts
|
||||||
|
|
||||||
Because you'll likely type these generator commands over and over, it makes sense to create aliases.
|
Because you'll likely type these generator commands over and over, it makes sense to create aliases:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Generator Stuff
|
# Generator Stuff
|
||||||
@ -278,32 +260,135 @@ alias g:v="bee generate view"
|
|||||||
alias g:mi="bee generate migration"
|
alias g:mi="bee generate migration"
|
||||||
```
|
```
|
||||||
|
|
||||||
These can be stored in, for example, your `~/.bash_profile` or `~/.bashrc` files.
|
These can be stored , for example, in your `~/.bash_profile` or `~/.bashrc` files.
|
||||||
|
|
||||||
## Help
|
## Help
|
||||||
|
|
||||||
If you happend to forget the usage of a command, you can always find the usage information by `bee help <command>`.
|
To print more information on the usage of a particular command, use `bee help <command>`.
|
||||||
|
|
||||||
For instance, to get more information about the `run` command:
|
For instance, to get more information about the `run` command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ bee help run
|
$ bee help run
|
||||||
usage: bee run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true]
|
usage: bee run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-tags=goBuildTags]
|
||||||
|
|
||||||
start the appname throw exec.Command
|
Run command will supervise the file system of the beego project using inotify,
|
||||||
|
it will recompile and restart the app after any modifications.
|
||||||
|
```
|
||||||
|
|
||||||
then start a inotify watch for current dir
|
## Contributing
|
||||||
|
Bug reports, feature requests and pull requests are always welcome.
|
||||||
when the file has changed bee will auto go build and restart the app
|
|
||||||
|
|
||||||
file changed
|
We work on two branches: `master` for stable, released code and `develop`, a development branch.
|
||||||
|
|
It might be important to distinguish them when you are reading the commit history searching for a feature or a bugfix,
|
||||||
check if it's go file
|
or when you are unsure of where to base your work from when contributing.
|
||||||
|
|
|
||||||
yes no
|
### Found a bug?
|
||||||
| |
|
|
||||||
go build do nothing
|
Please [submit an issue][new-issue] on GitHub and we will follow up.
|
||||||
|
|
Even better, we would appreciate a [Pull Request][new-pr] with a fix for it!
|
||||||
restart app
|
|
||||||
|
- If the bug was found in a release, it is best to base your work on `master` and submit your PR against it.
|
||||||
|
- If the bug was found on `develop` (the development branch), base your work on `develop` and submit your PR against it.
|
||||||
|
|
||||||
|
Please follow the [Pull Request Guidelines][new-pr].
|
||||||
|
|
||||||
|
### Want a feature?
|
||||||
|
|
||||||
|
Feel free to request a feature by [submitting an issue][new-issue] on GitHub and open the discussion.
|
||||||
|
|
||||||
|
If you'd like to implement a new feature, please consider opening an issue first to talk about it.
|
||||||
|
It may be that somebody is already working on it, or that there are particular issues that you should be aware of
|
||||||
|
before implementing the change. If you are about to open a Pull Request, please make sure to follow the [submissions guidelines][new-pr].
|
||||||
|
|
||||||
|
## Submission Guidelines
|
||||||
|
|
||||||
|
### Submitting an issue
|
||||||
|
|
||||||
|
Before you submit an issue, search the archive, maybe you will find that a similar one already exists.
|
||||||
|
|
||||||
|
If you are submitting an issue for a bug, please include the following:
|
||||||
|
|
||||||
|
- An overview of the issue
|
||||||
|
- Your use case (why is this a bug for you?)
|
||||||
|
- The version of `bee` you are running (include the output of `bee version`)
|
||||||
|
- Steps to reproduce the issue
|
||||||
|
- Eventually, logs from your application.
|
||||||
|
- Ideally, a suggested fix
|
||||||
|
|
||||||
|
The more information you give us, the more able to help we will be!
|
||||||
|
|
||||||
|
### Submitting a Pull Request
|
||||||
|
|
||||||
|
- First of all, make sure to base your work on the `develop` branch (the development branch):
|
||||||
|
|
||||||
```
|
```
|
||||||
|
# a bugfix branch for develop would be prefixed by fix/
|
||||||
|
# a bugfix branch for master would be prefixed by hotfix/
|
||||||
|
$ git checkout -b feature/my-feature develop
|
||||||
|
```
|
||||||
|
|
||||||
|
- Please create commits containing **related changes**. For example, two different bugfixes should produce two separate commits.
|
||||||
|
A feature should be made of commits splitted by **logical chunks** (no half-done changes). Use your best judgement as to
|
||||||
|
how many commits your changes require.
|
||||||
|
|
||||||
|
- Write insightful and descriptive commit messages. It lets us and future contributors quickly understand your changes
|
||||||
|
without having to read your changes. Please provide a summary in the first line (50-72 characters) and eventually,
|
||||||
|
go to greater lengths in your message's body. A good example can be found in [Angular commit message format](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#commit-message-format).
|
||||||
|
|
||||||
|
- Please **include the appropriate test cases** for your patch.
|
||||||
|
|
||||||
|
- Make sure all tests pass before submitting your changes.
|
||||||
|
|
||||||
|
- Rebase your commits. It may be that new commits have been introduced on `develop`.
|
||||||
|
Rebasing will update your branch with the most recent code and make your changes easier to review:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git fetch
|
||||||
|
$ git rebase origin/develop
|
||||||
|
```
|
||||||
|
|
||||||
|
- Push your changes:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git push origin -u feature/my-feature
|
||||||
|
```
|
||||||
|
|
||||||
|
- Open a pull request against the `develop` branch.
|
||||||
|
|
||||||
|
- If we suggest changes:
|
||||||
|
- Please make the required updates (after discussion if any)
|
||||||
|
- Only create new commits if it makes sense. Generally, you will want to amend your latest commit or rebase your branch after the new changes:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git rebase -i develop
|
||||||
|
# choose which commits to edit and perform the updates
|
||||||
|
```
|
||||||
|
|
||||||
|
- Re-run the tests
|
||||||
|
- Force push to your branch:
|
||||||
|
|
||||||
|
```
|
||||||
|
$ git push origin feature/my-feature -f
|
||||||
|
```
|
||||||
|
|
||||||
|
[new-issue]: #submitting-an-issue
|
||||||
|
[new-pr]: #submitting-a-pull-request
|
||||||
|
|
||||||
|
## Licence
|
||||||
|
|
||||||
|
```text
|
||||||
|
Copyright 2016 bee authors
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
```
|
20
apiapp.go
20
apiapp.go
@ -69,7 +69,6 @@ EnableDocs = true
|
|||||||
var apiMaingo = `package main
|
var apiMaingo = `package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "{{.Appname}}/docs"
|
|
||||||
_ "{{.Appname}}/routers"
|
_ "{{.Appname}}/routers"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
@ -87,7 +86,6 @@ func main() {
|
|||||||
var apiMainconngo = `package main
|
var apiMainconngo = `package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
_ "{{.Appname}}/docs"
|
|
||||||
_ "{{.Appname}}/routers"
|
_ "{{.Appname}}/routers"
|
||||||
|
|
||||||
"github.com/astaxie/beego"
|
"github.com/astaxie/beego"
|
||||||
@ -578,8 +576,6 @@ func createapi(cmd *Command, args []string) int {
|
|||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
|
||||||
os.Mkdir(path.Join(apppath, "controllers"), 0755)
|
os.Mkdir(path.Join(apppath, "controllers"), 0755)
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers"), "\x1b[0m")
|
||||||
os.Mkdir(path.Join(apppath, "docs"), 0755)
|
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "docs"), "\x1b[0m")
|
|
||||||
os.Mkdir(path.Join(apppath, "tests"), 0755)
|
os.Mkdir(path.Join(apppath, "tests"), 0755)
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests"), "\x1b[0m")
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
|
||||||
@ -606,7 +602,7 @@ func createapi(cmd *Command, args []string) int {
|
|||||||
ColorLog("[INFO] Using '%s' as 'driver'\n", driver)
|
ColorLog("[INFO] Using '%s' as 'driver'\n", driver)
|
||||||
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
|
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
|
||||||
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
|
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
|
||||||
generateAppcode(string(driver), string(conn), "3", string(tables), path.Join(apppath, args[0]))
|
generateAppcode(string(driver), string(conn), "3", string(tables), apppath)
|
||||||
} else {
|
} else {
|
||||||
os.Mkdir(path.Join(apppath, "models"), 0755)
|
os.Mkdir(path.Join(apppath, "models"), 0755)
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
|
||||||
@ -635,9 +631,6 @@ func createapi(cmd *Command, args []string) int {
|
|||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m")
|
||||||
WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2)
|
WriteToFile(path.Join(apppath, "models", "user.go"), apiModels2)
|
||||||
|
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "docs", "doc.go"), "\x1b[0m")
|
|
||||||
WriteToFile(path.Join(apppath, "docs", "doc.go"), "package docs")
|
|
||||||
|
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
|
||||||
WriteToFile(path.Join(apppath, "main.go"),
|
WriteToFile(path.Join(apppath, "main.go"),
|
||||||
strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1))
|
strings.Replace(apiMaingo, "{{.Appname}}", packpath, -1))
|
||||||
@ -652,9 +645,20 @@ func checkEnv(appname string) (apppath, packpath string, err error) {
|
|||||||
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
|
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
currpath, _ := os.Getwd()
|
||||||
|
currpath = path.Join(currpath, appname)
|
||||||
|
for _, gpath := range gps {
|
||||||
|
gsrcpath := path.Join(gpath, "src")
|
||||||
|
if strings.HasPrefix(currpath, gsrcpath) {
|
||||||
|
packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(path.Separator), "/", -1)
|
||||||
|
return currpath, packpath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// In case of multiple paths in the GOPATH, by default
|
// In case of multiple paths in the GOPATH, by default
|
||||||
// we use the first path
|
// we use the first path
|
||||||
gopath := gps[0]
|
gopath := gps[0]
|
||||||
|
ColorLog("[%s]You current workdir is not a $GOPATH/src, bee will create the application in GOPATH: %s\n", WARN, gopath)
|
||||||
Debugf("GOPATH: %s", gopath)
|
Debugf("GOPATH: %s", gopath)
|
||||||
|
|
||||||
gosrcpath := path.Join(gopath, "src")
|
gosrcpath := path.Join(gopath, "src")
|
||||||
|
2
bee.go
2
bee.go
@ -25,7 +25,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const version = "1.5.0"
|
const version = "1.5.1"
|
||||||
|
|
||||||
type Command struct {
|
type Command struct {
|
||||||
// Run runs the command.
|
// Run runs the command.
|
||||||
|
8
g.go
8
g.go
@ -170,11 +170,9 @@ func generateCode(cmd *Command, args []string) int {
|
|||||||
upsql := ""
|
upsql := ""
|
||||||
downsql := ""
|
downsql := ""
|
||||||
if fields != "" {
|
if fields != "" {
|
||||||
upsql = `m.SQL("CREATE TABLE ` + mname + "(" + generateSQLFromFields(fields.String()) + `)");`
|
dbMigrator := newDBDriver()
|
||||||
downsql = `m.SQL("DROP TABLE ` + "`" + mname + "`" + `")`
|
upsql = dbMigrator.generateCreateUp(mname)
|
||||||
if driver == "postgres" {
|
downsql = dbMigrator.generateCreateDown(mname)
|
||||||
downsql = strings.Replace(downsql, "`", "", -1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
generateMigration(mname, upsql, downsql, currpath)
|
generateMigration(mname, upsql, downsql, currpath)
|
||||||
case "controller":
|
case "controller":
|
||||||
|
@ -1105,7 +1105,7 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri
|
|||||||
|
|
||||||
var l []{{modelName}}
|
var l []{{modelName}}
|
||||||
qs = qs.OrderBy(sortFields...)
|
qs = qs.OrderBy(sortFields...)
|
||||||
if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
ml = append(ml, v)
|
ml = append(ml, v)
|
||||||
|
328
g_docs.go
328
g_docs.go
@ -108,8 +108,13 @@ func generateDocs(curpath string) {
|
|||||||
for _, l := range stmt.Rhs {
|
for _, l := range stmt.Rhs {
|
||||||
if v, ok := l.(*ast.CallExpr); ok {
|
if v, ok := l.(*ast.CallExpr); ok {
|
||||||
// analisys NewNamespace, it will return version and the subfunction
|
// analisys NewNamespace, it will return version and the subfunction
|
||||||
|
if selName := v.Fun.(*ast.SelectorExpr).Sel.String(); selName != "NewNamespace" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
version, params := analisysNewNamespace(v)
|
version, params := analisysNewNamespace(v)
|
||||||
rootapi.BasePath = version
|
if rootapi.BasePath == "" && version != "" {
|
||||||
|
rootapi.BasePath = version
|
||||||
|
}
|
||||||
for _, p := range params {
|
for _, p := range params {
|
||||||
switch pp := p.(type) {
|
switch pp := p.(type) {
|
||||||
case *ast.CallExpr:
|
case *ast.CallExpr:
|
||||||
@ -323,6 +328,17 @@ func isSystemPackage(pkgpath string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func peekNextSplitString(ss string) (s string, spacePos int) {
|
||||||
|
spacePos = strings.IndexFunc(ss, unicode.IsSpace)
|
||||||
|
if spacePos < 0 {
|
||||||
|
s = ss
|
||||||
|
spacePos = len(ss)
|
||||||
|
} else {
|
||||||
|
s = strings.TrimSpace(ss[:spacePos])
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// parse the func comments
|
// parse the func comments
|
||||||
func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error {
|
func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error {
|
||||||
var routerPath string
|
var routerPath string
|
||||||
@ -349,59 +365,54 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
|
|||||||
} else if strings.HasPrefix(t, "@Title") {
|
} else if strings.HasPrefix(t, "@Title") {
|
||||||
opts.OperationID = controllerName + "." + strings.TrimSpace(t[len("@Title"):])
|
opts.OperationID = controllerName + "." + strings.TrimSpace(t[len("@Title"):])
|
||||||
} else if strings.HasPrefix(t, "@Description") {
|
} else if strings.HasPrefix(t, "@Description") {
|
||||||
opts.Summary = strings.TrimSpace(t[len("@Description"):])
|
opts.Description = strings.TrimSpace(t[len("@Description"):])
|
||||||
|
} else if strings.HasPrefix(t, "@Summary") {
|
||||||
|
opts.Summary = strings.TrimSpace(t[len("@Summary"):])
|
||||||
} else if strings.HasPrefix(t, "@Success") {
|
} else if strings.HasPrefix(t, "@Success") {
|
||||||
ss := strings.TrimSpace(t[len("@Success"):])
|
ss := strings.TrimSpace(t[len("@Success"):])
|
||||||
rs := swagger.Response{}
|
rs := swagger.Response{}
|
||||||
st := make([]string, 3)
|
respCode, pos := peekNextSplitString(ss)
|
||||||
j := 0
|
ss = strings.TrimSpace(ss[pos:])
|
||||||
var tmp []rune
|
respType, pos := peekNextSplitString(ss)
|
||||||
start := false
|
if respType == "{object}" || respType == "{array}" {
|
||||||
|
isArray := respType == "{array}"
|
||||||
for i, c := range ss {
|
ss = strings.TrimSpace(ss[pos:])
|
||||||
if unicode.IsSpace(c) {
|
schemaName, pos := peekNextSplitString(ss)
|
||||||
if !start && j < 2 {
|
if schemaName == "" {
|
||||||
continue
|
ColorLog("[ERRO][%s.%s] Schema must follow {object} or {array}\n", controllerName, funcName)
|
||||||
|
os.Exit(-1)
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(schemaName, "[]") {
|
||||||
|
schemaName = schemaName[2:]
|
||||||
|
isArray = true
|
||||||
|
}
|
||||||
|
schema := swagger.Schema{}
|
||||||
|
if sType, ok := basicTypes[schemaName]; ok {
|
||||||
|
typeFormat := strings.Split(sType, ":")
|
||||||
|
schema.Type = typeFormat[0]
|
||||||
|
schema.Format = typeFormat[1]
|
||||||
|
} else {
|
||||||
|
cmpath, m, mod, realTypes := getModel(schemaName)
|
||||||
|
schema.Ref = "#/definitions/" + m
|
||||||
|
if _, ok := modelsList[pkgpath+controllerName]; !ok {
|
||||||
|
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0)
|
||||||
}
|
}
|
||||||
if j == 0 || j == 1 {
|
modelsList[pkgpath+controllerName][schemaName] = mod
|
||||||
st[j] = string(tmp)
|
appendModels(cmpath, pkgpath, controllerName, realTypes)
|
||||||
tmp = make([]rune, 0)
|
}
|
||||||
j++
|
if isArray {
|
||||||
start = false
|
rs.Schema = &swagger.Schema{
|
||||||
if j == 1 {
|
Type: "array",
|
||||||
continue
|
Items: &schema,
|
||||||
} else {
|
|
||||||
st[j] = strings.TrimSpace(ss[i+1:])
|
|
||||||
break
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
start = true
|
rs.Schema = &schema
|
||||||
tmp = append(tmp, c)
|
|
||||||
}
|
}
|
||||||
|
rs.Description = strings.TrimSpace(ss[pos:])
|
||||||
|
} else {
|
||||||
|
rs.Description = strings.TrimSpace(ss)
|
||||||
}
|
}
|
||||||
if len(tmp) > 0 && st[2] == "" {
|
opts.Responses[respCode] = rs
|
||||||
st[2] = strings.TrimSpace(string(tmp))
|
|
||||||
}
|
|
||||||
rs.Description = st[2]
|
|
||||||
if st[1] == "{object}" {
|
|
||||||
if st[2] == "" {
|
|
||||||
panic(controllerName + " " + funcName + " has no object")
|
|
||||||
}
|
|
||||||
cmpath, m, mod, realTypes := getModel(st[2])
|
|
||||||
//ll := strings.Split(st[2], ".")
|
|
||||||
//opts.Type = ll[len(ll)-1]
|
|
||||||
rs.Schema = &swagger.Schema{
|
|
||||||
Ref: "#/definitions/" + m,
|
|
||||||
}
|
|
||||||
if _, ok := modelsList[pkgpath+controllerName]; !ok {
|
|
||||||
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0)
|
|
||||||
}
|
|
||||||
modelsList[pkgpath+controllerName][st[2]] = mod
|
|
||||||
appendModels(cmpath, pkgpath, controllerName, realTypes)
|
|
||||||
}
|
|
||||||
opts.Responses[st[0]] = rs
|
|
||||||
} else if strings.HasPrefix(t, "@Param") {
|
} else if strings.HasPrefix(t, "@Param") {
|
||||||
para := swagger.Parameter{}
|
para := swagger.Parameter{}
|
||||||
p := getparams(strings.TrimSpace(t[len("@Param "):]))
|
p := getparams(strings.TrimSpace(t[len("@Param "):]))
|
||||||
@ -409,11 +420,25 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
|
|||||||
panic(controllerName + "_" + funcName + "'s comments @Param at least should has 4 params")
|
panic(controllerName + "_" + funcName + "'s comments @Param at least should has 4 params")
|
||||||
}
|
}
|
||||||
para.Name = p[0]
|
para.Name = p[0]
|
||||||
|
switch p[1] {
|
||||||
|
case "query":
|
||||||
|
fallthrough
|
||||||
|
case "header":
|
||||||
|
fallthrough
|
||||||
|
case "path":
|
||||||
|
fallthrough
|
||||||
|
case "formData":
|
||||||
|
fallthrough
|
||||||
|
case "body":
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
ColorLog("[WARN][%s.%s] Unknow param location: %s, Possible values are `query`, `header`, `path`, `formData` or `body`.\n", controllerName, funcName, p[1])
|
||||||
|
}
|
||||||
para.In = p[1]
|
para.In = p[1]
|
||||||
pp := strings.Split(p[2], ".")
|
pp := strings.Split(p[2], ".")
|
||||||
typ := pp[len(pp)-1]
|
typ := pp[len(pp)-1]
|
||||||
if len(pp) >= 2 {
|
if len(pp) >= 2 {
|
||||||
cmpath, m, mod, realTypes := getModel(typ)
|
cmpath, m, mod, realTypes := getModel(p[2])
|
||||||
para.Schema = &swagger.Schema{
|
para.Schema = &swagger.Schema{
|
||||||
Ref: "#/definitions/" + m,
|
Ref: "#/definitions/" + m,
|
||||||
}
|
}
|
||||||
@ -423,9 +448,32 @@ func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpat
|
|||||||
modelsList[pkgpath+controllerName][typ] = mod
|
modelsList[pkgpath+controllerName][typ] = mod
|
||||||
appendModels(cmpath, pkgpath, controllerName, realTypes)
|
appendModels(cmpath, pkgpath, controllerName, realTypes)
|
||||||
} else {
|
} else {
|
||||||
|
isArray := false
|
||||||
|
paraType := ""
|
||||||
|
paraFormat := ""
|
||||||
|
if strings.HasPrefix(typ, "[]") {
|
||||||
|
typ = typ[2:]
|
||||||
|
isArray = true
|
||||||
|
}
|
||||||
if typ == "string" || typ == "number" || typ == "integer" || typ == "boolean" ||
|
if typ == "string" || typ == "number" || typ == "integer" || typ == "boolean" ||
|
||||||
typ == "array" || typ == "file" {
|
typ == "array" || typ == "file" {
|
||||||
para.Type = typ
|
paraType = typ
|
||||||
|
} else if sType, ok := basicTypes[typ]; ok {
|
||||||
|
typeFormat := strings.Split(sType, ":")
|
||||||
|
paraType = typeFormat[0]
|
||||||
|
paraFormat = typeFormat[1]
|
||||||
|
} else {
|
||||||
|
ColorLog("[WARN][%s.%s] Unknow param type: %s\n", controllerName, funcName, typ)
|
||||||
|
}
|
||||||
|
if isArray {
|
||||||
|
para.Type = "array"
|
||||||
|
para.Items = &swagger.ParameterItems{
|
||||||
|
Type: paraType,
|
||||||
|
Format: paraFormat,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
para.Type = paraType
|
||||||
|
para.Format = paraFormat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(p) > 4 {
|
if len(p) > 4 {
|
||||||
@ -564,93 +612,114 @@ func getModel(str string) (pkgpath, objectname string, m swagger.Schema, realTyp
|
|||||||
if k != objectname {
|
if k != objectname {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ts, ok := d.Decl.(*ast.TypeSpec)
|
parseObject(d, k, &m, &realTypes, astPkgs)
|
||||||
if !ok {
|
}
|
||||||
ColorLog("Unknown type without TypeSec: %v", d)
|
}
|
||||||
os.Exit(1)
|
}
|
||||||
|
}
|
||||||
|
if m.Title == "" {
|
||||||
|
ColorLog("[WARN]can't find the object: %s\n", str)
|
||||||
|
// TODO remove when all type have been supported
|
||||||
|
//os.Exit(1)
|
||||||
|
}
|
||||||
|
if len(rootapi.Definitions) == 0 {
|
||||||
|
rootapi.Definitions = make(map[string]swagger.Schema)
|
||||||
|
}
|
||||||
|
rootapi.Definitions[objectname] = m
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs map[string]*ast.Package) {
|
||||||
|
ts, ok := d.Decl.(*ast.TypeSpec)
|
||||||
|
if !ok {
|
||||||
|
ColorLog("Unknown type without TypeSec: %v\n", d)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
// TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc...
|
||||||
|
st, ok := ts.Type.(*ast.StructType)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
m.Title = k
|
||||||
|
if st.Fields.List != nil {
|
||||||
|
m.Properties = make(map[string]swagger.Propertie)
|
||||||
|
for _, field := range st.Fields.List {
|
||||||
|
isSlice, realType, sType := typeAnalyser(field)
|
||||||
|
*realTypes = append(*realTypes, realType)
|
||||||
|
mp := swagger.Propertie{}
|
||||||
|
if isSlice {
|
||||||
|
mp.Type = "array"
|
||||||
|
if isBasicType(realType) {
|
||||||
|
typeFormat := strings.Split(sType, ":")
|
||||||
|
mp.Items = &swagger.Propertie{
|
||||||
|
Type: typeFormat[0],
|
||||||
|
Format: typeFormat[1],
|
||||||
}
|
}
|
||||||
st, ok := ts.Type.(*ast.StructType)
|
} else {
|
||||||
if !ok {
|
mp.Items = &swagger.Propertie{
|
||||||
continue
|
Ref: "#/definitions/" + realType,
|
||||||
}
|
}
|
||||||
m.Title = k
|
}
|
||||||
if st.Fields.List != nil {
|
} else {
|
||||||
m.Properties = make(map[string]swagger.Propertie)
|
if isBasicType(realType) {
|
||||||
for _, field := range st.Fields.List {
|
typeFormat := strings.Split(sType, ":")
|
||||||
isSlice, realType, sType := typeAnalyser(field)
|
mp.Type = typeFormat[0]
|
||||||
realTypes = append(realTypes, realType)
|
mp.Format = typeFormat[1]
|
||||||
mp := swagger.Propertie{}
|
} else if sType == "object" {
|
||||||
// add type slice
|
mp.Ref = "#/definitions/" + realType
|
||||||
if isSlice {
|
}
|
||||||
mp.Type = "array"
|
}
|
||||||
mp.Properties = make(map[string]swagger.Propertie)
|
if field.Names != nil {
|
||||||
if isBasicType(realType) {
|
|
||||||
typeFormat := strings.Split(sType, ":")
|
|
||||||
mp.Properties["items"] = swagger.Propertie{
|
|
||||||
Type: typeFormat[0],
|
|
||||||
Format: typeFormat[1],
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mp.Properties["items"] = swagger.Propertie{
|
|
||||||
Ref: "#/definitions/" + realType,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if isBasicType(realType) {
|
|
||||||
typeFormat := strings.Split(sType, ":")
|
|
||||||
mp.Type = typeFormat[0]
|
|
||||||
mp.Format = typeFormat[1]
|
|
||||||
} else if sType == "object" {
|
|
||||||
mp.Ref = "#/definitions/" + realType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// dont add property if anonymous field
|
// set property name as field name
|
||||||
if field.Names != nil {
|
var name = field.Names[0].Name
|
||||||
|
|
||||||
// set property name as field name
|
// if no tag skip tag processing
|
||||||
var name = field.Names[0].Name
|
if field.Tag == nil {
|
||||||
|
m.Properties[name] = mp
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// if no tag skip tag processing
|
var tagValues []string
|
||||||
if field.Tag == nil {
|
stag := reflect.StructTag(strings.Trim(field.Tag.Value, "`"))
|
||||||
m.Properties[name] = mp
|
tag := stag.Get("json")
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var tagValues []string
|
if tag != "" {
|
||||||
stag := reflect.StructTag(strings.Trim(field.Tag.Value, "`"))
|
tagValues = strings.Split(tag, ",")
|
||||||
tag := stag.Get("json")
|
}
|
||||||
|
|
||||||
if tag != "" {
|
// dont add property if json tag first value is "-"
|
||||||
tagValues = strings.Split(tag, ",")
|
if len(tagValues) == 0 || tagValues[0] != "-" {
|
||||||
}
|
|
||||||
|
|
||||||
// dont add property if json tag first value is "-"
|
// set property name to the left most json tag value only if is not omitempty
|
||||||
if len(tagValues) == 0 || tagValues[0] != "-" {
|
if len(tagValues) > 0 && tagValues[0] != "omitempty" {
|
||||||
|
name = tagValues[0]
|
||||||
|
}
|
||||||
|
|
||||||
// set property name to the left most json tag value only if is not omitempty
|
if thrifttag := stag.Get("thrift"); thrifttag != "" {
|
||||||
if len(tagValues) > 0 && tagValues[0] != "omitempty" {
|
ts := strings.Split(thrifttag, ",")
|
||||||
name = tagValues[0]
|
if ts[0] != "" {
|
||||||
}
|
name = ts[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if required := stag.Get("required"); required != "" {
|
||||||
|
m.Required = append(m.Required, name)
|
||||||
|
}
|
||||||
|
if desc := stag.Get("description"); desc != "" {
|
||||||
|
mp.Description = desc
|
||||||
|
}
|
||||||
|
|
||||||
if thrifttag := stag.Get("thrift"); thrifttag != "" {
|
m.Properties[name] = mp
|
||||||
ts := strings.Split(thrifttag, ",")
|
}
|
||||||
if ts[0] != "" {
|
if ignore := stag.Get("ignore"); ignore != "" {
|
||||||
name = ts[0]
|
continue
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
if required := stag.Get("required"); required != "" {
|
for _, pkg := range astPkgs {
|
||||||
m.Required = append(m.Required, name)
|
for _, fl := range pkg.Files {
|
||||||
}
|
for nameOfObj, obj := range fl.Scope.Objects {
|
||||||
if desc := stag.Get("description"); desc != "" {
|
if obj.Name == fmt.Sprint(field.Type) {
|
||||||
mp.Description = desc
|
parseObject(obj, nameOfObj, m, realTypes, astPkgs)
|
||||||
}
|
|
||||||
|
|
||||||
m.Properties[name] = mp
|
|
||||||
}
|
|
||||||
if ignore := stag.Get("ignore"); ignore != "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -658,15 +727,6 @@ func getModel(str string) (pkgpath, objectname string, m swagger.Schema, realTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if m.Title == "" {
|
|
||||||
ColorLog("can't find the object: %s", str)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
if len(rootapi.Definitions) == 0 {
|
|
||||||
rootapi.Definitions = make(map[string]swagger.Schema)
|
|
||||||
}
|
|
||||||
rootapi.Definitions[objectname] = m
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
|
func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
|
||||||
|
@ -263,7 +263,7 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri
|
|||||||
|
|
||||||
var l []{{modelName}}
|
var l []{{modelName}}
|
||||||
qs = qs.OrderBy(sortFields...)
|
qs = qs.OrderBy(sortFields...)
|
||||||
if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
ml = append(ml, v)
|
ml = append(ml, v)
|
||||||
|
157
g_migration.go
157
g_migration.go
@ -25,15 +25,168 @@ import (
|
|||||||
const (
|
const (
|
||||||
MPath = "migrations"
|
MPath = "migrations"
|
||||||
MDateFormat = "20060102_150405"
|
MDateFormat = "20060102_150405"
|
||||||
|
DBPath = "database"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DBDriver interface {
|
||||||
|
generateCreateUp(tableName string) string
|
||||||
|
generateCreateDown(tableName string) string
|
||||||
|
}
|
||||||
|
|
||||||
|
type mysqlDriver struct{}
|
||||||
|
|
||||||
|
func (m mysqlDriver) generateCreateUp(tableName string) string {
|
||||||
|
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");`
|
||||||
|
return upsql
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mysqlDriver) generateCreateDown(tableName string) string {
|
||||||
|
downsql := `m.SQL("DROP TABLE ` + "`" + tableName + "`" + `")`
|
||||||
|
return downsql
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mysqlDriver) generateSQLFromFields(fields string) string {
|
||||||
|
sql, tags := "", ""
|
||||||
|
fds := strings.Split(fields, ",")
|
||||||
|
for i, v := range fds {
|
||||||
|
kv := strings.SplitN(v, ":", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
typ, tag := m.getSQLType(kv[1])
|
||||||
|
if typ == "" {
|
||||||
|
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if i == 0 && strings.ToLower(kv[0]) != "id" {
|
||||||
|
sql += "`id` int(11) NOT NULL AUTO_INCREMENT,"
|
||||||
|
tags = tags + "PRIMARY KEY (`id`),"
|
||||||
|
}
|
||||||
|
sql += "`" + snakeString(kv[0]) + "` " + typ + ","
|
||||||
|
if tag != "" {
|
||||||
|
tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sql = strings.TrimRight(sql+tags, ",")
|
||||||
|
return sql
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m mysqlDriver) getSQLType(ktype string) (tp, tag string) {
|
||||||
|
kv := strings.SplitN(ktype, ":", 2)
|
||||||
|
switch kv[0] {
|
||||||
|
case "string":
|
||||||
|
if len(kv) == 2 {
|
||||||
|
return "varchar(" + kv[1] + ") NOT NULL", ""
|
||||||
|
}
|
||||||
|
return "varchar(128) NOT NULL", ""
|
||||||
|
case "text":
|
||||||
|
return "longtext NOT NULL", ""
|
||||||
|
case "auto":
|
||||||
|
return "int(11) NOT NULL AUTO_INCREMENT", ""
|
||||||
|
case "pk":
|
||||||
|
return "int(11) NOT NULL", "PRIMARY KEY (%s)"
|
||||||
|
case "datetime":
|
||||||
|
return "datetime NOT NULL", ""
|
||||||
|
case "int", "int8", "int16", "int32", "int64":
|
||||||
|
fallthrough
|
||||||
|
case "uint", "uint8", "uint16", "uint32", "uint64":
|
||||||
|
return "int(11) DEFAULT NULL", ""
|
||||||
|
case "bool":
|
||||||
|
return "tinyint(1) NOT NULL", ""
|
||||||
|
case "float32", "float64":
|
||||||
|
return "float NOT NULL", ""
|
||||||
|
case "float":
|
||||||
|
return "float NOT NULL", ""
|
||||||
|
}
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type postgresqlDriver struct{}
|
||||||
|
|
||||||
|
func (m postgresqlDriver) generateCreateUp(tableName string) string {
|
||||||
|
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");`
|
||||||
|
return upsql
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m postgresqlDriver) generateCreateDown(tableName string) string {
|
||||||
|
downsql := `m.SQL("DROP TABLE ` + tableName + `")`
|
||||||
|
return downsql
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m postgresqlDriver) generateSQLFromFields(fields string) string {
|
||||||
|
sql, tags := "", ""
|
||||||
|
fds := strings.Split(fields, ",")
|
||||||
|
for i, v := range fds {
|
||||||
|
kv := strings.SplitN(v, ":", 2)
|
||||||
|
if len(kv) != 2 {
|
||||||
|
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
typ, tag := m.getSQLType(kv[1])
|
||||||
|
if typ == "" {
|
||||||
|
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if i == 0 && strings.ToLower(kv[0]) != "id" {
|
||||||
|
sql += "id interger serial primary key,"
|
||||||
|
}
|
||||||
|
sql += snakeString(kv[0]) + " " + typ + ","
|
||||||
|
if tag != "" {
|
||||||
|
tags = tags + fmt.Sprintf(tag, snakeString(kv[0])) + ","
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if tags != "" {
|
||||||
|
sql = strings.TrimRight(sql+" "+tags, ",")
|
||||||
|
} else {
|
||||||
|
sql = strings.TrimRight(sql, ",")
|
||||||
|
}
|
||||||
|
return sql
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m postgresqlDriver) getSQLType(ktype string) (tp, tag string) {
|
||||||
|
kv := strings.SplitN(ktype, ":", 2)
|
||||||
|
switch kv[0] {
|
||||||
|
case "string":
|
||||||
|
if len(kv) == 2 {
|
||||||
|
return "char(" + kv[1] + ") NOT NULL", ""
|
||||||
|
}
|
||||||
|
return "TEXT NOT NULL", ""
|
||||||
|
case "text":
|
||||||
|
return "TEXT NOT NULL", ""
|
||||||
|
case "auto", "pk":
|
||||||
|
return "serial primary key", ""
|
||||||
|
case "datetime":
|
||||||
|
return "TIMESTAMP WITHOUT TIME ZONE NOT NULL", ""
|
||||||
|
case "int", "int8", "int16", "int32", "int64":
|
||||||
|
fallthrough
|
||||||
|
case "uint", "uint8", "uint16", "uint32", "uint64":
|
||||||
|
return "integer DEFAULT NULL", ""
|
||||||
|
case "bool":
|
||||||
|
return "boolean NOT NULL", ""
|
||||||
|
case "float32", "float64", "float":
|
||||||
|
return "numeric NOT NULL", ""
|
||||||
|
}
|
||||||
|
return "", ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDBDriver() DBDriver {
|
||||||
|
switch driver {
|
||||||
|
case "mysql":
|
||||||
|
return mysqlDriver{}
|
||||||
|
case "postgres":
|
||||||
|
return postgresqlDriver{}
|
||||||
|
default:
|
||||||
|
panic("driver not supported")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// generateMigration generates migration file template for database schema update.
|
// generateMigration generates migration file template for database schema update.
|
||||||
// The generated file template consists of an up() method for updating schema and
|
// The generated file template consists of an up() method for updating schema and
|
||||||
// a down() method for reverting the update.
|
// a down() method for reverting the update.
|
||||||
func generateMigration(mname, upsql, downsql, curpath string) {
|
func generateMigration(mname, upsql, downsql, curpath string) {
|
||||||
w := NewColorWriter(os.Stdout)
|
w := NewColorWriter(os.Stdout)
|
||||||
|
migrationFilePath := path.Join(curpath, DBPath, MPath)
|
||||||
migrationFilePath := path.Join(curpath, "database", MPath)
|
|
||||||
if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) {
|
if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) {
|
||||||
// create migrations directory
|
// create migrations directory
|
||||||
if err := os.MkdirAll(migrationFilePath, 0777); err != nil {
|
if err := os.MkdirAll(migrationFilePath, 0777); err != nil {
|
||||||
|
@ -225,7 +225,7 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri
|
|||||||
|
|
||||||
var l []{{modelName}}
|
var l []{{modelName}}
|
||||||
qs = qs.OrderBy(sortFields...)
|
qs = qs.OrderBy(sortFields...)
|
||||||
if _, err := qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
|
||||||
if len(fields) == 0 {
|
if len(fields) == 0 {
|
||||||
for _, v := range l {
|
for _, v := range l {
|
||||||
ml = append(ml, v)
|
ml = append(ml, v)
|
||||||
|
122
g_scaffold.go
122
g_scaffold.go
@ -1,9 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import "strings"
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func generateScaffold(sname, fields, currpath, driver, conn string) {
|
func generateScaffold(sname, fields, currpath, driver, conn string) {
|
||||||
ColorLog("[INFO] Do you want to create a '%v' model? [Yes|No] ", sname)
|
ColorLog("[INFO] Do you want to create a '%v' model? [Yes|No] ", sname)
|
||||||
@ -31,11 +28,13 @@ func generateScaffold(sname, fields, currpath, driver, conn string) {
|
|||||||
upsql := ""
|
upsql := ""
|
||||||
downsql := ""
|
downsql := ""
|
||||||
if fields != "" {
|
if fields != "" {
|
||||||
upsql = `m.SQL("CREATE TABLE ` + sname + "(" + generateSQLFromFields(fields) + `)");`
|
dbMigrator := newDBDriver()
|
||||||
downsql = `m.SQL("DROP TABLE ` + "`" + sname + "`" + `")`
|
upsql = dbMigrator.generateCreateUp(sname)
|
||||||
if driver == "" {
|
downsql = dbMigrator.generateCreateDown(sname)
|
||||||
downsql = strings.Replace(downsql, "`", "", -1)
|
//todo remove
|
||||||
}
|
//if driver == "" {
|
||||||
|
// downsql = strings.Replace(downsql, "`", "", -1)
|
||||||
|
//}
|
||||||
}
|
}
|
||||||
generateMigration(sname, upsql, downsql, currpath)
|
generateMigration(sname, upsql, downsql, currpath)
|
||||||
}
|
}
|
||||||
@ -47,108 +46,3 @@ func generateScaffold(sname, fields, currpath, driver, conn string) {
|
|||||||
}
|
}
|
||||||
ColorLog("[INFO] All done! Don't forget to add beego.Router(\"/%v\" ,&controllers.%vController{}) to routers/route.go\n", sname, strings.Title(sname))
|
ColorLog("[INFO] All done! Don't forget to add beego.Router(\"/%v\" ,&controllers.%vController{}) to routers/route.go\n", sname, strings.Title(sname))
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateSQLFromFields(fields string) string {
|
|
||||||
sql := ""
|
|
||||||
tags := ""
|
|
||||||
fds := strings.Split(fields, ",")
|
|
||||||
for i, v := range fds {
|
|
||||||
kv := strings.SplitN(v, ":", 2)
|
|
||||||
if len(kv) != 2 {
|
|
||||||
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
typ, tag := "", ""
|
|
||||||
switch driver {
|
|
||||||
case "mysql":
|
|
||||||
typ, tag = getSQLTypeMysql(kv[1])
|
|
||||||
case "postgres":
|
|
||||||
typ, tag = getSQLTypePostgresql(kv[1])
|
|
||||||
default:
|
|
||||||
typ, tag = getSQLTypeMysql(kv[1])
|
|
||||||
}
|
|
||||||
if typ == "" {
|
|
||||||
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if i == 0 && strings.ToLower(kv[0]) != "id" {
|
|
||||||
switch driver {
|
|
||||||
case "mysql":
|
|
||||||
sql = sql + "`id` int(11) NOT NULL AUTO_INCREMENT,"
|
|
||||||
tags = tags + "PRIMARY KEY (`id`),"
|
|
||||||
case "postgres":
|
|
||||||
sql = sql + "id interger serial primary key,"
|
|
||||||
default:
|
|
||||||
sql = sql + "`id` int(11) NOT NULL AUTO_INCREMENT,"
|
|
||||||
tags = tags + "PRIMARY KEY (`id`),"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sql = sql + "`" + snakeString(kv[0]) + "` " + typ + ","
|
|
||||||
if tag != "" {
|
|
||||||
tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + ","
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if driver == "postgres" {
|
|
||||||
sql = strings.Replace(sql, "`", "", -1)
|
|
||||||
tags = strings.Replace(tags, "`", "", -1)
|
|
||||||
}
|
|
||||||
sql = strings.TrimRight(sql+tags, ",")
|
|
||||||
return sql
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSQLTypeMysql(ktype string) (tp, tag string) {
|
|
||||||
kv := strings.SplitN(ktype, ":", 2)
|
|
||||||
switch kv[0] {
|
|
||||||
case "string":
|
|
||||||
if len(kv) == 2 {
|
|
||||||
return "varchar(" + kv[1] + ") NOT NULL", ""
|
|
||||||
}
|
|
||||||
return "varchar(128) NOT NULL", ""
|
|
||||||
case "text":
|
|
||||||
return "longtext NOT NULL", ""
|
|
||||||
case "auto":
|
|
||||||
return "int(11) NOT NULL AUTO_INCREMENT", ""
|
|
||||||
case "pk":
|
|
||||||
return "int(11) NOT NULL", "PRIMARY KEY (%s)"
|
|
||||||
case "datetime":
|
|
||||||
return "datetime NOT NULL", ""
|
|
||||||
case "int", "int8", "int16", "int32", "int64":
|
|
||||||
fallthrough
|
|
||||||
case "uint", "uint8", "uint16", "uint32", "uint64":
|
|
||||||
return "int(11) DEFAULT NULL", ""
|
|
||||||
case "bool":
|
|
||||||
return "tinyint(1) NOT NULL", ""
|
|
||||||
case "float32", "float64":
|
|
||||||
return "float NOT NULL", ""
|
|
||||||
case "float":
|
|
||||||
return "float NOT NULL", ""
|
|
||||||
}
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSQLTypePostgresql(ktype string) (tp, tag string) {
|
|
||||||
kv := strings.SplitN(ktype, ":", 2)
|
|
||||||
switch kv[0] {
|
|
||||||
case "string":
|
|
||||||
if len(kv) == 2 {
|
|
||||||
return "char(" + kv[1] + ") NOT NULL", ""
|
|
||||||
}
|
|
||||||
return "TEXT NOT NULL", ""
|
|
||||||
case "text":
|
|
||||||
return "TEXT NOT NULL", ""
|
|
||||||
case "auto", "pk":
|
|
||||||
return "serial primary key", ""
|
|
||||||
case "datetime":
|
|
||||||
return "TIMESTAMP WITHOUT TIME ZONE NOT NULL", ""
|
|
||||||
case "int", "int8", "int16", "int32", "int64":
|
|
||||||
fallthrough
|
|
||||||
case "uint", "uint8", "uint16", "uint32", "uint64":
|
|
||||||
return "integer DEFAULT NULL", ""
|
|
||||||
case "bool":
|
|
||||||
return "boolean NOT NULL", ""
|
|
||||||
case "float32", "float64", "float":
|
|
||||||
return "numeric NOT NULL", ""
|
|
||||||
}
|
|
||||||
return "", ""
|
|
||||||
}
|
|
||||||
|
22
new.go
22
new.go
@ -56,26 +56,16 @@ func init() {
|
|||||||
|
|
||||||
func createApp(cmd *Command, args []string) int {
|
func createApp(cmd *Command, args []string) int {
|
||||||
ShowShortVersionBanner()
|
ShowShortVersionBanner()
|
||||||
|
|
||||||
w := NewColorWriter(os.Stdout)
|
w := NewColorWriter(os.Stdout)
|
||||||
|
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
ColorLog("[ERRO] Argument [appname] is missing\n")
|
ColorLog("[ERRO] Argument [appname] is missing\n")
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
apppath, packpath, err := checkEnv(args[0])
|
||||||
gps := GetGOPATHs()
|
if err != nil {
|
||||||
if len(gps) == 0 {
|
fmt.Println(err)
|
||||||
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
|
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
// In case of multiple paths in the GOPATH, by default
|
|
||||||
// we use the first path
|
|
||||||
gopath := gps[0]
|
|
||||||
Debugf("GOPATH: %s", gopath)
|
|
||||||
|
|
||||||
gosrcpath := path.Join(gopath, "src") // User's workspace
|
|
||||||
apppath := path.Join(gosrcpath, args[0])
|
|
||||||
|
|
||||||
if isExist(apppath) {
|
if isExist(apppath) {
|
||||||
ColorLog("[ERRO] Path (%s) already exists\n", apppath)
|
ColorLog("[ERRO] Path (%s) already exists\n", apppath)
|
||||||
@ -119,13 +109,13 @@ func createApp(cmd *Command, args []string) int {
|
|||||||
WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl)
|
WriteToFile(path.Join(apppath, "views", "index.tpl"), indextpl)
|
||||||
|
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers", "router.go"), "\x1b[0m")
|
||||||
WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
|
WriteToFile(path.Join(apppath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packpath, -1))
|
||||||
|
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "tests", "default_test.go"), "\x1b[0m")
|
||||||
WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
|
WriteToFile(path.Join(apppath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packpath, -1))
|
||||||
|
|
||||||
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
|
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
|
||||||
WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/"), -1))
|
WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1))
|
||||||
|
|
||||||
ColorLog("[SUCC] New application successfully created!\n")
|
ColorLog("[SUCC] New application successfully created!\n")
|
||||||
return 0
|
return 0
|
||||||
|
15
run.go
15
run.go
@ -24,7 +24,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var cmdRun = &Command{
|
var cmdRun = &Command{
|
||||||
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-tags=goBuildTags]",
|
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-tags=goBuildTags] [-runmode=BEEGO_RUNMODE]",
|
||||||
Short: "run the app and start a Web server for development",
|
Short: "run the app and start a Web server for development",
|
||||||
Long: `
|
Long: `
|
||||||
Run command will supervise the file system of the beego project using inotify,
|
Run command will supervise the file system of the beego project using inotify,
|
||||||
@ -51,6 +51,8 @@ var (
|
|||||||
vendorWatch bool
|
vendorWatch bool
|
||||||
// Current user workspace
|
// Current user workspace
|
||||||
currentGoPath string
|
currentGoPath string
|
||||||
|
// Current runmode
|
||||||
|
runmode string
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -61,6 +63,7 @@ func init() {
|
|||||||
cmdRun.Flag.Var(&excludedPaths, "e", "Excluded paths[].")
|
cmdRun.Flag.Var(&excludedPaths, "e", "Excluded paths[].")
|
||||||
cmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Watch vendor folder")
|
cmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Watch vendor folder")
|
||||||
cmdRun.Flag.StringVar(&buildTags, "tags", "", "Build tags (https://golang.org/pkg/go/build/)")
|
cmdRun.Flag.StringVar(&buildTags, "tags", "", "Build tags (https://golang.org/pkg/go/build/)")
|
||||||
|
cmdRun.Flag.StringVar(&runmode, "runmode", "", "Set BEEGO_RUNMODE env variable.")
|
||||||
exit = make(chan bool)
|
exit = make(chan bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,6 +103,16 @@ func runApp(cmd *Command, args []string) int {
|
|||||||
|
|
||||||
Debugf("current path:%s\n", currpath)
|
Debugf("current path:%s\n", currpath)
|
||||||
|
|
||||||
|
if runmode == "prod" || runmode == "dev"{
|
||||||
|
os.Setenv("BEEGO_RUNMODE", runmode)
|
||||||
|
ColorLog("[INFO] Using '%s' as 'runmode'\n", os.Getenv("BEEGO_RUNMODE"))
|
||||||
|
}else if runmode != ""{
|
||||||
|
os.Setenv("BEEGO_RUNMODE", runmode)
|
||||||
|
ColorLog("[WARN] Using '%s' as 'runmode'\n", os.Getenv("BEEGO_RUNMODE"))
|
||||||
|
}else if os.Getenv("BEEGO_RUNMODE") != ""{
|
||||||
|
ColorLog("[WARN] Using '%s' as 'runmode'\n", os.Getenv("BEEGO_RUNMODE"))
|
||||||
|
}
|
||||||
|
|
||||||
err := loadConfig()
|
err := loadConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
|
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
|
||||||
|
12
rundocs.go
12
rundocs.go
@ -20,6 +20,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cmdRundocs = &Command{
|
var cmdRundocs = &Command{
|
||||||
@ -120,6 +121,7 @@ func unzipAndDelete(src string) error {
|
|||||||
}
|
}
|
||||||
defer r.Close()
|
defer r.Close()
|
||||||
|
|
||||||
|
rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger")
|
||||||
for _, f := range r.File {
|
for _, f := range r.File {
|
||||||
rc, err := f.Open()
|
rc, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -127,11 +129,12 @@ func unzipAndDelete(src string) error {
|
|||||||
}
|
}
|
||||||
defer rc.Close()
|
defer rc.Close()
|
||||||
|
|
||||||
|
fname := rp.Replace(f.Name)
|
||||||
if f.FileInfo().IsDir() {
|
if f.FileInfo().IsDir() {
|
||||||
os.MkdirAll(f.Name, f.Mode())
|
os.MkdirAll(fname, f.Mode())
|
||||||
} else {
|
} else {
|
||||||
f, err := os.OpenFile(
|
f, err := os.OpenFile(
|
||||||
f.Name, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -143,11 +146,6 @@ func unzipAndDelete(src string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os.RemoveAll("swagger")
|
|
||||||
err = os.Rename("swagger-"+swaggerVersion, "swagger")
|
|
||||||
if err != nil {
|
|
||||||
ColorLog("[%s]Rename swagger-%s to swagger:%s\n", ERRO, swaggerVersion, err)
|
|
||||||
}
|
|
||||||
ColorLog("[%s]Start delete src file %s\n", INFO, src)
|
ColorLog("[%s]Start delete src file %s\n", INFO, src)
|
||||||
return os.RemoveAll(src)
|
return os.RemoveAll(src)
|
||||||
}
|
}
|
||||||
|
31
watch.go
31
watch.go
@ -17,14 +17,14 @@ package main
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/howeyc/fsnotify"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"regexp"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/howeyc/fsnotify"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -47,8 +47,8 @@ func NewWatcher(paths []string, files []string, isgenerate bool) {
|
|||||||
case e := <-watcher.Event:
|
case e := <-watcher.Event:
|
||||||
isbuild := true
|
isbuild := true
|
||||||
|
|
||||||
// Skip TMP files for Sublime Text.
|
// Skip ignored files
|
||||||
if checkTMPFile(e.Name) {
|
if shouldIgnoreFile(e.Name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !checkIfWatchExt(e.Name) {
|
if !checkIfWatchExt(e.Name) {
|
||||||
@ -230,15 +230,30 @@ func Start(appname string) {
|
|||||||
started <- true
|
started <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkTMPFile returns true if the event was for TMP files.
|
// Should ignore filenames generated by
|
||||||
func checkTMPFile(name string) bool {
|
// Emacs, Vim or SublimeText
|
||||||
if strings.HasSuffix(strings.ToLower(name), ".tmp") {
|
func shouldIgnoreFile(filename string) bool {
|
||||||
return true
|
for _, regex := range ignoredFilesRegExps {
|
||||||
|
r, err := regexp.Compile(regex)
|
||||||
|
if err != nil {
|
||||||
|
panic("Could not compile the regex: " + regex)
|
||||||
|
}
|
||||||
|
if r.MatchString(filename) {
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
var watchExts = []string{".go"}
|
var watchExts = []string{".go"}
|
||||||
|
var ignoredFilesRegExps = []string{
|
||||||
|
`.#(\w+).go`,
|
||||||
|
`.(\w+).go.swp`,
|
||||||
|
`(\w+).go~`,
|
||||||
|
`(\w+).tmp`,
|
||||||
|
}
|
||||||
|
|
||||||
// checkIfWatchExt returns true if the name HasSuffix <watch_ext>.
|
// checkIfWatchExt returns true if the name HasSuffix <watch_ext>.
|
||||||
func checkIfWatchExt(name string) bool {
|
func checkIfWatchExt(name string) bool {
|
||||||
|
Loading…
Reference in New Issue
Block a user