Compare commits

...

235 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
Lukas Bachschwell 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
Lukas Bachschwell 10a2e56df0 Fixing absolute path for dir option of migration 2018-11-12 13:58:15 +01:00
Lukas Bachschwell 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
487 changed files with 4907 additions and 173567 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 ./...

1
.gitignore vendored
View File

@ -30,3 +30,4 @@ _testmain.go
bee
*.exe~
.goxc.local.json
vendor

View File

@ -11,4 +11,4 @@
}
},
"ConfigVersion": "0.9"
}
}

View File

@ -1,20 +1,22 @@
language: go
go:
- 1.10.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/gosimple
- go get -u honnef.co/go/tools/cmd/staticcheck
- go get -u honnef.co/go/tools/cmd/unused
- 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 vet $(go list ./... | grep -v /vendor/)
- structcheck $(go list ./... | grep -v /vendor/)
- gosimple -ignore "$(cat gosimple.ignore)" $(go list ./... | grep -v /vendor/)
- staticcheck -ignore "$(cat staticcheck.ignore)" $(go list ./... | grep -v /vendor/)
- unused $(go list ./... | grep -v /vendor/)
- unconvert $(go list ./... | grep -v /vendor/)
- 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

@ -188,4 +188,4 @@ third-party archives.
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.
limitations under the License.

View File

@ -24,6 +24,6 @@ clean:
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
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)
ghr -u beego -r bee $(VERSION) $(VERSION)

271
README.md
View File

@ -9,26 +9,34 @@ Bee is a command-line tool facilitating development of Beego-based application.
## Requirements
- Go version >= 1.3.
- Go version >= 1.13
## Installation
To install `bee` use the `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
@ -41,15 +49,17 @@ Bee provides a variety of commands which can be helpful at various stages of dev
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 for your Beego application
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
@ -63,17 +73,17 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
\____/ \___| \___| v2.0.4
├── Beego : 1.7.2
├── GoVersion : go1.7.4
├── GOOS : linux
├── Beego : 2.0.4
├── GoVersion : go1.14.1
├── GOOS : darwin
├── GOARCH : amd64
├── NumCPU : 2
├── NumCPU : 4
├── GOPATH : /home/beeuser/.go
├── GOROOT : /usr/lib/go
├── GOROOT : /usr/local/Cellar/go/1.14.1/libexec
├── Compiler : gc
└── Date : Monday, 26 Dec 2016
└── Published : 2020-09-13
```
You can also change the output format using `-o` flag:
@ -81,15 +91,16 @@ You can also change the output format using `-o` flag:
```bash
$ bee version -o json
{
"GoVersion": "go1.7.4",
"GOOS": "linux",
"GoVersion": "go1.14.1",
"GOOS": "darwin",
"GOARCH": "amd64",
"NumCPU": 2,
"NumCPU": 4,
"GOPATH": "/home/beeuser/.go",
"GOROOT": "/usr/lib/go",
"GOROOT": "/usr/local/Cellar/go/1.14.1/libexec",
"Compiler": "gc",
"BeeVersion": "1.6.2",
"BeegoVersion": "1.7.2"
"BeeVersion": "2.0.4",
"BeegoVersion": "2.0.4",
"Published": "2020-09-13"
}
```
@ -101,31 +112,27 @@ To create a new Beego web application:
```bash
$ bee new my-web-app
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
2016/12/26 22:28:11 INFO ▶ 0001 Creating application...
create /home/beeuser/.go/src/github.com/user/my-web-app/
create /home/beeuser/.go/src/github.com/user/my-web-app/conf/
create /home/beeuser/.go/src/github.com/user/my-web-app/controllers/
create /home/beeuser/.go/src/github.com/user/my-web-app/models/
create /home/beeuser/.go/src/github.com/user/my-web-app/routers/
create /home/beeuser/.go/src/github.com/user/my-web-app/tests/
create /home/beeuser/.go/src/github.com/user/my-web-app/static/
create /home/beeuser/.go/src/github.com/user/my-web-app/static/js/
create /home/beeuser/.go/src/github.com/user/my-web-app/static/css/
create /home/beeuser/.go/src/github.com/user/my-web-app/static/img/
create /home/beeuser/.go/src/github.com/user/my-web-app/views/
create /home/beeuser/.go/src/github.com/user/my-web-app/conf/app.conf
create /home/beeuser/.go/src/github.com/user/my-web-app/controllers/default.go
create /home/beeuser/.go/src/github.com/user/my-web-app/views/index.tpl
create /home/beeuser/.go/src/github.com/user/my-web-app/routers/router.go
create /home/beeuser/.go/src/github.com/user/my-web-app/tests/default_test.go
create /home/beeuser/.go/src/github.com/user/my-web-app/main.go
2016/12/26 22:28:11 SUCCESS ▶ 0002 New application successfully created!
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!
```
For more information on the usage, run `bee help new`.
@ -138,12 +145,6 @@ To run the application we just created, you can navigate to the application fold
$ cd my-web-app && bee run
```
Or from anywhere in your machine:
```
$ bee run github.com/user/my-web-app
```
For more information on the usage, run `bee help run`.
### bee pack
@ -157,7 +158,7 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
\____/ \___| \___| 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
@ -213,23 +214,25 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
2016/12/26 22:30:12 INFO ▶ 0001 Creating API...
create /home/beeuser/.go/src/github.com/user/my-api
create /home/beeuser/.go/src/github.com/user/my-api/conf
create /home/beeuser/.go/src/github.com/user/my-api/controllers
create /home/beeuser/.go/src/github.com/user/my-api/tests
create /home/beeuser/.go/src/github.com/user/my-api/conf/app.conf
create /home/beeuser/.go/src/github.com/user/my-api/models
create /home/beeuser/.go/src/github.com/user/my-api/routers/
create /home/beeuser/.go/src/github.com/user/my-api/controllers/object.go
create /home/beeuser/.go/src/github.com/user/my-api/controllers/user.go
create /home/beeuser/.go/src/github.com/user/my-api/tests/default_test.go
create /home/beeuser/.go/src/github.com/user/my-api/routers/router.go
create /home/beeuser/.go/src/github.com/user/my-api/models/object.go
create /home/beeuser/.go/src/github.com/user/my-api/models/user.go
create /home/beeuser/.go/src/github.com/user/my-api/main.go
2016/12/26 22:30:12 SUCCESS ▶ 0002 New API successfully created!
\____/ \___| \___| 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!
```
For more information on the usage, run `bee help api`.
@ -245,26 +248,18 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
2016/12/26 22:30:58 INFO ▶ 0001 Creating application...
create /home/beeuser/.go/src/github.com/user/my-rpc-app/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/conf/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/controllers/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/models/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/routers/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/tests/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/static/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/static/js/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/static/css/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/static/img/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/views/
create /home/beeuser/.go/src/github.com/user/my-rpc-app/conf/app.conf
create /home/beeuser/.go/src/github.com/user/my-rpc-app/controllers/default.go
create /home/beeuser/.go/src/github.com/user/my-rpc-app/views/index.tpl
create /home/beeuser/.go/src/github.com/user/my-rpc-app/routers/router.go
create /home/beeuser/.go/src/github.com/user/my-rpc-app/tests/default_test.go
create /home/beeuser/.go/src/github.com/user/my-rpc-app/main.go
2016/12/26 22:30:58 SUCCESS ▶ 0002 New application successfully created!
\____/ \___| \___| 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!
```
For more information on the usage, run `bee help hprose`.
@ -280,9 +275,8 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
2016/12/26 22:32:41 INFO ▶ 0001 Loading configuration from 'bee.json'...
2016/12/26 22:32:41 SUCCESS ▶ 0002 Baled resources successfully!
\____/ \___| \___| v2.0.0
2020/09/14 22:37:56 SUCCESS ▶ 0001 Baled resources successfully!
```
For more information on the usage, run `bee help bale`.
@ -306,31 +300,32 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
2016/12/26 22:33:58 INFO ▶ 0001 Using 'Hello' as controller name
2016/12/26 22:33:58 INFO ▶ 0002 Using 'controllers' as package name
create /home/beeuser/.go/src/github.com/user/my-web-app/controllers/hello.go
2016/12/26 22:33:58 SUCCESS ▶ 0003 Controller successfully generated!
\____/ \___| \___| 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.
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 `Go version 1.6.4` and exposing port `9000`:
For example, to generate a Dockerfile with `golang:1.20.1` baseimage and exposing port `9000`:
```bash
$ bee dockerize -image="library/golang:1.6.4" -expose=9000
$ bee dockerize -baseimage=golang:1.20.1 -expose=9000
______
| ___ \
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.6.2
2016/12/26 22:34:54 INFO ▶ 0001 Generating Dockerfile...
2016/12/26 22:34:54 SUCCESS ▶ 0002 Dockerfile generated.
\____/ \___| \___| 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`.
@ -345,8 +340,8 @@ ______
| |_/ / ___ ___
| ___ \ / _ \ / _ \
| |_/ /| __/| __/
\____/ \___| \___| v1.8.0
2017/03/22 11:17:05 INFO ▶ 0001 Starting Delve Debugger...
\____/ \___| \___| 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
@ -355,7 +350,7 @@ Breakpoint 1 set at 0x40100f for main.main() ./main.go:8
> main.main() ./main.go:8 (hits goroutine(1):1 total:1) (PC: 0x40100f)
3: import (
4: _ "github.com/user/myapp/routers"
5: "github.com/astaxie/beego"
5: beego "github.com/beego/beego/v2/server/web"
6: )
7:
=> 8: func main() {
@ -366,6 +361,68 @@ Breakpoint 1 set at 0x40100f for main.main() ./main.go:8
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:
@ -520,7 +577,7 @@ Rebasing will update your branch with the most recent code and make your changes
## Licence
```text
Copyright 2016 bee authors
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.

View File

@ -15,4 +15,4 @@
"driver": "mysql"
},
"enable_reload": false
}
}

View File

@ -16,22 +16,25 @@
package cmd
import (
"github.com/beego/bee/cmd/commands"
_ "github.com/beego/bee/cmd/commands/api"
_ "github.com/beego/bee/cmd/commands/bale"
_ "github.com/beego/bee/cmd/commands/beefix"
_ "github.com/beego/bee/cmd/commands/dlv"
_ "github.com/beego/bee/cmd/commands/dockerize"
_ "github.com/beego/bee/cmd/commands/generate"
_ "github.com/beego/bee/cmd/commands/hprose"
_ "github.com/beego/bee/cmd/commands/migrate"
_ "github.com/beego/bee/cmd/commands/new"
_ "github.com/beego/bee/cmd/commands/pack"
_ "github.com/beego/bee/cmd/commands/rs"
_ "github.com/beego/bee/cmd/commands/run"
_ "github.com/beego/bee/cmd/commands/server"
_ "github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/utils"
"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 {
@ -48,6 +51,8 @@ func IfGenerateDocs(name string, args []string) bool {
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}}
@ -85,6 +90,7 @@ func Usage() {
func Help(args []string) {
if len(args) == 0 {
Usage()
return
}
if len(args) != 1 {
utils.PrintErrorAndExit("Too many arguments", ErrorTemplate)

View File

@ -20,11 +20,13 @@ import (
path "path/filepath"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/generate"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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 = &commands.Command{
@ -33,9 +35,10 @@ var CmdApiapp = &commands.Command{
Short: "Creates a Beego API application",
Long: `
The command 'api' creates a Beego API application.
now default supoort generate a go modules project.
{{"Example:"|bold}}
$ bee api [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
$ 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, the command will generate an example API application. Otherwise the command
will connect to your database and generate models based on the existing tables.
@ -43,6 +46,7 @@ var CmdApiapp = &commands.Command{
The command 'api' creates a folder named [appname] with the following structure:
main.go
go.mod
{{"conf"|foldername}}
app.conf
{{"controllers"|foldername}}
@ -65,13 +69,14 @@ 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() {
@ -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,11 +551,15 @@ func TestGet(t *testing.T) {
}
`
var gopath utils.DocValue
var beegoVersion utils.DocValue
func init() {
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)
}
@ -550,14 +570,40 @@ func createAPI(cmd *commands.Command, args []string) int {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
if len(args) > 1 {
if len(args) >= 2 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
beeLogger.Log.Error(err.Error())
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)
}
}
appPath, packPath, err := utils.CheckEnv(args[0])
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)
}
}
appName := path.Base(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
}
@ -568,6 +614,10 @@ func createAPI(cmd *commands.Command, args []string) int {
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")
@ -575,11 +625,13 @@ func createAPI(cmd *commands.Command, args []string) int {
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")
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(apiconf, "{{.Appname}}", path.Base(args[0]), -1))
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)
@ -601,6 +653,11 @@ func createAPI(cmd *commands.Command, args []string) int {
beeLogger.Log.Infof("Using '%s' as 'tables'", generate.Tables)
generate.GenerateAppcode(string(generate.SQLDriver), string(generate.SQLConn), "3", string(generate.Tables), appPath)
} else {
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)
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)

View File

@ -24,11 +24,11 @@ import (
"runtime"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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 = &commands.Command{

View File

@ -1,232 +1,48 @@
package beefix
import (
"fmt"
"go/parser"
"go/token"
"io/ioutil"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"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: `As of {{"Beego 1.6"|bold}}, there are some backward compatibility issues.
Long: `
The command 'fix' will try to solve those issues by upgrading your code base
to be compatible with Beego version 1.6+.
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 {
output := cmd.Out()
beeLogger.Log.Info("Upgrading the application...")
dir, err := os.Getwd()
if err != nil {
beeLogger.Log.Fatalf("Error while getting the current working directory: %s", err)
t := target.String()
if t == "" || t == "1.6" {
return fixTo16(cmd, args)
} else if strings.HasPrefix(t, "2") {
// upgrade to v2
return fix1To2()
}
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
if strings.HasPrefix(info.Name(), ".") {
return filepath.SkipDir
}
return nil
}
if err != nil {
return err
}
if strings.HasSuffix(info.Name(), ".exe") {
return nil
}
err = fixFile(path)
fmt.Fprintf(output, colors.GreenBold("\tfix\t")+"%s\n", path)
if err != nil {
beeLogger.Log.Errorf("Could not fix file: %s", err)
}
return err
})
beeLogger.Log.Success("Upgrade Done!")
beeLogger.Log.Info("The target is compatible version, do nothing")
return 0
}
var rules = []string{
"beego.AppName", "beego.BConfig.AppName",
"beego.RunMode", "beego.BConfig.RunMode",
"beego.RecoverPanic", "beego.BConfig.RecoverPanic",
"beego.RouterCaseSensitive", "beego.BConfig.RouterCaseSensitive",
"beego.BeegoServerName", "beego.BConfig.ServerName",
"beego.EnableGzip", "beego.BConfig.EnableGzip",
"beego.ErrorsShow", "beego.BConfig.EnableErrorsShow",
"beego.CopyRequestBody", "beego.BConfig.CopyRequestBody",
"beego.MaxMemory", "beego.BConfig.MaxMemory",
"beego.Graceful", "beego.BConfig.Listen.Graceful",
"beego.HttpAddr", "beego.BConfig.Listen.HTTPAddr",
"beego.HttpPort", "beego.BConfig.Listen.HTTPPort",
"beego.ListenTCP4", "beego.BConfig.Listen.ListenTCP4",
"beego.EnableHttpListen", "beego.BConfig.Listen.EnableHTTP",
"beego.EnableHttpTLS", "beego.BConfig.Listen.EnableHTTPS",
"beego.HttpsAddr", "beego.BConfig.Listen.HTTPSAddr",
"beego.HttpsPort", "beego.BConfig.Listen.HTTPSPort",
"beego.HttpCertFile", "beego.BConfig.Listen.HTTPSCertFile",
"beego.HttpKeyFile", "beego.BConfig.Listen.HTTPSKeyFile",
"beego.EnableAdmin", "beego.BConfig.Listen.EnableAdmin",
"beego.AdminHttpAddr", "beego.BConfig.Listen.AdminAddr",
"beego.AdminHttpPort", "beego.BConfig.Listen.AdminPort",
"beego.UseFcgi", "beego.BConfig.Listen.EnableFcgi",
"beego.HttpServerTimeOut", "beego.BConfig.Listen.ServerTimeOut",
"beego.AutoRender", "beego.BConfig.WebConfig.AutoRender",
"beego.ViewsPath", "beego.BConfig.WebConfig.ViewsPath",
"beego.StaticDir", "beego.BConfig.WebConfig.StaticDir",
"beego.StaticExtensionsToGzip", "beego.BConfig.WebConfig.StaticExtensionsToGzip",
"beego.DirectoryIndex", "beego.BConfig.WebConfig.DirectoryIndex",
"beego.FlashName", "beego.BConfig.WebConfig.FlashName",
"beego.FlashSeperator", "beego.BConfig.WebConfig.FlashSeparator",
"beego.EnableDocs", "beego.BConfig.WebConfig.EnableDocs",
"beego.XSRFKEY", "beego.BConfig.WebConfig.XSRFKey",
"beego.EnableXSRF", "beego.BConfig.WebConfig.EnableXSRF",
"beego.XSRFExpire", "beego.BConfig.WebConfig.XSRFExpire",
"beego.TemplateLeft", "beego.BConfig.WebConfig.TemplateLeft",
"beego.TemplateRight", "beego.BConfig.WebConfig.TemplateRight",
"beego.SessionOn", "beego.BConfig.WebConfig.Session.SessionOn",
"beego.SessionProvider", "beego.BConfig.WebConfig.Session.SessionProvider",
"beego.SessionName", "beego.BConfig.WebConfig.Session.SessionName",
"beego.SessionGCMaxLifetime", "beego.BConfig.WebConfig.Session.SessionGCMaxLifetime",
"beego.SessionSavePath", "beego.BConfig.WebConfig.Session.SessionProviderConfig",
"beego.SessionCookieLifeTime", "beego.BConfig.WebConfig.Session.SessionCookieLifeTime",
"beego.SessionAutoSetCookie", "beego.BConfig.WebConfig.Session.SessionAutoSetCookie",
"beego.SessionDomain", "beego.BConfig.WebConfig.Session.SessionDomain",
"Ctx.Input.CopyBody(", "Ctx.Input.CopyBody(beego.BConfig.MaxMemory",
".UrlFor(", ".URLFor(",
".ServeJson(", ".ServeJSON(",
".ServeXml(", ".ServeXML(",
".ServeJsonp(", ".ServeJSONP(",
".XsrfToken(", ".XSRFToken(",
".CheckXsrfCookie(", ".CheckXSRFCookie(",
".XsrfFormHtml(", ".XSRFFormHTML(",
"beego.UrlFor(", "beego.URLFor(",
"beego.GlobalDocApi", "beego.GlobalDocAPI",
"beego.Errorhandler", "beego.ErrorHandler",
"Output.Jsonp(", "Output.JSONP(",
"Output.Json(", "Output.JSON(",
"Output.Xml(", "Output.XML(",
"Input.Uri()", "Input.URI()",
"Input.Url()", "Input.URL()",
"Input.AcceptsHtml()", "Input.AcceptsHTML()",
"Input.AcceptsXml()", "Input.AcceptsXML()",
"Input.AcceptsJson()", "Input.AcceptsJSON()",
"Ctx.XsrfToken()", "Ctx.XSRFToken()",
"Ctx.CheckXsrfCookie()", "Ctx.CheckXSRFCookie()",
"session.SessionStore", "session.Store",
".TplNames", ".TplName",
"swagger.ApiRef", "swagger.APIRef",
"swagger.ApiDeclaration", "swagger.APIDeclaration",
"swagger.Api", "swagger.API",
"swagger.ApiRef", "swagger.APIRef",
"swagger.Infomation", "swagger.Information",
"toolbox.UrlMap", "toolbox.URLMap",
"logs.LoggerInterface", "logs.Logger",
"Input.Request", "Input.Context.Request",
"Input.Params)", "Input.Params())",
"httplib.BeegoHttpSettings", "httplib.BeegoHTTPSettings",
"httplib.BeegoHttpRequest", "httplib.BeegoHTTPRequest",
".TlsClientConfig", ".TLSClientConfig",
".JsonBody", ".JSONBody",
".ToJson", ".ToJSON",
".ToXml", ".ToXML",
"beego.Html2str", "beego.HTML2str",
"beego.AssetsCss", "beego.AssetsCSS",
"orm.DR_Sqlite", "orm.DRSqlite",
"orm.DR_Postgres", "orm.DRPostgres",
"orm.DR_MySQL", "orm.DRMySQL",
"orm.DR_Oracle", "orm.DROracle",
"orm.Col_Add", "orm.ColAdd",
"orm.Col_Minus", "orm.ColMinus",
"orm.Col_Multiply", "orm.ColMultiply",
"orm.Col_Except", "orm.ColExcept",
"GenerateOperatorSql", "GenerateOperatorSQL",
"OperatorSql", "OperatorSQL",
"orm.Debug_Queries", "orm.DebugQueries",
"orm.COMMA_SPACE", "orm.CommaSpace",
".SendOut()", ".DoRequest()",
"validation.ValidationError", "validation.Error",
}
func fixFile(file string) error {
rp := strings.NewReplacer(rules...)
content, err := ioutil.ReadFile(file)
if err != nil {
return err
}
fixed := rp.Replace(string(content))
// Forword the RequestBody from the replace
// "Input.Request", "Input.Context.Request",
fixed = strings.Replace(fixed, "Input.Context.RequestBody", "Input.RequestBody", -1)
// 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
pareg = regexp.MustCompile(`(\.Put\(\")(.*)(\",)(\s)(.*)(,\s*)([^\*.]*)(\))`)
if pareg.MatchString(fixed) && strings.HasSuffix(file, ".go") {
fixed = pareg.ReplaceAllString(fixed, ".Put(\"$2\", $5, $7*time.Second)")
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly)
if err != nil {
panic(err)
}
// Print the imports from the file's AST.
hasTimepkg := false
for _, s := range f.Imports {
if s.Path.Value == `"time"` {
hasTimepkg = true
break
}
}
if !hasTimepkg {
fixed = strings.Replace(fixed, "import (", "import (\n\t\"time\"", 1)
}
}
// 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
if strings.HasSuffix(file, ".conf") {
fixed = strings.Replace(fixed, "HttpCertFile", "HTTPSCertFile", -1)
fixed = strings.Replace(fixed, "HttpKeyFile", "HTTPSKeyFile", -1)
fixed = strings.Replace(fixed, "EnableHttpListen", "HTTPEnable", -1)
fixed = strings.Replace(fixed, "EnableHttpTLS", "EnableHTTPS", -1)
fixed = strings.Replace(fixed, "EnableHttpTLS", "EnableHTTPS", -1)
fixed = strings.Replace(fixed, "BeegoServerName", "ServerName", -1)
fixed = strings.Replace(fixed, "AdminHttpAddr", "AdminAddr", -1)
fixed = strings.Replace(fixed, "AdminHttpPort", "AdminPort", -1)
fixed = strings.Replace(fixed, "HttpServerTimeOut", "ServerTimeOut", -1)
}
err = os.Truncate(file, 0)
if err != nil {
return err
}
return ioutil.WriteFile(file, []byte(fixed), 0666)
}

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

@ -0,0 +1,230 @@
// 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"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/beego/bee/v2/cmd/commands"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
)
// fixTo16 upgrade beego to 1.6
func fixTo16(cmd *commands.Command, args []string) int {
output := cmd.Out()
beeLogger.Log.Info("Upgrading the application...")
dir, err := os.Getwd()
if err != nil {
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(), ".") {
return filepath.SkipDir
}
return nil
}
if err != nil {
return err
}
if strings.HasSuffix(info.Name(), ".exe") {
return nil
}
err = fixFile(path)
fmt.Fprintf(output, colors.GreenBold("\tfix\t")+"%s\n", path)
if err != nil {
beeLogger.Log.Errorf("Could not fix file: %s", err)
}
return err
})
beeLogger.Log.Success("Upgrade Done!")
return 0
}
var rules = []string{
"beego.AppName", "beego.BConfig.AppName",
"beego.RunMode", "beego.BConfig.RunMode",
"beego.RecoverPanic", "beego.BConfig.RecoverPanic",
"beego.RouterCaseSensitive", "beego.BConfig.RouterCaseSensitive",
"beego.BeegoServerName", "beego.BConfig.ServerName",
"beego.EnableGzip", "beego.BConfig.EnableGzip",
"beego.ErrorsShow", "beego.BConfig.EnableErrorsShow",
"beego.CopyRequestBody", "beego.BConfig.CopyRequestBody",
"beego.MaxMemory", "beego.BConfig.MaxMemory",
"beego.Graceful", "beego.BConfig.Listen.Graceful",
"beego.HttpAddr", "beego.BConfig.Listen.HTTPAddr",
"beego.HttpPort", "beego.BConfig.Listen.HTTPPort",
"beego.ListenTCP4", "beego.BConfig.Listen.ListenTCP4",
"beego.EnableHttpListen", "beego.BConfig.Listen.EnableHTTP",
"beego.EnableHttpTLS", "beego.BConfig.Listen.EnableHTTPS",
"beego.HttpsAddr", "beego.BConfig.Listen.HTTPSAddr",
"beego.HttpsPort", "beego.BConfig.Listen.HTTPSPort",
"beego.HttpCertFile", "beego.BConfig.Listen.HTTPSCertFile",
"beego.HttpKeyFile", "beego.BConfig.Listen.HTTPSKeyFile",
"beego.EnableAdmin", "beego.BConfig.Listen.EnableAdmin",
"beego.AdminHttpAddr", "beego.BConfig.Listen.AdminAddr",
"beego.AdminHttpPort", "beego.BConfig.Listen.AdminPort",
"beego.UseFcgi", "beego.BConfig.Listen.EnableFcgi",
"beego.HttpServerTimeOut", "beego.BConfig.Listen.ServerTimeOut",
"beego.AutoRender", "beego.BConfig.WebConfig.AutoRender",
"beego.ViewsPath", "beego.BConfig.WebConfig.ViewsPath",
"beego.StaticDir", "beego.BConfig.WebConfig.StaticDir",
"beego.StaticExtensionsToGzip", "beego.BConfig.WebConfig.StaticExtensionsToGzip",
"beego.DirectoryIndex", "beego.BConfig.WebConfig.DirectoryIndex",
"beego.FlashName", "beego.BConfig.WebConfig.FlashName",
"beego.FlashSeperator", "beego.BConfig.WebConfig.FlashSeparator",
"beego.EnableDocs", "beego.BConfig.WebConfig.EnableDocs",
"beego.XSRFKEY", "beego.BConfig.WebConfig.XSRFKey",
"beego.EnableXSRF", "beego.BConfig.WebConfig.EnableXSRF",
"beego.XSRFExpire", "beego.BConfig.WebConfig.XSRFExpire",
"beego.TemplateLeft", "beego.BConfig.WebConfig.TemplateLeft",
"beego.TemplateRight", "beego.BConfig.WebConfig.TemplateRight",
"beego.SessionOn", "beego.BConfig.WebConfig.Session.SessionOn",
"beego.SessionProvider", "beego.BConfig.WebConfig.Session.SessionProvider",
"beego.SessionName", "beego.BConfig.WebConfig.Session.SessionName",
"beego.SessionGCMaxLifetime", "beego.BConfig.WebConfig.Session.SessionGCMaxLifetime",
"beego.SessionSavePath", "beego.BConfig.WebConfig.Session.SessionProviderConfig",
"beego.SessionCookieLifeTime", "beego.BConfig.WebConfig.Session.SessionCookieLifeTime",
"beego.SessionAutoSetCookie", "beego.BConfig.WebConfig.Session.SessionAutoSetCookie",
"beego.SessionDomain", "beego.BConfig.WebConfig.Session.SessionDomain",
"Ctx.Input.CopyBody(", "Ctx.Input.CopyBody(beego.BConfig.MaxMemory",
".UrlFor(", ".URLFor(",
".ServeJson(", ".ServeJSON(",
".ServeXml(", ".ServeXML(",
".ServeJsonp(", ".ServeJSONP(",
".XsrfToken(", ".XSRFToken(",
".CheckXsrfCookie(", ".CheckXSRFCookie(",
".XsrfFormHtml(", ".XSRFFormHTML(",
"beego.UrlFor(", "beego.URLFor(",
"beego.GlobalDocApi", "beego.GlobalDocAPI",
"beego.Errorhandler", "beego.ErrorHandler",
"Output.Jsonp(", "Output.JSONP(",
"Output.Json(", "Output.JSON(",
"Output.Xml(", "Output.XML(",
"Input.Uri()", "Input.URI()",
"Input.Url()", "Input.URL()",
"Input.AcceptsHtml()", "Input.AcceptsHTML()",
"Input.AcceptsXml()", "Input.AcceptsXML()",
"Input.AcceptsJson()", "Input.AcceptsJSON()",
"Ctx.XsrfToken()", "Ctx.XSRFToken()",
"Ctx.CheckXsrfCookie()", "Ctx.CheckXSRFCookie()",
"session.SessionStore", "session.Store",
".TplNames", ".TplName",
"swagger.ApiRef", "swagger.APIRef",
"swagger.ApiDeclaration", "swagger.APIDeclaration",
"swagger.Api", "swagger.API",
"swagger.ApiRef", "swagger.APIRef",
"swagger.Infomation", "swagger.Information",
"toolbox.UrlMap", "toolbox.URLMap",
"logs.LoggerInterface", "logs.Logger",
"Input.Request", "Input.Context.Request",
"Input.Params)", "Input.Params())",
"httplib.BeegoHttpSettings", "httplib.BeegoHTTPSettings",
"httplib.BeegoHttpRequest", "httplib.BeegoHTTPRequest",
".TlsClientConfig", ".TLSClientConfig",
".JsonBody", ".JSONBody",
".ToJson", ".ToJSON",
".ToXml", ".ToXML",
"beego.Html2str", "beego.HTML2str",
"beego.AssetsCss", "beego.AssetsCSS",
"orm.DR_Sqlite", "orm.DRSqlite",
"orm.DR_Postgres", "orm.DRPostgres",
"orm.DR_MySQL", "orm.DRMySQL",
"orm.DR_Oracle", "orm.DROracle",
"orm.Col_Add", "orm.ColAdd",
"orm.Col_Minus", "orm.ColMinus",
"orm.Col_Multiply", "orm.ColMultiply",
"orm.Col_Except", "orm.ColExcept",
"GenerateOperatorSql", "GenerateOperatorSQL",
"OperatorSql", "OperatorSQL",
"orm.Debug_Queries", "orm.DebugQueries",
"orm.COMMA_SPACE", "orm.CommaSpace",
".SendOut()", ".DoRequest()",
"validation.ValidationError", "validation.Error",
}
func fixFile(file string) error {
rp := strings.NewReplacer(rules...)
content, err := ioutil.ReadFile(file)
if err != nil {
return err
}
fixed := rp.Replace(string(content))
// Forword the RequestBody from the replace
// "Input.Request", "Input.Context.Request",
fixed = strings.Replace(fixed, "Input.Context.RequestBody", "Input.RequestBody", -1)
// 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
pareg = regexp.MustCompile(`(\.Put\(\")(.*)(\",)(\s)(.*)(,\s*)([^\*.]*)(\))`)
if pareg.MatchString(fixed) && strings.HasSuffix(file, ".go") {
fixed = pareg.ReplaceAllString(fixed, ".Put(\"$2\", $5, $7*time.Second)")
fset := token.NewFileSet() // positions are relative to fset
f, err := parser.ParseFile(fset, file, nil, parser.ImportsOnly)
if err != nil {
panic(err)
}
// Print the imports from the file's AST.
hasTimepkg := false
for _, s := range f.Imports {
if s.Path.Value == `"time"` {
hasTimepkg = true
break
}
}
if !hasTimepkg {
fixed = strings.Replace(fixed, "import (", "import (\n\t\"time\"", 1)
}
}
// 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
if strings.HasSuffix(file, ".conf") {
fixed = strings.Replace(fixed, "HttpCertFile", "HTTPSCertFile", -1)
fixed = strings.Replace(fixed, "HttpKeyFile", "HTTPSKeyFile", -1)
fixed = strings.Replace(fixed, "EnableHttpListen", "HTTPEnable", -1)
fixed = strings.Replace(fixed, "EnableHttpTLS", "EnableHTTPS", -1)
fixed = strings.Replace(fixed, "EnableHttpTLS", "EnableHTTPS", -1)
fixed = strings.Replace(fixed, "BeegoServerName", "ServerName", -1)
fixed = strings.Replace(fixed, "AdminHttpAddr", "AdminAddr", -1)
fixed = strings.Replace(fixed, "AdminHttpPort", "AdminPort", -1)
fixed = strings.Replace(fixed, "HttpServerTimeOut", "ServerTimeOut", -1)
}
err = os.Truncate(file, 0)
if err != nil {
return err
}
return ioutil.WriteFile(file, []byte(fixed), 0666)
}

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
}

View File

@ -6,8 +6,8 @@ import (
"os"
"strings"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
// Command is the unit of execution
@ -65,6 +65,7 @@ func (c *Command) Out() io.Writer {
if c.output != nil {
return *c.output
}
return colors.NewColorWriter(os.Stderr)
}

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

View File

@ -24,15 +24,16 @@ import (
"strings"
"time"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"github.com/derekparker/delve/service"
"github.com/derekparker/delve/service/rpc2"
"github.com/derekparker/delve/service/rpccommon"
"github.com/derekparker/delve/terminal"
"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{
@ -43,7 +44,7 @@ var cmdDlv = &commands.Command{
To debug your application using Delve, use: {{"$ bee dlv" | bold}}
For more information on Delve: https://github.com/derekparker/delve
For more information on Delve: https://github.com/go-delve/delve
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
Run: runDlv,
@ -148,11 +149,14 @@ func startDelveDebugger(addr string, ch chan int) int {
server := rpccommon.NewServer(&service.Config{
Listener: listener,
AcceptMulti: true,
AttachPid: 0,
APIVersion: 2,
WorkingDir: ".",
ProcessArgs: []string{abs},
}, false)
Debugger: debugger.Config{
AttachPid: 0,
WorkingDir: ".",
Backend: "default",
},
})
if err := server.Run(); err != nil {
beeLogger.Log.Fatalf("Could not start debugger server: %v", err)
}
@ -163,7 +167,7 @@ func startDelveDebugger(addr string, ch chan int) int {
go func() {
for {
if val := <-ch; val == 0 {
if _, err := client.Restart(); err != nil {
if _, err := client.Restart(true); err != nil {
utils.Notify("Error while restarting the client: "+err.Error(), "bee")
} else {
if verbose {
@ -182,7 +186,7 @@ func startDelveDebugger(addr string, ch chan int) int {
}
// Stop and kill the debugger server once user quits the REPL
if err := server.Stop(true); err != nil {
if err := server.Stop(); err != nil {
beeLogger.Log.Fatalf("Could not stop Delve server: %v", err)
}
return status
@ -227,7 +231,7 @@ func startWatcher(paths []string, ch chan int) {
// Wait 1s before re-build until there is no file change
scheduleTime := time.Now().Add(1 * time.Second)
time.Sleep(scheduleTime.Sub(time.Now()))
time.Sleep(time.Until(scheduleTime))
_, err := buildDebug()
if err != nil {
utils.Notify("Build Failed: "+err.Error(), "bee")

View File

@ -22,31 +22,36 @@ import (
"strings"
"text/template"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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 = `FROM {{.BaseImage}}
const dockerBuildTemplate = `# Build Golang binary
FROM {{.BaseImage}} AS build-golang
# Godep for vendoring
RUN go get github.com/tools/godep
WORKDIR {{.Appdir}}
# Recompile the standard library without CGO
RUN CGO_ENABLED=0 go install -a std
ENV APP_DIR $GOPATH{{.Appdir}}
RUN mkdir -p $APP_DIR
# Set the entrypoint
ENTRYPOINT (cd $APP_DIR && ./{{.Entrypoint}})
ADD . $APP_DIR
# Compile the binary and statically link
RUN cd $APP_DIR && CGO_ENABLED=0 godep go build -ldflags '-d -w -s'
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.
@ -57,13 +62,19 @@ type Dockerfile struct {
Expose string
}
// docker-compose.yaml
type Composefile struct {
Appname string
Expose string
}
var CmdDockerize = &commands.Command{
CustomFlags: true,
UsageLine: "dockerize",
Short: "Generates a Dockerfile for your Beego application",
Long: `Dockerize generates a Dockerfile for your Beego Web Application.
The Dockerfile will compile, get the dependencies with {{"godep"|bold}}, and set the entrypoint.
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"
`,
@ -78,8 +89,8 @@ var (
func init() {
fs := flag.NewFlagSet("dockerize", flag.ContinueOnError)
fs.StringVar(&baseImage, "image", "library/golang", "Set the base image of the Docker container.")
fs.StringVar(&expose, "expose", "8080", "Port(s) to expose in the Docker container.")
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)
}
@ -89,7 +100,7 @@ func dockerizeApp(cmd *commands.Command, args []string) int {
beeLogger.Log.Fatalf("Error parsing flags: %v", err.Error())
}
beeLogger.Log.Info("Generating Dockerfile...")
beeLogger.Log.Info("Generating Dockerfile and docker-compose.yaml...")
gopath := os.Getenv("GOPATH")
dir, err := filepath.Abs(".")
@ -102,19 +113,31 @@ func dockerizeApp(cmd *commands.Command, args []string) int {
// In case of multiple ports to expose inside the container,
// replace all the commas with whitespaces.
// See the verb EXPOSE in the Docker documentation.
if strings.Contains(expose, ",") {
expose = strings.Replace(expose, ",", " ", -1)
}
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: expose,
Expose: exposedockerfile,
}
composefile := Composefile{
Appname: entrypoint,
Expose: exposecompose,
}
generateDockerfile(dockerfile)
generatecomposefile(composefile)
return 0
}
@ -131,3 +154,17 @@ func generateDockerfile(df Dockerfile) {
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

@ -17,13 +17,13 @@ import (
"os"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
"github.com/beego/bee/generate"
"github.com/beego/bee/generate/swaggergen"
"github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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{
@ -53,6 +53,10 @@ var CmdGenerate = &commands.Command{
$ 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]
@ -72,6 +76,15 @@ func init() {
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)
}
@ -81,15 +94,6 @@ func GenerateCode(cmd *commands.Command, args []string) int {
beeLogger.Log.Fatal("Command is missing")
}
gps := utils.GetGOPATHs()
if len(gps) == 0 {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
gopath := gps[0]
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
gcmd := args[0]
switch gcmd {
case "scaffold":
@ -106,6 +110,8 @@ func GenerateCode(cmd *commands.Command, args []string) int {
model(cmd, args, currpath)
case "view":
view(args, currpath)
case "routers":
genRouters(cmd, args)
default:
beeLogger.Log.Fatal("Command is missing")
}
@ -113,6 +119,16 @@ func GenerateCode(cmd *commands.Command, args []string) int {
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")

View File

@ -1,18 +1,19 @@
package hprose
import (
"os"
"fmt"
"os"
"path"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/api"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/generate"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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{
@ -24,7 +25,7 @@ var CmdHproseapp = &commands.Command{
{{"To scaffold out your application, use:"|bold}}
$ bee hprose [appname] [-tables=""] [-driver=mysql] [-conn=root:@tcp(127.0.0.1:3306)/test]
$ 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.
@ -32,6 +33,7 @@ var CmdHproseapp = &commands.Command{
The command 'hprose' creates a folder named [appname] with the following structure:
main.go
go.mod
{{"conf"|foldername}}
app.conf
{{"models"|foldername}}
@ -42,34 +44,77 @@ var CmdHproseapp = &commands.Command{
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) != 1 {
if len(args) == 0 {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
curpath, _ := os.Getwd()
if len(args) > 1 {
cmd.Flag.Parse(args[1:])
if len(args) >= 2 {
err := cmd.Flag.Parse(args[1:])
if err != nil {
beeLogger.Log.Fatal("Parse args err " + err.Error())
}
}
apppath, packpath, err := utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
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")

View File

@ -23,12 +23,12 @@ import (
"strings"
"time"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
"github.com/beego/bee/utils"
"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/logger"
beeLogger "github.com/beego/bee/v2/logger"
)
var CmdMigrate = &commands.Command{
@ -38,19 +38,19 @@ var CmdMigrate = &commands.Command{
{{"To run all the migrations:"|bold}}
$ bee migrate [-driver=mysql] [-conn="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"]
{{"To rollback the last migration:"|bold}}
$ bee migrate rollback [-driver=mysql] [-conn="root:@tcp(127.0.0.1:3306)/test"]
$ 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"]
$ 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"]
$ 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,
@ -58,10 +58,12 @@ var CmdMigrate = &commands.Command{
var mDriver utils.DocValue
var mConn utils.DocValue
var mDir utils.DocValue
func init() {
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)
}
@ -69,15 +71,6 @@ func init() {
func RunMigration(cmd *commands.Command, args []string) int {
currpath, _ := os.Getwd()
gps := utils.GetGOPATHs()
if len(gps) == 0 {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
gopath := gps[0]
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
// Getting command line arguments
if len(args) != 0 {
cmd.Flag.Parse(args[1:])
@ -94,25 +87,41 @@ func RunMigration(cmd *commands.Command, args []string) int {
mConn = "root:@tcp(127.0.0.1:3306)/test"
}
}
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)
beeLogger.Log.Infof("Using '%s' as 'conn'", mConn)
driverStr, connStr := string(mDriver), string(mConn)
//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
beeLogger.Log.Info("Running all outstanding migrations")
MigrateUpdate(currpath, driverStr, connStr)
MigrateUpdate(currpath, driverStr, connStr, dirStr)
} else {
mcmd := args[0]
switch mcmd {
case "rollback":
beeLogger.Log.Info("Rolling back the last migration operation")
MigrateRollback(currpath, driverStr, connStr)
MigrateRollback(currpath, driverStr, connStr, dirStr)
case "reset":
beeLogger.Log.Info("Reseting all migrations")
MigrateReset(currpath, driverStr, connStr)
MigrateReset(currpath, driverStr, connStr, dirStr)
case "refresh":
beeLogger.Log.Info("Refreshing all migrations")
MigrateRefresh(currpath, driverStr, connStr)
MigrateRefresh(currpath, driverStr, connStr, dirStr)
default:
beeLogger.Log.Fatal("Command is missing")
}
@ -122,8 +131,10 @@ func RunMigration(cmd *commands.Command, args []string) int {
}
// 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")
func migrate(goal, currpath, driver, connStr, dir string) {
if dir == "" {
dir = path.Join(currpath, "database", "migrations")
}
postfix := ""
if runtime.GOOS == "windows" {
postfix = ".exe"
@ -187,8 +198,8 @@ func checkForSchemaUpdateTable(db *sql.DB, driver string) {
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" {
beeLogger.Log.Hint("Expecting TYPE: timestamp, DEFAULT: CURRENT_TIMESTAMP")
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)
}
}
@ -355,8 +366,8 @@ const (
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"
_ "{{DriverRepo}}"
)
@ -415,21 +426,21 @@ CREATE TABLE migrations (
)
// MigrateUpdate does the schema update
func MigrateUpdate(currpath, driver, connStr string) {
migrate("upgrade", currpath, driver, connStr)
func MigrateUpdate(currpath, driver, connStr, dir string) {
migrate("upgrade", currpath, driver, connStr, dir)
}
// MigrateRollback rolls back the latest migration
func MigrateRollback(currpath, driver, connStr string) {
migrate("rollback", currpath, driver, connStr)
func MigrateRollback(currpath, driver, connStr, dir string) {
migrate("rollback", currpath, driver, connStr, dir)
}
// MigrateReset rolls back all migrations
func MigrateReset(currpath, driver, connStr string) {
migrate("reset", currpath, driver, connStr)
func MigrateReset(currpath, driver, connStr, dir string) {
migrate("reset", currpath, driver, connStr, dir)
}
// migrationRefresh rolls back all migrations and start over again
func MigrateRefresh(currpath, driver, connStr string) {
migrate("refresh", currpath, driver, connStr)
// MigrateRefresh rolls back all migrations and start over again
func MigrateRefresh(currpath, driver, connStr, dir string) {
migrate("refresh", currpath, driver, connStr, dir)
}

View File

@ -20,22 +20,26 @@ import (
path "path/filepath"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"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 gopath utils.DocValue
var beegoVersion utils.DocValue
var CmdNew = &commands.Command{
UsageLine: "new [appname]",
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.
The command 'new' creates a folder named [appname] and generates the following structure:
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:
main.go
go.mod
{{"conf"|foldername}}
app.conf
{{"controllers"|foldername}}
@ -53,7 +57,7 @@ Creates a Beego application for the given app name in the current directory.
index.tpl
`,
PreRun: func(cmd *commands.Command, args []string) { version.ShowShortVersionBanner() },
PreRun: nil,
Run: CreateApp,
}
@ -66,7 +70,7 @@ var maingo = `package main
import (
_ "{{.Appname}}/routers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func main() {
@ -78,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 (
@ -94,14 +104,17 @@ 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)
}
@ -113,7 +126,7 @@ func TestBeego(t *testing.T) {
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestBeego", "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() {
@ -130,7 +143,7 @@ func TestBeego(t *testing.T) {
var controllers = `package controllers
import (
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
type MainController struct {
@ -138,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"
}
@ -245,22 +258,44 @@ var reloadJsClient = `function b(a){var c=new WebSocket(a);c.onclose=function(){
`
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) != 1 {
if len(args) == 0 {
beeLogger.Log.Fatal("Argument [appname] is missing")
}
apppath, packpath, err := utils.CheckEnv(args[0])
if err != nil {
beeLogger.Log.Fatalf("%s", err)
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)
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)
@ -269,46 +304,55 @@ func CreateApp(cmd *commands.Command, args []string) int {
beeLogger.Log.Info("Creating application...")
os.MkdirAll(apppath, 0755)
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))
// If it is the current directory, select the current folder name to package path
if packPath == "." {
packPath = path.Base(appPath)
}
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)
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, "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, "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, "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, "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, "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, "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, "main.go"), "\x1b[0m")
utils.WriteToFile(path.Join(apppath, "main.go"), strings.Replace(maingo, "{{.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

@ -18,10 +18,10 @@ import (
"syscall"
"time"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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 = &commands.Command{
@ -40,6 +40,7 @@ var CmdPack = &commands.Command{
var (
appPath string
appName string
excludeP string
excludeS string
outputP string
@ -57,6 +58,7 @@ func init() {
fs := flag.NewFlagSet("pack", flag.ContinueOnError)
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.")
@ -445,7 +447,9 @@ func packApp(cmd *commands.Command, args []string) int {
beeLogger.Log.Infof("Packaging application on '%s'...", thePath)
appName := path.Base(thePath)
if len(appName) == 0 {
appName = path.Base(thePath)
}
goos := runtime.GOOS
if v, found := syscall.Getenv("GOOS"); found {
@ -470,7 +474,7 @@ func packApp(cmd *commands.Command, args []string) int {
}()
if build {
beeLogger.Log.Info("Building application...")
beeLogger.Log.Infof("Building application (%v)...", appName)
var envs []string
for _, env := range buildEnvs {
parts := strings.SplitN(env, "=", 2)
@ -553,7 +557,8 @@ func packApp(cmd *commands.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 {

View File

@ -24,12 +24,12 @@ import (
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
"github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"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{

View File

@ -7,12 +7,12 @@ import (
"os"
"strings"
beeLogger "github.com/beego/bee/logger"
beeLogger "github.com/beego/bee/v2/logger"
)
var (
swaggerVersion = "3"
swaggerlink = "https://github.com/beego/swagger/archive/v" + swaggerVersion + ".zip"
swaggerVersion = "4.6.1"
swaggerlink = "https://codeload.github.com/beego/swagger/zip/refs/tags/v" + swaggerVersion
)
func downloadFromURL(url, fileName string) {

View File

@ -18,7 +18,7 @@ import (
"net/http"
"time"
beeLogger "github.com/beego/bee/logger"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/gorilla/websocket"
)

View File

@ -20,11 +20,11 @@ import (
"runtime"
"strings"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/config"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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{
@ -46,6 +46,8 @@ var (
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
@ -72,6 +74,7 @@ func init() {
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.")
@ -79,37 +82,44 @@ func init() {
commands.AvailableCommands = append(commands.AvailableCommands, CmdRun)
}
// RunApp locates files to watch, and starts the beego application
func RunApp(cmd *commands.Command, args []string) int {
if len(args) == 0 || args[0] == "watchall" {
currpath, _ = os.Getwd()
if found, _gopath, _ := utils.SearchGOPATHs(currpath); found {
appname = path.Base(currpath)
currentGoPath = _gopath
} else {
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", currpath)
}
} else {
// Check if passed Bee application path/name exists in the GOPATH(s)
if found, _gopath, _path := utils.SearchGOPATHs(args[0]); found {
currpath = _path
currentGoPath = _gopath
appname = path.Base(currpath)
} else {
beeLogger.Log.Fatalf("No application '%s' found in your GOPATH", args[0])
}
// The default app path is the current working directory
appPath, _ := os.Getwd()
if strings.HasSuffix(appname, ".go") && utils.IsExist(currpath) {
// 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(), currpath)
beeLogger.Log.Debugf("Current path: %s", utils.FILE(), utils.LINE(), appPath)
if runmode == "prod" || runmode == "dev" {
os.Setenv("BEEGO_RUNMODE", runmode)
@ -122,7 +132,7 @@ func RunApp(cmd *commands.Command, args []string) int {
}
var paths []string
readAppDirectories(currpath, &paths)
readAppDirectories(appPath, &paths)
// Because monitor files has some issues, we watch current directory
// and ignore non-go files.
@ -159,7 +169,7 @@ func RunApp(cmd *commands.Command, args []string) int {
}
}
if downdoc == "true" {
if _, err := os.Stat(path.Join(currpath, "swagger", "index.html")); err != nil {
if _, err := os.Stat(path.Join(appPath, "swagger", "index.html")); err != nil {
if os.IsNotExist(err) {
downloadFromURL(swaggerlink, "swagger.zip")
unzipAndDelete("swagger.zip")

View File

@ -24,10 +24,10 @@ import (
"sync"
"time"
"github.com/beego/bee/config"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"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"
)
@ -39,11 +39,11 @@ var (
watchExts = config.Conf.WatchExts
watchExtsStatic = config.Conf.WatchExtsStatic
ignoredFilesRegExps = []string{
`.#(\w+).go`,
`.(\w+).go.swp`,
`(\w+).go~`,
`(\w+).tmp`,
`commentsRouter_controllers.go`,
`.#(\w+).go$`,
`.(\w+).go.swp$`,
`(\w+).go~$`,
`(\w+).tmp$`,
`commentsRouter_controllers.go$`,
}
)
@ -85,7 +85,7 @@ func NewWatcher(paths []string, files []string, isgenerate bool) {
go func() {
// Wait 1s before autobuild until there is no file change.
scheduleTime = time.Now().Add(1 * time.Second)
time.Sleep(scheduleTime.Sub(time.Now()))
time.Sleep(time.Until(scheduleTime))
AutoBuild(files, isgenerate)
if config.Conf.EnableReload {
@ -148,7 +148,7 @@ func AutoBuild(files []string, isgenerate bool) {
}
appName := appname
if err == nil {
if runtime.GOOS == "windows" {
appName += ".exe"
}
@ -158,6 +158,9 @@ func AutoBuild(files []string, isgenerate bool) {
if buildTags != "" {
args = append(args, "-tags", buildTags)
}
if buildLDFlags != "" {
args = append(args, "-ldflags", buildLDFlags)
}
args = append(args, files...)
bcmd := exec.Command(cmdName, args...)
@ -183,9 +186,29 @@ func Kill() {
}
}()
if cmd != nil && cmd.Process != nil {
err := cmd.Process.Kill()
if err != nil {
beeLogger.Log.Errorf("Error while killing cmd process: %s", err)
// 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
}
}
}

View File

@ -17,13 +17,13 @@ package apiapp
import (
"net/http"
beeLogger "github.com/beego/bee/logger"
beeLogger "github.com/beego/bee/v2/logger"
"os"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/cmd/commands/version"
"github.com/beego/bee/utils"
"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{

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

@ -9,20 +9,21 @@ import (
"time"
beeLogger "github.com/beego/bee/logger"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/utils"
)
// RuntimeInfo holds information about the current runtime.
type RuntimeInfo struct {
GoVersion string
GOOS string
GOARCH string
NumCPU int
GOPATH string
GOROOT string
Compiler string
BeeVersion string
BeegoVersion string
GoVersion string
GOOS string
GOARCH string
NumCPU int
GOPATH string
GOROOT string
Compiler string
BeeVersion string
Published string
}
// InitBanner loads the banner and prints it to output
@ -51,7 +52,7 @@ func show(out io.Writer, content string) {
}
err = t.Execute(out, RuntimeInfo{
GetGoVersion(),
runtime.Version(),
runtime.GOOS,
runtime.GOARCH,
runtime.NumCPU(),
@ -59,7 +60,7 @@ func show(out io.Writer, content string) {
runtime.GOROOT(),
runtime.Compiler,
version,
GetBeegoVersion(),
utils.GetLastPublishedTime(),
})
if err != nil {
beeLogger.Log.Error(err.Error())

View File

@ -1,24 +1,18 @@
package version
import (
"bufio"
"bytes"
"encoding/json"
"flag"
"fmt"
"io"
"os"
"os/exec"
path "path/filepath"
"regexp"
"runtime"
"strings"
"github.com/beego/bee/cmd/commands"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"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______
@ -28,7 +22,6 @@ const verboseVersionBanner string = `%s%s______
| |_/ /| __/| __/
\____/ \___| \___| v{{ .BeeVersion }}%s
%s%s
Beego : {{ .BeegoVersion }}
GoVersion : {{ .GoVersion }}
GOOS : {{ .GOOS }}
GOARCH : {{ .GOARCH }}
@ -57,7 +50,7 @@ Prints the current Bee, Beego and Go version alongside the platform information.
}
var outputFormat string
const version = "1.10.0"
const version = config.Version
func init() {
fs := flag.NewFlagSet("version", flag.ContinueOnError)
@ -73,15 +66,14 @@ func versionCmd(cmd *commands.Command, args []string) int {
if outputFormat != "" {
runtimeInfo := RuntimeInfo{
GetGoVersion(),
runtime.GOOS,
runtime.GOARCH,
runtime.NumCPU(),
os.Getenv("GOPATH"),
runtime.GOROOT(),
runtime.Compiler,
version,
GetBeegoVersion(),
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":
@ -116,60 +108,3 @@ func ShowShortVersionBanner() {
output := colors.NewColorWriter(os.Stdout)
InitBanner(output, bytes.NewBufferString(colors.MagentaBold(shortVersionBanner)))
}
func GetBeegoVersion() string {
re, err := regexp.Compile(`VERSION = "([0-9.]+)"`)
if err != nil {
return ""
}
wgopath := utils.GetGOPATHs()
if len(wgopath) == 0 {
beeLogger.Log.Error("You need to set GOPATH environment variable")
return ""
}
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
}
beeLogger.Log.Error("Error while getting stats of 'beego.go'")
}
fd, err := os.Open(filename)
if err != nil {
beeLogger.Log.Error("Error while reading 'beego.go'")
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 is not installed. Please do consider installing it first: https://github.com/astaxie/beego"
}
func GetGoVersion() string {
var (
cmdOut []byte
err error
)
if cmdOut, err = exec.Command("go", "version").Output(); err != nil {
beeLogger.Log.Fatalf("There was an error running 'go version' command: %s", err)
}
return strings.Split(string(cmdOut), " ")[2]
}

View File

@ -4,7 +4,7 @@
// 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
// 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
@ -19,12 +19,18 @@ import (
"os"
"path/filepath"
beeLogger "github.com/beego/bee/logger"
"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"`
@ -77,6 +83,7 @@ type bale struct {
type database struct {
Driver string
Conn string
Dir string
}
// LoadConfig loads the bee tool configuration.

View File

@ -14,7 +14,7 @@
package generate
import "github.com/beego/bee/utils"
import "github.com/beego/bee/v2/utils"
var SQLDriver utils.DocValue
var SQLConn utils.DocValue
@ -22,3 +22,9 @@ 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

@ -15,17 +15,19 @@
package generate
import (
"bufio"
"database/sql"
"fmt"
"io"
"os"
"path"
"path/filepath"
"regexp"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
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"
)
@ -923,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) {
@ -948,11 +950,40 @@ func getFileName(tbName string) (filename string) {
func getPackagePath(curpath string) (packpath string) {
gopath := os.Getenv("GOPATH")
if gopath == "" {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
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)
}
beeLogger.Log.Debugf("GOPATH: %s", utils.FILE(), utils.LINE(), gopath)
appsrcpath := ""
haspath := false
wgopath := filepath.SplitList(gopath)
@ -992,7 +1023,7 @@ import (
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"
)
{{modelStruct}}
@ -1141,7 +1172,7 @@ import (
"strconv"
"strings"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// {{ctrlName}}Controller operations for {{ctrlName}}
@ -1316,7 +1347,7 @@ package routers
import (
"{{pkgPath}}/controllers"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func init() {

View File

@ -20,9 +20,9 @@ import (
"path"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
func GenerateController(cname, currpath string) {
@ -78,7 +78,7 @@ func GenerateController(cname, currpath string) {
var controllerTpl = `package {{packageName}}
import (
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// {{controllerName}}Controller operations for {{controllerName}}
@ -166,7 +166,7 @@ import (
"strconv"
"strings"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
// {{controllerName}}Controller operations for {{controllerName}}

View File

@ -24,9 +24,9 @@ import (
"path"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
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"
)
@ -47,7 +47,7 @@ import (
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
"github.com/astaxie/beego"
beego "github.com/beego/beego/v2/server/web"
)
func logInvokeHandler(
@ -90,8 +90,8 @@ import (
"{{.Appname}}/models"
"github.com/hprose/hprose-golang/rpc"
"github.com/astaxie/beego"
"github.com/astaxie/beego/orm"
beego "github.com/beego/beego/v2/server/web"
"github.com/beego/beego/v2/client/orm"
{{.DriverPkg}}
)
@ -419,7 +419,7 @@ import (
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"
)
{{modelStruct}}

View File

@ -21,9 +21,9 @@ import (
"strings"
"time"
"github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
"github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
const (
@ -238,7 +238,7 @@ func GenerateMigration(mname, upsql, downsql, curpath string) {
const (
MigrationHeader = `package main
import (
"github.com/astaxie/beego/migration"
"github.com/beego/beego/v2/client/orm/migration"
)
// DO NOT MODIFY

View File

@ -21,9 +21,9 @@ import (
"path"
"strings"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
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) {
@ -145,7 +145,7 @@ import (
"reflect"
"strings"
{{timePkg}}
"github.com/astaxie/beego/orm"
"github.com/beego/beego/v2/client/orm"
)
{{modelStruct}}

View File

@ -3,9 +3,9 @@ package generate
import (
"strings"
"github.com/beego/bee/cmd/commands/migrate"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/utils"
"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) {
@ -44,7 +44,7 @@ func GenerateScaffold(sname, fields, currpath, driver, conn string) {
// Run the migration
beeLogger.Log.Infof("Do you want to migrate the database? [Yes|No] ")
if utils.AskForConfirmation() {
migrate.MigrateUpdate(currpath, driver, conn)
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

@ -19,9 +19,9 @@ import (
"os"
"path"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/utils"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/bee/v2/logger/colors"
"github.com/beego/bee/v2/utils"
)
// recipe

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
}

View File

@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"go/ast"
"go/build"
"go/parser"
"go/token"
"os"
@ -32,12 +33,13 @@ import (
"strings"
"unicode"
"gopkg.in/yaml.v2"
yaml "gopkg.in/yaml.v2"
"github.com/astaxie/beego/swagger"
"github.com/astaxie/beego/utils"
beeLogger "github.com/beego/bee/logger"
bu "github.com/beego/bee/utils"
bu "github.com/beego/bee/v2/utils"
beeLogger "github.com/beego/bee/v2/logger"
"github.com/beego/beego/v2/core/utils"
"github.com/beego/beego/v2/server/web/swagger"
)
const (
@ -48,6 +50,12 @@ const (
aform = "multipart/form-data"
)
const (
astTypeArray = "array"
astTypeObject = "object"
astTypeMap = "map"
)
var pkgCache map[string]struct{} //pkg:controller:function:comments comments: key:value
var controllerComments map[string]string
var importlist map[string]string
@ -55,6 +63,7 @@ var controllerList map[string]map[string]*swagger.Item //controllername Paths it
var modelsList map[string]map[string]swagger.Schema
var rootapi swagger.Swagger
var astPkgs []*ast.Package
var pkgLoadedCache map[string]struct{}
// refer to builtin.go
var basicTypes = map[string]string{
@ -78,11 +87,17 @@ var basicTypes = map[string]string{
"byte": "string:byte",
"rune": "string:byte",
// builtin golang objects
"time.Time": "string:datetime",
"time.Time": "string:datetime",
"json.RawMessage": "object:",
}
var stdlibObject = map[string]string{
"&{time Time}": "time.Time",
"&{time Time}": "time.Time",
"&{json RawMessage}": "json.RawMessage",
}
var customObject = map[string]string{
"&{base ObjectID}": "string",
}
func init() {
@ -92,10 +107,11 @@ func init() {
controllerList = make(map[string]map[string]*swagger.Item)
modelsList = make(map[string]map[string]swagger.Schema)
astPkgs = make([]*ast.Package, 0)
pkgLoadedCache = make(map[string]struct{})
}
// ParsePackagesFromDir parses packages from a given directory
func ParsePackagesFromDir(dirpath string) {
// parsePackagesFromDir parses packages from a given directory
func parsePackagesFromDir(dirpath string) {
c := make(chan error)
go func() {
@ -111,12 +127,12 @@ func ParsePackagesFromDir(dirpath string) {
// all 'tests' folders and dot folders wihin dirpath
d, _ := filepath.Rel(dirpath, fpath)
if !(d == "vendor" || strings.HasPrefix(d, "vendor"+string(os.PathSeparator))) &&
!strings.Contains(fpath, "tests") &&
!strings.Contains(d, "tests") &&
!(d[0] == '.') {
err = parsePackageFromDir(fpath)
if err != nil {
// Send the error to through the channel and continue walking
c <- fmt.Errorf("Error while parsing directory: %s", err.Error())
c <- fmt.Errorf("error while parsing directory: %s", err.Error())
return nil
}
}
@ -144,13 +160,29 @@ func parsePackageFromDir(path string) error {
astPkgs = append(astPkgs, v)
}
if len(folderPkgs) != 0 {
workPath := bu.GetBeeWorkPath()
parentPath := filepath.Dir(workPath)
rel, err := filepath.Rel(parentPath, path)
if err != nil {
return err
}
pkgLoadedCache[rel] = struct{}{}
}
return nil
}
// GenerateDocs generates documentations for a given path.
func GenerateDocs(curpath string) {
fset := token.NewFileSet()
pkgspath := curpath
workspace := os.Getenv("BeeWorkspace")
if workspace != "" {
pkgspath = workspace
}
parsePackagesFromDir(pkgspath)
fset := token.NewFileSet()
f, err := parser.ParseFile(fset, filepath.Join(curpath, "routers", "router.go"), nil, parser.ParseComments)
if err != nil {
beeLogger.Log.Fatalf("Error while parsing router.go: %s", err)
@ -168,7 +200,7 @@ func GenerateDocs(curpath string) {
} 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"):])
rootapi.Infos.Description += fmt.Sprintf("%s\n", 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") {
@ -255,7 +287,7 @@ func GenerateDocs(curpath string) {
if im.Name != nil {
localName = im.Name.Name
}
analyseControllerPkg(path.Join(curpath, "vendor"), localName, im.Path.Value)
analyseControllerPkg(localName, im.Path.Value)
}
for _, d := range f.Decls {
switch specDecl := d.(type) {
@ -410,12 +442,12 @@ func analyseNSInclude(baseurl string, ce *ast.CallExpr) string {
return cname
}
func analyseControllerPkg(vendorPath, localName, pkgpath string) {
func analyseControllerPkg(localName, pkgpath string) {
pkgpath = strings.Trim(pkgpath, "\"")
if isSystemPackage(pkgpath) {
return
}
if pkgpath == "github.com/astaxie/beego" {
if pkgpath == "github.com/beego/beego/v2/server/web" {
return
}
if localName != "" {
@ -424,32 +456,19 @@ func analyseControllerPkg(vendorPath, localName, pkgpath string) {
pps := strings.Split(pkgpath, "/")
importlist[pps[len(pps)-1]] = pkgpath
}
gopaths := bu.GetGOPATHs()
if len(gopaths) == 0 {
beeLogger.Log.Fatal("GOPATH environment variable is not set or empty")
}
pkgRealpath := ""
wg, _ := filepath.EvalSymlinks(filepath.Join(vendorPath, pkgpath))
if utils.FileExists(wg) {
pkgRealpath = wg
} else {
wgopath := gopaths
for _, wg := range wgopath {
wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src", pkgpath))
if utils.FileExists(wg) {
pkgRealpath = wg
break
}
}
pkg, err := build.Default.Import(pkgpath, ".", build.FindOnly)
if err != nil {
beeLogger.Log.Fatalf("Package %s cannot be imported: %v", pkgpath, err)
}
pkgRealpath := pkg.Dir
if pkgRealpath != "" {
if _, ok := pkgCache[pkgpath]; ok {
return
}
pkgCache[pkgpath] = struct{}{}
} else {
beeLogger.Log.Fatalf("Package '%s' does not exist in the GOPATH or vendor path", pkgpath)
beeLogger.Log.Fatalf("Package '%s' does not have source directory", pkgpath)
}
fileSet := token.NewFileSet()
@ -460,6 +479,7 @@ func analyseControllerPkg(vendorPath, localName, pkgpath string) {
if err != nil {
beeLogger.Log.Fatalf("Error while parsing dir at '%s': %s", pkgpath, err)
}
for _, pkg := range astPkgs {
for _, fl := range pkg.Files {
for _, d := range fl.Decls {
@ -533,7 +553,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
//TODO: resultMap := buildParamMap(f.Type.Results)
if comments != nil && comments.List != nil {
for _, c := range comments.List {
t := strings.TrimSpace(strings.TrimLeft(c.Text, "//"))
t := strings.TrimSpace(strings.TrimPrefix(c.Text, "//"))
if strings.HasPrefix(t, "@router") {
elements := strings.TrimSpace(t[len("@router"):])
e1 := strings.SplitN(elements, " ", 2)
@ -550,7 +570,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
} 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"):])
opts.Description += fmt.Sprintf("%s\n<br>", strings.TrimSpace(t[len("@Description"):]))
} else if strings.HasPrefix(t, "@Summary") {
opts.Summary = strings.TrimSpace(t[len("@Summary"):])
} else if strings.HasPrefix(t, "@Success") {
@ -586,7 +606,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
}
if isArray {
rs.Schema = &swagger.Schema{
Type: "array",
Type: astTypeArray,
Items: &schema,
}
} else {
@ -640,7 +660,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
m, mod, realTypes := getModel(p[2])
if isArray {
para.Schema = &swagger.Schema{
Type: "array",
Type: astTypeArray,
Items: &swagger.Schema{
Ref: "#/definitions/" + m,
},
@ -722,7 +742,7 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error {
}
}
}
routerPath = urlReplace(routerPath)
if routerPath != "" {
//Go over function parameters which were not mapped and create swagger params for them
for name, typ := range funcParamMap {
@ -781,12 +801,23 @@ func setParamType(para *swagger.Parameter, typ string, pkgpath, controllerName s
isArray = true
}
if typ == "string" || typ == "number" || typ == "integer" || typ == "boolean" ||
typ == "array" || typ == "file" {
typ == astTypeArray || typ == "file" {
paraType = typ
if para.In == "body" {
para.Schema = &swagger.Schema{
Type: paraType,
}
}
} else if sType, ok := basicTypes[typ]; ok {
typeFormat := strings.Split(sType, ":")
paraType = typeFormat[0]
paraFormat = typeFormat[1]
if para.In == "body" {
para.Schema = &swagger.Schema{
Type: paraType,
Format: paraFormat,
}
}
} else {
m, mod, realTypes := getModel(typ)
para.Schema = &swagger.Schema{
@ -801,14 +832,14 @@ func setParamType(para *swagger.Parameter, typ string, pkgpath, controllerName s
if isArray {
if para.In == "body" {
para.Schema = &swagger.Schema{
Type: "array",
Type: astTypeArray,
Items: &swagger.Schema{
Type: paraType,
Format: paraFormat,
},
}
} else {
para.Type = "array"
para.Type = astTypeArray
para.Items = &swagger.ParameterItems{
Type: paraType,
Format: paraFormat,
@ -901,49 +932,61 @@ func getparams(str string) []string {
return r
}
func getModel(str string) (objectname string, m swagger.Schema, realTypes []string) {
func getModel(str string) (definitionName string, m swagger.Schema, realTypes []string) {
strs := strings.Split(str, ".")
objectname = strs[len(strs)-1]
packageName := ""
m.Type = "object"
// strs = [packageName].[objectName]
packageName := strs[0]
objectname := strs[len(strs)-1]
// Default all swagger schemas to object, if no other type is found
m.Type = astTypeObject
L:
for _, pkg := range astPkgs {
if strs[0] == pkg.Name {
for _, fl := range pkg.Files {
for k, d := range fl.Scope.Objects {
if d.Kind == ast.Typ {
if k != objectname {
// Still searching for the right object
continue
}
packageName = pkg.Name
parseObject(d, k, &m, &realTypes, astPkgs, pkg.Name)
parseObject(fl.Imports, d, k, &m, &realTypes, astPkgs, packageName)
// When we've found the correct object, we can stop searching
break L
}
}
}
}
}
if m.Title == "" {
beeLogger.Log.Warnf("Cannot find the object: %s", str)
// Don't log when error has already been logged
if _, found := rootapi.Definitions[str]; !found {
beeLogger.Log.Warnf("Cannot find the object: %s", str)
}
m.Title = objectname
// TODO remove when all type have been supported
//os.Exit(1)
}
if len(rootapi.Definitions) == 0 {
rootapi.Definitions = make(map[string]swagger.Schema)
}
objectname = packageName + "." + objectname
rootapi.Definitions[objectname] = m
return
rootapi.Definitions[str] = m
return str, m, realTypes
}
func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
func parseObject(imports []*ast.ImportSpec, d *ast.Object, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
ts, ok := d.Decl.(*ast.TypeSpec)
if !ok {
beeLogger.Log.Fatalf("Unknown type without TypeSec: %v\n", d)
beeLogger.Log.Fatalf("Unknown type without TypeSec: %v", d)
}
// TODO support other types, such as `ArrayType`, `MapType`, `InterfaceType` etc...
// TODO support other types, such as `MapType`, `InterfaceType` etc...
switch t := ts.Type.(type) {
case *ast.ArrayType:
m.Title = k
m.Type = "array"
m.Type = astTypeArray
if isBasicType(fmt.Sprint(t.Elt)) {
typeFormat := strings.Split(basicTypes[fmt.Sprint(t.Elt)], ":")
m.Format = typeFormat[0]
@ -959,7 +1002,7 @@ func parseObject(d *ast.Object, k string, m *swagger.Schema, realTypes *[]string
case *ast.Ident:
parseIdent(t, k, m, astPkgs)
case *ast.StructType:
parseStruct(t, k, m, realTypes, astPkgs, packageName)
parseStruct(imports, t, k, m, realTypes, astPkgs, packageName)
}
}
@ -970,8 +1013,8 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
if object, isStdLibObject := stdlibObject[basicType]; isStdLibObject {
basicType = object
}
if k, ok := basicTypes[basicType]; ok {
typeFormat := strings.Split(k, ":")
if t, ok := basicTypes[basicType]; ok {
typeFormat := strings.Split(t, ":")
m.Type = typeFormat[0]
m.Format = typeFormat[1]
}
@ -983,7 +1026,7 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
if obj.Kind == ast.Con {
vs, ok := obj.Decl.(*ast.ValueSpec)
if !ok {
beeLogger.Log.Fatalf("Unknown type without ValueSpec: %v\n", vs)
beeLogger.Log.Fatalf("Unknown type without ValueSpec: %v", vs)
}
ti, ok := vs.Type.(*ast.Ident)
@ -1000,7 +1043,7 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
for i, val := range vs.Values {
v, ok := val.(*ast.BasicLit)
if !ok {
beeLogger.Log.Warnf("Unknown type without BasicLit: %v\n", v)
beeLogger.Log.Warnf("Unknown type without BasicLit: %v", v)
continue
}
enums[int(val.Pos())] = fmt.Sprintf("%s = %s", vs.Names[i].Name, v.Value)
@ -1008,14 +1051,14 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
case token.INT:
vv, err := strconv.Atoi(v.Value)
if err != nil {
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v\n", v.Value)
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v", v.Value)
continue
}
enumValues[int(val.Pos())] = vv
case token.FLOAT:
vv, err := strconv.ParseFloat(v.Value, 64)
if err != nil {
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v\n", v.Value)
beeLogger.Log.Warnf("Unknown type with BasicLit to int: %v", v.Value)
continue
}
enumValues[int(val.Pos())] = vv
@ -1044,13 +1087,13 @@ func parseIdent(st *ast.Ident, k string, m *swagger.Schema, astPkgs []*ast.Packa
}
func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
func parseStruct(imports []*ast.ImportSpec, st *ast.StructType, k string, m *swagger.Schema, realTypes *[]string, astPkgs []*ast.Package, packageName string) {
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)
if (isSlice && isBasicType(realType)) || sType == "object" {
if (isSlice && isBasicType(realType)) || sType == astTypeObject {
if len(strings.Split(realType, " ")) > 1 {
realType = strings.Replace(realType, " ", ".", -1)
realType = strings.Replace(realType, "&", "", -1)
@ -1060,13 +1103,18 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
realType = packageName + "." + realType
}
}
if !isBasicType(realType) && sType == astTypeObject {
checkAndLoadPackage(imports, realType, packageName)
}
*realTypes = append(*realTypes, realType)
mp := swagger.Propertie{}
isObject := false
if isSlice {
mp.Type = "array"
if sType, ok := basicTypes[(strings.Replace(realType, "[]", "", -1))]; ok {
typeFormat := strings.Split(sType, ":")
mp.Type = astTypeArray
if t, ok := basicTypes[(strings.Replace(realType, "[]", "", -1))]; ok {
typeFormat := strings.Split(t, ":")
mp.Items = &swagger.Propertie{
Type: typeFormat[0],
Format: typeFormat[1],
@ -1077,14 +1125,14 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
}
}
} else {
if sType == "object" {
if sType == astTypeObject {
isObject = true
mp.Ref = "#/definitions/" + realType
} else if isBasicType(realType) {
typeFormat := strings.Split(sType, ":")
mp.Type = typeFormat[0]
mp.Format = typeFormat[1]
} else if realType == "map" {
} else if realType == astTypeMap {
typeFormat := strings.Split(sType, ":")
mp.AdditionalProperties = &swagger.Propertie{
Type: typeFormat[0],
@ -1119,8 +1167,11 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
}
}
tag := stag.Get("json")
if ignore := stag.Get("ignore"); ignore != "" {
continue
}
tag := stag.Get("json")
if tag != "" {
tagValues = strings.Split(tag, ",")
}
@ -1133,34 +1184,46 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
name = tagValues[0]
}
// set property type to the second tag value only if it is not omitempty and isBasicType
if len(tagValues) > 1 && tagValues[1] != "omitempty" && isBasicType(tagValues[1]) {
typeFormat := strings.Split(basicTypes[tagValues[1]], ":")
mp.Type = typeFormat[0]
mp.Format = typeFormat[1]
mp.Ref = ""
}
if thrifttag := stag.Get("thrift"); thrifttag != "" {
ts := strings.Split(thrifttag, ",")
if ts[0] != "" {
name = ts[0]
}
}
if required := stag.Get("required"); required != "" {
if required := stag.Get("required"); strings.EqualFold(required, "true") {
m.Required = append(m.Required, name)
}
if desc := stag.Get("description"); desc != "" {
mp.Description = desc
}
if mp.Description == "" && field.Comment != nil {
mp.Description = strings.TrimSpace(field.Comment.Text())
}
if example := stag.Get("example"); example != "" && !isObject && !isSlice {
mp.Example = str2RealType(example, realType)
}
m.Properties[name] = mp
}
if ignore := stag.Get("ignore"); ignore != "" {
continue
}
} else {
// only parse case of when embedded field is TypeName
// cases of *TypeName and Interface are not handled, maybe useless for swagger spec
tag := ""
if field.Tag != nil {
stag := reflect.StructTag(strings.Trim(field.Tag.Value, "`"))
if ignore := stag.Get("ignore"); ignore != "" {
continue
}
tag = stag.Get("json")
}
@ -1180,8 +1243,8 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
for _, pkg := range astPkgs {
for _, fl := range pkg.Files {
for nameOfObj, obj := range fl.Scope.Objects {
if obj.Name == fmt.Sprint(field.Type) {
parseObject(obj, nameOfObj, nm, realTypes, astPkgs, pkg.Name)
if pkg.Name+"."+obj.Name == realType {
parseObject(imports, obj, nameOfObj, nm, realTypes, astPkgs, pkg.Name)
}
}
}
@ -1189,6 +1252,7 @@ func parseStruct(st *ast.StructType, k string, m *swagger.Schema, realTypes *[]s
for name, p := range nm.Properties {
m.Properties[name] = p
}
m.Required = append(m.Required, nm.Required...)
continue
}
}
@ -1201,13 +1265,16 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
if isBasicType(fmt.Sprint(arr.Elt)) {
return true, fmt.Sprintf("[]%v", arr.Elt), basicTypes[fmt.Sprint(arr.Elt)]
}
if object, isCustomObject := customObject[fmt.Sprint(arr.Elt)]; isCustomObject {
return true, fmt.Sprintf("[]%v", object), basicTypes[object]
}
if mp, ok := arr.Elt.(*ast.MapType); ok {
return false, fmt.Sprintf("map[%v][%v]", mp.Key, mp.Value), "object"
return false, fmt.Sprintf("map[%v][%v]", mp.Key, mp.Value), astTypeObject
}
if star, ok := arr.Elt.(*ast.StarExpr); ok {
return true, fmt.Sprint(star.X), "object"
return true, fmt.Sprint(star.X), astTypeObject
}
return true, fmt.Sprint(arr.Elt), "object"
return true, fmt.Sprint(arr.Elt), astTypeObject
}
switch t := f.Type.(type) {
case *ast.StarExpr:
@ -1218,13 +1285,15 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
if k, ok := basicTypes[basicType]; ok {
return false, basicType, k
}
return false, basicType, "object"
return false, basicType, astTypeObject
case *ast.MapType:
val := fmt.Sprintf("%v", t.Value)
if isBasicType(val) {
return false, "map", basicTypes[val]
return false, astTypeMap, basicTypes[val]
}
return false, val, "object"
return false, val, astTypeObject
case *ast.InterfaceType:
return false, "interface", astTypeObject
}
basicType := fmt.Sprint(f.Type)
if object, isStdLibObject := stdlibObject[basicType]; isStdLibObject {
@ -1233,7 +1302,7 @@ func typeAnalyser(f *ast.Field) (isSlice bool, realType, swaggerType string) {
if k, ok := basicTypes[basicType]; ok {
return false, basicType, k
}
return false, basicType, "object"
return false, basicType, astTypeObject
}
func isBasicType(Type string) bool {
@ -1247,7 +1316,7 @@ func isBasicType(Type string) bool {
func appendModels(pkgpath, controllerName string, realTypes []string) {
for _, realType := range realTypes {
if realType != "" && !isBasicType(strings.TrimLeft(realType, "[]")) &&
!strings.HasPrefix(realType, "map") && !strings.HasPrefix(realType, "&") {
!strings.HasPrefix(realType, astTypeMap) && !strings.HasPrefix(realType, "&") {
if _, ok := modelsList[pkgpath+controllerName][realType]; ok {
continue
}
@ -1317,3 +1386,70 @@ func str2RealType(s string, typ string) interface{} {
return ret
}
func checkAndLoadPackage(imports []*ast.ImportSpec, realType, curPkgName string) {
arr := strings.Split(realType, ".")
if len(arr) != 2 {
return
}
objectPkgName := arr[0]
if objectPkgName == curPkgName {
return
}
pkgPath := ""
for _, im := range imports {
importPath := ""
if im.Path != nil {
importPath = strings.Trim(im.Path.Value, `"`)
}
if importPath == "" {
continue
}
if im.Name != nil && im.Name.Name == objectPkgName {
pkgPath = importPath
break
}
_, pkgName := filepath.Split(importPath)
if pkgName == objectPkgName {
pkgPath = importPath
break
}
}
if pkgPath == "" {
beeLogger.Log.Warnf("%s missing import package", realType)
return
}
if isSystemPackage(pkgPath) {
return
}
if _, ok := pkgLoadedCache[pkgPath]; ok {
return
}
pkg, err := build.Default.Import(pkgPath, ".", build.FindOnly)
if err != nil {
beeLogger.Log.Warnf("Package %s cannot be imported, err:%v", pkgPath, err)
return
}
pkgRealpath := pkg.Dir
fileSet := token.NewFileSet()
pkgs, 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 {
beeLogger.Log.Warnf("Error while parsing dir at '%s': %s", pkgRealpath, err)
}
for _, pkg := range pkgs {
astPkgs = append(astPkgs, pkg)
}
pkgLoadedCache[pkgPath] = struct{}{}
}

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=

View File

@ -1,3 +1,3 @@
github.com/beego/bee/cmd/commands/run/*.go:S1024
github.com/beego/bee/cmd/commands/dlv/*.go:S1024
github.com/beego/bee/utils/*.go:S1026
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

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

View File

@ -54,7 +54,7 @@ func NewModeColorWriter(w io.Writer, mode outputMode) io.Writer {
}
func Bold(message string) string {
return fmt.Sprintf("\x1b[1m%s\x1b[21m", message)
return fmt.Sprintf("\x1b[1m%s\x1b[0m", message)
}
// Black returns a black string

View File

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

View File

@ -24,7 +24,7 @@ import (
"text/template"
"time"
"github.com/beego/bee/logger/colors"
"github.com/beego/bee/v2/logger/colors"
)
var errInvalidLogLevel = errors.New("logger: invalid log level")

24
main.go
View File

@ -18,22 +18,14 @@ import (
"log"
"os"
"github.com/beego/bee/cmd"
"github.com/beego/bee/cmd/commands"
"github.com/beego/bee/config"
"github.com/beego/bee/generate/swaggergen"
"github.com/beego/bee/utils"
)
var (
workspace = os.Getenv("BeeWorkspace")
"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() {
currentpath, _ := os.Getwd()
if workspace != "" {
currentpath = workspace
}
utils.NoticeUpdateBee()
flag.Usage = cmd.Usage
flag.Parse()
log.SetFlags(0)
@ -66,12 +58,6 @@ func main() {
}
config.LoadConfig()
// Check if current directory is inside the GOPATH,
// if so parse the packages inside it.
if utils.IsInGOPATH(currentpath) && cmd.IfGenerateDocs(c.Name(), args) {
swaggergen.ParsePackagesFromDir(currentpath)
}
os.Exit(c.Run(c, args))
return
}

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

View File

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

View File

@ -21,7 +21,7 @@ import (
"runtime"
"github.com/beego/bee/config"
"github.com/beego/bee/v2/config"
)
const appName = "Beego"

View File

@ -16,23 +16,50 @@ 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"
beeLogger "github.com/beego/bee/logger"
"github.com/beego/bee/logger/colors"
"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 {
@ -71,7 +98,7 @@ func IsInGOPATH(thePath string) bool {
// 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/astaxie/beego".*?\).*func main()`)
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.
@ -305,6 +332,7 @@ func Tmpl(text string, data interface{}) {
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()
@ -328,7 +356,7 @@ func CheckEnv(appname string) (apppath, packpath string, err error) {
apppath = filepath.Join(gosrcpath, appname)
if _, e := os.Stat(apppath); !os.IsNotExist(e) {
err = fmt.Errorf("Cannot create application without removing '%s' first", apppath)
err = fmt.Errorf("cannot create application without removing '%s' first", apppath)
beeLogger.Log.Errorf("Path '%s' already exists", apppath)
return
}
@ -438,3 +466,187 @@ func defaultGOPATH() string {
}
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])
}

View File

@ -1,10 +1,10 @@
// Copyright 2014 beego Author. All Rights Reserved.
// 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
// 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,
@ -14,12 +14,4 @@
package utils
import (
"reflect"
"runtime"
)
// GetFuncName get function name
func GetFuncName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
const BEEGO_VERSION = "v2.1.0"

View File

@ -1,174 +0,0 @@
// 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.
//
// Swagger™ is a project used to describe and document RESTful APIs.
//
// The Swagger specification defines a set of files required to describe such an API. These files can then be used by the Swagger-UI project to display the API and Swagger-Codegen to generate clients in various languages. Additional utilities can also take advantage of the resulting files, such as testing tools.
// Now in version 2.0, Swagger is more enabling than ever. And it's 100% open source software.
// Package swagger struct definition
package swagger
// Swagger list the resource
type Swagger struct {
SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"`
Infos Information `json:"info" yaml:"info"`
Host string `json:"host,omitempty" yaml:"host,omitempty"`
BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"`
Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"`
Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"`
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Paths map[string]*Item `json:"paths" yaml:"paths"`
Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"`
SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"`
Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"`
Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
// Information Provides metadata about the API. The metadata can be used by the clients if needed.
type Information struct {
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Version string `json:"version,omitempty" yaml:"version,omitempty"`
TermsOfService string `json:"termsOfService,omitempty" yaml:"termsOfService,omitempty"`
Contact Contact `json:"contact,omitempty" yaml:"contact,omitempty"`
License *License `json:"license,omitempty" yaml:"license,omitempty"`
}
// Contact information for the exposed API.
type Contact struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
URL string `json:"url,omitempty" yaml:"url,omitempty"`
EMail string `json:"email,omitempty" yaml:"email,omitempty"`
}
// License information for the exposed API.
type License struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
URL string `json:"url,omitempty" yaml:"url,omitempty"`
}
// Item Describes the operations available on a single path.
type Item struct {
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
Get *Operation `json:"get,omitempty" yaml:"get,omitempty"`
Put *Operation `json:"put,omitempty" yaml:"put,omitempty"`
Post *Operation `json:"post,omitempty" yaml:"post,omitempty"`
Delete *Operation `json:"delete,omitempty" yaml:"delete,omitempty"`
Options *Operation `json:"options,omitempty" yaml:"options,omitempty"`
Head *Operation `json:"head,omitempty" yaml:"head,omitempty"`
Patch *Operation `json:"patch,omitempty" yaml:"patch,omitempty"`
}
// Operation Describes a single API operation on a path.
type Operation struct {
Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"`
Summary string `json:"summary,omitempty" yaml:"summary,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"`
Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"`
Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"`
Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"`
Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"`
Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"`
Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"`
Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"`
}
// Parameter Describes a single operation parameter.
type Parameter struct {
In string `json:"in,omitempty" yaml:"in,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
Schema *Schema `json:"schema,omitempty" yaml:"schema,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Format string `json:"format,omitempty" yaml:"format,omitempty"`
Items *ParameterItems `json:"items,omitempty" yaml:"items,omitempty"`
Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
}
// ParameterItems A limited subset of JSON-Schema's items object. It is used by parameter definitions that are not located in "body".
// http://swagger.io/specification/#itemsObject
type ParameterItems struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Format string `json:"format,omitempty" yaml:"format,omitempty"`
Items []*ParameterItems `json:"items,omitempty" yaml:"items,omitempty"` //Required if type is "array". Describes the type of items in the array.
CollectionFormat string `json:"collectionFormat,omitempty" yaml:"collectionFormat,omitempty"`
Default string `json:"default,omitempty" yaml:"default,omitempty"`
}
// Schema Object allows the definition of input and output data types.
type Schema struct {
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Format string `json:"format,omitempty" yaml:"format,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Items *Schema `json:"items,omitempty" yaml:"items,omitempty"`
Properties map[string]Propertie `json:"properties,omitempty" yaml:"properties,omitempty"`
Enum []interface{} `json:"enum,omitempty" yaml:"enum,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
}
// Propertie are taken from the JSON Schema definition but their definitions were adjusted to the Swagger Specification
type Propertie struct {
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
Title string `json:"title,omitempty" yaml:"title,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Default interface{} `json:"default,omitempty" yaml:"default,omitempty"`
Type string `json:"type,omitempty" yaml:"type,omitempty"`
Example interface{} `json:"example,omitempty" yaml:"example,omitempty"`
Required []string `json:"required,omitempty" yaml:"required,omitempty"`
Format string `json:"format,omitempty" yaml:"format,omitempty"`
ReadOnly bool `json:"readOnly,omitempty" yaml:"readOnly,omitempty"`
Properties map[string]Propertie `json:"properties,omitempty" yaml:"properties,omitempty"`
Items *Propertie `json:"items,omitempty" yaml:"items,omitempty"`
AdditionalProperties *Propertie `json:"additionalProperties,omitempty" yaml:"additionalProperties,omitempty"`
}
// Response as they are returned from executing this operation.
type Response struct {
Description string `json:"description" yaml:"description"`
Schema *Schema `json:"schema,omitempty" yaml:"schema,omitempty"`
Ref string `json:"$ref,omitempty" yaml:"$ref,omitempty"`
}
// Security Allows the definition of a security scheme that can be used by the operations
type Security struct {
Type string `json:"type,omitempty" yaml:"type,omitempty"` // Valid values are "basic", "apiKey" or "oauth2".
Description string `json:"description,omitempty" yaml:"description,omitempty"`
Name string `json:"name,omitempty" yaml:"name,omitempty"`
In string `json:"in,omitempty" yaml:"in,omitempty"` // Valid values are "query" or "header".
Flow string `json:"flow,omitempty" yaml:"flow,omitempty"` // Valid values are "implicit", "password", "application" or "accessCode".
AuthorizationURL string `json:"authorizationUrl,omitempty" yaml:"authorizationUrl,omitempty"`
TokenURL string `json:"tokenUrl,omitempty" yaml:"tokenUrl,omitempty"`
Scopes map[string]string `json:"scopes,omitempty" yaml:"scopes,omitempty"` // The available scopes for the OAuth2 security scheme.
}
// Tag Allows adding meta data to a single tag that is used by the Operation Object
type Tag struct {
Name string `json:"name,omitempty" yaml:"name,omitempty"`
Description string `json:"description,omitempty" yaml:"description,omitempty"`
ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"`
}
// ExternalDocs include Additional external documentation
type ExternalDocs struct {
Description string `json:"description,omitempty" yaml:"description,omitempty"`
URL string `json:"url,omitempty" yaml:"url,omitempty"`
}

View File

@ -1,478 +0,0 @@
// 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 utils
import (
"bytes"
"fmt"
"log"
"reflect"
"runtime"
)
var (
dunno = []byte("???")
centerDot = []byte("·")
dot = []byte(".")
)
type pointerInfo struct {
prev *pointerInfo
n int
addr uintptr
pos int
used []int
}
// Display print the data in console
func Display(data ...interface{}) {
display(true, data...)
}
// GetDisplayString return data print string
func GetDisplayString(data ...interface{}) string {
return display(false, data...)
}
func display(displayed bool, data ...interface{}) string {
var pc, file, line, ok = runtime.Caller(2)
if !ok {
return ""
}
var buf = new(bytes.Buffer)
fmt.Fprintf(buf, "[Debug] at %s() [%s:%d]\n", function(pc), file, line)
fmt.Fprintf(buf, "\n[Variables]\n")
for i := 0; i < len(data); i += 2 {
var output = fomateinfo(len(data[i].(string))+3, data[i+1])
fmt.Fprintf(buf, "%s = %s", data[i], output)
}
if displayed {
log.Print(buf)
}
return buf.String()
}
// return data dump and format bytes
func fomateinfo(headlen int, data ...interface{}) []byte {
var buf = new(bytes.Buffer)
if len(data) > 1 {
fmt.Fprint(buf, " ")
fmt.Fprint(buf, "[")
fmt.Fprintln(buf)
}
for k, v := range data {
var buf2 = new(bytes.Buffer)
var pointers *pointerInfo
var interfaces = make([]reflect.Value, 0, 10)
printKeyValue(buf2, reflect.ValueOf(v), &pointers, &interfaces, nil, true, " ", 1)
if k < len(data)-1 {
fmt.Fprint(buf2, ", ")
}
fmt.Fprintln(buf2)
buf.Write(buf2.Bytes())
}
if len(data) > 1 {
fmt.Fprintln(buf)
fmt.Fprint(buf, " ")
fmt.Fprint(buf, "]")
}
return buf.Bytes()
}
// check data is golang basic type
func isSimpleType(val reflect.Value, kind reflect.Kind, pointers **pointerInfo, interfaces *[]reflect.Value) bool {
switch kind {
case reflect.Bool:
return true
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return true
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
return true
case reflect.Float32, reflect.Float64:
return true
case reflect.Complex64, reflect.Complex128:
return true
case reflect.String:
return true
case reflect.Chan:
return true
case reflect.Invalid:
return true
case reflect.Interface:
for _, in := range *interfaces {
if reflect.DeepEqual(in, val) {
return true
}
}
return false
case reflect.UnsafePointer:
if val.IsNil() {
return true
}
var elem = val.Elem()
if isSimpleType(elem, elem.Kind(), pointers, interfaces) {
return true
}
var addr = val.Elem().UnsafeAddr()
for p := *pointers; p != nil; p = p.prev {
if addr == p.addr {
return true
}
}
return false
}
return false
}
// dump value
func printKeyValue(buf *bytes.Buffer, val reflect.Value, pointers **pointerInfo, interfaces *[]reflect.Value, structFilter func(string, string) bool, formatOutput bool, indent string, level int) {
var t = val.Kind()
switch t {
case reflect.Bool:
fmt.Fprint(buf, val.Bool())
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
fmt.Fprint(buf, val.Int())
case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64:
fmt.Fprint(buf, val.Uint())
case reflect.Float32, reflect.Float64:
fmt.Fprint(buf, val.Float())
case reflect.Complex64, reflect.Complex128:
fmt.Fprint(buf, val.Complex())
case reflect.UnsafePointer:
fmt.Fprintf(buf, "unsafe.Pointer(0x%X)", val.Pointer())
case reflect.Ptr:
if val.IsNil() {
fmt.Fprint(buf, "nil")
return
}
var addr = val.Elem().UnsafeAddr()
for p := *pointers; p != nil; p = p.prev {
if addr == p.addr {
p.used = append(p.used, buf.Len())
fmt.Fprintf(buf, "0x%X", addr)
return
}
}
*pointers = &pointerInfo{
prev: *pointers,
addr: addr,
pos: buf.Len(),
used: make([]int, 0),
}
fmt.Fprint(buf, "&")
printKeyValue(buf, val.Elem(), pointers, interfaces, structFilter, formatOutput, indent, level)
case reflect.String:
fmt.Fprint(buf, "\"", val.String(), "\"")
case reflect.Interface:
var value = val.Elem()
if !value.IsValid() {
fmt.Fprint(buf, "nil")
} else {
for _, in := range *interfaces {
if reflect.DeepEqual(in, val) {
fmt.Fprint(buf, "repeat")
return
}
}
*interfaces = append(*interfaces, val)
printKeyValue(buf, value, pointers, interfaces, structFilter, formatOutput, indent, level+1)
}
case reflect.Struct:
var t = val.Type()
fmt.Fprint(buf, t)
fmt.Fprint(buf, "{")
for i := 0; i < val.NumField(); i++ {
if formatOutput {
fmt.Fprintln(buf)
} else {
fmt.Fprint(buf, " ")
}
var name = t.Field(i).Name
if formatOutput {
for ind := 0; ind < level; ind++ {
fmt.Fprint(buf, indent)
}
}
fmt.Fprint(buf, name)
fmt.Fprint(buf, ": ")
if structFilter != nil && structFilter(t.String(), name) {
fmt.Fprint(buf, "ignore")
} else {
printKeyValue(buf, val.Field(i), pointers, interfaces, structFilter, formatOutput, indent, level+1)
}
fmt.Fprint(buf, ",")
}
if formatOutput {
fmt.Fprintln(buf)
for ind := 0; ind < level-1; ind++ {
fmt.Fprint(buf, indent)
}
} else {
fmt.Fprint(buf, " ")
}
fmt.Fprint(buf, "}")
case reflect.Array, reflect.Slice:
fmt.Fprint(buf, val.Type())
fmt.Fprint(buf, "{")
var allSimple = true
for i := 0; i < val.Len(); i++ {
var elem = val.Index(i)
var isSimple = isSimpleType(elem, elem.Kind(), pointers, interfaces)
if !isSimple {
allSimple = false
}
if formatOutput && !isSimple {
fmt.Fprintln(buf)
} else {
fmt.Fprint(buf, " ")
}
if formatOutput && !isSimple {
for ind := 0; ind < level; ind++ {
fmt.Fprint(buf, indent)
}
}
printKeyValue(buf, elem, pointers, interfaces, structFilter, formatOutput, indent, level+1)
if i != val.Len()-1 || !allSimple {
fmt.Fprint(buf, ",")
}
}
if formatOutput && !allSimple {
fmt.Fprintln(buf)
for ind := 0; ind < level-1; ind++ {
fmt.Fprint(buf, indent)
}
} else {
fmt.Fprint(buf, " ")
}
fmt.Fprint(buf, "}")
case reflect.Map:
var t = val.Type()
var keys = val.MapKeys()
fmt.Fprint(buf, t)
fmt.Fprint(buf, "{")
var allSimple = true
for i := 0; i < len(keys); i++ {
var elem = val.MapIndex(keys[i])
var isSimple = isSimpleType(elem, elem.Kind(), pointers, interfaces)
if !isSimple {
allSimple = false
}
if formatOutput && !isSimple {
fmt.Fprintln(buf)
} else {
fmt.Fprint(buf, " ")
}
if formatOutput && !isSimple {
for ind := 0; ind <= level; ind++ {
fmt.Fprint(buf, indent)
}
}
printKeyValue(buf, keys[i], pointers, interfaces, structFilter, formatOutput, indent, level+1)
fmt.Fprint(buf, ": ")
printKeyValue(buf, elem, pointers, interfaces, structFilter, formatOutput, indent, level+1)
if i != val.Len()-1 || !allSimple {
fmt.Fprint(buf, ",")
}
}
if formatOutput && !allSimple {
fmt.Fprintln(buf)
for ind := 0; ind < level-1; ind++ {
fmt.Fprint(buf, indent)
}
} else {
fmt.Fprint(buf, " ")
}
fmt.Fprint(buf, "}")
case reflect.Chan:
fmt.Fprint(buf, val.Type())
case reflect.Invalid:
fmt.Fprint(buf, "invalid")
default:
fmt.Fprint(buf, "unknow")
}
}
// PrintPointerInfo dump pointer value
func PrintPointerInfo(buf *bytes.Buffer, headlen int, pointers *pointerInfo) {
var anyused = false
var pointerNum = 0
for p := pointers; p != nil; p = p.prev {
if len(p.used) > 0 {
anyused = true
}
pointerNum++
p.n = pointerNum
}
if anyused {
var pointerBufs = make([][]rune, pointerNum+1)
for i := 0; i < len(pointerBufs); i++ {
var pointerBuf = make([]rune, buf.Len()+headlen)
for j := 0; j < len(pointerBuf); j++ {
pointerBuf[j] = ' '
}
pointerBufs[i] = pointerBuf
}
for pn := 0; pn <= pointerNum; pn++ {
for p := pointers; p != nil; p = p.prev {
if len(p.used) > 0 && p.n >= pn {
if pn == p.n {
pointerBufs[pn][p.pos+headlen] = '└'
var maxpos = 0
for i, pos := range p.used {
if i < len(p.used)-1 {
pointerBufs[pn][pos+headlen] = '┴'
} else {
pointerBufs[pn][pos+headlen] = '┘'
}
maxpos = pos
}
for i := 0; i < maxpos-p.pos-1; i++ {
if pointerBufs[pn][i+p.pos+headlen+1] == ' ' {
pointerBufs[pn][i+p.pos+headlen+1] = '─'
}
}
} else {
pointerBufs[pn][p.pos+headlen] = '│'
for _, pos := range p.used {
if pointerBufs[pn][pos+headlen] == ' ' {
pointerBufs[pn][pos+headlen] = '│'
} else {
pointerBufs[pn][pos+headlen] = '┼'
}
}
}
}
}
buf.WriteString(string(pointerBufs[pn]) + "\n")
}
}
}
// Stack get stack bytes
func Stack(skip int, indent string) []byte {
var buf = new(bytes.Buffer)
for i := skip; ; i++ {
var pc, file, line, ok = runtime.Caller(i)
if !ok {
break
}
buf.WriteString(indent)
fmt.Fprintf(buf, "at %s() [%s:%d]\n", function(pc), file, line)
}
return buf.Bytes()
}
// return the name of the function containing the PC if possible,
func function(pc uintptr) []byte {
fn := runtime.FuncForPC(pc)
if fn == nil {
return dunno
}
name := []byte(fn.Name())
// The name includes the path name to the package, which is unnecessary
// since the file name is already included. Plus, it has center dots.
// That is, we see
// runtime/debug.*T·ptrmethod
// and want
// *T.ptrmethod
if period := bytes.Index(name, dot); period >= 0 {
name = name[period+1:]
}
name = bytes.Replace(name, centerDot, dot, -1)
return name
}

View File

@ -1,101 +0,0 @@
// 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 utils
import (
"bufio"
"errors"
"io"
"os"
"path/filepath"
"regexp"
)
// SelfPath gets compiled executable file absolute path
func SelfPath() string {
path, _ := filepath.Abs(os.Args[0])
return path
}
// SelfDir gets compiled executable file directory
func SelfDir() string {
return filepath.Dir(SelfPath())
}
// FileExists reports whether the named file or directory exists.
func FileExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return false
}
}
return true
}
// SearchFile Search a file in paths.
// this is often used in search config file in /etc ~/
func SearchFile(filename string, paths ...string) (fullpath string, err error) {
for _, path := range paths {
if fullpath = filepath.Join(path, filename); FileExists(fullpath) {
return
}
}
err = errors.New(fullpath + " not found in paths")
return
}
// GrepFile like command grep -E
// for example: GrepFile(`^hello`, "hello.txt")
// \n is striped while read
func GrepFile(patten string, filename string) (lines []string, err error) {
re, err := regexp.Compile(patten)
if err != nil {
return
}
fd, err := os.Open(filename)
if err != nil {
return
}
lines = make([]string, 0)
reader := bufio.NewReader(fd)
prefix := ""
isLongLine := false
for {
byteLine, isPrefix, er := reader.ReadLine()
if er != nil && er != io.EOF {
return nil, er
}
if er == io.EOF {
break
}
line := string(byteLine)
if isPrefix {
prefix += line
continue
} else {
isLongLine = true
}
line = prefix + line
if isLongLine {
prefix = ""
}
if re.MatchString(line) {
lines = append(lines, line)
}
}
return lines, nil
}

View File

@ -1,423 +0,0 @@
// 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 utils
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"mime"
"mime/multipart"
"net/mail"
"net/smtp"
"net/textproto"
"os"
"path"
"path/filepath"
"strconv"
"strings"
"sync"
)
const (
maxLineLength = 76
upperhex = "0123456789ABCDEF"
)
// Email is the type used for email messages
type Email struct {
Auth smtp.Auth
Identity string `json:"identity"`
Username string `json:"username"`
Password string `json:"password"`
Host string `json:"host"`
Port int `json:"port"`
From string `json:"from"`
To []string
Bcc []string
Cc []string
Subject string
Text string // Plaintext message (optional)
HTML string // Html message (optional)
Headers textproto.MIMEHeader
Attachments []*Attachment
ReadReceipt []string
}
// Attachment is a struct representing an email attachment.
// Based on the mime/multipart.FileHeader struct, Attachment contains the name, MIMEHeader, and content of the attachment in question
type Attachment struct {
Filename string
Header textproto.MIMEHeader
Content []byte
}
// NewEMail create new Email struct with config json.
// config json is followed from Email struct fields.
func NewEMail(config string) *Email {
e := new(Email)
e.Headers = textproto.MIMEHeader{}
err := json.Unmarshal([]byte(config), e)
if err != nil {
return nil
}
return e
}
// Bytes Make all send information to byte
func (e *Email) Bytes() ([]byte, error) {
buff := &bytes.Buffer{}
w := multipart.NewWriter(buff)
// Set the appropriate headers (overwriting any conflicts)
// Leave out Bcc (only included in envelope headers)
e.Headers.Set("To", strings.Join(e.To, ","))
if e.Cc != nil {
e.Headers.Set("Cc", strings.Join(e.Cc, ","))
}
e.Headers.Set("From", e.From)
e.Headers.Set("Subject", e.Subject)
if len(e.ReadReceipt) != 0 {
e.Headers.Set("Disposition-Notification-To", strings.Join(e.ReadReceipt, ","))
}
e.Headers.Set("MIME-Version", "1.0")
// Write the envelope headers (including any custom headers)
if err := headerToBytes(buff, e.Headers); err != nil {
return nil, fmt.Errorf("Failed to render message headers: %s", err)
}
e.Headers.Set("Content-Type", fmt.Sprintf("multipart/mixed;\r\n boundary=%s\r\n", w.Boundary()))
fmt.Fprintf(buff, "%s:", "Content-Type")
fmt.Fprintf(buff, " %s\r\n", fmt.Sprintf("multipart/mixed;\r\n boundary=%s\r\n", w.Boundary()))
// Start the multipart/mixed part
fmt.Fprintf(buff, "--%s\r\n", w.Boundary())
header := textproto.MIMEHeader{}
// Check to see if there is a Text or HTML field
if e.Text != "" || e.HTML != "" {
subWriter := multipart.NewWriter(buff)
// Create the multipart alternative part
header.Set("Content-Type", fmt.Sprintf("multipart/alternative;\r\n boundary=%s\r\n", subWriter.Boundary()))
// Write the header
if err := headerToBytes(buff, header); err != nil {
return nil, fmt.Errorf("Failed to render multipart message headers: %s", err)
}
// Create the body sections
if e.Text != "" {
header.Set("Content-Type", fmt.Sprintf("text/plain; charset=UTF-8"))
header.Set("Content-Transfer-Encoding", "quoted-printable")
if _, err := subWriter.CreatePart(header); err != nil {
return nil, err
}
// Write the text
if err := quotePrintEncode(buff, e.Text); err != nil {
return nil, err
}
}
if e.HTML != "" {
header.Set("Content-Type", fmt.Sprintf("text/html; charset=UTF-8"))
header.Set("Content-Transfer-Encoding", "quoted-printable")
if _, err := subWriter.CreatePart(header); err != nil {
return nil, err
}
// Write the text
if err := quotePrintEncode(buff, e.HTML); err != nil {
return nil, err
}
}
if err := subWriter.Close(); err != nil {
return nil, err
}
}
// Create attachment part, if necessary
for _, a := range e.Attachments {
ap, err := w.CreatePart(a.Header)
if err != nil {
return nil, err
}
// Write the base64Wrapped content to the part
base64Wrap(ap, a.Content)
}
if err := w.Close(); err != nil {
return nil, err
}
return buff.Bytes(), nil
}
// AttachFile Add attach file to the send mail
func (e *Email) AttachFile(args ...string) (a *Attachment, err error) {
if len(args) < 1 && len(args) > 2 {
err = errors.New("Must specify a file name and number of parameters can not exceed at least two")
return
}
filename := args[0]
id := ""
if len(args) > 1 {
id = args[1]
}
f, err := os.Open(filename)
if err != nil {
return
}
ct := mime.TypeByExtension(filepath.Ext(filename))
basename := path.Base(filename)
return e.Attach(f, basename, ct, id)
}
// Attach is used to attach content from an io.Reader to the email.
// Parameters include an io.Reader, the desired filename for the attachment, and the Content-Type.
func (e *Email) Attach(r io.Reader, filename string, args ...string) (a *Attachment, err error) {
if len(args) < 1 && len(args) > 2 {
err = errors.New("Must specify the file type and number of parameters can not exceed at least two")
return
}
c := args[0] //Content-Type
id := ""
if len(args) > 1 {
id = args[1] //Content-ID
}
var buffer bytes.Buffer
if _, err = io.Copy(&buffer, r); err != nil {
return
}
at := &Attachment{
Filename: filename,
Header: textproto.MIMEHeader{},
Content: buffer.Bytes(),
}
// Get the Content-Type to be used in the MIMEHeader
if c != "" {
at.Header.Set("Content-Type", c)
} else {
// If the Content-Type is blank, set the Content-Type to "application/octet-stream"
at.Header.Set("Content-Type", "application/octet-stream")
}
if id != "" {
at.Header.Set("Content-Disposition", fmt.Sprintf("inline;\r\n filename=\"%s\"", filename))
at.Header.Set("Content-ID", fmt.Sprintf("<%s>", id))
} else {
at.Header.Set("Content-Disposition", fmt.Sprintf("attachment;\r\n filename=\"%s\"", filename))
}
at.Header.Set("Content-Transfer-Encoding", "base64")
e.Attachments = append(e.Attachments, at)
return at, nil
}
// Send will send out the mail
func (e *Email) Send() error {
if e.Auth == nil {
e.Auth = smtp.PlainAuth(e.Identity, e.Username, e.Password, e.Host)
}
// Merge the To, Cc, and Bcc fields
to := make([]string, 0, len(e.To)+len(e.Cc)+len(e.Bcc))
to = append(append(append(to, e.To...), e.Cc...), e.Bcc...)
// Check to make sure there is at least one recipient and one "From" address
if len(to) == 0 {
return errors.New("Must specify at least one To address")
}
// Use the username if no From is provided
if len(e.From) == 0 {
e.From = e.Username
}
from, err := mail.ParseAddress(e.From)
if err != nil {
return err
}
// use mail's RFC 2047 to encode any string
e.Subject = qEncode("utf-8", e.Subject)
raw, err := e.Bytes()
if err != nil {
return err
}
return smtp.SendMail(e.Host+":"+strconv.Itoa(e.Port), e.Auth, from.Address, to, raw)
}
// quotePrintEncode writes the quoted-printable text to the IO Writer (according to RFC 2045)
func quotePrintEncode(w io.Writer, s string) error {
var buf [3]byte
mc := 0
for i := 0; i < len(s); i++ {
c := s[i]
// We're assuming Unix style text formats as input (LF line break), and
// quoted-printble uses CRLF line breaks. (Literal CRs will become
// "=0D", but probably shouldn't be there to begin with!)
if c == '\n' {
io.WriteString(w, "\r\n")
mc = 0
continue
}
var nextOut []byte
if isPrintable(c) {
nextOut = append(buf[:0], c)
} else {
nextOut = buf[:]
qpEscape(nextOut, c)
}
// Add a soft line break if the next (encoded) byte would push this line
// to or past the limit.
if mc+len(nextOut) >= maxLineLength {
if _, err := io.WriteString(w, "=\r\n"); err != nil {
return err
}
mc = 0
}
if _, err := w.Write(nextOut); err != nil {
return err
}
mc += len(nextOut)
}
// No trailing end-of-line?? Soft line break, then. TODO: is this sane?
if mc > 0 {
io.WriteString(w, "=\r\n")
}
return nil
}
// isPrintable returns true if the rune given is "printable" according to RFC 2045, false otherwise
func isPrintable(c byte) bool {
return (c >= '!' && c <= '<') || (c >= '>' && c <= '~') || (c == ' ' || c == '\n' || c == '\t')
}
// qpEscape is a helper function for quotePrintEncode which escapes a
// non-printable byte. Expects len(dest) == 3.
func qpEscape(dest []byte, c byte) {
const nums = "0123456789ABCDEF"
dest[0] = '='
dest[1] = nums[(c&0xf0)>>4]
dest[2] = nums[(c & 0xf)]
}
// headerToBytes enumerates the key and values in the header, and writes the results to the IO Writer
func headerToBytes(w io.Writer, t textproto.MIMEHeader) error {
for k, v := range t {
// Write the header key
_, err := fmt.Fprintf(w, "%s:", k)
if err != nil {
return err
}
// Write each value in the header
for _, c := range v {
_, err := fmt.Fprintf(w, " %s\r\n", c)
if err != nil {
return err
}
}
}
return nil
}
// base64Wrap encodes the attachment content, and wraps it according to RFC 2045 standards (every 76 chars)
// The output is then written to the specified io.Writer
func base64Wrap(w io.Writer, b []byte) {
// 57 raw bytes per 76-byte base64 line.
const maxRaw = 57
// Buffer for each line, including trailing CRLF.
var buffer [maxLineLength + len("\r\n")]byte
copy(buffer[maxLineLength:], "\r\n")
// Process raw chunks until there's no longer enough to fill a line.
for len(b) >= maxRaw {
base64.StdEncoding.Encode(buffer[:], b[:maxRaw])
w.Write(buffer[:])
b = b[maxRaw:]
}
// Handle the last chunk of bytes.
if len(b) > 0 {
out := buffer[:base64.StdEncoding.EncodedLen(len(b))]
base64.StdEncoding.Encode(out, b)
out = append(out, "\r\n"...)
w.Write(out)
}
}
// Encode returns the encoded-word form of s. If s is ASCII without special
// characters, it is returned unchanged. The provided charset is the IANA
// charset name of s. It is case insensitive.
// RFC 2047 encoded-word
func qEncode(charset, s string) string {
if !needsEncoding(s) {
return s
}
return encodeWord(charset, s)
}
func needsEncoding(s string) bool {
for _, b := range s {
if (b < ' ' || b > '~') && b != '\t' {
return true
}
}
return false
}
// encodeWord encodes a string into an encoded-word.
func encodeWord(charset, s string) string {
buf := getBuffer()
buf.WriteString("=?")
buf.WriteString(charset)
buf.WriteByte('?')
buf.WriteByte('q')
buf.WriteByte('?')
enc := make([]byte, 3)
for i := 0; i < len(s); i++ {
b := s[i]
switch {
case b == ' ':
buf.WriteByte('_')
case b <= '~' && b >= '!' && b != '=' && b != '?' && b != '_':
buf.WriteByte(b)
default:
enc[0] = '='
enc[1] = upperhex[b>>4]
enc[2] = upperhex[b&0x0f]
buf.Write(enc)
}
}
buf.WriteString("?=")
es := buf.String()
putBuffer(buf)
return es
}
var bufPool = sync.Pool{
New: func() interface{} {
return new(bytes.Buffer)
},
}
func getBuffer() *bytes.Buffer {
return bufPool.Get().(*bytes.Buffer)
}
func putBuffer(buf *bytes.Buffer) {
if buf.Len() > 1024 {
return
}
buf.Reset()
bufPool.Put(buf)
}

View File

@ -1,44 +0,0 @@
// 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 utils
import (
"crypto/rand"
r "math/rand"
"time"
)
var alphaNum = []byte(`0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz`)
// RandomCreateBytes generate random []byte by specify chars.
func RandomCreateBytes(n int, alphabets ...byte) []byte {
if len(alphabets) == 0 {
alphabets = alphaNum
}
var bytes = make([]byte, n)
var randBy bool
if num, err := rand.Read(bytes); num != n || err != nil {
r.Seed(time.Now().UnixNano())
randBy = true
}
for i, b := range bytes {
if randBy {
bytes[i] = alphabets[r.Intn(len(alphabets))]
} else {
bytes[i] = alphabets[b%byte(len(alphabets))]
}
}
return bytes
}

View File

@ -1,91 +0,0 @@
// 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 utils
import (
"sync"
)
// BeeMap is a map with lock
type BeeMap struct {
lock *sync.RWMutex
bm map[interface{}]interface{}
}
// NewBeeMap return new safemap
func NewBeeMap() *BeeMap {
return &BeeMap{
lock: new(sync.RWMutex),
bm: make(map[interface{}]interface{}),
}
}
// Get from maps return the k's value
func (m *BeeMap) Get(k interface{}) interface{} {
m.lock.RLock()
defer m.lock.RUnlock()
if val, ok := m.bm[k]; ok {
return val
}
return nil
}
// Set Maps the given key and value. Returns false
// if the key is already in the map and changes nothing.
func (m *BeeMap) Set(k interface{}, v interface{}) bool {
m.lock.Lock()
defer m.lock.Unlock()
if val, ok := m.bm[k]; !ok {
m.bm[k] = v
} else if val != v {
m.bm[k] = v
} else {
return false
}
return true
}
// Check Returns true if k is exist in the map.
func (m *BeeMap) Check(k interface{}) bool {
m.lock.RLock()
defer m.lock.RUnlock()
_, ok := m.bm[k]
return ok
}
// Delete the given key and value.
func (m *BeeMap) Delete(k interface{}) {
m.lock.Lock()
defer m.lock.Unlock()
delete(m.bm, k)
}
// Items returns all items in safemap.
func (m *BeeMap) Items() map[interface{}]interface{} {
m.lock.RLock()
defer m.lock.RUnlock()
r := make(map[interface{}]interface{})
for k, v := range m.bm {
r[k] = v
}
return r
}
// Count returns the number of items within the map.
func (m *BeeMap) Count() int {
m.lock.RLock()
defer m.lock.RUnlock()
return len(m.bm)
}

View File

@ -1,170 +0,0 @@
// 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 utils
import (
"math/rand"
"time"
)
type reducetype func(interface{}) interface{}
type filtertype func(interface{}) bool
// InSlice checks given string in string slice or not.
func InSlice(v string, sl []string) bool {
for _, vv := range sl {
if vv == v {
return true
}
}
return false
}
// InSliceIface checks given interface in interface slice.
func InSliceIface(v interface{}, sl []interface{}) bool {
for _, vv := range sl {
if vv == v {
return true
}
}
return false
}
// SliceRandList generate an int slice from min to max.
func SliceRandList(min, max int) []int {
if max < min {
min, max = max, min
}
length := max - min + 1
t0 := time.Now()
rand.Seed(int64(t0.Nanosecond()))
list := rand.Perm(length)
for index := range list {
list[index] += min
}
return list
}
// SliceMerge merges interface slices to one slice.
func SliceMerge(slice1, slice2 []interface{}) (c []interface{}) {
c = append(slice1, slice2...)
return
}
// SliceReduce generates a new slice after parsing every value by reduce function
func SliceReduce(slice []interface{}, a reducetype) (dslice []interface{}) {
for _, v := range slice {
dslice = append(dslice, a(v))
}
return
}
// SliceRand returns random one from slice.
func SliceRand(a []interface{}) (b interface{}) {
randnum := rand.Intn(len(a))
b = a[randnum]
return
}
// SliceSum sums all values in int64 slice.
func SliceSum(intslice []int64) (sum int64) {
for _, v := range intslice {
sum += v
}
return
}
// SliceFilter generates a new slice after filter function.
func SliceFilter(slice []interface{}, a filtertype) (ftslice []interface{}) {
for _, v := range slice {
if a(v) {
ftslice = append(ftslice, v)
}
}
return
}
// SliceDiff returns diff slice of slice1 - slice2.
func SliceDiff(slice1, slice2 []interface{}) (diffslice []interface{}) {
for _, v := range slice1 {
if !InSliceIface(v, slice2) {
diffslice = append(diffslice, v)
}
}
return
}
// SliceIntersect returns slice that are present in all the slice1 and slice2.
func SliceIntersect(slice1, slice2 []interface{}) (diffslice []interface{}) {
for _, v := range slice1 {
if InSliceIface(v, slice2) {
diffslice = append(diffslice, v)
}
}
return
}
// SliceChunk separates one slice to some sized slice.
func SliceChunk(slice []interface{}, size int) (chunkslice [][]interface{}) {
if size >= len(slice) {
chunkslice = append(chunkslice, slice)
return
}
end := size
for i := 0; i <= (len(slice) - size); i += size {
chunkslice = append(chunkslice, slice[i:end])
end += size
}
return
}
// SliceRange generates a new slice from begin to end with step duration of int64 number.
func SliceRange(start, end, step int64) (intslice []int64) {
for i := start; i <= end; i += step {
intslice = append(intslice, i)
}
return
}
// SlicePad prepends size number of val into slice.
func SlicePad(slice []interface{}, size int, val interface{}) []interface{} {
if size <= len(slice) {
return slice
}
for i := 0; i < (size - len(slice)); i++ {
slice = append(slice, val)
}
return slice
}
// SliceUnique cleans repeated values in slice.
func SliceUnique(slice []interface{}) (uniqueslice []interface{}) {
for _, v := range slice {
if !InSliceIface(v, uniqueslice) {
uniqueslice = append(uniqueslice, v)
}
}
return
}
// SliceShuffle shuffles a slice.
func SliceShuffle(slice []interface{}) []interface{} {
for i := 0; i < len(slice); i++ {
a := rand.Intn(len(slice))
b := rand.Intn(len(slice))
slice[a], slice[b] = slice[b], slice[a]
}
return slice
}

View File

@ -1,20 +0,0 @@
The MIT License (MIT)
Copyright (c) 2014 Derek Parker
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,134 +0,0 @@
package config
import (
"fmt"
"io/ioutil"
"os"
"os/user"
"path"
yaml "gopkg.in/yaml.v2"
)
const (
configDir string = ".dlv"
configFile string = "config.yml"
)
// Describes a rule for substitution of path to source code file.
type SubstitutePathRule struct {
// Directory path will be substituted if it matches `From`.
From string
// Path to which substitution is performed.
To string
}
// Slice of source code path substitution rules.
type SubstitutePathRules []SubstitutePathRule
// Config defines all configuration options available to be set through the config file.
type Config struct {
// Commands aliases.
Aliases map[string][]string
// Source code path substitution rules.
SubstitutePath SubstitutePathRules `yaml:"substitute-path"`
}
// LoadConfig attempts to populate a Config object from the config.yml file.
func LoadConfig() *Config {
err := createConfigPath()
if err != nil {
fmt.Printf("Could not create config directory: %v.", err)
return nil
}
fullConfigFile, err := GetConfigFilePath(configFile)
if err != nil {
fmt.Printf("Unable to get config file path: %v.", err)
return nil
}
f, err := os.Open(fullConfigFile)
if err != nil {
createDefaultConfig(fullConfigFile)
return nil
}
defer func() {
err := f.Close()
if err != nil {
fmt.Printf("Closing config file failed: %v.", err)
}
}()
data, err := ioutil.ReadAll(f)
if err != nil {
fmt.Printf("Unable to read config data: %v.", err)
return nil
}
var c Config
err = yaml.Unmarshal(data, &c)
if err != nil {
fmt.Printf("Unable to decode config file: %v.", err)
return nil
}
return &c
}
func createDefaultConfig(path string) {
f, err := os.Create(path)
if err != nil {
fmt.Printf("Unable to create config file: %v.", err)
return
}
defer func() {
err := f.Close()
if err != nil {
fmt.Printf("Closing config file failed: %v.", err)
}
}()
err = writeDefaultConfig(f)
if err != nil {
fmt.Printf("Unable to write default configuration: %v.", err)
}
}
func writeDefaultConfig(f *os.File) error {
_, err := f.WriteString(
`# Configuration file for the delve debugger.
# This is the default configuration file. Available options are provided, but disabled.
# Delete the leading hash mark to enable an item.
# Provided aliases will be added to the default aliases for a given command.
aliases:
# command: ["alias1", "alias2"]
# Define sources path substitution rules. Can be used to rewrite a source path stored
# in program's debug information, if the sources were moved to a different place
# between compilation and debugging.
# Note that substitution rules will not be used for paths passed to "break" and "trace"
# commands.
substitute-path:
# - {from: path, to: path}
`)
return err
}
// createConfigPath creates the directory structure at which all config files are saved.
func createConfigPath() error {
path, err := GetConfigFilePath("")
if err != nil {
return err
}
return os.MkdirAll(path, 0700)
}
// GetConfigFilePath gets the full path to the given config file name.
func GetConfigFilePath(file string) (string, error) {
usr, err := user.Current()
if err != nil {
return "", err
}
return path.Join(usr.HomeDir, configDir, file), nil
}

View File

@ -1,95 +0,0 @@
package frame
import (
"encoding/binary"
"fmt"
"sort"
)
// Represents a Common Information Entry in
// the Dwarf .debug_frame section.
type CommonInformationEntry struct {
Length uint32
CIE_id uint32
Version uint8
Augmentation string
CodeAlignmentFactor uint64
DataAlignmentFactor int64
ReturnAddressRegister uint64
InitialInstructions []byte
}
// Represents a Frame Descriptor Entry in the
// Dwarf .debug_frame section.
type FrameDescriptionEntry struct {
Length uint32
CIE *CommonInformationEntry
Instructions []byte
begin, end uint64
order binary.ByteOrder
}
// Returns whether or not the given address is within the
// bounds of this frame.
func (fde *FrameDescriptionEntry) Cover(addr uint64) bool {
if (addr - fde.begin) < fde.end {
return true
}
return false
}
// Address of first location for this frame.
func (fde *FrameDescriptionEntry) Begin() uint64 {
return fde.begin
}
// Address of last location for this frame.
func (fde *FrameDescriptionEntry) End() uint64 {
return fde.begin + fde.end
}
// Set up frame for the given PC.
func (fde *FrameDescriptionEntry) EstablishFrame(pc uint64) *FrameContext {
return executeDwarfProgramUntilPC(fde, pc)
}
// Return the offset from the current SP that the return address is stored at.
func (fde *FrameDescriptionEntry) ReturnAddressOffset(pc uint64) (frameOffset, returnAddressOffset int64) {
frame := fde.EstablishFrame(pc)
return frame.cfa.offset, frame.regs[fde.CIE.ReturnAddressRegister].offset
}
type FrameDescriptionEntries []*FrameDescriptionEntry
func NewFrameIndex() FrameDescriptionEntries {
return make(FrameDescriptionEntries, 0, 1000)
}
type NoFDEForPCError struct {
PC uint64
}
func (err *NoFDEForPCError) Error() string {
return fmt.Sprintf("could not find FDE for PC %#v", err.PC)
}
// Returns the Frame Description Entry for the given PC.
func (fdes FrameDescriptionEntries) FDEForPC(pc uint64) (*FrameDescriptionEntry, error) {
idx := sort.Search(len(fdes), func(i int) bool {
if fdes[i].Cover(pc) {
return true
}
if fdes[i].LessThan(pc) {
return false
}
return true
})
if idx == len(fdes) {
return nil, &NoFDEForPCError{pc}
}
return fdes[idx], nil
}
func (frame *FrameDescriptionEntry) LessThan(pc uint64) bool {
return frame.End() <= pc
}

View File

@ -1,164 +0,0 @@
package frame
// Operation opcodes
const (
DW_OP_addr = 0x03
DW_OP_const1s = 0x09
)
const (
DW_OP_const2u = 0x0a
DW_OP_const2s = 0x0b
DW_OP_const4u = iota
DW_OP_const4s
DW_OP_const8u
DW_OP_const8s
DW_OP_constu
DW_OP_consts
DW_OP_dup
DW_OP_drop
DW_OP_over
DW_OP_pick
DW_OP_swap
DW_OP_rot
DW_OP_xderef
DW_OP_abs
DW_OP_and
DW_OP_div
DW_OP_minus
DW_OP_mod
DW_OP_mul
DW_OP_neg
DW_OP_not
DW_OP_or
DW_OP_plus
DW_OP_plus_uconst
DW_OP_shl
DW_OP_shr
DW_OP_shra
DW_OP_xor
DW_OP_skip
DW_OP_bra
DW_OP_eq
DW_OP_ge
DW_OP_gt
DW_OP_le
DW_OP_lt
DW_OP_ne
)
const (
DW_OP_lit0 = 0x30
DW_OP_lit1 = 0x31
DW_OP_lit2 = iota
DW_OP_lit3
DW_OP_lit4
DW_OP_lit5
DW_OP_lit6
DW_OP_lit7
DW_OP_lit8
DW_OP_lit9
DW_OP_lit10
DW_OP_lit11
DW_OP_lit12
DW_OP_lit13
DW_OP_lit14
DW_OP_lit15
DW_OP_lit16
DW_OP_lit17
DW_OP_lit18
DW_OP_lit19
DW_OP_lit20
DW_OP_lit21
DW_OP_lit22
DW_OP_lit23
DW_OP_lit24
DW_OP_lit25
DW_OP_lit26
DW_OP_lit27
DW_OP_lit28
DW_OP_lit29
DW_OP_lit30
DW_OP_lit31
DW_OP_reg0
DW_OP_reg1
DW_OP_reg2
DW_OP_reg3
DW_OP_reg4
DW_OP_reg5
DW_OP_reg6
DW_OP_reg7
DW_OP_reg8
DW_OP_reg9
DW_OP_reg10
DW_OP_reg11
DW_OP_reg12
DW_OP_reg13
DW_OP_reg14
DW_OP_reg15
DW_OP_reg16
DW_OP_reg17
DW_OP_reg18
DW_OP_reg19
DW_OP_reg20
DW_OP_reg21
DW_OP_reg22
DW_OP_reg23
DW_OP_reg24
DW_OP_reg25
DW_OP_reg26
DW_OP_reg27
DW_OP_reg28
DW_OP_reg29
DW_OP_reg30
DW_OP_reg31
DW_OP_breg0
DW_OP_breg1
DW_OP_breg2
DW_OP_breg3
DW_OP_breg4
DW_OP_breg5
DW_OP_breg6
DW_OP_breg7
DW_OP_breg8
DW_OP_breg9
DW_OP_breg10
DW_OP_breg11
DW_OP_breg12
DW_OP_breg13
DW_OP_breg14
DW_OP_breg15
DW_OP_breg16
DW_OP_breg17
DW_OP_breg18
DW_OP_breg19
DW_OP_breg20
DW_OP_breg21
DW_OP_breg22
DW_OP_breg23
DW_OP_breg24
DW_OP_breg25
DW_OP_breg26
DW_OP_breg27
DW_OP_breg28
DW_OP_breg29
DW_OP_breg30
DW_OP_breg31
DW_OP_regx
DW_OP_fbreg
DW_OP_bregx
DW_OP_piece
DW_OP_deref_size
DW_OP_xderef_size
DW_OP_nop
DW_OP_push_object_address
DW_OP_call2
DW_OP_call4
DW_OP_call_ref
DW_OP_form_tls_address
DW_OP_call_frame_cfa
DW_OP_bit_piece
DW_OP_lo_user = 0xe0
DW_OP_hi_user = 0xff
)

View File

@ -1,125 +0,0 @@
// Package frame contains data structures and
// related functions for parsing and searching
// through Dwarf .debug_frame data.
package frame
import (
"bytes"
"encoding/binary"
"github.com/derekparker/delve/dwarf/util"
)
type parsefunc func(*parseContext) parsefunc
type parseContext struct {
buf *bytes.Buffer
entries FrameDescriptionEntries
common *CommonInformationEntry
frame *FrameDescriptionEntry
length uint32
}
// Parse takes in data (a byte slice) and returns a slice of
// commonInformationEntry structures. Each commonInformationEntry
// has a slice of frameDescriptionEntry structures.
func Parse(data []byte, order binary.ByteOrder) FrameDescriptionEntries {
var (
buf = bytes.NewBuffer(data)
pctx = &parseContext{buf: buf, entries: NewFrameIndex()}
)
for fn := parselength; buf.Len() != 0; {
fn = fn(pctx)
}
for i := range pctx.entries {
pctx.entries[i].order = order
}
return pctx.entries
}
func cieEntry(data []byte) bool {
return bytes.Equal(data, []byte{0xff, 0xff, 0xff, 0xff})
}
func parselength(ctx *parseContext) parsefunc {
var data = ctx.buf.Next(8)
ctx.length = binary.LittleEndian.Uint32(data[:4]) - 4 // take off the length of the CIE id / CIE pointer.
if cieEntry(data[4:]) {
ctx.common = &CommonInformationEntry{Length: ctx.length}
return parseCIE
}
ctx.frame = &FrameDescriptionEntry{Length: ctx.length, CIE: ctx.common}
return parseFDE
}
func parseFDE(ctx *parseContext) parsefunc {
r := ctx.buf.Next(int(ctx.length))
ctx.frame.begin = binary.LittleEndian.Uint64(r[:8])
ctx.frame.end = binary.LittleEndian.Uint64(r[8:16])
// Insert into the tree after setting address range begin
// otherwise compares won't work.
ctx.entries = append(ctx.entries, ctx.frame)
// The rest of this entry consists of the instructions
// so we can just grab all of the data from the buffer
// cursor to length.
ctx.frame.Instructions = r[16:]
ctx.length = 0
return parselength
}
func parseCIE(ctx *parseContext) parsefunc {
data := ctx.buf.Next(int(ctx.length))
buf := bytes.NewBuffer(data)
// parse version
ctx.common.Version = data[0]
// parse augmentation
ctx.common.Augmentation, _ = util.ParseString(buf)
// parse code alignment factor
ctx.common.CodeAlignmentFactor, _ = util.DecodeULEB128(buf)
// parse data alignment factor
ctx.common.DataAlignmentFactor, _ = util.DecodeSLEB128(buf)
// parse return address register
ctx.common.ReturnAddressRegister, _ = util.DecodeULEB128(buf)
// parse initial instructions
// The rest of this entry consists of the instructions
// so we can just grab all of the data from the buffer
// cursor to length.
ctx.common.InitialInstructions = buf.Bytes() //ctx.buf.Next(int(ctx.length))
ctx.length = 0
return parselength
}
// DwarfEndian determines the endianness of the DWARF by using the version number field in the debug_info section
// Trick borrowed from "debug/dwarf".New()
func DwarfEndian(infoSec []byte) binary.ByteOrder {
if len(infoSec) < 6 {
return binary.BigEndian
}
x, y := infoSec[4], infoSec[5]
switch {
case x == 0 && y == 0:
return binary.BigEndian
case x == 0:
return binary.BigEndian
case y == 0:
return binary.LittleEndian
default:
return binary.BigEndian
}
}

View File

@ -1,429 +0,0 @@
package frame
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/derekparker/delve/dwarf/util"
)
type CurrentFrameAddress struct {
register uint64
offset int64
expression []byte
rule byte
}
type DWRule struct {
rule byte
offset int64
newreg uint64
expression []byte
}
type FrameContext struct {
loc uint64
order binary.ByteOrder
address uint64
cfa CurrentFrameAddress
regs map[uint64]DWRule
initialRegs map[uint64]DWRule
prevRegs map[uint64]DWRule
buf *bytes.Buffer
cie *CommonInformationEntry
codeAlignment uint64
dataAlignment int64
}
func (fctx *FrameContext) CFAOffset() int64 {
return fctx.cfa.offset
}
// Instructions used to recreate the table from the .debug_frame data.
const (
DW_CFA_nop = 0x0 // No ops
DW_CFA_set_loc = 0x01 // op1: address
DW_CFA_advance_loc1 = iota // op1: 1-bytes delta
DW_CFA_advance_loc2 // op1: 2-byte delta
DW_CFA_advance_loc4 // op1: 4-byte delta
DW_CFA_offset_extended // op1: ULEB128 register, op2: ULEB128 offset
DW_CFA_restore_extended // op1: ULEB128 register
DW_CFA_undefined // op1: ULEB128 register
DW_CFA_same_value // op1: ULEB128 register
DW_CFA_register // op1: ULEB128 register, op2: ULEB128 register
DW_CFA_remember_state // No ops
DW_CFA_restore_state // No ops
DW_CFA_def_cfa // op1: ULEB128 register, op2: ULEB128 offset
DW_CFA_def_cfa_register // op1: ULEB128 register
DW_CFA_def_cfa_offset // op1: ULEB128 offset
DW_CFA_def_cfa_expression // op1: BLOCK
DW_CFA_expression // op1: ULEB128 register, op2: BLOCK
DW_CFA_offset_extended_sf // op1: ULEB128 register, op2: SLEB128 BLOCK
DW_CFA_def_cfa_sf // op1: ULEB128 register, op2: SLEB128 offset
DW_CFA_def_cfa_offset_sf // op1: SLEB128 offset
DW_CFA_val_offset // op1: ULEB128, op2: ULEB128
DW_CFA_val_offset_sf // op1: ULEB128, op2: SLEB128
DW_CFA_val_expression // op1: ULEB128, op2: BLOCK
DW_CFA_lo_user = 0x1c // op1: BLOCK
DW_CFA_hi_user = 0x3f // op1: ULEB128 register, op2: BLOCK
DW_CFA_advance_loc = (0x1 << 6) // High 2 bits: 0x1, low 6: delta
DW_CFA_offset = (0x2 << 6) // High 2 bits: 0x2, low 6: register
DW_CFA_restore = (0x3 << 6) // High 2 bits: 0x3, low 6: register
)
// Rules defined for register values.
const (
rule_undefined = iota
rule_sameval
rule_offset
rule_valoffset
rule_register
rule_expression
rule_valexpression
rule_architectural
)
const low_6_offset = 0x3f
type instruction func(frame *FrameContext)
// // Mapping from DWARF opcode to function.
var fnlookup = map[byte]instruction{
DW_CFA_advance_loc: advanceloc,
DW_CFA_offset: offset,
DW_CFA_restore: restore,
DW_CFA_set_loc: setloc,
DW_CFA_advance_loc1: advanceloc1,
DW_CFA_advance_loc2: advanceloc2,
DW_CFA_advance_loc4: advanceloc4,
DW_CFA_offset_extended: offsetextended,
DW_CFA_restore_extended: restoreextended,
DW_CFA_undefined: undefined,
DW_CFA_same_value: samevalue,
DW_CFA_register: register,
DW_CFA_remember_state: rememberstate,
DW_CFA_restore_state: restorestate,
DW_CFA_def_cfa: defcfa,
DW_CFA_def_cfa_register: defcfaregister,
DW_CFA_def_cfa_offset: defcfaoffset,
DW_CFA_def_cfa_expression: defcfaexpression,
DW_CFA_expression: expression,
DW_CFA_offset_extended_sf: offsetextendedsf,
DW_CFA_def_cfa_sf: defcfasf,
DW_CFA_def_cfa_offset_sf: defcfaoffsetsf,
DW_CFA_val_offset: valoffset,
DW_CFA_val_offset_sf: valoffsetsf,
DW_CFA_val_expression: valexpression,
DW_CFA_lo_user: louser,
DW_CFA_hi_user: hiuser,
}
func executeCIEInstructions(cie *CommonInformationEntry) *FrameContext {
initialInstructions := make([]byte, len(cie.InitialInstructions))
copy(initialInstructions, cie.InitialInstructions)
frame := &FrameContext{
cie: cie,
regs: make(map[uint64]DWRule),
initialRegs: make(map[uint64]DWRule),
prevRegs: make(map[uint64]DWRule),
codeAlignment: cie.CodeAlignmentFactor,
dataAlignment: cie.DataAlignmentFactor,
buf: bytes.NewBuffer(initialInstructions),
}
frame.ExecuteDwarfProgram()
return frame
}
// Unwind the stack to find the return address register.
func executeDwarfProgramUntilPC(fde *FrameDescriptionEntry, pc uint64) *FrameContext {
frame := executeCIEInstructions(fde.CIE)
frame.order = fde.order
frame.loc = fde.Begin()
frame.address = pc
fdeInstructions := make([]byte, len(fde.Instructions))
copy(fdeInstructions, fde.Instructions)
frame.ExecuteUntilPC(fdeInstructions)
return frame
}
func (frame *FrameContext) ExecuteDwarfProgram() {
for frame.buf.Len() > 0 {
executeDwarfInstruction(frame)
}
}
// Execute dwarf instructions.
func (frame *FrameContext) ExecuteUntilPC(instructions []byte) {
frame.buf.Truncate(0)
frame.buf.Write(instructions)
// We only need to execute the instructions until
// ctx.loc > ctx.addess (which is the address we
// are currently at in the traced process).
for frame.address >= frame.loc && frame.buf.Len() > 0 {
executeDwarfInstruction(frame)
}
}
func executeDwarfInstruction(frame *FrameContext) {
instruction, err := frame.buf.ReadByte()
if err != nil {
panic("Could not read from instruction buffer")
}
if instruction == DW_CFA_nop {
return
}
fn := lookupFunc(instruction, frame.buf)
fn(frame)
}
func lookupFunc(instruction byte, buf *bytes.Buffer) instruction {
const high_2_bits = 0xc0
var restore bool
// Special case the 3 opcodes that have their argument encoded in the opcode itself.
switch instruction & high_2_bits {
case DW_CFA_advance_loc:
instruction = DW_CFA_advance_loc
restore = true
case DW_CFA_offset:
instruction = DW_CFA_offset
restore = true
case DW_CFA_restore:
instruction = DW_CFA_restore
restore = true
}
if restore {
// Restore the last byte as it actually contains the argument for the opcode.
err := buf.UnreadByte()
if err != nil {
panic("Could not unread byte")
}
}
fn, ok := fnlookup[instruction]
if !ok {
panic(fmt.Sprintf("Encountered an unexpected DWARF CFA opcode: %#v", instruction))
}
return fn
}
func advanceloc(frame *FrameContext) {
b, err := frame.buf.ReadByte()
if err != nil {
panic("Could not read byte")
}
delta := b & low_6_offset
frame.loc += uint64(delta) * frame.codeAlignment
}
func advanceloc1(frame *FrameContext) {
delta, err := frame.buf.ReadByte()
if err != nil {
panic("Could not read byte")
}
frame.loc += uint64(delta) * frame.codeAlignment
}
func advanceloc2(frame *FrameContext) {
var delta uint16
binary.Read(frame.buf, frame.order, &delta)
frame.loc += uint64(delta) * frame.codeAlignment
}
func advanceloc4(frame *FrameContext) {
var delta uint32
binary.Read(frame.buf, frame.order, &delta)
frame.loc += uint64(delta) * frame.codeAlignment
}
func offset(frame *FrameContext) {
b, err := frame.buf.ReadByte()
if err != nil {
panic(err)
}
var (
reg = b & low_6_offset
offset, _ = util.DecodeULEB128(frame.buf)
)
frame.regs[uint64(reg)] = DWRule{offset: int64(offset) * frame.dataAlignment, rule: rule_offset}
}
func restore(frame *FrameContext) {
b, err := frame.buf.ReadByte()
if err != nil {
panic(err)
}
reg := uint64(b & low_6_offset)
oldrule, ok := frame.initialRegs[reg]
if ok {
frame.regs[reg] = DWRule{offset: oldrule.offset, rule: rule_offset}
} else {
frame.regs[reg] = DWRule{rule: rule_undefined}
}
}
func setloc(frame *FrameContext) {
var loc uint64
binary.Read(frame.buf, frame.order, &loc)
frame.loc = loc
}
func offsetextended(frame *FrameContext) {
var (
reg, _ = util.DecodeULEB128(frame.buf)
offset, _ = util.DecodeULEB128(frame.buf)
)
frame.regs[reg] = DWRule{offset: int64(offset) * frame.dataAlignment, rule: rule_offset}
}
func undefined(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf)
frame.regs[reg] = DWRule{rule: rule_undefined}
}
func samevalue(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf)
frame.regs[reg] = DWRule{rule: rule_sameval}
}
func register(frame *FrameContext) {
reg1, _ := util.DecodeULEB128(frame.buf)
reg2, _ := util.DecodeULEB128(frame.buf)
frame.regs[reg1] = DWRule{newreg: reg2, rule: rule_register}
}
func rememberstate(frame *FrameContext) {
frame.prevRegs = frame.regs
}
func restorestate(frame *FrameContext) {
frame.regs = frame.prevRegs
}
func restoreextended(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf)
oldrule, ok := frame.initialRegs[reg]
if ok {
frame.regs[reg] = DWRule{offset: oldrule.offset, rule: rule_offset}
} else {
frame.regs[reg] = DWRule{rule: rule_undefined}
}
}
func defcfa(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf)
offset, _ := util.DecodeULEB128(frame.buf)
frame.cfa.register = reg
frame.cfa.offset = int64(offset)
}
func defcfaregister(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf)
frame.cfa.register = reg
}
func defcfaoffset(frame *FrameContext) {
offset, _ := util.DecodeULEB128(frame.buf)
frame.cfa.offset = int64(offset)
}
func defcfasf(frame *FrameContext) {
reg, _ := util.DecodeULEB128(frame.buf)
offset, _ := util.DecodeSLEB128(frame.buf)
frame.cfa.register = reg
frame.cfa.offset = offset * frame.dataAlignment
}
func defcfaoffsetsf(frame *FrameContext) {
offset, _ := util.DecodeSLEB128(frame.buf)
offset *= frame.dataAlignment
frame.cfa.offset = offset
}
func defcfaexpression(frame *FrameContext) {
var (
l, _ = util.DecodeULEB128(frame.buf)
expr = frame.buf.Next(int(l))
)
frame.cfa.expression = expr
frame.cfa.rule = rule_expression
}
func expression(frame *FrameContext) {
var (
reg, _ = util.DecodeULEB128(frame.buf)
l, _ = util.DecodeULEB128(frame.buf)
expr = frame.buf.Next(int(l))
)
frame.regs[reg] = DWRule{rule: rule_expression, expression: expr}
}
func offsetextendedsf(frame *FrameContext) {
var (
reg, _ = util.DecodeULEB128(frame.buf)
offset, _ = util.DecodeSLEB128(frame.buf)
)
frame.regs[reg] = DWRule{offset: offset * frame.dataAlignment, rule: rule_offset}
}
func valoffset(frame *FrameContext) {
var (
reg, _ = util.DecodeULEB128(frame.buf)
offset, _ = util.DecodeULEB128(frame.buf)
)
frame.regs[reg] = DWRule{offset: int64(offset), rule: rule_valoffset}
}
func valoffsetsf(frame *FrameContext) {
var (
reg, _ = util.DecodeULEB128(frame.buf)
offset, _ = util.DecodeSLEB128(frame.buf)
)
frame.regs[reg] = DWRule{offset: offset * frame.dataAlignment, rule: rule_valoffset}
}
func valexpression(frame *FrameContext) {
var (
reg, _ = util.DecodeULEB128(frame.buf)
l, _ = util.DecodeULEB128(frame.buf)
expr = frame.buf.Next(int(l))
)
frame.regs[reg] = DWRule{rule: rule_valexpression, expression: expr}
}
func louser(frame *FrameContext) {
frame.buf.Next(1)
}
func hiuser(frame *FrameContext) {
frame.buf.Next(1)
}

View File

@ -1,122 +0,0 @@
package line
import (
"bytes"
"encoding/binary"
"github.com/derekparker/delve/dwarf/util"
)
type DebugLinePrologue struct {
UnitLength uint32
Version uint16
Length uint32
MinInstrLength uint8
InitialIsStmt uint8
LineBase int8
LineRange uint8
OpcodeBase uint8
StdOpLengths []uint8
}
type DebugLineInfo struct {
Prologue *DebugLinePrologue
IncludeDirs []string
FileNames []*FileEntry
Instructions []byte
Lookup map[string]*FileEntry
}
type FileEntry struct {
Name string
DirIdx uint64
LastModTime uint64
Length uint64
}
type DebugLines []*DebugLineInfo
func (d *DebugLines) GetLineInfo(name string) *DebugLineInfo {
// Find in which table file exists and return it.
for _, l := range *d {
if _, ok := l.Lookup[name]; ok {
return l
}
}
return nil
}
func Parse(data []byte) DebugLines {
var (
lines = make(DebugLines, 0)
buf = bytes.NewBuffer(data)
)
// We have to parse multiple file name tables here.
for buf.Len() > 0 {
dbl := new(DebugLineInfo)
dbl.Lookup = make(map[string]*FileEntry)
parseDebugLinePrologue(dbl, buf)
parseIncludeDirs(dbl, buf)
parseFileEntries(dbl, buf)
// Instructions size calculation breakdown:
// - dbl.Prologue.UnitLength is the length of the entire unit, not including the 4 bytes to represent that length.
// - dbl.Prologue.Length is the length of the prologue not including unit length, version or prologue length itself.
// - So you have UnitLength - PrologueLength - (version_length_bytes(2) + prologue_length_bytes(4)).
dbl.Instructions = buf.Next(int(dbl.Prologue.UnitLength - dbl.Prologue.Length - 6))
lines = append(lines, dbl)
}
return lines
}
func parseDebugLinePrologue(dbl *DebugLineInfo, buf *bytes.Buffer) {
p := new(DebugLinePrologue)
p.UnitLength = binary.LittleEndian.Uint32(buf.Next(4))
p.Version = binary.LittleEndian.Uint16(buf.Next(2))
p.Length = binary.LittleEndian.Uint32(buf.Next(4))
p.MinInstrLength = uint8(buf.Next(1)[0])
p.InitialIsStmt = uint8(buf.Next(1)[0])
p.LineBase = int8(buf.Next(1)[0])
p.LineRange = uint8(buf.Next(1)[0])
p.OpcodeBase = uint8(buf.Next(1)[0])
p.StdOpLengths = make([]uint8, p.OpcodeBase-1)
binary.Read(buf, binary.LittleEndian, &p.StdOpLengths)
dbl.Prologue = p
}
func parseIncludeDirs(info *DebugLineInfo, buf *bytes.Buffer) {
for {
str, _ := util.ParseString(buf)
if str == "" {
break
}
info.IncludeDirs = append(info.IncludeDirs, str)
}
}
func parseFileEntries(info *DebugLineInfo, buf *bytes.Buffer) {
for {
entry := new(FileEntry)
name, _ := util.ParseString(buf)
if name == "" {
break
}
entry.Name = name
entry.DirIdx, _ = util.DecodeULEB128(buf)
entry.LastModTime, _ = util.DecodeULEB128(buf)
entry.Length, _ = util.DecodeULEB128(buf)
info.FileNames = append(info.FileNames, entry)
info.Lookup[name] = entry
}
}

View File

@ -1,252 +0,0 @@
package line
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/derekparker/delve/dwarf/util"
)
type Location struct {
File string
Line int
Address uint64
Delta int
}
type StateMachine struct {
dbl *DebugLineInfo
file string
line int
address uint64
column uint
isStmt bool
basicBlock bool
endSeq bool
lastWasStandard bool
lastDelta int
}
type opcodefn func(*StateMachine, *bytes.Buffer)
// Special opcodes
const (
DW_LNS_copy = 1
DW_LNS_advance_pc = 2
DW_LNS_advance_line = 3
DW_LNS_set_file = 4
DW_LNS_set_column = 5
DW_LNS_negate_stmt = 6
DW_LNS_set_basic_block = 7
DW_LNS_const_add_pc = 8
DW_LNS_fixed_advance_pc = 9
)
// Extended opcodes
const (
DW_LINE_end_sequence = 1
DW_LINE_set_address = 2
DW_LINE_define_file = 3
)
var standardopcodes = map[byte]opcodefn{
DW_LNS_copy: copyfn,
DW_LNS_advance_pc: advancepc,
DW_LNS_advance_line: advanceline,
DW_LNS_set_file: setfile,
DW_LNS_set_column: setcolumn,
DW_LNS_negate_stmt: negatestmt,
DW_LNS_set_basic_block: setbasicblock,
DW_LNS_const_add_pc: constaddpc,
DW_LNS_fixed_advance_pc: fixedadvancepc,
}
var extendedopcodes = map[byte]opcodefn{
DW_LINE_end_sequence: endsequence,
DW_LINE_set_address: setaddress,
DW_LINE_define_file: definefile,
}
func newStateMachine(dbl *DebugLineInfo) *StateMachine {
return &StateMachine{dbl: dbl, file: dbl.FileNames[0].Name, line: 1}
}
// Returns all PCs for a given file/line. Useful for loops where the 'for' line
// could be split amongst 2 PCs.
func (dbl *DebugLines) AllPCsForFileLine(f string, l int) (pcs []uint64) {
var (
foundFile bool
lastAddr uint64
lineInfo = dbl.GetLineInfo(f)
sm = newStateMachine(lineInfo)
buf = bytes.NewBuffer(lineInfo.Instructions)
)
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
findAndExecOpcode(sm, buf, b)
if foundFile && sm.file != f {
return
}
if sm.line == l && sm.file == f && sm.address != lastAddr {
foundFile = true
pcs = append(pcs, sm.address)
line := sm.line
// Keep going until we're on a different line. We only care about
// when a line comes back around (i.e. for loop) so get to next line,
// and try to find the line we care about again.
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
findAndExecOpcode(sm, buf, b)
if line < sm.line {
break
}
}
}
}
return
}
var NoSourceError = errors.New("no source available")
func (dbl *DebugLines) AllPCsBetween(begin, end uint64, filename string) ([]uint64, error) {
lineInfo := dbl.GetLineInfo(filename)
if lineInfo == nil {
return nil, NoSourceError
}
var (
pcs []uint64
lastaddr uint64
sm = newStateMachine(lineInfo)
buf = bytes.NewBuffer(lineInfo.Instructions)
)
for b, err := buf.ReadByte(); err == nil; b, err = buf.ReadByte() {
findAndExecOpcode(sm, buf, b)
if sm.address > end {
break
}
if sm.address >= begin && sm.address > lastaddr {
lastaddr = sm.address
pcs = append(pcs, sm.address)
}
}
return pcs, nil
}
func findAndExecOpcode(sm *StateMachine, buf *bytes.Buffer, b byte) {
switch {
case b == 0:
execExtendedOpcode(sm, b, buf)
case b < sm.dbl.Prologue.OpcodeBase:
execStandardOpcode(sm, b, buf)
default:
execSpecialOpcode(sm, b)
}
}
func execSpecialOpcode(sm *StateMachine, instr byte) {
var (
opcode = uint8(instr)
decoded = opcode - sm.dbl.Prologue.OpcodeBase
)
if sm.dbl.Prologue.InitialIsStmt == uint8(1) {
sm.isStmt = true
}
sm.lastDelta = int(sm.dbl.Prologue.LineBase + int8(decoded%sm.dbl.Prologue.LineRange))
sm.line += sm.lastDelta
sm.address += uint64(decoded / sm.dbl.Prologue.LineRange)
sm.basicBlock = false
sm.lastWasStandard = false
}
func execExtendedOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
_, _ = util.DecodeULEB128(buf)
b, _ := buf.ReadByte()
fn, ok := extendedopcodes[b]
if !ok {
panic(fmt.Sprintf("Encountered unknown extended opcode %#v\n", b))
}
sm.lastWasStandard = false
fn(sm, buf)
}
func execStandardOpcode(sm *StateMachine, instr byte, buf *bytes.Buffer) {
fn, ok := standardopcodes[instr]
if !ok {
panic(fmt.Sprintf("Encountered unknown standard opcode %#v\n", instr))
}
sm.lastWasStandard = true
fn(sm, buf)
}
func copyfn(sm *StateMachine, buf *bytes.Buffer) {
sm.basicBlock = false
}
func advancepc(sm *StateMachine, buf *bytes.Buffer) {
addr, _ := util.DecodeULEB128(buf)
sm.address += addr * uint64(sm.dbl.Prologue.MinInstrLength)
}
func advanceline(sm *StateMachine, buf *bytes.Buffer) {
line, _ := util.DecodeSLEB128(buf)
sm.line += int(line)
sm.lastDelta = int(line)
}
func setfile(sm *StateMachine, buf *bytes.Buffer) {
i, _ := util.DecodeULEB128(buf)
sm.file = sm.dbl.FileNames[i-1].Name
}
func setcolumn(sm *StateMachine, buf *bytes.Buffer) {
c, _ := util.DecodeULEB128(buf)
sm.column = uint(c)
}
func negatestmt(sm *StateMachine, buf *bytes.Buffer) {
sm.isStmt = !sm.isStmt
}
func setbasicblock(sm *StateMachine, buf *bytes.Buffer) {
sm.basicBlock = true
}
func constaddpc(sm *StateMachine, buf *bytes.Buffer) {
sm.address += (255 / uint64(sm.dbl.Prologue.LineRange))
}
func fixedadvancepc(sm *StateMachine, buf *bytes.Buffer) {
var operand uint16
binary.Read(buf, binary.LittleEndian, &operand)
sm.address += uint64(operand)
}
func endsequence(sm *StateMachine, buf *bytes.Buffer) {
sm.endSeq = true
}
func setaddress(sm *StateMachine, buf *bytes.Buffer) {
var addr uint64
binary.Read(buf, binary.LittleEndian, &addr)
sm.address = addr
}
func definefile(sm *StateMachine, buf *bytes.Buffer) {
var (
_, _ = util.ParseString(buf)
_, _ = util.DecodeULEB128(buf)
_, _ = util.DecodeULEB128(buf)
_, _ = util.DecodeULEB128(buf)
)
// Don't do anything here yet.
}

View File

@ -1,84 +0,0 @@
package op
import (
"bytes"
"encoding/binary"
"errors"
"fmt"
"github.com/derekparker/delve/dwarf/util"
)
const (
DW_OP_addr = 0x3
DW_OP_call_frame_cfa = 0x9c
DW_OP_plus = 0x22
DW_OP_consts = 0x11
DW_OP_plus_uconsts = 0x23
)
type stackfn func(*bytes.Buffer, []int64, int64) ([]int64, error)
var oplut = map[byte]stackfn{
DW_OP_call_frame_cfa: callframecfa,
DW_OP_plus: plus,
DW_OP_consts: consts,
DW_OP_addr: addr,
DW_OP_plus_uconsts: plusuconsts,
}
func ExecuteStackProgram(cfa int64, instructions []byte) (int64, error) {
stack := make([]int64, 0, 3)
buf := bytes.NewBuffer(instructions)
for opcode, err := buf.ReadByte(); err == nil; opcode, err = buf.ReadByte() {
fn, ok := oplut[opcode]
if !ok {
return 0, fmt.Errorf("invalid instruction %#v", opcode)
}
stack, err = fn(buf, stack, cfa)
if err != nil {
return 0, err
}
}
if len(stack) == 0 {
return 0, errors.New("empty OP stack")
}
return stack[len(stack)-1], nil
}
func callframecfa(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
if cfa == 0 {
return stack, fmt.Errorf("Could not retrieve CFA for current PC")
}
return append(stack, int64(cfa)), nil
}
func addr(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
return append(stack, int64(binary.LittleEndian.Uint64(buf.Next(8)))), nil
}
func plus(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
var (
slen = len(stack)
digits = stack[slen-2 : slen]
st = stack[:slen-2]
)
return append(st, digits[0]+digits[1]), nil
}
func plusuconsts(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
slen := len(stack)
num, _ := util.DecodeULEB128(buf)
stack[slen-1] = stack[slen-1] + int64(num)
return stack, nil
}
func consts(buf *bytes.Buffer, stack []int64, cfa int64) ([]int64, error) {
num, _ := util.DecodeSLEB128(buf)
return append(stack, num), nil
}

View File

@ -1,345 +0,0 @@
package reader
import (
"errors"
"fmt"
"golang.org/x/debug/dwarf"
"github.com/derekparker/delve/dwarf/op"
)
type Reader struct {
*dwarf.Reader
depth int
}
// New returns a reader for the specified dwarf data.
func New(data *dwarf.Data) *Reader {
return &Reader{data.Reader(), 0}
}
// Seek moves the reader to an arbitrary offset.
func (reader *Reader) Seek(off dwarf.Offset) {
reader.depth = 0
reader.Reader.Seek(off)
}
// SeekToEntry moves the reader to an arbitrary entry.
func (reader *Reader) SeekToEntry(entry *dwarf.Entry) error {
reader.Seek(entry.Offset)
// Consume the current entry so .Next works as intended
_, err := reader.Next()
return err
}
// SeekToFunctionEntry moves the reader to the function that includes the
// specified program counter.
func (reader *Reader) SeekToFunction(pc uint64) (*dwarf.Entry, error) {
reader.Seek(0)
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Tag != dwarf.TagSubprogram {
continue
}
lowpc, ok := entry.Val(dwarf.AttrLowpc).(uint64)
if !ok {
continue
}
highpc, ok := entry.Val(dwarf.AttrHighpc).(uint64)
if !ok {
continue
}
if lowpc <= pc && highpc > pc {
return entry, nil
}
}
return nil, fmt.Errorf("unable to find function context")
}
// Returns the address for the named entry.
func (reader *Reader) AddrFor(name string) (uint64, error) {
entry, err := reader.FindEntryNamed(name, false)
if err != nil {
return 0, err
}
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
if !ok {
return 0, fmt.Errorf("type assertion failed")
}
addr, err := op.ExecuteStackProgram(0, instructions)
if err != nil {
return 0, err
}
return uint64(addr), nil
}
// Returns the address for the named struct member. Expects the reader to be at the parent entry
// or one of the parents children, thus does not seek to parent by itself.
func (reader *Reader) AddrForMember(member string, initialInstructions []byte) (uint64, error) {
for {
entry, err := reader.NextMemberVariable()
if err != nil {
return 0, err
}
if entry == nil {
return 0, fmt.Errorf("nil entry for member named %s", member)
}
name, ok := entry.Val(dwarf.AttrName).(string)
if !ok || name != member {
continue
}
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
if !ok {
continue
}
addr, err := op.ExecuteStackProgram(0, append(initialInstructions, instructions...))
return uint64(addr), err
}
}
var TypeNotFoundErr = errors.New("no type entry found, use 'types' for a list of valid types")
// SeekToType moves the reader to the type specified by the entry,
// optionally resolving typedefs and pointer types. If the reader is set
// to a struct type the NextMemberVariable call can be used to walk all member data.
func (reader *Reader) SeekToType(entry *dwarf.Entry, resolveTypedefs bool, resolvePointerTypes bool) (*dwarf.Entry, error) {
offset, ok := entry.Val(dwarf.AttrType).(dwarf.Offset)
if !ok {
return nil, fmt.Errorf("entry does not have a type attribute")
}
// Seek to the first type offset
reader.Seek(offset)
// Walk the types to the base
for typeEntry, err := reader.Next(); typeEntry != nil; typeEntry, err = reader.Next() {
if err != nil {
return nil, err
}
if typeEntry.Tag == dwarf.TagTypedef && !resolveTypedefs {
return typeEntry, nil
}
if typeEntry.Tag == dwarf.TagPointerType && !resolvePointerTypes {
return typeEntry, nil
}
offset, ok = typeEntry.Val(dwarf.AttrType).(dwarf.Offset)
if !ok {
return typeEntry, nil
}
reader.Seek(offset)
}
return nil, TypeNotFoundErr
}
func (reader *Reader) NextType() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
switch entry.Tag {
case dwarf.TagArrayType, dwarf.TagBaseType, dwarf.TagClassType, dwarf.TagStructType, dwarf.TagUnionType, dwarf.TagConstType, dwarf.TagVolatileType, dwarf.TagRestrictType, dwarf.TagEnumerationType, dwarf.TagPointerType, dwarf.TagSubroutineType, dwarf.TagTypedef, dwarf.TagUnspecifiedType:
return entry, nil
}
}
return nil, nil
}
// SeekToTypeNamed moves the reader to the type specified by the name.
// If the reader is set to a struct type the NextMemberVariable call
// can be used to walk all member data.
func (reader *Reader) SeekToTypeNamed(name string) (*dwarf.Entry, error) {
// Walk the types to the base
for entry, err := reader.NextType(); entry != nil; entry, err = reader.NextType() {
if err != nil {
return nil, err
}
n, ok := entry.Val(dwarf.AttrName).(string)
if !ok {
continue
}
if n == name {
return entry, nil
}
}
return nil, TypeNotFoundErr
}
// Finds the entry for 'name'.
func (reader *Reader) FindEntryNamed(name string, member bool) (*dwarf.Entry, error) {
depth := 1
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Children {
depth++
}
if entry.Tag == 0 {
depth--
if depth <= 0 {
return nil, fmt.Errorf("could not find symbol value for %s", name)
}
}
if member {
if entry.Tag != dwarf.TagMember {
continue
}
} else {
if entry.Tag != dwarf.TagVariable && entry.Tag != dwarf.TagFormalParameter && entry.Tag != dwarf.TagStructType {
continue
}
}
n, ok := entry.Val(dwarf.AttrName).(string)
if !ok || n != name {
continue
}
return entry, nil
}
return nil, fmt.Errorf("could not find symbol value for %s", name)
}
func (reader *Reader) InstructionsForEntryNamed(name string, member bool) ([]byte, error) {
entry, err := reader.FindEntryNamed(name, member)
if err != nil {
return nil, err
}
var attr dwarf.Attr
if member {
attr = dwarf.AttrDataMemberLoc
} else {
attr = dwarf.AttrLocation
}
instr, ok := entry.Val(attr).([]byte)
if !ok {
return nil, errors.New("invalid typecast for Dwarf instructions")
}
return instr, nil
}
func (reader *Reader) InstructionsForEntry(entry *dwarf.Entry) ([]byte, error) {
if entry.Tag == dwarf.TagMember {
instructions, ok := entry.Val(dwarf.AttrDataMemberLoc).([]byte)
if !ok {
return nil, fmt.Errorf("member data has no data member location attribute")
}
// clone slice to prevent stomping on the dwarf data
return append([]byte{}, instructions...), nil
}
// non-member
instructions, ok := entry.Val(dwarf.AttrLocation).([]byte)
if !ok {
return nil, fmt.Errorf("entry has no location attribute")
}
// clone slice to prevent stomping on the dwarf data
return append([]byte{}, instructions...), nil
}
// NextScopeVariable moves the reader to the next debug entry that describes a local variable and returns the entry.
func (reader *Reader) NextScopeVariable() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
// All scope variables will be at the same depth
reader.SkipChildren()
// End of the current depth
if entry.Tag == 0 {
break
}
if entry.Tag == dwarf.TagVariable || entry.Tag == dwarf.TagFormalParameter {
return entry, nil
}
}
// No more items
return nil, nil
}
// NextMememberVariable moves the reader to the next debug entry that describes a member variable and returns the entry.
func (reader *Reader) NextMemberVariable() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
// All member variables will be at the same depth
reader.SkipChildren()
// End of the current depth
if entry.Tag == 0 {
break
}
if entry.Tag == dwarf.TagMember {
return entry, nil
}
}
// No more items
return nil, nil
}
// NextPackageVariable moves the reader to the next debug entry that describes a package variable.
// Any TagVariable entry that is not inside a sub prgram entry and is marked external is considered a package variable.
func (reader *Reader) NextPackageVariable() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Tag == dwarf.TagVariable {
ext, ok := entry.Val(dwarf.AttrExternal).(bool)
if ok && ext {
return entry, nil
}
}
// Ignore everything inside sub programs
if entry.Tag == dwarf.TagSubprogram {
reader.SkipChildren()
}
}
// No more items
return nil, nil
}
func (reader *Reader) NextCompileUnit() (*dwarf.Entry, error) {
for entry, err := reader.Next(); entry != nil; entry, err = reader.Next() {
if err != nil {
return nil, err
}
if entry.Tag == dwarf.TagCompileUnit {
return entry, nil
}
}
return nil, nil
}

View File

@ -1,81 +0,0 @@
package util
import "bytes"
// DecodeULEB128 decodes an unsigned Little Endian Base 128
// represented number.
func DecodeULEB128(buf *bytes.Buffer) (uint64, uint32) {
var (
result uint64
shift uint64
length uint32
)
if buf.Len() == 0 {
return 0, 0
}
for {
b, err := buf.ReadByte()
if err != nil {
panic("Could not parse ULEB128 value")
}
length++
result |= uint64((uint(b) & 0x7f) << shift)
// If high order bit is 1.
if b&0x80 == 0 {
break
}
shift += 7
}
return result, length
}
// DecodeSLEB128 decodes a signed Little Endian Base 128
// represented number.
func DecodeSLEB128(buf *bytes.Buffer) (int64, uint32) {
var (
b byte
err error
result int64
shift uint64
length uint32
)
if buf.Len() == 0 {
return 0, 0
}
for {
b, err = buf.ReadByte()
if err != nil {
panic("Could not parse SLEB128 value")
}
length++
result |= int64((int64(b) & 0x7f) << shift)
shift += 7
if b&0x80 == 0 {
break
}
}
if (shift < 8*uint64(length)) && (b&0x40 > 0) {
result |= -(1 << shift)
}
return result, length
}
func ParseString(data *bytes.Buffer) (string, uint32) {
str, err := data.ReadString(0x0)
if err != nil {
panic("Could not parse string")
}
return str[:len(str)-1], uint32(len(str))
}

View File

@ -1,79 +0,0 @@
package proc
import "runtime"
// Arch defines an interface for representing a
// CPU architecture.
type Arch interface {
SetGStructOffset(ver GoVersion, iscgo bool)
PtrSize() int
BreakpointInstruction() []byte
BreakpointSize() int
GStructOffset() uint64
}
// AMD64 represents the AMD64 CPU architecture.
type AMD64 struct {
ptrSize int
breakInstruction []byte
breakInstructionLen int
gStructOffset uint64
hardwareBreakpointUsage []bool
}
// AMD64Arch returns an initialized AMD64
// struct.
func AMD64Arch() *AMD64 {
var breakInstr = []byte{0xCC}
return &AMD64{
ptrSize: 8,
breakInstruction: breakInstr,
breakInstructionLen: len(breakInstr),
hardwareBreakpointUsage: make([]bool, 4),
}
}
// SetGStructOffset sets the offset of the G struct on the AMD64
// arch struct. The offset is dependent on the Go compiler Version
// and whether or not the target program was externally linked.
func (a *AMD64) SetGStructOffset(ver GoVersion, isextld bool) {
switch runtime.GOOS {
case "darwin":
a.gStructOffset = 0x8a0
case "linux":
a.gStructOffset = 0xfffffffffffffff0
if isextld || ver.AfterOrEqual(GoVersion{1, 5, -1, 2, 0}) || ver.IsDevel() {
a.gStructOffset += 8
}
case "windows":
// Use ArbitraryUserPointer (0x28) as pointer to pointer
// to G struct per:
// https://golang.org/src/runtime/cgo/gcc_windows_amd64.c
a.gStructOffset = 0x28
}
}
// PtrSize returns the size of a pointer
// on this architecture.
func (a *AMD64) PtrSize() int {
return a.ptrSize
}
// BreakpointInstruction returns the Breakpoint
// instruction for this architecture.
func (a *AMD64) BreakpointInstruction() []byte {
return a.breakInstruction
}
// BreakpointSize returns the size of the
// breakpoint instruction on this architecture.
func (a *AMD64) BreakpointSize() int {
return a.breakInstructionLen
}
// GStructOffset returns the offset of the G
// struct in thread local storage.
func (a *AMD64) GStructOffset() uint64 {
return a.gStructOffset
}

View File

@ -1,163 +0,0 @@
package proc
import (
"errors"
"fmt"
"go/ast"
"go/constant"
"reflect"
)
// Breakpoint represents a breakpoint. Stores information on the break
// point including the byte of data that originally was stored at that
// address.
type Breakpoint struct {
// File & line information for printing.
FunctionName string
File string
Line int
Addr uint64 // Address breakpoint is set for.
OriginalData []byte // If software breakpoint, the data we replace with breakpoint instruction.
Name string // User defined name of the breakpoint
ID int // Monotonically increasing ID.
Kind BreakpointKind // Whether this is an internal breakpoint (for next'ing or stepping).
// Breakpoint information
Tracepoint bool // Tracepoint flag
Goroutine bool // Retrieve goroutine information
Stacktrace int // Number of stack frames to retrieve
Variables []string // Variables to evaluate
LoadArgs *LoadConfig
LoadLocals *LoadConfig
HitCount map[int]uint64 // Number of times a breakpoint has been reached in a certain goroutine
TotalHitCount uint64 // Number of times a breakpoint has been reached
// DeferReturns: when kind == NextDeferBreakpoint this breakpoint
// will also check if the caller is runtime.gopanic or if the return
// address is in the DeferReturns array.
// Next uses NextDeferBreakpoints for the breakpoint it sets on the
// deferred function, DeferReturns is populated with the
// addresses of calls to runtime.deferreturn in the current
// function. This insures that the breakpoint on the deferred
// function only triggers on panic or on the defer call to
// the function, not when the function is called directly
DeferReturns []uint64
// Cond: if not nil the breakpoint will be triggered only if evaluating Cond returns true
Cond ast.Expr
}
// Breakpoint Kind determines the behavior of delve when the
// breakpoint is reached.
type BreakpointKind int
const (
// UserBreakpoint is a user set breakpoint
UserBreakpoint BreakpointKind = iota
// NextBreakpoint is a breakpoint set by Next, Continue
// will stop on it and delete it
NextBreakpoint
// NextDeferBreakpoint is a breakpoint set by Next on the
// first deferred function. In addition to checking their condition
// breakpoints of this kind will also check that the function has been
// called by runtime.gopanic or through runtime.deferreturn.
NextDeferBreakpoint
// StepBreakpoint is a breakpoint set by Step on a CALL instruction,
// Continue will set a new breakpoint (of NextBreakpoint kind) on the
// destination of CALL, delete this breakpoint and then continue again
StepBreakpoint
)
func (bp *Breakpoint) String() string {
return fmt.Sprintf("Breakpoint %d at %#v %s:%d (%d)", bp.ID, bp.Addr, bp.File, bp.Line, bp.TotalHitCount)
}
// Clear this breakpoint appropriately depending on whether it is a
// hardware or software breakpoint.
func (bp *Breakpoint) Clear(thread *Thread) (*Breakpoint, error) {
if _, err := thread.writeMemory(uintptr(bp.Addr), bp.OriginalData); err != nil {
return nil, fmt.Errorf("could not clear breakpoint %s", err)
}
return bp, nil
}
// BreakpointExistsError is returned when trying to set a breakpoint at
// an address that already has a breakpoint set for it.
type BreakpointExistsError struct {
file string
line int
addr uint64
}
func (bpe BreakpointExistsError) Error() string {
return fmt.Sprintf("Breakpoint exists at %s:%d at %x", bpe.file, bpe.line, bpe.addr)
}
// InvalidAddressError represents the result of
// attempting to set a breakpoint at an invalid address.
type InvalidAddressError struct {
address uint64
}
func (iae InvalidAddressError) Error() string {
return fmt.Sprintf("Invalid address %#v\n", iae.address)
}
func (dbp *Process) writeSoftwareBreakpoint(thread *Thread, addr uint64) error {
_, err := thread.writeMemory(uintptr(addr), dbp.arch.BreakpointInstruction())
return err
}
func (bp *Breakpoint) checkCondition(thread *Thread) (bool, error) {
if bp.Cond == nil {
return true, nil
}
if bp.Kind == NextDeferBreakpoint {
frames, err := thread.Stacktrace(2)
if err == nil {
ispanic := len(frames) >= 3 && frames[2].Current.Fn != nil && frames[2].Current.Fn.Name == "runtime.gopanic"
isdeferreturn := false
if len(frames) >= 1 {
for _, pc := range bp.DeferReturns {
if frames[0].Ret == pc {
isdeferreturn = true
break
}
}
}
if !ispanic && !isdeferreturn {
return false, nil
}
}
}
scope, err := thread.Scope()
if err != nil {
return true, err
}
v, err := scope.evalAST(bp.Cond)
if err != nil {
return true, fmt.Errorf("error evaluating expression: %v", err)
}
if v.Unreadable != nil {
return true, fmt.Errorf("condition expression unreadable: %v", v.Unreadable)
}
if v.Kind != reflect.Bool {
return true, errors.New("condition expression not boolean")
}
return constant.BoolVal(v.Value), nil
}
// Internal returns true for breakpoints not set directly by the user.
func (bp *Breakpoint) Internal() bool {
return bp.Kind != UserBreakpoint
}
// NoBreakpointError is returned when trying to
// clear a breakpoint that does not exist.
type NoBreakpointError struct {
addr uint64
}
func (nbp NoBreakpointError) Error() string {
return fmt.Sprintf("no breakpoint at %#v", nbp.addr)
}

View File

@ -1,67 +0,0 @@
package proc
type AsmInstruction struct {
Loc Location
DestLoc *Location
Bytes []byte
Breakpoint bool
AtPC bool
Inst *ArchInst
}
type AssemblyFlavour int
const (
GNUFlavour = AssemblyFlavour(iota)
IntelFlavour
)
// Disassemble disassembles target memory between startPC and endPC
// If currentGoroutine is set and thread is stopped at a CALL instruction Disassemble will evaluate the argument of the CALL instruction using the thread's registers
// Be aware that the Bytes field of each returned instruction is a slice of a larger array of size endPC - startPC
func (thread *Thread) Disassemble(startPC, endPC uint64, currentGoroutine bool) ([]AsmInstruction, error) {
if thread.dbp.exited {
return nil, &ProcessExitedError{}
}
mem, err := thread.readMemory(uintptr(startPC), int(endPC-startPC))
if err != nil {
return nil, err
}
r := make([]AsmInstruction, 0, len(mem)/15)
pc := startPC
var curpc uint64
var regs Registers
if currentGoroutine {
regs, _ = thread.Registers(false)
if regs != nil {
curpc = regs.PC()
}
}
for len(mem) > 0 {
bp, atbp := thread.dbp.Breakpoints[pc]
if atbp {
for i := range bp.OriginalData {
mem[i] = bp.OriginalData[i]
}
}
file, line, fn := thread.dbp.PCToLine(pc)
loc := Location{PC: pc, File: file, Line: line, Fn: fn}
inst, err := asmDecode(mem, pc)
if err == nil {
atpc := currentGoroutine && (curpc == pc)
destloc := thread.resolveCallArg(inst, atpc, regs)
r = append(r, AsmInstruction{Loc: loc, DestLoc: destloc, Bytes: mem[:inst.Len], Breakpoint: atbp, AtPC: atpc, Inst: inst})
pc += uint64(inst.Size())
mem = mem[inst.Size():]
} else {
r = append(r, AsmInstruction{Loc: loc, Bytes: mem[:1], Breakpoint: atbp, Inst: nil})
pc++
mem = mem[1:]
}
}
return r, nil
}

View File

@ -1,183 +0,0 @@
package proc
import (
"debug/gosym"
"encoding/binary"
"rsc.io/x86/x86asm"
)
var maxInstructionLength uint64 = 15
type ArchInst x86asm.Inst
func asmDecode(mem []byte, pc uint64) (*ArchInst, error) {
inst, err := x86asm.Decode(mem, 64)
if err != nil {
return nil, err
}
patchPCRel(pc, &inst)
r := ArchInst(inst)
return &r, nil
}
func (inst *ArchInst) Size() int {
return inst.Len
}
// converts PC relative arguments to absolute addresses
func patchPCRel(pc uint64, inst *x86asm.Inst) {
for i := range inst.Args {
rel, isrel := inst.Args[i].(x86asm.Rel)
if isrel {
inst.Args[i] = x86asm.Imm(int64(pc) + int64(rel) + int64(inst.Len))
}
}
return
}
func (inst *AsmInstruction) Text(flavour AssemblyFlavour) string {
if inst.Inst == nil {
return "?"
}
var text string
switch flavour {
case GNUFlavour:
text = x86asm.GNUSyntax(x86asm.Inst(*inst.Inst))
case IntelFlavour:
fallthrough
default:
text = x86asm.IntelSyntax(x86asm.Inst(*inst.Inst))
}
if inst.IsCall() && inst.DestLoc != nil && inst.DestLoc.Fn != nil {
text += " " + inst.DestLoc.Fn.Name
}
return text
}
func (inst *AsmInstruction) IsCall() bool {
return inst.Inst.Op == x86asm.CALL || inst.Inst.Op == x86asm.LCALL
}
func (thread *Thread) resolveCallArg(inst *ArchInst, currentGoroutine bool, regs Registers) *Location {
if inst.Op != x86asm.CALL && inst.Op != x86asm.LCALL {
return nil
}
var pc uint64
var err error
switch arg := inst.Args[0].(type) {
case x86asm.Imm:
pc = uint64(arg)
case x86asm.Reg:
if !currentGoroutine || regs == nil {
return nil
}
pc, err = regs.Get(int(arg))
if err != nil {
return nil
}
case x86asm.Mem:
if !currentGoroutine || regs == nil {
return nil
}
if arg.Segment != 0 {
return nil
}
regs, err := thread.Registers(false)
if err != nil {
return nil
}
base, err1 := regs.Get(int(arg.Base))
index, err2 := regs.Get(int(arg.Index))
if err1 != nil || err2 != nil {
return nil
}
addr := uintptr(int64(base) + int64(index*uint64(arg.Scale)) + arg.Disp)
//TODO: should this always be 64 bits instead of inst.MemBytes?
pcbytes, err := thread.readMemory(addr, inst.MemBytes)
if err != nil {
return nil
}
pc = binary.LittleEndian.Uint64(pcbytes)
default:
return nil
}
file, line, fn := thread.dbp.PCToLine(pc)
if fn == nil {
return nil
}
return &Location{PC: pc, File: file, Line: line, Fn: fn}
}
type instrseq []x86asm.Op
// Possible stacksplit prologues are inserted by stacksplit in
// $GOROOT/src/cmd/internal/obj/x86/obj6.go.
// The stacksplit prologue will always begin with loading curg in CX, this
// instruction is added by load_g_cx in the same file and is either 1 or 2
// MOVs.
var prologues []instrseq
func init() {
var tinyStacksplit = instrseq{x86asm.CMP, x86asm.JBE}
var smallStacksplit = instrseq{x86asm.LEA, x86asm.CMP, x86asm.JBE}
var bigStacksplit = instrseq{x86asm.MOV, x86asm.CMP, x86asm.JE, x86asm.LEA, x86asm.SUB, x86asm.CMP, x86asm.JBE}
var unixGetG = instrseq{x86asm.MOV}
var windowsGetG = instrseq{x86asm.MOV, x86asm.MOV}
prologues = make([]instrseq, 0, 2*3)
for _, getG := range []instrseq{unixGetG, windowsGetG} {
for _, stacksplit := range []instrseq{tinyStacksplit, smallStacksplit, bigStacksplit} {
prologue := make(instrseq, 0, len(getG)+len(stacksplit))
prologue = append(prologue, getG...)
prologue = append(prologue, stacksplit...)
prologues = append(prologues, prologue)
}
}
}
// FirstPCAfterPrologue returns the address of the first instruction after the prologue for function fn
// If sameline is set FirstPCAfterPrologue will always return an address associated with the same line as fn.Entry
func (dbp *Process) FirstPCAfterPrologue(fn *gosym.Func, sameline bool) (uint64, error) {
text, err := dbp.CurrentThread.Disassemble(fn.Entry, fn.End, false)
if err != nil {
return fn.Entry, err
}
if len(text) <= 0 {
return fn.Entry, nil
}
for _, prologue := range prologues {
if len(prologue) >= len(text) {
continue
}
if checkPrologue(text, prologue) {
r := &text[len(prologue)]
if sameline {
if r.Loc.Line != text[0].Loc.Line {
return fn.Entry, nil
}
}
return r.Loc.PC, nil
}
}
return fn.Entry, nil
}
func checkPrologue(s []AsmInstruction, prologuePattern instrseq) bool {
line := s[0].Loc.Line
for i, op := range prologuePattern {
if s[i].Inst.Op != op || s[i].Loc.Line != line {
return false
}
}
return true
}

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