1
0
mirror of https://github.com/beego/bee.git synced 2024-06-02 05:53:28 +00:00

Compare commits

...

571 Commits

Author SHA1 Message Date
Ming Deng
a106dd6ba2
Merge pull request #858 from beego/develop
Prepare v2.1.0
2023-07-31 22:42:46 +08:00
Ming Deng
c8ccbb7e70
Merge pull request #857 from flycash/develop
upgrade beego version to v2.1.0
2023-07-31 22:41:33 +08:00
Deng Ming
07a06e75cc upgrade beego version to v2.1.0 2023-07-31 22:39:40 +08:00
Ming Deng
2d3dae7fa0
Merge pull request #856 from flycash/develop
upgrade the delve version
2023-06-10 23:23:54 +08:00
Deng Ming
e879c37436 upgrade the delve version 2023-06-10 23:22:24 +08:00
Ming Deng
0db82ee3bb
Merge pull request #852 from rpsteinbrueck/patch-2
updating readme - installation and bee dockerize
2023-06-10 23:16:28 +08:00
RS
0420c775cf
updating readme - installation and bee dockerize
- updating install commands since go get is deprecated (https://go.dev/doc/go-get-install-deprecation)
- updating bee dockerize example, since docker-compose yaml file gets created since https://github.com/beego/bee/pull/850
2023-05-02 21:09:59 +02:00
Ming Deng
969ce1d1eb
Merge pull request #851 from beego/develop
Prepare Release v2.0.5
2023-04-10 16:41:17 +08:00
Ming Deng
95cab0c26f
Merge pull request #850 from rpsteinbrueck/patch-1
Update dockerize.go
2023-04-10 16:39:33 +08:00
RS
01569d265c
Update dockerize.go
- gedep is deprecated. (https://github.com/tools/godep)
  thus Dockerfile not building due to the following error:
  => ERROR [2/6] RUN go get github.com/tools/godep
  ...
  'go get' is no longer supported outside a module.


main changes in this commit
- Changed outdated Dockerfile in dockerBuildTemplate
- hardcoding baseimage version "golang:1.20.2" because this version is latest (At the time of this commit) and working 
- used Dockerfile examples from official golang image on docker.com (https://docs.docker.com/language/golang/build-images/ & https://hub.docker.com/_/golang)
- Also added new feature to generate docker-compose.yaml, which uses the generated Dockerfile as a build
- docker-compose up -d works with Docker Compose version v2.17.2
- changed and tested expose ports - working for Dockerfile and docker-compose.yaml
2023-04-02 03:40:14 +02:00
Ming Deng
0cf9bdde10
Merge pull request #847 from rpsteinbrueck/patch-1
beeLogger lib missing in import list for var apiMainconngo
2023-03-30 19:34:26 +08:00
RS
5aa9764e55
Update apiapp.go
Clearly main function for var apiMainconngo uses "beeLogger.Log.Fatal("%s", err", resulting in an error when executing bee run. Issue is resolved by adding lib "beeLogger "github.com/beego/bee/v2/logger" to var apiMainconngo's import list.
2023-03-19 23:27:34 +01:00
Ming Deng
ebb8c0ad31
Merge pull request #835 from epicsagas/develop
fix: change example beego site url on default controller
2022-07-30 15:36:20 +08:00
Sangseng Lee
8c91192dae
Merge pull request #1 from epicsagas/epicsagas-patch-1
fix: change site url on default controller
2022-07-29 10:37:12 +09:00
Sangseng Lee
d78f259fdf
fix: change site url on default controller 2022-07-29 10:36:30 +09:00
Ming Deng
22ea0fa345
Merge pull request #827 from beego/develop
Release v2.0.4
2022-06-12 10:54:39 +08:00
Ming Deng
ef570ffb7b
Merge pull request #826 from flycash/develop
upgrade to v2.0.4
2022-06-12 10:53:36 +08:00
Deng Ming
651d604cca upgrade to v2.0.4 2022-06-12 10:52:09 +08:00
Ming Deng
f9d0af2146
Merge pull request #824 from flycash/develop
fix Beego#4972: bee version failed
2022-06-10 19:04:27 +08:00
Deng Ming
afe1678459 fix Beego#4972: bee version failed 2022-06-10 19:02:53 +08:00
Ming Deng
a75a0c8723
Merge pull request #822 from flycash/develop
Prepare release v2.0.3
2022-05-23 22:03:25 +08:00
zhangqz
97df75a28c fix required struct tag when anonymous nested struct 2022-05-23 22:01:34 +08:00
Ming Deng
d04f11c57a Fix 767 2022-05-23 22:01:34 +08:00
Ming Deng
d7fcaf0921
Merge pull request #820 from flycash/develop
upgrade Beego to v2.0.3
2022-05-23 21:58:21 +08:00
Deng Ming
7ee363657f upgrade Beego to v2.0.3 2022-05-23 21:55:10 +08:00
Ming Deng
1b4f90114a
Merge pull request #817 from xinyidev/develop
fix struct comment
2022-05-23 21:37:46 +08:00
xinyi
47e6e7c145
Create go.yml 2022-04-25 10:43:30 +08:00
xinyi
50ffa7ed8c fix struct comment 2022-04-24 19:22:39 +08:00
Ming Deng
8a299fa755
Merge pull request #814 from flycash/develop
bump up beego to v2.0.2, bump up swagger ui to v4.6.1
2022-03-10 00:12:20 +08:00
Deng Ming
e3d0b640df bump up beego to v2.0.2, bump up swagger ui to v4.6.1 2022-03-10 00:10:04 +08:00
Ming Deng
8f8166b3da
Merge pull request #803 from DandDevy/patch-1
Fix description of the new command
2021-09-18 23:08:58 +08:00
Daniel Ashcroft
1a47e0e945
Fix description of the new command 2021-09-17 01:26:52 +01:00
Ming Deng
9a9dbc0d78
Merge pull request #802 from GeekTree0101/bug/Geektree0101/fix-bold-attribute
[Bug] Bold message should be end with all attributes off(\x1b[0m)
2021-09-02 22:32:00 +08:00
Geektree0101
3b15b101e2 Bold message should be end with all attributes off(\x1b[0m) 2021-09-02 22:32:17 +09:00
Ming Deng
0d739375d1
Merge pull request #796 from DataSttructure/develop
fix cmd api bug
2021-08-13 23:03:21 +08:00
DataSttructure
c36f132fd8
Merge pull request #1 from DataSttructure/DataSttructure-patch-1
Update apiapp.go
2021-08-12 17:59:36 +08:00
DataSttructure
e22201eae3
Update apiapp.go
Add error handling for beego.AppConfig.String("sqlconn") in line 102
2021-08-12 17:57:59 +08:00
Ming Deng
bdeabd3b70
Merge pull request #794 from jianzhiyao/patch-1
fix command "bee fix -t 2"
2021-08-05 18:32:44 +08:00
jianzhiyao
112769d885
Update fix1To2.go 2021-08-05 18:31:53 +08:00
jianzhiyao
97e66f3d18
fix command "bee fix -t 2"
due to import developing branch of beego
2021-08-05 18:26:46 +08:00
Ming Deng
ee7b335232
Merge pull request #715 from jackywu/develop
fixbug: ignore tag did not works; set property type to the second tag…
2021-06-28 21:01:24 +08:00
Ming Deng
5bbc43e153
Merge pull request #789 from y4h2/develop
fix lint | with uncoditional strings.Replace
2021-06-17 23:09:25 +08:00
Yu Huang
d0cfcd96ba fix lint with uncoditional strings.Replace 2021-06-17 11:02:31 -04:00
Ming Deng
d63e07087c
Merge pull request #780 from flycash/develop
Remove Beego version because when we use GO mod, we can not know specific project's beego version
2021-05-08 19:40:01 +08:00
Ming Deng
6b1c370fd0 Fix static check 2021-05-07 21:10:49 +08:00
Ming Deng
7b3d1b5f64 Remove Beego version because when we use GO mod, we can not know specific project's beego version 2021-05-06 22:58:31 +08:00
Ming Deng
457c2f7dc8
Merge pull request #779 from RedBoneZhang/Branch_master
fix required struct tag when anonymous nested struct
2021-04-30 07:36:48 -07:00
Ming Deng
551d7cb8d3 go mod tidy 2021-04-30 22:26:23 +08:00
zhangqz
665150ec64 fix required struct tag when anonymous nested struct 2021-04-30 14:14:47 +08:00
Ming Deng
f73ad3252b
Merge pull request #768 from flycash/master
Fix 767
2021-03-29 23:21:48 +08:00
Ming Deng
844823a367 Fix 767 2021-03-29 23:11:14 +08:00
Ming Deng
cbb523325d
Merge pull request #762 from flycash/generateRouters
Add bee generate routers command
2021-02-09 23:54:59 +08:00
Ming Deng
22a4b07b4a Add bee generate routers command 2021-02-09 23:34:45 +08:00
Ming Deng
0a690decfb
Merge pull request #606 from LnZd/feature/analyse-import-pkg
search package from import paths, while missing type object
2021-02-09 20:11:41 +08:00
Ming Deng
21f42e22a4
Merge pull request #603 from LnZd/fix-required-tag
Fix required struct tag
2021-02-09 19:48:53 +08:00
John
9428a53176 fix test case 2021-02-07 10:54:57 +08:00
John
824fa639f0 add more test case 2021-02-07 10:47:42 +08:00
John
637637efb2 add copyright comment 2021-02-06 20:32:17 +08:00
John
7f80477761 update .travis.yml 2021-02-06 20:22:14 +08:00
John
d995fc5328 add unit test 2021-02-06 20:10:12 +08:00
John
02a66c7bd7 change log level 2021-02-06 19:44:32 +08:00
John
9541046a29 load package from ouside of the project 2021-02-05 09:44:52 +08:00
John
d0bc4f76fc
Merge branch 'develop' into fix-required-tag 2021-01-28 19:48:23 +08:00
John
100f0af03a
Merge branch 'develop' into feature/analyse-import-pkg 2021-01-28 19:45:53 +08:00
Ming Deng
3a727232d7
Merge pull request #760 from wangle201210/develop
Template url customization
2021-01-11 23:40:50 +08:00
王厚伟
29e2203ba1 optimization bee pro gen url 2021-01-11 00:24:24 +08:00
王厚伟
a44ef93f99 接收不同git仓库 2021-01-08 02:09:11 +08:00
Ming Deng
88101ce7a5
Merge pull request #759 from zyt312074545/fix/help_info
fix help message
2020-12-29 09:36:36 +08:00
zyt312074545
6f2d624a32 fix help message 2020-12-29 00:04:09 +08:00
Ming Deng
734d77f60d
Merge pull request #758 from higker/develop
fix generate case problem.
2020-12-28 20:47:39 +08:00
Jarvib Ding
e9edae7563
remove commit go.sum file 2020-12-28 18:13:20 +08:00
Dings
7db43f16d5 fix generate case problem. 2020-12-27 15:56:23 +08:00
Ming Deng
6c17de3436
Merge pull request #757 from flycash/updateMd
add quick start
2020-12-24 22:44:35 +08:00
Ming Deng
ea846e1ec6 add quick start 2020-12-24 21:51:33 +08:00
Ming Deng
ee56934371
Merge pull request #719 from wangle201210/develop
add command "bee pro toml" for create beegopro.toml
2020-12-23 20:49:12 +08:00
王厚伟
f150956981 fix readme 2020-12-22 23:52:19 +08:00
王厚伟
adbc0af183 Merge branch 'develop-up' into develop
# Conflicts:
#	README.md
#	cmd/commands/update/update.go
#	cmd/commands/version/banner.go
2020-12-22 22:17:05 +08:00
Ming Deng
639eccfef9
Merge pull request #756 from flycash/updateMd
Fix beego#4377
2020-12-19 20:52:19 +08:00
Ming Deng
486ac49f38 Fix beego#4377 2020-12-19 20:06:27 +08:00
Ming Deng
9f04de468a
Merge pull request #755 from beego/develop
Using v2.0.2
2020-12-16 14:54:35 +08:00
Ming Deng
31930ecd29
Merge pull request #754 from flycash/updateMd
updating version
2020-12-16 14:38:49 +08:00
Ming Deng
037f319c11 updating version 2020-12-16 14:17:35 +08:00
Ming Deng
4eb58f534b
Merge pull request #752 from beego/develop
Develop to master
2020-12-16 14:11:38 +08:00
Ming Deng
3b2304a480
Merge pull request #753 from flycash/updateMd
upgrade version to 2
2020-12-16 13:54:19 +08:00
Ming Deng
06e09b0f87 upgrade version to 2 2020-12-16 13:35:23 +08:00
Ming Deng
8eb7a2dfaf
Merge pull request #750 from flycash/updateMd
Using 2.0.1
2020-12-14 17:08:52 +08:00
Ming Deng
ebb2fee3fc Using 2.0.1 2020-12-14 17:06:10 +08:00
Ming Deng
d1611db053
Merge pull request #749 from flycash/updateMd
Fix Bee fix
2020-12-14 16:37:20 +08:00
Ming Deng
c93bda1d3c Fix Bee 2020-12-14 16:25:27 +08:00
Ming Deng
642d933c4a
Merge pull request #747 from flycash/updateMd
using beego v2
2020-12-14 13:20:03 +08:00
Ming Deng
c693549cc6 Fix pro path 2020-12-14 13:13:50 +08:00
Ming Deng
cdb41fad3f using beego v2 2020-12-14 13:08:47 +08:00
Ming Deng
c619ccf1b3
Merge pull request #746 from flycash/updateMd
Using beego/beego
2020-12-14 01:04:08 +08:00
Ming Deng
9d68c302bd Using beego/beego 2020-12-14 00:47:33 +08:00
Ming Deng
958e4564d1
Merge pull request #743 from 1920853199/develop
fix issues #730 bee generate appcode [index out of range [2] with length 0]
2020-12-03 23:54:21 +08:00
chenli
e3e1a9849f fix 2020-12-03 22:01:24 +08:00
chenli
32230de2ea fix issues #730 2020-12-02 23:02:26 +08:00
王厚伟
b8213eba24 add InitToml and fmt code 2020-11-26 14:15:00 +08:00
王厚伟
62abed87e9 change readme 2020-11-26 14:01:59 +08:00
王厚伟
9c423bbc97 merge 2.0 2020-11-26 13:58:15 +08:00
Ming Deng
1653a01eaa
Merge pull request #741 from flycash/updateMd
update beego version
2020-11-26 13:54:05 +08:00
Ming Deng
bc846b254e Update to v1.12.3 2020-11-25 21:01:30 +08:00
Ming Deng
62c20031a1 update beego version 2020-11-25 20:56:37 +08:00
Ming Deng
a5fb1b4690
Merge pull request #737 from flycash/delve
replace github.com/gadelkareem/delve with github.com/go-delve/delve
2020-11-10 23:22:49 +08:00
Ming Deng
0080f54a08 replace github.com/gadelkareem/delve with github.com/go-delve/delve 2020-11-10 22:39:27 +08:00
Ming Deng
36e532fa4b
Merge pull request #731 from flycash/develop
using beego to rerwite all commands
2020-11-05 23:59:12 +08:00
Ming Deng
f2a93c8c75 using beego to rerwite all commands 2020-11-05 23:57:37 +08:00
Ming Deng
22b64e8157
Merge pull request #729 from flycash/develop
Fix beego module
2020-11-02 22:31:56 +08:00
Ming Deng
fa7aee4d01 Fix beego module 2020-11-02 22:26:46 +08:00
Ming Deng
1ed5c71087
Merge pull request #726 from flycash/develop
Bee fix command support v2.x
2020-10-15 22:18:10 +08:00
Ming Deng
29e5fadf6a Bee fix command 2020-10-15 22:10:45 +08:00
Ming Deng
9f1d5fc5eb
Merge pull request #725 from flycash/develop
add dev githook command
2020-10-10 08:53:19 +08:00
Ming Deng
e0fd237002 add dev githook command 2020-10-09 23:35:22 +08:00
Ming Deng
f5665162f7
Merge pull request #724 from flycash/develop
Bee new using v2.0 beego
2020-10-09 22:42:03 +08:00
Ming Deng
cef7185b35 Bee new using v2.0 beego 2020-10-07 16:36:04 +08:00
wangle
1605bacc9e fix 2020-09-15 00:14:34 +08:00
wangle
3ea61a8926 update readme.md 2020-09-15 00:09:05 +08:00
wangle
674b52a732 change updatedTime to publishedTime 2020-09-15 00:05:38 +08:00
wangle
7a7357a983 print lastPushedTime & update readme.md 2020-09-14 23:27:33 +08:00
wangle
81ed06ea01 get template from git when run 'bee pro toml' if template dose not exit 2020-09-11 01:03:44 +08:00
wangle
8f0badc630 add command "bee pro toml" for create beegopro.toml 2020-09-10 19:35:44 +08:00
askuy
8b942b1f22
Merge pull request #718 from wangle201210/develop
make .beego dir if don`t exist
2020-09-07 14:43:08 +08:00
wucheng
d496d26a1c revert:修复了自定义map结构的显示 2020-08-27 14:53:32 +08:00
wucheng
c0d29b0d2a 修复了自定义map结构的显示 2020-08-27 14:23:02 +08:00
wucheng
b45ded3355 添加自定义的对象显示类型 2020-08-26 17:22:57 +08:00
wucheng
2c673b7d1e support interface type 2020-08-26 11:17:09 +08:00
wucheng
53b0b68d00 使得function的Description头也可以直接多行注释 2020-08-24 10:48:59 +08:00
wucheng
2862ff48db 对@Description支持多行描述 2020-08-12 16:14:23 +08:00
wucheng
b56b3794e4 fixbug: ignore tag did not works; set property type to the second tag value only if it is not omitempty and isBasicType 2020-08-12 10:19:09 +08:00
wangle
413f4ef129 make .beego dir if don`t exist 2020-08-10 22:46:29 +08:00
wangle
f0815cc9b2 Merge branch 'develop' of https://github.com/beego/bee into develop 2020-08-10 22:38:13 +08:00
wangle
732fdfa321 get bee latest version by 'https://api.github.com/repos/beego/bee/tags' 2020-08-09 15:27:37 +08:00
wangle
82e40f9010 fix the bee path 2020-08-09 15:27:37 +08:00
wangle
9c63635169 add cmd 'bee update' to update self
just notice once a day if there is a new version
2020-08-09 15:27:37 +08:00
wangle
e0ea0abf5b Automatic update bee every day
Backup only when content changes
Fix the version
2020-08-09 15:27:37 +08:00
wangle
07fa523da9 get bee latest version by 'https://api.github.com/repos/beego/bee/tags' 2020-08-02 23:02:12 +08:00
wangle
40a90af5be fix the bee path 2020-08-02 17:00:29 +08:00
wangle
e539c34ea0 add cmd 'bee update' to update self
just notice once a day if there is a new version
2020-08-02 16:17:02 +08:00
wangle
a23c76305a Automatic update bee every day
Backup only when content changes
Fix the version
2020-08-01 17:12:09 +08:00
Hanjiang Yu
c562cedf96 Internalize parsePackagesFromDir() 2020-08-01 16:24:26 +08:00
Hanjiang Yu
a68e8ae3e8 Parse AST even not in GOPATH 2020-08-01 16:24:26 +08:00
Hanjiang Yu
e0ada8860d Use go/build to resolve package path for bee generate docs 2020-08-01 16:24:26 +08:00
askuy
6a2f44720e Revert "bak file err"
This reverts commit 0e6ce7dea0.
2020-07-27 13:13:23 +08:00
askuy
3e5f9cf213 Revert "Change bee version"
This reverts commit e0ce20407c.
2020-07-27 13:13:23 +08:00
askuy
19d0116825 Revert "Backup only when content changes"
This reverts commit f601e441f3.
2020-07-27 13:13:23 +08:00
askuy
0a2c7f0c57 Revert "Compare content after formatting"
This reverts commit 174d2ab2e8.
2020-07-27 13:11:05 +08:00
askuy
59fa4ace1e Revert "Only contents in "CompareExcept" are excluded during comparison"
This reverts commit a9d3de0872.
2020-07-27 13:11:05 +08:00
wangle
a9d3de0872 Only contents in "CompareExcept" are excluded during comparison 2020-07-26 20:18:33 +08:00
wangle
174d2ab2e8 Compare content after formatting 2020-07-26 20:18:33 +08:00
qiantao
dbb41fa430 1. default gopath=false,
2. fix error work path.
2020-07-26 10:26:38 +08:00
wangle
f601e441f3 Backup only when content changes 2020-07-26 10:24:52 +08:00
wangle
e0ce20407c Change bee version 2020-07-26 10:24:52 +08:00
wangle
0e6ce7dea0 bak file err 2020-07-26 10:24:52 +08:00
askuy
13a81b8140
Merge pull request #692 from beego/feature/beegopro
repair staticcheck
2020-07-21 22:27:25 +08:00
yitea
d9633cd9af repair staticcheck 2020-07-21 22:24:42 +08:00
askuy
5005bd4408
Merge pull request #691 from beego/develop
support go mod and bee pro gen
2020-07-19 20:57:50 +08:00
askuy
b90f93409e
Merge pull request #690 from beego/feature/beegopro
Feature/beegopro
2020-07-19 20:49:28 +08:00
yitea
cc2b2d1054 bee support go mod, modify readme. 2020-07-19 20:47:18 +08:00
yitea
4637afa242 beego pro move to beego group 2020-07-18 23:08:49 +08:00
yitea
f3240109bf bee new uses go mod by default 2020-07-18 22:09:28 +08:00
yitea
8ac965a433 Merge branch 'develop' into feature/beegopro 2020-07-18 10:48:10 +08:00
yitea
adf3cc850f bee pro remove go dependence 2020-07-18 10:45:50 +08:00
qiantao
91e4ac31a4 use go env check project is go mod or not. 2020-07-18 10:45:50 +08:00
qiantao
8893ad2d13 generate go.mod skip Minor version. 2020-07-18 10:45:50 +08:00
qiantao
fccdcbbeda fix #477 2020-07-18 10:45:50 +08:00
askuy
c37857ed01
Merge pull request #687 from guhan121/develop0711
更好的检查go mod 方式;生成的go.mod 忽略Minor version
2020-07-16 23:12:49 +08:00
askuy
20b7aec77a
Merge pull request #683 from guhan121/develop
fix #477
2020-07-16 23:11:30 +08:00
yitea
2c329fd606 support beego pro migration exec sql 2020-07-11 17:44:39 +08:00
yitea
cf3c3bdc8b fix judge sql ext bug
fix orm tag bug
change the timestamp file path
2020-07-11 17:13:13 +08:00
qiantao
4158ab284e use go env check project is go mod or not. 2020-07-11 14:06:10 +08:00
qiantao
4110083cae generate go.mod skip Minor version. 2020-07-11 12:29:24 +08:00
yitea
9db1e8fb4c beego pro add mysql source type 2020-07-05 14:54:26 +08:00
yitea
8758f6eaa1 beego pro init 2020-07-04 22:58:03 +08:00
qiantao
8cceb76836 fix #477 2020-07-02 09:39:55 +08:00
askuy
bb5e0435c9
Merge pull request #674 from guhan121/develop
generate go module project
2020-06-28 22:27:39 +08:00
qiantao
9433a7b66f 1. new,api,hprose 命令增加两个参数 [-module=true] [-beego=v1.12.1] 用于生成go module项目
2. generate,migrate命令不再打印GOPATH.
3. pack命令排除。
4. run命令支持传递ldflags参数
5. fix watch file bug.ignoredFilesRegExps数组对每个文件增加$,防止目录存在tmp的情况
6. getPackagePath函数被调用时如果找不到GOPATH,则看看工程有没有go.mod 有就当做go module项目处理。
7. .travis.yml检查时排除/pkg/mod/目录
2020-06-25 22:29:27 +08:00
askuy
a780721c88
Merge pull request #573 from lyfunny/develop
gendoc bug
2020-06-23 21:56:47 +08:00
askuy
8e91f22aeb
Merge pull request #677 from beego/develop
fix go get upgrade error
2020-06-23 21:36:03 +08:00
askuy
1334a99810
Merge pull request #666 from gadelkareem/develop
fix: Fix github.com/go-delve/delve upgrade error
2020-06-20 18:27:34 +08:00
Waleed Gadelkareem
ad695cd8c6 Merge branch 'develop' of github.com:beego/bee into develop
# Conflicts:
#	cmd/commands/dlv/dlv_amd64.go
#	go.mod
#	go.sum
2020-06-20 11:58:52 +02:00
askuy
fc12eabbb6
Merge pull request #671 from beego/develop
bee upgrade version to 1.11.0
2020-06-20 12:28:43 +08:00
askuy
8ebb7977f9 bee update version 2020-06-20 12:26:28 +08:00
askuy
3121f64b8f
Merge pull request #670 from beego/develop
merge pull request from develop
2020-06-20 12:22:12 +08:00
askuy
141938e899 resolve conflict 2020-06-20 12:17:43 +08:00
askuy
dfde62c411
Merge pull request #669 from yitea/develop
update delve version
2020-06-20 11:20:16 +08:00
yitea
f7419c24fc update delve version 2020-06-20 11:13:58 +08:00
Waleed Gadelkareem
f5cc7abe8d fix: Fix github.com/go-delve/delve upgrade error 2020-06-19 20:02:57 +02:00
askuy
280d71a799
Merge pull request #665 from gadelkareem/develop
fix: Fix github.com/go-delve/delve import error and add go mod
2020-06-19 23:25:23 +08:00
Waleed Gadelkareem
b1dbdd023c fix: Fix github.com/go-delve/delve import error and add go mod 2020-06-19 17:15:22 +02:00
John
8357e26a9f fix warning 2019-05-28 16:55:07 +08:00
John
5d223c6513 update to go version 1.12.5 2019-05-28 15:45:56 +08:00
John
81ed8514be search package from import paths, while missing type object 2019-05-28 15:45:26 +08:00
John
c687a67d52 update to go version 1.12.5 2019-05-28 01:43:30 +08:00
John
f694778078 Fix required struct tag 2019-05-27 08:02:30 +08:00
Faissal Elamraoui
6a86284cec
Merge pull request #586 from cjereme/fix/infosec-output-security
Fixes #536
2019-04-11 07:34:49 +02:00
Faissal Elamraoui
6f1ff54713
Merge pull request #595 from maxshine/develop
Fix swagger docs missing schema attr for primitive body type param
2019-04-10 18:08:26 +02:00
Faissal Elamraoui
1febc2de16
Merge pull request #589 from CodeLingoBot/rewrite
Fix function comment
2019-04-10 18:04:09 +02:00
Yang, Gao
521e9a3bc0 [Fix] Fix swagger docs missing schema attr for primitive body type @Param annotation 2019-04-10 23:32:55 +08:00
CodeLingoBot
4562f47f4d Fix function comments based on best practices from Effective Go
Signed-off-by: CodeLingoBot <bot@codelingo.io>
2019-03-21 16:17:56 +13:00
cjereme
0f9b9ea345 Update loggging information on bee migrate 2019-03-07 22:14:52 -08:00
Faissal Elamraoui
36a17c40b0
Merge pull request #578 from tvanriper/patch-1
Fix for projects with 'tests' in path
2019-02-12 14:36:12 +01:00
Joseph Edwards Van Riper III
384d46897b
Fix for projects with 'tests' in path
Projects with the string 'tests' in their path cannot document their models properly in swaggergen.  The comment says the 'tests' subfolder within the dirpath should be excluded, but the test was for the full path.  This should fix the discrepancy.
2019-02-12 08:23:17 -05:00
Faissal Elamraoui
de82e68f73
Merge pull request #544 from dotSlashLu/dev
Introduce new "sqlconn" attribute into app.conf
2019-01-24 22:42:36 +01:00
Faissal Elamraoui
231e90d274 Kill the server process gracefully on Windows
See discussion in pull request #569
2019-01-23 10:21:40 +01:00
Faissal Elamraoui
4b7edb7235
Merge pull request #559 from s00500/develop
Adds  "-dir" option to migrate command to set migrations directory
2019-01-16 07:47:03 +01:00
c5099ba2a0 Update migrate description for dir option 2019-01-15 18:38:10 +01:00
LiuYang
9f600ccb45 Merge branch 'develop' of https://github.com/beego/bee into develop 2019-01-15 11:57:55 +08:00
Faissal Elamraoui
d06f56566c
Merge pull request #563 from luhuisicnu/develop
Use quoted strings in bee help api
2019-01-10 08:47:27 +01:00
Faissal Elamraoui
12019e22af
Merge pull request #569 from sangheee/develop
Kill the server process gracefully
2019-01-10 08:30:18 +01:00
Faissal Elamraoui
f7120a52bf
Merge pull request #571 from taveek/patch-2
Fix all staticcheck errors
2019-01-09 07:39:54 +01:00
Tavee Khunbida
df31f04b26 Fix accidently removed time.Sleep 2019-01-08 22:21:19 +07:00
LiuYang
ab854cc874 Update g_docs.go
bug fix
2019-01-08 12:04:02 +08:00
Tavee Khunbida
4d1304b78c Fix staticcheck failed - error strings should not be capitalized (ST1005) 2019-01-08 01:08:03 +07:00
Tavee Khunbida
22af6cc712 Fix staticcheck failed - cutset contains duplicate characters (SA1024) 2019-01-08 01:07:11 +07:00
Tavee Khunbida
f2696160ae Fix staticcheck failed - error strings should not be capitalized (ST1005) 2019-01-08 01:04:40 +07:00
Tavee Khunbida
d24c05d83e Fix staticcheck failed - should use time.Until instead of t.Sub(time.Now()) (S1024) 2019-01-08 01:03:58 +07:00
Tavee Khunbida
79d6746aa2 Fix staticcheck failed - should use time.Until instead of t.Sub(time.Now()) (S1024) 2019-01-08 01:02:14 +07:00
Tavee Khunbida
19be52dc8c Fix panic on running tests for newly generated project 2019-01-08 00:34:51 +07:00
sanghee
87a287cac2 Remove comments and add error handling 2019-01-04 23:28:36 +09:00
sanghee
8252ea9f88 When restarting, terminate process gracefully 2019-01-04 23:04:38 +09:00
Hank.Lu
babd8d04b4
Update hprose.go
db连接信息使用双引号包含
2018-12-06 15:01:38 +08:00
Hank.Lu
d3a825f92d
Merge pull request #1 from luhuisicnu/luhuisicnu-patch-1
Update apiapp.go
2018-12-06 15:00:49 +08:00
Hank.Lu
5ba90258a4
Update apiapp.go
db连接信息使用双引号包含
2018-12-06 15:00:12 +08:00
10a2e56df0 Fixing absolute path for dir option of migration 2018-11-12 13:58:15 +01:00
3d977edbb4 Adding dir parameter to migrate command 2018-11-12 13:10:43 +01:00
astaxie
10bb0454f6
Merge pull request #552 from MZIchenjl/fix-mojave-dlv
Fix delve build error on mojave
2018-10-23 17:26:53 +08:00
MZI
ebc19047f2
Fix unknown backend "" error 2018-10-14 18:28:06 +08:00
MZI
2ef722e758
Fix delve funcs 2018-10-13 21:46:20 +08:00
MZI
db6c162b03
Update vendors 2018-10-13 21:45:53 +08:00
MZI
bf5480b2df
Remove cmd dlv 2018-10-13 20:58:11 +08:00
Faissal Elamraoui
e3e401cadd
Merge pull request #550 from franzwilhelm/develop
Add support for apps outside of GOPATH with go modules, fixes #549
2018-10-08 14:00:36 +02:00
Franz von der Lippe
d63a5eb53d Fix badly created definition names 2018-10-06 23:18:32 +02:00
Franz Wilhelm von der Lippe
6689e25d6f Add support for apps outside of gopath with go modules, fixes #549 2018-10-06 13:35:26 +02:00
dotSlashLu
cb2fae3e68 cmd/api: put sqlconn to app.conf 2018-09-13 16:09:45 +08:00
dotSlashLu
393e315ba5 cmd/new: unify variable naming convention with cmd/api
camelCase should be the standard anyway
2018-09-13 14:51:09 +08:00
astaxie
f728b23527
Merge pull request #491 from beego/develop
bee 1.10.0
2018-07-22 12:13:01 +08:00
astaxie
5ed819a025 version 1.10.0 2018-07-22 12:06:22 +08:00
astaxie
b05f8ace9e update dep 2018-07-22 11:59:24 +08:00
astaxie
815bdd737a update to go version 1.10.3 2018-07-21 23:06:23 +08:00
astaxie
50e2cfbcbd Merge branch 'master' into develop 2018-07-21 23:03:47 +08:00
astaxie
1fb0bebe30
Merge pull request #516 from qida/master
Update ignoredFilesRegExps
2018-07-21 22:59:18 +08:00
astaxie
25a2684240
Merge pull request #522 from lixiangzhong/master
Update watch.go
2018-07-21 22:58:48 +08:00
astaxie
62388db728
Merge pull request #499 from ansiz/master
support bee tool workspace specify
2018-07-21 22:30:24 +08:00
astaxie
f496e0f36f
Merge pull request #526 from wilhelmguo/master
fix *time.Time type parse error.
2018-07-21 22:29:20 +08:00
astaxie
ecd8896cf3
Merge pull request #530 from Medicean/master
fix bee.json & Beefile watch_ext doesn't work
2018-07-21 22:28:38 +08:00
astaxie
2b0ceaf411
Merge pull request #535 from scf2k/nsinclude-fix
Fix docs generator to handle cases when var is passed to NSInclude()
2018-07-21 22:28:14 +08:00
astaxie
a386880832
Merge pull request #537 from wilhelmguo/master
Support extra args to run application.
2018-07-21 22:27:53 +08:00
Vladimir Alaev
7b2e95e9bd Fix docs generator to handle cases when var is passed to NSInclude() 2018-07-09 18:21:57 +03:00
wilhelmguo
6dd625232d Merge branch 'master' of v.src.corp.qihoo.net:scp/bee 2018-06-26 18:10:37 +08:00
Codeb Fan
cd82742af9 Support extra args to run application. 2018-06-26 18:07:49 +08:00
Medicean
25063a62c4 fix bee.json & Beefile watch_ext doesn't work 2018-06-11 18:01:35 +08:00
guoshaowei
bb68873f45 fix *time.Time type parse error. 2018-05-10 14:37:03 +08:00
astaxie
5c1ee91097
Merge pull request #515 from coseyo/bugfix_path
fix api path contain regex string bug
2018-04-20 16:52:15 +08:00
qida
c1896dd4cf
Update ignoredFilesRegExps
解决了在执行 `bee run -gendoc=true` 时,更新`commentsRouter_controllers.go`文件导致多次触发"build"的bug。
2018-03-27 15:08:24 +08:00
zhongyijun
cb47a5a5fe fix api path contain regex string bug 2018-03-23 14:29:39 +08:00
astaxie
b0432d7c04
Merge pull request #514 from WUMUXIAN/develop
Swagger docs generation improvement.
2018-03-18 13:43:29 +08:00
WUMUXIAN
c23138b457 Added support for ArrayType type definition. 2018-03-16 13:34:54 +08:00
Muxian Wu
611eecc204 Made the example value for enum type sensitive. 2018-03-15 18:05:37 +08:00
astaxie
be6186155f
Merge pull request #513 from WUMUXIAN/develop
Swagger Enum Fix:
2018-03-13 16:51:32 +08:00
Muxian Wu
685c16d5eb Swagger Enum Fix:
1. For now the type inference is not supported, they will be skipped.
2. The enums in the documentation will be listed based on it's position.
3. Be able to support multiple values defined.
2018-03-12 15:52:00 +08:00
astaxie
3469f0ae4c
Merge pull request #512 from WUMUXIAN/features/swagger-example-enum-support
Swagger: Enum improvement, example value improvement.
2018-03-11 10:49:57 +08:00
WUMUXIAN
d217d0b85c Swagger:
1. Improve the enum support, the enum will be in a format of "enum_name = enum_value"
2. An example value will be automatically generated.
3. Example is disabled for slice field.
2018-03-10 17:35:59 +08:00
astaxie
4ca7777c32
Merge pull request #505 from louisevanderlith/master
Convert error on Swagger Generate
2018-01-18 12:15:58 +08:00
Louise van der Lith
4f53288e6a v.Fun can't always be converted to *ast.SelectorExpr. Added a check to confirm that the object is correct. 2018-01-09 10:49:57 +02:00
astaxie
b2087846ab
Merge pull request #500 from amrfaissal/fix-travisci-badge
Fixes TravisCI badge
2018-01-01 18:39:40 +08:00
astaxie
d23d3e5bfb
Merge pull request #502 from terryding77/fix/uint_default_value_in_swagger_json
fix issue #501
2017-12-30 13:54:44 +08:00
lixz
5ba8b15e3a
Update watch.go
在window编译linux后,bee run 执行的appname为linux的可执行文件
2017-12-29 17:09:02 +08:00
Terry Ding
d70cedc7de fix issue #501 2017-12-28 00:47:14 +08:00
Faissal Elamraoui
418230b131 Fix TravisCI badge 2017-12-21 17:30:50 +01:00
xhzhang
fdf0e9c768 feat: support bee workspace specify
support bee workspace specify instead of current path only
2017-12-21 23:32:40 +08:00
ansiz
1937c6ddb7
Merge pull request #1 from beego/master
update from origin
2017-12-21 23:31:51 +08:00
astaxie
4ab8b8e30e bee 1.9.1 2017-11-27 15:51:51 +08:00
astaxie
bfeaf6c8df
Merge pull request #490 from skOak/develop
add swagger spec support for struct embedded field
2017-11-21 11:43:33 +08:00
hemin
363abeeae2 add swagger spec support for struct embedded field 2017-11-20 16:36:27 +08:00
astaxie
76a4feb17e
Merge pull request #458 from BusterMachine7/master
array的格式
2017-11-19 11:20:07 +08:00
astaxie
2265bfb0ff
Merge pull request #479 from scf2k/vendor-scan
Fix docs generator to ignore all child folders of the vendor folder
2017-11-19 11:18:32 +08:00
astaxie
e75824f797
Merge pull request #488 from ilylia/develop
support enum, except iota and type inference.
2017-11-19 11:17:39 +08:00
ilylia
4711873e25 support enum, except iota and type inference. 2017-11-13 14:29:44 +08:00
astaxie
d8cb6ff47f Merge pull request #481 from guihaojin/feature/custom-model-name
Code cleanup, remove redundant selectedTables/selectedTableNames
2017-10-23 06:52:27 -05:00
Haojin Gui
7d78224b99 Remove redundant selectedTables.
When selectedTables is not nil, we are already generating tables
from it. So we don't need to pass it further.
2017-10-20 23:32:13 -07:00
Haojin Gui
f8e9f67ae6 Add empty line. 2017-10-20 23:32:13 -07:00
Faissal Elamraoui
b94b47d7d5 Merge pull request #483 from TankTheFrank/feature/refresh-browser-on-build
Refresh browser page after binary builds
2017-10-19 15:16:45 +02:00
TankTheFrank
c34cb05355 after build the browser is refreshed 2017-10-19 14:23:08 +03:00
qida
9dc796dc1e Merge pull request #1 from beego/master
Merge
2017-10-07 09:46:16 +08:00
Vladimir Alaev
a5cddac554 Fix docs generator to ignore all child folders of the vendor folder within project dir 2017-10-04 16:54:05 +03:00
astaxie
65e995ca17 Merge pull request #476 from soonick/master
Only import the correct driver when doing a migration. Fixes #447
2017-09-25 13:00:32 +08:00
Adrian Ancona Novelo
52e3087bb4 Only import the correct driver when doing a migration. Fixes #447 2017-09-25 10:48:08 +08:00
astaxie
e90da8f77b Merge pull request #474 from beego/develop
v1.9.1
2017-09-14 08:16:02 +08:00
asta xie
ceefd74c9b v1.9.1 2017-09-12 21:23:20 +08:00
Sergey Lanzman
fbbb713465 Merge pull request #468 from hamidfzm/master
Generate multipart/form-data consumer for API doc
2017-08-18 21:21:44 +03:00
Hamid FzM
ae1f1a9bf4 Remove wrong consumer 2017-08-16 15:42:40 +04:30
Hamid FzM
2936241fe6 Update g_docs.go 2017-08-16 15:28:59 +04:30
Hamid FzM
cdec05b5e3 Generate multipart/form-data consumer for API doc 2017-08-16 14:47:07 +04:30
Sergey Lanzman
0405523d35 Merge pull request #462 from gigovich/develop
Fix #438. Fix random module matching from swagger generator.
2017-08-11 22:18:29 +03:00
astaxie
b8040300b6 Merge pull request #464 from liusy182/patch-1
Do no omit response description
2017-08-06 22:40:20 +08:00
Liu Siyuan
0a42575490 Do no omit response description
[swagger specs](https://swagger.io/docs/specification/describing-responses/) requires each response to have a description. Otherwise, ignorable error will be generated. This PR makes sure that description field is not omitted in the event that user did not give a description.
2017-08-03 17:32:46 +08:00
Givi Khojanashvili
52c8cb8b6a Fix #438. Fix random module matching from swagger generator. 2017-08-01 16:46:05 +03:00
zhangyanzhe
58bfa5c1ec array format 2017-07-19 15:49:54 +08:00
zhangyanzhe
d0b3ede4ec array format 2017-07-19 15:38:04 +08:00
zhangyanzhe
2b04261f9c array format 2017-07-19 14:47:19 +08:00
zhangyanzhe
254174eda6 array format 2017-07-19 14:42:46 +08:00
astaxie
aae0cc4587 Merge pull request #456 from beego/develop
v1.9.0
2017-07-19 00:56:52 +08:00
astaxie
3b3da1655d Merge pull request #444 from qida/develop
读取 ref(pk) 值
2017-07-19 00:31:29 +08:00
astaxie
d29f8e8ec3 Merge pull request #441 from hudangwei/develop
fix #440 only get these tables information in custom the option ‘-tab…
2017-07-19 00:30:54 +08:00
astaxie
899aede629 Merge pull request #454 from scf2k/fixscan
Fix: docs generator skips everything containing 'vendor'
2017-07-19 00:29:40 +08:00
astaxie
b65934a764 v1.9.0 2017-07-19 00:28:53 +08:00
astaxie
3523212500 bee add subcommand server 2017-07-19 00:28:12 +08:00
astaxie
1b03d81aa2 Merge pull request #455 from gnanakeethan/feature/database-migration
[Proposal] Database Migrations
2017-07-17 10:55:31 +08:00
Gnanakeethan Balasubramaniam
552111517e
Revert "Update: complementary fix for removing calling ddlSpec on migration"
The odds of getting this perfectly up is not good.

This reverts commit 3673659178.
2017-07-16 08:13:08 +05:30
Gnanakeethan Balasubramaniam
3673659178
Update: complementary fix for removing calling ddlSpec on migration
file.

Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-16 07:25:36 +05:30
Gnanakeethan Balasubramaniam
042a4cf244
Update: fixing switch statement
Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-13 21:24:53 +05:30
Gnanakeethan Balasubramaniam
ea63bf253e
UPDATE: creating ddl migration spec is now possible
SUMMARY: The DDL migration can now be generated by adding a `-ddl` and a
proper "alter" or "create" as argument value.

Migration generation had been modified to accommodate the complementary
code for ddl generation

Signed-off-by: Gnanakeethan Balasubramaniam <gnanakeethan@gmail.com>
2017-07-13 20:30:06 +05:30
Vladimir Alaev
416fb2ec9d Fix: docs generator skips everything containing 'vendor' in path which is wrong. Fixed that to skip only the 'vendor' dir directly under the project root. Also don't even scan a dir beginning with a '.'. 2017-07-12 17:23:53 +03:00
sunqida
5c3807e29a Merge remote-tracking branch 'remotes/beego/develop' into develop 2017-06-08 20:31:10 +08:00
astaxie
34faa8fca6 Merge pull request #445 from eyalpost/develop
support multiple http methods
2017-06-06 09:54:46 +08:00
Eyal Post
0099ef2f92 support multiple http methods 2017-06-05 18:19:45 +03:00
qida
681fc57e16 读取 ref(pk) 值 2017-06-05 09:34:38 +08:00
hudangwei
812b8c4e5b if tag.Comment is empty, the ORM tag string will not contain description 2017-05-30 19:43:40 +08:00
hudangwei
f5471680e4 fix tag description,add tag description by getting database table information column comment 2017-05-30 16:21:45 +08:00
astaxie
46fc9d75ae Merge pull request #443 from cfsalguero/year_type
Added MySQL year data type
2017-05-30 13:36:50 +08:00
Carlos Salguero
b4bee5cceb Added MySQL year data type 2017-05-29 15:48:57 -03:00
hudangwei
f657d22fc7 fix tag description,add tag description by getting database table information column comment 2017-05-26 13:30:28 +08:00
hudangwei
8b01334faf fix #440 only get these tables information in custom the option ‘-tables’ 2017-05-20 13:06:25 +08:00
astaxie
9e4a43f08a Merge pull request #439 from beego/develop
v1.8.4
2017-05-19 21:19:23 +08:00
astaxie
0000e7d7c9 gosimple 2017-05-19 09:41:47 +08:00
astaxie
0d0e583346 v1.8.4 2017-05-18 22:58:13 +08:00
astaxie
bacdca6037 Merge pull request #421 from eyalpost/develop
Add support for controller methods with paramaters
2017-05-18 18:28:36 +08:00
astaxie
69760a96ec Merge pull request #436 from franzwilhelm/master
Add complete swagger 3.0 security support for oauth2, apiKey and basic
2017-05-16 11:17:35 +08:00
franzwilhelm
e8c0f528a6 add ignore for staticcheck 2017-05-15 00:56:56 +02:00
franzwilhelm
fef25c2c5f add complete swagger 3.0 security support for oauth2, apiKey and basic
fix len(p) handling, add support for global security

update swagger.go in vendor, fix redundant break
2017-05-14 14:38:06 +02:00
astaxie
a1e8589798 Merge pull request #432 from dawxy/develop
Fixed an error in the basicType of pointer when the swagger document was automatically generated
2017-05-08 20:15:15 +08:00
dawxy
49d791502a Fixed an error in the basicType of pointer when the swagger document was automatically generated 2017-05-08 08:41:12 +08:00
dawxy
4ef471170e Fixed an error in the basicType of pointer when the swagger document was automatically generated 2017-05-08 08:38:06 +08:00
Sergey Lanzman
a7ff7b8615 Merge pull request #428 from futureskywei/develop
slice type generate swgger doc error fix
2017-05-05 23:19:36 +03:00
guoshaowei
50ae47c61f fix gen doc slice type bug 2017-05-05 11:31:03 +08:00
guoshaowei
3f63cd706f fix gen doc slice type bug 2017-05-05 10:59:45 +08:00
eyalpost
65aec741fb go fmt 2017-04-28 18:45:26 +03:00
astaxie
e1f3353511 add ineffassign check 2017-04-28 22:53:38 +08:00
astaxie
823dca76d5 add gofmt check for travis 2017-04-28 20:36:44 +08:00
eyalpost
a117a48d7b add support for controller methods with paramaters
- allow automatic mapping of type from method params
- generate swagger for parameters not covered by comment annotations
2017-04-26 00:10:03 +03:00
astaxie
c76d4d1451 add publish target 2017-04-24 22:55:12 +08:00
astaxie
1a79d6dcca Merge pull request #417 from beego/develop
bee 1.8.3
2017-04-24 22:00:49 +08:00
astaxie
1cc7abaac6 fix gosimple 2017-04-24 21:45:27 +08:00
astaxie
963e1c9d05 bee 1.8.3 2017-04-24 21:11:32 +08:00
astaxie
e84d6f9a9c use filepath to generate appcode 2017-04-24 21:06:31 +08:00
astaxie
ffbe29ae22 fix #2581 2017-04-24 21:00:39 +08:00
astaxie
6afbafa250 Check Gopath in one place 2017-04-24 20:51:56 +08:00
astaxie
3daa0d2639 support go1.8 default gopath 2017-04-24 20:10:52 +08:00
astaxie
94553cdca7 Merge pull request #416 from beego/develop
fix #379
2017-04-20 09:42:34 +08:00
astaxie
096cef1b6c fix #379 2017-04-20 00:26:25 +08:00
astaxie
de2656749f Merge pull request #415 from beego/develop
V1.8.2
2017-04-20 00:05:31 +08:00
astaxie
c5bc543c13 update to v1.8.2 2017-04-19 23:52:32 +08:00
astaxie
db57fa50a0 fix #400 2017-04-19 23:51:12 +08:00
astaxie
8f8ece57b0 Merge pull request #414 from beego/revert-410-develop
Revert "Develop"
2017-04-19 23:03:11 +08:00
astaxie
593ef9c47c Revert "Develop" 2017-04-19 23:02:57 +08:00
astaxie
3b316ecd81 update swagger to v3 2017-04-19 20:52:36 +08:00
astaxie
05a49939e1 fix #413 #409 2017-04-19 20:35:17 +08:00
astaxie
07ca21401c Merge pull request #410 from qida/develop
Develop
2017-04-18 20:32:26 +08:00
qida
3b0dd10302 windows下路径问题 2017-04-18 14:36:32 +08:00
qida
a353b6d69a 增加关联查询 2017-04-18 14:34:24 +08:00
Gero
1336d6b411 Fixes #401
Consider vendor folder when analyzing router.go parsed imports.
2017-04-13 18:10:00 +02:00
astaxie
52a37a86a9 Merge pull request #392 from beego/hotfix-dlv-support
Use conditional build for Delve support
2017-04-07 22:45:59 +08:00
Faissal Elamraoui
d9306e9fcf Fixes #406
Adds support for darwin/amd64 platforms but requires cgo
for cross compilation.
2017-04-07 15:56:47 +02:00
Faissal Elamraoui
a22baf1b65 Setup ignore list for gosimple 2017-04-03 00:01:23 +02:00
Faissal Elamraoui
1e478bb32e Resolves #393
When new changes are introduced, re-build the debug binary and restart
the Delve Debugger client. It also adds a verbose mode for dlv command
which notifies the user if enabled.
2017-04-02 23:37:02 +02:00
Faissal Elamraoui
f80384a9f5 Move getFileModTime() to utils package 2017-04-02 23:36:17 +02:00
Faissal Elamraoui
5600cb1c36 Fixes #389
This makes sure dlv is used for amd64 architecture. The current release
has a few problems with darwin architecture hence the conditional build
tag.
2017-03-26 16:57:19 +02:00
Faissal Elamraoui
4dd6983d3c Use Delve v0.12.1 instead of master 2017-03-26 16:55:28 +02:00
astaxie
bef9d4d5e8 Merge pull request #391 from beego/develop
Develop
2017-03-24 22:35:48 +08:00
astaxie
abf3c41032 Merge pull request #390 from ogero/develop
Fix generate swagger model api doc on Windows.
2017-03-24 22:35:15 +08:00
Gero Nimo
0cffaf8ea6 Fix generate swagger model api doc on Windows.
Add multiple gopath support for ParsePackagesFromDir.
Improves gloomyzerg@39cc0bc04e109ff0f69e73d567354d9e82b7c24c fix for #332 that got lost on some merge.
2017-03-24 05:05:00 -03:00
Sergey Lanzman
701b2e2ea8 Merge pull request #388 from beego/master
send the PR from master to develop
2017-03-23 16:01:45 +02:00
astaxie
e6bb3f893c Merge pull request #387 from beego/release_1.8.1
Release 1.8.1
2017-03-23 21:56:37 +08:00
Faissal Elamraoui
e3a67ef07f Fix conflicts & Merge branch 'develop' 2017-03-23 14:47:12 +01:00
Faissal Elamraoui
db5616465b Bump the version to 1.8.1 2017-03-23 14:30:03 +01:00
Boris Borshevsky
48c931d635 add arguments support to rs functionality (#386) 2017-03-23 11:15:53 +01:00
Faissal Elamraoui
8c0742c140 Merge pull request #384 from amrfaissal/dlv-support
Add support for Delve debugger
2017-03-22 17:01:34 +01:00
Faissal Elamraoui
072cc85708 Updated REAMDE.md 2017-03-22 11:47:39 +01:00
Faissal Elamraoui
72f144baad Refactor code for dlv command 2017-03-22 11:47:39 +01:00
Faissal Elamraoui
ad641afb34 Update vendor folder (support for Delve RPC) 2017-03-21 15:47:57 +01:00
Faissal Elamraoui
427541fcd9 Start both Delve's RPC server and terminal (as client) 2017-03-21 15:47:57 +01:00
Faissal Elamraoui
36436c0f53 Ability to execute commands using Go tool 2017-03-21 15:47:57 +01:00
Faissal Elamraoui
69023e9ae0 Merge pull request #385 from scrpgil/develop
Change to execution directory used by dockerBuildTemplate
2017-03-20 15:33:59 +01:00
scrpgil
32e7b144f9 Fix mistake of execution directory by dockerBuldTemplate 2017-03-20 22:57:09 +09:00
Faissal Elamraoui
7811c335e9 Update vendor folder (Delve support) 2017-03-19 23:48:59 +01:00
Faissal Elamraoui
f9939bc286 Add support for Delve
This adds support for debugging tool Delve. The command dlv starts a
debugging REPL that allows the user to debug his application using Delve
tool. Resolves #365.
2017-03-19 23:48:58 +01:00
Sergey Lanzman
9760ce6623 Merge pull request #382 from scrpgil/develop
fix docker build error by dockerBuildTemplate
2017-03-19 15:38:10 +02:00
scrpgil
8d646b4be1 fix docker build error by dockerBuildTemplate 2017-03-19 22:01:19 +09:00
Faissal Elamraoui
aa19ecedb0 Resolves #381 with few improvements 2017-03-18 20:11:10 +01:00
Faissal Elamraoui
77a36964e5 Adds Windows support for command execution 2017-03-18 20:10:43 +01:00
Faissal Elamraoui
855ac34dd3 Makes config.LoadConfig() silent 2017-03-18 20:05:06 +01:00
Faissal Elamraoui
e543958fe3 Improves rs command using Go templates 2017-03-18 20:04:08 +01:00
Sergey Lanzman
01703caefa delete scripts
add rs
2017-03-17 17:10:56 +02:00
Sergey Lanzman
c01a15197e Merge pull request #380 from beego/cleanup
cleanup
2017-03-17 11:06:15 +02:00
astaxie
dd3f690bf7 cleanup 2017-03-17 13:33:15 +08:00
astaxie
20c6a26952 Merge pull request #375 from amrfaissal/fix-load-config
Fixes configuration loading since last changes
2017-03-17 11:50:23 +08:00
Faissal Elamraoui
609ed8fcd5 Merge branch 'develop' into fix-load-config 2017-03-16 21:35:44 +00:00
astaxie
fd4772fe82 Merge pull request #373 from sergeylanzman/add-scripts-options
add scripts option(custom commands)
2017-03-16 23:27:10 +08:00
Faissal Elamraoui
64a8570c70 Ignore gosimple's S1024 check for go1.8 2017-03-15 17:45:51 +01:00
Faissal Elamraoui
09f53c0400 Fix staticcheck emtpy branch error 2017-03-15 17:44:29 +01:00
Faissal Elamraoui
792cb3f311 Load configuration for all commands
This removes the filepath.Walk() when loading configuration,
as it can read a Beefile from another project in the $GOPATH.
Now config.LoadConfig() is called for all available commands.
2017-03-15 15:18:33 +01:00
Faissal Elamraoui
e57cc7b94e This makes sure default config is always loaded
When loading configuration from Beefile or bee.json default values are
not loaded. This fixes that behaviour and makes sure defaults are loaded
and overrided if present in Beefile/bee.json.
2017-03-13 20:34:04 +01:00
Sergey Lanzman
3be35d9d81 Merge pull request #376 from amrfaissal/fix-notificator
Fixes desktop notificator for Windows and Linux
2017-03-13 02:54:28 +02:00
Faissal Elamraoui
6394f3f80a Fixes desktop notificator for Windows and Linux 2017-03-12 23:47:19 +00:00
Faissal Elamraoui
426237fefe Fixes configuration loading since last changes 2017-03-12 23:24:50 +00:00
Sergey Lanzman
b3ea5dda0e Merge pull request #367 from gloomyzerg/master
fix #332 swagger generate bug on windows
2017-03-12 17:24:20 +02:00
Faissal Elamraoui
4ef1a0e80e Merge pull request #374 from sergeylanzman/linters
Add Go linters
2017-03-11 22:26:07 +00:00
Sergey Lanzman
d1330dfc0b add scripts option(custom commands)
example to use:
1. Go test with custom params or other test framework like ginkgo
2. Fronted tools like grunt
3. Other custom  commands
2017-03-11 12:46:39 +02:00
Sergey Lanzman
513debab13 update travis.yml 2017-03-11 11:03:45 +02:00
Sergey Lanzman
feea8877c0 go vet
go simple
golint
structcheck
staticcheck
unused
unconvert
2017-03-11 10:57:06 +02:00
astaxie
3d5b13d84e Merge pull request #370 from sergeylanzman/make-log-for-beego-developer
Make logs for beego developer, not for  bee developer
2017-03-11 15:36:37 +08:00
Sergey Lanzman
380cce650e Update logger.go 2017-03-11 09:14:24 +02:00
astaxie
78836f0a4c Merge pull request #369 from sergeylanzman/merge-default-config-with-config-file
merge default config with config file
2017-03-11 12:24:45 +08:00
astaxie
0e79cb596e Merge pull request #368 from sergeylanzman/add-notify-on-faild-build
add notify on build fail
2017-03-11 12:23:49 +08:00
Sergey Lanzman
abf2b4a4cb 1. Make logs for beego developer not for bee developer
2. Fix debug mode
2017-03-10 20:32:22 +02:00
Sergey Lanzman
c782720cb7 merge default config with config file 2017-03-10 20:13:42 +02:00
Sergey Lanzman
dacee6ba16 add notify on fails build 2017-03-10 20:04:49 +02:00
astaxie
6dce4df2cb Merge pull request #362 from sergeylanzman/refactor
Refactor
2017-03-10 18:58:13 +08:00
gloomyzerg
39cc0bc04e fix #332 swagger generate bug on windows 2017-03-10 17:49:58 +08:00
Sergey Lanzman
c1a60c0ec3 update travis.yml 2017-03-10 11:49:31 +02:00
Sergey Lanzman
c538bfbc8f Refactor!
create sub packages
delete unused code
delete code from not use command cmdRouter,cmdTest, cmdRundocs
make command plugins
check with gosimple,staticcheck,go vet,unused,unconvert
2017-03-10 11:48:26 +02:00
Sergey Lanzman
74baba4f63 Merge pull request #3 from beego/develop
Develop
2017-03-10 11:44:26 +02:00
astaxie
9db35a8270 Merge pull request #364 from szyhf/master
给bee run增加了一个参数extra,允许watch额外的包(刚忘了要pr到develop)
2017-03-08 11:30:24 +08:00
Back Yu
cc74358320 简化参数extra为ex,并移除了多于的日志 2017-03-07 13:00:37 +08:00
Back Yu
1f6e89a670 允许run命令使用extra参数,watch额外的package。 2017-03-07 12:56:47 +08:00
astaxie
932f16ba4e Merge pull request #361 from beego/develop
bee 1.8.0
2017-03-06 21:59:08 +08:00
astaxie
8eed14a851 bee 1.8.0 2017-03-06 21:33:19 +08:00
astaxie
38f8d6fc56 Merge pull request #358 from sergeylanzman/patch-2
Swagger: add support time.Time and int16
2017-03-05 21:44:18 +08:00
Sergey Lanzman
3b5e381a48 add support time.Time and int16 2017-03-01 12:42:14 +02:00
Faissal Elamraoui
7bd1e415dd Merge pull request #357 from sergeylanzman/patch-1
Update watch.go
2017-02-26 19:12:46 +01:00
Sergey Lanzman
ee3dd8f436 Update watch.go
fix bug with reload static files
before:
on change static file bee reload web page
on change go files bee only reload web page
after:
on change static file bee reload web page
on change go files bee rebuild app without not reload web page.
2017-02-25 22:14:45 +02:00
astaxie
c2161cac3f Merge pull request #356 from radioinmyhead/patch-2
fix GOROOT
2017-02-23 22:58:17 +08:00
radioinmyhead
cf1809a64b fix GOROOT
set goroot by runtime.GOROOT if goroot is empty
2017-02-21 16:30:55 +08:00
Faissal Elamraoui
14eeb07402 Merge pull request #353 from sergeylanzman/improve-live-reload
Improve live reload by adding support for static files
2017-02-14 07:28:27 +01:00
Sergey Lanzman
b867a57d65 improve live reload 2017-02-13 23:05:32 +02:00
astaxie
268a9d8346 Merge pull request #352 from ogero/develop
Fixes #351
2017-02-13 12:34:04 +08:00
Gero
c53a621c52 Fixes #351 2017-02-11 16:54:12 -03:00
astaxie
496f162f9b Merge pull request #350 from amrfaissal/hot-reload
AutoReload support for Beego applications
2017-02-07 11:02:18 +08:00
Faissal Elamraoui
62260c1033 Generate WebSocket client in static/js 2017-01-27 16:57:37 +01:00
Faissal Elamraoui
c5f8b8d28e Add gorilla/websocket to vendor folder 2017-01-23 20:12:40 +01:00
Faissal Elamraoui
3f15b69bcc Send a reload message when AutoBuild is triggered 2017-01-22 22:28:52 +01:00
Faissal Elamraoui
de62ae6043 Start the Reload server (if enabled) 2017-01-22 22:27:20 +01:00
Faissal Elamraoui
24eee99d5b Enable reload through JSON/YAML configuration files 2017-01-22 22:24:52 +01:00
Faissal Elamraoui
4ad45b3cd7 Implements the Reload WebSocket endpoint
It hosts a WebSocket service with a single "/reload" endpoint, to which
a browser can connect to and receive payload or notification from the
server. Each notification can be handled (in the client-side) and reload
the entire web page with the new updates.
2017-01-22 22:14:29 +01:00
astaxie
848618b21e update travis 2016-12-27 20:44:17 +08:00
Faissal Elamraoui
f9d0b2f2fc Merge pull request #347 from amrfaissal/fix-hproseapp
Handle case when appname argument is missing
2016-12-27 09:50:51 +01:00
Faissal Elamraoui
0dbf0c9693 Handle case when appname argument is missing 2016-12-27 09:44:15 +01:00
astaxie
09e6fb26e2 Merge pull request #346 from Lao-liu/develop
fix bee hprose error.
2016-12-27 11:59:00 +08:00
Laoliu
20fdbe6a1a fix bee hprose error. 2016-12-27 09:01:08 +08:00
Faissal Elamraoui
3c676b602c Updated README.md 2016-12-26 22:44:27 +01:00
Faissal Elamraoui
bbe1a4efe3 Merge pull request #344 from amrfaissal/fix-183
hotfix: Configuration loading from JSON and YAML
2016-12-26 13:49:26 +01:00
Faissal Elamraoui
1799601be1 Merge pull request #345 from amrfaissal/develop
This fixes #147
2016-12-25 13:56:47 +01:00
Faissal Elamraoui
3a51d4830c This fixes #147 2016-12-25 13:53:06 +01:00
Faissal Elamraoui
e215969963 This fixes #183
Passes the conf variable by reference to JSON and YAML parsers instead of
a copy.
2016-12-25 13:24:11 +01:00
astaxie
d801cc2469 Merge pull request #343 from amrfaissal/set-version-output-format
Set the output format for bee version
2016-12-25 13:51:22 +08:00
Faissal Elamraoui
059df76c3e Set the output format for bee version
This adds the ability to set the output format (using -o flag) of bee
version command. It supports both JSON and YAML formats.
2016-12-24 14:51:14 +01:00
Faissal Elamraoui
d8b9d96d84 Merge pull request #342 from amrfaissal/bee-dockerize
Dockerize a Beego Web Application
2016-12-23 13:10:21 +01:00
Faissal Elamraoui
040b160ecd Added default base image + New layout for displaying options 2016-12-23 11:53:02 +01:00
Faissal Elamraoui
4ea1715df6 Expose more than one port
This adds the ability to expose more than one port inside the Docker
container.
2016-12-22 22:53:45 +01:00
Faissal Elamraoui
699d76bc95 Ability to specify the base image of the Docker container 2016-12-22 18:29:13 +01:00
Faissal Elamraoui
81c6de6cb3 Ability to dockerize a Beego application
This introduces a new command "dockerize" which will generate
a Dockerfile to allow a Beego Web Application to run inside Docker.
2016-12-22 18:10:45 +01:00
astaxie
77acc749e4 update vendor 2016-12-20 17:02:58 +08:00
astaxie
a02243ba7a Merge pull request #333 from vCaesar/test-pr
Update fsnotify
2016-12-20 16:58:36 +08:00
astaxie
d7433a6e39 Merge pull request #337 from sergeylanzman/add-inet-type
Add inet type for postgresql
2016-12-20 16:58:14 +08:00
astaxie
0a58d03ca0 Merge pull request #334 from amrfaissal/fix-beegen-output
Fix bee generate output in watch.go
2016-12-20 16:57:51 +08:00
astaxie
0b6212575d Merge pull request #335 from sergeylanzman/parse-all-package-only-if-docs-generate
Parse all packages only if docs generate
2016-12-20 16:56:58 +08:00
astaxie
b4a92f7521 Merge pull request #336 from sergeylanzman/go-install-default
Go install default
2016-12-20 16:56:01 +08:00
astaxie
54537ee8ee fix the generate 2016-12-20 16:54:03 +08:00
astaxie
ea51b6e831 Merge pull request #339 from onealtang/master
fix #338 failed to generate swagger doc
2016-12-20 16:52:43 +08:00
tangshancheng
b0928f186f fix #338 failed to generate swagger doc 2016-12-14 23:57:59 +08:00
astaxie
2ccbbb47e4 v1.6.1 2016-12-13 05:04:37 +08:00
astaxie
4e532f49f6 Merge pull request #338 from sergeylanzman/fix-swagger-generate-bug
Fix swagger generate bug
2016-12-13 05:03:20 +08:00
Sergey Lanzman
cfc8658ab2 fix bug with generate swagger. 2016-12-12 22:35:39 +02:00
Sergey Lanzman
b6d935523a add inet type for Postgres 2016-12-12 22:34:13 +02:00
Sergey Lanzman
aa195ecd46 Enable go install by default to reduce build time without gopm. 2016-12-12 22:30:50 +02:00
Sergey Lanzman
98cd088409 parse all packages this long operations
run only on docs generate
2016-12-12 22:27:54 +02:00
Sergey Lanzman
2ff99d4ea7 Merge pull request #1 from beego/master
update master
2016-12-12 20:21:34 +02:00
Faissal Elamraoui
a0020d65af Fix bee generate output in watch.go
This removes the output of bee generate in watch.go as it shows
the entire logger output (including the banner). Added also the ability
to catch the exec.Command error instead of returning the exit status.
2016-12-11 23:39:59 +01:00
vCaesar
998e110c6c Update fsnotify 2016-12-09 01:31:24 +08:00
astaxie
9786cb47ea bee 1.6.0 2016-12-05 23:17:15 +08:00
astaxie
28324a2756 add vendor 2016-12-05 23:07:45 +08:00
Faissal Elamraoui
71e23417c6 Merge pull request #331 from amrfaissal/fix-330
Removes the temp dir once bee pack is done
2016-12-05 14:54:06 +01:00
Faissal Elamraoui
1f917e9900 Merge pull request #329 from amrfaissal/enhance-help-and-usage
Enhances the commands help and usage output
2016-12-05 14:53:46 +01:00
Faissal Elamraoui
8dca816aac Fixed padding for printing an option 2016-12-05 14:52:37 +01:00
Faissal Elamraoui
592eac9974 Fixed a typo 2016-12-05 14:40:15 +01:00
Faissal Elamraoui
ce71c916d5 Displays the default value of a command flag
Added ability to display the default value of a command's flag,
truncated in case it contains a column (:). Also instead of displaying
the entire command usage/help in case of an undefined flag, output a
small message with "bee help cmd".
2016-12-04 16:30:38 +01:00
Faissal Elamraoui
b42874b967 This fixes #330
Removes the generated temp directory to avoid fulling the /tmp after
running bee pack a few times.
2016-12-04 14:48:42 +01:00
Faissal Elamraoui
73aa44e1a7 Added a few tweaks to the folder structure in the long description 2016-12-03 16:06:46 +01:00
Faissal Elamraoui
e927a9193d Enhances the commands short and long description
This enhances the output of bee help/usage by using colored and bold text to
highlight examples.
2016-12-03 11:54:41 +01:00
Faissal Elamraoui
196e732e19 Removes the use of template/html
This uses the template/text instead because template/html does not escape
quotes and replaces them with their HTML codes. Added two more util
functions to make it easy to use bold and colored text in the command long
description.
2016-12-03 11:46:10 +01:00
Faissal Elamraoui
6cf7b5d518 Enhanced the usage and help output
Now each command has its own output destination, which can be changed
using a SetOutput(writer) method. Added ability to display the options
of each command.
2016-12-01 21:18:20 +01:00
Faissal Elamraoui
a6ce37ddf3 Merge pull request #326 from amrfaissal/more-colors
Adds more colors to color.go
2016-11-23 16:00:53 +01:00
Faissal Elamraoui
1c0a569116 Fixed a typo 2016-11-23 15:58:38 +01:00
Faissal Elamraoui
621dbf2ed9 Added black and white colors 2016-11-23 15:58:21 +01:00
Faissal Elamraoui
1dc55894c9 Merge pull request #322 from amrfaissal/fix-dirparser-and-enhancements
Fix directory parser and enhancements
2016-11-22 10:39:41 +01:00
Faissal Elamraoui
5defe7c368 Fix merge conflict 2016-11-22 10:33:11 +01:00
Faissal Elamraoui
215ef4485a Merge pull request #324 from amrfaissal/nonbeego-support
Removes the check if the current path is a Beego project
2016-11-22 09:58:03 +01:00
Faissal Elamraoui
e39dc9fb7f #323: Removes the check if the current path is a Beego project 2016-11-21 15:23:08 +01:00
Faissal Elamraoui
ac935ad4e0 Merge pull request #321 from r0nni3/r0nni3-patch-isnull-filter
isnull filter needs boolean value for the Filter function
2016-11-20 22:42:54 +01:00
Faissal Elamraoui
03f2057eb0 Added PreRun phase to Command struct
Now each command has a PreRun function that will execute before calling
the Run() function. This allows to show the banner and do some pre-check
work. Also moved parsePackagesFromDir() to the main function to avoid
getting called each time 'bee' is invoked.
2016-11-20 22:28:52 +01:00
Faissal Elamraoui
35384b463e This allows the isBeegoProject() function to do the walking inside a Goroutine 2016-11-20 11:55:44 +01:00
Faissal Elamraoui
7fcbba0f53 Initialize the logger templates inside the logger singleton once (and only once) 2016-11-20 11:54:12 +01:00
Faissal Elamraoui
ab39926c41 Enhances the package dir parser
The function parsePackagesFromDir() was panicing when it encounter some
"invalid" Go files. Instead, this will allow it to display a warning and
continue the execution of the command.
2016-11-20 11:46:42 +01:00
Faissal Elamraoui
eac9dc25d3 Merge pull request #319 from amrfaissal/fix-debug-log
Fixes debug log message
2016-11-18 22:02:38 +01:00
Ronnie A. Baez Sesto
fb93677604 isnull filter needs boolean value for the Filter function
With changes suggested by @amrfaissal
2016-11-16 16:39:54 -04:00
Faissal Elamraoui
6b27ef186a This makes the logger instance a singleton 2016-11-16 12:33:01 +01:00
Faissal Elamraoui
21fc177551 Acquire lock when logging 2016-11-15 12:25:37 +01:00
Faissal Elamraoui
deacdaa667 Fixes the filename and lineNo in debug log message 2016-11-14 18:05:34 +01:00
astaxie
9aaade6cbb Merge pull request #318 from hcrgm/patch-1
Swagger: parse @LicenseUrl first
2016-11-14 21:10:07 +08:00
hcrgm
63b5a81104 Update g_docs.go 2016-11-14 19:07:22 +08:00
astaxie
c3c264ddb5 Merge pull request #317 from amrfaissal/centralized-logging
New logging infrastructure for Bee
2016-11-14 09:24:44 +08:00
Faissal Elamraoui
cf7aef47f0 Implementing the new logging infrastructure
Moved logging to the new logging infrastructure by removing the use of
ColorLog() function. Added more documentation. Also fixed some typos in
comments and function names.
2016-11-13 15:14:48 +01:00
Faissal Elamraoui
0e54238559 Included leading zeros for the log record ID 2016-11-13 15:06:34 +01:00
Faissal Elamraoui
cb47cd011c Moved all utility functions to one place 2016-11-13 14:12:38 +01:00
Faissal Elamraoui
af8e06cd53 Added more helper functions to output colored text 2016-11-13 14:10:11 +01:00
Faissal Elamraoui
b4e13b5529 Logging infrastructure for Bee
logger.go implements the logging infrastructure for Bee.
The end user can set the preferred backend (that implements io.Writer).
It supports multiple logging levels, and logs are sent to the output
colored based on each level. Debug logs are treated differently, i.e.
they will be sent to the output unless DEBUG_ENABLED is set to "1".
2016-11-13 13:46:32 +01:00
astaxie
04c0f9d7b4 output error 2016-11-10 16:51:50 +08:00
astaxie
f7001294a9 fix #312 2016-11-09 20:17:55 +08:00
astaxie
a3c1d42dab Merge pull request #305 from xiaoqiang0/develop
Swagger: support default value columns for @Param
2016-11-07 22:47:16 +08:00
astaxie
dcc0fb67d2 Merge pull request #306 from amrfaissal/rewrite-load-conf
Rewrite configuration loading
2016-11-07 22:45:17 +08:00
Faissal Elamraoui
440c5e967c Rewrite configuration loading
Rewrited loadConfig() function to walk the project directory
looking for bee.json and Beefile. If no configuration file
found, it fallbacks to the default configuration. In case
of an error, a log message is printed to the console.
2016-11-03 16:48:09 +01:00
Zhang Qiang
3199a019d7 Swagger: support default value columns for @Param
This patch support default value after 'type' column if total
columns is six.

This enhancement also is compatiable with old five columns.
2016-11-03 23:18:05 +08:00
astaxie
4ff3cf5ce8 Merge pull request #303 from Lao-liu/develop
Update hprose 2.0
2016-11-01 19:50:59 +08:00
Laoliu
0ccc6306b7 Update hprose 2.0 2016-11-01 18:59:32 +08:00
astaxie
50fafd72e8 Merge pull request #296 from amrfaissal/fix-goversion
Fix GoVersion value
2016-10-24 10:20:35 +08:00
Faissal Elamraoui
5cc09e5c6c This fixes #295 2016-10-22 15:44:22 +02:00
astaxie
1d8aa1a48d Merge pull request #292 from ihippik/patch-4
Default values in structure
2016-10-11 10:16:51 +08:00
Konstantin
7c7e75435c Update g_docs.go 2016-10-10 19:49:33 +03:00
Konstantin
e8f85a57c2 Add types error handler (log)
the usual warning not panic
2016-10-10 17:36:51 +03:00
Konstantin
31406ebe5a Default values in structure
Swagger default value for golang stucture.

format: 
doc:"default(my_defaul_value)"

type MyStruct struct {
	Template string `json:"template" doc:"default(<h1>Hello, {{ name }}! </h1>)"`
	Name string `json:"name"`
	MyNumber int64 `json:"temp"  doc:"default(10)"`
	MyBool bool `json:"bl"  doc:"default(true)"`
	MyFloat float64 `json:"fl"  doc:"default(12.1234)"`
}
2016-10-08 11:35:26 +03:00
astaxie
244e9ccdc9 Merge pull request #286 from sergeylanzman/swagger-support-multi-package
Swaager - add support multi package with golang way myPackage.struct
2016-09-28 07:44:55 +08:00
Sergey Lanzman
d93e9a4271 Update g_docs.go 2016-09-27 18:20:01 +03:00
astaxie
178e74db40 Merge pull request #287 from amrfaissal/fix-multiple-main
Fix & Tweaks
2016-09-27 10:04:17 +08:00
Faissal Elamraoui
56568f4d2c tweak: Exit with message instead of a panic
In case no application is found in GOPATH(s), exit with a friendly
message instead of a panic. Also removed useless else block in watch.go.
2016-09-26 20:32:14 +02:00
Faissal Elamraoui
287af20d1a fix: This fixes #247
Moved isBeegoProject(app) method from pack.go to util.go. Rewrite it
to walk the application folder tree looking for main files.
2016-09-26 20:25:15 +02:00
Sergey Lanzman
4ebf7eab65 add support multi package with gaoling way myPackage.struct 2016-09-25 01:34:26 +03:00
astaxie
f7d2e04e07 change to 1.5.2 2016-09-22 23:12:55 +08:00
astaxie
b368f2b16a Merge branch 'master' into develop 2016-09-22 23:12:06 +08:00
astaxie
29c9e1bab7 fix the map type generate 2016-09-22 23:04:58 +08:00
astaxie
205428abce fix the licence issue 2016-09-22 22:26:39 +08:00
astaxie
9e856ecb33 Merge pull request #284 from filiphaftek/master
Fix incorrect generation of postgres table id type
2016-09-18 09:07:37 +08:00
Filip
465115c28e Fix incorrect generation of postgres table id type 2016-09-17 21:54:00 +02:00
astaxie
8191997cbf Merge pull request #282 from oter/develop
Fix .exe postfix issue on Windows platform.
2016-09-16 10:47:51 +08:00
OTER
b282761292 Fix .exe postfix issue on Windows platform. 2016-09-15 22:40:03 +03:00
astaxie
77f3b13fc3 Merge pull request #281 from sergeylanzman/develop
Improve swagger
2016-09-15 08:57:24 +08:00
Sergey Lanzman
1b75ccb9fe Improve swagger (Main params,yaml 2016-09-15 00:09:54 +03:00
Sergey Lanzman
6189e101c9 Merge pull request #4 from beego/develop
Develop update
2016-09-14 22:59:52 +03:00
astaxie
e296e96e70 Merge pull request #276 from ZetaChow/develop
Develop
2016-09-09 15:52:22 +08:00
ZetaChow
0d0bea81bf 去掉offset(int64)赋0值,去掉query (map[...]...)定义,以符合Lint 2016-09-09 15:38:44 +08:00
ZetaChow
411aa43080 修改PUT和Get One 错误的注释 2016-09-09 15:27:36 +08:00
ZetaChow
ad34b7be2a 修改函数注释,以符合Lint规范 2016-09-09 15:20:59 +08:00
astaxie
6f5df78d45 Merge pull request #271 from CodyGuo/master
Fix to issue #270
2016-09-07 13:43:33 +08:00
CodyGuo
ed67ef47e6 Fix to issue #270 2016-09-04 20:45:11 +08:00
CodyGuo
f6a219fb3a Fix to issue #270 2016-09-04 13:53:45 +08:00
astaxie
f453885864 update to 1.5.1 2016-08-30 00:18:17 +08:00
astaxie
eb64d25e4a Merge pull request #264 from beego/master
Develop update
2016-08-30 00:15:44 +08:00
astaxie
3d7a532567 Merge pull request #263 from sergeylanzman/swagger-add-embedded-struct
Swagger add embedded struct
2016-08-29 22:09:11 +08:00
Sergey Lanzman
004778c662 swagger add embedded struct 2016-08-29 11:04:47 +02:00
Sergey Lanzman
abb3443c01 Merge pull request #3 from beego/develop
Develop update
2016-08-29 10:56:12 +02:00
astaxie
28f6abc3a0 merge master 2016-08-24 11:07:57 +08:00
astaxie
a58931fd82 Merge pull request #253 from amrfaissal/readme-v1.5.0
Updated README.md
2016-08-23 01:16:41 +08:00
Faissal Elamraoui
98f4ff83c1 docs: Updated README.md
The README.md is updated to include the latest changes in bee and
Beego. New submission guidelines are added to organize contributions
to the project.
2016-08-22 18:29:11 +02:00
astaxie
a985ff0a06 Merge pull request #252 from tnextday/develop
add todo
2016-08-22 19:31:49 +08:00
tnextday
07ca4481b0 add todo 2016-08-22 16:11:06 +08:00
astaxie
eed820ab62 Merge pull request #251 from kyawmyintthein/master
Add runmode flag on bee run command to set BEEGO_RUNMODE
2016-08-22 15:53:57 +08:00
astaxie
73c3b3beaa Merge pull request #249 from tnextday/develop
Add array type support in comment param
2016-08-22 11:47:44 +08:00
Kyaw Myint Thein
368b69b73f update readme file for bee run 2016-08-21 10:56:28 +08:00
Kyaw Myint Thein
c9d5fbfe64 add runmode flag on bee run to set BEEGO_RUNMODE env 2016-08-21 10:55:10 +08:00
tnextday
c3ff72ae77 Add support for query param array format.
exmple:

// @Param	app		query	[]string	true	support multipil app params

Update support for responses object format.
exmple:

// @Success 200 success
// @Success 200 {object} int64 success count
// @Success 200 {object} []int64 success ids
// @Success 200 {array} int64 success ids
2016-08-20 15:12:15 +08:00
tnextday
df9f5a77da Merge commit '5309c72ef751bd4edb45d1702996eb279033b281' into develop 2016-08-20 11:18:46 +08:00
tnextday
ca2f60c72d add array type support in comment param 2016-08-20 11:17:30 +08:00
101 changed files with 10417 additions and 4681 deletions

25
.github/workflows/go.yml vendored Normal file
View File

@ -0,0 +1,25 @@
name: Go
on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.18
- name: Build
run: go build -v ./...
- name: Test
run: go test -v ./...

2
.gitignore vendored
View File

@ -7,6 +7,7 @@
_obj
_test
.idea
.vscode
# Architecture specific extensions/prefixes
*.[568vq]
@ -29,3 +30,4 @@ _testmain.go
bee
*.exe~
.goxc.local.json
vendor

View File

@ -1,6 +1,22 @@
language: go
go:
- 1.5.3
- 1.4.3
- 1.3.3
- 1.14.6
install:
- export PATH=$PATH:$HOME/gopath/bin
- go get -u github.com/opennota/check/cmd/structcheck
- go get -u honnef.co/go/tools/cmd/staticcheck
- go get -u github.com/mdempsky/unconvert
- go get -u github.com/gordonklaus/ineffassign
script:
- pwd
- cd $(dirname `dirname $(pwd)`)/beego/bee
- export GO111MODULE="on"
- go mod download
- go test -coverprofile=coverage.txt -covermode=atomic ./...
- find . ! \( -path './vendor' -prune \) -type f -name '*.go' -print0 | xargs -0 gofmt -l -s
- go list ./... | grep -v /vendor/ | grep -v /pkg/mod/
- go vet $(go list ./... | grep -v /vendor/ | grep -v /pkg/mod/ )
- structcheck $(go list ./... | grep -v /vendor/ | grep -v /pkg/mod/ )
- staticcheck $(go list ./... | grep -v /vendor/ | grep -v /pkg/mod/ )
- unconvert $(go list ./... | grep -v /vendor/ | grep -v /pkg/mod/ )
- ineffassign .

View File

@ -1,9 +1,7 @@
version: 0
gopm:
enable: false
install: false
go_install: false
watch_ext: []
watch_ext: [".go"]
watch_ext_static: [".html", ".tpl", ".js", ".css"]
dir_structure:
watch_all: false
controllers: ""
@ -13,3 +11,4 @@ cmd_args: []
envs: []
database:
driver: "mysql"
enable_reload: false

View File

@ -1,3 +1,5 @@
VERSION = $(shell grep 'const version' cmd/commands/version/version.go | sed -E 's/.*"(.+)"$$/v\1/')
.PHONY: all test clean build install
GOFLAGS ?= $(GOFLAGS:)
@ -18,3 +20,10 @@ bench: install
clean:
go clean $(GOFLAGS) -i ./...
publish:
mkdir -p bin/$(VERSION)
cd bin/$(VERSION)
xgo -v -x --targets="windows/*,darwin/*,linux/386,linux/amd64,linux/arm-5,linux/arm64" -out bee_$(VERSION) github.com/beego/bee/v2
cd ..
ghr -u beego -r bee $(VERSION) $(VERSION)

706
README.md
View File

@ -1,273 +1,431 @@
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://img.shields.io/travis/beego/bee.svg?branch=master&label=master)](https://travis-ci.org/beego/bee)
[![Build Status](https://img.shields.io/travis/beego/bee.svg?branch=develop&label=develop)](https://travis-ci.org/beego/bee)
## Requirements
- Go version >= 1.3.
- Go version >= 1.13
## Installation
Begin by installing `bee` using `go get` command.
To install or update `bee` use the `go install` command:
```bash
go get github.com/beego/bee
go install github.com/beego/bee/v2@latest
```
Then you can add `bee` binary to PATH environment variable in your `~/.bashrc` or `~/.bash_profile` file:
## Then you can add `bee` binary to PATH environment variable in your `~/.bashrc` or `~/.bash_profile` file:
```bash
export PATH=$PATH:<your_main_gopath>/bin
```
## Installing and updating bee prior Go version 1.17
To install `bee` use the `go get` command:
```bash
go get github.com/beego/bee/v2
```
> If you already have `bee` installed, updating `bee` is simple:
```bash
go get -u github.com/beego/bee
go get -u github.com/beego/bee/v2
```
## Basic commands
Bee provides a variety of commands which can be helpful at various stage 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
Bee provides a variety of commands which can be helpful at various stages of development. The top level commands include:
The first command is the easiest: displaying which version of `bee`, `beego` and `go` is installed on your machine:
```
version Prints the current Bee version
migrate Runs database migrations
api Creates a Beego API application
bale Transforms non-Go files to Go source files
fix Fixes your application by making it compatible with newer versions of Beego
pro Source code generator
dlv Start a debugging session using Delve
dockerize Generates a Dockerfile and docker-compose.yaml for your Beego application
generate Source code generator
hprose Creates an RPC application based on Hprose and Beego frameworks
new Creates a Beego application
pack Compresses a Beego application into a single file
rs Run customized scripts
run Run the application by starting a local development server
server serving static content over HTTP on port
update Update Bee
```
### bee version
To display the current version of `bee`, `beego` and `go` installed on your machine:
```bash
$ bee version
bee :1.2.2
beego :1.4.0
Go :go version go1.2.1 linux/amd64
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.4
├── Beego : 2.0.4
├── GoVersion : go1.14.1
├── GOOS : darwin
├── GOARCH : amd64
├── NumCPU : 4
├── GOPATH : /home/beeuser/.go
├── GOROOT : /usr/local/Cellar/go/1.14.1/libexec
├── Compiler : gc
└── Published : 2020-09-13
```
## bee new
Creating a new beego web application is no big deal, too.
You can also change the output format using `-o` flag:
```bash
$ bee new myapp
[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/
/home/zheng/gopath/src/myapp/tests/
/home/zheng/gopath/src/myapp/static/
/home/zheng/gopath/src/myapp/static/js/
/home/zheng/gopath/src/myapp/static/css/
/home/zheng/gopath/src/myapp/static/img/
/home/zheng/gopath/src/myapp/views/
/home/zheng/gopath/src/myapp/conf/app.conf
/home/zheng/gopath/src/myapp/controllers/default.go
/home/zheng/gopath/src/myapp/views/index.tpl
/home/zheng/gopath/src/myapp/routers/router.go
/home/zheng/gopath/src/myapp/tests/default_test.go
/home/zheng/gopath/src/myapp/main.go
2014/08/29 15:45:47 [SUCC] New application successfully created!
$ bee version -o json
{
"GoVersion": "go1.14.1",
"GOOS": "darwin",
"GOARCH": "amd64",
"NumCPU": 4,
"GOPATH": "/home/beeuser/.go",
"GOROOT": "/usr/local/Cellar/go/1.14.1/libexec",
"Compiler": "gc",
"BeeVersion": "2.0.4",
"BeegoVersion": "2.0.4",
"Published": "2020-09-13"
}
```
## bee run
For more information on the usage, run `bee help version`.
To run the application we just created, navigate to the application folder and execute `bee run`.
### bee new
To create a new Beego web application:
```bash
$ cd myapp
$ bee run
$ bee new my-web-app
2020/09/14 22:28:51 INFO ▶ 0001 generate new project support go modules.
2020/09/14 22:28:51 INFO ▶ 0002 Creating application...
create /Users/beeuser/learn/my-web-app/go.mod
create /Users/beeuser/learn/my-web-app/
create /Users/beeuser/learn/my-web-app/conf/
create /Users/beeuser/learn/my-web-app/controllers/
create /Users/beeuser/learn/my-web-app/models/
create /Users/beeuser/learn/my-web-app/routers/
create /Users/beeuser/learn/my-web-app/tests/
create /Users/beeuser/learn/my-web-app/static/
create /Users/beeuser/learn/my-web-app/static/js/
create /Users/beeuser/learn/my-web-app/static/css/
create /Users/beeuser/learn/my-web-app/static/img/
create /Users/beeuser/learn/my-web-app/views/
create /Users/beeuser/learn/my-web-app/conf/app.conf
create /Users/beeuser/learn/my-web-app/controllers/default.go
create /Users/beeuser/learn/my-web-app/views/index.tpl
create /Users/beeuser/learn/my-web-app/routers/router.go
create /Users/beeuser/learn/my-web-app/tests/default_test.go
create /Users/beeuser/learn/my-web-app/main.go
2020/09/14 22:28:51 SUCCESS ▶ 0003 New application successfully created!
```
## bee pack
For more information on the usage, run `bee help new`.
### bee run
To run the application we just created, you can navigate to the application folder and execute:
```bash
usage: 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
-be=[] additional ENV Variables of go build. eg: GOARCH=arm
-o compressed file output dir. default use current path
-f="" format. [ tar.gz / zip ]. default tar.gz
-exp="" relpath exclude prefix. default: .
-exs="" relpath exclude suffix. default: .go:.DS_Store:.tmp
all path use : as separator
-exr=[] file/directory name exclude by Regexp. default: ^.
-fs=false follow symlink. default false
-ss=false skip symlink. default false
default embed symlink into compressed file
-v=false verbose
$ cd my-web-app && bee run
```
## bee api
For more information on the usage, run `bee help run`.
### bee pack
To compress a Beego application into a single deployable file:
```bash
usage: bee api [appname]
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
-conn: the connection string used by the driver, the default is ''
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
if conn is empty will create a example api application. otherwise generate api application based on an existing database.
In the current path, will create a folder named [appname]
In the appname folder has the follow struct:
├── conf
│ └── app.conf
├── controllers
│ └── object.go
│ └── user.go
├── routers
│ └── router.go
├── tests
│ └── default_test.go
├── main.go
└── models
└── object.go
└── user.go
$ bee pack
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.0
2016/12/26 22:29:29 INFO ▶ 0001 Packaging application on '/home/beeuser/.go/src/github.com/user/my-web-app'...
2016/12/26 22:29:29 INFO ▶ 0002 Building application...
2016/12/26 22:29:29 INFO ▶ 0003 Using: GOOS=linux GOARCH=amd64
2016/12/26 22:29:31 SUCCESS ▶ 0004 Build Successful!
2016/12/26 22:29:31 INFO ▶ 0005 Writing to output: /home/beeuser/.go/src/github.com/user/my-web-app/my-web-app.tar.gz
2016/12/26 22:29:31 INFO ▶ 0006 Excluding relpath prefix: .
2016/12/26 22:29:31 INFO ▶ 0007 Excluding relpath suffix: .go:.DS_Store:.tmp
2016/12/26 22:29:32 SUCCESS ▶ 0008 Application packed!
```
## bee hprose
For more information on the usage, run `bee help pack`.
### bee rs
Inspired by makefile / npm scripts.
Run script allows you to run arbitrary commands using Bee.
Custom commands are provided from the "scripts" object inside bee.json or Beefile.
To run a custom command, use: $ bee rs mycmd ARGS
```bash
usage: bee hprose [appname]
$ bee help rs
create an rpc application use hprose base on beego framework
USAGE
bee rs
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
-conn: the connection string used by the driver, the default is ''
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
DESCRIPTION
Run script allows you to run arbitrary commands using Bee.
Custom commands are provided from the "scripts" object inside bee.json or Beefile.
if conn is empty will create a example rpc application. otherwise generate rpc application use hprose based on an existing database.
To run a custom command, use: $ bee rs mycmd ARGS
In the current path, will create a folder named [appname]
In the appname folder has the follow struct:
├── conf
│ └── app.conf
├── main.go
└── models
└── object.go
└── user.go
AVAILABLE SCRIPTS
gtest
APP_ENV=test APP_CONF_PATH=$(pwd)/conf go test -v -cover
gtestall
APP_ENV=test APP_CONF_PATH=$(pwd)/conf go test -v -cover $(go list ./... | grep -v /vendor/)
```
## bee bale
*Run your scripts with:*
```$ bee rs gtest tests/*.go```
```$ bee rs gtestall```
### bee api
To create a Beego API application:
```bash
usage: 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.
This is mainly used for zealots who are requiring 100% Go code.
$ bee api my-api
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.0
2020/09/14 22:35:11 INFO ▶ 0001 generate api project support go modules.
2020/09/14 22:35:11 INFO ▶ 0002 Creating API...
create /Users/beeuser/code/learn/my-api/go.mod
create /Users/beeuser/code/learn/my-api
create /Users/beeuser/code/learn/my-api/conf
create /Users/beeuser/code/learn/my-api/controllers
create /Users/beeuser/code/learn/my-api/tests
create /Users/beeuser/code/learn/my-api/conf/app.conf
create /Users/beeuser/code/learn/my-api/models
create /Users/beeuser/code/learn/my-api/routers/
create /Users/beeuser/code/learn/my-api/controllers/object.go
create /Users/beeuser/code/learn/my-api/controllers/user.go
create /Users/beeuser/code/learn/my-api/tests/default_test.go
create /Users/beeuser/code/learn/my-api/routers/router.go
create /Users/beeuser/code/learn/my-api/models/object.go
create /Users/beeuser/code/learn/my-api/models/user.go
create /Users/beeuser/code/learn/my-api/main.go
2020/09/14 22:35:11 SUCCESS ▶ 0003 New API successfully created!
```
## bee migrate
For more information on the usage, run `bee help api`.
### bee hprose
To create an Hprose RPC application based on Beego:
```bash
usage: bee migrate [Command]
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
bee migrate rollback [-driver="mysql"] [-conn="root:@tcp(127.0.0.1:3306)/test"]
rollback the last migration operation
-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 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 hprose my-rpc-app
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.0
2020/09/14 22:36:39 INFO ▶ 0001 generate api project support go modules.
2020/09/14 22:36:39 INFO ▶ 0002 Creating Hprose application...
create /Users/beeuser/code/learn/my-rpc-app/go.mod
create /Users/beeuser/code/learn/my-rpc-app
create /Users/beeuser/code/learn/my-rpc-app/conf
create /Users/beeuser/code/learn/my-rpc-app/conf/app.conf
create /Users/beeuser/code/learn/my-rpc-app/models
create /Users/beeuser/code/learn/my-rpc-app/models/object.go
create /Users/beeuser/code/learn/my-rpc-app/models/user.go
create /Users/beeuser/code/learn/my-rpc-app/main.go
2020/09/14 22:36:39 SUCCESS ▶ 0003 New Hprose application successfully created!
```
## bee generate
For more information on the usage, run `bee help hprose`.
Bee also comes with a souce code generator which speeds up the development.
### bee bale
To pack all the static files into Go source files:
```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
$ bee bale
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.0
2020/09/14 22:37:56 SUCCESS ▶ 0001 Baled resources successfully!
```
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
$ bee generate controller hello
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.0
2020/09/14 22:38:44 INFO ▶ 0001 Using 'Hello' as controller name
2020/09/14 22:38:44 INFO ▶ 0002 Using 'controllers' as package name
create /Users/beeuser/code/learn/my-api/controllers/hello.go
2020/09/14 22:38:44 SUCCESS ▶ 0003 Controller successfully generated!
```
For more information on the usage, run `bee help generate`.
### bee dockerize
Bee also helps you dockerize your Beego application by generating a Dockerfile and a docker-compose.yaml file.
For example, to generate a Dockerfile with `golang:1.20.1` baseimage and exposing port `9000`:
```bash
$ bee dockerize -baseimage=golang:1.20.1 -expose=9000
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.4
2023/05/02 21:03:05 INFO ▶ 0001 Generating Dockerfile and docker-compose.yaml...
2023/05/02 21:03:05 SUCCESS ▶ 0002 Dockerfile generated.
2023/05/02 21:03:05 SUCCESS ▶ 0003 docker-compose.yaml generated.
```
For more information on the usage, run `bee help dockerize`.
### bee dlv
Bee can also help with debugging your application. To start a debugging session:
```bash
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v2.0.0
2020/09/14 22:40:12 INFO ▶ 0001 Starting Delve Debugger...
Type 'help' for list of commands.
(dlv) break main.main
Breakpoint 1 set at 0x40100f for main.main() ./main.go:8
(dlv) continue
> main.main() ./main.go:8 (hits goroutine(1):1 total:1) (PC: 0x40100f)
3: import (
4: _ "github.com/user/myapp/routers"
5: beego "github.com/beego/beego/v2/server/web"
6: )
7:
=> 8: func main() {
9: beego.Run()
10: }
11:
```
For more information on the usage, run `bee help dlv`.
### bee pro
#### bee pro toml
To create a beegopro.toml file
```bash
$ bee pro toml
2020/09/14 22:51:18 SUCCESS ▶ 0001 Successfully created file beegopro.toml
2020/09/14 22:51:18 SUCCESS ▶ 0002 Toml successfully generated!
```
#### bee pro gen
Source code generator by beegopro.toml
```bash
$ bee pro gen
2020/09/14 23:01:13 INFO ▶ 0001 Create /Users/beeuser/.beego/beego-pro Success!
2020/09/14 23:01:13 INFO ▶ 0002 git pull /Users/beeuser/.beego/beego-pro
2020/09/14 23:01:15 INFO ▶ 0003 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0004 Using 'example' as package name from controllers
2020/09/14 23:01:15 INFO ▶ 0005 create file '/Users/beeuser/code/learn/my-web-app/controllers/bee_default_controller.go' from controllers
2020/09/14 23:01:15 INFO ▶ 0006 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0007 Using 'example' as package name from controllers
2020/09/14 23:01:15 INFO ▶ 0008 create file '/Users/beeuser/code/learn/my-web-app/controllers/example.go' from controllers
2020/09/14 23:01:15 INFO ▶ 0009 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0010 Using 'example' as package name from models
2020/09/14 23:01:15 INFO ▶ 0011 create file '/Users/beeuser/code/learn/my-web-app/models/bee_default_model.go' from models
2020/09/14 23:01:15 INFO ▶ 0012 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0013 Using 'example' as package name from models
2020/09/14 23:01:15 INFO ▶ 0014 create file '/Users/beeuser/code/learn/my-web-app/models/example.go' from models
2020/09/14 23:01:15 INFO ▶ 0015 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0016 Using 'example' as package name from routers
2020/09/14 23:01:15 INFO ▶ 0017 create file '/Users/beeuser/code/learn/my-web-app/routers/example.go' from routers
2020/09/14 23:01:15 INFO ▶ 0018 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0019 Using 'example' as package name from example
2020/09/14 23:01:15 INFO ▶ 0020 create file '/Users/beeuser/code/learn/my-web-app/ant/src/pages/example/list.tsx' from example
2020/09/14 23:01:15 INFO ▶ 0021 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0022 Using 'example' as package name from example
2020/09/14 23:01:15 INFO ▶ 0023 create file '/Users/beeuser/code/learn/my-web-app/ant/src/pages/example/formconfig.tsx' from example
2020/09/14 23:01:15 INFO ▶ 0024 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0025 Using 'example' as package name from example
2020/09/14 23:01:15 INFO ▶ 0026 create file '/Users/beeuser/code/learn/my-web-app/ant/src/pages/example/create.tsx' from example
2020/09/14 23:01:15 INFO ▶ 0027 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0028 Using 'example' as package name from example
2020/09/14 23:01:15 INFO ▶ 0029 create file '/Users/beeuser/code/learn/my-web-app/ant/src/pages/example/update.tsx' from example
2020/09/14 23:01:15 INFO ▶ 0030 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0031 Using 'example' as package name from example
2020/09/14 23:01:15 INFO ▶ 0032 create file '/Users/beeuser/code/learn/my-web-app/ant/src/pages/example/info.tsx' from example
2020/09/14 23:01:15 INFO ▶ 0033 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0034 Using 'example' as package name from sql
2020/09/14 23:01:15 INFO ▶ 0035 create file '/Users/beeuser/code/learn/my-web-app/sql/example_up.sql' from sql
2020/09/14 23:01:15 INFO ▶ 0036 2020/09/14 23:01:15 INFO ▶ 0001 db exec info ./sql/example_up.sql
2020/09/14 23:01:15 SUCCESS ▶ 0002 Migration successfully generated!
2020/09/14 23:01:15 INFO ▶ 0037 Using 'example' as name
2020/09/14 23:01:15 INFO ▶ 0038 Using 'example' as package name from sql
2020/09/14 23:01:15 INFO ▶ 0039 create file '/Users/beeuser/code/learn/my-web-app/sql/example_down.sql' from sql
2020/09/14 23:01:15 SUCCESS ▶ 0040 Gen successfully generated!
```
####
## 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
# Generator Stuff
@ -278,32 +436,158 @@ alias g:v="bee generate view"
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
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:
```bash
$ 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] [-runmode=BEEGO_RUNMODE]
start the appname throw exec.Command
OPTIONS
-downdoc
Enable auto-download of the swagger file if it does not exist.
then start a inotify watch for current dir
-e=[]
List of paths to exclude.
when the file has changed bee will auto go build and restart the app
-gendoc
Enable auto-generate the docs.
file changed
|
check if it's go file
|
yes no
| |
go build do nothing
|
restart app
-main=[]
Specify main go files.
-runmode
Set the Beego run mode.
-tags
Set the build tags. See: https://golang.org/pkg/go/build/
-vendor=false
Enable watch vendor folder.
DESCRIPTION
Run command will supervise the filesystem of the application for any changes, and recompile/restart it.
```
## Contributing
Bug reports, feature requests and pull requests are always welcome.
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,
or when you are unsure of where to base your work from when contributing.
### Found a bug?
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!
- 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 2020 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.
```

View File

@ -1,283 +0,0 @@
// Copyright 2013 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.
package main
import (
"bytes"
"errors"
"fmt"
"go/ast"
gobuild "go/build"
"go/doc"
"go/parser"
"go/token"
"io"
"io/ioutil"
"os"
"path"
"runtime"
"strings"
"time"
)
var cmdRouter = &Command{
UsageLine: "router",
Short: "auto-generate routers for the app controllers",
Long: `
`,
}
func init() {
cmdRouter.Run = autoRouter
}
func autoRouter(cmd *Command, args []string) int {
fmt.Println("[INFO] Starting auto-generating routers...")
return 0
}
// getControllerInfo returns controllers that embeded "beego.controller"
// and their methods of package in given path.
func getControllerInfo(path string) (map[string][]string, error) {
now := time.Now()
path = strings.TrimSuffix(path, "/")
dir, err := os.Open(path)
if err != nil {
return nil, err
}
fis, err := dir.Readdir(0)
if err != nil {
return nil, err
}
files := make([]*source, 0, len(fis))
for _, fi := range fis {
// Only load go files.
if strings.HasSuffix(fi.Name(), ".go") {
f, err := os.Open(path + "/" + fi.Name())
if err != nil {
return nil, err
}
p := make([]byte, fi.Size())
_, err = f.Read(p)
if err != nil {
return nil, err
}
f.Close()
files = append(files, &source{
name: path + "/" + fi.Name(),
data: p,
})
}
}
rw := &routerWalker{
pdoc: &Package{
ImportPath: path,
},
}
cm := make(map[string][]string)
pdoc, err := rw.build(files)
for _, t := range pdoc.Types {
// Check if embeded "beego.Controller".
if strings.Index(t.Decl, "beego.Controller") > -1 {
for _, f := range t.Methods {
cm[t.Name] = append(cm[t.Name], f.Name)
}
}
}
fmt.Println(time.Since(now))
return cm, nil
}
// A source describles a source code file.
type source struct {
name string
data []byte
}
func (s *source) Name() string { return s.name }
func (s *source) Size() int64 { return int64(len(s.data)) }
func (s *source) Mode() os.FileMode { return 0 }
func (s *source) ModTime() time.Time { return time.Time{} }
func (s *source) IsDir() bool { return false }
func (s *source) Sys() interface{} { return nil }
// A routerWalker holds the state used when building the documentation.
type routerWalker struct {
pdoc *Package
srcs map[string]*source // Source files.
fset *token.FileSet
buf []byte // scratch space for printNode method.
}
// Package represents full information and documentation for a package.
type Package struct {
ImportPath string
// Top-level declarations.
Types []*Type
}
// Type represents structs and interfaces.
type Type struct {
Name string // Type name.
Decl string
Methods []*Func // Exported methods.
}
// Func represents functions
type Func struct {
Name string
}
// build generates data from source files.
func (w *routerWalker) build(srcs []*source) (*Package, error) {
// Add source files to walker, I skipped references here.
w.srcs = make(map[string]*source)
for _, src := range srcs {
w.srcs[src.name] = src
}
w.fset = token.NewFileSet()
// Find the package and associated files.
ctxt := gobuild.Context{
GOOS: runtime.GOOS,
GOARCH: runtime.GOARCH,
CgoEnabled: true,
JoinPath: path.Join,
IsAbsPath: path.IsAbs,
SplitPathList: func(list string) []string { return strings.Split(list, ":") },
IsDir: func(path string) bool { panic("unexpected") },
HasSubdir: func(root, dir string) (rel string, ok bool) { panic("unexpected") },
ReadDir: func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) },
OpenFile: func(path string) (r io.ReadCloser, err error) { return w.openFile(path) },
Compiler: "gc",
}
bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0)
// Continue if there are no Go source files; we still want the directory info.
_, nogo := err.(*gobuild.NoGoError)
if err != nil {
if nogo {
err = nil
} else {
return nil, errors.New("routerWalker.build -> " + err.Error())
}
}
// Parse the Go files
files := make(map[string]*ast.File)
for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) {
file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments)
if err != nil {
return nil, errors.New("routerWalker.build -> parse go files: " + err.Error())
}
files[name] = file
}
apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil)
mode := doc.Mode(0)
if w.pdoc.ImportPath == "builtin" {
mode |= doc.AllDecls
}
pdoc := doc.New(apkg, w.pdoc.ImportPath, mode)
w.pdoc.Types = w.types(pdoc.Types)
return w.pdoc, err
}
func (w *routerWalker) funcs(fdocs []*doc.Func) []*Func {
var result []*Func
for _, d := range fdocs {
result = append(result, &Func{
Name: d.Name,
})
}
return result
}
func (w *routerWalker) types(tdocs []*doc.Type) []*Type {
var result []*Type
for _, d := range tdocs {
result = append(result, &Type{
Decl: w.printDecl(d.Decl),
Name: d.Name,
Methods: w.funcs(d.Methods),
})
}
return result
}
func (w *routerWalker) printDecl(decl ast.Node) string {
var d Code
d, w.buf = printDecl(decl, w.fset, w.buf)
return d.Text
}
func (w *routerWalker) readDir(dir string) ([]os.FileInfo, error) {
if dir != w.pdoc.ImportPath {
panic("unexpected")
}
fis := make([]os.FileInfo, 0, len(w.srcs))
for _, src := range w.srcs {
fis = append(fis, src)
}
return fis, nil
}
func (w *routerWalker) openFile(path string) (io.ReadCloser, error) {
if strings.HasPrefix(path, w.pdoc.ImportPath+"/") {
if src, ok := w.srcs[path[len(w.pdoc.ImportPath)+1:]]; ok {
return ioutil.NopCloser(bytes.NewReader(src.data)), nil
}
}
panic("unexpected")
}
func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) {
pkg := imports[path]
if pkg == nil {
// Guess the package name without importing it. Start with the last
// element of the path.
name := path[strings.LastIndex(path, "/")+1:]
// Trim commonly used prefixes and suffixes containing illegal name
// runes.
name = strings.TrimSuffix(name, ".go")
name = strings.TrimSuffix(name, "-go")
name = strings.TrimPrefix(name, "go.")
name = strings.TrimPrefix(name, "go-")
name = strings.TrimPrefix(name, "biogo.")
// It's also common for the last element of the path to contain an
// extra "go" prefix, but not always. TODO: examine unresolved ids to
// detect when trimming the "go" prefix is appropriate.
pkg = ast.NewObj(ast.Pkg, name)
pkg.Data = ast.NewScope(nil)
imports[path] = pkg
}
return pkg, nil
}

View File

@ -1,9 +0,0 @@
package main
import (
"testing"
)
func TestGetControllerInfo(t *testing.T) {
getControllerInfo("testdata/router/")
}

188
bee.go
View File

@ -1,188 +0,0 @@
// Copyright 2013 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.
// Bee is a tool for developling applications based on beego framework.
package main
import (
"flag"
"fmt"
"html/template"
"io"
"log"
"os"
"strings"
)
const version = "1.5.0"
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string) int
// UsageLine is the one-line usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short template.HTML
// Long is the long message shown in the 'go help <this-command>' output.
Long template.HTML
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
}
// Name returns the command's name: the first word in the usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
func (c *Command) Usage() {
fmt.Fprintf(os.Stderr, "usage: %s\n\n", c.UsageLine)
fmt.Fprintf(os.Stderr, "%s\n", strings.TrimSpace(string(c.Long)))
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as importpath.
func (c *Command) Runnable() bool {
return c.Run != nil
}
var commands = []*Command{
cmdNew,
cmdRun,
cmdPack,
cmdApiapp,
cmdHproseapp,
//cmdRouter,
//cmdTest,
cmdBale,
cmdVersion,
cmdGenerate,
//cmdRundocs,
cmdMigrate,
cmdFix,
}
func main() {
flag.Usage = usage
flag.Parse()
log.SetFlags(0)
args := flag.Args()
if len(args) < 1 {
usage()
}
if args[0] == "help" {
help(args[1:])
return
}
for _, cmd := range commands {
if cmd.Name() == args[0] && cmd.Run != nil {
cmd.Flag.Usage = func() { cmd.Usage() }
if cmd.CustomFlags {
args = args[1:]
} else {
cmd.Flag.Parse(args[1:])
args = cmd.Flag.Args()
}
os.Exit(cmd.Run(cmd, args))
return
}
}
fmt.Fprintf(os.Stderr, "bee: unknown subcommand %q\nRun 'bee help' for usage.\n", args[0])
os.Exit(2)
}
var usageTemplate = `Bee is a tool for managing beego framework.
Usage:
bee command [arguments]
The commands are:
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "bee help [command]" for more information about a command.
Additional help topics:
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use "bee help [topic]" for more information about that topic.
`
var helpTemplate = `{{if .Runnable}}usage: bee {{.UsageLine}}
{{end}}{{.Long | trim}}
`
func usage() {
tmpl(os.Stdout, usageTemplate, commands)
os.Exit(2)
}
func tmpl(w io.Writer, text string, data interface{}) {
t := template.New("top")
t.Funcs(template.FuncMap{"trim": func(s template.HTML) template.HTML {
return template.HTML(strings.TrimSpace(string(s)))
}})
template.Must(t.Parse(text))
if err := t.Execute(w, data); err != nil {
panic(err)
}
}
func help(args []string) {
if len(args) == 0 {
usage()
// not exit 2: succeeded at 'go help'.
return
}
if len(args) != 1 {
fmt.Fprintf(os.Stdout, "usage: bee help command\n\nToo many arguments given.\n")
os.Exit(2) // failed at 'bee help'
}
arg := args[0]
for _, cmd := range commands {
if cmd.Name() == arg {
tmpl(os.Stdout, helpTemplate, cmd)
// not exit 2: succeeded at 'go help cmd'.
return
}
}
fmt.Fprintf(os.Stdout, "Unknown help topic %#q. Run 'bee help'.\n", arg)
os.Exit(2) // failed at 'bee help cmd'
}

View File

@ -1,11 +1,8 @@
{
"version": 0,
"gopm": {
"enable": false,
"install": false
},
"go_install": false,
"watch_ext": [],
"watch_ext": [".go"],
"watch_ext_static": [".html", ".tpl", ".js", ".css"],
"dir_structure": {
"watch_all": false,
"controllers": "",
@ -16,5 +13,6 @@
"envs": [],
"database": {
"driver": "mysql"
}
},
"enable_reload": false
}

108
cmd/bee.go Normal file
View File

@ -0,0 +1,108 @@
// Copyright 2013 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.
// Package cmd ...
package cmd
import (
"github.com/beego/bee/v2/cmd/commands"
_ "github.com/beego/bee/v2/cmd/commands/api"
_ "github.com/beego/bee/v2/cmd/commands/bale"
_ "github.com/beego/bee/v2/cmd/commands/beefix"
_ "github.com/beego/bee/v2/cmd/commands/beegopro"
_ "github.com/beego/bee/v2/cmd/commands/dev"
_ "github.com/beego/bee/v2/cmd/commands/dlv"
_ "github.com/beego/bee/v2/cmd/commands/dockerize"
_ "github.com/beego/bee/v2/cmd/commands/generate"
_ "github.com/beego/bee/v2/cmd/commands/hprose"
_ "github.com/beego/bee/v2/cmd/commands/migrate"
_ "github.com/beego/bee/v2/cmd/commands/new"
_ "github.com/beego/bee/v2/cmd/commands/pack"
_ "github.com/beego/bee/v2/cmd/commands/rs"
_ "github.com/beego/bee/v2/cmd/commands/run"
_ "github.com/beego/bee/v2/cmd/commands/server"
_ "github.com/beego/bee/v2/cmd/commands/update"
_ "github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/utils"
)
func IfGenerateDocs(name string, args []string) bool {
if name != "generate" {
return false
}
for _, a := range args {
if a == "docs" {
return true
}
}
return false
}
var usageTemplate = `Bee is a Fast and Flexible tool for managing your Beego Web Application.
You are using bee for beego v2.x. If you are working on beego v1.x, please downgrade version to bee v1.12.0
{{"USAGE" | headline}}
{{"bee command [arguments]" | bold}}
{{"AVAILABLE COMMANDS" | headline}}
{{range .}}{{if .Runnable}}
{{.Name | printf "%-11s" | bold}} {{.Short}}{{end}}{{end}}
Use {{"bee help [command]" | bold}} for more information about a command.
{{"ADDITIONAL HELP TOPICS" | headline}}
{{range .}}{{if not .Runnable}}
{{.Name | printf "%-11s"}} {{.Short}}{{end}}{{end}}
Use {{"bee help [topic]" | bold}} for more information about that topic.
`
var helpTemplate = `{{"USAGE" | headline}}
{{.UsageLine | printf "bee %s" | bold}}
{{if .Options}}{{endline}}{{"OPTIONS" | headline}}{{range $k,$v := .Options}}
{{$k | printf "-%s" | bold}}
{{$v}}
{{end}}{{end}}
{{"DESCRIPTION" | headline}}
{{tmpltostr .Long . | trim}}
`
var ErrorTemplate = `bee: %s.
Use {{"bee help" | bold}} for more information.
`
func Usage() {
utils.Tmpl(usageTemplate, commands.AvailableCommands)
}
func Help(args []string) {
if len(args) == 0 {
Usage()
return
}
if len(args) != 1 {
utils.PrintErrorAndExit("Too many arguments", ErrorTemplate)
}
arg := args[0]
for _, cmd := range commands.AvailableCommands {
if cmd.Name() == arg {
utils.Tmpl(helpTemplate, cmd)
return
}
}
utils.PrintErrorAndExit("Unknown help topic", ErrorTemplate)
}

View File

@ -12,66 +12,71 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package apiapp
import (
"fmt"
"os"
path "path/filepath"
"strings"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/generate"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var cmdApiapp = &Command{
var CmdApiapp = &commands.Command{
// CustomFlags: true,
UsageLine: "api [appname]",
Short: "create an API beego application",
Short: "Creates a Beego API application",
Long: `
Create an API beego application.
The command 'api' creates a Beego API application.
now default supoort generate a go modules project.
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] (default: mysql)
-conn: the connection string used by the driver, the default is ''
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
{{"Example:"|bold}}
$ bee api [appname] [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-gopath=false] [-beego=v1.12.3]
If 'conn' argument is empty, bee api creates an example API application,
when 'conn' argument is provided, bee api generates an API application based
on the existing database.
If 'conn' argument is empty, the command will generate an example API application. Otherwise the command
will connect to your database and generate models based on the existing tables.
The command 'api' creates a folder named [appname] and inside the folder deploy
the following files/directories structure:
The command 'api' creates a folder named [appname] with the following structure:
conf
main.go
go.mod
{{"conf"|foldername}}
app.conf
controllers
{{"controllers"|foldername}}
object.go
user.go
routers
{{"routers"|foldername}}
router.go
tests
{{"tests"|foldername}}
default_test.go
main.go
models
{{"models"|foldername}}
object.go
user.go
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: createAPI,
}
var apiconf = `appname = {{.Appname}}
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
sqlconn = {{.SQLConnStr}}
`
var apiMaingo = `package main
import (
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func main() {
@ -88,16 +93,18 @@ var apiMainconngo = `package main
import (
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
beego "github.com/beego/beego/v2/server/web"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/beego/v2/client/orm"
{{.DriverPkg}}
)
func init() {
orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}")
}
func main() {
sqlConn,err := beego.AppConfig.String("sqlconn")
if err != nil {
beeLogger.Log.Fatal("%s", err)
}
orm.RegisterDataBase("default", "{{.DriverName}}", sqlConn)
if beego.BConfig.RunMode == "dev" {
beego.BConfig.WebConfig.DirectoryIndex = true
beego.BConfig.WebConfig.StaticDir["/swagger"] = "swagger"
@ -105,6 +112,14 @@ func main() {
beego.Run()
}
`
var goMod = `
module %s
go %s
require github.com/beego/beego/v2 %s
require github.com/smartystreets/goconvey v1.6.4
`
var apirouter = `// @APIVersion 1.0.0
@ -119,7 +134,7 @@ package routers
import (
"{{.Appname}}/controllers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func init() {
@ -139,7 +154,7 @@ func init() {
}
`
var apiModels = `package models
var APIModels = `package models
import (
"errors"
@ -194,7 +209,7 @@ func Delete(ObjectId string) {
`
var apiModels2 = `package models
var APIModels2 = `package models
import (
"errors"
@ -288,7 +303,7 @@ import (
"{{.Appname}}/models"
"encoding/json"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// Operations about object
@ -381,7 +396,7 @@ import (
"{{.Appname}}/models"
"encoding/json"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// Operations about Users
@ -506,12 +521,13 @@ import (
"path/filepath"
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/core/logs"
. "github.com/smartystreets/goconvey/convey"
)
func init() {
_, file, _, _ := runtime.Caller(1)
_, file, _, _ := runtime.Caller(0)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
@ -522,7 +538,7 @@ func TestGet(t *testing.T) {
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
logs.Info("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
@ -535,139 +551,144 @@ func TestGet(t *testing.T) {
}
`
var gopath utils.DocValue
var beegoVersion utils.DocValue
func init() {
cmdApiapp.Run = createapi
cmdApiapp.Flag.Var(&tables, "tables", "specify tables to generate model")
cmdApiapp.Flag.Var(&driver, "driver", "database driver: mysql, postgresql, etc.")
cmdApiapp.Flag.Var(&conn, "conn", "connection string used by the driver to connect to a database instance")
CmdApiapp.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.")
CmdApiapp.Flag.Var(&generate.SQLDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
CmdApiapp.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the driver to connect to a database instance.")
CmdApiapp.Flag.Var(&gopath, "gopath", "Support go path,default false")
CmdApiapp.Flag.Var(&beegoVersion, "beego", "set beego version,only take effect by go mod")
commands.AvailableCommands = append(commands.AvailableCommands, CmdApiapp)
}
func createapi(cmd *Command, args []string) int {
ShowShortVersionBanner()
w := NewColorWriter(os.Stdout)
func createAPI(cmd *commands.Command, args []string) int {
output := cmd.Out()
if len(args) < 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
beeLogger.Log.Fatal("Argument [appname] is missing")
}
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
}
apppath, packpath, err := checkEnv(args[0])
if len(args) >= 2 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
fmt.Println(err)
beeLogger.Log.Fatal("Parse args err " + err.Error())
}
}
var appPath string
var packPath string
var err error
if gopath == `true` {
beeLogger.Log.Info("Generate api project support GOPATH")
version.ShowShortVersionBanner()
appPath, packPath, err = utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
} else {
beeLogger.Log.Info("Generate api project support go modules.")
appPath = path.Join(utils.GetBeeWorkPath(), args[0])
packPath = args[0]
if beegoVersion.String() == `` {
beegoVersion.Set(utils.BEEGO_VERSION)
}
}
if utils.IsExist(appPath) {
beeLogger.Log.Errorf(colors.Bold("Application '%s' already exists"), appPath)
beeLogger.Log.Warn(colors.Bold("Do you want to overwrite it? [Yes|No] "))
if !utils.AskForConfirmation() {
os.Exit(2)
}
if driver == "" {
driver = "mysql"
}
if conn == "" {
}
ColorLog("[INFO] Creating API...\n")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
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)
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, "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, "conf", "app.conf"), "\x1b[0m")
WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(apiconf, "{{.Appname}}", path.Base(args[0]), -1))
if conn != "" {
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
maingoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
if driver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if driver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
appName := path.Base(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
WriteToFile(path.Join(apppath, "main.go"),
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
beeLogger.Log.Info("Creating API...")
os.MkdirAll(appPath, 0755)
if gopath != `true` { //generate first for calc model name
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "go.mod"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "go.mod"), fmt.Sprintf(goMod, packPath, utils.GetGoVersionSkipMinor(), beegoVersion.String()))
}
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", appPath, "\x1b[0m")
os.Mkdir(path.Join(appPath, "conf"), 0755)
fmt.Fprintf(output, "\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)
fmt.Fprintf(output, "\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, "tests"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "tests"), "\x1b[0m")
if generate.SQLConn != "" {
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "conf", "app.conf"), "\x1b[0m")
confContent := strings.Replace(apiconf, "{{.Appname}}", appName, -1)
confContent = strings.Replace(confContent, "{{.SQLConnStr}}", generate.SQLConn.String(), -1)
utils.WriteToFile(path.Join(appPath, "conf", "app.conf"), confContent)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "main.go"), "\x1b[0m")
mainGoContent := strings.Replace(apiMainconngo, "{{.Appname}}", packPath, -1)
mainGoContent = strings.Replace(mainGoContent, "{{.DriverName}}", string(generate.SQLDriver), -1)
if generate.SQLDriver == "mysql" {
mainGoContent = strings.Replace(mainGoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if generate.SQLDriver == "postgres" {
mainGoContent = strings.Replace(mainGoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
utils.WriteToFile(path.Join(appPath, "main.go"),
strings.Replace(
maingoContent,
mainGoContent,
"{{.conn}}",
conn.String(),
generate.SQLConn.String(),
-1,
),
)
ColorLog("[INFO] Using '%s' as 'driver'\n", driver)
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
generateAppcode(string(driver), string(conn), "3", string(tables), apppath)
beeLogger.Log.Infof("Using '%s' as 'driver'", generate.SQLDriver)
beeLogger.Log.Infof("Using '%s' as 'conn'", generate.SQLConn)
beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables)
generate.GenerateAppcode(string(generate.SQLDriver), string(generate.SQLConn), "3", string(generate.Tables), appPath)
} else {
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")
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "conf", "app.conf"), "\x1b[0m")
confContent := strings.Replace(apiconf, "{{.Appname}}", appName, -1)
confContent = strings.Replace(confContent, "{{.SQLConnStr}}", "", -1)
utils.WriteToFile(path.Join(appPath, "conf", "app.conf"), confContent)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "object.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "controllers", "object.go"),
strings.Replace(apiControllers, "{{.Appname}}", packpath, -1))
os.Mkdir(path.Join(appPath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models"), "\x1b[0m")
os.Mkdir(path.Join(appPath, "routers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "routers")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "user.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "controllers", "user.go"),
strings.Replace(apiControllers2, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers", "object.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "controllers", "object.go"),
strings.Replace(apiControllers, "{{.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")
WriteToFile(path.Join(apppath, "tests", "default_test.go"),
strings.Replace(apiTests, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers", "user.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "controllers", "user.go"),
strings.Replace(apiControllers2, "{{.Appname}}", packPath, -1))
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(apirouter, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "tests", "default_test.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "tests", "default_test.go"),
strings.Replace(apiTests, "{{.Appname}}", packPath, -1))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "models", "object.go"), apiModels)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "routers", "router.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "routers", "router.go"),
strings.Replace(apirouter, "{{.Appname}}", packPath, -1))
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)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models", "object.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "models", "object.go"), APIModels)
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(apiMaingo, "{{.Appname}}", packpath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models", "user.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "models", "user.go"), APIModels2)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "main.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "main.go"),
strings.Replace(apiMaingo, "{{.Appname}}", packPath, -1))
}
ColorLog("[SUCC] New API successfully created!\n")
beeLogger.Log.Success("New API successfully created!")
return 0
}
func checkEnv(appname string) (apppath, packpath string, err error) {
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
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) {
return currpath, currpath[len(gsrcpath)+1:], nil
}
}
// In case of multiple paths in the GOPATH, by default
// we use the first path
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)
gosrcpath := path.Join(gopath, "src")
apppath = path.Join(gosrcpath, appname)
if _, e := os.Stat(apppath); os.IsNotExist(e) == false {
err = fmt.Errorf("Cannot create application without removing '%s' first.", apppath)
ColorLog("[ERRO] Path '%s' already exists\n", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(path.Separator)), "/")
return
}

View File

@ -11,8 +11,7 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package main
package bale
import (
"bytes"
@ -24,72 +23,70 @@ import (
"path/filepath"
"runtime"
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/config"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var cmdBale = &Command{
var CmdBale = &commands.Command{
UsageLine: "bale",
Short: "packs non-Go files to Go source files",
Long: `
Bale command compress all the static files in to a single binary file.
Short: "Transforms non-Go files to Go source files",
Long: `Bale command compress all the static files in to a single binary file.
This is usefull to not have to carry static files including js, css, images
and views when publishing a project.
auto-generate unpack function to main package then run it during the runtime.
This is mainly used for zealots who are requiring 100% Go code.
This is useful to not have to carry static files including js, css, images and
views when deploying a Web application.
It will auto-generate an unpack function to the main package then run it during the runtime.
This is mainly used for zealots who are requiring 100% Go code.
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: runBale,
}
func init() {
cmdBale.Run = runBale
commands.AvailableCommands = append(commands.AvailableCommands, CmdBale)
}
func runBale(cmd *Command, args []string) int {
ShowShortVersionBanner()
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
func runBale(cmd *commands.Command, args []string) int {
os.RemoveAll("bale")
os.Mkdir("bale", os.ModePerm)
// Pack and compress data.
for _, p := range conf.Bale.Dirs {
if !isExist(p) {
ColorLog("[WARN] Skipped directory( %s )\n", p)
// Pack and compress data
for _, p := range config.Conf.Bale.Dirs {
if !utils.IsExist(p) {
beeLogger.Log.Warnf("Skipped directory: %s", p)
continue
}
ColorLog("[INFO] Packaging directory( %s )\n", p)
beeLogger.Log.Infof("Packaging directory: %s", p)
filepath.Walk(p, walkFn)
}
// Generate auto-uncompress function.
buf := new(bytes.Buffer)
buf.WriteString(fmt.Sprintf(BaleHeader, conf.Bale.Import,
buf.WriteString(fmt.Sprintf(BaleHeader, config.Conf.Bale.Import,
strings.Join(resFiles, "\",\n\t\t\""),
strings.Join(resFiles, ",\n\t\tbale.R")))
fw, err := os.Create("bale.go")
if err != nil {
ColorLog("[ERRO] Fail to create file[ %s ]\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Failed to create file: %s", err)
}
defer fw.Close()
_, err = fw.Write(buf.Bytes())
if err != nil {
ColorLog("[ERRO] Fail to write data[ %s ]\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Failed to write data: %s", err)
}
ColorLog("[SUCC] Baled resources successfully!\n")
beeLogger.Log.Success("Baled resources successfully!")
return 0
}
const (
// BaleHeader ...
BaleHeader = `package main
import(
@ -145,19 +142,18 @@ func saveFile(filePath string, b []byte) (int, error) {
var resFiles = make([]string, 0, 10)
func walkFn(resPath string, info os.FileInfo, err error) error {
func walkFn(resPath string, info os.FileInfo, _ error) error {
if info.IsDir() || filterSuffix(resPath) {
return nil
}
// Open resource files.
// Open resource files
fr, err := os.Open(resPath)
if err != nil {
ColorLog("[ERRO] Fail to read file[ %s ]\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Failed to read file: %s", err)
}
// Convert path.
// Convert path
resPath = strings.Replace(resPath, "_", "_0_", -1)
resPath = strings.Replace(resPath, ".", "_1_", -1)
resPath = strings.Replace(resPath, "-", "_2_", -1)
@ -168,19 +164,18 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
}
resPath = strings.Replace(resPath, sep, "_4_", -1)
// Create corresponding Go source files.
// Create corresponding Go source files
os.MkdirAll(path.Dir(resPath), os.ModePerm)
fw, err := os.Create("bale/" + resPath + ".go")
if err != nil {
ColorLog("[ERRO] Fail to create file[ %s ]\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Failed to create file: %s", err)
}
defer fw.Close()
// Write header.
// Write header
fmt.Fprintf(fw, Header, resPath)
// Copy and compress data.
// Copy and compress data
gz := gzip.NewWriter(&ByteWriter{Writer: fw})
io.Copy(gz, fr)
gz.Close()
@ -193,7 +188,7 @@ func walkFn(resPath string, info os.FileInfo, err error) error {
}
func filterSuffix(name string) bool {
for _, s := range conf.Bale.IngExt {
for _, s := range config.Conf.Bale.IngExt {
if strings.HasSuffix(name, s) {
return true
}
@ -202,6 +197,7 @@ func filterSuffix(name string) bool {
}
const (
// Header ...
Header = `package bale
import(
@ -212,6 +208,7 @@ import(
func R%s() []byte {
gz, err := gzip.NewReader(bytes.NewBuffer([]byte{`
// Footer ...
Footer = `
}))
@ -229,6 +226,7 @@ func R%s() []byte {
var newline = []byte{'\n'}
// ByteWriter ...
type ByteWriter struct {
io.Writer
c int
@ -244,12 +242,9 @@ func (w *ByteWriter) Write(p []byte) (n int, err error) {
w.Writer.Write(newline)
w.c = 0
}
fmt.Fprintf(w.Writer, "0x%02x,", p[n])
w.c++
}
n++
return
}

View File

@ -0,0 +1,48 @@
package beefix
import (
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var CmdFix = &commands.Command{
UsageLine: "fix",
Short: "Fixes your application by making it compatible with newer versions of Beego",
Long: `
The command 'fix' will try to solve those issues by upgrading your code base
to be compatible with Beego old version
-s source version
-t target version
example: bee fix -s 1 -t 2 means that upgrade Beego version from v1.x to v2.x
`,
}
var (
source, target utils.DocValue
)
func init() {
CmdFix.Run = runFix
CmdFix.PreRun = func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() }
CmdFix.Flag.Var(&source, "s", "source version")
CmdFix.Flag.Var(&target, "t", "target version")
commands.AvailableCommands = append(commands.AvailableCommands, CmdFix)
}
func runFix(cmd *commands.Command, args []string) int {
t := target.String()
if t == "" || t == "1.6" {
return fixTo16(cmd, args)
} else if strings.HasPrefix(t, "2") {
// upgrade to v2
return fix1To2()
}
beeLogger.Log.Info("The target is compatible version, do nothing")
return 0
}

View File

@ -0,0 +1,61 @@
// Copyright 2020
//
// 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.
package beefix
import (
"os"
"os/exec"
beeLogger "github.com/beego/bee/v2/logger"
)
func fix1To2() int {
beeLogger.Log.Info("Upgrading the application...")
cmdStr := `go get -u github.com/beego/beego/v2@master`
err := runShell(cmdStr)
if err != nil {
beeLogger.Log.Error(err.Error())
beeLogger.Log.Error(`fetch v2.0.1 failed. Please try to run: export GO111MODULE=on
and if your network is not stable, please try to use proxy, for example: export GOPROXY=https://goproxy.cn;'
`)
return 1
}
cmdStr = `find ./ -name '*.go' -type f -exec sed -i '' -e 's/github.com\/astaxie\/beego/github.com\/beego\/beego\/v2\/adapter/g' {} \;`
err = runShell(cmdStr)
if err != nil {
beeLogger.Log.Error(err.Error())
return 1
}
cmdStr = `find ./ -name '*.go' -type f -exec sed -i '' -e 's/"github.com\/beego\/beego\/v2\/adapter"/beego "github.com\/beego\/beego\/v2\/adapter"/g' {} \;`
err = runShell(cmdStr)
if err != nil {
beeLogger.Log.Error(err.Error())
return 1
}
return 0
}
func runShell(cmdStr string) error {
c := exec.Command("sh", "-c", cmdStr)
c.Stdout = os.Stdout
err := c.Run()
if err != nil {
beeLogger.Log.Errorf("execute command [%s] failed: %s", cmdStr, err.Error())
return err
}
return nil
}

View File

@ -1,6 +1,21 @@
package main
// Copyright 2020
//
// 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.
package beefix
import (
"fmt"
"go/parser"
"go/token"
"io/ioutil"
@ -8,31 +23,23 @@ import (
"path/filepath"
"regexp"
"strings"
"fmt"
"github.com/beego/bee/v2/cmd/commands"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
)
var cmdFix = &Command{
UsageLine: "fix",
Short: "fix the beego application to make it compatible with beego 1.6",
Long: `
As from beego1.6, there's some incompatible code with the old version.
// fixTo16 upgrade beego to 1.6
func fixTo16(cmd *commands.Command, args []string) int {
output := cmd.Out()
bee fix help to upgrade the application to beego 1.6
`,
}
beeLogger.Log.Info("Upgrading the application...")
func init() {
cmdFix.Run = runFix
}
func runFix(cmd *Command, args []string) int {
ShowShortVersionBanner()
ColorLog("[INFO] Upgrading the application...\n")
dir, err := os.Getwd()
if err != nil {
ColorLog("[ERRO] GetCurrent Path:%s\n", err)
beeLogger.Log.Fatalf("Error while getting the current working directory: %s", err)
}
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if strings.HasPrefix(info.Name(), ".") {
@ -47,13 +54,13 @@ func runFix(cmd *Command, args []string) int {
return nil
}
err = fixFile(path)
fmt.Println("\tfix\t", path)
fmt.Fprintf(output, colors.GreenBold("\tfix\t")+"%s\n", path)
if err != nil {
ColorLog("[ERRO] Could not fix file: %s\n", err)
beeLogger.Log.Errorf("Could not fix file: %s", err)
}
return err
})
ColorLog("[INFO] Upgrade done!\n")
beeLogger.Log.Success("Upgrade Done!")
return 0
}
@ -167,18 +174,18 @@ func fixFile(file string) error {
}
fixed := rp.Replace(string(content))
// forword the RequestBody from the replace
// Forword the RequestBody from the replace
// "Input.Request", "Input.Context.Request",
fixed = strings.Replace(fixed, "Input.Context.RequestBody", "Input.RequestBody", -1)
// regexp replace
// Regexp replace
pareg := regexp.MustCompile(`(Input.Params\[")(.*)("])`)
fixed = pareg.ReplaceAllString(fixed, "Input.Param(\"$2\")")
pareg = regexp.MustCompile(`(Input.Data\[\")(.*)(\"\])(\s)(=)(\s)(.*)`)
fixed = pareg.ReplaceAllString(fixed, "Input.SetData(\"$2\", $7)")
pareg = regexp.MustCompile(`(Input.Data\[\")(.*)(\"\])`)
fixed = pareg.ReplaceAllString(fixed, "Input.Data(\"$2\")")
// fix the cache object Put method
// Fix the cache object Put method
pareg = regexp.MustCompile(`(\.Put\(\")(.*)(\",)(\s)(.*)(,\s*)([^\*.]*)(\))`)
if pareg.MatchString(fixed) && strings.HasSuffix(file, ".go") {
fixed = pareg.ReplaceAllString(fixed, ".Put(\"$2\", $5, $7*time.Second)")
@ -199,11 +206,11 @@ func fixFile(file string) error {
fixed = strings.Replace(fixed, "import (", "import (\n\t\"time\"", 1)
}
}
// replace the v.Apis in docs.go
// Replace the v.Apis in docs.go
if strings.Contains(file, "docs.go") {
fixed = strings.Replace(fixed, "v.Apis", "v.APIs", -1)
}
// replace the config file
// Replace the config file
if strings.HasSuffix(file, ".conf") {
fixed = strings.Replace(fixed, "HttpCertFile", "HTTPSCertFile", -1)
fixed = strings.Replace(fixed, "HttpKeyFile", "HTTPSKeyFile", -1)

View File

@ -0,0 +1,63 @@
// Copyright 2013 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.
package beegopro
import (
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/internal/app/module/beegopro"
"github.com/beego/bee/v2/logger"
)
var CmdBeegoPro = &commands.Command{
UsageLine: "pro [command]",
Short: "Source code generator",
Long: ``,
Run: BeegoPro,
}
func init() {
CmdBeegoPro.Flag.Var(&beegopro.SQL, "sql", "sql file path")
CmdBeegoPro.Flag.Var(&beegopro.SQLMode, "sqlmode", "sql mode")
CmdBeegoPro.Flag.Var(&beegopro.SQLModePath, "sqlpath", "sql mode path")
CmdBeegoPro.Flag.Var(&beegopro.GitRemotePath, "url", "git remote path")
commands.AvailableCommands = append(commands.AvailableCommands, CmdBeegoPro)
}
func BeegoPro(cmd *commands.Command, args []string) int {
if len(args) < 1 {
beeLogger.Log.Fatal("Command is missing")
}
if len(args) >= 2 {
cmd.Flag.Parse(args[1:])
}
gcmd := args[0]
switch gcmd {
case "gen":
beegopro.DefaultBeegoPro.Run()
case "toml":
beegopro.DefaultBeegoPro.InitToml()
case "config":
beegopro.DefaultBeegoPro.GenConfig()
case "migration":
beegopro.DefaultBeegoPro.Migration(args)
default:
beeLogger.Log.Fatal("Command is missing")
}
beeLogger.Log.Successf("%s successfully generated!", strings.Title(gcmd))
return 0
}

95
cmd/commands/command.go Normal file
View File

@ -0,0 +1,95 @@
package commands
import (
"flag"
"io"
"os"
"strings"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
// Command is the unit of execution
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string) int
// PreRun performs an operation before running the command
PreRun func(cmd *Command, args []string)
// UsageLine is the one-line Usage message.
// The first word in the line is taken to be the command name.
UsageLine string
// Short is the short description shown in the 'go help' output.
Short string
// Long is the long message shown in the 'go help <this-command>' output.
Long string
// Flag is a set of flags specific to this command.
Flag flag.FlagSet
// CustomFlags indicates that the command will do its own
// flag parsing.
CustomFlags bool
// output out writer if set in SetOutput(w)
output *io.Writer
}
var AvailableCommands = []*Command{}
var cmdUsage = `Use {{printf "bee help %s" .Name | bold}} for more information.{{endline}}`
// Name returns the command's name: the first word in the Usage line.
func (c *Command) Name() string {
name := c.UsageLine
i := strings.Index(name, " ")
if i >= 0 {
name = name[:i]
}
return name
}
// SetOutput sets the destination for Usage and error messages.
// If output is nil, os.Stderr is used.
func (c *Command) SetOutput(output io.Writer) {
c.output = &output
}
// Out returns the out writer of the current command.
// If cmd.output is nil, os.Stderr is used.
func (c *Command) Out() io.Writer {
if c.output != nil {
return *c.output
}
return colors.NewColorWriter(os.Stderr)
}
// Usage puts out the Usage for the command.
func (c *Command) Usage() {
utils.Tmpl(cmdUsage, c)
os.Exit(2)
}
// Runnable reports whether the command can be run; otherwise
// it is a documentation pseudo-command such as import path.
func (c *Command) Runnable() bool {
return c.Run != nil
}
func (c *Command) Options() map[string]string {
options := make(map[string]string)
c.Flag.VisitAll(func(f *flag.Flag) {
defaultVal := f.DefValue
if len(defaultVal) > 0 {
options[f.Name+"="+defaultVal] = f.Usage
} else {
options[f.Name] = f.Usage
}
})
return options
}

56
cmd/commands/dev/cmd.go Normal file
View File

@ -0,0 +1,56 @@
// Copyright 2020
//
// 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.
package dev
import (
"github.com/beego/bee/v2/cmd/commands"
beeLogger "github.com/beego/bee/v2/logger"
)
var CmdDev = &commands.Command{
CustomFlags: true,
UsageLine: "dev [command]",
Short: "Commands which used to help to develop beego and bee",
Long: `
Commands that help developer develop, build and test beego.
- githook Prepare githooks
`,
Run: Run,
}
func init() {
commands.AvailableCommands = append(commands.AvailableCommands, CmdDev)
}
func Run(cmd *commands.Command, args []string) int {
if len(args) < 1 {
beeLogger.Log.Fatal("Command is missing")
}
if len(args) >= 2 {
cmd.Flag.Parse(args[1:])
}
gcmd := args[0]
switch gcmd {
case "githook":
initGitHook()
default:
beeLogger.Log.Fatal("Unknown command")
}
return 0
}

View File

@ -0,0 +1,47 @@
// Copyright 2020
//
// 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.
package dev
import (
"os"
beeLogger "github.com/beego/bee/v2/logger"
)
var preCommit = `
goimports -w -format-only ./ \
ineffassign . \
staticcheck -show-ignored -checks "-ST1017,-U1000,-ST1005,-S1034,-S1012,-SA4006,-SA6005,-SA1019,-SA1024" ./ \
`
// for now, we simply override pre-commit file
func initGitHook() {
// pcf => pre-commit file
pcfPath := "./.git/hooks/pre-commit"
pcf, err := os.OpenFile(pcfPath, os.O_RDWR|os.O_CREATE, 0777)
if err != nil {
beeLogger.Log.Errorf("try to create or open file failed: %s, cause: %s", pcfPath, err.Error())
return
}
defer pcf.Close()
_, err = pcf.Write(([]byte)(preCommit))
if err != nil {
beeLogger.Log.Errorf("could not init githooks: %s", err.Error())
} else {
beeLogger.Log.Successf("The githooks has been added, the content is:\n %s ", preCommit)
}
}

16
cmd/commands/dlv/dlv.go Normal file
View File

@ -0,0 +1,16 @@
// Copyright 2017 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.
// Package dlv ...
package dlv

View File

@ -0,0 +1,249 @@
// Copyright 2017 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.
// Package dlv ...
package dlv
import (
"flag"
"fmt"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
"github.com/fsnotify/fsnotify"
"github.com/go-delve/delve/pkg/terminal"
"github.com/go-delve/delve/service"
"github.com/go-delve/delve/service/debugger"
"github.com/go-delve/delve/service/rpc2"
"github.com/go-delve/delve/service/rpccommon"
)
var cmdDlv = &commands.Command{
CustomFlags: true,
UsageLine: "dlv [-package=\"\"] [-port=8181] [-verbose=false]",
Short: "Start a debugging session using Delve",
Long: `dlv command start a debugging session using debugging tool Delve.
To debug your application using Delve, use: {{"$ bee dlv" | bold}}
For more information on Delve: https://github.com/go-delve/delve
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: runDlv,
}
var (
packageName string
verbose bool
port int
)
func init() {
fs := flag.NewFlagSet("dlv", flag.ContinueOnError)
fs.StringVar(&packageName, "package", "", "The package to debug (Must have a main package)")
fs.BoolVar(&verbose, "verbose", false, "Enable verbose mode")
fs.IntVar(&port, "port", 8181, "Port to listen to for clients")
cmdDlv.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, cmdDlv)
}
func runDlv(cmd *commands.Command, args []string) int {
if err := cmd.Flag.Parse(args); err != nil {
beeLogger.Log.Fatalf("Error while parsing flags: %v", err.Error())
}
var (
addr = fmt.Sprintf("127.0.0.1:%d", port)
paths = make([]string, 0)
notifyChan = make(chan int)
)
if err := loadPathsToWatch(&paths); err != nil {
beeLogger.Log.Fatalf("Error while loading paths to watch: %v", err.Error())
}
go startWatcher(paths, notifyChan)
return startDelveDebugger(addr, notifyChan)
}
// buildDebug builds a debug binary in the current working directory
func buildDebug() (string, error) {
args := []string{"-gcflags", "-N -l", "-o", "debug"}
args = append(args, utils.SplitQuotedFields("-ldflags='-linkmode internal'")...)
args = append(args, packageName)
if err := utils.GoCommand("build", args...); err != nil {
return "", err
}
fp, err := filepath.Abs("./debug")
if err != nil {
return "", err
}
return fp, nil
}
// loadPathsToWatch loads the paths that needs to be watched for changes
func loadPathsToWatch(paths *[]string) error {
directory, err := os.Getwd()
if err != nil {
return err
}
filepath.Walk(directory, func(path string, info os.FileInfo, _ error) error {
if strings.HasSuffix(info.Name(), "docs") {
return filepath.SkipDir
}
if strings.HasSuffix(info.Name(), "swagger") {
return filepath.SkipDir
}
if strings.HasSuffix(info.Name(), "vendor") {
return filepath.SkipDir
}
if filepath.Ext(info.Name()) == ".go" {
*paths = append(*paths, path)
}
return nil
})
return nil
}
// startDelveDebugger starts the Delve debugger server
func startDelveDebugger(addr string, ch chan int) int {
beeLogger.Log.Info("Starting Delve Debugger...")
fp, err := buildDebug()
if err != nil {
beeLogger.Log.Fatalf("Error while building debug binary: %v", err)
}
defer os.Remove(fp)
abs, err := filepath.Abs("./debug")
if err != nil {
beeLogger.Log.Fatalf("%v", err)
}
// Create and start the debugger server
listener, err := net.Listen("tcp", addr)
if err != nil {
beeLogger.Log.Fatalf("Could not start listener: %s", err)
}
defer listener.Close()
server := rpccommon.NewServer(&service.Config{
Listener: listener,
AcceptMulti: true,
APIVersion: 2,
ProcessArgs: []string{abs},
Debugger: debugger.Config{
AttachPid: 0,
WorkingDir: ".",
Backend: "default",
},
})
if err := server.Run(); err != nil {
beeLogger.Log.Fatalf("Could not start debugger server: %v", err)
}
// Start the Delve client REPL
client := rpc2.NewClient(addr)
// Make sure the client is restarted when new changes are introduced
go func() {
for {
if val := <-ch; val == 0 {
if _, err := client.Restart(true); err != nil {
utils.Notify("Error while restarting the client: "+err.Error(), "bee")
} else {
if verbose {
utils.Notify("Delve Debugger Restarted", "bee")
}
}
}
}
}()
// Create the terminal and connect it to the client debugger
term := terminal.New(client, nil)
status, err := term.Run()
if err != nil {
beeLogger.Log.Fatalf("Could not start Delve REPL: %v", err)
}
// Stop and kill the debugger server once user quits the REPL
if err := server.Stop(); err != nil {
beeLogger.Log.Fatalf("Could not stop Delve server: %v", err)
}
return status
}
var eventsModTime = make(map[string]int64)
// startWatcher starts the fsnotify watcher on the passed paths
func startWatcher(paths []string, ch chan int) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
beeLogger.Log.Fatalf("Could not start the watcher: %v", err)
}
defer watcher.Close()
// Feed the paths to the watcher
for _, path := range paths {
if err := watcher.Add(path); err != nil {
beeLogger.Log.Fatalf("Could not set a watch on path: %v", err)
}
}
for {
select {
case evt := <-watcher.Events:
build := true
if filepath.Ext(evt.Name) != ".go" {
continue
}
mt := utils.GetFileModTime(evt.Name)
if t := eventsModTime[evt.Name]; mt == t {
build = false
}
eventsModTime[evt.Name] = mt
if build {
go func() {
if verbose {
utils.Notify("Rebuilding application with the new changes", "bee")
}
// Wait 1s before re-build until there is no file change
scheduleTime := time.Now().Add(1 * time.Second)
time.Sleep(time.Until(scheduleTime))
_, err := buildDebug()
if err != nil {
utils.Notify("Build Failed: "+err.Error(), "bee")
} else {
ch <- 0 // Notify listeners
}
}()
}
case err := <-watcher.Errors:
if err != nil {
ch <- -1
}
}
}
}

View File

@ -0,0 +1,170 @@
// 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.
package dockerize
import (
"flag"
"os"
"path"
"path/filepath"
"strings"
"text/template"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
const dockerBuildTemplate = `# Build Golang binary
FROM {{.BaseImage}} AS build-golang
WORKDIR {{.Appdir}}
COPY . .
RUN go get -v && go build -v -o /usr/local/bin/{{.Entrypoint}}
EXPOSE {{.Expose}}
CMD ["{{.Entrypoint}}"]
`
const composeBuildTemplate = `version: '3'
networks:
{{.Appname}}_network_compose:
driver: bridge
services:
{{.Appname}}:
container_name: {{.Appname}}
build: .
restart: unless-stopped
networks:
{{.Appname}}_network_compose:
ports:{{.Expose}}
`
// Dockerfile holds the information about the Docker container.
type Dockerfile struct {
BaseImage string
Appdir string
Entrypoint string
Expose string
}
// docker-compose.yaml
type Composefile struct {
Appname string
Expose string
}
var CmdDockerize = &commands.Command{
CustomFlags: true,
UsageLine: "dockerize",
Short: "Generates a Dockerfile and docker-compose.yaml for your Beego application",
Long: `Dockerize generates a Dockerfile and docker-compose.yaml for your Beego Web Application.
The Dockerfile will compile and run the application.
The docker-compose.yaml can be used to build and deploy the generated Dockerfile.
{{"Example:"|bold}}
$ bee dockerize -expose="3000,80,25"
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: dockerizeApp,
}
var (
expose string
baseImage string
)
func init() {
fs := flag.NewFlagSet("dockerize", flag.ContinueOnError)
fs.StringVar(&baseImage, "baseimage", "golang:1.20.2", "Set the base image of the Docker container.")
fs.StringVar(&expose, "expose", "8080", "Port(s) to expose for the Docker container.")
CmdDockerize.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdDockerize)
}
func dockerizeApp(cmd *commands.Command, args []string) int {
if err := cmd.Flag.Parse(args); err != nil {
beeLogger.Log.Fatalf("Error parsing flags: %v", err.Error())
}
beeLogger.Log.Info("Generating Dockerfile and docker-compose.yaml...")
gopath := os.Getenv("GOPATH")
dir, err := filepath.Abs(".")
if err != nil {
beeLogger.Log.Error(err.Error())
}
appdir := strings.Replace(dir, gopath, "", 1)
// In case of multiple ports to expose inside the container,
// replace all the commas with whitespaces.
// See the verb EXPOSE in the Docker documentation.
exposedockerfile := strings.Replace(expose, ",", " ", -1)
// Multiple ports expose for docker-compose.yaml
ports := strings.Fields(strings.Replace(expose, ",", " ", -1))
exposecompose := ""
for _, port := range ports {
composeport := ("\n - " + "\"" + port + ":" + port + "\"")
exposecompose += composeport
}
_, entrypoint := path.Split(appdir)
dockerfile := Dockerfile{
BaseImage: baseImage,
Appdir: appdir,
Entrypoint: entrypoint,
Expose: exposedockerfile,
}
composefile := Composefile{
Appname: entrypoint,
Expose: exposecompose,
}
generateDockerfile(dockerfile)
generatecomposefile(composefile)
return 0
}
func generateDockerfile(df Dockerfile) {
t := template.Must(template.New("dockerBuildTemplate").Parse(dockerBuildTemplate)).Funcs(utils.BeeFuncMap())
f, err := os.Create("Dockerfile")
if err != nil {
beeLogger.Log.Fatalf("Error writing Dockerfile: %v", err.Error())
}
defer utils.CloseFile(f)
t.Execute(f, df)
beeLogger.Log.Success("Dockerfile generated.")
}
func generatecomposefile(df Composefile) {
t := template.Must(template.New("composeBuildTemplate").Parse(composeBuildTemplate)).Funcs(utils.BeeFuncMap())
f, err := os.Create("docker-compose.yaml")
if err != nil {
beeLogger.Log.Fatalf("Error writing docker-compose.yaml: %v", err.Error())
}
defer utils.CloseFile(f)
t.Execute(f, df)
beeLogger.Log.Success("docker-compose.yaml generated.")
}

View File

@ -0,0 +1,234 @@
// Copyright 2013 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.
package generate
import (
"os"
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/config"
"github.com/beego/bee/v2/generate"
"github.com/beego/bee/v2/generate/swaggergen"
"github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var CmdGenerate = &commands.Command{
UsageLine: "generate [command]",
Short: "Source code generator",
Long: ` {{"To scaffold out your entire application:"|bold}}
$ bee generate scaffold [scaffoldname] [-fields="title:string,body:text"] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
{{"To generate a Model based on fields:"|bold}}
$ bee generate model [modelname] [-fields="name:type"]
{{"To generate a controller:"|bold}}
$ bee generate controller [controllerfile]
{{"To generate a CRUD view:"|bold}}
$ bee generate view [viewpath]
{{"To generate a migration file for making database schema updates:"|bold}}
$ bee generate migration [migrationfile] [-fields="name:type"]
{{"To generate swagger doc file:"|bold}}
$ bee generate docs
{{"To generate swagger doc file:"|bold}}
$ bee generate routers [-ctrlDir=/path/to/controller/directory] [-routersFile=/path/to/routers/file.go] [-routersPkg=myPackage]
{{"To generate a test case:"|bold}}
$ bee generate test [routerfile]
{{"To generate appcode based on an existing database:"|bold}}
$ bee generate appcode [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-level=3]
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: GenerateCode,
}
func init() {
CmdGenerate.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.")
CmdGenerate.Flag.Var(&generate.SQLDriver, "driver", "Database SQLDriver. Either mysql, postgres or sqlite.")
CmdGenerate.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the SQLDriver to connect to a database instance.")
CmdGenerate.Flag.Var(&generate.Level, "level", "Either 1, 2 or 3. i.e. 1=models; 2=models and controllers; 3=models, controllers and routers.")
CmdGenerate.Flag.Var(&generate.Fields, "fields", "List of table Fields.")
CmdGenerate.Flag.Var(&generate.DDL, "ddl", "Generate DDL Migration")
// bee generate routers
CmdGenerate.Flag.Var(&generate.ControllerDirectory, "ctrlDir",
"Controller directory. Bee scans this directory and its sub directory to generate routers")
CmdGenerate.Flag.Var(&generate.RoutersFile, "routersFile",
"Routers file. If not found, Bee create a new one. Bee will truncates this file and output routers info into this file")
CmdGenerate.Flag.Var(&generate.RouterPkg, "routersPkg",
`router's package. Default is routers, it means that "package routers" in the generated file`)
commands.AvailableCommands = append(commands.AvailableCommands, CmdGenerate)
}
func GenerateCode(cmd *commands.Command, args []string) int {
currpath, _ := os.Getwd()
if len(args) < 1 {
beeLogger.Log.Fatal("Command is missing")
}
gcmd := args[0]
switch gcmd {
case "scaffold":
scaffold(cmd, args, currpath)
case "docs":
swaggergen.GenerateDocs(currpath)
case "appcode":
appCode(cmd, args, currpath)
case "migration":
migration(cmd, args, currpath)
case "controller":
controller(args, currpath)
case "model":
model(cmd, args, currpath)
case "view":
view(args, currpath)
case "routers":
genRouters(cmd, args)
default:
beeLogger.Log.Fatal("Command is missing")
}
beeLogger.Log.Successf("%s successfully generated!", strings.Title(gcmd))
return 0
}
func genRouters(cmd *commands.Command, args []string) {
err := cmd.Flag.Parse(args[1:])
beeLogger.Log.Infof("input parameter: %v", args)
if err != nil {
beeLogger.Log.Errorf("could not parse input parameter: %+v", err)
return
}
generate.GenRouters()
}
func scaffold(cmd *commands.Command, args []string, currpath string) {
if len(args) < 2 {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
if generate.SQLDriver == "" {
generate.SQLDriver = utils.DocValue(config.Conf.Database.Driver)
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
}
if generate.SQLConn == "" {
generate.SQLConn = utils.DocValue(config.Conf.Database.Conn)
if generate.SQLConn == "" {
generate.SQLConn = "root:@tcp(127.0.0.1:3306)/test"
}
}
if generate.Fields == "" {
beeLogger.Log.Hint("Fields option should not be empty, i.e. -Fields=\"title:string,body:text\"")
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
sname := args[1]
generate.GenerateScaffold(sname, generate.Fields.String(), currpath, generate.SQLDriver.String(), generate.SQLConn.String())
}
func appCode(cmd *commands.Command, args []string, currpath string) {
cmd.Flag.Parse(args[1:])
if generate.SQLDriver == "" {
generate.SQLDriver = utils.DocValue(config.Conf.Database.Driver)
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
}
if generate.SQLConn == "" {
generate.SQLConn = utils.DocValue(config.Conf.Database.Conn)
if generate.SQLConn == "" {
if generate.SQLDriver == "mysql" {
generate.SQLConn = "root:@tcp(127.0.0.1:3306)/test"
} else if generate.SQLDriver == "postgres" {
generate.SQLConn = "postgres://postgres:postgres@127.0.0.1:5432/postgres"
}
}
}
if generate.Level == "" {
generate.Level = "3"
}
beeLogger.Log.Infof("Using '%s' as 'SQLDriver'", generate.SQLDriver)
beeLogger.Log.Infof("Using '%s' as 'SQLConn'", generate.SQLConn)
beeLogger.Log.Infof("Using '%s' as 'Tables'", generate.Tables)
beeLogger.Log.Infof("Using '%s' as 'Level'", generate.Level)
generate.GenerateAppcode(generate.SQLDriver.String(), generate.SQLConn.String(), generate.Level.String(), generate.Tables.String(), currpath)
}
func migration(cmd *commands.Command, args []string, currpath string) {
if len(args) < 2 {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
mname := args[1]
beeLogger.Log.Infof("Using '%s' as migration name", mname)
upsql := ""
downsql := ""
if generate.Fields != "" {
dbMigrator := generate.NewDBDriver()
upsql = dbMigrator.GenerateCreateUp(mname)
downsql = dbMigrator.GenerateCreateDown(mname)
}
generate.GenerateMigration(mname, upsql, downsql, currpath)
}
func controller(args []string, currpath string) {
if len(args) == 2 {
cname := args[1]
generate.GenerateController(cname, currpath)
} else {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
}
func model(cmd *commands.Command, args []string, currpath string) {
if len(args) < 2 {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
cmd.Flag.Parse(args[2:])
if generate.Fields == "" {
beeLogger.Log.Hint("Fields option should not be empty, i.e. -Fields=\"title:string,body:text\"")
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
sname := args[1]
generate.GenerateModel(sname, generate.Fields.String(), currpath)
}
func view(args []string, currpath string) {
if len(args) == 2 {
cname := args[1]
generate.GenerateView(cname, currpath)
} else {
beeLogger.Log.Fatal("Wrong number of arguments. Run: bee help generate")
}
}

View File

@ -0,0 +1,164 @@
package hprose
import (
"fmt"
"os"
"path"
"strings"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/api"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/generate"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var CmdHproseapp = &commands.Command{
// CustomFlags: true,
UsageLine: "hprose [appname]",
Short: "Creates an RPC application based on Hprose and Beego frameworks",
Long: `
The command 'hprose' creates an RPC application based on both Beego and Hprose (http://hprose.com/).
{{"To scaffold out your application, use:"|bold}}
$ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-gopath=false] [-beego=v1.12.3]
If 'conn' is empty, the command will generate a sample application. Otherwise the command
will connect to your database and generate models based on the existing tables.
The command 'hprose' creates a folder named [appname] with the following structure:
main.go
go.mod
{{"conf"|foldername}}
app.conf
{{"models"|foldername}}
object.go
user.go
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: createhprose,
}
var goMod = `
module %s
go %s
require github.com/beego/beego/v2 %s
require github.com/smartystreets/goconvey v1.6.4
`
var gopath utils.DocValue
var beegoVersion utils.DocValue
func init() {
CmdHproseapp.Flag.Var(&generate.Tables, "tables", "List of table names separated by a comma.")
CmdHproseapp.Flag.Var(&generate.SQLDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
CmdHproseapp.Flag.Var(&generate.SQLConn, "conn", "Connection string used by the driver to connect to a database instance.")
CmdHproseapp.Flag.Var(&gopath, "gopath", "Support go path,default false")
CmdHproseapp.Flag.Var(&beegoVersion, "beego", "set beego version,only take effect by go mod")
commands.AvailableCommands = append(commands.AvailableCommands, CmdHproseapp)
}
func createhprose(cmd *commands.Command, args []string) int {
output := cmd.Out()
if len(args) == 0 {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
curpath, _ := os.Getwd()
if len(args) >= 2 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
beeLogger.Log.Fatal("Parse args err " + err.Error())
}
}
var apppath string
var packpath string
var err error
if gopath == `true` {
beeLogger.Log.Info("Generate api project support GOPATH")
version.ShowShortVersionBanner()
apppath, packpath, err = utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
} else {
beeLogger.Log.Info("Generate api project support go modules.")
apppath = path.Join(utils.GetBeeWorkPath(), args[0])
packpath = args[0]
if beegoVersion.String() == `` {
beegoVersion.Set(utils.BEEGO_VERSION)
}
}
if utils.IsExist(apppath) {
beeLogger.Log.Errorf(colors.Bold("Application '%s' already exists"), apppath)
beeLogger.Log.Warn(colors.Bold("Do you want to overwrite it? [Yes|No] "))
if !utils.AskForConfirmation() {
os.Exit(2)
}
}
if generate.SQLDriver == "" {
generate.SQLDriver = "mysql"
}
beeLogger.Log.Info("Creating Hprose application...")
os.MkdirAll(apppath, 0755)
if gopath != `true` { //generate first for calc model name
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "go.mod"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "go.mod"), fmt.Sprintf(goMod, packpath, utils.GetGoVersionSkipMinor(), beegoVersion.String()))
}
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf", "app.conf"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(generate.Hproseconf, "{{.Appname}}", args[0], -1))
if generate.SQLConn != "" {
beeLogger.Log.Infof("Using '%s' as 'driver'", generate.SQLDriver)
beeLogger.Log.Infof("Using '%s' as 'conn'", generate.SQLConn)
beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables)
generate.GenerateHproseAppcode(string(generate.SQLDriver), string(generate.SQLConn), "1", string(generate.Tables), path.Join(curpath, args[0]))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
maingoContent := strings.Replace(generate.HproseMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(generate.SQLDriver), -1)
maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(generate.HproseAddFunctions, ""), -1)
if generate.SQLDriver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if generate.SQLDriver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
utils.WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
generate.SQLConn.String(),
-1,
),
)
} else {
os.Mkdir(path.Join(apppath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models"), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "object.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "models", "object.go"), apiapp.APIModels)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "models", "user.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "models", "user.go"), apiapp.APIModels2)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(generate.HproseMaingo, "{{.Appname}}", packpath, -1))
}
beeLogger.Log.Success("New Hprose application successfully created!")
return 0
}

View File

@ -11,151 +11,144 @@
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
package main
package migrate
import (
"database/sql"
"fmt"
"os"
"os/exec"
"path"
"runtime"
"strconv"
"strings"
"time"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/config"
"github.com/beego/bee/v2/utils"
beeLogger "github.com/beego/bee/v2/logger"
)
var cmdMigrate = &Command{
var CmdMigrate = &commands.Command{
UsageLine: "migrate [Command]",
Short: "run database migrations",
Long: `
bee migrate [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
run all outstanding migrations
-driver: [mysql | postgres | sqlite] (default: mysql)
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
Short: "Runs database migrations",
Long: `The command 'migrate' allows you to run database migrations to keep it up-to-date.
bee migrate rollback [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
rollback the last migration operation
-driver: [mysql | postgres | sqlite] (default: mysql)
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
{{"To run all the migrations:"|bold}}
bee migrate reset [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
rollback all migrations
-driver: [mysql | postgres | sqlite] (default: mysql)
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
$ bee migrate [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-dir="path/to/migration"]
bee migrate refresh [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
rollback all migrations and run them all again
-driver: [mysql | postgres | sqlite] (default: mysql)
-conn: the connection string used by the driver, the default is root:@tcp(127.0.0.1:3306)/test
{{"To rollback the last migration:"|bold}}
$ bee migrate rollback [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-dir="path/to/migration"]
{{"To do a reset, which will rollback all the migrations:"|bold}}
$ bee migrate reset [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-dir="path/to/migration"]
{{"To update your schema:"|bold}}
$ bee migrate refresh [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"] [-dir="path/to/migration"]
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: RunMigration,
}
var mDriver docValue
var mConn docValue
var mDriver utils.DocValue
var mConn utils.DocValue
var mDir utils.DocValue
func init() {
cmdMigrate.Run = runMigration
cmdMigrate.Flag.Var(&mDriver, "driver", "database driver: mysql, postgres, sqlite, etc.")
cmdMigrate.Flag.Var(&mConn, "conn", "connection string used by the driver to connect to a database instance")
CmdMigrate.Flag.Var(&mDriver, "driver", "Database driver. Either mysql, postgres or sqlite.")
CmdMigrate.Flag.Var(&mConn, "conn", "Connection string used by the driver to connect to a database instance.")
CmdMigrate.Flag.Var(&mDir, "dir", "The directory where the migration files are stored")
commands.AvailableCommands = append(commands.AvailableCommands, CmdMigrate)
}
// runMigration is the entry point for starting a migration
func runMigration(cmd *Command, args []string) int {
ShowShortVersionBanner()
func RunMigration(cmd *commands.Command, args []string) int {
currpath, _ := os.Getwd()
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
gopath := gps[0]
Debugf("GOPATH: %s", gopath)
// load config
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
// getting command line arguments
// Getting command line arguments
if len(args) != 0 {
cmd.Flag.Parse(args[1:])
}
if mDriver == "" {
mDriver = docValue(conf.Database.Driver)
mDriver = utils.DocValue(config.Conf.Database.Driver)
if mDriver == "" {
mDriver = "mysql"
}
}
if mConn == "" {
mConn = docValue(conf.Database.Conn)
mConn = utils.DocValue(config.Conf.Database.Conn)
if mConn == "" {
mConn = "root:@tcp(127.0.0.1:3306)/test"
}
}
ColorLog("[INFO] Using '%s' as 'driver'\n", mDriver)
ColorLog("[INFO] Using '%s' as 'conn'\n", mConn)
driverStr, connStr := string(mDriver), string(mConn)
if mDir == "" {
mDir = utils.DocValue(config.Conf.Database.Dir)
if mDir == "" {
mDir = utils.DocValue(path.Join(currpath, "database", "migrations"))
}
}
beeLogger.Log.Infof("Using '%s' as 'driver'", mDriver)
//Log sensitive connection information only when DEBUG is set to true.
beeLogger.Log.Debugf("Conn: %s", utils.FILE(), utils.LINE(), mConn)
beeLogger.Log.Infof("Using '%s' as 'dir'", mDir)
driverStr, connStr, dirStr := string(mDriver), string(mConn), string(mDir)
dirRune := []rune(dirStr)
if dirRune[0] != '/' && dirRune[1] != ':' {
dirStr = path.Join(currpath, dirStr)
}
if len(args) == 0 {
// run all outstanding migrations
ColorLog("[INFO] Running all outstanding migrations\n")
migrateUpdate(currpath, driverStr, connStr)
beeLogger.Log.Info("Running all outstanding migrations")
MigrateUpdate(currpath, driverStr, connStr, dirStr)
} else {
mcmd := args[0]
switch mcmd {
case "rollback":
ColorLog("[INFO] Rolling back the last migration operation\n")
migrateRollback(currpath, driverStr, connStr)
beeLogger.Log.Info("Rolling back the last migration operation")
MigrateRollback(currpath, driverStr, connStr, dirStr)
case "reset":
ColorLog("[INFO] Reseting all migrations\n")
migrateReset(currpath, driverStr, connStr)
beeLogger.Log.Info("Reseting all migrations")
MigrateReset(currpath, driverStr, connStr, dirStr)
case "refresh":
ColorLog("[INFO] Refreshing all migrations\n")
migrateRefresh(currpath, driverStr, connStr)
beeLogger.Log.Info("Refreshing all migrations")
MigrateRefresh(currpath, driverStr, connStr, dirStr)
default:
ColorLog("[ERRO] Command is missing\n")
os.Exit(2)
beeLogger.Log.Fatal("Command is missing")
}
}
ColorLog("[SUCC] Migration successful!\n")
beeLogger.Log.Success("Migration successful!")
return 0
}
// migrateUpdate does the schema update
func migrateUpdate(currpath, driver, connStr string) {
migrate("upgrade", currpath, driver, connStr)
}
// migrateRollback rolls back the latest migration
func migrateRollback(currpath, driver, connStr string) {
migrate("rollback", currpath, driver, connStr)
}
// migrateReset rolls back all migrations
func migrateReset(currpath, driver, connStr string) {
migrate("reset", currpath, driver, connStr)
}
// migrationRefresh rolls back all migrations and start over again
func migrateRefresh(currpath, driver, connStr string) {
migrate("refresh", currpath, driver, connStr)
}
// migrate generates source code, build it, and invoke the binary who does the actual migration
func migrate(goal, currpath, driver, connStr string) {
dir := path.Join(currpath, "database", "migrations")
binary := "m"
func migrate(goal, currpath, driver, connStr, dir string) {
if dir == "" {
dir = path.Join(currpath, "database", "migrations")
}
postfix := ""
if runtime.GOOS == "windows" {
postfix = ".exe"
}
binary := "m" + postfix
source := binary + ".go"
// connect to database
// Connect to database
db, err := sql.Open(driver, connStr)
if err != nil {
ColorLog("[ERRO] Could not connect to %s: %s\n", driver, connStr)
ColorLog("[ERRO] Error: %v", err.Error())
os.Exit(2)
beeLogger.Log.Fatalf("Could not connect to database using '%s': %s", connStr, err)
}
defer db.Close()
checkForSchemaUpdateTable(db, driver)
latestName, latestTime := getLatestMigration(db, goal)
writeMigrationSourceFile(dir, source, driver, connStr, latestTime, latestName, goal)
@ -170,56 +163,61 @@ func migrate(goal, currpath, driver, connStr string) {
func checkForSchemaUpdateTable(db *sql.DB, driver string) {
showTableSQL := showMigrationsTableSQL(driver)
if rows, err := db.Query(showTableSQL); err != nil {
ColorLog("[ERRO] Could not show migrations table: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not show migrations table: %s", err)
} else if !rows.Next() {
// no migrations table, create anew
// No migrations table, create new ones
createTableSQL := createMigrationsTableSQL(driver)
ColorLog("[INFO] Creating 'migrations' table...\n")
beeLogger.Log.Infof("Creating 'migrations' table...")
if _, err := db.Query(createTableSQL); err != nil {
ColorLog("[ERRO] Could not create migrations table: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create migrations table: %s", err)
}
}
// checking that migrations table schema are expected
// Checking that migrations table schema are expected
selectTableSQL := selectMigrationsTableSQL(driver)
if rows, err := db.Query(selectTableSQL); err != nil {
ColorLog("[ERRO] Could not show columns of migrations table: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not show columns of migrations table: %s", err)
} else {
for rows.Next() {
var fieldBytes, typeBytes, nullBytes, keyBytes, defaultBytes, extraBytes []byte
if err := rows.Scan(&fieldBytes, &typeBytes, &nullBytes, &keyBytes, &defaultBytes, &extraBytes); err != nil {
ColorLog("[ERRO] Could not read column information: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not read column information: %s", err)
}
fieldStr, typeStr, nullStr, keyStr, defaultStr, extraStr :=
string(fieldBytes), string(typeBytes), string(nullBytes), string(keyBytes), string(defaultBytes), string(extraBytes)
if fieldStr == "id_migration" {
if keyStr != "PRI" || extraStr != "auto_increment" {
ColorLog("[ERRO] Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s\n", keyStr, extraStr)
ColorLog("[HINT] Expecting KEY: PRI, EXTRA: auto_increment\n")
os.Exit(2)
beeLogger.Log.Hint("Expecting KEY: PRI, EXTRA: auto_increment")
beeLogger.Log.Fatalf("Column migration.id_migration type mismatch: KEY: %s, EXTRA: %s", keyStr, extraStr)
}
} else if fieldStr == "name" {
if !strings.HasPrefix(typeStr, "varchar") || nullStr != "YES" {
ColorLog("[ERRO] Column migration.name type mismatch: TYPE: %s, NULL: %s\n", typeStr, nullStr)
ColorLog("[HINT] Expecting TYPE: varchar, NULL: YES\n")
os.Exit(2)
beeLogger.Log.Hint("Expecting TYPE: varchar, NULL: YES")
beeLogger.Log.Fatalf("Column migration.name type mismatch: TYPE: %s, NULL: %s", typeStr, nullStr)
}
} else if fieldStr == "created_at" {
if typeStr != "timestamp" || defaultStr != "CURRENT_TIMESTAMP" {
ColorLog("[ERRO] Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s\n", typeStr, defaultStr)
ColorLog("[HINT] Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP\n")
os.Exit(2)
if typeStr != "timestamp" || (!strings.EqualFold(defaultStr, "CURRENT_TIMESTAMP") && !strings.EqualFold(defaultStr, "CURRENT_TIMESTAMP()")) {
beeLogger.Log.Hint("Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP || CURRENT_TIMESTAMP()")
beeLogger.Log.Fatalf("Column migration.timestamp type mismatch: TYPE: %s, DEFAULT: %s", typeStr, defaultStr)
}
}
}
}
}
func driverImportStatement(driver string) string {
switch driver {
case "mysql":
return "github.com/go-sql-driver/mysql"
case "postgres":
return "github.com/lib/pq"
default:
return "github.com/go-sql-driver/mysql"
}
}
func showMigrationsTableSQL(driver string) string {
switch driver {
case "mysql":
@ -257,26 +255,22 @@ func selectMigrationsTableSQL(driver string) string {
func getLatestMigration(db *sql.DB, goal string) (file string, createdAt int64) {
sql := "SELECT name FROM migrations where status = 'update' ORDER BY id_migration DESC LIMIT 1"
if rows, err := db.Query(sql); err != nil {
ColorLog("[ERRO] Could not retrieve migrations: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not retrieve migrations: %s", err)
} else {
if rows.Next() {
if err := rows.Scan(&file); err != nil {
ColorLog("[ERRO] Could not read migrations in database: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not read migrations in database: %s", err)
}
createdAtStr := file[len(file)-15:]
if t, err := time.Parse("20060102_150405", createdAtStr); err != nil {
ColorLog("[ERRO] Could not parse time: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not parse time: %s", err)
} else {
createdAt = t.Unix()
}
} else {
// migration table has no 'update' record, no point rolling back
if goal == "rollback" {
ColorLog("[ERRO] There is nothing to rollback\n")
os.Exit(2)
beeLogger.Log.Fatal("There is nothing to rollback")
}
file, createdAt = "", 0
}
@ -288,19 +282,18 @@ func getLatestMigration(db *sql.DB, goal string) (file string, createdAt int64)
func writeMigrationSourceFile(dir, source, driver, connStr string, latestTime int64, latestName string, task string) {
changeDir(dir)
if f, err := os.OpenFile(source, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err != nil {
ColorLog("[ERRO] Could not create file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create file: %s", err)
} else {
content := strings.Replace(MigrationMainTPL, "{{DBDriver}}", driver, -1)
content = strings.Replace(content, "{{DriverRepo}}", driverImportStatement(driver), -1)
content = strings.Replace(content, "{{ConnStr}}", connStr, -1)
content = strings.Replace(content, "{{LatestTime}}", strconv.FormatInt(latestTime, 10), -1)
content = strings.Replace(content, "{{LatestName}}", latestName, -1)
content = strings.Replace(content, "{{Task}}", task, -1)
if _, err := f.WriteString(content); err != nil {
ColorLog("[ERRO] Could not write to file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not write to file: %s", err)
}
CloseFile(f)
utils.CloseFile(f)
}
}
@ -309,7 +302,7 @@ func buildMigrationBinary(dir, binary string) {
changeDir(dir)
cmd := exec.Command("go", "build", "-o", binary)
if out, err := cmd.CombinedOutput(); err != nil {
ColorLog("[ERRO] Could not build migration binary: %s\n", err)
beeLogger.Log.Errorf("Could not build migration binary: %s", err)
formatShellErrOutput(string(out))
removeTempFile(dir, binary)
removeTempFile(dir, binary+".go")
@ -323,7 +316,7 @@ func runMigrationBinary(dir, binary string) {
cmd := exec.Command("./" + binary)
if out, err := cmd.CombinedOutput(); err != nil {
formatShellOutput(string(out))
ColorLog("[ERRO] Could not run migration binary: %s\n", err)
beeLogger.Log.Errorf("Could not run migration binary: %s", err)
removeTempFile(dir, binary)
removeTempFile(dir, binary+".go")
os.Exit(2)
@ -336,8 +329,7 @@ func runMigrationBinary(dir, binary string) {
// It exits the system when encouter an error
func changeDir(dir string) {
if err := os.Chdir(dir); err != nil {
ColorLog("[ERRO] Could not find migration directory: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not find migration directory: %s", err)
}
}
@ -345,7 +337,7 @@ func changeDir(dir string) {
func removeTempFile(dir, file string) {
changeDir(dir)
if err := os.Remove(file); err != nil {
ColorLog("[WARN] Could not remove temporary file: %s\n", err)
beeLogger.Log.Warnf("Could not remove temporary file: %s", err)
}
}
@ -353,8 +345,7 @@ func removeTempFile(dir, file string) {
func formatShellErrOutput(o string) {
for _, line := range strings.Split(o, "\n") {
if line != "" {
ColorLog("[ERRO] -| ")
fmt.Println(line)
beeLogger.Log.Errorf("|> %s", line)
}
}
}
@ -363,23 +354,22 @@ func formatShellErrOutput(o string) {
func formatShellOutput(o string) {
for _, line := range strings.Split(o, "\n") {
if line != "" {
ColorLog("[INFO] -| ")
fmt.Println(line)
beeLogger.Log.Infof("|> %s", line)
}
}
}
const (
// MigrationMainTPL migration main template
MigrationMainTPL = `package main
import(
"os"
"github.com/astaxie/beego/orm"
"github.com/astaxie/beego/migration"
"github.com/beego/beego/v2/client/orm"
"github.com/beego/beego/v2/client/orm/migration"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "{{DriverRepo}}"
)
func init(){
@ -409,6 +399,7 @@ func main(){
}
`
// MYSQLMigrationDDL MySQL migration SQL
MYSQLMigrationDDL = `
CREATE TABLE migrations (
id_migration int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'surrogate key',
@ -420,7 +411,7 @@ CREATE TABLE migrations (
PRIMARY KEY (id_migration)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
`
// POSTGRESMigrationDDL Postgres migration SQL
POSTGRESMigrationDDL = `
CREATE TYPE migrations_status AS ENUM('update', 'rollback');
@ -433,3 +424,23 @@ CREATE TABLE migrations (
status migrations_status
)`
)
// MigrateUpdate does the schema update
func MigrateUpdate(currpath, driver, connStr, dir string) {
migrate("upgrade", currpath, driver, connStr, dir)
}
// MigrateRollback rolls back the latest migration
func MigrateRollback(currpath, driver, connStr, dir string) {
migrate("rollback", currpath, driver, connStr, dir)
}
// MigrateReset rolls back all migrations
func MigrateReset(currpath, driver, connStr, dir string) {
migrate("reset", currpath, driver, connStr, dir)
}
// MigrateRefresh rolls back all migrations and start over again
func MigrateRefresh(currpath, driver, connStr, dir string) {
migrate("refresh", currpath, driver, connStr, dir)
}

View File

@ -12,113 +12,53 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package new
import (
"fmt"
"os"
path "path/filepath"
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
var cmdNew = &Command{
UsageLine: "new [appname]",
Short: "Create a Beego application",
var gopath utils.DocValue
var beegoVersion utils.DocValue
var CmdNew = &commands.Command{
UsageLine: "new [appname] [-gopath=false] [-beego=v2.1.0]",
Short: "Creates a Beego application",
Long: `
Creates a Beego application for the given app name in the current directory.
now defaults to generating as a go modules project
The command 'new' creates a folder named [appname] [-gopath=false] [-beego=v1.12.3] and generates the following structure:
The command 'new' creates a folder named [appname] and inside the folder deploy
the following files/directories structure:
|- main.go
|- conf
|- app.conf
|- controllers
|- default.go
|- models
|- routers
|- router.go
|- tests
|- default_test.go
|- static
|- js
|- css
|- img
|- views
index.tpl
main.go
go.mod
{{"conf"|foldername}}
app.conf
{{"controllers"|foldername}}
default.go
{{"models"|foldername}}
{{"routers"|foldername}}
router.go
{{"tests"|foldername}}
default_test.go
{{"static"|foldername}}
{{"js"|foldername}}
{{"css"|foldername}}
{{"img"|foldername}}
{{"views"|foldername}}
index.tpl
`,
}
func init() {
cmdNew.Run = createApp
}
func createApp(cmd *Command, args []string) int {
ShowShortVersionBanner()
w := NewColorWriter(os.Stdout)
if len(args) != 1 {
ColorLog("[ERRO] Argument [appname] is missing\n")
os.Exit(2)
}
apppath, packpath, err := checkEnv(args[0])
if err != nil {
fmt.Println(err)
os.Exit(2)
}
if isExist(apppath) {
ColorLog("[ERRO] Path (%s) already exists\n", apppath)
ColorLog("[WARN] Do you want to overwrite it? [Yes|No] ")
if !askForConfirmation() {
os.Exit(2)
}
}
ColorLog("[INFO] Creating application...\n")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "conf")+string(path.Separator), "\x1b[0m")
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")+string(path.Separator), "\x1b[0m")
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")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "routers"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "routers")+string(path.Separator), "\x1b[0m")
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")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "js"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "js")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "css"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "css")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "static", "img"), 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "static", "img")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(apppath, "views"), 0755)
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")
WriteToFile(path.Join(apppath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "controllers", "default.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "controllers", "default.go"), controllers)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "views", "index.tpl"), "\x1b[0m")
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")
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")
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")
WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packpath, -1))
ColorLog("[SUCC] New application successfully created!\n")
return 0
PreRun: nil,
Run: CreateApp,
}
var appconf = `appname = {{.Appname}}
@ -130,7 +70,7 @@ var maingo = `package main
import (
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func main() {
@ -142,14 +82,20 @@ var router = `package routers
import (
"{{.Appname}}/controllers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func init() {
beego.Router("/", &controllers.MainController{})
}
`
var goMod = `module %s
go %s
require github.com/beego/beego/v2 %s
require github.com/smartystreets/goconvey v1.6.4
`
var test = `package test
import (
@ -158,26 +104,29 @@ import (
"testing"
"runtime"
"path/filepath"
"github.com/beego/beego/v2/core/logs"
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
. "github.com/smartystreets/goconvey/convey"
)
func init() {
_, file, _, _ := runtime.Caller(1)
_, file, _, _ := runtime.Caller(0)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
// TestMain is a sample to run an endpoint test
func TestMain(t *testing.T) {
// TestBeego is a sample to run an endpoint test
func TestBeego(t *testing.T) {
r, _ := http.NewRequest("GET", "/", nil)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestMain", "Code[%d]\n%s", w.Code, w.Body.String())
logs.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
@ -194,7 +143,7 @@ func TestMain(t *testing.T) {
var controllers = `package controllers
import (
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
@ -202,7 +151,7 @@ type MainController struct {
}
func (c *MainController) Get() {
c.Data["Website"] = "beego.me"
c.Data["Website"] = "beego.vip"
c.Data["Email"] = "astaxie@gmail.com"
c.TplName = "index.tpl"
}
@ -299,16 +248,112 @@ var indextpl = `<!DOCTYPE html>
</div>
</footer>
<div class="backdrop"></div>
<script src="/static/js/reload.min.js"></script>
</body>
</html>
`
// WriteToFile creates a file and writes content to it
func WriteToFile(filename, content string) {
f, err := os.Create(filename)
defer CloseFile(f)
if err != nil {
panic(err)
}
f.WriteString(content)
var reloadJsClient = `function b(a){var c=new WebSocket(a);c.onclose=function(){setTimeout(function(){b(a)},2E3)};c.onmessage=function(){location.reload()}}try{if(window.WebSocket)try{b("ws://localhost:12450/reload")}catch(a){console.error(a)}else console.log("Your browser does not support WebSockets.")}catch(a){console.error("Exception during connecting to Reload:",a)};
`
func init() {
CmdNew.Flag.Var(&gopath, "gopath", "Support go path,default false")
CmdNew.Flag.Var(&beegoVersion, "beego", "set beego version,only take effect by go mod")
commands.AvailableCommands = append(commands.AvailableCommands, CmdNew)
}
func CreateApp(cmd *commands.Command, args []string) int {
output := cmd.Out()
if len(args) == 0 {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
if len(args) >= 2 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
beeLogger.Log.Fatal("Parse args err " + err.Error())
}
}
var appPath string
var packPath string
var err error
if gopath == `true` {
beeLogger.Log.Info("Generate new project support GOPATH")
version.ShowShortVersionBanner()
appPath, packPath, err = utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
} else {
beeLogger.Log.Info("Generate new project support go modules.")
appPath = path.Join(utils.GetBeeWorkPath(), args[0])
packPath = args[0]
if beegoVersion.String() == `` {
beegoVersion.Set(utils.BEEGO_VERSION)
}
}
if utils.IsExist(appPath) {
beeLogger.Log.Errorf(colors.Bold("Application '%s' already exists"), appPath)
beeLogger.Log.Warn(colors.Bold("Do you want to overwrite it? [Yes|No] "))
if !utils.AskForConfirmation() {
os.Exit(2)
}
}
beeLogger.Log.Info("Creating application...")
// If it is the current directory, select the current folder name to package path
if packPath == "." {
packPath = path.Base(appPath)
}
os.MkdirAll(appPath, 0755)
if gopath != `true` {
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "go.mod"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "go.mod"), fmt.Sprintf(goMod, packPath, utils.GetGoVersionSkipMinor(), beegoVersion.String()))
}
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", appPath+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "conf"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "conf")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "controllers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "models"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "models")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "routers"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "routers")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "tests"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "tests")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "static"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "static")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "static", "js"), 0755)
utils.WriteToFile(path.Join(appPath, "static", "js", "reload.min.js"), reloadJsClient)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "static", "js")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "static", "css"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "static", "css")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "static", "img"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "static", "img")+string(path.Separator), "\x1b[0m")
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "views")+string(path.Separator), "\x1b[0m")
os.Mkdir(path.Join(appPath, "views"), 0755)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "conf", "app.conf"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "conf", "app.conf"), strings.Replace(appconf, "{{.Appname}}", path.Base(args[0]), -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "controllers", "default.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "controllers", "default.go"), controllers)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "views", "index.tpl"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "views", "index.tpl"), indextpl)
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "routers", "router.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "routers", "router.go"), strings.Replace(router, "{{.Appname}}", packPath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "tests", "default_test.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "tests", "default_test.go"), strings.Replace(test, "{{.Appname}}", packPath, -1))
fmt.Fprintf(output, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(appPath, "main.go"), "\x1b[0m")
utils.WriteToFile(path.Join(appPath, "main.go"), strings.Replace(maingo, "{{.Appname}}", packPath, -1))
beeLogger.Log.Success("New application successfully created!")
return 0
}

View File

@ -1,18 +1,4 @@
// Copyright 2013 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.
package main
package pack
import (
"archive/tar"
@ -21,7 +7,6 @@ import (
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
path "path/filepath"
@ -32,82 +17,60 @@ import (
"strings"
"syscall"
"time"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var cmdPack = &Command{
var CmdPack = &commands.Command{
CustomFlags: true,
UsageLine: "pack",
Short: "Compress a beego project into a single file",
Long: `
Pack is used to compress a beego project into a single file.
This eases the deployment by extracting the zip file to a server.
Short: "Compresses a Beego application into a single file",
Long: `Pack is used to compress Beego applications into a tarball/zip file.
This eases the deployment by directly extracting the file to a server.
-p app path (default is the current path).
-b build specify platform app (default: true).
-ba additional args of go build
-be=[] additional ENV Variables of go build. eg: GOARCH=arm
-o compressed file output dir. default use current path
-f="" format: tar.gz, zip (default: tar.gz)
-exp="" relpath exclude prefix (default: .). use : as separator
-exs="" relpath exclude suffix (default: .go:.DS_Store:.tmp). use : as separator
all path use : as separator
-exr=[] file/directory name exclude by Regexp (default: ^).
-fs=false follow symlink (default: false).
-ss=false skip symlink (default: false)
default embed symlink into compressed file
-v=false verbose
{{"Example:"|bold}}
$ bee pack -v -ba="-ldflags '-s -w'"
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: packApp,
}
var (
appPath string
appName string
excludeP string
excludeS string
outputP string
excludeR ListOpts
excludeR utils.ListOpts
fsym bool
ssym bool
build bool
buildArgs string
buildEnvs ListOpts
buildEnvs utils.ListOpts
verbose bool
format string
w io.Writer
)
type ListOpts []string
func (opts *ListOpts) String() string {
return fmt.Sprint(*opts)
}
func (opts *ListOpts) Set(value string) error {
*opts = append(*opts, value)
return nil
}
func init() {
fs := flag.NewFlagSet("pack", flag.ContinueOnError)
fs.StringVar(&appPath, "p", "", "app path. default is current path")
fs.BoolVar(&build, "b", true, "build specify platform app")
fs.StringVar(&buildArgs, "ba", "", "additional args of go build")
fs.Var(&buildEnvs, "be", "additional ENV Variables of go build. eg: GOARCH=arm")
fs.StringVar(&outputP, "o", "", "compressed file output dir. default use current path")
fs.StringVar(&format, "f", "tar.gz", "format. [ tar.gz / zip ]")
fs.StringVar(&excludeP, "exp", ".", "path exclude prefix. use : as separator")
fs.StringVar(&excludeS, "exs", ".go:.DS_Store:.tmp", "path exclude suffix. use : as separator")
fs.Var(&excludeR, "exr", "filename exclude by Regexp")
fs.BoolVar(&fsym, "fs", false, "follow symlink")
fs.BoolVar(&ssym, "ss", false, "skip symlink")
fs.BoolVar(&verbose, "v", false, "verbose")
cmdPack.Flag = *fs
cmdPack.Run = packApp
w = NewColorWriter(os.Stdout)
}
func exitPrint(con string) {
fmt.Fprintln(os.Stderr, con)
os.Exit(2)
fs.StringVar(&appPath, "p", "", "Set the application path. Defaults to the current path.")
fs.BoolVar(&build, "b", true, "Tell the command to do a build for the current platform. Defaults to true.")
fs.StringVar(&appName, "a", "", "Set the application name. Defaults to the dir name.")
fs.StringVar(&buildArgs, "ba", "", "Specify additional args for Go build.")
fs.Var(&buildEnvs, "be", "Specify additional env variables for Go build. e.g. GOARCH=arm.")
fs.StringVar(&outputP, "o", "", "Set the compressed file output path. Defaults to the current path.")
fs.StringVar(&format, "f", "tar.gz", "Set file format. Either tar.gz or zip. Defaults to tar.gz.")
fs.StringVar(&excludeP, "exp", ".", "Set prefixes of paths to be excluded. Uses a column (:) as separator.")
fs.StringVar(&excludeS, "exs", ".go:.DS_Store:.tmp", "Set suffixes of paths to be excluded. Uses a column (:) as separator.")
fs.Var(&excludeR, "exr", "Set a regular expression of files to be excluded.")
fs.BoolVar(&fsym, "fs", false, "Tell the command to follow symlinks. Defaults to false.")
fs.BoolVar(&ssym, "ss", false, "Tell the command to skip symlinks. Defaults to false.")
fs.BoolVar(&verbose, "v", false, "Be more verbose during the operation. Defaults to false.")
CmdPack.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdPack)
}
type walker interface {
@ -132,10 +95,7 @@ type walkFileTree struct {
excludeRegexp []*regexp.Regexp
excludeSuffix []string
allfiles map[string]bool
}
func (wft *walkFileTree) setPrefix(prefix string) {
wft.prefix = prefix
output *io.Writer
}
func (wft *walkFileTree) isExclude(fPath string) bool {
@ -244,7 +204,7 @@ func (wft *walkFileTree) walkLeaf(fpath string, fi os.FileInfo, err error) error
if added, err := wft.wak.compress(name, fpath, fi); added {
if verbose {
fmt.Fprintf(w, "\t%s%scompressed%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", name, "\x1b[0m")
fmt.Fprintf(*wft.output, "\t%s%scompressed%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", name, "\x1b[0m")
}
wft.allfiles[name] = true
return err
@ -335,12 +295,12 @@ func (wft *tarWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
return false, err
}
if isSym == false {
if !isSym {
fr, err := os.Open(fpath)
if err != nil {
return false, err
}
defer CloseFile(fr)
defer utils.CloseFile(fr)
_, err = io.Copy(tw, fr)
if err != nil {
return false, err
@ -371,12 +331,12 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
return false, err
}
if isSym == false {
if !isSym {
fr, err := os.Open(fpath)
if err != nil {
return false, err
}
defer CloseFile(fr)
defer utils.CloseFile(fr)
_, err = io.Copy(w, fr)
if err != nil {
return false, err
@ -395,13 +355,13 @@ func (wft *zipWalk) compress(name, fpath string, fi os.FileInfo) (bool, error) {
return true, nil
}
func packDirectory(excludePrefix []string, excludeSuffix []string,
func packDirectory(output io.Writer, excludePrefix []string, excludeSuffix []string,
excludeRegexp []*regexp.Regexp, includePath ...string) (err error) {
ColorLog("Excluding relpath prefix: %s\n", strings.Join(excludePrefix, ":"))
ColorLog("Excluding relpath suffix: %s\n", strings.Join(excludeSuffix, ":"))
beeLogger.Log.Infof("Excluding relpath prefix: %s", strings.Join(excludePrefix, ":"))
beeLogger.Log.Infof("Excluding relpath suffix: %s", strings.Join(excludeSuffix, ":"))
if len(excludeRegexp) > 0 {
ColorLog("Excluding filename regex: `%s`\n", strings.Join(excludeR, "`, `"))
beeLogger.Log.Infof("Excluding filename regex: `%s`", strings.Join(excludeR, "`, `"))
}
w, err := os.OpenFile(outputP, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
@ -413,6 +373,7 @@ func packDirectory(excludePrefix []string, excludeSuffix []string,
if format == "zip" {
walk := new(zipWalk)
walk.output = &output
zw := zip.NewWriter(w)
defer func() {
zw.Close()
@ -426,6 +387,7 @@ func packDirectory(excludePrefix []string, excludeSuffix []string,
wft = walk
} else {
walk := new(tarWalk)
walk.output = &output
cw := gzip.NewWriter(w)
tw := tar.NewWriter(cw)
@ -454,29 +416,10 @@ func packDirectory(excludePrefix []string, excludeSuffix []string,
return
}
func isBeegoProject(thePath string) bool {
fh, _ := os.Open(thePath)
fis, _ := fh.Readdir(-1)
regex := regexp.MustCompile(`(?s)package main.*?import.*?\(.*?github.com/astaxie/beego".*?\).*func main()`)
for _, fi := range fis {
if fi.IsDir() == false && strings.HasSuffix(fi.Name(), ".go") {
data, err := ioutil.ReadFile(path.Join(thePath, fi.Name()))
if err != nil {
continue
}
if len(regex.Find(data)) > 0 {
return true
}
}
}
return false
}
func packApp(cmd *Command, args []string) int {
ShowShortVersionBanner()
func packApp(cmd *commands.Command, args []string) int {
output := cmd.Out()
curPath, _ := os.Getwd()
thePath := ""
var thePath string
nArgs := []string{}
has := false
@ -488,28 +431,26 @@ func packApp(cmd *Command, args []string) int {
nArgs = append(nArgs, a)
}
}
cmdPack.Flag.Parse(nArgs)
cmd.Flag.Parse(nArgs)
if path.IsAbs(appPath) == false {
if !path.IsAbs(appPath) {
appPath = path.Join(curPath, appPath)
}
thePath, err := path.Abs(appPath)
if err != nil {
exitPrint(fmt.Sprintf("Wrong app path: %s", thePath))
beeLogger.Log.Fatalf("Wrong application path: %s", thePath)
}
if stat, err := os.Stat(thePath); os.IsNotExist(err) || stat.IsDir() == false {
exitPrint(fmt.Sprintf("App path does not exist: %s", thePath))
if stat, err := os.Stat(thePath); os.IsNotExist(err) || !stat.IsDir() {
beeLogger.Log.Fatalf("Application path does not exist: %s", thePath)
}
if isBeegoProject(thePath) == false {
exitPrint(fmt.Sprintf("Bee does not support non Beego project"))
beeLogger.Log.Infof("Packaging application on '%s'...", thePath)
if len(appName) == 0 {
appName = path.Base(thePath)
}
ColorLog("Packaging application: %s\n", thePath)
appName := path.Base(thePath)
goos := runtime.GOOS
if v, found := syscall.Getenv("GOOS"); found {
goos = v
@ -524,9 +465,16 @@ func packApp(cmd *Command, args []string) int {
tmpdir := path.Join(os.TempDir(), "beePack-"+str)
os.Mkdir(tmpdir, 0700)
defer func() {
// Remove the tmpdir once bee pack is done
err := os.RemoveAll(tmpdir)
if err != nil {
beeLogger.Log.Error("Failed to remove the generated temp dir")
}
}()
if build {
ColorLog("Building application...\n")
beeLogger.Log.Infof("Building application (%v)...", appName)
var envs []string
for _, env := range buildEnvs {
parts := strings.SplitN(env, "=", 2)
@ -548,7 +496,7 @@ func packApp(cmd *Command, args []string) int {
os.Setenv("GOOS", goos)
os.Setenv("GOARCH", goarch)
ColorLog("Env: GOOS=%s GOARCH=%s\n", goos, goarch)
beeLogger.Log.Infof("Using: GOOS=%s GOARCH=%s", goos, goarch)
binPath := path.Join(tmpdir, appName)
if goos == "windows" {
@ -561,7 +509,7 @@ func packApp(cmd *Command, args []string) int {
}
if verbose {
fmt.Fprintf(w, "\t%s%s+ go %s%s%s\n", "\x1b[32m", "\x1b[1m", strings.Join(args, " "), "\x1b[21m", "\x1b[0m")
fmt.Fprintf(output, "\t%s%s+ go %s%s%s\n", "\x1b[32m", "\x1b[1m", strings.Join(args, " "), "\x1b[21m", "\x1b[0m")
}
execmd := exec.Command("go", args...)
@ -571,10 +519,10 @@ func packApp(cmd *Command, args []string) int {
execmd.Dir = thePath
err = execmd.Run()
if err != nil {
exitPrint(err.Error())
beeLogger.Log.Fatal(err.Error())
}
ColorLog("Build successful\n")
beeLogger.Log.Success("Build Successful!")
}
switch format {
@ -585,14 +533,14 @@ func packApp(cmd *Command, args []string) int {
outputN := appName + "." + format
if outputP == "" || path.IsAbs(outputP) == false {
if outputP == "" || !path.IsAbs(outputP) {
outputP = path.Join(curPath, outputP)
}
if _, err := os.Stat(outputP); err != nil {
err = os.MkdirAll(outputP, 0755)
if err != nil {
exitPrint(err.Error())
beeLogger.Log.Fatal(err.Error())
}
}
@ -609,23 +557,26 @@ func packApp(cmd *Command, args []string) int {
exs = append(exs, p)
}
}
exs = append(exs, `go.mod`)
exs = append(exs, `go.sum`)
var exr []*regexp.Regexp
for _, r := range excludeR {
if len(r) > 0 {
if re, err := regexp.Compile(r); err != nil {
exitPrint(err.Error())
beeLogger.Log.Fatal(err.Error())
} else {
exr = append(exr, re)
}
}
}
err = packDirectory(exp, exs, exr, tmpdir, thePath)
beeLogger.Log.Infof("Writing to output: %s", outputP)
err = packDirectory(output, exp, exs, exr, tmpdir, thePath)
if err != nil {
exitPrint(err.Error())
beeLogger.Log.Fatal(err.Error())
}
ColorLog("Writing to output: `%s`\n", outputP)
beeLogger.Log.Success("Application packed!")
return 0
}

102
cmd/commands/rs/rs.go Normal file
View File

@ -0,0 +1,102 @@
// Copyright 2017 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.
// Package rs ...
package rs
import (
"fmt"
"os"
"os/exec"
"runtime"
"time"
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/config"
"github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
var cmdRs = &commands.Command{
UsageLine: "rs",
Short: "Run customized scripts",
Long: `Run script allows you to run arbitrary commands using Bee.
Custom commands are provided from the "scripts" object inside bee.json or Beefile.
To run a custom command, use: {{"$ bee rs mycmd ARGS" | bold}}
{{if len .}}
{{"AVAILABLE SCRIPTS"|headline}}{{range $cmdName, $cmd := .}}
{{$cmdName | bold}}
{{$cmd}}{{end}}{{end}}
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: runScript,
}
func init() {
config.LoadConfig()
cmdRs.Long = utils.TmplToString(cmdRs.Long, config.Conf.Scripts)
commands.AvailableCommands = append(commands.AvailableCommands, cmdRs)
}
func runScript(cmd *commands.Command, args []string) int {
if len(args) == 0 {
cmd.Usage()
}
start := time.Now()
script, args := args[0], args[1:]
if c, exist := config.Conf.Scripts[script]; exist {
command := customCommand{
Name: script,
Command: c,
Args: args,
}
if err := command.run(); err != nil {
beeLogger.Log.Error(err.Error())
}
} else {
beeLogger.Log.Errorf("Command '%s' not found in Beefile/bee.json", script)
}
elapsed := time.Since(start)
fmt.Println(colors.GreenBold(fmt.Sprintf("Finished in %s.", elapsed)))
return 0
}
type customCommand struct {
Name string
Command string
Args []string
}
func (c *customCommand) run() error {
beeLogger.Log.Info(colors.GreenBold(fmt.Sprintf("Running '%s'...", c.Name)))
var cmd *exec.Cmd
switch runtime.GOOS {
case "darwin", "linux":
args := append([]string{c.Command}, c.Args...)
cmd = exec.Command("sh", "-c", strings.Join(args, " "))
case "windows":
args := append([]string{c.Command}, c.Args...)
cmd = exec.Command("cmd", "/C", strings.Join(args, " "))
}
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}

88
cmd/commands/run/docs.go Normal file
View File

@ -0,0 +1,88 @@
package run
import (
"archive/zip"
"io"
"net/http"
"os"
"strings"
beeLogger "github.com/beego/bee/v2/logger"
)
var (
swaggerVersion = "4.6.1"
swaggerlink = "https://codeload.github.com/beego/swagger/zip/refs/tags/v" + swaggerVersion
)
func downloadFromURL(url, fileName string) {
var down bool
if fd, err := os.Stat(fileName); err != nil && os.IsNotExist(err) {
down = true
} else if fd.Size() == int64(0) {
down = true
} else {
beeLogger.Log.Infof("'%s' already exists", fileName)
return
}
if down {
beeLogger.Log.Infof("Downloading '%s' to '%s'...", url, fileName)
output, err := os.Create(fileName)
if err != nil {
beeLogger.Log.Errorf("Error while creating '%s': %s", fileName, err)
return
}
defer output.Close()
response, err := http.Get(url)
if err != nil {
beeLogger.Log.Errorf("Error while downloading '%s': %s", url, err)
return
}
defer response.Body.Close()
n, err := io.Copy(output, response.Body)
if err != nil {
beeLogger.Log.Errorf("Error while downloading '%s': %s", url, err)
return
}
beeLogger.Log.Successf("%d bytes downloaded!", n)
}
}
func unzipAndDelete(src string) error {
beeLogger.Log.Infof("Unzipping '%s'...", src)
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger")
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
fname := rp.Replace(f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fname, f.Mode())
} else {
f, err := os.OpenFile(
fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
}
beeLogger.Log.Successf("Done! Deleting '%s'...", src)
return os.RemoveAll(src)
}

192
cmd/commands/run/reload.go Normal file
View File

@ -0,0 +1,192 @@
// Copyright 2017 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.
package run
import (
"bytes"
"net/http"
"time"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/gorilla/websocket"
)
// wsBroker maintains the set of active clients and broadcasts messages to the clients.
type wsBroker struct {
clients map[*wsClient]bool // Registered clients.
broadcast chan []byte // Inbound messages from the clients.
register chan *wsClient // Register requests from the clients.
unregister chan *wsClient // Unregister requests from clients.
}
func (br *wsBroker) run() {
for {
select {
case client := <-br.register:
br.clients[client] = true
case client := <-br.unregister:
if _, ok := br.clients[client]; ok {
delete(br.clients, client)
close(client.send)
}
case message := <-br.broadcast:
for client := range br.clients {
select {
case client.send <- message:
default:
close(client.send)
delete(br.clients, client)
}
}
}
}
}
// wsClient represents the end-client.
type wsClient struct {
broker *wsBroker // The broker.
conn *websocket.Conn // The websocket connection.
send chan []byte // Buffered channel of outbound messages.
}
// readPump pumps messages from the websocket connection to the broker.
func (c *wsClient) readPump() {
defer func() {
c.broker.unregister <- c
c.conn.Close()
}()
for {
_, _, err := c.conn.ReadMessage()
if err != nil {
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
beeLogger.Log.Errorf("An error happened when reading from the Websocket client: %v", err)
}
break
}
}
}
// write writes a message with the given message type and payload.
func (c *wsClient) write(mt int, payload []byte) error {
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
return c.conn.WriteMessage(mt, payload)
}
// writePump pumps messages from the broker to the websocket connection.
func (c *wsClient) writePump() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
c.conn.Close()
}()
for {
select {
case message, ok := <-c.send:
if !ok {
// The broker closed the channel.
c.write(websocket.CloseMessage, []byte{})
return
}
c.conn.SetWriteDeadline(time.Now().Add(writeWait))
w, err := c.conn.NextWriter(websocket.TextMessage)
if err != nil {
return
}
w.Write(message)
n := len(c.send)
for i := 0; i < n; i++ {
w.Write([]byte("/n"))
w.Write(<-c.send)
}
if err := w.Close(); err != nil {
return
}
case <-ticker.C:
if err := c.write(websocket.PingMessage, []byte{}); err != nil {
return
}
}
}
}
var (
broker *wsBroker // The broker.
reloadAddress = ":12450" // The port on which the reload server will listen to.
upgrader = websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool { return true },
}
)
const (
writeWait = 10 * time.Second // Time allowed to write a message to the peer.
pongWait = 60 * time.Second // Time allowed to read the next pong message from the peer.
pingPeriod = (pongWait * 9) / 10 // Send pings to peer with this period. Must be less than pongWait.
)
func startReloadServer() {
broker = &wsBroker{
broadcast: make(chan []byte),
register: make(chan *wsClient),
unregister: make(chan *wsClient),
clients: make(map[*wsClient]bool),
}
go broker.run()
http.HandleFunc("/reload", func(w http.ResponseWriter, r *http.Request) {
handleWsRequest(broker, w, r)
})
go startServer()
beeLogger.Log.Infof("Reload server listening at %s", reloadAddress)
}
func startServer() {
err := http.ListenAndServe(reloadAddress, nil)
if err != nil {
beeLogger.Log.Errorf("Failed to start up the Reload server: %v", err)
return
}
}
func sendReload(payload string) {
message := bytes.TrimSpace([]byte(payload))
broker.broadcast <- message
}
// handleWsRequest handles websocket requests from the peer.
func handleWsRequest(broker *wsBroker, w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
beeLogger.Log.Errorf("error while upgrading server connection: %v", err)
return
}
client := &wsClient{
broker: broker,
conn: conn,
send: make(chan []byte, 256),
}
client.broker.register <- client
go client.writePump()
client.readPump()
}

256
cmd/commands/run/run.go Normal file
View File

@ -0,0 +1,256 @@
// Copyright 2013 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.
package run
import (
"io/ioutil"
"os"
path "path/filepath"
"runtime"
"strings"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/config"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var CmdRun = &commands.Command{
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-ex=extraPackageToWatch] [-tags=goBuildTags] [-runmode=BEEGO_RUNMODE]",
Short: "Run the application by starting a local development server",
Long: `
Run command will supervise the filesystem of the application for any changes, and recompile/restart it.
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: RunApp,
}
var (
mainFiles utils.ListOpts
downdoc utils.DocValue
gendoc utils.DocValue
// The flags list of the paths excluded from watching
excludedPaths utils.StrFlags
// Pass through to -tags arg of "go build"
buildTags string
// Pass through to -ldflags arg of "go build"
buildLDFlags string
// Application path
currpath string
// Application name
appname string
// Channel to signal an Exit
exit chan bool
// Flag to watch the vendor folder
vendorWatch bool
// Current user workspace
currentGoPath string
// Current runmode
runmode string
// Extra args to run application
runargs string
// Extra directories
extraPackages utils.StrFlags
)
var started = make(chan bool)
func init() {
CmdRun.Flag.Var(&mainFiles, "main", "Specify main go files.")
CmdRun.Flag.Var(&gendoc, "gendoc", "Enable auto-generate the docs.")
CmdRun.Flag.Var(&downdoc, "downdoc", "Enable auto-download of the swagger file if it does not exist.")
CmdRun.Flag.Var(&excludedPaths, "e", "List of paths to exclude.")
CmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Enable watch vendor folder.")
CmdRun.Flag.StringVar(&buildTags, "tags", "", "Set the build tags. See: https://golang.org/pkg/go/build/")
CmdRun.Flag.StringVar(&buildLDFlags, "ldflags", "", "Set the build ldflags. See: https://golang.org/pkg/go/build/")
CmdRun.Flag.StringVar(&runmode, "runmode", "", "Set the Beego run mode.")
CmdRun.Flag.StringVar(&runargs, "runargs", "", "Extra args to run application")
CmdRun.Flag.Var(&extraPackages, "ex", "List of extra package to watch.")
exit = make(chan bool)
commands.AvailableCommands = append(commands.AvailableCommands, CmdRun)
}
// RunApp locates files to watch, and starts the beego application
func RunApp(cmd *commands.Command, args []string) int {
// The default app path is the current working directory
appPath, _ := os.Getwd()
// If an argument is presented, we use it as the app path
if len(args) != 0 && args[0] != "watchall" {
if path.IsAbs(args[0]) {
appPath = args[0]
} else {
appPath = path.Join(appPath, args[0])
}
}
if utils.IsInGOPATH(appPath) {
if found, _gopath, _path := utils.SearchGOPATHs(appPath); found {
appPath = _path
appname = path.Base(appPath)
currentGoPath = _gopath
} else {
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", appPath)
}
if strings.HasSuffix(appname, ".go") && utils.IsExist(appPath) {
beeLogger.Log.Warnf("The appname is in conflict with file's current path. Do you want to build appname as '%s'", appname)
beeLogger.Log.Info("Do you want to overwrite it? [yes|no] ")
if !utils.AskForConfirmation() {
return 0
}
}
} else {
beeLogger.Log.Warn("Running application outside of GOPATH")
appname = path.Base(appPath)
currentGoPath = appPath
}
beeLogger.Log.Infof("Using '%s' as 'appname'", appname)
beeLogger.Log.Debugf("Current path: %s", utils.FILE(), utils.LINE(), appPath)
if runmode == "prod" || runmode == "dev" {
os.Setenv("BEEGO_RUNMODE", runmode)
beeLogger.Log.Infof("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
} else if runmode != "" {
os.Setenv("BEEGO_RUNMODE", runmode)
beeLogger.Log.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
} else if os.Getenv("BEEGO_RUNMODE") != "" {
beeLogger.Log.Warnf("Using '%s' as 'runmode'", os.Getenv("BEEGO_RUNMODE"))
}
var paths []string
readAppDirectories(appPath, &paths)
// Because monitor files has some issues, we watch current directory
// and ignore non-go files.
for _, p := range config.Conf.DirStruct.Others {
paths = append(paths, strings.Replace(p, "$GOPATH", currentGoPath, -1))
}
if len(extraPackages) > 0 {
// get the full path
for _, packagePath := range extraPackages {
if found, _, _fullPath := utils.SearchGOPATHs(packagePath); found {
readAppDirectories(_fullPath, &paths)
} else {
beeLogger.Log.Warnf("No extra package '%s' found in your GOPATH", packagePath)
}
}
// let paths unique
strSet := make(map[string]struct{})
for _, p := range paths {
strSet[p] = struct{}{}
}
paths = make([]string, len(strSet))
index := 0
for i := range strSet {
paths[index] = i
index++
}
}
files := []string{}
for _, arg := range mainFiles {
if len(arg) > 0 {
files = append(files, arg)
}
}
if downdoc == "true" {
if _, err := os.Stat(path.Join(appPath, "swagger", "index.html")); err != nil {
if os.IsNotExist(err) {
downloadFromURL(swaggerlink, "swagger.zip")
unzipAndDelete("swagger.zip")
}
}
}
// Start the Reload server (if enabled)
if config.Conf.EnableReload {
startReloadServer()
}
if gendoc == "true" {
NewWatcher(paths, files, true)
AutoBuild(files, true)
} else {
NewWatcher(paths, files, false)
AutoBuild(files, false)
}
for {
<-exit
runtime.Goexit()
}
}
func readAppDirectories(directory string, paths *[]string) {
fileInfos, err := ioutil.ReadDir(directory)
if err != nil {
return
}
useDirectory := false
for _, fileInfo := range fileInfos {
if strings.HasSuffix(fileInfo.Name(), "docs") {
continue
}
if strings.HasSuffix(fileInfo.Name(), "swagger") {
continue
}
if !vendorWatch && strings.HasSuffix(fileInfo.Name(), "vendor") {
continue
}
if isExcluded(path.Join(directory, fileInfo.Name())) {
continue
}
if fileInfo.IsDir() && fileInfo.Name()[0] != '.' {
readAppDirectories(directory+"/"+fileInfo.Name(), paths)
continue
}
if useDirectory {
continue
}
if path.Ext(fileInfo.Name()) == ".go" || (ifStaticFile(fileInfo.Name()) && config.Conf.EnableReload) {
*paths = append(*paths, directory)
useDirectory = true
}
}
}
// If a file is excluded
func isExcluded(filePath string) bool {
for _, p := range excludedPaths {
absP, err := path.Abs(p)
if err != nil {
beeLogger.Log.Errorf("Cannot get absolute path of '%s'", p)
continue
}
absFilePath, err := path.Abs(filePath)
if err != nil {
beeLogger.Log.Errorf("Cannot get absolute path of '%s'", filePath)
break
}
if strings.HasPrefix(absFilePath, absP) {
beeLogger.Log.Infof("'%s' is not being watched", filePath)
return true
}
}
return false
}

281
cmd/commands/run/watch.go Normal file
View File

@ -0,0 +1,281 @@
// Copyright 2013 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.
package run
import (
"bytes"
"os"
"os/exec"
"regexp"
"runtime"
"strings"
"sync"
"time"
"github.com/beego/bee/v2/config"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
"github.com/fsnotify/fsnotify"
)
var (
cmd *exec.Cmd
state sync.Mutex
eventTime = make(map[string]int64)
scheduleTime time.Time
watchExts = config.Conf.WatchExts
watchExtsStatic = config.Conf.WatchExtsStatic
ignoredFilesRegExps = []string{
`.#(\w+).go$`,
`.(\w+).go.swp$`,
`(\w+).go~$`,
`(\w+).tmp$`,
`commentsRouter_controllers.go$`,
}
)
// NewWatcher starts an fsnotify Watcher on the specified paths
func NewWatcher(paths []string, files []string, isgenerate bool) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
beeLogger.Log.Fatalf("Failed to create watcher: %s", err)
}
go func() {
for {
select {
case e := <-watcher.Events:
isBuild := true
if ifStaticFile(e.Name) && config.Conf.EnableReload {
sendReload(e.String())
continue
}
// Skip ignored files
if shouldIgnoreFile(e.Name) {
continue
}
if !shouldWatchFileWithExtension(e.Name) {
continue
}
mt := utils.GetFileModTime(e.Name)
if t := eventTime[e.Name]; mt == t {
beeLogger.Log.Hintf(colors.Bold("Skipping: ")+"%s", e.String())
isBuild = false
}
eventTime[e.Name] = mt
if isBuild {
beeLogger.Log.Hintf("Event fired: %s", e)
go func() {
// Wait 1s before autobuild until there is no file change.
scheduleTime = time.Now().Add(1 * time.Second)
time.Sleep(time.Until(scheduleTime))
AutoBuild(files, isgenerate)
if config.Conf.EnableReload {
// Wait 100ms more before refreshing the browser
time.Sleep(100 * time.Millisecond)
sendReload(e.String())
}
}()
}
case err := <-watcher.Errors:
beeLogger.Log.Warnf("Watcher error: %s", err.Error()) // No need to exit here
}
}
}()
beeLogger.Log.Info("Initializing watcher...")
for _, path := range paths {
beeLogger.Log.Hintf(colors.Bold("Watching: ")+"%s", path)
err = watcher.Add(path)
if err != nil {
beeLogger.Log.Fatalf("Failed to watch directory: %s", err)
}
}
}
// AutoBuild builds the specified set of files
func AutoBuild(files []string, isgenerate bool) {
state.Lock()
defer state.Unlock()
os.Chdir(currpath)
cmdName := "go"
var (
err error
stderr bytes.Buffer
)
// For applications use full import path like "github.com/.../.."
// are able to use "go install" to reduce build time.
if config.Conf.GoInstall {
icmd := exec.Command(cmdName, "install", "-v")
icmd.Stdout = os.Stdout
icmd.Stderr = os.Stderr
icmd.Env = append(os.Environ(), "GOGC=off")
icmd.Run()
}
if isgenerate {
beeLogger.Log.Info("Generating the docs...")
icmd := exec.Command("bee", "generate", "docs")
icmd.Env = append(os.Environ(), "GOGC=off")
err = icmd.Run()
if err != nil {
utils.Notify("", "Failed to generate the docs.")
beeLogger.Log.Errorf("Failed to generate the docs.")
return
}
beeLogger.Log.Success("Docs generated!")
}
appName := appname
if err == nil {
if runtime.GOOS == "windows" {
appName += ".exe"
}
args := []string{"build"}
args = append(args, "-o", appName)
if buildTags != "" {
args = append(args, "-tags", buildTags)
}
if buildLDFlags != "" {
args = append(args, "-ldflags", buildLDFlags)
}
args = append(args, files...)
bcmd := exec.Command(cmdName, args...)
bcmd.Env = append(os.Environ(), "GOGC=off")
bcmd.Stderr = &stderr
err = bcmd.Run()
if err != nil {
utils.Notify(stderr.String(), "Build Failed")
beeLogger.Log.Errorf("Failed to build the application: %s", stderr.String())
return
}
}
beeLogger.Log.Success("Built Successfully!")
Restart(appName)
}
// Kill kills the running command process
func Kill() {
defer func() {
if e := recover(); e != nil {
beeLogger.Log.Infof("Kill recover: %s", e)
}
}()
if cmd != nil && cmd.Process != nil {
// Windows does not support Interrupt
if runtime.GOOS == "windows" {
cmd.Process.Signal(os.Kill)
} else {
cmd.Process.Signal(os.Interrupt)
}
ch := make(chan struct{}, 1)
go func() {
cmd.Wait()
ch <- struct{}{}
}()
select {
case <-ch:
return
case <-time.After(10 * time.Second):
beeLogger.Log.Info("Timeout. Force kill cmd process")
err := cmd.Process.Kill()
if err != nil {
beeLogger.Log.Errorf("Error while killing cmd process: %s", err)
}
return
}
}
}
// Restart kills the running command process and starts it again
func Restart(appname string) {
beeLogger.Log.Debugf("Kill running process", utils.FILE(), utils.LINE())
Kill()
go Start(appname)
}
// Start starts the command process
func Start(appname string) {
beeLogger.Log.Infof("Restarting '%s'...", appname)
if !strings.Contains(appname, "./") {
appname = "./" + appname
}
cmd = exec.Command(appname)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if runargs != "" {
r := regexp.MustCompile("'.+'|\".+\"|\\S+")
m := r.FindAllString(runargs, -1)
cmd.Args = append([]string{appname}, m...)
} else {
cmd.Args = append([]string{appname}, config.Conf.CmdArgs...)
}
cmd.Env = append(os.Environ(), config.Conf.Envs...)
go cmd.Run()
beeLogger.Log.Successf("'%s' is running...", appname)
started <- true
}
func ifStaticFile(filename string) bool {
for _, s := range watchExtsStatic {
if strings.HasSuffix(filename, s) {
return true
}
}
return false
}
// shouldIgnoreFile ignores filenames generated by Emacs, Vim or SublimeText.
// It returns true if the file should be ignored, false otherwise.
func shouldIgnoreFile(filename string) bool {
for _, regex := range ignoredFilesRegExps {
r, err := regexp.Compile(regex)
if err != nil {
beeLogger.Log.Fatalf("Could not compile regular expression: %s", err)
}
if r.MatchString(filename) {
return true
}
continue
}
return false
}
// shouldWatchFileWithExtension returns true if the name of the file
// hash a suffix that should be watched.
func shouldWatchFileWithExtension(name string) bool {
for _, s := range watchExts {
if strings.HasSuffix(name, s) {
return true
}
}
return false
}

View File

@ -0,0 +1,76 @@
// Copyright 2013 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.
package apiapp
import (
"net/http"
beeLogger "github.com/beego/bee/v2/logger"
"os"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/cmd/commands/version"
"github.com/beego/bee/v2/utils"
)
var CmdServer = &commands.Command{
// CustomFlags: true,
UsageLine: "server [port]",
Short: "serving static content over HTTP on port",
Long: `
The command 'server' creates a Beego API application.
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: createAPI,
}
var (
a utils.DocValue
p utils.DocValue
f utils.DocValue
)
func init() {
CmdServer.Flag.Var(&a, "a", "Listen address")
CmdServer.Flag.Var(&p, "p", "Listen port")
CmdServer.Flag.Var(&f, "f", "Static files fold")
commands.AvailableCommands = append(commands.AvailableCommands, CmdServer)
}
func createAPI(cmd *commands.Command, args []string) int {
if len(args) > 0 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
beeLogger.Log.Error(err.Error())
}
}
if a == "" {
a = "127.0.0.1"
}
if p == "" {
p = "8080"
}
if f == "" {
cwd, _ := os.Getwd()
f = utils.DocValue(cwd)
}
beeLogger.Log.Infof("Start server on http://%s:%s, static file %s", a, p, f)
err := http.ListenAndServe(string(a)+":"+string(p), http.FileServer(http.Dir(f)))
if err != nil {
beeLogger.Log.Error(err.Error())
}
return 0
}

View File

@ -0,0 +1,41 @@
package update
import (
"flag"
"os"
"os/exec"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/config"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var CmdUpdate = &commands.Command{
UsageLine: "update",
Short: "Update Bee",
Long: `
Automatic run command "go get -u github.com/beego/bee/v2" for selfupdate
`,
Run: updateBee,
}
func init() {
fs := flag.NewFlagSet("update", flag.ContinueOnError)
CmdUpdate.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdUpdate)
}
func updateBee(cmd *commands.Command, args []string) int {
beeLogger.Log.Info("Updating")
beePath := config.GitRemotePath
cmdUp := exec.Command("go", "get", "-u", beePath)
cmdUp.Stdout = os.Stdout
cmdUp.Stderr = os.Stderr
if err := cmdUp.Run(); err != nil {
beeLogger.Log.Warnf("Run cmd err:%s", err)
}
// update the Time when updateBee every time
utils.UpdateLastPublishedTime()
return 0
}

View File

@ -1,4 +1,4 @@
package main
package version
import (
"io"
@ -6,10 +6,15 @@ import (
"os"
"runtime"
"text/template"
"time"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
type vars struct {
// RuntimeInfo holds information about the current runtime.
type RuntimeInfo struct {
GoVersion string
GOOS string
GOARCH string
@ -18,12 +23,7 @@ type vars struct {
GOROOT string
Compiler string
BeeVersion string
BeegoVersion string
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
Published string
}
// InitBanner loads the banner and prints it to output
@ -31,15 +31,12 @@ func Now(layout string) string {
// print the banner in case of error.
func InitBanner(out io.Writer, in io.Reader) {
if in == nil {
ColorLog("[ERRO] The input is nil\n")
os.Exit(2)
beeLogger.Log.Fatal("The input is nil")
}
banner, err := ioutil.ReadAll(in)
if err != nil {
ColorLog("[ERRO] Error trying to read the banner\n")
ColorLog("[HINT] %v\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Error while trying to read the banner: %s", err)
}
show(out, string(banner))
@ -51,12 +48,10 @@ func show(out io.Writer, content string) {
Parse(content)
if err != nil {
ColorLog("[ERRO] Cannot parse the banner template\n")
ColorLog("[HINT] %v\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Cannot parse the banner template: %s", err)
}
err = t.Execute(out, vars{
err = t.Execute(out, RuntimeInfo{
runtime.Version(),
runtime.GOOS,
runtime.GOARCH,
@ -65,9 +60,14 @@ func show(out io.Writer, content string) {
runtime.GOROOT(),
runtime.Compiler,
version,
getBeegoVersion(),
utils.GetLastPublishedTime(),
})
if err != nil {
panic(err)
beeLogger.Log.Error(err.Error())
}
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
}

View File

@ -0,0 +1,110 @@
package version
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"gopkg.in/yaml.v2"
"os"
"runtime"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/config"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
)
const verboseVersionBanner string = `%s%s______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}%s
%s%s
GoVersion : {{ .GoVersion }}
GOOS : {{ .GOOS }}
GOARCH : {{ .GOARCH }}
NumCPU : {{ .NumCPU }}
GOPATH : {{ .GOPATH }}
GOROOT : {{ .GOROOT }}
Compiler : {{ .Compiler }}
Date : {{ Now "Monday, 2 Jan 2006" }}%s
`
const shortVersionBanner = `______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}
`
var CmdVersion = &commands.Command{
UsageLine: "version",
Short: "Prints the current Bee version",
Long: `
Prints the current Bee, Beego and Go version alongside the platform information.
`,
Run: versionCmd,
}
var outputFormat string
const version = config.Version
func init() {
fs := flag.NewFlagSet("version", flag.ContinueOnError)
fs.StringVar(&outputFormat, "o", "", "Set the output format. Either json or yaml.")
CmdVersion.Flag = *fs
commands.AvailableCommands = append(commands.AvailableCommands, CmdVersion)
}
func versionCmd(cmd *commands.Command, args []string) int {
cmd.Flag.Parse(args)
stdout := cmd.Out()
if outputFormat != "" {
runtimeInfo := RuntimeInfo{
GoVersion: runtime.Version(),
GOOS: runtime.GOOS,
GOARCH: runtime.GOARCH,
NumCPU: runtime.NumCPU(),
GOPATH: os.Getenv("GOPATH"),
GOROOT: runtime.GOROOT(),
Compiler: runtime.Compiler,
BeeVersion: version,
}
switch outputFormat {
case "json":
{
b, err := json.MarshalIndent(runtimeInfo, "", " ")
if err != nil {
beeLogger.Log.Error(err.Error())
}
fmt.Println(string(b))
return 0
}
case "yaml":
{
b, err := yaml.Marshal(&runtimeInfo)
if err != nil {
beeLogger.Log.Error(err.Error())
}
fmt.Println(string(b))
return 0
}
}
}
coloredBanner := fmt.Sprintf(verboseVersionBanner, "\x1b[35m", "\x1b[1m",
"\x1b[0m", "\x1b[32m", "\x1b[1m", "\x1b[0m")
InitBanner(stdout, bytes.NewBufferString(coloredBanner))
return 0
}
// ShowShortVersionBanner prints the short version banner.
func ShowShortVersionBanner() {
output := colors.NewColorWriter(os.Stdout)
InitBanner(output, bytes.NewBufferString(colors.MagentaBold(shortVersionBanner)))
}

261
code.go
View File

@ -1,261 +0,0 @@
// Copyright 2011 Gary Burd
// Copyright 2013 Unknown
//
// 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.
package main
import (
"go/ast"
"go/printer"
"go/scanner"
"go/token"
"math"
"strconv"
)
const (
notPredeclared = iota
predeclaredType
predeclaredConstant
predeclaredFunction
)
// predeclared represents the set of all predeclared identifiers.
var predeclared = map[string]int{
"bool": predeclaredType,
"byte": predeclaredType,
"complex128": predeclaredType,
"complex64": predeclaredType,
"error": predeclaredType,
"float32": predeclaredType,
"float64": predeclaredType,
"int16": predeclaredType,
"int32": predeclaredType,
"int64": predeclaredType,
"int8": predeclaredType,
"int": predeclaredType,
"rune": predeclaredType,
"string": predeclaredType,
"uint16": predeclaredType,
"uint32": predeclaredType,
"uint64": predeclaredType,
"uint8": predeclaredType,
"uint": predeclaredType,
"uintptr": predeclaredType,
"true": predeclaredConstant,
"false": predeclaredConstant,
"iota": predeclaredConstant,
"nil": predeclaredConstant,
"append": predeclaredFunction,
"cap": predeclaredFunction,
"close": predeclaredFunction,
"complex": predeclaredFunction,
"copy": predeclaredFunction,
"delete": predeclaredFunction,
"imag": predeclaredFunction,
"len": predeclaredFunction,
"make": predeclaredFunction,
"new": predeclaredFunction,
"panic": predeclaredFunction,
"print": predeclaredFunction,
"println": predeclaredFunction,
"real": predeclaredFunction,
"recover": predeclaredFunction,
}
const (
ExportLinkAnnotation AnnotationKind = iota
AnchorAnnotation
CommentAnnotation
PackageLinkAnnotation
BuiltinAnnotation
)
// annotationVisitor collects annotations.
type annotationVisitor struct {
annotations []Annotation
}
func (v *annotationVisitor) add(kind AnnotationKind, importPath string) {
v.annotations = append(v.annotations, Annotation{Kind: kind, ImportPath: importPath})
}
func (v *annotationVisitor) ignoreName() {
v.add(-1, "")
}
func (v *annotationVisitor) Visit(n ast.Node) ast.Visitor {
switch n := n.(type) {
case *ast.TypeSpec:
v.ignoreName()
ast.Walk(v, n.Type)
case *ast.FuncDecl:
if n.Recv != nil {
ast.Walk(v, n.Recv)
}
v.ignoreName()
ast.Walk(v, n.Type)
case *ast.Field:
for _ = range n.Names {
v.ignoreName()
}
ast.Walk(v, n.Type)
case *ast.ValueSpec:
for _ = range n.Names {
v.add(AnchorAnnotation, "")
}
if n.Type != nil {
ast.Walk(v, n.Type)
}
for _, x := range n.Values {
ast.Walk(v, x)
}
case *ast.Ident:
switch {
case n.Obj == nil && predeclared[n.Name] != notPredeclared:
v.add(BuiltinAnnotation, "")
case n.Obj != nil && ast.IsExported(n.Name):
v.add(ExportLinkAnnotation, "")
default:
v.ignoreName()
}
case *ast.SelectorExpr:
if x, _ := n.X.(*ast.Ident); x != nil {
if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg {
if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil {
if path, err := strconv.Unquote(spec.Path.Value); err == nil {
v.add(PackageLinkAnnotation, path)
if path == "C" {
v.ignoreName()
} else {
v.add(ExportLinkAnnotation, path)
}
return nil
}
}
}
}
ast.Walk(v, n.X)
v.ignoreName()
default:
return v
}
return nil
}
func printDecl(decl ast.Node, fset *token.FileSet, buf []byte) (Code, []byte) {
v := &annotationVisitor{}
ast.Walk(v, decl)
buf = buf[:0]
err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(sliceWriter{&buf}, fset, decl)
if err != nil {
return Code{Text: err.Error()}, buf
}
var annotations []Annotation
var s scanner.Scanner
fset = token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(buf))
s.Init(file, buf, nil, scanner.ScanComments)
loop:
for {
pos, tok, lit := s.Scan()
switch tok {
case token.EOF:
break loop
case token.COMMENT:
p := file.Offset(pos)
e := p + len(lit)
if p > math.MaxInt16 || e > math.MaxInt16 {
break loop
}
annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)})
case token.IDENT:
if len(v.annotations) == 0 {
// Oops!
break loop
}
annotation := v.annotations[0]
v.annotations = v.annotations[1:]
if annotation.Kind == -1 {
continue
}
p := file.Offset(pos)
e := p + len(lit)
if p > math.MaxInt16 || e > math.MaxInt16 {
break loop
}
annotation.Pos = int16(p)
annotation.End = int16(e)
if len(annotations) > 0 && annotation.Kind == ExportLinkAnnotation {
prev := annotations[len(annotations)-1]
if prev.Kind == PackageLinkAnnotation &&
prev.ImportPath == annotation.ImportPath &&
prev.End+1 == annotation.Pos {
// merge with previous
annotation.Pos = prev.Pos
annotations[len(annotations)-1] = annotation
continue loop
}
}
annotations = append(annotations, annotation)
}
}
return Code{Text: string(buf), Annotations: annotations}, buf
}
type AnnotationKind int16
type Annotation struct {
Pos, End int16
Kind AnnotationKind
ImportPath string
}
type Code struct {
Text string
Annotations []Annotation
}
func commentAnnotations(src string) []Annotation {
var annotations []Annotation
var s scanner.Scanner
fset := token.NewFileSet()
file := fset.AddFile("", fset.Base(), len(src))
s.Init(file, []byte(src), nil, scanner.ScanComments)
for {
pos, tok, lit := s.Scan()
switch tok {
case token.EOF:
return annotations
case token.COMMENT:
p := file.Offset(pos)
e := p + len(lit)
if p > math.MaxInt16 || e > math.MaxInt16 {
return annotations
}
annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)})
}
}
}
type sliceWriter struct{ p *[]byte }
func (w sliceWriter) Write(p []byte) (int, error) {
*w.p = append(*w.p, p...)
return len(p), nil
}

View File

@ -1,51 +0,0 @@
// Copyright 2013 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.
package main
import "io"
type outputMode int
// DiscardNonColorEscSeq supports the divided color escape sequence.
// But non-color escape sequence is not output.
// Please use the OutputNonColorEscSeq If you want to output a non-color
// escape sequences such as ncurses. However, it does not support the divided
// color escape sequence.
const (
_ outputMode = iota
DiscardNonColorEscSeq
OutputNonColorEscSeq
)
// NewColorWriter creates and initializes a new ansiColorWriter
// using io.Writer w as its initial contents.
// In the console of Windows, which change the foreground and background
// colors of the text by the escape sequence.
// In the console of other systems, which writes to w all text.
func NewColorWriter(w io.Writer) io.Writer {
return NewModeColorWriter(w, DiscardNonColorEscSeq)
}
// NewModeColorWriter create and initializes a new ansiColorWriter
// by specifying the outputMode.
func NewModeColorWriter(w io.Writer, mode outputMode) io.Writer {
if _, ok := w.(*colorWriter); !ok {
return &colorWriter{
w: w,
mode: mode,
}
}
return w
}

124
conf.go
View File

@ -1,124 +0,0 @@
// Copyright 2013 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.
package main
import (
"encoding/json"
"io/ioutil"
"os"
"gopkg.in/yaml.v2"
)
const ConfVer = 0
var defaultConf = `{
"version": 0,
"gopm": {
"enable": false,
"install": false
},
"go_install": false,
"watch_ext": [],
"dir_structure": {
"watch_all": false,
"controllers": "",
"models": "",
"others": []
},
"cmd_args": [],
"envs": [],
"database": {
"driver": "mysql"
}
}
`
var conf struct {
Version int
// gopm support
Gopm struct {
Enable bool
Install bool
}
// Indicates whether execute "go install" before "go build".
GoInstall bool `json:"go_install" yaml:"go_install"`
WatchExt []string `json:"watch_ext" yaml:"watch_ext"`
DirStruct struct {
WatchAll bool `json:"watch_all" yaml:"watch_all"`
Controllers string
Models string
Others []string // Other directories.
} `json:"dir_structure" yaml:"dir_structure"`
CmdArgs []string `json:"cmd_args" yaml:"cmd_args"`
Envs []string
Bale struct {
Import string
Dirs []string
IngExt []string `json:"ignore_ext" yaml:"ignore_ext"`
}
Database struct {
Driver string
Conn string
}
}
// loadConfig loads customized configuration.
func loadConfig() error {
foundConf := false
f, err := os.Open("bee.json")
if err == nil {
defer f.Close()
ColorLog("[INFO] Detected bee.json\n")
d := json.NewDecoder(f)
err = d.Decode(&conf)
if err != nil {
return err
}
foundConf = true
}
byml, erryml := ioutil.ReadFile("Beefile")
if erryml == nil {
ColorLog("[INFO] Detected Beefile\n")
err = yaml.Unmarshal(byml, &conf)
if err != nil {
return err
}
foundConf = true
}
if !foundConf {
// Use default.
err = json.Unmarshal([]byte(defaultConf), &conf)
if err != nil {
return err
}
}
// Check format version.
if conf.Version != ConfVer {
ColorLog("[WARN] Your bee.json is out-of-date, please update!\n")
ColorLog("[HINT] Compare bee.json under bee source code path and yours\n")
}
// Set variables.
if len(conf.DirStruct.Controllers) == 0 {
conf.DirStruct.Controllers = "controllers"
}
if len(conf.DirStruct.Models) == 0 {
conf.DirStruct.Models = "models"
}
// Append watch exts.
watchExts = append(watchExts, conf.WatchExt...)
return nil
}

170
config/conf.go Normal file
View File

@ -0,0 +1,170 @@
// Copyright 2013 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.
package config
import (
"encoding/json"
"io/ioutil"
"os"
"path/filepath"
"gopkg.in/yaml.v2"
beeLogger "github.com/beego/bee/v2/logger"
)
const confVer = 0
const (
Version = "2.1.0"
GitRemotePath = "github.com/beego/bee/v2"
)
var Conf = struct {
Version int
WatchExts []string `json:"watch_ext" yaml:"watch_ext"`
WatchExtsStatic []string `json:"watch_ext_static" yaml:"watch_ext_static"`
GoInstall bool `json:"go_install" yaml:"go_install"` // Indicates whether execute "go install" before "go build".
DirStruct dirStruct `json:"dir_structure" yaml:"dir_structure"`
CmdArgs []string `json:"cmd_args" yaml:"cmd_args"`
Envs []string
Bale bale
Database database
EnableReload bool `json:"enable_reload" yaml:"enable_reload"`
EnableNotification bool `json:"enable_notification" yaml:"enable_notification"`
Scripts map[string]string `json:"scripts" yaml:"scripts"`
}{
WatchExts: []string{".go"},
WatchExtsStatic: []string{".html", ".tpl", ".js", ".css"},
GoInstall: true,
DirStruct: dirStruct{
Others: []string{},
},
CmdArgs: []string{},
Envs: []string{},
Bale: bale{
Dirs: []string{},
IngExt: []string{},
},
Database: database{
Driver: "mysql",
},
EnableNotification: true,
Scripts: map[string]string{},
}
// dirStruct describes the application's directory structure
type dirStruct struct {
WatchAll bool `json:"watch_all" yaml:"watch_all"`
Controllers string
Models string
Others []string // Other directories
}
// bale
type bale struct {
Import string
Dirs []string
IngExt []string `json:"ignore_ext" yaml:"ignore_ext"`
}
// database holds the database connection information
type database struct {
Driver string
Conn string
Dir string
}
// LoadConfig loads the bee tool configuration.
// It looks for Beefile or bee.json in the current path,
// and falls back to default configuration in case not found.
func LoadConfig() {
currentPath, err := os.Getwd()
if err != nil {
beeLogger.Log.Error(err.Error())
}
dir, err := os.Open(currentPath)
if err != nil {
beeLogger.Log.Error(err.Error())
}
defer dir.Close()
files, err := dir.Readdir(-1)
if err != nil {
beeLogger.Log.Error(err.Error())
}
for _, file := range files {
switch file.Name() {
case "bee.json":
{
err = parseJSON(filepath.Join(currentPath, file.Name()), &Conf)
if err != nil {
beeLogger.Log.Errorf("Failed to parse JSON file: %s", err)
}
break
}
case "Beefile":
{
err = parseYAML(filepath.Join(currentPath, file.Name()), &Conf)
if err != nil {
beeLogger.Log.Errorf("Failed to parse YAML file: %s", err)
}
break
}
}
}
// Check format version
if Conf.Version != confVer {
beeLogger.Log.Warn("Your configuration file is outdated. Please do consider updating it.")
beeLogger.Log.Hint("Check the latest version of bee's configuration file.")
}
// Set variables
if len(Conf.DirStruct.Controllers) == 0 {
Conf.DirStruct.Controllers = "controllers"
}
if len(Conf.DirStruct.Models) == 0 {
Conf.DirStruct.Models = "models"
}
}
func parseJSON(path string, v interface{}) error {
var (
data []byte
err error
)
data, err = ioutil.ReadFile(path)
if err != nil {
return err
}
err = json.Unmarshal(data, v)
return err
}
func parseYAML(path string, v interface{}) error {
var (
data []byte
err error
)
data, err = ioutil.ReadFile(path)
if err != nil {
return err
}
err = yaml.Unmarshal(data, v)
return err
}

215
g.go
View File

@ -1,215 +0,0 @@
// Copyright 2013 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.
package main
import (
"os"
"strings"
)
var cmdGenerate = &Command{
UsageLine: "generate [Command]",
Short: "source code generator",
Long: `
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
`,
}
var driver docValue
var conn docValue
var level docValue
var tables docValue
var fields docValue
func init() {
cmdGenerate.Run = generateCode
cmdGenerate.Flag.Var(&tables, "tables", "specify tables to generate model")
cmdGenerate.Flag.Var(&driver, "driver", "database driver: mysql, postgresql, etc.")
cmdGenerate.Flag.Var(&conn, "conn", "connection string used by the driver to connect to a database instance")
cmdGenerate.Flag.Var(&level, "level", "1 = models only; 2 = models and controllers; 3 = models, controllers and routers")
cmdGenerate.Flag.Var(&fields, "fields", "specify the fields want to generate.")
}
func generateCode(cmd *Command, args []string) int {
ShowShortVersionBanner()
currpath, _ := os.Getwd()
if len(args) < 1 {
ColorLog("[ERRO] command is missing\n")
os.Exit(2)
}
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start[ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
gopath := gps[0]
Debugf("GOPATH: %s", gopath)
gcmd := args[0]
switch gcmd {
case "scaffold":
if len(args) < 2 {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate scaffold [scaffoldname] [-fields=\"\"]\n")
os.Exit(2)
}
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
cmd.Flag.Parse(args[2:])
if driver == "" {
driver = docValue(conf.Database.Driver)
if driver == "" {
driver = "mysql"
}
}
if conn == "" {
conn = docValue(conf.Database.Conn)
if conn == "" {
conn = "root:@tcp(127.0.0.1:3306)/test"
}
}
if fields == "" {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate scaffold [scaffoldname] [-fields=\"title:string,body:text\"]\n")
os.Exit(2)
}
sname := args[1]
generateScaffold(sname, fields.String(), currpath, driver.String(), conn.String())
case "docs":
generateDocs(currpath)
case "appcode":
// load config
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
cmd.Flag.Parse(args[1:])
if driver == "" {
driver = docValue(conf.Database.Driver)
if driver == "" {
driver = "mysql"
}
}
if conn == "" {
conn = docValue(conf.Database.Conn)
if conn == "" {
if driver == "mysql" {
conn = "root:@tcp(127.0.0.1:3306)/test"
} else if driver == "postgres" {
conn = "postgres://postgres:postgres@127.0.0.1:5432/postgres"
}
}
}
if level == "" {
level = "3"
}
ColorLog("[INFO] Using '%s' as 'driver'\n", driver)
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
ColorLog("[INFO] Using '%s' as 'level'\n", level)
generateAppcode(driver.String(), conn.String(), level.String(), tables.String(), currpath)
case "migration":
if len(args) < 2 {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate migration [migrationname] [-fields=\"\"]\n")
os.Exit(2)
}
cmd.Flag.Parse(args[2:])
mname := args[1]
ColorLog("[INFO] Using '%s' as migration name\n", mname)
upsql := ""
downsql := ""
if fields != "" {
dbMigrator := newDBDriver()
upsql = dbMigrator.generateCreateUp(mname)
downsql = dbMigrator.generateCreateDown(mname)
}
generateMigration(mname, upsql, downsql, currpath)
case "controller":
if len(args) == 2 {
cname := args[1]
generateController(cname, currpath)
} else {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate controller [controllername]\n")
os.Exit(2)
}
case "model":
if len(args) < 2 {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate model [modelname] [-fields=\"\"]\n")
os.Exit(2)
}
cmd.Flag.Parse(args[2:])
if fields == "" {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate model [modelname] [-fields=\"title:string,body:text\"]\n")
os.Exit(2)
}
sname := args[1]
generateModel(sname, fields.String(), currpath)
case "view":
if len(args) == 2 {
cname := args[1]
generateView(cname, currpath)
} else {
ColorLog("[ERRO] Wrong number of arguments\n")
ColorLog("[HINT] Usage: bee generate view [viewpath]\n")
os.Exit(2)
}
default:
ColorLog("[ERRO] Command is missing\n")
}
ColorLog("[SUCC] %s successfully generated!\n", strings.Title(gcmd))
return 0
}

805
g_docs.go
View File

@ -1,805 +0,0 @@
// Copyright 2013 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.
package main
import (
"encoding/json"
"errors"
"fmt"
"go/ast"
"go/parser"
"go/token"
"os"
"path"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strconv"
"strings"
"unicode"
"github.com/astaxie/beego/swagger"
"github.com/astaxie/beego/utils"
)
const (
ajson = "application/json"
axml = "application/xml"
aplain = "text/plain"
ahtml = "text/html"
)
var pkgCache map[string]struct{} //pkg:controller:function:comments comments: key:value
var controllerComments map[string]string
var importlist map[string]string
var controllerList map[string]map[string]*swagger.Item //controllername Paths items
var modelsList map[string]map[string]swagger.Schema
var rootapi swagger.Swagger
func init() {
pkgCache = make(map[string]struct{})
controllerComments = make(map[string]string)
importlist = make(map[string]string)
controllerList = make(map[string]map[string]*swagger.Item)
modelsList = make(map[string]map[string]swagger.Schema)
}
func generateDocs(curpath string) {
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, path.Join(curpath, "routers", "router.go"), nil, parser.ParseComments)
if err != nil {
ColorLog("[ERRO] parse router.go error\n")
os.Exit(2)
}
rootapi.Infos = swagger.Information{}
rootapi.SwaggerVersion = "2.0"
//analysis API comments
if f.Comments != nil {
for _, c := range f.Comments {
for _, s := range strings.Split(c.Text(), "\n") {
if strings.HasPrefix(s, "@APIVersion") {
rootapi.Infos.Version = strings.TrimSpace(s[len("@APIVersion"):])
} else if strings.HasPrefix(s, "@Title") {
rootapi.Infos.Title = strings.TrimSpace(s[len("@Title"):])
} else if strings.HasPrefix(s, "@Description") {
rootapi.Infos.Description = strings.TrimSpace(s[len("@Description"):])
} else if strings.HasPrefix(s, "@TermsOfServiceUrl") {
rootapi.Infos.TermsOfService = strings.TrimSpace(s[len("@TermsOfServiceUrl"):])
} else if strings.HasPrefix(s, "@Contact") {
rootapi.Infos.Contact.EMail = strings.TrimSpace(s[len("@Contact"):])
} else if strings.HasPrefix(s, "@License") {
rootapi.Infos.License.Name = strings.TrimSpace(s[len("@License"):])
} else if strings.HasPrefix(s, "@LicenseUrl") {
rootapi.Infos.License.URL = strings.TrimSpace(s[len("@LicenseUrl"):])
}
}
}
}
// analisys controller package
for _, im := range f.Imports {
localName := ""
if im.Name != nil {
localName = im.Name.Name
}
analisyscontrollerPkg(localName, im.Path.Value)
}
for _, d := range f.Decls {
switch specDecl := d.(type) {
case *ast.FuncDecl:
for _, l := range specDecl.Body.List {
switch stmt := l.(type) {
case *ast.AssignStmt:
for _, l := range stmt.Rhs {
if v, ok := l.(*ast.CallExpr); ok {
// analisys NewNamespace, it will return version and the subfunction
if selName := v.Fun.(*ast.SelectorExpr).Sel.String(); selName != "NewNamespace" {
continue
}
version, params := analisysNewNamespace(v)
if rootapi.BasePath == "" && version != "" {
rootapi.BasePath = version
}
for _, p := range params {
switch pp := p.(type) {
case *ast.CallExpr:
controllerName := ""
if selname := pp.Fun.(*ast.SelectorExpr).Sel.String(); selname == "NSNamespace" {
s, params := analisysNewNamespace(pp)
for _, sp := range params {
switch pp := sp.(type) {
case *ast.CallExpr:
if pp.Fun.(*ast.SelectorExpr).Sel.String() == "NSInclude" {
controllerName = analisysNSInclude(s, pp)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: strings.Trim(s, "/"),
Description: v,
})
}
}
}
}
} else if selname == "NSInclude" {
controllerName = analisysNSInclude("", pp)
if v, ok := controllerComments[controllerName]; ok {
rootapi.Tags = append(rootapi.Tags, swagger.Tag{
Name: controllerName, // if the NSInclude has no prefix, we use the controllername as the tag
Description: v,
})
}
}
}
}
}
}
}
}
}
}
os.Mkdir(path.Join(curpath, "swagger"), 0755)
fd, err := os.Create(path.Join(curpath, "swagger", "swagger.json"))
if err != nil {
panic(err)
}
defer fd.Close()
dt, err := json.MarshalIndent(rootapi, "", " ")
if err != nil {
panic(err)
}
_, err = fd.Write(dt)
if err != nil {
panic(err)
}
}
// return version and the others params
func analisysNewNamespace(ce *ast.CallExpr) (first string, others []ast.Expr) {
for i, p := range ce.Args {
if i == 0 {
switch pp := p.(type) {
case *ast.BasicLit:
first = strings.Trim(pp.Value, `"`)
}
continue
}
others = append(others, p)
}
return
}
func analisysNSInclude(baseurl string, ce *ast.CallExpr) string {
cname := ""
for _, p := range ce.Args {
x := p.(*ast.UnaryExpr).X.(*ast.CompositeLit).Type.(*ast.SelectorExpr)
if v, ok := importlist[fmt.Sprint(x.X)]; ok {
cname = v + x.Sel.Name
}
if apis, ok := controllerList[cname]; ok {
for rt, item := range apis {
tag := ""
if baseurl != "" {
rt = baseurl + rt
tag = strings.Trim(baseurl, "/")
} else {
tag = cname
}
if item.Get != nil {
item.Get.Tags = []string{tag}
}
if item.Post != nil {
item.Post.Tags = []string{tag}
}
if item.Put != nil {
item.Put.Tags = []string{tag}
}
if item.Patch != nil {
item.Patch.Tags = []string{tag}
}
if item.Head != nil {
item.Head.Tags = []string{tag}
}
if item.Delete != nil {
item.Delete.Tags = []string{tag}
}
if item.Options != nil {
item.Options.Tags = []string{tag}
}
if len(rootapi.Paths) == 0 {
rootapi.Paths = make(map[string]*swagger.Item)
}
rt = urlReplace(rt)
rootapi.Paths[rt] = item
}
}
}
return cname
}
func analisyscontrollerPkg(localName, pkgpath string) {
pkgpath = strings.Trim(pkgpath, "\"")
if isSystemPackage(pkgpath) {
return
}
if pkgpath == "github.com/astaxie/beego" {
return
}
if localName != "" {
importlist[localName] = pkgpath
} else {
pps := strings.Split(pkgpath, "/")
importlist[pps[len(pps)-1]] = pkgpath
}
gopath := os.Getenv("GOPATH")
if gopath == "" {
panic("please set gopath")
}
pkgRealpath := ""
wgopath := filepath.SplitList(gopath)
for _, wg := range wgopath {
wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src", pkgpath))
if utils.FileExists(wg) {
pkgRealpath = wg
break
}
}
if pkgRealpath != "" {
if _, ok := pkgCache[pkgpath]; ok {
return
}
pkgCache[pkgpath] = struct{}{}
} else {
ColorLog("[ERRO] the %s pkg not exist in gopath\n", pkgpath)
os.Exit(1)
}
fileSet := token.NewFileSet()
astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool {
name := info.Name()
return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}, parser.ParseComments)
if err != nil {
ColorLog("[ERRO] the %s pkg parser.ParseDir error\n", pkgpath)
os.Exit(1)
}
for _, pkg := range astPkgs {
for _, fl := range pkg.Files {
for _, d := range fl.Decls {
switch specDecl := d.(type) {
case *ast.FuncDecl:
if specDecl.Recv != nil && len(specDecl.Recv.List) > 0 {
if t, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr); ok {
// parse controller method
parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(t.X), pkgpath)
}
}
case *ast.GenDecl:
if specDecl.Tok == token.TYPE {
for _, s := range specDecl.Specs {
switch tp := s.(*ast.TypeSpec).Type.(type) {
case *ast.StructType:
_ = tp.Struct
//parse controller definition comments
if strings.TrimSpace(specDecl.Doc.Text()) != "" {
controllerComments[pkgpath+s.(*ast.TypeSpec).Name.String()] = specDecl.Doc.Text()
}
}
}
}
}
}
}
}
}
func isSystemPackage(pkgpath string) bool {
goroot := runtime.GOROOT()
if goroot == "" {
panic("goroot is empty, do you install Go right?")
}
wg, _ := filepath.EvalSymlinks(filepath.Join(goroot, "src", "pkg", pkgpath))
if utils.FileExists(wg) {
return true
}
//TODO(zh):support go1.4
wg, _ = filepath.EvalSymlinks(filepath.Join(goroot, "src", pkgpath))
if utils.FileExists(wg) {
return true
}
return false
}
// parse the func comments
func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error {
var routerPath string
var HTTPMethod string
opts := swagger.Operation{
Responses: make(map[string]swagger.Response),
}
if comments != nil && comments.List != nil {
for _, c := range comments.List {
t := strings.TrimSpace(strings.TrimLeft(c.Text, "//"))
if strings.HasPrefix(t, "@router") {
elements := strings.TrimSpace(t[len("@router"):])
e1 := strings.SplitN(elements, " ", 2)
if len(e1) < 1 {
return errors.New("you should has router infomation")
}
routerPath = e1[0]
if len(e1) == 2 && e1[1] != "" {
e1 = strings.SplitN(e1[1], " ", 2)
HTTPMethod = strings.ToUpper(strings.Trim(e1[0], "[]"))
} else {
HTTPMethod = "GET"
}
} else if strings.HasPrefix(t, "@Title") {
opts.OperationID = controllerName + "." + strings.TrimSpace(t[len("@Title"):])
} else if strings.HasPrefix(t, "@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") {
ss := strings.TrimSpace(t[len("@Success"):])
rs := swagger.Response{}
st := make([]string, 3)
j := 0
var tmp []rune
start := false
for i, c := range ss {
if unicode.IsSpace(c) {
if !start && j < 2 {
continue
}
if j == 0 || j == 1 {
st[j] = string(tmp)
tmp = make([]rune, 0)
j++
start = false
if j == 1 {
continue
} else {
st[j] = strings.TrimSpace(ss[i+1:])
break
}
}
} else {
start = true
tmp = append(tmp, c)
}
}
if len(tmp) > 0 && st[2] == "" {
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)
} else if st[1] == "{array}" {
rs.Schema = &swagger.Schema{}
rs.Schema.Type = "array"
if sType, ok := basicTypes[st[2]]; ok {
typeFormat := strings.Split(sType, ":")
rs.Schema.Type = typeFormat[0]
rs.Schema.Format = typeFormat[1]
} else {
cmpath, m, mod, realTypes := getModel(st[2])
rs.Schema.Items = &swagger.Propertie{
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") {
para := swagger.Parameter{}
p := getparams(strings.TrimSpace(t[len("@Param "):]))
if len(p) < 4 {
panic(controllerName + "_" + funcName + "'s comments @Param at least should has 4 params")
}
para.Name = p[0]
switch p[1] {
case "query":
fallthrough
case "header":
fallthrough
case "path":
fallthrough
case "formData":
fallthrough
case "body":
break
default:
fmt.Fprintf(os.Stderr, "[%s.%s] Unknow param location: %s, Possible values are `query`, `header`, `path`, `formData` or `body`.\n", controllerName, funcName, p[1])
}
para.In = p[1]
pp := strings.Split(p[2], ".")
typ := pp[len(pp)-1]
if len(pp) >= 2 {
cmpath, m, mod, realTypes := getModel(p[2])
para.Schema = &swagger.Schema{
Ref: "#/definitions/" + m,
}
if _, ok := modelsList[pkgpath+controllerName]; !ok {
modelsList[pkgpath+controllerName] = make(map[string]swagger.Schema, 0)
}
modelsList[pkgpath+controllerName][typ] = mod
appendModels(cmpath, pkgpath, controllerName, realTypes)
} else {
if typ == "string" || typ == "number" || typ == "integer" || typ == "boolean" ||
typ == "array" || typ == "file" {
para.Type = typ
} else if sType, ok := basicTypes[typ]; ok {
typeFormat := strings.Split(sType, ":")
para.Type = typeFormat[0]
para.Format = typeFormat[1]
} else {
fmt.Fprintf(os.Stderr, "[%s.%s] Unknow param type: %s\n", controllerName, funcName, typ)
}
}
if len(p) > 4 {
para.Required, _ = strconv.ParseBool(p[3])
para.Description = strings.Trim(p[4], `" `)
} else {
para.Description = strings.Trim(p[3], `" `)
}
opts.Parameters = append(opts.Parameters, para)
} else if strings.HasPrefix(t, "@Failure") {
rs := swagger.Response{}
st := strings.TrimSpace(t[len("@Failure"):])
var cd []rune
var start bool
for i, s := range st {
if unicode.IsSpace(s) {
if start {
rs.Description = strings.TrimSpace(st[i+1:])
break
} else {
continue
}
}
start = true
cd = append(cd, s)
}
opts.Responses[string(cd)] = rs
} else if strings.HasPrefix(t, "@Deprecated") {
opts.Deprecated, _ = strconv.ParseBool(strings.TrimSpace(t[len("@Deprecated"):]))
} else if strings.HasPrefix(t, "@Accept") {
accepts := strings.Split(strings.TrimSpace(strings.TrimSpace(t[len("@Accept"):])), ",")
for _, a := range accepts {
switch a {
case "json":
opts.Consumes = append(opts.Consumes, ajson)
opts.Produces = append(opts.Produces, ajson)
case "xml":
opts.Consumes = append(opts.Consumes, axml)
opts.Produces = append(opts.Produces, axml)
case "plain":
opts.Consumes = append(opts.Consumes, aplain)
opts.Produces = append(opts.Produces, aplain)
case "html":
opts.Consumes = append(opts.Consumes, ahtml)
opts.Produces = append(opts.Produces, ahtml)
}
}
}
}
}
if routerPath != "" {
var item *swagger.Item
if itemList, ok := controllerList[pkgpath+controllerName]; ok {
if it, ok := itemList[routerPath]; !ok {
item = &swagger.Item{}
} else {
item = it
}
} else {
controllerList[pkgpath+controllerName] = make(map[string]*swagger.Item)
item = &swagger.Item{}
}
switch HTTPMethod {
case "GET":
item.Get = &opts
case "POST":
item.Post = &opts
case "PUT":
item.Put = &opts
case "PATCH":
item.Patch = &opts
case "DELETE":
item.Delete = &opts
case "HEAD":
item.Head = &opts
case "OPTIONS":
item.Options = &opts
}
controllerList[pkgpath+controllerName][routerPath] = item
}
return nil
}
// analisys params return []string
// @Param query form string true "The email for login"
// [query form string true "The email for login"]
func getparams(str string) []string {
var s []rune
var j int
var start bool
var r []string
for i, c := range []rune(str) {
if unicode.IsSpace(c) {
if !start {
continue
} else {
if j == 3 {
r = append(r, string(s))
r = append(r, strings.TrimSpace((str[i+1:])))
break
}
start = false
j++
r = append(r, string(s))
s = make([]rune, 0)
continue
}
}
start = true
s = append(s, c)
}
return r
}
func getModel(str string) (pkgpath, objectname string, m swagger.Schema, realTypes []string) {
strs := strings.Split(str, ".")
objectname = strs[len(strs)-1]
pkgpath = strings.Join(strs[:len(strs)-1], "/")
curpath, _ := os.Getwd()
pkgRealpath := path.Join(curpath, pkgpath)
fileSet := token.NewFileSet()
astPkgs, err := parser.ParseDir(fileSet, pkgRealpath, func(info os.FileInfo) bool {
name := info.Name()
return !info.IsDir() && !strings.HasPrefix(name, ".") && strings.HasSuffix(name, ".go")
}, parser.ParseComments)
if err != nil {
ColorLog("[ERRO] the model %s parser.ParseDir error\n", str)
os.Exit(1)
}
m.Type = "object"
for _, pkg := range astPkgs {
for _, fl := range pkg.Files {
for k, d := range fl.Scope.Objects {
if d.Kind == ast.Typ {
if k != objectname {
continue
}
ts, ok := d.Decl.(*ast.TypeSpec)
if !ok {
ColorLog("Unknown type without TypeSec: %v", d)
os.Exit(1)
}
st, ok := ts.Type.(*ast.StructType)
if !ok {
continue
}
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{}
// add type slice
if isSlice {
mp.Type = "array"
if isBasicType(realType) {
typeFormat := strings.Split(sType, ":")
mp.Items = &swagger.Propertie{
Type: typeFormat[0],
Format: typeFormat[1],
}
} else {
mp.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
if field.Names != nil {
// set property name as field name
var name = field.Names[0].Name
// if no tag skip tag processing
if field.Tag == nil {
m.Properties[name] = mp
continue
}
var tagValues []string
stag := reflect.StructTag(strings.Trim(field.Tag.Value, "`"))
tag := stag.Get("json")
if tag != "" {
tagValues = strings.Split(tag, ",")
}
// dont add property if json tag first value is "-"
if len(tagValues) == 0 || tagValues[0] != "-" {
// set property name to the left most json tag value only if is not omitempty
if len(tagValues) > 0 && tagValues[0] != "omitempty" {
name = tagValues[0]
}
if thrifttag := stag.Get("thrift"); thrifttag != "" {
ts := strings.Split(thrifttag, ",")
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
}
m.Properties[name] = mp
}
if ignore := stag.Get("ignore"); ignore != "" {
continue
}
}
}
}
}
}
}
}
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) {
if arr, ok := f.Type.(*ast.ArrayType); ok {
if isBasicType(fmt.Sprint(arr.Elt)) {
return false, fmt.Sprintf("[]%v", arr.Elt), basicTypes[fmt.Sprint(arr.Elt)]
}
if mp, ok := arr.Elt.(*ast.MapType); ok {
return false, fmt.Sprintf("map[%v][%v]", mp.Key, mp.Value), "object"
}
if star, ok := arr.Elt.(*ast.StarExpr); ok {
return true, fmt.Sprint(star.X), "object"
}
return true, fmt.Sprint(arr.Elt), "object"
}
switch t := f.Type.(type) {
case *ast.StarExpr:
return false, fmt.Sprint(t.X), "object"
case *ast.MapType:
return false, fmt.Sprint(t.Value), "object"
}
if k, ok := basicTypes[fmt.Sprint(f.Type)]; ok {
return false, fmt.Sprint(f.Type), k
}
return false, fmt.Sprint(f.Type), "object"
}
func isBasicType(Type string) bool {
if _, ok := basicTypes[Type]; ok {
return true
}
return false
}
// refer to builtin.go
var basicTypes = map[string]string{
"bool": "boolean:",
"uint": "integer:int32", "uint8": "integer:int32", "uint16": "integer:int32", "uint32": "integer:int32", "uint64": "integer:int64",
"int": "integer:int64", "int8": "integer:int32", "int16:int32": "integer:int32", "int32": "integer:int32", "int64": "integer:int64",
"uintptr": "integer:int64",
"float32": "number:float", "float64": "number:double",
"string": "string:",
"complex64": "number:float", "complex128": "number:double",
"byte": "string:byte", "rune": "string:byte",
}
// regexp get json tag
func grepJSONTag(tag string) string {
r, _ := regexp.Compile(`json:"([^"]*)"`)
matches := r.FindAllStringSubmatch(tag, -1)
if len(matches) > 0 {
return matches[0][1]
}
return ""
}
// append models
func appendModels(cmpath, pkgpath, controllerName string, realTypes []string) {
var p string
if cmpath != "" {
p = strings.Join(strings.Split(cmpath, "/"), ".") + "."
} else {
p = ""
}
for _, realType := range realTypes {
if realType != "" && !isBasicType(strings.TrimLeft(realType, "[]")) &&
!strings.HasPrefix(realType, "map") && !strings.HasPrefix(realType, "&") {
if _, ok := modelsList[pkgpath+controllerName][p+realType]; ok {
continue
}
//fmt.Printf(pkgpath + ":" + controllerName + ":" + cmpath + ":" + realType + "\n")
_, _, mod, newRealTypes := getModel(p + realType)
modelsList[pkgpath+controllerName][p+realType] = mod
appendModels(cmpath, pkgpath, controllerName, newRealTypes)
}
}
}
func urlReplace(src string) string {
pt := strings.Split(src, "/")
for i, p := range pt {
if len(p) > 0 {
if p[0] == ':' {
pt[i] = "{" + p[1:] + "}"
} else if p[0] == '?' && p[1] == ':' {
pt[i] = "{" + p[2:] + "}"
}
}
}
return strings.Join(pt, "/")
}

View File

@ -1,48 +0,0 @@
package main
import "strings"
func generateScaffold(sname, fields, currpath, driver, conn string) {
ColorLog("[INFO] Do you want to create a '%v' model? [Yes|No] ", sname)
// Generate the model
if askForConfirmation() {
generateModel(sname, fields, currpath)
}
// Generate the controller
ColorLog("[INFO] Do you want to create a '%v' controller? [Yes|No] ", sname)
if askForConfirmation() {
generateController(sname, currpath)
}
// Generate the views
ColorLog("[INFO] Do you want to create views for this '%v' resource? [Yes|No] ", sname)
if askForConfirmation() {
generateView(sname, currpath)
}
// Generate a migration
ColorLog("[INFO] Do you want to create a '%v' migration and schema for this resource? [Yes|No] ", sname)
if askForConfirmation() {
upsql := ""
downsql := ""
if fields != "" {
dbMigrator := newDBDriver()
upsql = dbMigrator.generateCreateUp(sname)
downsql = dbMigrator.generateCreateDown(sname)
//todo remove
//if driver == "" {
// downsql = strings.Replace(downsql, "`", "", -1)
//}
}
generateMigration(sname, upsql, downsql, currpath)
}
// Run the migration
ColorLog("[INFO] Do you want to migrate the database? [Yes|No] ")
if askForConfirmation() {
migrateUpdate(currpath, driver, conn)
}
ColorLog("[INFO] All done! Don't forget to add beego.Router(\"/%v\" ,&controllers.%vController{}) to routers/route.go\n", sname, strings.Title(sname))
}

30
generate/g.go Normal file
View File

@ -0,0 +1,30 @@
// Copyright 2013 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.
package generate
import "github.com/beego/bee/v2/utils"
var SQLDriver utils.DocValue
var SQLConn utils.DocValue
var Level utils.DocValue
var Tables utils.DocValue
var Fields utils.DocValue
var DDL utils.DocValue
// bee generate routers
var ControllerDirectory utils.DocValue
var RoutersFile utils.DocValue
var RouterPkg utils.DocValue

View File

@ -12,18 +12,22 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"bufio"
"database/sql"
"fmt"
"io"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"strings"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
)
@ -39,7 +43,7 @@ type DbTransformer interface {
GetTableNames(conn *sql.DB) []string
GetConstraints(conn *sql.DB, table *Table, blackList map[string]bool)
GetColumns(conn *sql.DB, table *Table, blackList map[string]bool)
GetGoDataType(sqlType string) string
GetGoDataType(sqlType string) (string, error)
}
// MysqlDB is the MySQL version of DbTransformer
@ -99,6 +103,7 @@ var typeMappingMysql = map[string]string{
"decimal": "float64",
"binary": "string", // binary
"varbinary": "string",
"year": "int16",
}
// typeMappingPostgres maps SQL data type to corresponding Go data type
@ -131,7 +136,8 @@ var typeMappingPostgres = map[string]string{
"USER-DEFINED": "string", // user defined
"uuid": "string", // uuid
"json": "string", // json
"jsonb": "string",
"jsonb": "string", // jsonb
"inet": "string", // ip address
}
// Table represent a table in a database
@ -179,11 +185,12 @@ type OrmTag struct {
RelFk bool
ReverseMany bool
RelM2M bool
Comment string //column comment
}
// String returns the source code string for the Table struct
func (tb *Table) String() string {
rv := fmt.Sprintf("type %s struct {\n", camelCase(tb.Name))
rv := fmt.Sprintf("type %s struct {\n", utils.CamelCase(tb.Name))
for _, v := range tb.Columns {
rv += v.String() + "\n"
}
@ -252,10 +259,13 @@ func (tag *OrmTag) String() string {
if len(ormOptions) == 0 {
return ""
}
if tag.Comment != "" {
return fmt.Sprintf("`orm:\"%s\" description:\"%s\"`", strings.Join(ormOptions, ";"), tag.Comment)
}
return fmt.Sprintf("`orm:\"%s\"`", strings.Join(ormOptions, ";"))
}
func generateAppcode(driver, connStr, level, tables, currpath string) {
func GenerateAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
@ -265,9 +275,7 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
case "3":
mode = OModel | OController | ORouter
default:
ColorLog("[ERRO] Invalid 'level' option: %s\n", level)
ColorLog("[HINT] Level must be either 1, 2 or 3\n")
os.Exit(2)
beeLogger.Log.Fatal("Invalid level value. Must be either \"1\", \"2\", or \"3\"")
}
var selectedTables map[string]bool
if tables != "" {
@ -280,12 +288,9 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
case "mysql":
case "postgres":
case "sqlite":
ColorLog("[ERRO] Generating app code from SQLite database is not supported yet.\n")
os.Exit(2)
beeLogger.Log.Fatal("Generating app code from SQLite database is not supported yet.")
default:
ColorLog("[ERRO] Unknown database driver: %s\n", driver)
ColorLog("[HINT] Driver must be one of mysql, postgres or sqlite\n")
os.Exit(2)
beeLogger.Log.Fatal("Unknown database driver. Must be either \"mysql\", \"postgres\" or \"sqlite\"")
}
gen(driver, connStr, mode, selectedTables, currpath)
}
@ -295,13 +300,19 @@ func generateAppcode(driver, connStr, level, tables, currpath string) {
func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, apppath string) {
db, err := sql.Open(dbms, connStr)
if err != nil {
ColorLog("[ERRO] Could not connect to %s database: %s, %s\n", dbms, connStr, err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err)
}
defer db.Close()
if trans, ok := dbDriver[dbms]; ok {
ColorLog("[INFO] Analyzing database tables...\n")
tableNames := trans.GetTableNames(db)
beeLogger.Log.Info("Analyzing database tables...")
var tableNames []string
if len(selectedTableNames) != 0 {
for tableName := range selectedTableNames {
tableNames = append(tableNames, tableName)
}
} else {
tableNames = trans.GetTableNames(db)
}
tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath)
mvcPath.ModelPath = path.Join(apppath, "models")
@ -309,27 +320,23 @@ func gen(dbms, connStr string, mode byte, selectedTableNames map[string]bool, ap
mvcPath.RouterPath = path.Join(apppath, "routers")
createPaths(mode, mvcPath)
pkgPath := getPackagePath(apppath)
writeSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames)
writeSourceFiles(pkgPath, tables, mode, mvcPath)
} else {
ColorLog("[ERRO] Generating app code from %s database is not supported yet.\n", dbms)
os.Exit(2)
beeLogger.Log.Fatalf("Generating app code from '%s' database is not supported yet.", dbms)
}
}
// getTables gets a list table names in current database
// GetTableNames returns a slice of table names in the current database
func (*MysqlDB) GetTableNames(db *sql.DB) (tables []string) {
rows, err := db.Query("SHOW TABLES")
if err != nil {
ColorLog("[ERRO] Could not show tables\n")
ColorLog("[HINT] Check your connection string\n")
os.Exit(2)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
ColorLog("[ERRO] Could not show tables\n")
os.Exit(2)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
tables = append(tables, name)
}
@ -358,8 +365,8 @@ func getTableObjects(tableNames []string, db *sql.DB, dbTransformer DbTransforme
return
}
// getConstraints gets primary key, unique key and foreign keys of a table from information_schema
// and fill in Table struct
// GetConstraints gets primary key, unique key and foreign keys of a table from
// information_schema and fill in the Table struct
func (*MysqlDB) GetConstraints(db *sql.DB, table *Table, blackList map[string]bool) {
rows, err := db.Query(
`SELECT
@ -372,14 +379,12 @@ func (*MysqlDB) GetConstraints(db *sql.DB, table *Table, blackList map[string]bo
c.table_schema = database() AND c.table_name = ? AND u.table_schema = database() AND u.table_name = ?`,
table.Name, table.Name) // u.position_in_unique_constraint,
if err != nil {
ColorLog("[ERRO] Could not query INFORMATION_SCHEMA for PK/UK/FK information\n")
os.Exit(2)
beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for PK/UK/FK information")
}
for rows.Next() {
var constraintTypeBytes, columnNameBytes, refTableSchemaBytes, refTableNameBytes, refColumnNameBytes, refOrdinalPosBytes []byte
if err := rows.Scan(&constraintTypeBytes, &columnNameBytes, &refTableSchemaBytes, &refTableNameBytes, &refColumnNameBytes, &refOrdinalPosBytes); err != nil {
ColorLog("[ERRO] Could not read INFORMATION_SCHEMA for PK/UK/FK information\n")
os.Exit(2)
beeLogger.Log.Fatal("Could not read INFORMATION_SCHEMA for PK/UK/FK information")
}
constraintType, columnName, refTableSchema, refTableName, refColumnName, refOrdinalPos :=
string(constraintTypeBytes), string(columnNameBytes), string(refTableSchemaBytes),
@ -389,7 +394,7 @@ func (*MysqlDB) GetConstraints(db *sql.DB, table *Table, blackList map[string]bo
table.Pk = columnName
} else {
table.Pk = ""
// add table to blacklist so that other struct will not reference it, because we are not
// Add table to blacklist so that other struct will not reference it, because we are not
// registering blacklisted tables
blackList[table.Name] = true
}
@ -406,35 +411,44 @@ func (*MysqlDB) GetConstraints(db *sql.DB, table *Table, blackList map[string]bo
}
}
// getColumns retrieve columns details from information_schema
// and fill in the Column struct
// GetColumns retrieves columns details from
// information_schema and fill in the Column struct
func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[string]bool) {
// retrieve columns
colDefRows, _ := db.Query(
colDefRows, err := db.Query(
`SELECT
column_name, data_type, column_type, is_nullable, column_default, extra
column_name, data_type, column_type, is_nullable, column_default, extra, column_comment
FROM
information_schema.columns
WHERE
table_schema = database() AND table_name = ?`,
table.Name)
if err != nil {
beeLogger.Log.Fatalf("Could not query the database: %s", err)
}
defer colDefRows.Close()
for colDefRows.Next() {
// datatype as bytes so that SQL <null> values can be retrieved
var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte
if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil {
ColorLog("[ERRO] Could not query INFORMATION_SCHEMA for column information\n")
os.Exit(2)
var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes, columnCommentBytes []byte
if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes, &columnCommentBytes); err != nil {
beeLogger.Log.Fatal("Could not query INFORMATION_SCHEMA for column information")
}
colName, dataType, columnType, isNullable, columnDefault, extra :=
string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes)
colName, dataType, columnType, isNullable, columnDefault, extra, columnComment :=
string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes), string(columnCommentBytes)
// create a column
col := new(Column)
col.Name = camelCase(colName)
col.Type = mysqlDB.GetGoDataType(dataType)
col.Name = utils.CamelCase(colName)
col.Type, err = mysqlDB.GetGoDataType(dataType)
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
// Tag info
tag := new(OrmTag)
tag.Column = colName
tag.Comment = columnComment
if table.Pk == colName {
col.Name = "Id"
col.Type = "int"
@ -453,8 +467,8 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
if isFk && !isBl {
tag.RelFk = true
refStructName := fkCol.RefTable
col.Name = camelCase(colName)
col.Type = "*" + camelCase(refStructName)
col.Name = utils.CamelCase(colName)
col.Type = "*" + utils.CamelCase(refStructName)
} else {
// if the name of column is Id, and it's not primary key
if colName == "id" {
@ -466,7 +480,10 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
if isSQLSignedIntType(dataType) {
sign := extractIntSignness(columnType)
if sign == "unsigned" && extra != "auto_increment" {
col.Type = mysqlDB.GetGoDataType(dataType + " " + sign)
col.Type, err = mysqlDB.GetGoDataType(dataType + " " + sign)
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
}
}
if isSQLStringType(dataType) {
@ -500,15 +517,11 @@ func (mysqlDB *MysqlDB) GetColumns(db *sql.DB, table *Table, blackList map[strin
}
// GetGoDataType maps an SQL data type to Golang data type
func (*MysqlDB) GetGoDataType(sqlType string) (goType string) {
var typeMapping = map[string]string{}
typeMapping = typeMappingMysql
if v, ok := typeMapping[sqlType]; ok {
return v
func (*MysqlDB) GetGoDataType(sqlType string) (string, error) {
if v, ok := typeMappingMysql[sqlType]; ok {
return v, nil
}
ColorLog("[ERRO] data type (%s) not found!\n", sqlType)
os.Exit(2)
return goType
return "", fmt.Errorf("data type '%s' not found", sqlType)
}
// GetTableNames for PostgreSQL
@ -519,16 +532,14 @@ func (*PostgresDB) GetTableNames(db *sql.DB) (tables []string) {
table_type = 'BASE TABLE' AND
table_schema NOT IN ('pg_catalog', 'information_schema')`)
if err != nil {
ColorLog("[ERRO] Could not show tables: %s\n", err)
ColorLog("[HINT] Check your connection string\n")
os.Exit(2)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
ColorLog("[ERRO] Could not show tables\n")
os.Exit(2)
beeLogger.Log.Fatalf("Could not show tables: %s", err)
}
tables = append(tables, name)
}
@ -558,14 +569,13 @@ func (*PostgresDB) GetConstraints(db *sql.DB, table *Table, blackList map[string
AND u.table_name = $2`,
table.Name, table.Name) // u.position_in_unique_constraint,
if err != nil {
ColorLog("[ERRO] Could not query INFORMATION_SCHEMA for PK/UK/FK information: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for PK/UK/FK information: %s", err)
}
for rows.Next() {
var constraintTypeBytes, columnNameBytes, refTableSchemaBytes, refTableNameBytes, refColumnNameBytes, refOrdinalPosBytes []byte
if err := rows.Scan(&constraintTypeBytes, &columnNameBytes, &refTableSchemaBytes, &refTableNameBytes, &refColumnNameBytes, &refOrdinalPosBytes); err != nil {
ColorLog("[ERRO] Could not read INFORMATION_SCHEMA for PK/UK/FK information\n")
os.Exit(2)
beeLogger.Log.Fatalf("Could not read INFORMATION_SCHEMA for PK/UK/FK information: %s", err)
}
constraintType, columnName, refTableSchema, refTableName, refColumnName, refOrdinalPos :=
string(constraintTypeBytes), string(columnNameBytes), string(refTableSchemaBytes),
@ -595,7 +605,7 @@ func (*PostgresDB) GetConstraints(db *sql.DB, table *Table, blackList map[string
// GetColumns for PostgreSQL
func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map[string]bool) {
// retrieve columns
colDefRows, _ := db.Query(
colDefRows, err := db.Query(
`SELECT
column_name,
data_type,
@ -614,20 +624,27 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
table_catalog = current_database() AND table_schema NOT IN ('pg_catalog', 'information_schema')
AND table_name = $1`,
table.Name)
if err != nil {
beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err)
}
defer colDefRows.Close()
for colDefRows.Next() {
// datatype as bytes so that SQL <null> values can be retrieved
var colNameBytes, dataTypeBytes, columnTypeBytes, isNullableBytes, columnDefaultBytes, extraBytes []byte
if err := colDefRows.Scan(&colNameBytes, &dataTypeBytes, &columnTypeBytes, &isNullableBytes, &columnDefaultBytes, &extraBytes); err != nil {
ColorLog("[ERRO] Could not query INFORMATION_SCHEMA for column information\n")
os.Exit(2)
beeLogger.Log.Fatalf("Could not query INFORMATION_SCHEMA for column information: %s", err)
}
colName, dataType, columnType, isNullable, columnDefault, extra :=
string(colNameBytes), string(dataTypeBytes), string(columnTypeBytes), string(isNullableBytes), string(columnDefaultBytes), string(extraBytes)
// create a column
// Create a column
col := new(Column)
col.Name = camelCase(colName)
col.Type = postgresDB.GetGoDataType(dataType)
col.Name = utils.CamelCase(colName)
col.Type, err = postgresDB.GetGoDataType(dataType)
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
// Tag info
tag := new(OrmTag)
tag.Column = colName
@ -649,8 +666,8 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
if isFk && !isBl {
tag.RelFk = true
refStructName := fkCol.RefTable
col.Name = camelCase(colName)
col.Type = "*" + camelCase(refStructName)
col.Name = utils.CamelCase(colName)
col.Type = "*" + utils.CamelCase(refStructName)
} else {
// if the name of column is Id, and it's not primary key
if colName == "id" {
@ -690,13 +707,11 @@ func (postgresDB *PostgresDB) GetColumns(db *sql.DB, table *Table, blackList map
}
// GetGoDataType returns the Go type from the mapped Postgres type
func (*PostgresDB) GetGoDataType(sqlType string) (goType string) {
func (*PostgresDB) GetGoDataType(sqlType string) (string, error) {
if v, ok := typeMappingPostgres[sqlType]; ok {
return v
return v, nil
}
ColorLog("[ERRO] data type (%s) not found!\n", sqlType)
os.Exit(2)
return goType
return "", fmt.Errorf("data type '%s' not found", sqlType)
}
// deleteAndRecreatePaths removes several directories completely
@ -715,65 +730,60 @@ func createPaths(mode byte, paths *MvcPath) {
// writeSourceFiles generates source files for model/controller/router
// It will wipe the following directories and recreate them:./models, ./controllers, ./routers
// Newly geneated files will be inside these folders.
func writeSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
func writeSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath) {
if (OModel & mode) == OModel {
ColorLog("[INFO] Creating model files...\n")
writeModelFiles(tables, paths.ModelPath, selectedTables)
beeLogger.Log.Info("Creating model files...")
writeModelFiles(tables, paths.ModelPath)
}
if (OController & mode) == OController {
ColorLog("[INFO] Creating controller files...\n")
writeControllerFiles(tables, paths.ControllerPath, selectedTables, pkgPath)
beeLogger.Log.Info("Creating controller files...")
writeControllerFiles(tables, paths.ControllerPath, pkgPath)
}
if (ORouter & mode) == ORouter {
ColorLog("[INFO] Creating router files...\n")
writeRouterFile(tables, paths.RouterPath, selectedTables, pkgPath)
beeLogger.Log.Info("Creating router files...")
writeRouterFile(tables, paths.RouterPath, pkgPath)
}
}
// writeModelFiles generates model files
func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
w := NewColorWriter(os.Stdout)
func writeModelFiles(tables []*Table, mPath string) {
w := colors.NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
if _, selected := selectedTables[tb.Name]; !selected {
continue
}
}
filename := getFileName(tb.Name)
fpath := path.Join(mPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
continue
}
} else {
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
continue
}
}
template := ""
var template string
if tb.Pk == "" {
template = StructModelTPL
} else {
template = ModelTPL
}
fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{modelName}}", utils.CamelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{tableName}}", tb.Name, -1)
// if table contains time field, import time.Time package
// If table contains time field, import time.Time package
timePkg := ""
importTimePkg := ""
if tb.ImportTimePkg {
@ -783,26 +793,19 @@ func writeModelFiles(tables []*Table, mPath string, selectedTables map[string]bo
fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1)
fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1)
if _, err := f.WriteString(fileStr); err != nil {
ColorLog("[ERRO] Could not write model file to %s\n", fpath)
os.Exit(2)
beeLogger.Log.Fatalf("Could not write model file to '%s': %s", fpath, err)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
}
// writeControllerFiles generates controller files
func writeControllerFiles(tables []*Table, cPath string, selectedTables map[string]bool, pkgPath string) {
w := NewColorWriter(os.Stdout)
func writeControllerFiles(tables []*Table, cPath string, pkgPath string) {
w := colors.NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
if _, selected := selectedTables[tb.Name]; !selected {
continue
}
}
if tb.Pk == "" {
continue
}
@ -810,107 +813,81 @@ func writeControllerFiles(tables []*Table, cPath string, selectedTables map[stri
fpath := path.Join(cPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
continue
}
} else {
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
continue
}
}
fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", camelCase(tb.Name), -1)
fileStr := strings.Replace(CtrlTPL, "{{ctrlName}}", utils.CamelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{pkgPath}}", pkgPath, -1)
if _, err := f.WriteString(fileStr); err != nil {
ColorLog("[ERRO] Could not write controller file to %s\n", fpath)
os.Exit(2)
beeLogger.Log.Fatalf("Could not write controller file to '%s': %s", fpath, err)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
}
// writeRouterFile generates router file
func writeRouterFile(tables []*Table, rPath string, selectedTables map[string]bool, pkgPath string) {
w := NewColorWriter(os.Stdout)
func writeRouterFile(tables []*Table, rPath string, pkgPath string) {
w := colors.NewColorWriter(os.Stdout)
var nameSpaces []string
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
if selectedTables != nil {
if _, selected := selectedTables[tb.Name]; !selected {
continue
}
}
if tb.Pk == "" {
continue
}
// add namespaces
// Add namespaces
nameSpace := strings.Replace(NamespaceTPL, "{{nameSpace}}", tb.Name, -1)
nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", camelCase(tb.Name), -1)
nameSpace = strings.Replace(nameSpace, "{{ctrlName}}", utils.CamelCase(tb.Name), -1)
nameSpaces = append(nameSpaces, nameSpace)
}
// add export controller
fpath := path.Join(rPath, "router.go")
// Add export controller
fpath := filepath.Join(rPath, "router.go")
routerStr := strings.Replace(RouterTPL, "{{nameSpaces}}", strings.Join(nameSpaces, ""), 1)
routerStr = strings.Replace(routerStr, "{{pkgPath}}", pkgPath, 1)
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
return
}
} else {
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
return
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
return
}
}
if _, err := f.WriteString(routerStr); err != nil {
ColorLog("[ERRO] Could not write router file to '%s'\n", fpath)
os.Exit(2)
beeLogger.Log.Fatalf("Could not write router file to '%s': %s", fpath, err)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
}
// formatSourceCode formats source files
func formatSourceCode(filename string) {
cmd := exec.Command("gofmt", "-w", filename)
if err := cmd.Run(); err != nil {
ColorLog("[WARN] gofmt err: %s\n", err)
}
}
// camelCase converts a _ delimited string to camel case
// e.g. very_important_person => VeryImportantPerson
func camelCase(in string) string {
tokens := strings.Split(in, "_")
for i := range tokens {
tokens[i] = strings.Title(strings.Trim(tokens[i], " "))
}
return strings.Join(tokens, "")
utils.FormatSourceCode(fpath)
}
func isSQLTemporalType(t string) bool {
@ -948,9 +925,9 @@ func extractColSize(colType string) string {
}
func extractIntSignness(colType string) string {
regex := regexp.MustCompile(`(int|smallint|mediumint|bigint)\([0-9]+\)(.*)`)
regex := regexp.MustCompile(`(int|smallint|mediumint|bigint).*`)
signRegex := regex.FindStringSubmatch(colType)
return strings.Trim(signRegex[2], " ")
return strings.Trim(signRegex[1], " ")
}
func extractDecimal(colType string) (digits string, decimals string) {
@ -972,10 +949,39 @@ func getFileName(tbName string) (filename string) {
func getPackagePath(curpath string) (packpath string) {
gopath := os.Getenv("GOPATH")
Debugf("gopath:%s", gopath)
if gopath == "" {
ColorLog("[ERRO] You should set GOPATH in the env")
os.Exit(2)
info := "GOPATH environment variable is not set or empty"
gomodpath := filepath.Join(curpath, `go.mod`)
re, err := regexp.Compile(`^module\s+(.+)$`)
if err != nil {
beeLogger.Log.Error(info)
beeLogger.Log.Fatalf("try `go.mod` generate regexp error:%s", err)
return ""
}
fd, err := os.Open(gomodpath)
if err != nil {
beeLogger.Log.Error(info)
beeLogger.Log.Fatalf("try `go.mod` Error while reading 'go.mod',%s", gomodpath)
}
reader := bufio.NewReader(fd)
for {
byteLine, _, er := reader.ReadLine()
if er != nil && er != io.EOF {
return ""
}
if er == io.EOF {
break
}
line := string(byteLine)
s := re.FindStringSubmatch(line)
if len(s) >= 2 {
return s[1]
}
}
beeLogger.Log.Error(info)
beeLogger.Log.Fatalf("try `go.mod` Error while parse 'go.mod',%s", gomodpath)
} else {
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
}
appsrcpath := ""
@ -983,9 +989,8 @@ func getPackagePath(curpath string) (packpath string) {
wgopath := filepath.SplitList(gopath)
for _, wg := range wgopath {
wg, _ = filepath.EvalSymlinks(path.Join(wg, "src"))
if filepath.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src"))
if strings.HasPrefix(strings.ToLower(curpath), strings.ToLower(wg)) {
haspath = true
appsrcpath = wg
break
@ -993,13 +998,11 @@ func getPackagePath(curpath string) (packpath string) {
}
if !haspath {
ColorLog("[ERRO] Can't generate application code outside of GOPATH '%s'\n", gopath)
os.Exit(2)
beeLogger.Log.Fatalf("Cannot generate application code outside of GOPATH '%s' compare with CWD '%s'", gopath, curpath)
}
if curpath == appsrcpath {
ColorLog("[ERRO] Can't generate application code outside of application PATH \n")
os.Exit(2)
beeLogger.Log.Fatal("Cannot generate application code outside of application path")
}
packpath = strings.Join(strings.Split(curpath[len(appsrcpath)+1:], string(filepath.Separator)), "/")
@ -1020,7 +1023,7 @@ import (
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"
)
{{modelStruct}}
@ -1062,8 +1065,12 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri
for k, v := range query {
// rewrite dot-notation to Object__Attribute
k = strings.Replace(k, ".", "__", -1)
if strings.Contains(k, "isnull") {
qs = qs.Filter(k, (v == "true" || v == "1"))
} else {
qs = qs.Filter(k, v)
}
}
// order by:
var sortFields []string
if len(sortby) != 0 {
@ -1165,14 +1172,15 @@ import (
"strconv"
"strings"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// oprations for {{ctrlName}}
// {{ctrlName}}Controller operations for {{ctrlName}}
type {{ctrlName}}Controller struct {
beego.Controller
}
// URLMapping ...
func (c *{{ctrlName}}Controller) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
@ -1181,6 +1189,7 @@ func (c *{{ctrlName}}Controller) URLMapping() {
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Post
// @Description create {{ctrlName}}
// @Param body body models.{{ctrlName}} true "body for {{ctrlName}} content"
@ -1202,7 +1211,8 @@ func (c *{{ctrlName}}Controller) Post() {
c.ServeJSON()
}
// @Title Get
// GetOne ...
// @Title Get One
// @Description get {{ctrlName}} by id
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.{{ctrlName}}
@ -1220,6 +1230,7 @@ func (c *{{ctrlName}}Controller) GetOne() {
c.ServeJSON()
}
// GetAll ...
// @Title Get All
// @Description get {{ctrlName}}
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
@ -1235,9 +1246,9 @@ func (c *{{ctrlName}}Controller) GetAll() {
var fields []string
var sortby []string
var order []string
var query map[string]string = make(map[string]string)
var query = make(map[string]string)
var limit int64 = 10
var offset int64 = 0
var offset int64
// fields: col1,col2,entity.col3
if v := c.GetString("fields"); v != "" {
@ -1282,7 +1293,8 @@ func (c *{{ctrlName}}Controller) GetAll() {
c.ServeJSON()
}
// @Title Update
// Put ...
// @Title Put
// @Description update the {{ctrlName}}
// @Param id path string true "The id you want to update"
// @Param body body models.{{ctrlName}} true "body for {{ctrlName}} content"
@ -1305,6 +1317,7 @@ func (c *{{ctrlName}}Controller) Put() {
c.ServeJSON()
}
// Delete ...
// @Title Delete
// @Description delete the {{ctrlName}}
// @Param id path string true "The id you want to delete"
@ -1334,7 +1347,7 @@ package routers
import (
"{{pkgPath}}/controllers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func init() {

View File

@ -12,20 +12,21 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"fmt"
"os"
"path"
"strings"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
// article
// cms/article
//
func generateController(cname, currpath string) {
w := NewColorWriter(os.Stdout)
func GenerateController(cname, currpath string) {
w := colors.NewColorWriter(os.Stdout)
p, f := path.Split(cname)
controllerName := strings.Title(f)
@ -36,27 +37,26 @@ func generateController(cname, currpath string) {
packageName = p[i+1 : len(p)-1]
}
ColorLog("[INFO] Using '%s' as controller name\n", controllerName)
ColorLog("[INFO] Using '%s' as package name\n", packageName)
beeLogger.Log.Infof("Using '%s' as controller name", controllerName)
beeLogger.Log.Infof("Using '%s' as package name", packageName)
fp := path.Join(currpath, "controllers", p)
if _, err := os.Stat(fp); os.IsNotExist(err) {
// Create the controller's directory
if err := os.MkdirAll(fp, 0777); err != nil {
ColorLog("[ERRO] Could not create controllers directory: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create controllers directory: %s", err)
}
}
fpath := path.Join(fp, strings.ToLower(controllerName)+".go")
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
modelPath := path.Join(currpath, "models", strings.ToLower(controllerName)+".go")
var content string
if _, err := os.Stat(modelPath); err == nil {
ColorLog("[INFO] Using matching model '%s'\n", controllerName)
beeLogger.Log.Infof("Using matching model '%s'", controllerName)
content = strings.Replace(controllerModelTpl, "{{packageName}}", packageName, -1)
pkgPath := getPackagePath(currpath)
content = strings.Replace(content, "{{pkgPath}}", pkgPath, -1)
@ -68,25 +68,25 @@ func generateController(cname, currpath string) {
f.WriteString(content)
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create controller file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create controller file: %s", err)
}
}
var controllerTpl = `package {{packageName}}
import (
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// operations for {{controllerName}}
// {{controllerName}}Controller operations for {{controllerName}}
type {{controllerName}}Controller struct {
beego.Controller
}
// URLMapping ...
func (c *{{controllerName}}Controller) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
@ -95,6 +95,7 @@ func (c *{{controllerName}}Controller) URLMapping() {
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Create
// @Description create {{controllerName}}
// @Param body body models.{{controllerName}} true "body for {{controllerName}} content"
@ -105,6 +106,7 @@ func (c *{{controllerName}}Controller) Post() {
}
// GetOne ...
// @Title GetOne
// @Description get {{controllerName}} by id
// @Param id path string true "The key for staticblock"
@ -115,6 +117,7 @@ func (c *{{controllerName}}Controller) GetOne() {
}
// GetAll ...
// @Title GetAll
// @Description get {{controllerName}}
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
@ -130,7 +133,8 @@ func (c *{{controllerName}}Controller) GetAll() {
}
// @Title Update
// Put ...
// @Title Put
// @Description update the {{controllerName}}
// @Param id path string true "The id you want to update"
// @Param body body models.{{controllerName}} true "body for {{controllerName}} content"
@ -141,6 +145,7 @@ func (c *{{controllerName}}Controller) Put() {
}
// Delete ...
// @Title Delete
// @Description delete the {{controllerName}}
// @Param id path string true "The id you want to delete"
@ -161,14 +166,15 @@ import (
"strconv"
"strings"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// oprations for {{controllerName}}
// {{controllerName}}Controller operations for {{controllerName}}
type {{controllerName}}Controller struct {
beego.Controller
}
// URLMapping ...
func (c *{{controllerName}}Controller) URLMapping() {
c.Mapping("Post", c.Post)
c.Mapping("GetOne", c.GetOne)
@ -177,6 +183,7 @@ func (c *{{controllerName}}Controller) URLMapping() {
c.Mapping("Delete", c.Delete)
}
// Post ...
// @Title Post
// @Description create {{controllerName}}
// @Param body body models.{{controllerName}} true "body for {{controllerName}} content"
@ -195,7 +202,8 @@ func (c *{{controllerName}}Controller) Post() {
c.ServeJSON()
}
// @Title Get
// GetOne ...
// @Title Get One
// @Description get {{controllerName}} by id
// @Param id path string true "The key for staticblock"
// @Success 200 {object} models.{{controllerName}}
@ -213,6 +221,7 @@ func (c *{{controllerName}}Controller) GetOne() {
c.ServeJSON()
}
// GetAll ...
// @Title Get All
// @Description get {{controllerName}}
// @Param query query string false "Filter. e.g. col1:v1,col2:v2 ..."
@ -228,9 +237,9 @@ func (c *{{controllerName}}Controller) GetAll() {
var fields []string
var sortby []string
var order []string
var query map[string]string = make(map[string]string)
var query = make(map[string]string)
var limit int64 = 10
var offset int64 = 0
var offset int64
// fields: col1,col2,entity.col3
if v := c.GetString("fields"); v != "" {
@ -275,7 +284,8 @@ func (c *{{controllerName}}Controller) GetAll() {
c.ServeJSON()
}
// @Title Update
// Put ...
// @Title Put
// @Description update the {{controllerName}}
// @Param id path string true "The id you want to update"
// @Param body body models.{{controllerName}} true "body for {{controllerName}} content"
@ -295,6 +305,7 @@ func (c *{{controllerName}}Controller) Put() {
c.ServeJSON()
}
// Delete ...
// @Title Delete
// @Description delete the {{controllerName}}
// @Param id path string true "The id you want to delete"

View File

@ -15,7 +15,7 @@
* *
\**********************************************************/
package main
package generate
import (
"database/sql"
@ -24,11 +24,256 @@ import (
"path"
"strings"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
)
func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
var Hproseconf = `appname = {{.Appname}}
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
`
var HproseMaingo = `package main
import (
"fmt"
"reflect"
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
beego "github.com/beego/beego/v2/server/web"
)
func logInvokeHandler(
name string,
args []reflect.Value,
context rpc.Context,
next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
fmt.Printf("%s(%v) = ", name, args)
results, err = next(name, args, context)
fmt.Printf("%v %v\r\n", results, err)
return
}
func main() {
// Create WebSocketServer
// service := rpc.NewWebSocketService()
// Create Http Server
service := rpc.NewHTTPService()
// Use Logger Middleware
service.AddInvokeHandler(logInvokeHandler)
// Publish Functions
service.AddFunction("AddOne", models.AddOne)
service.AddFunction("GetOne", models.GetOne)
// Start Service
beego.Handler("/", service)
beego.Run()
}
`
var HproseMainconngo = `package main
import (
"fmt"
"reflect"
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/client/orm"
{{.DriverPkg}}
)
func init() {
orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}")
}
func logInvokeHandler(
name string,
args []reflect.Value,
context rpc.Context,
next rpc.NextInvokeHandler) (results []reflect.Value, err error) {
fmt.Printf("%s(%v) = ", name, args)
results, err = next(name, args, context)
fmt.Printf("%v %v\r\n", results, err)
return
}
func main() {
// Create WebSocketServer
// service := rpc.NewWebSocketService()
// Create Http Server
service := rpc.NewHTTPService()
// Use Logger Middleware
service.AddInvokeHandler(logInvokeHandler)
{{HproseFunctionList}}
// Start Service
beego.Handler("/", service)
beego.Run()
}
`
var HproseModels = `package models
import (
"errors"
"strconv"
"time"
)
var (
Objects map[string]*Object
)
type Object struct {
ObjectId string
Score int64
PlayerName string
}
func init() {
Objects = make(map[string]*Object)
Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"}
Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"}
}
func AddOne(object Object) (ObjectId string) {
object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10)
Objects[object.ObjectId] = &object
return object.ObjectId
}
func GetOne(ObjectId string) (object *Object, err error) {
if v, ok := Objects[ObjectId]; ok {
return v, nil
}
return nil, errors.New("ObjectId Not Exist")
}
func GetAll() map[string]*Object {
return Objects
}
func Update(ObjectId string, Score int64) (err error) {
if v, ok := Objects[ObjectId]; ok {
v.Score = Score
return nil
}
return errors.New("ObjectId Not Exist")
}
func Delete(ObjectId string) {
delete(Objects, ObjectId)
}
`
var HproseModels2 = `package models
import (
"errors"
"strconv"
"time"
)
var (
UserList map[string]*User
)
func init() {
UserList = make(map[string]*User)
u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}}
UserList["user_11111"] = &u
}
type User struct {
Id string
Username string
Password string
Profile Profile
}
type Profile struct {
Gender string
Age int
Address string
Email string
}
func AddUser(u User) string {
u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10)
UserList[u.Id] = &u
return u.Id
}
func GetUser(uid string) (u *User, err error) {
if u, ok := UserList[uid]; ok {
return u, nil
}
return nil, errors.New("User not exists")
}
func GetAllUsers() map[string]*User {
return UserList
}
func UpdateUser(uid string, uu *User) (a *User, err error) {
if u, ok := UserList[uid]; ok {
if uu.Username != "" {
u.Username = uu.Username
}
if uu.Password != "" {
u.Password = uu.Password
}
if uu.Profile.Age != 0 {
u.Profile.Age = uu.Profile.Age
}
if uu.Profile.Address != "" {
u.Profile.Address = uu.Profile.Address
}
if uu.Profile.Gender != "" {
u.Profile.Gender = uu.Profile.Gender
}
if uu.Profile.Email != "" {
u.Profile.Email = uu.Profile.Email
}
return u, nil
}
return nil, errors.New("User Not Exist")
}
func Login(username, password string) bool {
for _, u := range UserList {
if u.Username == username && u.Password == password {
return true
}
}
return false
}
func DeleteUser(uid string) {
delete(UserList, uid)
}
`
var HproseAddFunctions = []string{}
func GenerateHproseAppcode(driver, connStr, level, tables, currpath string) {
var mode byte
switch level {
case "1":
@ -38,9 +283,7 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
case "3":
mode = OModel | OController | ORouter
default:
ColorLog("[ERRO] Invalid 'level' option: %s\n", level)
ColorLog("[HINT] Level must be either 1, 2 or 3\n")
os.Exit(2)
beeLogger.Log.Fatal("Invalid 'level' option. Level must be either \"1\", \"2\" or \"3\"")
}
var selectedTables map[string]bool
if tables != "" {
@ -53,12 +296,9 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
case "mysql":
case "postgres":
case "sqlite":
ColorLog("[ERRO] Generating app code from SQLite database is not supported yet.\n")
os.Exit(2)
beeLogger.Log.Fatal("Generating app code from SQLite database is not supported yet")
default:
ColorLog("[ERRO] Unknown database driver: %s\n", driver)
ColorLog("[HINT] Driver must be one of mysql, postgres or sqlite\n")
os.Exit(2)
beeLogger.Log.Fatalf("Unknown database driver '%s'. Driver must be one of mysql, postgres or sqlite", driver)
}
genHprose(driver, connStr, mode, selectedTables, currpath)
}
@ -68,12 +308,11 @@ func generateHproseAppcode(driver, connStr, level, tables, currpath string) {
func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bool, currpath string) {
db, err := sql.Open(dbms, connStr)
if err != nil {
ColorLog("[ERRO] Could not connect to %s database: %s, %s\n", dbms, connStr, err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", dbms, connStr, err)
}
defer db.Close()
if trans, ok := dbDriver[dbms]; ok {
ColorLog("[INFO] Analyzing database tables...\n")
beeLogger.Log.Info("Analyzing database tables...")
tableNames := trans.GetTableNames(db)
tables := getTableObjects(tableNames, db, trans)
mvcPath := new(MvcPath)
@ -82,8 +321,7 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo
pkgPath := getPackagePath(currpath)
writeHproseSourceFiles(pkgPath, tables, mode, mvcPath, selectedTableNames)
} else {
ColorLog("[ERRO] Generating app code from %s database is not supported yet.\n", dbms)
os.Exit(2)
beeLogger.Log.Fatalf("Generating app code from '%s' database is not supported yet", dbms)
}
}
@ -92,14 +330,14 @@ func genHprose(dbms, connStr string, mode byte, selectedTableNames map[string]bo
// Newly geneated files will be inside these folders.
func writeHproseSourceFiles(pkgPath string, tables []*Table, mode byte, paths *MvcPath, selectedTables map[string]bool) {
if (OModel & mode) == OModel {
ColorLog("[INFO] Creating model files...\n")
beeLogger.Log.Info("Creating model files...")
writeHproseModelFiles(tables, paths.ModelPath, selectedTables)
}
}
// writeHproseModelFiles generates model files
func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[string]bool) {
w := NewColorWriter(os.Stdout)
w := colors.NewColorWriter(os.Stdout)
for _, tb := range tables {
// if selectedTables map is not nil and this table is not selected, ignore it
@ -112,34 +350,34 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
fpath := path.Join(mPath, filename+".go")
var f *os.File
var err error
if isExist(fpath) {
ColorLog("[WARN] '%v' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if askForConfirmation() {
if utils.IsExist(fpath) {
beeLogger.Log.Warnf("'%s' already exists. Do you want to overwrite it? [Yes|No] ", fpath)
if utils.AskForConfirmation() {
f, err = os.OpenFile(fpath, os.O_RDWR|os.O_TRUNC, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
continue
}
} else {
ColorLog("[WARN] Skipped create file '%s'\n", fpath)
beeLogger.Log.Warnf("Skipped create file '%s'", fpath)
continue
}
} else {
f, err = os.OpenFile(fpath, os.O_CREATE|os.O_RDWR, 0666)
if err != nil {
ColorLog("[WARN] %v\n", err)
beeLogger.Log.Warnf("%s", err)
continue
}
}
template := ""
var template string
if tb.Pk == "" {
template = HproseStructModelTPL
} else {
template = HproseModelTPL
hproseAddFunctions = append(hproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", camelCase(tb.Name), -1))
HproseAddFunctions = append(HproseAddFunctions, strings.Replace(HproseAddFunction, "{{modelName}}", utils.CamelCase(tb.Name), -1))
}
fileStr := strings.Replace(template, "{{modelStruct}}", tb.String(), 1)
fileStr = strings.Replace(fileStr, "{{modelName}}", camelCase(tb.Name), -1)
fileStr = strings.Replace(fileStr, "{{modelName}}", utils.CamelCase(tb.Name), -1)
// if table contains time field, import time.Time package
timePkg := ""
importTimePkg := ""
@ -150,12 +388,11 @@ func writeHproseModelFiles(tables []*Table, mPath string, selectedTables map[str
fileStr = strings.Replace(fileStr, "{{timePkg}}", timePkg, -1)
fileStr = strings.Replace(fileStr, "{{importTimePkg}}", importTimePkg, -1)
if _, err := f.WriteString(fileStr); err != nil {
ColorLog("[ERRO] Could not write model file to '%s'\n", fpath)
os.Exit(2)
beeLogger.Log.Fatalf("Could not write model file to '%s'", fpath)
}
CloseFile(f)
utils.CloseFile(f)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
}
}
@ -182,7 +419,7 @@ import (
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"
)
{{modelStruct}}

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"fmt"
@ -20,6 +20,10 @@ import (
"path"
"strings"
"time"
"github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
const (
@ -29,18 +33,18 @@ const (
)
type DBDriver interface {
generateCreateUp(tableName string) string
generateCreateDown(tableName string) string
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()) + `)");`
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 {
func (m mysqlDriver) GenerateCreateDown(tableName string) string {
downsql := `m.SQL("DROP TABLE ` + "`" + tableName + "`" + `")`
return downsql
}
@ -51,21 +55,21 @@ func (m mysqlDriver) generateSQLFromFields(fields string) string {
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")
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
typ, tag := m.getSQLType(kv[1])
if typ == "" {
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
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 + ","
sql += "`" + utils.SnakeString(kv[0]) + "` " + typ + ","
if tag != "" {
tags = tags + fmt.Sprintf(tag, "`"+snakeString(kv[0])+"`") + ","
tags = tags + fmt.Sprintf(tag, "`"+utils.SnakeString(kv[0])+"`") + ","
}
}
sql = strings.TrimRight(sql+tags, ",")
@ -104,12 +108,12 @@ func (m mysqlDriver) getSQLType(ktype string) (tp, tag string) {
type postgresqlDriver struct{}
func (m postgresqlDriver) generateCreateUp(tableName string) string {
upsql := `m.SQL("CREATE TABLE ` + tableName + "(" + m.generateSQLFromFields(fields.String()) + `)");`
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 {
func (m postgresqlDriver) GenerateCreateDown(tableName string) string {
downsql := `m.SQL("DROP TABLE ` + tableName + `")`
return downsql
}
@ -120,20 +124,20 @@ func (m postgresqlDriver) generateSQLFromFields(fields string) string {
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")
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
typ, tag := m.getSQLType(kv[1])
if typ == "" {
ColorLog("[ERRO] Fields format is wrong. Should be: key:type,key:type " + v + "\n")
beeLogger.Log.Error("Fields format is wrong. Should be: key:type,key:type " + v)
return ""
}
if i == 0 && strings.ToLower(kv[0]) != "id" {
sql += "id interger serial primary key,"
sql += "id serial primary key,"
}
sql += snakeString(kv[0]) + " " + typ + ","
sql += utils.SnakeString(kv[0]) + " " + typ + ","
if tag != "" {
tags = tags + fmt.Sprintf(tag, snakeString(kv[0])) + ","
tags = tags + fmt.Sprintf(tag, utils.SnakeString(kv[0])) + ","
}
}
if tags != "" {
@ -170,76 +174,117 @@ func (m postgresqlDriver) getSQLType(ktype string) (tp, tag string) {
return "", ""
}
func newDBDriver() DBDriver {
switch driver {
func NewDBDriver() DBDriver {
switch SQLDriver {
case "mysql":
return mysqlDriver{}
case "postgres":
return postgresqlDriver{}
default:
panic("driver not supported")
beeLogger.Log.Fatal("Driver not supported")
return nil
}
}
// generateMigration generates migration file template for database schema update.
// The generated file template consists of an up() method for updating schema and
// a down() method for reverting the update.
func generateMigration(mname, upsql, downsql, curpath string) {
w := NewColorWriter(os.Stdout)
func GenerateMigration(mname, upsql, downsql, curpath string) {
w := colors.NewColorWriter(os.Stdout)
migrationFilePath := path.Join(curpath, DBPath, MPath)
if _, err := os.Stat(migrationFilePath); os.IsNotExist(err) {
// create migrations directory
if err := os.MkdirAll(migrationFilePath, 0777); err != nil {
ColorLog("[ERRO] Could not create migration directory: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create migration directory: %s", err)
}
}
// create file
today := time.Now().Format(MDateFormat)
fpath := path.Join(migrationFilePath, fmt.Sprintf("%s_%s.go", today, mname))
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
content := strings.Replace(MigrationTPL, "{{StructName}}", camelCase(mname)+"_"+today, -1)
content = strings.Replace(content, "{{CurrTime}}", today, -1)
content = strings.Replace(content, "{{UpSQL}}", upsql, -1)
content = strings.Replace(content, "{{DownSQL}}", downsql, -1)
f.WriteString(content)
defer utils.CloseFile(f)
ddlSpec := ""
spec := ""
up := ""
down := ""
if DDL != "" {
ddlSpec = "m.ddlSpec()"
switch strings.Title(DDL.String()) {
case "Create":
spec = strings.Replace(DDLSpecCreate, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
case "Alter":
spec = strings.Replace(DDLSpecAlter, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
}
spec = strings.Replace(spec, "{{tableName}}", mname, -1)
} else {
up = strings.Replace(MigrationUp, "{{UpSQL}}", upsql, -1)
up = strings.Replace(up, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
down = strings.Replace(MigrationDown, "{{DownSQL}}", downsql, -1)
down = strings.Replace(down, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
}
header := strings.Replace(MigrationHeader, "{{StructName}}", utils.CamelCase(mname)+"_"+today, -1)
header = strings.Replace(header, "{{ddlSpec}}", ddlSpec, -1)
header = strings.Replace(header, "{{CurrTime}}", today, -1)
f.WriteString(header + spec + up + down)
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create migration file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create migration file: %s", err)
}
}
const MigrationTPL = `package main
const (
MigrationHeader = `package main
import (
"github.com/beego/beego/v2/client/orm/migration"
)
import (
"github.com/astaxie/beego/migration"
)
// DO NOT MODIFY
type {{StructName}} struct {
// DO NOT MODIFY
type {{StructName}} struct {
migration.Migration
}
}
// DO NOT MODIFY
func init() {
// DO NOT MODIFY
func init() {
m := &{{StructName}}{}
m.Created = "{{CurrTime}}"
{{ddlSpec}}
migration.Register("{{StructName}}", m)
}
}
`
// Run the migrations
func (m *{{StructName}}) Up() {
DDLSpecCreate = `
/*
refer beego/migration/doc.go
*/
func(m *{{StructName}}) ddlSpec(){
m.CreateTable("{{tableName}}", "InnoDB", "utf8")
m.PriCol("id").SetAuto(true).SetNullable(false).SetDataType("INT(10)").SetUnsigned(true)
}
`
DDLSpecAlter = `
/*
refer beego/migration/doc.go
*/
func(m *{{StructName}}) ddlSpec(){
m.AlterTable("{{tableName}}")
}
`
MigrationUp = `
// Run the migrations
func (m *{{StructName}}) Up() {
// use m.SQL("CREATE TABLE ...") to make schema update
{{UpSQL}}
}
// Reverse the migrations
func (m *{{StructName}}) Down() {
}`
MigrationDown = `
// Reverse the migrations
func (m *{{StructName}}) Down() {
// use m.SQL("DROP TABLE ...") to reverse schema update
{{DownSQL}}
}
`
}
`
)

View File

@ -12,7 +12,7 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"errors"
@ -20,10 +20,14 @@ import (
"os"
"path"
"strings"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
func generateModel(mname, fields, currpath string) {
w := NewColorWriter(os.Stdout)
func GenerateModel(mname, fields, currpath string) {
w := colors.NewColorWriter(os.Stdout)
p, f := path.Split(mname)
modelName := strings.Title(f)
@ -35,25 +39,23 @@ func generateModel(mname, fields, currpath string) {
modelStruct, hastime, err := getStruct(modelName, fields)
if err != nil {
ColorLog("[ERRO] Could not generate the model struct: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not generate the model struct: %s", err)
}
ColorLog("[INFO] Using '%s' as model name\n", modelName)
ColorLog("[INFO] Using '%s' as package name\n", packageName)
beeLogger.Log.Infof("Using '%s' as model name", modelName)
beeLogger.Log.Infof("Using '%s' as package name", packageName)
fp := path.Join(currpath, "models", p)
if _, err := os.Stat(fp); os.IsNotExist(err) {
// Create the model's directory
if err := os.MkdirAll(fp, 0777); err != nil {
ColorLog("[ERRO] Could not create the model directory: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create the model directory: %s", err)
}
}
fpath := path.Join(fp, strings.ToLower(modelName)+".go")
if f, err := os.OpenFile(fpath, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
content := strings.Replace(modelTpl, "{{packageName}}", packageName, -1)
content = strings.Replace(content, "{{modelName}}", modelName, -1)
content = strings.Replace(content, "{{modelStruct}}", modelStruct, -1)
@ -64,11 +66,10 @@ func generateModel(mname, fields, currpath string) {
}
f.WriteString(content)
// Run 'gofmt' on the generated source code
formatSourceCode(fpath)
utils.FormatSourceCode(fpath)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", fpath, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create model file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create model file: %s", err)
}
}
@ -98,7 +99,7 @@ func getStruct(structname, fields string) (string, bool, error) {
if hastimeinner {
hastime = true
}
structStr = structStr + camelString(kv[0]) + " " + typ + " " + tag + "\n"
structStr = structStr + utils.CamelString(kv[0]) + " " + typ + " " + tag + "\n"
}
structStr += "}\n"
return structStr, hastime, nil
@ -144,7 +145,7 @@ import (
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"
)
{{modelStruct}}
@ -166,7 +167,7 @@ func Add{{modelName}}(m *{{modelName}}) (id int64, err error) {
func Get{{modelName}}ById(id int64) (v *{{modelName}}, err error) {
o := orm.NewOrm()
v = &{{modelName}}{Id: id}
if err = o.Read(v); err == nil {
if err = o.QueryTable(new({{modelName}})).Filter("Id", id).RelatedSel().One(v); err == nil {
return v, nil
}
return nil, err
@ -224,7 +225,7 @@ func GetAll{{modelName}}(query map[string]string, fields []string, sortby []stri
}
var l []{{modelName}}
qs = qs.OrderBy(sortFields...)
qs = qs.OrderBy(sortFields...).RelatedSel()
if _, err = qs.Limit(limit, offset).All(&l, fields...); err == nil {
if len(fields) == 0 {
for _, v := range l {

50
generate/g_scaffold.go Normal file
View File

@ -0,0 +1,50 @@
package generate
import (
"strings"
"github.com/beego/bee/v2/cmd/commands/migrate"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
func GenerateScaffold(sname, fields, currpath, driver, conn string) {
beeLogger.Log.Infof("Do you want to create a '%s' model? [Yes|No] ", sname)
// Generate the model
if utils.AskForConfirmation() {
GenerateModel(sname, fields, currpath)
}
// Generate the controller
beeLogger.Log.Infof("Do you want to create a '%s' controller? [Yes|No] ", sname)
if utils.AskForConfirmation() {
GenerateController(sname, currpath)
}
// Generate the views
beeLogger.Log.Infof("Do you want to create views for this '%s' resource? [Yes|No] ", sname)
if utils.AskForConfirmation() {
GenerateView(sname, currpath)
}
// Generate a migration
beeLogger.Log.Infof("Do you want to create a '%s' migration and schema for this resource? [Yes|No] ", sname)
if utils.AskForConfirmation() {
upsql := ""
downsql := ""
if fields != "" {
dbMigrator := NewDBDriver()
upsql = dbMigrator.GenerateCreateUp(sname)
downsql = dbMigrator.GenerateCreateDown(sname)
}
GenerateMigration(sname, upsql, downsql, currpath)
}
// Run the migration
beeLogger.Log.Infof("Do you want to migrate the database? [Yes|No] ")
if utils.AskForConfirmation() {
migrate.MigrateUpdate(currpath, driver, conn, "")
}
beeLogger.Log.Successf("All done! Don't forget to add beego.Router(\"/%s\" ,&controllers.%sController{}) to routers/route.go\n", sname, strings.Title(sname))
}

View File

@ -12,65 +12,64 @@
// License for the specific language governing permissions and limitations
// under the License.
package main
package generate
import (
"fmt"
"os"
"path"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
// recipe
// admin/recipe
func generateView(viewpath, currpath string) {
w := NewColorWriter(os.Stdout)
func GenerateView(viewpath, currpath string) {
w := colors.NewColorWriter(os.Stdout)
ColorLog("[INFO] Generating view...\n")
beeLogger.Log.Info("Generating view...")
absViewPath := path.Join(currpath, "views", viewpath)
err := os.MkdirAll(absViewPath, os.ModePerm)
if err != nil {
ColorLog("[ERRO] Could not create '%s' view: %s\n", viewpath, err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create '%s' view: %s", viewpath, err)
}
cfile := path.Join(absViewPath, "index.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
cfile = path.Join(absViewPath, "show.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
cfile = path.Join(absViewPath, "create.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
cfile = path.Join(absViewPath, "edit.tpl")
if f, err := os.OpenFile(cfile, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666); err == nil {
defer CloseFile(f)
defer utils.CloseFile(f)
f.WriteString(cfile)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", cfile, "\x1b[0m")
} else {
ColorLog("[ERRO] Could not create view file: %s\n", err)
os.Exit(2)
beeLogger.Log.Fatalf("Could not create view file: %s", err)
}
}

549
generate/gen_routes.go Normal file
View File

@ -0,0 +1,549 @@
// Copyright 2014 beego Author. All Rights Reserved.
//
// 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.
package generate
import (
"errors"
"fmt"
"go/ast"
"os"
"path/filepath"
"regexp"
"sort"
"strconv"
"strings"
"unicode"
"github.com/beego/beego/v2/server/web"
"golang.org/x/tools/go/packages"
"github.com/beego/beego/v2/core/logs"
"github.com/beego/beego/v2/server/web/context/param"
beeLogger "github.com/beego/bee/v2/logger"
)
var globalRouterTemplate = `package {{.routersDir}}
import (
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/server/web/context/param"{{.globalimport}}
)
func init() {
{{.globalinfo}}
}
`
var (
genInfoList map[string][]web.ControllerComments
routerHooks = map[string]int{
"beego.BeforeStatic": web.BeforeStatic,
"beego.BeforeRouter": web.BeforeRouter,
"beego.BeforeExec": web.BeforeExec,
"beego.AfterExec": web.AfterExec,
"beego.FinishRouter": web.FinishRouter,
}
routerHooksMapping = map[int]string{
web.BeforeStatic: "beego.BeforeStatic",
web.BeforeRouter: "beego.BeforeRouter",
web.BeforeExec: "beego.BeforeExec",
web.AfterExec: "beego.AfterExec",
web.FinishRouter: "beego.FinishRouter",
}
)
func GenRouters() {
ctrlPath := ControllerDirectory.String()
if len(ctrlPath) == 0 {
ctrlPath = "controllers"
}
routersPath := RoutersFile.String()
if len(routersPath) == 0 {
routersPath = "routers/commentsRouter.go"
}
genRouters(ctrlPath, routersPath)
}
func genRouters(ctrlPath string, routersPath string) {
beeLogger.Log.Infof("read controller info from directory[%s], and output routers to [%s]", ctrlPath, routersPath)
err := parserPkg(ctrlPath, routersPath)
if err != nil {
beeLogger.Log.Errorf("Could not generate routers. Please check your input: %+v", err)
}
}
func parserPkg(ctrlPath string, routersPath string) error {
genInfoList = make(map[string][]web.ControllerComments)
pkgs, err := packages.Load(&packages.Config{
Mode: packages.NeedName | packages.NeedFiles | packages.NeedCompiledGoFiles | packages.NeedSyntax,
Dir: ctrlPath,
}, "./...")
if err != nil {
return err
}
for _, pkg := range pkgs {
for _, fl := range pkg.Syntax {
for _, d := range fl.Decls {
switch specDecl := d.(type) {
case *ast.FuncDecl:
if specDecl.Recv != nil {
exp, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr) // Check that the type is correct first beforing throwing to parser
if ok {
err = parserComments(specDecl, fmt.Sprint(exp.X), pkg.PkgPath)
if err != nil {
return err
}
}
}
}
}
}
}
return genRouterCode(routersPath)
}
type parsedComment struct {
routerPath string
methods []string
params map[string]parsedParam
filters []parsedFilter
imports []parsedImport
}
type parsedImport struct {
importPath string
importAlias string
}
type parsedFilter struct {
pattern string
pos int
filter string
params []bool
}
type parsedParam struct {
name string
datatype string
location string
defValue string
required bool
}
func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
if f.Doc != nil {
parsedComments, err := parseComment(f.Doc.List)
if err != nil {
return err
}
for _, parsedComment := range parsedComments {
if parsedComment.routerPath != "" {
key := pkgpath + ":" + controllerName
cc := web.ControllerComments{}
cc.Method = f.Name.String()
cc.Router = parsedComment.routerPath
cc.AllowHTTPMethods = parsedComment.methods
cc.MethodParams = buildMethodParams(f.Type.Params.List, parsedComment)
cc.FilterComments = buildFilters(parsedComment.filters)
cc.ImportComments = buildImports(parsedComment.imports)
genInfoList[key] = append(genInfoList[key], cc)
}
}
}
return nil
}
func buildImports(pis []parsedImport) []*web.ControllerImportComments {
var importComments []*web.ControllerImportComments
for _, pi := range pis {
importComments = append(importComments, &web.ControllerImportComments{
ImportPath: pi.importPath,
ImportAlias: pi.importAlias,
})
}
return importComments
}
func buildFilters(pfs []parsedFilter) []*web.ControllerFilterComments {
var filterComments []*web.ControllerFilterComments
for _, pf := range pfs {
var (
returnOnOutput bool
resetParams bool
)
if len(pf.params) >= 1 {
returnOnOutput = pf.params[0]
}
if len(pf.params) >= 2 {
resetParams = pf.params[1]
}
filterComments = append(filterComments, &web.ControllerFilterComments{
Filter: pf.filter,
Pattern: pf.pattern,
Pos: pf.pos,
ReturnOnOutput: returnOnOutput,
ResetParams: resetParams,
})
}
return filterComments
}
func buildMethodParams(funcParams []*ast.Field, pc *parsedComment) []*param.MethodParam {
result := make([]*param.MethodParam, 0, len(funcParams))
for _, fparam := range funcParams {
for _, pName := range fparam.Names {
methodParam := buildMethodParam(fparam, pName.Name, pc)
result = append(result, methodParam)
}
}
return result
}
func buildMethodParam(fparam *ast.Field, name string, pc *parsedComment) *param.MethodParam {
options := []param.MethodParamOption{}
if cparam, ok := pc.params[name]; ok {
// Build param from comment info
name = cparam.name
if cparam.required {
options = append(options, param.IsRequired)
}
switch cparam.location {
case "body":
options = append(options, param.InBody)
case "header":
options = append(options, param.InHeader)
case "path":
options = append(options, param.InPath)
}
if cparam.defValue != "" {
options = append(options, param.Default(cparam.defValue))
}
} else {
if paramInPath(name, pc.routerPath) {
options = append(options, param.InPath)
}
}
return param.New(name, options...)
}
func paramInPath(name, route string) bool {
return strings.HasSuffix(route, ":"+name) ||
strings.Contains(route, ":"+name+"/")
}
var routeRegex = regexp.MustCompile(`@router\s+(\S+)(?:\s+\[(\S+)\])?`)
func parseComment(lines []*ast.Comment) (pcs []*parsedComment, err error) {
pcs = []*parsedComment{}
params := map[string]parsedParam{}
filters := []parsedFilter{}
imports := []parsedImport{}
const doubleSlash = "/"
for _, c := range lines {
t := strings.TrimSpace(strings.TrimLeft(c.Text, doubleSlash))
const paramPrefix = "@Param"
if strings.HasPrefix(t, paramPrefix) {
pv := getparams(strings.TrimSpace(strings.TrimPrefix(t, paramPrefix)))
if len(pv) < 4 {
logs.Error("Invalid @Param format. Needs at least 4 parameters")
}
p := parsedParam{}
names := strings.SplitN(pv[0], "=>", 2)
p.name = names[0]
funcParamName := p.name
if len(names) > 1 {
funcParamName = names[1]
}
p.location = pv[1]
p.datatype = pv[2]
switch len(pv) {
case 5:
p.required, _ = strconv.ParseBool(pv[3])
case 6:
p.defValue = pv[3]
p.required, _ = strconv.ParseBool(pv[4])
}
params[funcParamName] = p
}
}
for _, c := range lines {
t := strings.TrimSpace(strings.TrimLeft(c.Text, doubleSlash))
if strings.HasPrefix(t, "@Import") {
iv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Import")))
if len(iv) == 0 || len(iv) > 2 {
logs.Error("Invalid @Import format. Only accepts 1 or 2 parameters")
continue
}
p := parsedImport{}
p.importPath = iv[0]
if len(iv) == 2 {
p.importAlias = iv[1]
}
imports = append(imports, p)
}
}
filterLoop:
for _, c := range lines {
t := strings.TrimSpace(strings.TrimLeft(c.Text, doubleSlash))
if strings.HasPrefix(t, "@Filter") {
fv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Filter")))
if len(fv) < 3 {
logs.Error("Invalid @Filter format. Needs at least 3 parameters")
continue filterLoop
}
p := parsedFilter{}
p.pattern = fv[0]
posName := fv[1]
if pos, exists := routerHooks[posName]; exists {
p.pos = pos
} else {
logs.Error("Invalid @Filter pos: ", posName)
continue filterLoop
}
p.filter = fv[2]
fvParams := fv[3:]
for _, fvParam := range fvParams {
switch fvParam {
case "true":
p.params = append(p.params, true)
case "false":
p.params = append(p.params, false)
default:
logs.Error("Invalid @Filter param: ", fvParam)
continue filterLoop
}
}
filters = append(filters, p)
}
}
for _, c := range lines {
var pc = &parsedComment{}
pc.params = params
pc.filters = filters
pc.imports = imports
t := strings.TrimSpace(strings.TrimLeft(c.Text, doubleSlash))
if strings.HasPrefix(t, "@router") {
t := strings.TrimSpace(strings.TrimLeft(c.Text, doubleSlash))
matches := routeRegex.FindStringSubmatch(t)
if len(matches) == 3 {
pc.routerPath = matches[1]
methods := matches[2]
if methods == "" {
pc.methods = []string{"get"}
// pc.hasGet = true
} else {
pc.methods = strings.Split(methods, ",")
// pc.hasGet = strings.Contains(methods, "get")
}
pcs = append(pcs, pc)
} else {
return nil, errors.New("router information is missing")
}
}
}
return
}
// direct copy from bee\g_docs.go
// analysis params return []string
// @Param query form string true "The email for login"
// [query form string true "The email for login"]
func getparams(str string) []string {
var s []rune
var j int
var start bool
var r []string
var quoted int8
for _, c := range str {
if unicode.IsSpace(c) && quoted == 0 {
if !start {
continue
} else {
start = false
j++
r = append(r, string(s))
s = make([]rune, 0)
continue
}
}
start = true
if c == '"' {
quoted ^= 1
continue
}
s = append(s, c)
}
if len(s) > 0 {
r = append(r, string(s))
}
return r
}
func genRouterCode(routersPath string) error {
logs.Info("generate router from comments")
var (
globalinfo string
globalimport string
sortKey []string
)
for k := range genInfoList {
sortKey = append(sortKey, k)
}
sort.Strings(sortKey)
for _, k := range sortKey {
cList := genInfoList[k]
sort.Sort(web.ControllerCommentsSlice(cList))
for _, c := range cList {
allmethod := "nil"
if len(c.AllowHTTPMethods) > 0 {
allmethod = "[]string{"
for _, m := range c.AllowHTTPMethods {
allmethod += `"` + m + `",`
}
allmethod = strings.TrimRight(allmethod, ",") + "}"
}
params := "nil"
if len(c.Params) > 0 {
params = "[]map[string]string{"
for _, p := range c.Params {
for k, v := range p {
params = params + `map[string]string{` + k + `:"` + v + `"},`
}
}
params = strings.TrimRight(params, ",") + "}"
}
methodParams := "param.Make("
if len(c.MethodParams) > 0 {
lines := make([]string, 0, len(c.MethodParams))
for _, m := range c.MethodParams {
lines = append(lines, fmt.Sprint(m))
}
methodParams += "\n " +
strings.Join(lines, ",\n ") +
",\n "
}
methodParams += ")"
imports := ""
if len(c.ImportComments) > 0 {
for _, i := range c.ImportComments {
var s string
if i.ImportAlias != "" {
s = fmt.Sprintf(`
%s "%s"`, i.ImportAlias, i.ImportPath)
} else {
s = fmt.Sprintf(`
"%s"`, i.ImportPath)
}
if !strings.Contains(globalimport, s) {
imports += s
}
}
}
filters := ""
if len(c.FilterComments) > 0 {
for _, f := range c.FilterComments {
filters += fmt.Sprintf(` &beego.ControllerFilter{
Pattern: "%s",
Pos: %s,
Filter: %s,
ReturnOnOutput: %v,
ResetParams: %v,
},`, f.Pattern, routerHooksMapping[f.Pos], f.Filter, f.ReturnOnOutput, f.ResetParams)
}
}
if filters == "" {
filters = "nil"
} else {
filters = fmt.Sprintf(`[]*beego.ControllerFilter{
%s
}`, filters)
}
globalimport += imports
globalinfo = globalinfo + `
beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"],
beego.ControllerComments{
Method: "` + strings.TrimSpace(c.Method) + `",
` + "Router: `" + c.Router + "`" + `,
AllowHTTPMethods: ` + allmethod + `,
MethodParams: ` + methodParams + `,
Filters: ` + filters + `,
Params: ` + params + `})
`
}
}
if globalinfo != "" {
routersPathDir := filepath.Dir(routersPath)
err := os.MkdirAll(routersPathDir, os.ModePerm)
if err != nil {
return err
}
f, err := os.Create(routersPath)
if err != nil {
return err
}
defer f.Close()
routersDir := RouterPkg.String()
if len(routersDir) == 0{
routersDir = "routers"
}
beeLogger.Log.Infof("using %s as routers file's package", routersDir)
content := strings.Replace(globalRouterTemplate, "{{.globalinfo}}", globalinfo, -1)
content = strings.Replace(content, "{{.routersDir}}", routersDir, -1)
content = strings.Replace(content, "{{.globalimport}}", globalimport, -1)
_, err = f.WriteString(content)
if err != nil {
return err
}
}
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,224 @@
// Copyright 2013 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.
package swaggergen
import (
_ "github.com/shopspring/decimal"
"go/ast"
"go/build"
"io/ioutil"
"os"
"path/filepath"
"testing"
)
// package model
//
// import (
// "sync"
//
// "example.com/pkgnotexist"
// "github.com/shopspring/decimal"
// )
//
// type Object struct {
// Field1 decimal.Decimal
// Field2 pkgnotexist.TestType
// Field3 sync.Map
// }
func TestCheckAndLoadPackageOnGoMod(t *testing.T) {
defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
os.Setenv("GO111MODULE", "on")
testCases := []struct {
pkgName string
pkgImportPath string
imports []*ast.ImportSpec
realType string
curPkgName string
expected bool
}{
{
pkgName: "decimal",
pkgImportPath: "github.com/shopspring/decimal",
imports: []*ast.ImportSpec{
{
Path: &ast.BasicLit{
Value: "github.com/shopspring/decimal",
},
},
},
realType: "decimal.Decimal",
curPkgName: "model",
expected: true,
},
{
pkgName: "pkgnotexist",
pkgImportPath: "example.com/pkgnotexist",
imports: []*ast.ImportSpec{
{
Path: &ast.BasicLit{
Value: "example.com/pkgnotexist",
},
},
},
realType: "pkgnotexist.TestType",
curPkgName: "model",
expected: false,
},
{
pkgName: "sync",
pkgImportPath: "sync",
imports: []*ast.ImportSpec{
{
Path: &ast.BasicLit{
Value: "sync",
},
},
},
realType: "sync.Map",
curPkgName: "model",
expected: false,
},
}
for _, test := range testCases {
checkAndLoadPackage(test.imports, test.realType, test.curPkgName)
result := false
for _, v := range astPkgs {
if v.Name == test.pkgName {
result = true
break
}
}
if test.expected != result {
t.Fatalf("load module error, expected: %v, result: %v", test.expected, result)
}
}
}
// package model
//
// import (
// "sync"
//
// "example.com/comm"
// "example.com/pkgnotexist"
// )
//
// type Object struct {
// Field1 comm.Common
// Field2 pkgnotexist.TestType
// Field3 sync.Map
// }
func TestCheckAndLoadPackageOnGoPath(t *testing.T) {
var (
testCommPkg = `
package comm
type Common struct {
Code string
Error string
}
`
)
gopath, err := ioutil.TempDir("", "gobuild-gopath")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(gopath)
if err := os.MkdirAll(filepath.Join(gopath, "src/example.com/comm"), 0777); err != nil {
t.Fatal(err)
}
if err := ioutil.WriteFile(filepath.Join(gopath, "src/example.com/comm/comm.go"), []byte(testCommPkg), 0666); err != nil {
t.Fatal(err)
}
defer os.Setenv("GO111MODULE", os.Getenv("GO111MODULE"))
os.Setenv("GO111MODULE", "off")
defer os.Setenv("GOPATH", os.Getenv("GOPATH"))
os.Setenv("GOPATH", gopath)
build.Default.GOPATH = gopath
testCases := []struct {
pkgName string
pkgImportPath string
imports []*ast.ImportSpec
realType string
curPkgName string
expected bool
}{
{
pkgName: "comm",
pkgImportPath: "example.com/comm",
imports: []*ast.ImportSpec{
{
Path: &ast.BasicLit{
Value: "example.com/comm",
},
},
},
realType: "comm.Common",
curPkgName: "model",
expected: true,
},
{
pkgName: "pkgnotexist",
pkgImportPath: "example.com/pkgnotexist",
imports: []*ast.ImportSpec{
{
Path: &ast.BasicLit{
Value: "example.com/pkgnotexist",
},
},
},
realType: "pkgnotexist.TestType",
curPkgName: "model",
expected: false,
},
{
pkgName: "sync",
pkgImportPath: "sync",
imports: []*ast.ImportSpec{
{
Path: &ast.BasicLit{
Value: "sync",
},
},
},
realType: "sync.Map",
curPkgName: "model",
expected: false,
},
}
for _, test := range testCases {
checkAndLoadPackage(test.imports, test.realType, test.curPkgName)
result := false
for _, v := range astPkgs {
if v.Name == test.pkgName {
result = true
break
}
}
if test.expected != result {
t.Fatalf("load module error, expected: %v, result: %v", test.expected, result)
}
}
}

63
go.mod Normal file
View File

@ -0,0 +1,63 @@
module github.com/beego/bee/v2
go 1.18
require (
github.com/beego/beego/v2 v2.1.0
github.com/davecgh/go-spew v1.1.1
github.com/flosch/pongo2 v0.0.0-20200529170236-5abacdfa4915
github.com/fsnotify/fsnotify v1.4.9
github.com/go-delve/delve v1.20.2
github.com/go-sql-driver/mysql v1.7.0
github.com/gorilla/websocket v1.4.2
github.com/lib/pq v1.10.5
github.com/pelletier/go-toml v1.9.2
github.com/shopspring/decimal v1.3.1
github.com/smartwalle/pongo2render v1.0.1
github.com/spf13/viper v1.7.0
golang.org/x/tools v0.1.12
gopkg.in/yaml.v2 v2.4.0
)
require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cilium/ebpf v0.7.0 // indirect
github.com/cosiner/argv v0.1.0 // indirect
github.com/derekparker/trie v0.0.0-20221213183930-4c74548207f4 // indirect
github.com/go-delve/liner v1.2.3-0.20220127212407-d32d89dd2a5d // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/go-dap v0.7.0 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/konsorten/go-windows-terminal-sequences v1.0.3 // indirect
github.com/magiconair/properties v1.8.1 // indirect
github.com/mattn/go-colorable v0.0.9 // indirect
github.com/mattn/go-isatty v0.0.3 // indirect
github.com/mattn/go-runewidth v0.0.13 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.15.1 // indirect
github.com/prometheus/client_model v0.3.0 // indirect
github.com/prometheus/common v0.42.0 // indirect
github.com/prometheus/procfs v0.9.0 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/sirupsen/logrus v1.6.0 // indirect
github.com/spf13/afero v1.1.2 // indirect
github.com/spf13/cast v1.3.0 // indirect
github.com/spf13/jwalterweatherman v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
go.starlark.net v0.0.0-20220816155156-cfacd8902214 // indirect
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 // indirect
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
golang.org/x/net v0.7.0 // indirect
golang.org/x/sys v0.6.0 // indirect
golang.org/x/text v0.7.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect
gopkg.in/ini.v1 v1.51.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

467
go.sum Normal file
View File

@ -0,0 +1,467 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beego/beego/v2 v2.1.0 h1:Lk0FtQGvDQCx5V5yEu4XwDsIgt+QOlNjt5emUa3/ZmA=
github.com/beego/beego/v2 v2.1.0/go.mod h1:6h36ISpaxNrrpJ27siTpXBG8d/Icjzsc7pU1bWpp0EE=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.7.0 h1:1k/q3ATgxSXRdrmPfH8d7YK0GfqVsEKZAX9dQZvs56k=
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosiner/argv v0.1.0 h1:BVDiEL32lwHukgJKP87btEPenzrrHUjajs/8yzaqcXg=
github.com/cosiner/argv v0.1.0/go.mod h1:EusR6TucWKX+zFgtdUsKT2Cvg45K5rtpCcWz4hK06d8=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/derekparker/trie v0.0.0-20221213183930-4c74548207f4 h1:atN94qKNhLpy+9BwbE5nxvFj4rScJi6W3x/NfFmMDg4=
github.com/derekparker/trie v0.0.0-20221213183930-4c74548207f4/go.mod h1:C7Es+DLenIpPc9J6IYw4jrK0h7S9bKj4DNl8+KxGEXU=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
github.com/flosch/pongo2 v0.0.0-20200529170236-5abacdfa4915 h1:rNVrewdFbSujcoKZifC6cHJfqCTbCIR7XTLHW5TqUWU=
github.com/flosch/pongo2 v0.0.0-20200529170236-5abacdfa4915/go.mod h1:fB4mx6dzqFinCxIf3a7Mf5yLk+18Bia9mPAnuejcvDA=
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
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/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127 h1:0gkP6mzaMqkmpcJYCFOLkIBwI7xFExG03bbkOkCvUPI=
github.com/go-check/check v0.0.0-20180628173108-788fd7840127/go.mod h1:9ES+weclKsC9YodN5RgxqK/VD9HM9JsCSh7rNhMZE98=
github.com/go-delve/delve v1.20.2 h1:rgPK7Iqb1oQk+i2Ilg0fpH6p5LqyixYiAt4N3Lhx4/Y=
github.com/go-delve/delve v1.20.2/go.mod h1:KQtnLRy2M+cNHCRnDzURxljVNbRTdvVDD5Mb10KGP18=
github.com/go-delve/liner v1.2.3-0.20220127212407-d32d89dd2a5d h1:pxjSLshkZJGLVm0wv20f/H0oTWiq/egkoJQ2ja6LEvo=
github.com/go-delve/liner v1.2.3-0.20220127212407-d32d89dd2a5d/go.mod h1:biJCRbqp51wS+I92HMqn5H8/A0PAhxn2vyOT+JqhiGI=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-dap v0.7.0 h1:088PdKBUkxAxrXrnY8FREUJXpS6Y6jhAyZIuJv3OGOM=
github.com/google/go-dap v0.7.0/go.mod h1:5q8aYQFnHOAZEMP+6vmq25HKYAEwE+LF5yh7JKrrhSQ=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
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/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/errors v0.0.0-20190930114154-d42613fe1ab9/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3 h1:CE8S1cTafDpPvMhIxNJKvHsGVBgn1xWYf1NbHQhywc8=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
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.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
github.com/lib/pq v1.10.5/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.9.2 h1:7NiByeVF4jKSG1lDF3X8LTIkq2/bu+1uYbIm1eS5tzk=
github.com/pelletier/go-toml v1.9.2/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.15.1 h1:8tXpTmJbyH5lydzFPoxSIJ0J46jdh3tylbvM1xCv0LI=
github.com/prometheus/client_golang v1.15.1/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI=
github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/smartwalle/pongo2render v1.0.1 h1:rsPnDTu/+zIT5HEB5RbMjxKY5hisov26j0isZL/7YS0=
github.com/smartwalle/pongo2render v1.0.1/go.mod h1:MGnTzND7nEMz7g194kjlnw8lx/V5JJlb1hr5kDXEO0I=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0 h1:xVKxvI7ouOI5I+U9s2eeiUfMaWBVoXA3AWskkrqK0VM=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.starlark.net v0.0.0-20220816155156-cfacd8902214 h1:MqijAN3S61c7KWasOk+zIqIjHQPN6WUra/X3+YAkQxQ=
go.starlark.net v0.0.0-20220816155156-cfacd8902214/go.mod h1:VZcBMdr3cT3PnBoWunTabuSEXwVAH+ZJ5zxfs3AdASk=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4 h1:QlVATYS7JBoZMVaf+cNjb90WD/beKVHnIxFKT4QaHVI=
golang.org/x/arch v0.0.0-20190927153633-4e8777c89be4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38=
golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

3
gosimple.ignore Normal file
View File

@ -0,0 +1,3 @@
github.com/beego/bee/v2/cmd/commands/run/*.go:S1024
github.com/beego/bee/v2/cmd/commands/dlv/*.go:S1024
github.com/beego/bee/v2/utils/*.go:S1026

View File

@ -1,325 +0,0 @@
/**********************************************************\
| |
| hprose |
| |
| Official WebSite: http://www.hprose.com/ |
| http://www.hprose.org/ |
| |
\**********************************************************/
/**********************************************************\
* *
* Build rpc application use Hprose base on beego *
* *
* LastModified: Oct 13, 2014 *
* Author: Liu jian <laoliu@lanmv.com> *
* *
\**********************************************************/
package main
import (
"fmt"
"os"
path "path/filepath"
"strings"
)
var cmdHproseapp = &Command{
// CustomFlags: true,
UsageLine: "hprose [appname]",
Short: "create an rpc application use hprose base on beego framework",
Long: `
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
-conn: the connection string used by the driver, the default is ''
e.g. for mysql: root:@tcp(127.0.0.1:3306)/test
e.g. for postgres: postgres://postgres:postgres@127.0.0.1:5432/postgres
if conn is empty will create a example rpc application. otherwise generate rpc application use hprose based on an existing database.
In the current path, will create a folder named [appname]
In the appname folder has the follow struct:
conf
app.conf
main.go
models
object.go
user.go
`,
}
var hproseconf = `appname = {{.Appname}}
httpport = 8080
runmode = dev
autorender = false
copyrequestbody = true
EnableDocs = true
`
var hproseMaingo = `package main
import (
"{{.Appname}}/models"
"github.com/hprose/hprose-go/hprose"
"github.com/astaxie/beego"
)
func main() {
service := hprose.NewHttpService()
service.AddFunction("AddOne", models.AddOne)
service.AddFunction("GetOne", models.GetOne)
beego.Handler("/", service)
beego.Run()
}
`
var hproseMainconngo = `package main
import (
"{{.Appname}}/models"
"github.com/hprose/hprose-go/hprose"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
{{.DriverPkg}}
)
func init() {
orm.RegisterDataBase("default", "{{.DriverName}}", "{{.conn}}")
}
func main() {
service := hprose.NewHttpService()
{{HproseFunctionList}}
beego.Handler("/", service)
beego.Run()
}
`
var hproseModels = `package models
import (
"errors"
"strconv"
"time"
)
var (
Objects map[string]*Object
)
type Object struct {
ObjectId string
Score int64
PlayerName string
}
func init() {
Objects = make(map[string]*Object)
Objects["hjkhsbnmn123"] = &Object{"hjkhsbnmn123", 100, "astaxie"}
Objects["mjjkxsxsaa23"] = &Object{"mjjkxsxsaa23", 101, "someone"}
}
func AddOne(object Object) (ObjectId string) {
object.ObjectId = "astaxie" + strconv.FormatInt(time.Now().UnixNano(), 10)
Objects[object.ObjectId] = &object
return object.ObjectId
}
func GetOne(ObjectId string) (object *Object, err error) {
if v, ok := Objects[ObjectId]; ok {
return v, nil
}
return nil, errors.New("ObjectId Not Exist")
}
func GetAll() map[string]*Object {
return Objects
}
func Update(ObjectId string, Score int64) (err error) {
if v, ok := Objects[ObjectId]; ok {
v.Score = Score
return nil
}
return errors.New("ObjectId Not Exist")
}
func Delete(ObjectId string) {
delete(Objects, ObjectId)
}
`
var hproseModels2 = `package models
import (
"errors"
"strconv"
"time"
)
var (
UserList map[string]*User
)
func init() {
UserList = make(map[string]*User)
u := User{"user_11111", "astaxie", "11111", Profile{"male", 20, "Singapore", "astaxie@gmail.com"}}
UserList["user_11111"] = &u
}
type User struct {
Id string
Username string
Password string
Profile Profile
}
type Profile struct {
Gender string
Age int
Address string
Email string
}
func AddUser(u User) string {
u.Id = "user_" + strconv.FormatInt(time.Now().UnixNano(), 10)
UserList[u.Id] = &u
return u.Id
}
func GetUser(uid string) (u *User, err error) {
if u, ok := UserList[uid]; ok {
return u, nil
}
return nil, errors.New("User not exists")
}
func GetAllUsers() map[string]*User {
return UserList
}
func UpdateUser(uid string, uu *User) (a *User, err error) {
if u, ok := UserList[uid]; ok {
if uu.Username != "" {
u.Username = uu.Username
}
if uu.Password != "" {
u.Password = uu.Password
}
if uu.Profile.Age != 0 {
u.Profile.Age = uu.Profile.Age
}
if uu.Profile.Address != "" {
u.Profile.Address = uu.Profile.Address
}
if uu.Profile.Gender != "" {
u.Profile.Gender = uu.Profile.Gender
}
if uu.Profile.Email != "" {
u.Profile.Email = uu.Profile.Email
}
return u, nil
}
return nil, errors.New("User Not Exist")
}
func Login(username, password string) bool {
for _, u := range UserList {
if u.Username == username && u.Password == password {
return true
}
}
return false
}
func DeleteUser(uid string) {
delete(UserList, uid)
}
`
var hproseAddFunctions = []string{}
func init() {
cmdHproseapp.Run = createhprose
cmdHproseapp.Flag.Var(&tables, "tables", "specify tables to generate model")
cmdHproseapp.Flag.Var(&driver, "driver", "database driver: mysql, postgresql, etc.")
cmdHproseapp.Flag.Var(&conn, "conn", "connection string used by the driver to connect to a database instance")
}
func createhprose(cmd *Command, args []string) int {
ShowShortVersionBanner()
w := NewColorWriter(os.Stdout)
curpath, _ := os.Getwd()
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
}
apppath, packpath, err := checkEnv(args[0])
if err != nil {
fmt.Println(err)
os.Exit(2)
}
if driver == "" {
driver = "mysql"
}
if conn == "" {
}
ColorLog("[INFO] Creating Hprose application...\n")
os.MkdirAll(apppath, 0755)
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", apppath, "\x1b[0m")
os.Mkdir(path.Join(apppath, "conf"), 0755)
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", "app.conf"), "\x1b[0m")
WriteToFile(path.Join(apppath, "conf", "app.conf"),
strings.Replace(hproseconf, "{{.Appname}}", args[0], -1))
if conn != "" {
ColorLog("[INFO] Using '%s' as 'driver'\n", driver)
ColorLog("[INFO] Using '%s' as 'conn'\n", conn)
ColorLog("[INFO] Using '%s' as 'tables'\n", tables)
generateHproseAppcode(string(driver), string(conn), "1", string(tables), path.Join(curpath, args[0]))
fmt.Fprintf(w, "\t%s%screate%s\t %s%s\n", "\x1b[32m", "\x1b[1m", "\x1b[21m", path.Join(apppath, "main.go"), "\x1b[0m")
maingoContent := strings.Replace(hproseMainconngo, "{{.Appname}}", packpath, -1)
maingoContent = strings.Replace(maingoContent, "{{.DriverName}}", string(driver), -1)
maingoContent = strings.Replace(maingoContent, "{{HproseFunctionList}}", strings.Join(hproseAddFunctions, ""), -1)
if driver == "mysql" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/go-sql-driver/mysql"`, -1)
} else if driver == "postgres" {
maingoContent = strings.Replace(maingoContent, "{{.DriverPkg}}", `_ "github.com/lib/pq"`, -1)
}
WriteToFile(path.Join(apppath, "main.go"),
strings.Replace(
maingoContent,
"{{.conn}}",
conn.String(),
-1,
),
)
} else {
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", "object.go"), "\x1b[0m")
WriteToFile(path.Join(apppath, "models", "object.go"), apiModels)
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)
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(hproseMaingo, "{{.Appname}}", packpath, -1))
}
ColorLog("[SUCC] New Hprose application successfully created!\n")
return 0
}

View File

@ -0,0 +1,23 @@
package beegopro
import (
"io/ioutil"
"github.com/beego/bee/v2/internal/pkg/utils"
beeLogger "github.com/beego/bee/v2/logger"
)
var CompareExcept = []string{"@BeeGenerateTime"}
func (c *Container) GenConfig() {
if utils.IsExist(c.BeegoProFile) {
beeLogger.Log.Fatalf("beego pro toml exist")
return
}
err := ioutil.WriteFile("beegopro.toml", []byte(BeegoToml), 0644)
if err != nil {
beeLogger.Log.Fatalf("write beego pro toml err: %s", err)
return
}
}

View File

@ -0,0 +1,18 @@
package beegopro
const BeegoToml = `
dsn = "root:123456@tcp(127.0.0.1:3306)/beego"
driver = "mysql"
proType = "default"
enableModule = []
apiPrefix = "/"
gitRemotePath = "https://github.com/beego-dev/beego-pro.git"
format = true
sourceGen = "text"
gitPull = true
[models.user]
name = ["uid"]
orm = ["auto"]
comment = ["Uid"]
`

View File

@ -0,0 +1,254 @@
package beegopro
import (
"fmt"
"io/ioutil"
"net/url"
"strings"
"sync"
"time"
"github.com/beego/bee/v2/internal/pkg/git"
"github.com/beego/bee/v2/internal/pkg/system"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
"github.com/davecgh/go-spew/spew"
"github.com/pelletier/go-toml"
"github.com/spf13/viper"
)
var GitRemotePath utils.DocValue
const MDateFormat = "20060102_150405"
var DefaultBeegoPro = &Container{
BeegoProFile: system.CurrentDir + "/beegopro.toml",
TimestampFile: system.CurrentDir + "/.beegopro.timestamp",
GoModFile: system.CurrentDir + "/go.mod",
UserOption: UserOption{
Debug: false,
ContextDebug: false,
Dsn: "",
Driver: "mysql",
ProType: "default",
ApiPrefix: "/api",
EnableModule: nil,
Models: make(map[string]TextModel),
GitRemotePath: "",
//GitRemotePath: "https://github.com/beego/beego-pro.git",
Branch: "master",
//GitLocalPath: system.BeegoHome + "/beego-pro",
EnableFormat: true,
SourceGen: "text",
EnableGitPull: true,
Path: map[string]string{
"beego": ".",
},
EnableGomod: true,
RefreshGitTime: 24 * 3600,
Extend: nil,
},
GenerateTime: time.Now().Format(MDateFormat),
GenerateTimeUnix: time.Now().Unix(),
TmplOption: TmplOption{},
CurPath: system.CurrentDir,
EnableModules: make(map[string]interface{}), // get the user configuration, get the enable module result
FunctionOnce: make(map[string]sync.Once), // get the tmpl configuration, get the function once result
}
func (c *Container) Run() {
// init git refresh cache time
c.initTimestamp()
c.initUserOption()
c.initTemplateOption()
c.initParser()
c.initRender()
c.flushTimestamp()
}
func (c *Container) initUserOption() {
if !utils.IsExist(c.BeegoProFile) {
beeLogger.Log.Fatalf("beego pro config is not exist, beego json path: %s", c.BeegoProFile)
return
}
viper.SetConfigFile(c.BeegoProFile)
err := viper.ReadInConfig()
if err != nil {
beeLogger.Log.Fatalf("read beego pro config content, err: %s", err.Error())
return
}
err = viper.Unmarshal(&c.UserOption)
if err != nil {
beeLogger.Log.Fatalf("beego pro config unmarshal error, err: %s", err.Error())
return
}
if c.UserOption.Debug {
viper.Debug()
}
if c.UserOption.EnableGomod {
if !utils.IsExist(c.GoModFile) {
beeLogger.Log.Fatalf("go mod not exist, please create go mod file")
return
}
}
for _, value := range c.UserOption.EnableModule {
c.EnableModules[value] = struct{}{}
}
if len(c.EnableModules) == 0 {
c.EnableModules["*"] = struct{}{}
}
if c.UserOption.Debug {
fmt.Println("c.modules", c.EnableModules)
}
}
func (c *Container) initTemplateOption() {
c.GetLocalPath()
if c.UserOption.EnableGitPull && (c.GenerateTimeUnix-c.Timestamp.GitCacheLastRefresh > c.UserOption.RefreshGitTime) {
err := git.CloneORPullRepo(c.UserOption.GitRemotePath, c.UserOption.GitLocalPath)
if err != nil {
beeLogger.Log.Fatalf("beego pro git clone or pull repo error, err: %s", err)
return
}
c.Timestamp.GitCacheLastRefresh = c.GenerateTimeUnix
}
tree, err := toml.LoadFile(c.UserOption.GitLocalPath + "/" + c.UserOption.ProType + "/bee.toml")
if err != nil {
beeLogger.Log.Fatalf("beego tmpl exec error, err: %s", err)
return
}
err = tree.Unmarshal(&c.TmplOption)
if err != nil {
beeLogger.Log.Fatalf("beego tmpl parse error, err: %s", err)
return
}
if c.UserOption.Debug {
spew.Dump("tmpl", c.TmplOption)
}
for _, value := range c.TmplOption.Descriptor {
if value.Once {
c.FunctionOnce[value.SrcName] = sync.Once{}
}
}
}
func (c *Container) initParser() {
driver, flag := ParserDriver[c.UserOption.SourceGen]
if !flag {
beeLogger.Log.Fatalf("parse driver not exit, source gen %s", c.UserOption.SourceGen)
}
driver.RegisterOption(c.UserOption, c.TmplOption)
c.Parser = driver
}
func (c *Container) initRender() {
for _, desc := range c.TmplOption.Descriptor {
_, allFlag := c.EnableModules["*"]
_, moduleFlag := c.EnableModules[desc.Module]
if !allFlag && !moduleFlag {
continue
}
models := c.Parser.GetRenderInfos(desc)
// model table name, model table schema
for _, m := range models {
// some render exec once
syncOnce, flag := c.FunctionOnce[desc.SrcName]
if flag {
syncOnce.Do(func() {
c.renderModel(m)
})
continue
}
c.renderModel(m)
}
}
}
func (c *Container) renderModel(m RenderInfo) {
// todo optimize
m.GenerateTime = c.GenerateTime
render := NewRender(m)
render.Exec(m.Descriptor.SrcName)
if render.Descriptor.IsExistScript() {
err := render.Descriptor.ExecScript(c.CurPath)
if err != nil {
beeLogger.Log.Fatalf("beego exec shell error, err: %s", err)
}
}
}
func (c *Container) initTimestamp() {
if utils.IsExist(c.TimestampFile) {
tree, err := toml.LoadFile(c.TimestampFile)
if err != nil {
beeLogger.Log.Fatalf("beego timestamp tmpl exec error, err: %s", err)
return
}
err = tree.Unmarshal(&c.Timestamp)
if err != nil {
beeLogger.Log.Fatalf("beego timestamp tmpl parse error, err: %s", err)
return
}
}
c.Timestamp.Generate = c.GenerateTimeUnix
}
func (c *Container) flushTimestamp() {
tomlByte, err := toml.Marshal(c.Timestamp)
if err != nil {
beeLogger.Log.Fatalf("marshal timestamp tmpl parse error, err: %s", err)
}
err = ioutil.WriteFile(c.TimestampFile, tomlByte, 0644)
if err != nil {
beeLogger.Log.Fatalf("flush timestamp tmpl parse error, err: %s", err)
}
}
func (c *Container) InitToml() {
if exist := utils.IsExist(c.BeegoProFile); exist {
beeLogger.Log.Fatalf("file beegopro.toml already exists")
}
sourceFile := c.UserOption.GitLocalPath + "/beegopro.toml"
input, err := ioutil.ReadFile(sourceFile)
if err != nil {
beeLogger.Log.Fatalf("read beegopro.toml file err, %s", err.Error())
return
}
err = ioutil.WriteFile(c.BeegoProFile, input, 0644)
if err != nil {
beeLogger.Log.Fatalf("create beegopro.toml file err, %s", err.Error())
return
}
beeLogger.Log.Success("Successfully created file beegopro.toml")
}
//form https://github.com/beego/beego-pro.git
//get beego/beego-pro
func (c *Container) GetLocalPath() {
if c.UserOption.GitLocalPath != "" {
return
}
if GitRemotePath != "" {
c.UserOption.GitRemotePath = GitRemotePath.String()
}
if c.UserOption.GitRemotePath == "" {
c.UserOption.GitRemotePath = "https://github.com/beego/beego-pro.git"
}
parse, err := url.Parse(c.UserOption.GitRemotePath)
if err != nil {
beeLogger.Log.Fatalf("git GitRemotePath err, %s", err.Error())
return
}
s := parse.Path
s = strings.TrimRight(s, ".git")
c.UserOption.GitLocalPath = system.BeegoHome + s
}

View File

@ -0,0 +1,80 @@
package beegopro
import (
"database/sql"
"io/ioutil"
"path/filepath"
"strings"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
var SQL utils.DocValue
var SQLMode utils.DocValue
var SQLModePath utils.DocValue
var (
SQLModeUp = "up"
SQLModeDown = "down"
)
func (c *Container) Migration(args []string) {
c.initUserOption()
db, err := sql.Open(c.UserOption.Driver, c.UserOption.Dsn)
if err != nil {
beeLogger.Log.Fatalf("Could not connect to '%s' database using '%s': %s", c.UserOption.Driver, c.UserOption.Dsn, err)
return
}
defer db.Close()
switch SQLMode.String() {
case SQLModeUp:
doByMode(db, "up.sql")
case SQLModeDown:
doByMode(db, "down.sql")
default:
doBySqlFile(db)
}
}
func doBySqlFile(db *sql.DB) {
fileName := SQL.String()
if !utils.IsExist(fileName) {
beeLogger.Log.Fatalf("sql mode path not exist, path %s", SQL.String())
}
doDb(db, fileName)
}
func doByMode(db *sql.DB, suffix string) {
pathName := SQLModePath.String()
if !utils.IsExist(pathName) {
beeLogger.Log.Fatalf("sql mode path not exist, path %s", SQLModePath.String())
}
rd, err := ioutil.ReadDir(pathName)
if err != nil {
beeLogger.Log.Fatalf("read dir err, path %s, err %s", pathName, err)
}
for _, fi := range rd {
if !fi.IsDir() {
if !strings.HasSuffix(fi.Name(), suffix) {
continue
}
doDb(db, filepath.Join(pathName, fi.Name()))
}
}
}
func doDb(db *sql.DB, filePath string) {
absFile, _ := filepath.Abs(filePath)
content, err := ioutil.ReadFile(filePath)
if err != nil {
beeLogger.Log.Errorf("read file err %s, abs file %s", err, absFile)
}
_, err = db.Exec(string(content))
if err != nil {
beeLogger.Log.Errorf("db exec err %s", err)
}
beeLogger.Log.Infof("db exec info %s", filePath)
}

View File

@ -0,0 +1,13 @@
package beegopro
type Parser interface {
RegisterOption(userOption UserOption, tmplOption TmplOption)
Parse(descriptor Descriptor)
GetRenderInfos(descriptor Descriptor) (output []RenderInfo)
Unregister()
}
var ParserDriver = map[string]Parser{
"text": &TextParser{},
"mysql": &MysqlParser{},
}

View File

@ -0,0 +1,88 @@
package beegopro
import (
"database/sql"
"fmt"
"github.com/beego/bee/v2/internal/pkg/utils"
beeLogger "github.com/beego/bee/v2/logger"
)
type MysqlParser struct {
userOption UserOption
tmplOption TmplOption
}
func (m *MysqlParser) RegisterOption(userOption UserOption, tmplOption TmplOption) {
m.userOption = userOption
m.tmplOption = tmplOption
}
func (*MysqlParser) Parse(descriptor Descriptor) {
}
func (m *MysqlParser) GetRenderInfos(descriptor Descriptor) (output []RenderInfo) {
tableSchemas, err := m.getTableSchemas()
if err != nil {
beeLogger.Log.Fatalf("get table schemas err %s", err)
}
models := tableSchemas.ToTableMap()
output = make([]RenderInfo, 0)
// model table name, model table schema
for modelName, content := range models {
output = append(output, RenderInfo{
Module: descriptor.Module,
ModelName: modelName,
Content: content,
Option: m.userOption,
Descriptor: descriptor,
TmplPath: m.tmplOption.RenderPath,
})
}
return
}
func (t *MysqlParser) Unregister() {
}
func (m *MysqlParser) getTableSchemas() (resp TableSchemas, err error) {
dsn, err := utils.ParseDSN(m.userOption.Dsn)
if err != nil {
beeLogger.Log.Fatalf("parse dsn err %s", err)
return
}
conn, err := sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s)/information_schema", dsn.User, dsn.Passwd, dsn.Addr))
if err != nil {
beeLogger.Log.Fatalf("Could not connect to mysql database using '%s': %s", m.userOption.Dsn, err)
return
}
defer conn.Close()
q := `SELECT TABLE_NAME, COLUMN_NAME, IS_NULLABLE, DATA_TYPE, CHARACTER_MAXIMUM_LENGTH,
NUMERIC_PRECISION, NUMERIC_SCALE,COLUMN_TYPE,COLUMN_KEY,COLUMN_COMMENT
FROM COLUMNS WHERE TABLE_SCHEMA = ? ORDER BY TABLE_NAME, ORDINAL_POSITION`
rows, err := conn.Query(q, dsn.DBName)
if err != nil {
return nil, err
}
columns := make(TableSchemas, 0)
for rows.Next() {
cs := TableSchema{}
err := rows.Scan(&cs.TableName, &cs.ColumnName, &cs.IsNullable, &cs.DataType,
&cs.CharacterMaximumLength, &cs.NumericPrecision, &cs.NumericScale,
&cs.ColumnType, &cs.ColumnKey, &cs.Comment)
if err != nil {
return nil, err
}
columns = append(columns, cs)
}
if err := rows.Err(); err != nil {
return nil, err
}
return columns, nil
}

View File

@ -0,0 +1,35 @@
package beegopro
type TextParser struct {
userOption UserOption
tmplOption TmplOption
}
func (t *TextParser) RegisterOption(userOption UserOption, tmplOption TmplOption) {
t.userOption = userOption
t.tmplOption = tmplOption
}
func (*TextParser) Parse(descriptor Descriptor) {
}
func (t *TextParser) GetRenderInfos(descriptor Descriptor) (output []RenderInfo) {
output = make([]RenderInfo, 0)
// model table name, model table schema
for modelName, content := range t.userOption.Models {
output = append(output, RenderInfo{
Module: descriptor.Module,
ModelName: modelName,
Content: content.ToModelInfos(),
Option: t.userOption,
Descriptor: descriptor,
TmplPath: t.tmplOption.RenderPath,
})
}
return
}
func (t *TextParser) Unregister() {
}

View File

@ -0,0 +1,59 @@
package beegopro
import (
"strings"
"unicode/utf8"
"github.com/beego/bee/v2/utils"
"github.com/flosch/pongo2"
)
func init() {
_ = pongo2.RegisterFilter("lowerFirst", pongo2LowerFirst)
_ = pongo2.RegisterFilter("upperFirst", pongo2UpperFirst)
_ = pongo2.RegisterFilter("snakeString", pongo2SnakeString)
_ = pongo2.RegisterFilter("camelString", pongo2CamelString)
}
func pongo2LowerFirst(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
if in.Len() <= 0 {
return pongo2.AsValue(""), nil
}
t := in.String()
r, size := utf8.DecodeRuneInString(t)
return pongo2.AsValue(strings.ToLower(string(r)) + t[size:]), nil
}
func pongo2UpperFirst(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
if in.Len() <= 0 {
return pongo2.AsValue(""), nil
}
t := in.String()
return pongo2.AsValue(strings.Replace(t, string(t[0]), strings.ToUpper(string(t[0])), 1)), nil
}
// snake string, XxYy to xx_yy
func pongo2SnakeString(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
if in.Len() <= 0 {
return pongo2.AsValue(""), nil
}
t := in.String()
return pongo2.AsValue(utils.SnakeString(t)), nil
}
// snake string, XxYy to xx_yy
func pongo2CamelString(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, *pongo2.Error) {
if in.Len() <= 0 {
return pongo2.AsValue(""), nil
}
t := in.String()
return pongo2.AsValue(utils.CamelString(t)), nil
}
//func upperFirst(str string) string {
// return strings.Replace(str, string(str[0]), strings.ToUpper(string(str[0])), 1)
//}
func lowerFirst(str string) string {
return strings.Replace(str, string(str[0]), strings.ToLower(string(str[0])), 1)
}

View File

@ -0,0 +1,153 @@
package beegopro
import (
"go/format"
"io/ioutil"
"os"
"path"
"path/filepath"
"github.com/davecgh/go-spew/spew"
"github.com/flosch/pongo2"
"github.com/smartwalle/pongo2render"
"github.com/beego/bee/v2/internal/pkg/system"
beeLogger "github.com/beego/bee/v2/logger"
)
// render
type RenderFile struct {
*pongo2render.Render
Context pongo2.Context
GenerateTime string
Option UserOption
ModelName string
PackageName string
FlushFile string
PkgPath string
TmplPath string
Descriptor Descriptor
}
func NewRender(m RenderInfo) *RenderFile {
var (
pathCtx pongo2.Context
newDescriptor Descriptor
)
// parse descriptor, get flush file path, beego path, etc...
newDescriptor, pathCtx = m.Descriptor.Parse(m.ModelName, m.Option.Path)
obj := &RenderFile{
Context: make(pongo2.Context),
Option: m.Option,
ModelName: m.ModelName,
GenerateTime: m.GenerateTime,
Descriptor: newDescriptor,
}
obj.FlushFile = newDescriptor.DstPath
// new render
obj.Render = pongo2render.NewRender(path.Join(obj.Option.GitLocalPath, obj.Option.ProType, m.TmplPath))
filePath := path.Dir(obj.FlushFile)
err := createPath(filePath)
if err != nil {
beeLogger.Log.Fatalf("Could not create the controllers directory: %s", err)
}
// get go package path
obj.PkgPath = getPackagePath()
relativePath, err := filepath.Rel(system.CurrentDir, obj.FlushFile)
if err != nil {
beeLogger.Log.Fatalf("Could not get the relative path: %s", err)
}
modelSchemas := m.Content.ToModelSchemas()
camelPrimaryKey := modelSchemas.GetPrimaryKey()
importMaps := make(map[string]struct{})
if modelSchemas.IsExistTime() {
importMaps["time"] = struct{}{}
}
obj.PackageName = filepath.Base(filepath.Dir(relativePath))
beeLogger.Log.Infof("Using '%s' as name", obj.ModelName)
beeLogger.Log.Infof("Using '%s' as package name from %s", obj.ModelName, obj.PackageName)
// package
obj.SetContext("packageName", obj.PackageName)
obj.SetContext("packageImports", importMaps)
// todo optimize
// todo Set the beego directory, should recalculate the package
if pathCtx["pathRelBeego"] == "." {
obj.SetContext("packagePath", obj.PkgPath)
} else {
obj.SetContext("packagePath", obj.PkgPath+"/"+pathCtx["pathRelBeego"].(string))
}
obj.SetContext("packageMod", obj.PkgPath)
obj.SetContext("modelSchemas", modelSchemas)
obj.SetContext("modelPrimaryKey", camelPrimaryKey)
for key, value := range pathCtx {
obj.SetContext(key, value)
}
obj.SetContext("apiPrefix", obj.Option.ApiPrefix)
obj.SetContext("generateTime", obj.GenerateTime)
if obj.Option.ContextDebug {
spew.Dump(obj.Context)
}
return obj
}
func (r *RenderFile) SetContext(key string, value interface{}) {
r.Context[key] = value
}
func (r *RenderFile) Exec(name string) {
var (
buf string
err error
)
buf, err = r.Render.Template(name).Execute(r.Context)
if err != nil {
beeLogger.Log.Fatalf("Could not create the %s render tmpl: %s", name, err)
return
}
_, err = os.Stat(r.Descriptor.DstPath)
var orgContent []byte
if err == nil {
if org, err := os.OpenFile(r.Descriptor.DstPath, os.O_RDONLY, 0666); err == nil {
orgContent, _ = ioutil.ReadAll(org)
org.Close()
} else {
beeLogger.Log.Infof("file err %s", err)
}
}
// Replace or create when content changes
output := []byte(buf)
ext := filepath.Ext(r.FlushFile)
if r.Option.EnableFormat && ext == ".go" {
// format code
var bts []byte
bts, err = format.Source([]byte(buf))
if err != nil {
beeLogger.Log.Warnf("format buf error %s", err.Error())
}
output = bts
}
if FileContentChange(orgContent, output, GetSeg(ext)) {
err = r.write(r.FlushFile, output)
if err != nil {
beeLogger.Log.Fatalf("Could not create file: %s", err)
return
}
beeLogger.Log.Infof("create file '%s' from %s", r.FlushFile, r.PackageName)
}
}

View File

@ -0,0 +1,142 @@
package beegopro
import (
"fmt"
"path/filepath"
"strings"
"sync"
"github.com/beego/bee/v2/internal/pkg/command"
"github.com/beego/bee/v2/internal/pkg/system"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
"github.com/flosch/pongo2"
"github.com/smartwalle/pongo2render"
)
// store all data
type Container struct {
BeegoProFile string // beego pro toml
TimestampFile string // store ts file
GoModFile string // go mod file
UserOption UserOption // user option
TmplOption TmplOption // tmpl option
CurPath string // user current path
EnableModules map[string]interface{} // beego pro provider a collection of module
FunctionOnce map[string]sync.Once // exec function once
Timestamp Timestamp
GenerateTime string
GenerateTimeUnix int64
Parser Parser
}
// user option
type UserOption struct {
Debug bool `json:"debug"`
ContextDebug bool `json:"contextDebug"`
Dsn string `json:"dsn"`
Driver string `json:"driver"`
ProType string `json:"proType"`
ApiPrefix string `json:"apiPrefix"`
EnableModule []string `json:"enableModule"`
Models map[string]TextModel `json:"models"`
GitRemotePath string `json:"gitRemotePath"`
Branch string `json:"branch"`
GitLocalPath string `json:"gitLocalPath"`
EnableFormat bool `json:"enableFormat"`
SourceGen string `json:"sourceGen"`
EnableGitPull bool `json:"enbaleGitPull"`
Path map[string]string `json:"path"`
EnableGomod bool `json:"enableGomod"`
RefreshGitTime int64 `json:"refreshGitTime"`
Extend map[string]string `json:"extend"` // extend user data
}
// tmpl option
type TmplOption struct {
RenderPath string `toml:"renderPath"`
Descriptor []Descriptor
}
type Descriptor struct {
Module string `toml:"module"`
SrcName string `toml:"srcName"`
DstPath string `toml:"dstPath"`
Once bool `toml:"once"`
Script string `toml:"script"`
}
func (descriptor Descriptor) Parse(modelName string, paths map[string]string) (newDescriptor Descriptor, ctx pongo2.Context) {
var (
err error
relativeDstPath string
absFile string
relPath string
)
newDescriptor = descriptor
render := pongo2render.NewRender("")
ctx = make(pongo2.Context)
for key, value := range paths {
absFile, err = filepath.Abs(value)
if err != nil {
beeLogger.Log.Fatalf("absolute path error %s from key %s and value %s", err, key, value)
}
relPath, err = filepath.Rel(system.CurrentDir, absFile)
if err != nil {
beeLogger.Log.Fatalf("Could not get the relative path: %s", err)
}
// user input path
ctx["path"+utils.CamelCase(key)] = value
// relativePath
ctx["pathRel"+utils.CamelCase(key)] = relPath
}
ctx["modelName"] = lowerFirst(utils.CamelString(modelName))
relativeDstPath, err = render.TemplateFromString(descriptor.DstPath).Execute(ctx)
if err != nil {
beeLogger.Log.Fatalf("beego tmpl exec error, err: %s", err)
return
}
newDescriptor.DstPath, err = filepath.Abs(relativeDstPath)
if err != nil {
beeLogger.Log.Fatalf("absolute path error %s from flush file %s", err, relativeDstPath)
}
newDescriptor.Script, err = render.TemplateFromString(descriptor.Script).Execute(ctx)
if err != nil {
beeLogger.Log.Fatalf("parse script %s, error %s", descriptor.Script, err)
}
return
}
func (descriptor Descriptor) IsExistScript() bool {
return descriptor.Script != ""
}
func (d Descriptor) ExecScript(path string) (err error) {
arr := strings.Split(d.Script, " ")
if len(arr) == 0 {
return
}
stdout, stderr, err := command.ExecCmdDir(path, arr[0], arr[1:]...)
if err != nil {
return concatenateError(err, stderr)
}
beeLogger.Log.Info(stdout)
return nil
}
type Timestamp struct {
GitCacheLastRefresh int64 `toml:"gitCacheLastRefresh"`
Generate int64 `toml:"generate"`
}
func concatenateError(err error, stderr string) error {
if len(stderr) == 0 {
return err
}
return fmt.Errorf("%v: %s", err, stderr)
}

View File

@ -0,0 +1,98 @@
package beegopro
import (
"strings"
"github.com/beego/bee/v2/utils"
)
// parse get the model info
type ModelInfo struct {
Name string `json:"name"` // mysql name
InputType string `json:"inputType"` // user input type
MysqlType string `json:"mysqlType"` // mysql type
GoType string `json:"goType"` // go type
Orm string `json:"orm"` // orm tag
Comment string `json:"comment"` // mysql comment
Extend string `json:"extend"` // user extend info
}
func (m ModelInfo) GetColumnKey() (columnKey string) {
if m.InputType == "auto" || m.Orm == "pk" {
columnKey = "PRI"
}
return
}
func (m ModelInfo) IsPrimaryKey() (flag bool) {
if m.Orm == "auto" || m.Orm == "pk" || strings.ToLower(m.Name) == "id" {
flag = true
}
return
}
type ModelInfos []ModelInfo
// to render model schemas
func (modelInfos ModelInfos) ToModelSchemas() (output ModelSchemas) {
output = make(ModelSchemas, 0)
for i, value := range modelInfos {
if i == 0 && !value.IsPrimaryKey() {
inputType, goType, mysqlType, ormTag := getModelType("auto")
output = append(output, &ModelSchema{
Name: "id",
InputType: inputType,
ColumnKey: "PRI",
Comment: "ID",
MysqlType: mysqlType,
GoType: goType,
OrmTag: ormTag,
Extend: value.Extend,
})
}
modelSchema := &ModelSchema{
Name: value.Name,
InputType: value.InputType,
ColumnKey: value.GetColumnKey(),
MysqlType: value.MysqlType,
Comment: value.Comment,
GoType: value.GoType,
OrmTag: value.Orm,
}
output = append(output, modelSchema)
}
return
}
type ModelSchema struct {
Name string // column name
InputType string // user input type
MysqlType string // mysql type
ColumnKey string // PRI
Comment string // comment
GoType string // go type
OrmTag string // orm tag
Extend string
}
type ModelSchemas []*ModelSchema
func (m ModelSchemas) IsExistTime() bool {
for _, value := range m {
if value.InputType == "datetime" {
return true
}
}
return false
}
func (m ModelSchemas) GetPrimaryKey() string {
camelPrimaryKey := ""
for _, value := range m {
if value.ColumnKey == "PRI" {
camelPrimaryKey = utils.CamelString(value.Name)
}
}
return camelPrimaryKey
}

View File

@ -0,0 +1,75 @@
package beegopro
import (
"database/sql"
"errors"
"github.com/beego/bee/v2/logger"
)
type TableSchema struct {
TableName string
ColumnName string
IsNullable string
DataType string
CharacterMaximumLength sql.NullInt64
NumericPrecision sql.NullInt64
NumericScale sql.NullInt64
ColumnType string
ColumnKey string
Comment string
}
type TableSchemas []TableSchema
func (tableSchemas TableSchemas) ToTableMap() (resp map[string]ModelInfos) {
resp = make(map[string]ModelInfos)
for _, value := range tableSchemas {
if _, ok := resp[value.TableName]; !ok {
resp[value.TableName] = make(ModelInfos, 0)
}
modelInfos := resp[value.TableName]
inputType, goType, err := value.ToGoType()
if err != nil {
beeLogger.Log.Fatalf("parse go type err %s", err)
return
}
modelInfo := ModelInfo{
Name: value.ColumnName,
InputType: inputType,
GoType: goType,
Comment: value.Comment,
}
if value.ColumnKey == "PRI" {
modelInfo.Orm = "pk"
}
resp[value.TableName] = append(modelInfos, modelInfo)
}
return
}
// GetGoDataType maps an SQL data type to Golang data type
func (col TableSchema) ToGoType() (inputType string, goType string, err error) {
switch col.DataType {
case "char", "varchar", "enum", "set", "text", "longtext", "mediumtext", "tinytext":
goType = "string"
case "blob", "mediumblob", "longblob", "varbinary", "binary":
goType = "[]byte"
case "date", "time", "datetime", "timestamp":
goType, inputType = "time.Time", "dateTime"
case "tinyint", "smallint", "int", "mediumint":
goType = "int"
case "bit", "bigint":
goType = "int64"
case "float", "decimal", "double":
goType = "float64"
}
if goType == "" {
err = errors.New("No compatible datatype (" + col.DataType + ", CamelName: " + col.ColumnName + ") found")
}
return
}

View File

@ -0,0 +1,11 @@
package beegopro
type RenderInfo struct {
Module string
ModelName string
Option UserOption
Content ModelInfos
Descriptor Descriptor
TmplPath string
GenerateTime string
}

View File

@ -0,0 +1,50 @@
package beegopro
import (
beeLogger "github.com/beego/bee/v2/logger"
)
type TextModel struct {
Names []string
Orms []string
Comments []string
Extends []string
}
func (content TextModel) ToModelInfos() (output []ModelInfo) {
namesLen := len(content.Names)
ormsLen := len(content.Orms)
commentsLen := len(content.Comments)
if namesLen != ormsLen && namesLen != commentsLen {
beeLogger.Log.Fatalf("length error, namesLen is %d, ormsLen is %d, commentsLen is %d", namesLen, ormsLen, commentsLen)
}
extendLen := len(content.Extends)
if extendLen != 0 && extendLen != namesLen {
beeLogger.Log.Fatalf("extend length error, namesLen is %d, extendsLen is %d", namesLen, extendLen)
}
output = make([]ModelInfo, 0)
for i, name := range content.Names {
comment := content.Comments[i]
if comment == "" {
comment = name
}
inputType, goType, mysqlType, ormTag := getModelType(content.Orms[i])
m := ModelInfo{
Name: name,
InputType: inputType,
GoType: goType,
Orm: ormTag,
Comment: comment,
MysqlType: mysqlType,
Extend: "",
}
// extend value
if extendLen != 0 {
m.Extend = content.Extends[i]
}
output = append(output, m)
}
return
}

View File

@ -0,0 +1,215 @@
package beegopro
import (
"crypto/md5"
"errors"
"fmt"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"time"
"github.com/beego/bee/v2/internal/pkg/utils"
beeLogger "github.com/beego/bee/v2/logger"
)
// write to file
func (c *RenderFile) write(filename string, buf []byte) (err error) {
if utils.IsExist(filename) && !isNeedOverwrite(filename) {
return
}
filePath := filepath.Dir(filename)
err = createPath(filePath)
if err != nil {
err = errors.New("write create path " + err.Error())
return
}
filePathBak := filePath + "/bak"
err = createPath(filePathBak)
if err != nil {
err = errors.New("write create path bak " + err.Error())
return
}
name := path.Base(filename)
if utils.IsExist(filename) {
bakName := fmt.Sprintf("%s/%s.%s.bak", filePathBak, filepath.Base(name), time.Now().Format("2006.01.02.15.04.05"))
beeLogger.Log.Infof("bak file '%s'", bakName)
if err := os.Rename(filename, bakName); err != nil {
err = errors.New("file is bak error, path is " + bakName)
return err
}
}
file, err := os.Create(filename)
defer func() {
err = file.Close()
if err != nil {
beeLogger.Log.Fatalf("file close error, err %s", err)
}
}()
if err != nil {
err = errors.New("write create file " + err.Error())
return
}
err = ioutil.WriteFile(filename, buf, 0644)
if err != nil {
err = errors.New("write write file " + err.Error())
return
}
return
}
func isNeedOverwrite(fileName string) (flag bool) {
seg := GetSeg(filepath.Ext(fileName))
f, err := os.Open(fileName)
if err != nil {
return
}
defer f.Close()
overwrite := ""
var contentByte []byte
contentByte, err = ioutil.ReadAll(f)
if err != nil {
return
}
for _, s := range strings.Split(string(contentByte), "\n") {
s = strings.TrimSpace(strings.TrimPrefix(s, seg))
if strings.HasPrefix(s, "@BeeOverwrite") {
overwrite = strings.TrimSpace(s[len("@BeeOverwrite"):])
}
}
if strings.ToLower(overwrite) == "yes" {
flag = true
return
}
return
}
// createPath 调用os.MkdirAll递归创建文件夹
func createPath(filePath string) error {
if !utils.IsExist(filePath) {
err := os.MkdirAll(filePath, os.ModePerm)
return err
}
return nil
}
func getPackagePath() (packagePath string) {
f, err := os.Open("go.mod")
if err != nil {
return
}
defer f.Close()
var contentByte []byte
contentByte, err = ioutil.ReadAll(f)
if err != nil {
return
}
for _, s := range strings.Split(string(contentByte), "\n") {
packagePath = strings.TrimSpace(strings.TrimPrefix(s, "module"))
return
}
return
}
func getModelType(orm string) (inputType, goType, mysqlType, tag string) {
kv := strings.SplitN(orm, ",", 2)
inputType = kv[0]
switch inputType {
case "string":
goType = "string"
tag = "size(255)"
// todo use orm data
mysqlType = "varchar(255) NOT NULL"
case "text":
goType = "string"
tag = "type(longtext)"
mysqlType = "longtext NOT NULL"
case "auto":
goType = "int"
tag = "auto"
mysqlType = "int(11) NOT NULL AUTO_INCREMENT"
case "pk":
goType = "int"
tag = "pk"
mysqlType = "int(11) NOT NULL"
case "datetime":
goType = "time.Time"
tag = "type(datetime)"
mysqlType = "datetime NOT NULL"
case "int", "int8", "int16", "int32", "int64":
fallthrough
case "uint", "uint8", "uint16", "uint32", "uint64":
goType = inputType
tag = ""
mysqlType = "int(11) DEFAULT NULL"
case "bool":
goType = inputType
tag = ""
mysqlType = "int(11) DEFAULT NULL"
case "float32", "float64":
goType = inputType
tag = ""
mysqlType = "float NOT NULL"
case "float":
goType = "float64"
tag = ""
mysqlType = "float NOT NULL"
default:
beeLogger.Log.Fatalf("not support type: %s", inputType)
}
// user set orm tag
if len(kv) == 2 {
tag = kv[1]
}
return
}
func FileContentChange(org, new []byte, seg string) bool {
if len(org) == 0 {
return true
}
orgContent := GetFilterContent(string(org), seg)
newContent := GetFilterContent(string(new), seg)
orgMd5 := md5.Sum([]byte(orgContent))
newMd5 := md5.Sum([]byte(newContent))
if orgMd5 != newMd5 {
return true
}
beeLogger.Log.Infof("File has no change in the content")
return false
}
func GetFilterContent(content string, seg string) string {
res := ""
for _, s := range strings.Split(content, "\n") {
s = strings.TrimSpace(strings.TrimPrefix(s, seg))
var have bool
for _, except := range CompareExcept {
if strings.HasPrefix(s, except) {
have = true
}
}
if !have {
res += s
}
}
return res
}
func GetSeg(ext string) string {
switch ext {
case ".sql":
return "--"
default:
return "//"
}
}

View File

@ -0,0 +1,65 @@
package command
import (
"bytes"
"fmt"
"os/exec"
"strconv"
"strings"
)
// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
bufOut := new(bytes.Buffer)
bufErr := new(bytes.Buffer)
cmd := exec.Command(cmdName, args...)
cmd.Dir = dir
cmd.Stdout = bufOut
cmd.Stderr = bufErr
err := cmd.Run()
return bufOut.Bytes(), bufErr.Bytes(), err
}
// ExecCmdBytes executes system command
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdBytes(cmdName string, args ...string) ([]byte, []byte, error) {
return ExecCmdDirBytes("", cmdName, args...)
}
// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
return string(bufOut), string(bufErr), err
}
// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
return ExecCmdDir("", cmdName, args...)
}
// 版本对比 v1比v2大返回1小于返回-1等于返回0
func VerCompare(ver1, ver2 string) int {
ver1 = strings.TrimLeft(ver1, "ver") // 清除v,e,r
ver2 = strings.TrimLeft(ver2, "ver") // 清除v,e,r
p1 := strings.Split(ver1, ".")
p2 := strings.Split(ver2, ".")
ver1 = ""
for _, v := range p1 {
iv, _ := strconv.Atoi(v)
ver1 = fmt.Sprintf("%s%04d", ver1, iv)
}
ver2 = ""
for _, v := range p2 {
iv, _ := strconv.Atoi(v)
ver2 = fmt.Sprintf("%s%04d", ver2, iv)
}
return strings.Compare(ver1, ver2)
}

View File

@ -0,0 +1,209 @@
package git
import (
"errors"
"fmt"
"path/filepath"
"sort"
"strconv"
"strings"
"github.com/beego/bee/v2/internal/pkg/command"
"github.com/beego/bee/v2/internal/pkg/utils"
beeLogger "github.com/beego/bee/v2/logger"
)
// git tag
func GetTags(repoPath string, limit int) ([]string, error) {
repo, err := OpenRepository(repoPath)
if err != nil {
return nil, err
}
err = repo.Pull()
if err != nil {
return nil, err
}
list, err := repo.GetTags()
if err != nil {
return nil, err
}
if len(list) > limit {
list = list[0:limit]
}
return list, nil
}
// clone repo
func CloneRepo(url string, dst string) (err error) {
if utils.IsExist(dst) {
return errors.New("dst is not empty, dst is " + dst)
}
if !utils.Mkdir(dst) {
err = errors.New("make dir error, dst is " + dst)
return
}
beeLogger.Log.Info("start git clone from " + url + ", to dst at " + dst)
_, stderr, err := command.ExecCmd("git", "clone", url, dst)
if err != nil {
beeLogger.Log.Error("error git clone from " + url + ", to dst at " + dst)
return concatenateError(err, stderr)
}
return nil
}
// CloneORPullRepo
func CloneORPullRepo(url string, dst string) error {
if !utils.IsDir(dst) {
return CloneRepo(url, dst)
} else {
utils.Mkdir(dst)
repo, err := OpenRepository(dst)
if err != nil {
return err
}
return repo.Pull()
}
}
//
func CloneRepoBranch(branch string, url string, dst string) error {
_, stderr, err := command.ExecCmd("git", "clone", "-b", branch, url, dst)
if err != nil {
return concatenateError(err, stderr)
}
return nil
}
// SortTag ...
type SortTag struct {
data []string
}
// Len ...
func (t *SortTag) Len() int {
return len(t.data)
}
// Swap ...
func (t *SortTag) Swap(i, j int) {
t.data[i], t.data[j] = t.data[j], t.data[i]
}
// Less ...
func (t *SortTag) Less(i, j int) bool {
return command.VerCompare(t.data[i], t.data[j]) == 1
}
// Sort ...
func (t *SortTag) Sort() []string {
sort.Sort(t)
return t.data
}
// Repository ...
type Repository struct {
Path string
}
// OpenRepository ...
func OpenRepository(repoPath string) (*Repository, error) {
repoPath, err := filepath.Abs(repoPath)
if err != nil {
return nil, err
} else if !utils.IsDir(repoPath) {
return nil, errors.New("no such file or directory")
}
return &Repository{Path: repoPath}, nil
}
// 拉取代码
func (repo *Repository) Pull() error {
beeLogger.Log.Info("git pull " + repo.Path)
_, stderr, err := command.ExecCmdDir(repo.Path, "git", "pull")
if err != nil {
return concatenateError(err, stderr)
}
return nil
}
// 获取tag列表
func (repo *Repository) GetTags() ([]string, error) {
stdout, stderr, err := command.ExecCmdDir(repo.Path, "git", "tag", "-l")
if err != nil {
return nil, concatenateError(err, stderr)
}
tags := strings.Split(stdout, "\n")
tags = tags[:len(tags)-1]
so := &SortTag{data: tags}
return so.Sort(), nil
}
// 获取两个版本之间的修改日志
func (repo *Repository) GetChangeLogs(startVer, endVer string) ([]string, error) {
// git log --pretty=format:"%cd %cn: %s" --date=iso v1.8.0...v1.9.0
stdout, stderr, err := command.ExecCmdDir(repo.Path, "git", "log", "--pretty=format:%cd %cn: %s", "--date=iso", startVer+"..."+endVer)
if err != nil {
return nil, concatenateError(err, stderr)
}
logs := strings.Split(stdout, "\n")
return logs, nil
}
// 获取两个版本之间的差异文件列表
func (repo *Repository) GetChangeFiles(startVer, endVer string, onlyFile bool) ([]string, error) {
// git diff --name-status -b v1.8.0 v1.9.0
param := "--name-status"
if onlyFile {
param = "--name-only"
}
stdout, stderr, err := command.ExecCmdDir(repo.Path, "git", "diff", param, "-b", startVer, endVer)
if err != nil {
return nil, concatenateError(err, stderr)
}
lines := strings.Split(stdout, "\n")
return lines[:len(lines)-1], nil
}
// 获取两个版本间的新增或修改的文件数量
func (repo *Repository) GetDiffFileCount(startVer, endVer string) (int, error) {
cmd := "git diff --name-status -b " + startVer + " " + endVer + " |grep -v ^D |wc -l"
stdout, stderr, err := command.ExecCmdDir(repo.Path, "/bin/bash", "-c", cmd)
if err != nil {
return 0, concatenateError(err, stderr)
}
count, _ := strconv.Atoi(strings.TrimSpace(stdout))
return count, nil
}
// 导出版本到tar包
func (repo *Repository) Export(startVer, endVer string, filename string) error {
// git archive --format=tar.gz $endVer $(git diff --name-status -b $beginVer $endVer |grep -v ^D |grep -v Upgrade/ |awk '{print $2}') -o $tmpFile
cmd := ""
if startVer == "" {
cmd = "git archive --format=tar " + endVer + " | gzip > " + filename
} else {
cmd = "git archive --format=tar " + endVer + " $(dgit diff --name-status -b " + startVer + " " + endVer + "|grep -v ^D |awk '{print $2}') | gzip > " + filename
}
_, stderr, err := command.ExecCmdDir(repo.Path, "/bin/bash", "-c", cmd)
if err != nil {
return concatenateError(err, stderr)
}
return nil
}
func concatenateError(err error, stderr string) error {
if len(stderr) == 0 {
return err
}
return fmt.Errorf("%v: %s", err, stderr)
}

View File

@ -0,0 +1,22 @@
package system
import (
"os"
"os/user"
"path/filepath"
)
// Bee System Params ...
var (
Usr, _ = user.Current()
BeegoHome = filepath.Join(Usr.HomeDir, "/.beego")
CurrentDir = getCurrentDirectory()
GoPath = os.Getenv("GOPATH")
)
func getCurrentDirectory() string {
if dir, err := os.Getwd(); err == nil {
return dir
}
return ""
}

113
internal/pkg/utils/dsn.go Normal file
View File

@ -0,0 +1,113 @@
package utils
import (
"errors"
"net/url"
"strings"
)
// DSN ...
type DSN struct {
User string // Username
Passwd string // Password (requires User)
Net string // Network type
Addr string // Network address (requires Net)
DBName string // Database name
Params map[string]string // Connection parameters
}
var (
errInvalidDSNUnescaped = errors.New("invalid DSN: did you forget to escape a param value?")
errInvalidDSNAddr = errors.New("invalid DSN: network address not terminated (missing closing brace)")
errInvalidDSNNoSlash = errors.New("invalid DSN: missing the slash separating the database name")
)
// ParseDSN parses the DSN string to a Config
func ParseDSN(dsn string) (cfg *DSN, err error) {
// New config with some default values
cfg = new(DSN)
// [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN]
// Find the last '/' (since the password or the net addr might contain a '/')
foundSlash := false
for i := len(dsn) - 1; i >= 0; i-- {
if dsn[i] == '/' {
foundSlash = true
var j, k int
// left part is empty if i <= 0
if i > 0 {
// [username[:password]@][protocol[(address)]]
// Find the last '@' in dsn[:i]
for j = i; j >= 0; j-- {
if dsn[j] == '@' {
// username[:password]
// Find the first ':' in dsn[:j]
for k = 0; k < j; k++ {
if dsn[k] == ':' {
cfg.Passwd = dsn[k+1 : j]
break
}
}
cfg.User = dsn[:k]
break
}
}
// [protocol[(address)]]
// Find the first '(' in dsn[j+1:i]
for k = j + 1; k < i; k++ {
if dsn[k] == '(' {
// dsn[i-1] must be == ')' if an address is specified
if dsn[i-1] != ')' {
if strings.ContainsRune(dsn[k+1:i], ')') {
return nil, errInvalidDSNUnescaped
}
return nil, errInvalidDSNAddr
}
cfg.Addr = dsn[k+1 : i-1]
break
}
}
cfg.Net = dsn[j+1 : k]
}
// dbname[?param1=value1&...&paramN=valueN]
// Find the first '?' in dsn[i+1:]
for j = i + 1; j < len(dsn); j++ {
if dsn[j] == '?' {
if err = parseDSNParams(cfg, dsn[j+1:]); err != nil {
return
}
break
}
}
cfg.DBName = dsn[i+1 : j]
break
}
}
if !foundSlash && len(dsn) > 0 {
return nil, errInvalidDSNNoSlash
}
return
}
func parseDSNParams(cfg *DSN, params string) (err error) {
for _, v := range strings.Split(params, "&") {
param := strings.SplitN(v, "=", 2)
if len(param) != 2 {
continue
}
// lazy init
if cfg.Params == nil {
cfg.Params = make(map[string]string)
}
value := param[1]
if cfg.Params[param[0]], err = url.QueryUnescape(value); err != nil {
return
}
}
return
}

View File

@ -0,0 +1,38 @@
package utils
import (
"os"
beeLogger "github.com/beego/bee/v2/logger"
)
// Mkdir ...
func Mkdir(dir string) bool {
if dir == "" {
beeLogger.Log.Fatalf("The directory is empty")
return false
}
err := os.MkdirAll(dir, 0755)
if err != nil {
beeLogger.Log.Fatalf("Could not create the directory: %s", err)
return false
}
beeLogger.Log.Infof("Create %s Success!", dir)
return true
}
// IsDir ...
func IsDir(dir string) bool {
f, e := os.Stat(dir)
if e != nil {
return false
}
return f.IsDir()
}
// IsExist returns whether a file or directory exists.
func IsExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}

148
logger/colors/color.go Normal file
View File

@ -0,0 +1,148 @@
// Copyright 2013 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.
package colors
import (
"fmt"
"io"
)
type outputMode int
// DiscardNonColorEscSeq supports the divided color escape sequence.
// But non-color escape sequence is not output.
// Please use the OutputNonColorEscSeq If you want to output a non-color
// escape sequences such as ncurses. However, it does not support the divided
// color escape sequence.
const (
_ outputMode = iota
DiscardNonColorEscSeq
OutputNonColorEscSeq
)
// NewColorWriter creates and initializes a new ansiColorWriter
// using io.Writer w as its initial contents.
// In the console of Windows, which change the foreground and background
// colors of the text by the escape sequence.
// In the console of other systems, which writes to w all text.
func NewColorWriter(w io.Writer) io.Writer {
return NewModeColorWriter(w, DiscardNonColorEscSeq)
}
// NewModeColorWriter create and initializes a new ansiColorWriter
// by specifying the outputMode.
func NewModeColorWriter(w io.Writer, mode outputMode) io.Writer {
if _, ok := w.(*colorWriter); !ok {
return &colorWriter{
w: w,
mode: mode,
}
}
return w
}
func Bold(message string) string {
return fmt.Sprintf("\x1b[1m%s\x1b[0m", message)
}
// Black returns a black string
func Black(message string) string {
return fmt.Sprintf("\x1b[30m%s\x1b[0m", message)
}
// White returns a white string
func White(message string) string {
return fmt.Sprintf("\x1b[37m%s\x1b[0m", message)
}
// Cyan returns a cyan string
func Cyan(message string) string {
return fmt.Sprintf("\x1b[36m%s\x1b[0m", message)
}
// Blue returns a blue string
func Blue(message string) string {
return fmt.Sprintf("\x1b[34m%s\x1b[0m", message)
}
// Red returns a red string
func Red(message string) string {
return fmt.Sprintf("\x1b[31m%s\x1b[0m", message)
}
// Green returns a green string
func Green(message string) string {
return fmt.Sprintf("\x1b[32m%s\x1b[0m", message)
}
// Yellow returns a yellow string
func Yellow(message string) string {
return fmt.Sprintf("\x1b[33m%s\x1b[0m", message)
}
// Gray returns a gray string
func Gray(message string) string {
return fmt.Sprintf("\x1b[37m%s\x1b[0m", message)
}
// Magenta returns a magenta string
func Magenta(message string) string {
return fmt.Sprintf("\x1b[35m%s\x1b[0m", message)
}
// BlackBold returns a black Bold string
func BlackBold(message string) string {
return fmt.Sprintf("\x1b[30m%s\x1b[0m", Bold(message))
}
// WhiteBold returns a white Bold string
func WhiteBold(message string) string {
return fmt.Sprintf("\x1b[37m%s\x1b[0m", Bold(message))
}
// CyanBold returns a cyan Bold string
func CyanBold(message string) string {
return fmt.Sprintf("\x1b[36m%s\x1b[0m", Bold(message))
}
// BlueBold returns a blue Bold string
func BlueBold(message string) string {
return fmt.Sprintf("\x1b[34m%s\x1b[0m", Bold(message))
}
// RedBold returns a red Bold string
func RedBold(message string) string {
return fmt.Sprintf("\x1b[31m%s\x1b[0m", Bold(message))
}
// GreenBold returns a green Bold string
func GreenBold(message string) string {
return fmt.Sprintf("\x1b[32m%s\x1b[0m", Bold(message))
}
// YellowBold returns a yellow Bold string
func YellowBold(message string) string {
return fmt.Sprintf("\x1b[33m%s\x1b[0m", Bold(message))
}
// GrayBold returns a gray Bold string
func GrayBold(message string) string {
return fmt.Sprintf("\x1b[37m%s\x1b[0m", Bold(message))
}
// MagentaBold returns a magenta Bold string
func MagentaBold(message string) string {
return fmt.Sprintf("\x1b[35m%s\x1b[0m", Bold(message))
}

View File

@ -14,7 +14,7 @@
// +build !windows
package main
package colors
import "io"

View File

@ -14,7 +14,7 @@
// +build windows
package main
package colors
import (
"bytes"
@ -360,7 +360,7 @@ func isParameterChar(b byte) bool {
}
func (cw *colorWriter) Write(p []byte) (int, error) {
r, nw, first, last := 0, 0, 0, 0
var r, nw, first, last int
if cw.mode != DiscardNonColorEscSeq {
cw.state = outsideCsiCode
cw.resetBuffer()
@ -378,7 +378,6 @@ func (cw *colorWriter) Write(p []byte) (int, error) {
switch ch {
case firstCsiChar:
cw.paramStartBuf.WriteByte(ch)
break
case secondeCsiChar:
cw.paramStartBuf.WriteByte(ch)
cw.state = secondCsiCode
@ -419,7 +418,7 @@ func (cw *colorWriter) Write(p []byte) (int, error) {
}
if cw.mode != DiscardNonColorEscSeq || cw.state == outsideCsiCode {
nw, err = cw.w.Write(p[first:len(p)])
nw, err = cw.w.Write(p[first:])
r += nw
}

294
logger/logger.go Normal file
View File

@ -0,0 +1,294 @@
// Copyright 2013 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.
package beeLogger
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"sync"
"sync/atomic"
"text/template"
"time"
"github.com/beego/bee/v2/logger/colors"
)
var errInvalidLogLevel = errors.New("logger: invalid log level")
const (
levelDebug = iota
levelError
levelFatal
levelCritical
levelSuccess
levelWarn
levelInfo
levelHint
)
var (
sequenceNo uint64
instance *BeeLogger
once sync.Once
)
var debugMode = os.Getenv("DEBUG_ENABLED") == "1"
var logLevel = levelInfo
// BeeLogger logs logging records to the specified io.Writer
type BeeLogger struct {
mu sync.Mutex
output io.Writer
}
// LogRecord represents a log record and contains the timestamp when the record
// was created, an increasing id, level and the actual formatted log line.
type LogRecord struct {
ID string
Level string
Message string
Filename string
LineNo int
}
var Log = GetBeeLogger(os.Stdout)
var (
logRecordTemplate *template.Template
debugLogRecordTemplate *template.Template
)
// GetBeeLogger initializes the logger instance with a NewColorWriter output
// and returns a singleton
func GetBeeLogger(w io.Writer) *BeeLogger {
once.Do(func() {
var (
err error
simpleLogFormat = `{{Now "2006/01/02 15:04:05"}} {{.Level}}{{.ID}} {{.Message}}{{EndLine}}`
debugLogFormat = `{{Now "2006/01/02 15:04:05"}} {{.Level}}{{.ID}} {{.Filename}}:{{.LineNo}} {{.Message}}{{EndLine}}`
)
// Initialize and parse logging templates
funcs := template.FuncMap{
"Now": Now,
"EndLine": EndLine,
}
logRecordTemplate, err = template.New("simpleLogFormat").Funcs(funcs).Parse(simpleLogFormat)
if err != nil {
panic(err)
}
debugLogRecordTemplate, err = template.New("debugLogFormat").Funcs(funcs).Parse(debugLogFormat)
if err != nil {
panic(err)
}
instance = &BeeLogger{output: colors.NewColorWriter(w)}
})
return instance
}
// SetOutput sets the logger output destination
func (l *BeeLogger) SetOutput(w io.Writer) {
l.mu.Lock()
defer l.mu.Unlock()
l.output = colors.NewColorWriter(w)
}
// Now returns the current local time in the specified layout
func Now(layout string) string {
return time.Now().Format(layout)
}
// EndLine returns the a newline escape character
func EndLine() string {
return "\n"
}
func (l *BeeLogger) getLevelTag(level int) string {
switch level {
case levelFatal:
return "FATAL "
case levelSuccess:
return "SUCCESS "
case levelHint:
return "HINT "
case levelDebug:
return "DEBUG "
case levelInfo:
return "INFO "
case levelWarn:
return "WARN "
case levelError:
return "ERROR "
case levelCritical:
return "CRITICAL"
default:
panic(errInvalidLogLevel)
}
}
func (l *BeeLogger) getColorLevel(level int) string {
switch level {
case levelCritical:
return colors.RedBold(l.getLevelTag(level))
case levelFatal:
return colors.RedBold(l.getLevelTag(level))
case levelInfo:
return colors.BlueBold(l.getLevelTag(level))
case levelHint:
return colors.CyanBold(l.getLevelTag(level))
case levelDebug:
return colors.YellowBold(l.getLevelTag(level))
case levelError:
return colors.RedBold(l.getLevelTag(level))
case levelWarn:
return colors.YellowBold(l.getLevelTag(level))
case levelSuccess:
return colors.GreenBold(l.getLevelTag(level))
default:
panic(errInvalidLogLevel)
}
}
// mustLog logs the message according to the specified level and arguments.
// It panics in case of an error.
func (l *BeeLogger) mustLog(level int, message string, args ...interface{}) {
if level > logLevel {
return
}
// Acquire the lock
l.mu.Lock()
defer l.mu.Unlock()
// Create the logging record and pass into the output
record := LogRecord{
ID: fmt.Sprintf("%04d", atomic.AddUint64(&sequenceNo, 1)),
Level: l.getColorLevel(level),
Message: fmt.Sprintf(message, args...),
}
err := logRecordTemplate.Execute(l.output, record)
if err != nil {
panic(err)
}
}
// mustLogDebug logs a debug message only if debug mode
// is enabled. i.e. DEBUG_ENABLED="1"
func (l *BeeLogger) mustLogDebug(message string, file string, line int, args ...interface{}) {
if !debugMode {
return
}
// Change the output to Stderr
l.SetOutput(os.Stderr)
// Create the log record
record := LogRecord{
ID: fmt.Sprintf("%04d", atomic.AddUint64(&sequenceNo, 1)),
Level: l.getColorLevel(levelDebug),
Message: fmt.Sprintf(message, args...),
LineNo: line,
Filename: filepath.Base(file),
}
err := debugLogRecordTemplate.Execute(l.output, record)
if err != nil {
panic(err)
}
}
// Debug outputs a debug log message
func (l *BeeLogger) Debug(message string, file string, line int) {
l.mustLogDebug(message, file, line)
}
// Debugf outputs a formatted debug log message
func (l *BeeLogger) Debugf(message string, file string, line int, vars ...interface{}) {
l.mustLogDebug(message, file, line, vars...)
}
// Info outputs an information log message
func (l *BeeLogger) Info(message string) {
l.mustLog(levelInfo, message)
}
// Infof outputs a formatted information log message
func (l *BeeLogger) Infof(message string, vars ...interface{}) {
l.mustLog(levelInfo, message, vars...)
}
// Warn outputs a warning log message
func (l *BeeLogger) Warn(message string) {
l.mustLog(levelWarn, message)
}
// Warnf outputs a formatted warning log message
func (l *BeeLogger) Warnf(message string, vars ...interface{}) {
l.mustLog(levelWarn, message, vars...)
}
// Error outputs an error log message
func (l *BeeLogger) Error(message string) {
l.mustLog(levelError, message)
}
// Errorf outputs a formatted error log message
func (l *BeeLogger) Errorf(message string, vars ...interface{}) {
l.mustLog(levelError, message, vars...)
}
// Fatal outputs a fatal log message and exists
func (l *BeeLogger) Fatal(message string) {
l.mustLog(levelFatal, message)
os.Exit(255)
}
// Fatalf outputs a formatted log message and exists
func (l *BeeLogger) Fatalf(message string, vars ...interface{}) {
l.mustLog(levelFatal, message, vars...)
os.Exit(255)
}
// Success outputs a success log message
func (l *BeeLogger) Success(message string) {
l.mustLog(levelSuccess, message)
}
// Successf outputs a formatted success log message
func (l *BeeLogger) Successf(message string, vars ...interface{}) {
l.mustLog(levelSuccess, message, vars...)
}
// Hint outputs a hint log message
func (l *BeeLogger) Hint(message string) {
l.mustLog(levelHint, message)
}
// Hintf outputs a formatted hint log message
func (l *BeeLogger) Hintf(message string, vars ...interface{}) {
l.mustLog(levelHint, message, vars...)
}
// Critical outputs a critical log message
func (l *BeeLogger) Critical(message string) {
l.mustLog(levelCritical, message)
}
// Criticalf outputs a formatted critical log message
func (l *BeeLogger) Criticalf(message string, vars ...interface{}) {
l.mustLog(levelCritical, message, vars...)
}

67
main.go Normal file
View File

@ -0,0 +1,67 @@
// Copyright 2013 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.
package main
import (
"flag"
"log"
"os"
"github.com/beego/bee/v2/cmd"
"github.com/beego/bee/v2/cmd/commands"
"github.com/beego/bee/v2/config"
"github.com/beego/bee/v2/utils"
)
func main() {
utils.NoticeUpdateBee()
flag.Usage = cmd.Usage
flag.Parse()
log.SetFlags(0)
args := flag.Args()
if len(args) < 1 {
cmd.Usage()
os.Exit(2)
return
}
if args[0] == "help" {
cmd.Help(args[1:])
return
}
for _, c := range commands.AvailableCommands {
if c.Name() == args[0] && c.Run != nil {
c.Flag.Usage = func() { c.Usage() }
if c.CustomFlags {
args = args[1:]
} else {
c.Flag.Parse(args[1:])
args = c.Flag.Args()
}
if c.PreRun != nil {
c.PreRun(c, args)
}
config.LoadConfig()
os.Exit(c.Run(c, args))
return
}
}
utils.PrintErrorAndExit("Unknown subcommand", cmd.ErrorTemplate)
}

206
run.go
View File

@ -1,206 +0,0 @@
// Copyright 2013 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.
package main
import (
"fmt"
"io/ioutil"
"os"
path "path/filepath"
"runtime"
"strings"
)
var cmdRun = &Command{
UsageLine: "run [appname] [watchall] [-main=*.go] [-downdoc=true] [-gendoc=true] [-vendor=true] [-e=folderToExclude] [-tags=goBuildTags]",
Short: "run the app and start a Web server for development",
Long: `
Run command will supervise the file system of the beego project using inotify,
it will recompile and restart the app after any modifications.
`,
}
var (
mainFiles ListOpts
downdoc docValue
gendoc docValue
// The flags list of the paths excluded from watching
excludedPaths strFlags
// Pass through to -tags arg of "go build"
buildTags string
// Application path
currpath string
// Application name
appname string
// Channel to signal an Exit
exit chan bool
// Flag to watch the vendor folder
vendorWatch bool
// Current user workspace
currentGoPath string
)
func init() {
cmdRun.Run = runApp
cmdRun.Flag.Var(&mainFiles, "main", "specify main go files")
cmdRun.Flag.Var(&gendoc, "gendoc", "auto generate the docs")
cmdRun.Flag.Var(&downdoc, "downdoc", "auto download swagger file when not exist")
cmdRun.Flag.Var(&excludedPaths, "e", "Excluded paths[].")
cmdRun.Flag.BoolVar(&vendorWatch, "vendor", false, "Watch vendor folder")
cmdRun.Flag.StringVar(&buildTags, "tags", "", "Build tags (https://golang.org/pkg/go/build/)")
exit = make(chan bool)
}
func runApp(cmd *Command, args []string) int {
ShowShortVersionBanner()
if len(args) == 0 || args[0] == "watchall" {
currpath, _ = os.Getwd()
if found, _gopath, _ := SearchGOPATHs(currpath); found {
appname = path.Base(currpath)
currentGoPath = _gopath
} else {
exitPrint(fmt.Sprintf("Bee does not support non Beego project: %s", currpath))
}
ColorLog("[INFO] Using '%s' as 'appname'\n", appname)
} else {
// Check if passed Bee application path/name exists in the GOPATH(s)
if found, _gopath, _path := SearchGOPATHs(args[0]); found {
currpath = _path
currentGoPath = _gopath
appname = path.Base(currpath)
} else {
panic(fmt.Sprintf("No Beego application '%s' found in your GOPATH", args[0]))
}
ColorLog("[INFO] Using '%s' as 'appname'\n", appname)
if strings.HasSuffix(appname, ".go") && isExist(currpath) {
ColorLog("[WARN] The appname is in conflict with currpath's file, do you want to build appname as %s\n", appname)
ColorLog("[INFO] Do you want to overwrite it? [yes|no]] ")
if !askForConfirmation() {
return 0
}
}
}
Debugf("current path:%s\n", currpath)
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
var paths []string
readAppDirectories(currpath, &paths)
// Because monitor files has some issues, we watch current directory
// and ignore non-go files.
for _, p := range conf.DirStruct.Others {
paths = append(paths, strings.Replace(p, "$GOPATH", currentGoPath, -1))
}
files := []string{}
for _, arg := range mainFiles {
if len(arg) > 0 {
files = append(files, arg)
}
}
if downdoc == "true" {
if _, err := os.Stat(path.Join(currpath, "swagger", "index.html")); err != nil {
if os.IsNotExist(err) {
downloadFromURL(swaggerlink, "swagger.zip")
unzipAndDelete("swagger.zip")
}
}
}
if gendoc == "true" {
NewWatcher(paths, files, true)
Autobuild(files, true)
} else {
NewWatcher(paths, files, false)
Autobuild(files, false)
}
for {
select {
case <-exit:
runtime.Goexit()
}
}
}
func readAppDirectories(directory string, paths *[]string) {
fileInfos, err := ioutil.ReadDir(directory)
if err != nil {
return
}
useDirectory := false
for _, fileInfo := range fileInfos {
if strings.HasSuffix(fileInfo.Name(), "docs") {
continue
}
if strings.HasSuffix(fileInfo.Name(), "swagger") {
continue
}
if !vendorWatch && strings.HasSuffix(fileInfo.Name(), "vendor") {
continue
}
if isExcluded(path.Join(directory, fileInfo.Name())) {
continue
}
if fileInfo.IsDir() == true && fileInfo.Name()[0] != '.' {
readAppDirectories(directory+"/"+fileInfo.Name(), paths)
continue
}
if useDirectory == true {
continue
}
if path.Ext(fileInfo.Name()) == ".go" {
*paths = append(*paths, directory)
useDirectory = true
}
}
return
}
// If a file is excluded
func isExcluded(filePath string) bool {
for _, p := range excludedPaths {
absP, err := path.Abs(p)
if err != nil {
ColorLog("[ERROR] Can not get absolute path of [ %s ]\n", p)
continue
}
absFilePath, err := path.Abs(filePath)
if err != nil {
ColorLog("[ERROR] Can not get absolute path of [ %s ]\n", filePath)
break
}
if strings.HasPrefix(absFilePath, absP) {
ColorLog("[INFO] Excluding from watching [ %s ]\n", filePath)
return true
}
}
return false
}

View File

@ -1,151 +0,0 @@
// Copyright 2013 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.
package main
import (
"archive/zip"
"fmt"
"io"
"log"
"net/http"
"os"
"strings"
)
var cmdRundocs = &Command{
UsageLine: "rundocs [-isDownload=true] [-docport=8888]",
Short: "rundocs will run the docs server,default is 8089",
Long: `
-d meaning will download the docs file from github
-p meaning server the Server on which port, default is 8089
`,
}
var (
swaggerVersion = "2"
swaggerlink = "https://github.com/beego/swagger/archive/v" + swaggerVersion + ".zip"
)
type docValue string
func (d *docValue) String() string {
return fmt.Sprint(*d)
}
func (d *docValue) Set(value string) error {
*d = docValue(value)
return nil
}
var isDownload docValue
var docport docValue
func init() {
cmdRundocs.Run = runDocs
cmdRundocs.Flag.Var(&isDownload, "isDownload", "weather download the Swagger Docs")
cmdRundocs.Flag.Var(&docport, "docport", "doc server port")
}
func runDocs(cmd *Command, args []string) int {
if isDownload == "true" {
downloadFromURL(swaggerlink, "swagger.zip")
err := unzipAndDelete("swagger.zip")
if err != nil {
fmt.Println("has err exet unzipAndDelete", err)
}
}
if docport == "" {
docport = "8089"
}
if _, err := os.Stat("swagger"); err != nil && os.IsNotExist(err) {
fmt.Println("there's no swagger, please use bee rundocs -isDownload=true downlaod first")
os.Exit(2)
}
fmt.Println("start the docs server on: http://127.0.0.1:" + docport)
log.Fatal(http.ListenAndServe(":"+string(docport), http.FileServer(http.Dir("swagger"))))
return 0
}
func downloadFromURL(url, fileName string) {
var down bool
if fd, err := os.Stat(fileName); err != nil && os.IsNotExist(err) {
down = true
} else if fd.Size() == int64(0) {
down = true
} else {
ColorLog("[%s] Filename %s already exist\n", INFO, fileName)
return
}
if down {
ColorLog("[%s]Downloading %s to %s\n", SUCC, url, fileName)
output, err := os.Create(fileName)
if err != nil {
ColorLog("[%s]Error while creating %s: %s\n", ERRO, fileName, err)
return
}
defer output.Close()
response, err := http.Get(url)
if err != nil {
ColorLog("[%s]Error while downloading %s:%s\n", ERRO, url, err)
return
}
defer response.Body.Close()
n, err := io.Copy(output, response.Body)
if err != nil {
ColorLog("[%s]Error while downloading %s:%s\n", ERRO, url, err)
return
}
ColorLog("[%s] %d bytes downloaded.\n", SUCC, n)
}
}
func unzipAndDelete(src string) error {
ColorLog("[%s]start to unzip file from %s\n", INFO, src)
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer r.Close()
rp := strings.NewReplacer("swagger-"+swaggerVersion, "swagger")
for _, f := range r.File {
rc, err := f.Open()
if err != nil {
return err
}
defer rc.Close()
fname := rp.Replace(f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fname, f.Mode())
} else {
f, err := os.OpenFile(
fname, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer f.Close()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
}
ColorLog("[%s]Start delete src file %s\n", INFO, src)
return os.RemoveAll(src)
}

7
scripts/quickstart.sh Normal file
View File

@ -0,0 +1,7 @@
#!/bin/sh
export GO111MODULE=on
go get github.com/beego/bee/v2@latest
bee new hello
cd hello
bee run

1
staticcheck.ignore Normal file
View File

@ -0,0 +1 @@
github.com/beego/bee/v2/generate/swaggergen/*.go:SA1024

101
test.go
View File

@ -1,101 +0,0 @@
// Copyright 2013 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.
package main
import (
"os"
"os/exec"
path "path/filepath"
"time"
_ "github.com/smartystreets/goconvey/convey"
)
var cmdTest = &Command{
UsageLine: "test [appname]",
Short: "test the app",
Long: ``,
}
func init() {
cmdTest.Run = testApp
}
func safePathAppend(arr []string, paths ...string) []string {
for _, path := range paths {
if pathExists(path) {
arr = append(arr, path)
}
}
return arr
}
func pathExists(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
var started = make(chan bool)
func testApp(cmd *Command, args []string) int {
if len(args) != 1 {
ColorLog("[ERRO] Cannot start running[ %s ]\n",
"argument 'appname' is missing")
os.Exit(2)
}
crupath, _ := os.Getwd()
Debugf("current path:%s\n", crupath)
err := loadConfig()
if err != nil {
ColorLog("[ERRO] Fail to parse bee.json[ %s ]\n", err)
}
var paths []string
readAppDirectories(crupath, &paths)
NewWatcher(paths, nil, false)
appname = args[0]
for {
select {
case <-started:
runTest()
}
}
}
func runTest() {
ColorLog("[INFO] Start testing...\n")
time.Sleep(time.Second * 1)
crupwd, _ := os.Getwd()
testDir := path.Join(crupwd, "tests")
if pathExists(testDir) {
os.Chdir(testDir)
}
var err error
icmd := exec.Command("go", "test")
icmd.Stdout = os.Stdout
icmd.Stderr = os.Stderr
ColorLog("[TRAC] ============== Test Begin ===================\n")
err = icmd.Run()
ColorLog("[TRAC] ============== Test End ===================\n")
if err != nil {
ColorLog("[ERRO] ============== Test failed ===================\n")
ColorLog("[ERRO] %s", err)
return
}
ColorLog("[SUCC] Test finish\n")
}

View File

@ -1,28 +0,0 @@
package router
import (
"github.com/astaxie/beego"
)
type Router struct {
beego.Controller
}
func (r *Router) Get() {
}
func (r *Router) Post() {
}
type Controller struct {
}
func (c *Controller) Put() {
}
func (c *Controller) Delete() {
}

297
util.go
View File

@ -1,297 +0,0 @@
// Copyright 2013 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.
package main
import (
"log"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"path"
"fmt"
)
// Go is a basic promise implementation: it wraps calls a function in a goroutine
// and returns a channel which will later return the function's return value.
func Go(f func() error) chan error {
ch := make(chan error)
go func() {
ch <- f()
}()
return ch
}
// if os.env DEBUG set, debug is on
func Debugf(format string, a ...interface{}) {
if os.Getenv("DEBUG") != "" {
_, file, line, ok := runtime.Caller(1)
if !ok {
file = "<unknown>"
line = -1
} else {
file = filepath.Base(file)
}
fmt.Fprintf(os.Stderr, fmt.Sprintf("[debug] %s:%d %s\n", file, line, format), a...)
}
}
const (
Gray = uint8(iota + 90)
Red
Green
Yellow
Blue
Magenta
//NRed = uint8(31) // Normal
EndColor = "\033[0m"
INFO = "INFO"
TRAC = "TRAC"
ERRO = "ERRO"
WARN = "WARN"
SUCC = "SUCC"
)
// ColorLog colors log and print to stdout.
// See color rules in function 'ColorLogS'.
func ColorLog(format string, a ...interface{}) {
fmt.Print(ColorLogS(format, a...))
}
// ColorLogS colors log and return colored content.
// Log format: <level> <content [highlight][path]> [ error ].
// Level: TRAC -> blue; ERRO -> red; WARN -> Magenta; SUCC -> green; others -> default.
// Content: default; path: yellow; error -> red.
// Level has to be surrounded by "[" and "]".
// Highlights have to be surrounded by "# " and " #"(space), "#" will be deleted.
// Paths have to be surrounded by "( " and " )"(space).
// Errors have to be surrounded by "[ " and " ]"(space).
// Note: it hasn't support windows yet, contribute is welcome.
func ColorLogS(format string, a ...interface{}) string {
log := fmt.Sprintf(format, a...)
var clog string
if runtime.GOOS != "windows" {
// Level.
i := strings.Index(log, "]")
if log[0] == '[' && i > -1 {
clog += "[" + getColorLevel(log[1:i]) + "]"
}
log = log[i+1:]
// Error.
log = strings.Replace(log, "[ ", fmt.Sprintf("[\033[%dm", Red), -1)
log = strings.Replace(log, " ]", EndColor+"]", -1)
// Path.
log = strings.Replace(log, "( ", fmt.Sprintf("(\033[%dm", Yellow), -1)
log = strings.Replace(log, " )", EndColor+")", -1)
// Highlights.
log = strings.Replace(log, "# ", fmt.Sprintf("\033[%dm", Gray), -1)
log = strings.Replace(log, " #", EndColor, -1)
log = clog + log
} else {
// Level.
i := strings.Index(log, "]")
if log[0] == '[' && i > -1 {
clog += "[" + log[1:i] + "]"
}
log = log[i+1:]
// Error.
log = strings.Replace(log, "[ ", "[", -1)
log = strings.Replace(log, " ]", "]", -1)
// Path.
log = strings.Replace(log, "( ", "(", -1)
log = strings.Replace(log, " )", ")", -1)
// Highlights.
log = strings.Replace(log, "# ", "", -1)
log = strings.Replace(log, " #", "", -1)
log = clog + log
}
return time.Now().Format("2006/01/02 15:04:05 ") + log
}
// getColorLevel returns colored level string by given level.
func getColorLevel(level string) string {
level = strings.ToUpper(level)
switch level {
case INFO:
return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level)
case TRAC:
return fmt.Sprintf("\033[%dm%s\033[0m", Blue, level)
case ERRO:
return fmt.Sprintf("\033[%dm%s\033[0m", Red, level)
case WARN:
return fmt.Sprintf("\033[%dm%s\033[0m", Magenta, level)
case SUCC:
return fmt.Sprintf("\033[%dm%s\033[0m", Green, level)
default:
return level
}
}
// IsExist returns whether a file or directory exists.
func isExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
// GetGOPATHs returns all paths in GOPATH variable.
func GetGOPATHs() []string {
gopath := os.Getenv("GOPATH")
var paths []string
if runtime.GOOS == "windows" {
gopath = strings.Replace(gopath, "\\", "/", -1)
paths = strings.Split(gopath, ";")
} else {
paths = strings.Split(gopath, ":")
}
return paths
}
func SearchGOPATHs(app string) (bool, string, string) {
gps := GetGOPATHs()
if len(gps) == 0 {
ColorLog("[ERRO] Fail to start [ %s ]\n", "GOPATH environment variable is not set or empty")
os.Exit(2)
}
// Lookup the application inside the user workspace(s)
for _, gopath := range gps {
var currentPath string
if !strings.Contains(app, "src") {
gopathsrc := path.Join(gopath, "src")
currentPath = path.Join(gopathsrc, app)
} else {
currentPath = app
}
if isExist(currentPath) {
if !isBeegoProject(currentPath) {
continue
}
return true, gopath, currentPath
}
}
return false, "", ""
}
// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
// confirmations. If the input is not recognized, it will ask again. The function does not return
// until it gets a valid response from the user. Typically, you should use fmt to print out a question
// before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)")
func askForConfirmation() bool {
var response string
_, err := fmt.Scanln(&response)
if err != nil {
log.Fatal(err)
}
okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
nokayResponses := []string{"n", "N", "no", "No", "NO"}
if containsString(okayResponses, response) {
return true
} else if containsString(nokayResponses, response) {
return false
} else {
fmt.Println("Please type yes or no and then press enter:")
return askForConfirmation()
}
}
func containsString(slice []string, element string) bool {
for _, elem := range slice {
if elem == element {
return true
}
}
return false
}
// snake string, XxYy to xx_yy
func snakeString(s string) string {
data := make([]byte, 0, len(s)*2)
j := false
num := len(s)
for i := 0; i < num; i++ {
d := s[i]
if i > 0 && d >= 'A' && d <= 'Z' && j {
data = append(data, '_')
}
if d != '_' {
j = true
}
data = append(data, d)
}
return strings.ToLower(string(data[:len(data)]))
}
func camelString(s string) string {
data := make([]byte, 0, len(s))
j := false
k := false
num := len(s) - 1
for i := 0; i <= num; i++ {
d := s[i]
if k == false && d >= 'A' && d <= 'Z' {
k = true
}
if d >= 'a' && d <= 'z' && (j || k == false) {
d = d - 32
j = false
k = true
}
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
j = true
continue
}
data = append(data, d)
}
return string(data[:len(data)])
}
// The string flag list, implemented flag.Value interface
type strFlags []string
func (s *strFlags) String() string {
return fmt.Sprintf("%s", *s)
}
func (s *strFlags) Set(value string) error {
*s = append(*s, value)
return nil
}
// CloseFile attempts to close the passed file
// or panics with the actual error
func CloseFile(f *os.File) {
if err := f.Close(); err != nil {
panic(err)
}
}

14
utils/doc_value.go Normal file
View File

@ -0,0 +1,14 @@
package utils
import "fmt"
type DocValue string
func (d *DocValue) String() string {
return fmt.Sprint(*d)
}
func (d *DocValue) Set(value string) error {
*d = DocValue(value)
return nil
}

14
utils/list_opts.go Normal file
View File

@ -0,0 +1,14 @@
package utils
import "fmt"
type ListOpts []string
func (opts *ListOpts) String() string {
return fmt.Sprint(*opts)
}
func (opts *ListOpts) Set(value string) error {
*opts = append(*opts, value)
return nil
}

84
utils/notification.go Normal file
View File

@ -0,0 +1,84 @@
// Copyright 2017 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.
package utils
import (
"fmt"
"os/exec"
"strconv"
"strings"
"runtime"
"github.com/beego/bee/v2/config"
)
const appName = "Beego"
func Notify(text, title string) {
if !config.Conf.EnableNotification {
return
}
switch runtime.GOOS {
case "darwin":
osxNotify(text, title)
case "linux":
linuxNotify(text, title)
case "windows":
windowsNotify(text, title)
}
}
func osxNotify(text, title string) {
var cmd *exec.Cmd
if existTerminalNotifier() {
cmd = exec.Command("terminal-notifier", "-title", appName, "-message", text, "-subtitle", title)
} else if MacOSVersionSupport() {
notification := fmt.Sprintf("display notification \"%s\" with title \"%s\" subtitle \"%s\"", text, appName, title)
cmd = exec.Command("osascript", "-e", notification)
} else {
cmd = exec.Command("growlnotify", "-n", appName, "-m", title)
}
cmd.Run()
}
func windowsNotify(text, title string) {
exec.Command("growlnotify", "/i:", "", "/t:", title, text).Run()
}
func linuxNotify(text, title string) {
exec.Command("notify-send", "-i", "", title, text).Run()
}
func existTerminalNotifier() bool {
cmd := exec.Command("which", "terminal-notifier")
err := cmd.Start()
if err != nil {
return false
}
err = cmd.Wait()
return err != nil
}
func MacOSVersionSupport() bool {
cmd := exec.Command("sw_vers", "-productVersion")
check, _ := cmd.Output()
version := strings.Split(string(check), ".")
major, _ := strconv.Atoi(version[0])
minor, _ := strconv.Atoi(version[1])
if major < 10 || (major == 10 && minor < 9) {
return false
}
return true
}

15
utils/str_flag.go Normal file
View File

@ -0,0 +1,15 @@
package utils
import "fmt"
// The string flag list, implemented flag.Value interface
type StrFlags []string
func (s *StrFlags) String() string {
return fmt.Sprintf("%s", *s)
}
func (s *StrFlags) Set(value string) error {
*s = append(*s, value)
return nil
}

652
utils/utils.go Normal file
View File

@ -0,0 +1,652 @@
// Copyright 2013 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.
package utils
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"os"
"os/exec"
"path"
"path/filepath"
"regexp"
"runtime"
"strconv"
"strings"
"text/template"
"time"
"unicode"
"github.com/beego/bee/v2/config"
"github.com/beego/bee/v2/internal/pkg/system"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
)
type tagName struct {
Name string `json:"name"`
}
type Repos struct {
UpdatedAt time.Time `json:"updated_at"`
PushedAt time.Time `json:"pushed_at"`
}
type Releases struct {
PublishedAt time.Time `json:"published_at"`
TagName string `json:"tag_name"`
}
func GetBeeWorkPath() string {
curpath, err := os.Getwd()
if err != nil {
panic(err)
}
return curpath
}
// Go is a basic promise implementation: it wraps calls a function in a goroutine
// and returns a channel which will later return the function's return value.
func Go(f func() error) chan error {
ch := make(chan error)
go func() {
ch <- f()
}()
return ch
}
// IsExist returns whether a file or directory exists.
func IsExist(path string) bool {
_, err := os.Stat(path)
return err == nil || os.IsExist(err)
}
// GetGOPATHs returns all paths in GOPATH variable.
func GetGOPATHs() []string {
gopath := os.Getenv("GOPATH")
if gopath == "" && strings.Compare(runtime.Version(), "go1.8") >= 0 {
gopath = defaultGOPATH()
}
return filepath.SplitList(gopath)
}
// IsInGOPATH checks whether the path is inside of any GOPATH or not
func IsInGOPATH(thePath string) bool {
for _, gopath := range GetGOPATHs() {
if strings.Contains(thePath, filepath.Join(gopath, "src")) {
return true
}
}
return false
}
// IsBeegoProject checks whether the current path is a Beego application or not
func IsBeegoProject(thePath string) bool {
mainFiles := []string{}
hasBeegoRegex := regexp.MustCompile(`(?s)package main.*?import.*?\(.*?github.com/beego/beego/v2".*?\).*func main()`)
c := make(chan error)
// Walk the application path tree to look for main files.
// Main files must satisfy the 'hasBeegoRegex' regular expression.
go func() {
filepath.Walk(thePath, func(fpath string, f os.FileInfo, err error) error {
if err != nil {
return nil
}
// Skip sub-directories
if !f.IsDir() {
var data []byte
data, err = ioutil.ReadFile(fpath)
if err != nil {
c <- err
return nil
}
if len(hasBeegoRegex.Find(data)) > 0 {
mainFiles = append(mainFiles, fpath)
}
}
return nil
})
close(c)
}()
if err := <-c; err != nil {
beeLogger.Log.Fatalf("Unable to walk '%s' tree: %s", thePath, err)
}
if len(mainFiles) > 0 {
return true
}
return false
}
// SearchGOPATHs searchs the user GOPATH(s) for the specified application name.
// It returns a boolean, the application's GOPATH and its full path.
func SearchGOPATHs(app string) (bool, string, string) {
gps := GetGOPATHs()
if len(gps) == 0 {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
// Lookup the application inside the user workspace(s)
for _, gopath := range gps {
var currentPath string
if !strings.Contains(app, "src") {
gopathsrc := path.Join(gopath, "src")
currentPath = path.Join(gopathsrc, app)
} else {
currentPath = app
}
if IsExist(currentPath) {
return true, gopath, currentPath
}
}
return false, "", ""
}
// askForConfirmation uses Scanln to parse user input. A user must type in "yes" or "no" and
// then press enter. It has fuzzy matching, so "y", "Y", "yes", "YES", and "Yes" all count as
// confirmations. If the input is not recognized, it will ask again. The function does not return
// until it gets a valid response from the user. Typically, you should use fmt to print out a question
// before calling askForConfirmation. E.g. fmt.Println("WARNING: Are you sure? (yes/no)")
func AskForConfirmation() bool {
var response string
_, err := fmt.Scanln(&response)
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
okayResponses := []string{"y", "Y", "yes", "Yes", "YES"}
nokayResponses := []string{"n", "N", "no", "No", "NO"}
if containsString(okayResponses, response) {
return true
} else if containsString(nokayResponses, response) {
return false
} else {
fmt.Println("Please type yes or no and then press enter:")
return AskForConfirmation()
}
}
func containsString(slice []string, element string) bool {
for _, elem := range slice {
if elem == element {
return true
}
}
return false
}
// snake string, XxYy to xx_yy
func SnakeString(s string) string {
data := make([]byte, 0, len(s)*2)
j := false
num := len(s)
for i := 0; i < num; i++ {
d := s[i]
if i > 0 && d >= 'A' && d <= 'Z' && j {
data = append(data, '_')
}
if d != '_' {
j = true
}
data = append(data, d)
}
return strings.ToLower(string(data[:]))
}
func CamelString(s string) string {
data := make([]byte, 0, len(s))
j := false
k := false
num := len(s) - 1
for i := 0; i <= num; i++ {
d := s[i]
if !k && d >= 'A' && d <= 'Z' {
k = true
}
if d >= 'a' && d <= 'z' && (j || !k) {
d = d - 32
j = false
k = true
}
if k && d == '_' && num > i && s[i+1] >= 'a' && s[i+1] <= 'z' {
j = true
continue
}
data = append(data, d)
}
return string(data[:])
}
// camelCase converts a _ delimited string to camel case
// e.g. very_important_person => VeryImportantPerson
func CamelCase(in string) string {
tokens := strings.Split(in, "_")
for i := range tokens {
tokens[i] = strings.Title(strings.Trim(tokens[i], " "))
}
return strings.Join(tokens, "")
}
// formatSourceCode formats source files
func FormatSourceCode(filename string) {
cmd := exec.Command("gofmt", "-w", filename)
if err := cmd.Run(); err != nil {
beeLogger.Log.Warnf("Error while running gofmt: %s", err)
}
}
// CloseFile attempts to close the passed file
// or panics with the actual error
func CloseFile(f *os.File) {
err := f.Close()
MustCheck(err)
}
// MustCheck panics when the error is not nil
func MustCheck(err error) {
if err != nil {
panic(err)
}
}
// WriteToFile creates a file and writes content to it
func WriteToFile(filename, content string) {
f, err := os.Create(filename)
MustCheck(err)
defer CloseFile(f)
_, err = f.WriteString(content)
MustCheck(err)
}
// __FILE__ returns the file name in which the function was invoked
func FILE() string {
_, file, _, _ := runtime.Caller(1)
return file
}
// __LINE__ returns the line number at which the function was invoked
func LINE() int {
_, _, line, _ := runtime.Caller(1)
return line
}
// BeeFuncMap returns a FuncMap of functions used in different templates.
func BeeFuncMap() template.FuncMap {
return template.FuncMap{
"trim": strings.TrimSpace,
"bold": colors.Bold,
"headline": colors.MagentaBold,
"foldername": colors.RedBold,
"endline": EndLine,
"tmpltostr": TmplToString,
}
}
// TmplToString parses a text template and return the result as a string.
func TmplToString(tmpl string, data interface{}) string {
t := template.New("tmpl").Funcs(BeeFuncMap())
template.Must(t.Parse(tmpl))
var doc bytes.Buffer
err := t.Execute(&doc, data)
MustCheck(err)
return doc.String()
}
// EndLine returns the a newline escape character
func EndLine() string {
return "\n"
}
func Tmpl(text string, data interface{}) {
output := colors.NewColorWriter(os.Stderr)
t := template.New("Usage").Funcs(BeeFuncMap())
template.Must(t.Parse(text))
err := t.Execute(output, data)
if err != nil {
beeLogger.Log.Error(err.Error())
}
}
func CheckEnv(appname string) (apppath, packpath string, err error) {
gps := GetGOPATHs()
if len(gps) == 0 {
beeLogger.Log.Error("if you want new a go module project,please add param `-gopath=false`.")
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
currpath, _ := os.Getwd()
currpath = filepath.Join(currpath, appname)
for _, gpath := range gps {
gsrcpath := filepath.Join(gpath, "src")
if strings.HasPrefix(strings.ToLower(currpath), strings.ToLower(gsrcpath)) {
packpath = strings.Replace(currpath[len(gsrcpath)+1:], string(filepath.Separator), "/", -1)
return currpath, packpath, nil
}
}
// In case of multiple paths in the GOPATH, by default
// we use the first path
gopath := gps[0]
beeLogger.Log.Warn("You current workdir is not inside $GOPATH/src.")
beeLogger.Log.Debugf("GOPATH: %s", FILE(), LINE(), gopath)
gosrcpath := filepath.Join(gopath, "src")
apppath = filepath.Join(gosrcpath, appname)
if _, e := os.Stat(apppath); !os.IsNotExist(e) {
err = fmt.Errorf("cannot create application without removing '%s' first", apppath)
beeLogger.Log.Errorf("Path '%s' already exists", apppath)
return
}
packpath = strings.Join(strings.Split(apppath[len(gosrcpath)+1:], string(filepath.Separator)), "/")
return
}
func PrintErrorAndExit(message, errorTemplate string) {
Tmpl(fmt.Sprintf(errorTemplate, message), nil)
os.Exit(2)
}
// GoCommand executes the passed command using Go tool
func GoCommand(command string, args ...string) error {
allargs := []string{command}
allargs = append(allargs, args...)
goBuild := exec.Command("go", allargs...)
goBuild.Stderr = os.Stderr
return goBuild.Run()
}
// SplitQuotedFields is like strings.Fields but ignores spaces
// inside areas surrounded by single quotes.
// To specify a single quote use backslash to escape it: '\''
func SplitQuotedFields(in string) []string {
type stateEnum int
const (
inSpace stateEnum = iota
inField
inQuote
inQuoteEscaped
)
state := inSpace
r := []string{}
var buf bytes.Buffer
for _, ch := range in {
switch state {
case inSpace:
if ch == '\'' {
state = inQuote
} else if !unicode.IsSpace(ch) {
buf.WriteRune(ch)
state = inField
}
case inField:
if ch == '\'' {
state = inQuote
} else if unicode.IsSpace(ch) {
r = append(r, buf.String())
buf.Reset()
} else {
buf.WriteRune(ch)
}
case inQuote:
if ch == '\'' {
state = inField
} else if ch == '\\' {
state = inQuoteEscaped
} else {
buf.WriteRune(ch)
}
case inQuoteEscaped:
buf.WriteRune(ch)
state = inQuote
}
}
if buf.Len() != 0 {
r = append(r, buf.String())
}
return r
}
// GetFileModTime returns unix timestamp of `os.File.ModTime` for the given path.
func GetFileModTime(path string) int64 {
path = strings.Replace(path, "\\", "/", -1)
f, err := os.Open(path)
if err != nil {
beeLogger.Log.Errorf("Failed to open file on '%s': %s", path, err)
return time.Now().Unix()
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
beeLogger.Log.Errorf("Failed to get file stats: %s", err)
return time.Now().Unix()
}
return fi.ModTime().Unix()
}
func defaultGOPATH() string {
env := "HOME"
if runtime.GOOS == "windows" {
env = "USERPROFILE"
} else if runtime.GOOS == "plan9" {
env = "home"
}
if home := os.Getenv(env); home != "" {
return filepath.Join(home, "go")
}
return ""
}
func GetGoVersionSkipMinor() string {
strArray := strings.Split(runtime.Version()[2:], `.`)
return strArray[0] + `.` + strArray[1]
}
func IsGOMODULE() bool {
if combinedOutput, e := exec.Command(`go`, `env`).CombinedOutput(); e != nil {
beeLogger.Log.Errorf("i cann't find go.")
} else {
regex := regexp.MustCompile(`GOMOD="?(.+go.mod)"?`)
stringSubmatch := regex.FindStringSubmatch(string(combinedOutput))
return len(stringSubmatch) == 2
}
return false
}
func NoticeUpdateBee() {
cmd := exec.Command("go", "version")
cmd.Output()
if cmd.Process == nil || cmd.Process.Pid <= 0 {
beeLogger.Log.Warn("There is no go environment")
return
}
beeHome := system.BeegoHome
if !IsExist(beeHome) {
if err := os.MkdirAll(beeHome, 0755); err != nil {
beeLogger.Log.Fatalf("Could not create the directory: %s", err)
return
}
}
fp := beeHome + "/.noticeUpdateBee"
timeNow := time.Now().Unix()
var timeOld int64
if !IsExist(fp) {
f, err := os.Create(fp)
if err != nil {
beeLogger.Log.Warnf("Create noticeUpdateBee file err: %s", err)
return
}
defer f.Close()
}
oldContent, err := ioutil.ReadFile(fp)
if err != nil {
beeLogger.Log.Warnf("Read noticeUpdateBee file err: %s", err)
return
}
timeOld, _ = strconv.ParseInt(string(oldContent), 10, 64)
if timeNow-timeOld < 24*60*60 {
return
}
w, err := os.OpenFile(fp, os.O_WRONLY|os.O_TRUNC, 0644)
if err != nil {
beeLogger.Log.Warnf("Open noticeUpdateBee file err: %s", err)
return
}
defer w.Close()
timeNowStr := strconv.FormatInt(timeNow, 10)
if _, err := w.WriteString(timeNowStr); err != nil {
beeLogger.Log.Warnf("Update noticeUpdateBee file err: %s", err)
return
}
beeLogger.Log.Info("Getting bee latest version...")
versionLast := BeeLastVersion()
versionNow := config.Version
if versionLast == "" {
beeLogger.Log.Warn("Get latest version err")
return
}
if versionNow != versionLast {
beeLogger.Log.Warnf("Update available %s ==> %s", versionNow, versionLast)
beeLogger.Log.Warn("Run `bee update` to update")
}
beeLogger.Log.Info("Your bee are up to date")
}
func BeeLastVersion() (version string) {
var url = "https://api.github.com/repos/beego/bee/tags"
resp, err := http.Get(url)
if err != nil {
beeLogger.Log.Warnf("Get bee tags from github error: %s", err)
return
}
defer resp.Body.Close()
bodyContent, _ := ioutil.ReadAll(resp.Body)
var tags []tagName
if err = json.Unmarshal(bodyContent, &tags); err != nil {
beeLogger.Log.Warnf("Unmarshal tags body error: %s", err)
return
}
if len(tags) < 1 {
beeLogger.Log.Warn("There is no tags")
return
}
last := tags[0]
re, _ := regexp.Compile(`[0-9.]+`)
versionList := re.FindStringSubmatch(last.Name)
if len(versionList) > 0 {
return versionList[0]
}
beeLogger.Log.Warn("There is no tags")
return
}
// get info of bee repos
func BeeReposInfo() (repos Repos) {
var url = "https://api.github.com/repos/beego/bee"
resp, err := http.Get(url)
if err != nil {
beeLogger.Log.Warnf("Get bee repos from github error: %s", err)
return
}
defer resp.Body.Close()
bodyContent, _ := ioutil.ReadAll(resp.Body)
if err = json.Unmarshal(bodyContent, &repos); err != nil {
beeLogger.Log.Warnf("Unmarshal repos body error: %s", err)
return
}
return
}
// get info of bee releases
func BeeReleasesInfo() (repos []Releases) {
var url = "https://api.github.com/repos/beego/bee/releases"
resp, err := http.Get(url)
if err != nil {
beeLogger.Log.Warnf("Get bee releases from github error: %s", err)
return
}
defer resp.Body.Close()
bodyContent, _ := ioutil.ReadAll(resp.Body)
if err = json.Unmarshal(bodyContent, &repos); err != nil {
beeLogger.Log.Warnf("Unmarshal releases body error: %s", err)
return
}
return
}
//TODO merge UpdateLastPublishedTime and NoticeUpdateBee
func UpdateLastPublishedTime() {
info := BeeReleasesInfo()
if len(info) == 0 {
beeLogger.Log.Warn("Has no releases")
return
}
createdAt := info[0].PublishedAt.Format("2006-01-02")
beeHome := system.BeegoHome
if !IsExist(beeHome) {
if err := os.MkdirAll(beeHome, 0755); err != nil {
beeLogger.Log.Fatalf("Could not create the directory: %s", err)
return
}
}
fp := beeHome + "/.lastPublishedAt"
w, err := os.OpenFile(fp, os.O_WRONLY|os.O_TRUNC|os.O_CREATE, 0644)
if err != nil {
beeLogger.Log.Warnf("Open .lastPublishedAt file err: %s", err)
return
}
defer w.Close()
if _, err := w.WriteString(createdAt); err != nil {
beeLogger.Log.Warnf("Update .lastPublishedAt file err: %s", err)
return
}
}
func GetLastPublishedTime() string {
fp := system.BeegoHome + "/.lastPublishedAt"
if !IsExist(fp) {
UpdateLastPublishedTime()
}
w, err := os.OpenFile(fp, os.O_RDONLY, 0644)
if err != nil {
beeLogger.Log.Warnf("Open .lastPublishedAt file err: %s", err)
return "unknown"
}
t := make([]byte, 1024)
read, err := w.Read(t)
if err != nil {
beeLogger.Log.Warnf("read .lastPublishedAt file err: %s", err)
return "unknown"
}
return string(t[:read])
}

17
utils/version.go Normal file
View File

@ -0,0 +1,17 @@
// Copyright 2020
//
// 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.
package utils
const BEEGO_VERSION = "v2.1.0"

View File

@ -1,116 +0,0 @@
package main
import (
"bufio"
"bytes"
"fmt"
"io"
"os"
path "path/filepath"
"regexp"
)
var cmdVersion = &Command{
UsageLine: "version",
Short: "prints the current Bee version",
Long: `
Prints the current Bee, Beego and Go version alongside the platform information
`,
}
const verboseVersionBanner string = `%s%s______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}%s
%s%s
Beego : {{ .BeegoVersion }}
GoVersion : {{ .GoVersion }}
GOOS : {{ .GOOS }}
GOARCH : {{ .GOARCH }}
NumCPU : {{ .NumCPU }}
GOPATH : {{ .GOPATH }}
GOROOT : {{ .GOROOT }}
Compiler : {{ .Compiler }}
Date : {{ Now "Monday, 2 Jan 2006" }}%s
`
const shortVersionBanner = `%s%s______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}%s
`
func init() {
cmdVersion.Run = versionCmd
}
func versionCmd(cmd *Command, args []string) int {
ShowVerboseVersionBanner()
return 0
}
// ShowVerboseVersionBanner prints the verbose version banner
func ShowVerboseVersionBanner() {
w := NewColorWriter(os.Stdout)
coloredBanner := fmt.Sprintf(verboseVersionBanner, "\x1b[35m", "\x1b[1m", "\x1b[0m",
"\x1b[32m", "\x1b[1m", "\x1b[0m")
InitBanner(w, bytes.NewBufferString(coloredBanner))
}
// ShowShortVersionBanner prints the short version banner
func ShowShortVersionBanner() {
w := NewColorWriter(os.Stdout)
coloredBanner := fmt.Sprintf(shortVersionBanner, "\x1b[35m", "\x1b[1m", "\x1b[0m")
InitBanner(w, bytes.NewBufferString(coloredBanner))
}
func getBeegoVersion() string {
gopath := os.Getenv("GOPATH")
re, err := regexp.Compile(`VERSION = "([0-9.]+)"`)
if err != nil {
return ""
}
if gopath == "" {
err = fmt.Errorf("You should set GOPATH env variable")
return ""
}
wgopath := path.SplitList(gopath)
for _, wg := range wgopath {
wg, _ = path.EvalSymlinks(path.Join(wg, "src", "github.com", "astaxie", "beego"))
filename := path.Join(wg, "beego.go")
_, err := os.Stat(filename)
if err != nil {
if os.IsNotExist(err) {
continue
}
ColorLog("[ERRO] Get `beego.go` has error\n")
}
fd, err := os.Open(filename)
if err != nil {
ColorLog("[ERRO] Open `beego.go` has error\n")
continue
}
reader := bufio.NewReader(fd)
for {
byteLine, _, er := reader.ReadLine()
if er != nil && er != io.EOF {
return ""
}
if er == io.EOF {
break
}
line := string(byteLine)
s := re.FindStringSubmatch(line)
if len(s) >= 2 {
return s[1]
}
}
}
return "Beego not installed. Please install it first: https://github.com/astaxie/beego"
}

266
watch.go
View File

@ -1,266 +0,0 @@
// Copyright 2013 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.
package main
import (
"bytes"
"fmt"
"github.com/howeyc/fsnotify"
"os"
"os/exec"
"regexp"
"runtime"
"strings"
"sync"
"time"
)
var (
cmd *exec.Cmd
state sync.Mutex
eventTime = make(map[string]int64)
scheduleTime time.Time
)
func NewWatcher(paths []string, files []string, isgenerate bool) {
watcher, err := fsnotify.NewWatcher()
if err != nil {
ColorLog("[ERRO] Fail to create new Watcher[ %s ]\n", err)
os.Exit(2)
}
go func() {
for {
select {
case e := <-watcher.Event:
isbuild := true
// Skip ignored files
if shouldIgnoreFile(e.Name) {
continue
}
if !checkIfWatchExt(e.Name) {
continue
}
mt := getFileModTime(e.Name)
if t := eventTime[e.Name]; mt == t {
ColorLog("[SKIP] # %s #\n", e.String())
isbuild = false
}
eventTime[e.Name] = mt
if isbuild {
ColorLog("[EVEN] %s\n", e)
go func() {
// Wait 1s before autobuild util there is no file change.
scheduleTime = time.Now().Add(1 * time.Second)
for {
time.Sleep(scheduleTime.Sub(time.Now()))
if time.Now().After(scheduleTime) {
break
}
return
}
Autobuild(files, isgenerate)
}()
}
case err := <-watcher.Error:
ColorLog("[WARN] %s\n", err.Error()) // No need to exit here
}
}
}()
ColorLog("[INFO] Initializing watcher...\n")
for _, path := range paths {
ColorLog("[TRAC] Directory( %s )\n", path)
err = watcher.Watch(path)
if err != nil {
ColorLog("[ERRO] Fail to watch directory[ %s ]\n", err)
os.Exit(2)
}
}
}
// getFileModTime retuens unix timestamp of `os.File.ModTime` by given path.
func getFileModTime(path string) int64 {
path = strings.Replace(path, "\\", "/", -1)
f, err := os.Open(path)
if err != nil {
ColorLog("[ERRO] Fail to open file[ %s ]\n", err)
return time.Now().Unix()
}
defer f.Close()
fi, err := f.Stat()
if err != nil {
ColorLog("[ERRO] Fail to get file information[ %s ]\n", err)
return time.Now().Unix()
}
return fi.ModTime().Unix()
}
func Autobuild(files []string, isgenerate bool) {
state.Lock()
defer state.Unlock()
ColorLog("[INFO] Start building...\n")
os.Chdir(currpath)
cmdName := "go"
if conf.Gopm.Enable {
cmdName = "gopm"
}
var err error
// For applications use full import path like "github.com/.../.."
// are able to use "go install" to reduce build time.
if conf.GoInstall || conf.Gopm.Install {
icmd := exec.Command("go", "list", "./...")
buf := bytes.NewBuffer([]byte(""))
icmd.Stdout = buf
icmd.Env = append(os.Environ(), "GOGC=off")
err = icmd.Run()
if err == nil {
list := strings.Split(buf.String(), "\n")[1:]
for _, pkg := range list {
if len(pkg) == 0 {
continue
}
icmd = exec.Command(cmdName, "install", pkg)
icmd.Stdout = os.Stdout
icmd.Stderr = os.Stderr
icmd.Env = append(os.Environ(), "GOGC=off")
err = icmd.Run()
if err != nil {
break
}
}
}
}
if isgenerate {
icmd := exec.Command("bee", "generate", "docs")
icmd.Env = append(os.Environ(), "GOGC=off")
icmd.Stdout = os.Stdout
icmd.Stderr = os.Stderr
icmd.Run()
ColorLog("============== generate docs ===================\n")
}
if err == nil {
appName := appname
if runtime.GOOS == "windows" {
appName += ".exe"
}
args := []string{"build"}
args = append(args, "-o", appName)
if buildTags != "" {
args = append(args, "-tags", buildTags)
}
args = append(args, files...)
bcmd := exec.Command(cmdName, args...)
bcmd.Env = append(os.Environ(), "GOGC=off")
bcmd.Stdout = os.Stdout
bcmd.Stderr = os.Stderr
err = bcmd.Run()
}
if err != nil {
ColorLog("[ERRO] ============== Build failed ===================\n")
return
}
ColorLog("[SUCC] Build was successful\n")
Restart(appname)
}
func Kill() {
defer func() {
if e := recover(); e != nil {
fmt.Println("Kill.recover -> ", e)
}
}()
if cmd != nil && cmd.Process != nil {
err := cmd.Process.Kill()
if err != nil {
fmt.Println("Kill -> ", err)
}
}
}
func Restart(appname string) {
Debugf("kill running process")
Kill()
go Start(appname)
}
func Start(appname string) {
ColorLog("[INFO] Restarting %s ...\n", appname)
if strings.Index(appname, "./") == -1 {
appname = "./" + appname
}
cmd = exec.Command(appname)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.Args = append([]string{appname}, conf.CmdArgs...)
cmd.Env = append(os.Environ(), conf.Envs...)
go cmd.Run()
ColorLog("[INFO] %s is running...\n", appname)
started <- true
}
// Should ignore filenames generated by
// Emacs, Vim or SublimeText
func shouldIgnoreFile(filename string) bool {
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
}
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>.
func checkIfWatchExt(name string) bool {
for _, s := range watchExts {
if strings.HasSuffix(name, s) {
return true
}
}
return false
}