Compare commits

..

773 Commits

Author SHA1 Message Date
1e3aa5f080 fix: v2.9.5 (#4503) 2025-11-10 21:40:35 +08:00
fde47e8981 fix(cmd/gf): The problem of the command 'gen dao' becoming very slow (#4498)
fixed #4479

修复gf gen dao执行严重变慢的问题

主要调整,降级两个依赖库
`go get golang.org/x/tools@v0.26.0` // 直接依赖
`go get golang.org/x/text@v0.25.0` // 间接依赖

至于为什么这两个库会导致慢,还需要深入排查
2025-11-10 17:38:50 +08:00
c02148cd6b feat(‎container/garray): Sorted T Array (#4470)
Add the sorted T array

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: hailaz <739476267@qq.com>
2025-10-17 18:10:31 +08:00
XG
1d4e684949 refactor(cmd/gf): Optimize run command to reload only on file write events (#4476)
优化run命令使得只在文件有写入事件时才触发reload:
gf run 的文件监控逻辑之前会对所有文件系统事件做出响应,包括非内容修改的事件(如文件access
time变化),这会导致开发过程中不必要的频繁重载。本次修改在文件监控回调中增加了event.IsWrite()的判断,确保只有在文件内容被实际写入时才触发重载逻辑,优化了开发体验。
2025-10-16 16:20:24 +08:00
8ff0de88b8 build(contrib): upgrade nacos registry&config (#4473)
RT
2025-10-16 11:29:44 +08:00
ac3efe5a00 feat(os/gcfg): Add file watcher with custom callback support (#4446)
为`gcfg`添加配置文件变更自定义回调,实现了`WatcherAdapter`接口,以下是`AdapterFile`的用法
test.yaml
```
b: "b"

```
```
package main

import (
	"fmt"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/os/gcfg"
	"github.com/gogf/gf/v2/os/gctx"
)

func main() {
	ctx := gctx.New()
	file, _ := gcfg.NewAdapterFile("test.yaml")
	file.Data(ctx)
	file.AddWatcher("test", func() {
		value := file.MustGet(ctx, "b")
		fmt.Println(value.String())
	})
	server := g.Server()
	server.Run()
}
```
使用`g`和默认配置文件
```
	file := g.Cfg().GetAdapter().(*gcfg.AdapterFile)
	file.AddWatcher("test", func() {

	})
	file := g.Cfg().GetAdapter().(*gcfg.AdapterFile)
	file.RemoveWatcher("test")
```

注意:由于`gf`的`AdapterFile`使用的监听到文件变化删除缓存下一次重新初始化的懒加载方案,所有除了默认加载的`config.xxx`文件外,自定义的配置文件像`test.yaml`之类的都需要在`AddWatcher`前主动读取一次数据进行初始化监听(
`g.Cfg("test").Data(ctx)`)

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: Hunk Zhu <hunk@joy999.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-15 16:59:52 +08:00
613
2744fe2212 fix(net/gclient): fix content-type 'application/json;charset=utf-8' … (#4369)
fix(net/gclient): fix content-type 'application/json;charset=utf-8' can
not match `application/json`

---------

Co-authored-by: houseme <housemecn@gmail.com>
2025-10-15 16:14:33 +08:00
1682cc98bb feat(gdb): Allow to set table field metadata and allow to generate table fields registration code when generating dao (#4460)
`gdb`在第一次查询时会拉取一次`table`的`fields meta`信息,为后续orm的字段过滤和时间特性服务,`gen
dao`时已经获得了`table`的所有`fields
meta`,提供一个生成`table`的功能,允许客户自行决定是否生成,是否注入已知表结构缓存到指定`db`实例。
1. 能解决部分兼容`mysql`的二开数据库在获取`fields meta`时无法和`mysql`保持一致的问题。
2.
可以模拟表字段信息而不需要真实的数据库连接,对于已知的表结构,可以直接设置缓存,在无法连接数据库的情况下,仍然可以使用表字段信息,使用gdb构建sql时不需要受限于实际数据库即可使用`gdb.ToSQL()`方法。
4. 提升访问速度

生成的示例目录
<img width="389" height="670" alt="SCR-20251010-ntne"
src="https://github.com/user-attachments/assets/ebb08e70-cce1-4b73-9128-6ff784e4df3b"
/>

生成的示例代码
```golang
// =================================================================================
// This file is auto-generated by the GoFrame CLI tool. You may modify it as needed.
// =================================================================================

package table

import (
	"context"

	"github.com/gogf/gf/v2/database/gdb"
)

// RolePermissions defines the fields of table "role_permissions" with their properties.
// This map is used internally by GoFrame ORM to understand table structure.
var RolePermissions = map[string]*gdb.TableField{
	"role_id": {
		Index:   0,
		Name:    "role_id",
		Type:    "bigint unsigned",
		Null:    false,
		Key:     "PRI",
		Default: nil,
		Extra:   "",
		Comment: "",
	},
	"permission_id": {
		Index:   1,
		Name:    "permission_id",
		Type:    "bigint unsigned",
		Null:    false,
		Key:     "PRI",
		Default: nil,
		Extra:   "",
		Comment: "",
	},
	"created_at": {
		Index:   2,
		Name:    "created_at",
		Type:    "timestamp",
		Null:    false,
		Key:     "",
		Default: "CURRENT_TIMESTAMP",
		Extra:   "DEFAULT_GENERATED",
		Comment: "",
	},
	"updated_at": {
		Index:   3,
		Name:    "updated_at",
		Type:    "timestamp",
		Null:    false,
		Key:     "",
		Default: "CURRENT_TIMESTAMP",
		Extra:   "DEFAULT_GENERATED on update CURRENT_TIMESTAMP",
		Comment: "",
	},
	"deleted_at": {
		Index:   4,
		Name:    "deleted_at",
		Type:    "timestamp",
		Null:    true,
		Key:     "",
		Default: nil,
		Extra:   "",
		Comment: "",
	},
}

// SetRolePermissionsTableFields registers the table fields definition to the database instance.
// db: database instance that implements gdb.DB interface.
// schema: optional schema/namespace name, especially for databases that support schemas.
func SetRolePermissionsTableFields(ctx context.Context, db gdb.DB, schema ...string) error {
	return db.GetCore().SetTableFields(ctx, "role_permissions", RolePermissions, schema...)
}

```
2025-10-15 15:50:16 +08:00
613
2742c98c06 fix(os/gcron): unit testing case of package gcron occasionally failed (#4419)
fix https://github.com/gogf/gf/issues/3999

1. fix  jobWaiter   sync.WaitGroup  data race
2. fix logger      glog.ILogger data race

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-15 15:17:05 +08:00
4226a23a39 feat(container/garray): add TArray (#4466)
Add TArray[T] for wrapping Array

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-15 15:08:26 +08:00
613
b8e414e125 fix(os/gcache): defaultcache lazy init (#4468)
defaultcache更改为懒加载,在用户使用redis缓存时,避免了程序启动时不必要的初始化开销。


<img width="2638" height="806" alt="image"
src="https://github.com/user-attachments/assets/96bb0097-8463-4303-971c-ee1a9ef671a6"
/>

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-10-15 15:01:47 +08:00
08c34b5ed7 feat(gf/build): Add support for the Loongson architecture (loong64) (#4467)
添加对龙芯架构(loong64)的支持

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-10-15 14:38:42 +08:00
416f314390 fix(contrib/drivers/pgsql): Merge duplicated fields, especially for key constraints. (#4465)
pgsql 执行TableFields 或者字段信息时需要合并key信息
2025-10-13 18:16:09 +08:00
98f0c36a1d fix: update gf cli to v2.9.4 (#4463)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action

Co-authored-by: hailaz <hailaz@users.noreply.github.com>
2025-10-11 15:10:30 +08:00
2b7b4c8581 fix: v2.9.4 (#4461)
Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-10-11 14:58:01 +08:00
613
b8844f3d40 fix(net/ghttp): attachment filename support utf8 (#4459) 2025-10-10 10:32:02 +08:00
3e2176d799 fix:(cmd/gf): matching for table ex fix bug (#4458)
fix the bug: sometimes it won't remove all broad matching talbenames.

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-10-09 12:08:28 +08:00
2f9225057f fix(contrib/drivers/mysql): Fix unit test issue for batch insert in MySQL driver (#4456)
Resolve a temporary issue in the unit tests for batch insertion by
adjusting user IDs.

因为底层的插入随机性,会导致单元测试偶发失败。
2025-09-30 14:33:46 +08:00
7b373446dc feat(cmd/gf): add broad matching to gf gen dao's tableEx attribute. (#4453)
Add "*" and "?" to tableEx for "gf gen dao".

The "*" will match none or some char. And the "?" only match one char.

Co-authored-by: hailaz <739476267@qq.com>
2025-09-30 11:27:03 +08:00
0f6d47c7a8 fix(container/gqueue): Optimize queue length calculation and loop structure in test cases (#4455)
fixed #4376
2025-09-29 17:26:39 +08:00
f24729206b fix(database/gdb): Resolved the schema error in the database output log when using the database sharding feature (#4319)
error log
```
2025-06-18T15:36:08.315+08:00 [DEBU] {10a3b0cfd9124a186b89b07f50e67ce6} [  0 ms] [default] [db_0] [rows:1  ] SELECT `id`,`custom_name` FROM `custom` WHERE `id`=1 LIMIT 1

2025-06-18T15:36:09.259+08:00 [DEBU] {10a3b0cfd9124a186b89b07f50e67ce6} [  1 ms] [default] [db_0] [rows:1  ] SELECT `id`,`custom_name`,`remark`FROM `custom` WHERE `id`=2 LIMIT 1

```
right log
```
2025-06-18T15:36:08.315+08:00 [DEBU] {10a3b0cfd9124a186b89b07f50e67ce6} [  0 ms] [default] [db_0] [rows:1  ] SELECT `id`,`custom_name` FROM `custom` WHERE `id`=1 LIMIT 1

2025-06-18T15:36:09.259+08:00 [DEBU] {10a3b0cfd9124a186b89b07f50e67ce6} [  1 ms] [default] [db_1] [rows:1  ] SELECT `id`,`custom_name`,`remark`FROM `custom` WHERE `id`=2 LIMIT 1
```

```

type DbShardingRule struct {
}

func (d *DbShardingRule) SchemaName(ctx context.Context, config gdb.ShardingSchemaConfig, value any) (string, error) {
	if name, ok := value.(string); ok && (len(name) > 0) && gstr.HasPrefix(name, config.Prefix) {
		return name, nil
	}
	return "default", nil
}

func (d *DbShardingRule) TableName(ctx context.Context, config gdb.ShardingTableConfig, value any) (string, error) {
	return "", nil
}
```

```
config := gdb.ShardingConfig{
		Schema: gdb.ShardingSchemaConfig{
			Enable: true,
			Prefix: "db_",
			Rule:   &DbShardingRule{},
		},
	}
dao.Custom.Ctx(ctx).Sharding(config).ShardingValue("db_0").Where("id", 1).One()
dao.Custom.Ctx(ctx).Sharding(config).ShardingValue("db_1").Where("id", 2).One()
```
我有两个完全一样的数据库db_0和db_1,两个custom表里都只有一条数据,id是1和2,执行上面两条查询得的结果是正确的,
输出日志中应该分别是`[default] [db_0]`和`[default] [db_1]`,但是实际输出的都是`[default]
[db_0]`,

查看具体代码实现,该日志由Core实例中获取group和schema构成,而实际执行sql时如果使用了分库特性那么执行sql的link会使用当前面schema重新生成,但是没有重新赋给Core实例,所以输出日志的时候还是错的,只需要在生成link后生成日志前把schema赋给Core就行,方法执行完成后defer将schema重置回去,防止有人重复使用同一个gdb对象造成困扰

![SCR-20250618-ovoc](https://github.com/user-attachments/assets/815c364e-939f-4a2c-9669-d5b7d2742511)

![SCR-20250618-ovvk](https://github.com/user-attachments/assets/e7d0e375-78e6-4748-90ac-d02dba18720f)

![SCR-20250618-ozsu](https://github.com/user-attachments/assets/faa6d69b-331e-476b-8bf8-f62e564b04d3)

![SCR-20250618-ozwj](https://github.com/user-attachments/assets/15c524dc-dc19-4499-a3d3-32bf1d918a3a)
2025-09-28 17:57:27 +08:00
7e9715ab1d feat(contrib/drivers/mssql): mssql support LastInsertId (#4051)
修复mssqlserver的InsertAndGetId方法;插入记录如果是自增主键则返回ID

---------

Co-authored-by: 林孝义 <linxy@3755.com>
Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-28 17:55:08 +08:00
f565a347c4 fix(database/gdb): Fix GetArray return type and add Bools method (#4452)
Change the return type of the GetArray method to Array for consistency
in data structure. Introduce a new Bools method to convert Vars to a
slice of bools, along with corresponding test cases to validate the
functionality.

```go
// 改进前
res, _ := db.Model(table).Fields("id").Array()
ids := make([]int64, 0, len(res))
for _, v := range res {
ids = append(ids, v.Int64())
}
g.Dump(ids)
// 改进后
res, _ := db.Model(table).Fields("id").Array()
ids := res.Int64s()
g.Dump(ids)
```
2025-09-28 17:08:37 +08:00
f172e61585 fix(net/ghttp): Server Domain if is empty str, bind handler pattern will add @ which is not expect #4100 (#4101)
fix https://github.com/gogf/gf/issues/4100

---------

Co-authored-by: elonnzhang <elonnzhang@tencent.com>
Co-authored-by: hailaz <739476267@qq.com>
2025-09-26 18:49:36 +08:00
22d873f6bd fix(gerror): Fixed serialization failure issue when gerror.Error text field contains quote symbols (#4449)
如果调用internal 下的json.Marshal时 参数如果是gerror.Error 并且 字段中带有符号" 会导致序列化失败
原因是原gerror.Error 的MarshalJson方法只对字符串做了简单的处理 如果err.Error 返回的字符串中有符号"
这个符号会在序列化的时候被认为是字符串的终止导致序列化失败
<img width="854" height="186" alt="image"
src="https://github.com/user-attachments/assets/9a1e6d72-943f-41ad-a487-8a3c0f28f9f0"
/>

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-09-26 16:07:47 +08:00
613
b60b04e27a fix(database/gdb): performance improvement in fields grouping when in… (#4440)
fix https://github.com/gogf/gf/issues/3906

<img width="2604" height="980" alt="image"
src="https://github.com/user-attachments/assets/50852928-7ff5-4676-8ecf-6960c184e805"
/>

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-09-26 11:11:14 +08:00
613
d2bc5d812b fix(cmd/gf): run AddSigHandlerShutdown cannot work well (#4441)
https://github.com/gogf/gf/issues/3752

Sending [Interrupt] on Windows is not implemented.

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-09-23 10:58:24 +08:00
613
0648fd688e fix(cmd/gf): add extra option to controller the behavior downloading … (#4435)
https://github.com/gogf/gf/issues/3938
2025-09-22 17:30:06 +08:00
d0cfcce85b ci: Add CodeQL analysis workflow configuration (#4436) 2025-09-18 17:55:19 +08:00
2518d490c3 ci: Add Scorecard workflow for supply-chain security (#4437) 2025-09-18 17:55:03 +08:00
edc96a8c16 feat(database/gdb): Add the function of obtaining all configurations to facilitate business operations such as verification after addition. (#4389)
…ss operations such as verification after addition.

---------

Signed-off-by: sxp20008 <81209245@qq.com>
Co-authored-by: houseme <housemecn@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: hailaz <739476267@qq.com>
2025-09-18 16:21:02 +08:00
22427a08ad docs(i18n/gi18n): deleting the duplicate package documents (#4251)
Avoid in https://pkg.go.dev/github.com/gogf/gf/v2/i18n/gi18n display
duplicate content.

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-09-05 10:09:45 +08:00
41a5484620 fix(database/gredis): gredis support get raw client (#4306)
Fixes https://github.com/gogf/gf/issues/4298
Fixes https://github.com/gogf/gf/issues/2196
Fixes https://github.com/gogf/gf/issues/2135
```go
import goredis "github.com/redis/go-redis/v9"

func ExampleUsage(ctx context.Context, redis *Redis) error {
	client := redis.Client()
	universalClient, ok := client.(goredis.UniversalClient)
	if !ok {
		return errors.New("failed to assert to UniversalClient")
	}

	// Use universalClient for advanced operations like Pipeline
	pipe := universalClient.Pipeline()
	pipe.Set(ctx, "key1", "value1", 0)
	pipe.Set(ctx, "key2", "value2", 0)
	results, err := pipe.Exec(ctx)
	if err != nil {
		return err
	}
	// ... handle results
	return nil
}
```

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-09-03 16:09:43 +08:00
325ee45a55 fix: update gf cli to v2.9.3 (#4418)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action

Co-authored-by: hailaz <hailaz@users.noreply.github.com>
2025-09-03 12:53:52 +08:00
627aa5d27f fix: Update version to v2.9.3 (#4417)
Change all references from v2.9.2 to v2.9.3 and update the release name
accordingly.
2025-09-03 12:48:06 +08:00
47db44843e fix(os/gtime): fix gtime time string handle logic (#4409)
1、gtime的StrToTime方法优化对时间字段格式兼容处理,并且针对时间越界抛出异常。
2、移除部分无用代码:
<img width="697" height="282" alt="image"
src="https://github.com/user-attachments/assets/92a88140-37c0-4ee1-aef7-c6418e9edd06"
/>

Fixes #4394

---------

Signed-off-by: Zjmainstay <hzgdys@163.com>
Co-authored-by: hailaz <739476267@qq.com>
2025-09-03 12:19:27 +08:00
a39498f74f fix: update gf cli to v2.9.3-rc4 (#4416)
Automated changes by
[create-pull-request](https://github.com/peter-evans/create-pull-request)
GitHub action

Co-authored-by: hailaz <hailaz@users.noreply.github.com>
2025-09-03 11:51:14 +08:00
80b866e11c fix: Update dependencies and exclude test data from go.mod processing (#4415)
Update dependencies and ensure that go.mod files in the test data
directory are excluded from processing during the tag creation for the
CLI tool.
2025-09-03 11:42:44 +08:00
2a77d3203e fix: Improve the typeMap check logic of "gf gen dao" (#4410)
Let it can support such as "Array(UInt256)", "Array(FixedString(25))".
Now we can typeMap as:
"array(uint256)": []big.Int
"array(fixedstring(25))": [25]string
"array(fixedstring)": []string
"array": []any

Now it will first match more precise rules. So it will match
array(uint256) and array(fixedstring(25)) first. Then the
"array(fixedstring)", the last is "array"
2025-09-03 11:16:38 +08:00
3c451bef82 fix: path ./cmd/gf (#4414) 2025-09-03 10:53:50 +08:00
5073f25691 chore: chmod +x update_version.sh (#4413) 2025-09-03 10:36:56 +08:00
40e97f1325 fix: #4269 (#4412)
fixed #4269
2025-09-02 22:49:05 +08:00
502d158bc0 fix: version 2.9.2 (#4405) 2025-09-01 15:33:50 +08:00
f08897a114 chore(tablewriter): upgrade to v1.0.9 and refactor table rendering logic (#4352)
### What’s Changed

* Upgraded `github.com/olekukonko/tablewriter` from previous version to
**v1.0.9**.

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-09-01 12:20:22 +08:00
b6181e4bde fix: report coverage on the latest go version (#4398) 2025-08-29 16:10:37 +08:00
613
f8cdeae2d7 fix(net/goai): fix g.Meta is passed as parameters of a request (#4397)
fix https://github.com/gogf/gf/issues/4247

<img width="2860" height="2308" alt="image"
src="https://github.com/user-attachments/assets/755cfe8a-b3ae-4c5a-ba04-68cc1b188ca7"
/>
2025-08-29 15:30:28 +08:00
bea060af4c feat: update linter config and deprecation notice (#4399)
- Add `gofmt` rewrite-rules to `.golangci.yml` for code formatting
consistency.
- Update deprecation comment in `gpage.go` to specify removal in version
3.0.

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-29 15:26:56 +08:00
94cc233325 fix: disable specific staticcheck rules and update lint config (#4396)
fix: disable specific staticcheck rules and update lint config

- Disabled staticcheck rules SA1029, SA1019, S1000, and related checks
in `.golangci.yml` to filter out unwanted linter errors.
- Updated staticcheck checks list for more precise linting control.
- Clarified configuration for easier maintenance and future updates.

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-29 10:32:30 +08:00
fsl
71743e6903 chore: add OpenSSF Scorecard for README.md (#3696)
Why is this needed:

The OpenSSF Scorecard improves open-source project's security by
providing automated, transparent assessments of their security
practices. It will help you identify vulnerabilities, adhere to best
practices, and continuously enhance your security posture, increasing
user trust and reducing the risk of security exploits.

I'll be the one to create the PR to add the scorecard GitHub action, and
I will also work with you to remediate the identified vulnerabilities.
I'll go through each [scorecard
check](https://github.com/ossf/scorecard/blob/main/docs/checks.md) to
see where the score has dropped and how it can be improved.


Integrate [scorecard](https://github.com/ossf/scorecard) in CI, and
display a Scorecard badge on the gogf repository
You also need to manually create a project, refer to
https://bestpractices.coreinfrastructure.org/en/projects
Manually create an gogf organization to report results, please see
https://sonarcloud.io/explore/projects?sort=-analysis_date

Signed-off-by: fsl <1171313930@qq.com>
2025-08-29 10:28:29 +08:00
f9ec3b19f7 fix(net/ghttp): wrong in-tag param parse for query param (#4227) (#4228)
Fixed issue #4227 and add unit test

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-08-29 09:46:48 +08:00
ee24da4e72 refactor: interface{} to any and reflect.Ptr to reflect.Pointer (#4395)
This pull request standardizes the use of the Go 1.18+ `any` type alias
instead of `interface{}` throughout the codebase. The change improves
code readability and aligns with modern Go best practices. The update
touches many files, including core data structures, code generation
templates, logging utilities, and test data, ensuring consistency across
all usages.

**Type alias migration to `any`:**

* Replaced all instances of `interface{}` with `any` in core data
structures such as `garray` and in generated model structs (e.g.,
`TableUser`, `User1`, `User2`) to modernize type usage.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[3]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[4]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[5]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[6]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
* Updated function signatures, method parameters, and return types from
`interface{}` to `any` in various parts of the codebase, including code
generation, service logic, and logging utilities (e.g., `mlog`).
[[1]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[2]](diffhunk://#diff-2b1953fb78cf3593d8c2c7d911e95b65fd0b847c30ed0b4d167d16fe6d781235L54-R74)
[[3]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[4]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)
[[5]](diffhunk://#diff-c5d51d56f487779a2b6207c7ad26c7a20bbadcc846ce094fe60ab4cabff58c51L107-R107)
[[6]](diffhunk://#diff-f96e6a9fdb416eb1804ceaba1fe0ac637bff22c43837f8bb849c2366ce72d4a1L116-R121)
[[7]](diffhunk://#diff-f94c83a1b08ae060d9346f4a6031fc4a7b9a0b894e02d9afaa09018b6598eac0L112-R112)
[[8]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L36-R36)
[[9]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L74-R74)
[[10]](diffhunk://#diff-748b11dbe8828dd4c040ec23cae0b8fe57ecf0a2d1b7694ea39102294e633c64L96-R96)

**Generated code and templates:**

* Adjusted generated files and code generation templates to output `any`
instead of `interface{}` for relevant struct fields and function
signatures, ensuring that new code generation aligns with the updated
convention.
[[1]](diffhunk://#diff-6c19859cb32c7516ea95ddc8f8235460818eb2f24d2204308e0d9e1b19e7d90fL15-R19)
[[2]](diffhunk://#diff-a15ba2f5e830b4833c47b902515a4f9e5a4f83a3707698f3229b307ec3776b41L15-R18)
[[3]](diffhunk://#diff-52e0837e84d49221d1b810d88fdf78221f36cffcd664fb42f8aba49a79b974dcL15-R19)
[[4]](diffhunk://#diff-11c3457d1a23a4ca6ecd00d6b856289774936b6a708384cf03aff164044e7546L15-R19)
[[5]](diffhunk://#diff-2cff9cf8e6a0cc34087326d8c8149c3bbaf74c76fdbdf5a73daed13cc04249e1L15-R19)
[[6]](diffhunk://#diff-175edfeea54490b8fe4e18ffcbea5835efaf8f0b8acf623359073987cae7eb76L48-R55)
[[7]](diffhunk://#diff-e001b7a4b63603b9b14f00de78a4d570bb76c5f57d856a24643f071032e12356L66-R73)
[[8]](diffhunk://#diff-5582954e8a9983988dc8854ad82067fb2ac6269b988e07357ad8db1dfec5f1a0L39-R41)

**Container and utility updates:**

* Refactored the `garray` container implementation and related
constructors/methods to use `[]any` instead of `[]interface{}`, along
with corresponding function signatures.
[[1]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L31-R31)
[[2]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L52-R52)
[[3]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L62-R62)
[[4]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L73-R86)
[[5]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L96-R97)
[[6]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L107-R114)
[[7]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L124-R124)
[[8]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L135-R143)
[[9]](diffhunk://#diff-3a1259e160a4dfa5fe49dfe739fbdb986c0d0a2220a709882ea48d3ae1b8f911L167-R167)

These changes collectively modernize the codebase and prepare it for
future Go developments by using the idiomatic `any` type.
2025-08-28 16:53:19 +08:00
26f20787ba perf(net/gclient): optimize default http.Transport connection pool configuration (#4390) 2025-08-28 15:08:25 +08:00
1371b3bad5 fix: revert #4388 (#4392) 2025-08-28 13:00:08 +08:00
1da73451b9 fix: spacing in min value validation message (#4388)
Fix spacing in min value validation message
2025-08-27 19:05:55 +08:00
94b623e126 fix: update dependencies to version v2.9.1 for various contrib modules and drivers (#4386)
Fixes #4385
2025-08-27 12:21:38 +08:00
4262aa254d chore(deps): Update dependent versions to enhance compatibility and security (#4380)
#4344

---------

Co-authored-by: houseme <housemecn@gmail.com>
2025-08-23 14:53:49 +08:00
8cff64915b fix(tracing): set database span kind to client (#4334)
In [OpenTelemetry
spec](https://opentelemetry.io/docs/specs/semconv/database/database-spans/),
the span kind of database should be `client`.
2025-08-22 22:49:13 +08:00
bec98e8de0 fix(database/gdb): clickhouse can not support int128/int256/uint128/uint256 (#4370)
When use clickhouse and use field type int128/int256/uint128/uint256. It
can not work well and it will return 0 value.
Add the new field types to let it work well.

By the way, the data struct field need be set to big.Int when use the
types.
2025-08-22 22:05:15 +08:00
a6dbf4b7eb feat: upgrade workflow checkout version v5 (#4381)
feat: upgrade workflow checkout version v5

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-22 21:58:00 +08:00
0c2f60468b chore(deps): bump github.com/redis/go-redis/v9 from 9.7.0 to 9.12.1 in /contrib/nosql/redis (#4215)
Bumps [github.com/redis/go-redis/v9](https://github.com/redis/go-redis)
from 9.7.0 to 9.7.3.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/redis/go-redis/releases">github.com/redis/go-redis/v9's
releases</a>.</em></p>
<blockquote>
<h2>v9.7.3</h2>
<h2>What's Changed</h2>
<ul>
<li>fix: handle network error on SETINFO (<a
href="https://redirect.github.com/redis/go-redis/issues/3295">#3295</a>)
(<a
href="https://github.com/redis/go-redis/security/advisories/GHSA-92cp-5422-2mw7">CVE-2025-29923</a>)</li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/redis/go-redis/compare/v9.7.1...v9.7.3">https://github.com/redis/go-redis/compare/v9.7.1...v9.7.3</a></p>
<h2>v9.7.1</h2>
<h1>Changes</h1>
<ul>
<li>Recognize byte slice for key argument in cluster client hash slot
computation (<a
href="https://redirect.github.com/redis/go-redis/issues/3049">#3049</a>)</li>
<li>fix(search&amp;aggregate):fix error overwrite and typo <a
href="https://redirect.github.com/redis/go-redis/issues/3220">#3220</a>
(<a
href="https://redirect.github.com/redis/go-redis/issues/3224">#3224</a>)</li>
<li>fix: linter configuration (<a
href="https://redirect.github.com/redis/go-redis/issues/3279">#3279</a>)</li>
<li>fix(search): if ft.aggregate use limit when limitoffset is zero (<a
href="https://redirect.github.com/redis/go-redis/issues/3275">#3275</a>)</li>
<li>Reinstate read-only lock on hooks access in dialHook to fix data
race (<a
href="https://redirect.github.com/redis/go-redis/issues/3225">#3225</a>)</li>
<li>fix: flaky ClientKillByFilter test (<a
href="https://redirect.github.com/redis/go-redis/issues/3268">#3268</a>)</li>
<li>chore: fix some comments (<a
href="https://redirect.github.com/redis/go-redis/issues/3226">#3226</a>)</li>
<li>fix(aggregate, search): ft.aggregate bugfixes (<a
href="https://redirect.github.com/redis/go-redis/issues/3263">#3263</a>)</li>
<li>fix: add unstableresp3 to cluster client (<a
href="https://redirect.github.com/redis/go-redis/issues/3266">#3266</a>)</li>
<li>Fix race condition in clusterNodes.Addrs() (<a
href="https://redirect.github.com/redis/go-redis/issues/3219">#3219</a>)</li>
<li>SortByWithCount FTSearchOptions fix (<a
href="https://redirect.github.com/redis/go-redis/issues/3201">#3201</a>)</li>
<li>Eliminate redundant dial mutex causing unbounded connection queue
contention (<a
href="https://redirect.github.com/redis/go-redis/issues/3088">#3088</a>)</li>
<li>Add guidance on unstable RESP3 support for RediSearch commands to
README (<a
href="https://redirect.github.com/redis/go-redis/issues/3177">#3177</a>)</li>
</ul>
<h2>🚀 New Features</h2>
<ul>
<li>Add guidance on unstable RESP3 support for RediSearch commands to
README (<a
href="https://redirect.github.com/redis/go-redis/issues/3177">#3177</a>)</li>
</ul>
<h2>🐛 Bug Fixes</h2>
<ul>
<li>fix(search): if ft.aggregate use limit when limitoffset is zero (<a
href="https://redirect.github.com/redis/go-redis/issues/3275">#3275</a>)</li>
<li>fix: add unstableresp3 to cluster client (<a
href="https://redirect.github.com/redis/go-redis/issues/3266">#3266</a>)</li>
<li>fix(aggregate, search): ft.aggregate bugfixes (<a
href="https://redirect.github.com/redis/go-redis/issues/3263">#3263</a>)</li>
<li>SortByWithCount FTSearchOptions fix (<a
href="https://redirect.github.com/redis/go-redis/issues/3201">#3201</a>)</li>
<li>Recognize byte slice for key argument in cluster client hash slot
computation (<a
href="https://redirect.github.com/redis/go-redis/issues/3049">#3049</a>)</li>
</ul>
<h2>Contributors</h2>
<p>We'd like to thank all the contributors who worked on this
release!</p>
<p><a
href="https://github.com/ofekshenawa"><code>@​ofekshenawa</code></a>, <a
href="https://github.com/Cgol9"><code>@​Cgol9</code></a>, <a
href="https://github.com/LINKIWI"><code>@​LINKIWI</code></a>, <a
href="https://github.com/shawnwgit"><code>@​shawnwgit</code></a>, <a
href="https://github.com/zhuhaicity"><code>@​zhuhaicity</code></a>, <a
href="https://github.com/bitsark"><code>@​bitsark</code></a>, <a
href="https://github.com/vladvildanov"><code>@​vladvildanov</code></a>,
<a href="https://github.com/ndyakov"><code>@​ndyakov</code></a></p>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/redis/go-redis/compare/v9.7.0...v9.7.1">https://github.com/redis/go-redis/compare/v9.7.0...v9.7.1</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="a29d91d9ca"><code>a29d91d</code></a>
release 9.7.3, retract 9.7.2 (<a
href="https://redirect.github.com/redis/go-redis/issues/3314">#3314</a>)</li>
<li><a
href="ce3034c7b3"><code>ce3034c</code></a>
bump version to 9.7.2</li>
<li><a
href="0af2b32f93"><code>0af2b32</code></a>
fix: handle network error on SETINFO (<a
href="https://redirect.github.com/redis/go-redis/issues/3295">#3295</a>)
(CVE-2025-29923)</li>
<li><a
href="3d041a1dd6"><code>3d041a1</code></a>
release: 9.7.1 patch (<a
href="https://redirect.github.com/redis/go-redis/issues/3278">#3278</a>)</li>
<li>See full diff in <a
href="https://github.com/redis/go-redis/compare/v9.7.0...v9.7.3">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/redis/go-redis/v9&package-manager=go_modules&previous-version=9.7.0&new-version=9.7.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)
You can disable automated security fix PRs for this repo from the
[Security Alerts page](https://github.com/gogf/gf/network/alerts).

</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-08-22 17:11:09 +08:00
656ae070da fix(cmd/gf): fix gen sharding dao in multiple shardingPattern tables … (#4379)
fix #4378 
fix #4330

---------

Co-authored-by: hailaz <739476267@qq.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-08-22 16:46:23 +08:00
2d5fcd73cb chore: upgrade dependencies to latest versions and fix security vulne… (#4237)
This PR includes the following updates and fixes:

- **Dependency upgrades**: Updated all dependencies in `go.mod` to their
latest versions to ensure compatibility and leverage the latest features
and fixes.
- **Security fixes**:
- Resolved known vulnerabilities in `golang.org/x/net` by upgrading to
the latest secure version.
- Addressed security issues in `golang.org/x/crypto` by upgrading to the
latest secure version.

These changes improve the overall security and stability of the project.
Please review the changes and ensure compatibility with the updated
dependencies.

---------

Co-authored-by: hailaz <739476267@qq.com>
2025-08-22 15:29:16 +08:00
82043856f4 chore(polaris): Bump github.com/polarismesh/polaris-go from v1.5.8 to v1.6.1 (#4241)
- Updated `github.com/polarismesh/polaris-go` dependency to v1.6.1 in
`go.mod`.
- Ensured compatibility with the latest changes in the Polaris Go SDK.
- Verified that all related functionality works as expected after the
upgrade.
- Resolved any potential breaking changes introduced in the new version.

This upgrade includes performance improvements, bug fixes, and new
features provided by the Polaris Go SDK.
2025-08-22 15:07:34 +08:00
7ffdff37e4 chore: upgrade golangci-lint configuration and optimize codebase (#4236)
This PR includes the following changes:

- **Upgrade `.golangci.yml`**: Updated the configuration file to align
with the latest golangci-lint version, ensuring compatibility and
leveraging new features.
- **Refactor GitHub Action workflow**: Modified `golangci-lint.yml` in
the GitHub Actions workflow to reflect the updated configuration and
improve CI performance.
- **Codebase optimization**: Refactored code to address issues and
warnings raised by the updated golangci-lint rules, including:
  - Improved function length and complexity.
  - Enhanced error handling and variable naming conventions.
- Fixed minor issues such as unused imports and formatting
inconsistencies.

These changes aim to maintain code quality, ensure compatibility with
the latest tools, and improve overall maintainability.
2025-08-22 13:29:09 +08:00
613
24083b865d fix(internal/utils): fix +.1 is pass checks numeric (#4374) 2025-08-21 15:44:26 +08:00
8cb64c9f88 fix(cmd/gf): "unknown time zone" when using "gf gen dao" for clickhouse on windows platform (#4368)
fix bug: could not load time location: "unknown time zone Asia/Shanghai"

The bug will appear when I use gf in windows to do "gf gen dao" for
clickhouse.
2025-08-15 13:35:59 +08:00
5fa656d1cc fix(os/gtime): add handling for nil time pointers to avoid causing panic (#4323)
from https://github.com/gogf/gf/pull/4322
Fixes https://github.com/gogf/gf/issues/4307
2025-06-24 15:53:47 +08:00
09ec90746a chore: bump golang.org/x/tools to v0.34.0 for Go 1.25 compatibility (#4313)
chore: bump golang.org/x/tools to v0.34.0 for Go 1.25 compatibility

```
   # golang.org/x/tools/internal/tokeninternal
  /Users/brew/Library/Caches/Homebrew/go_mod_cache/pkg/mod/golang.org/x/tools@v0.21.1-0.20240508182429-e35e4ccd0d2d/internal/tokeninternal/tokeninternal.go:64:9: invalid array length -delta * delta (constant -256 of type int64)
```

relates to https://github.com/Homebrew/homebrew-core/pull/226636
2025-06-20 21:21:03 +08:00
c0d1e44526 fix(database/gdb): support multiple order fields in gdb_model_with and merged #4272 fix scanning functionality for deep slice types (#4320)
Fix:#4311
Merged: #4272
2025-06-20 21:09:41 +08:00
b323862b4c Merge pull request #1 from fainc/master
Update util/gconv/gconv_z_unit_scan_test.go
2025-06-20 19:23:04 +08:00
3d9cdb8997 fix(gdb): support multiple order fields in "with" 2025-06-20 19:11:01 +08:00
7180d895ea Update util/gconv/gconv_z_unit_scan_test.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-20 18:17:40 +08:00
afb1595fbe Merge branch 'gogf:master' into master 2025-06-20 18:07:15 +08:00
6637add9ca fix(net/ghttp): improve GetMetaTag method to handle nil and type checks (#4284)
修复没有做handler参数数量判断导致可能出现的数组越界问题
2025-06-19 09:43:24 +08:00
bc862cf97b chore: bump golang.org/x/tools to v0.34.0 for Go 1.25 compatibility
Signed-off-by: Rui Chen <rui@chenrui.dev>
2025-06-14 13:34:25 -04:00
9033ca087b fix(net/ghttp): improve GetMetaTag method to handle nil and type checks 2025-05-16 17:55:00 +08:00
b985fd978c Merge branch 'master' into master 2025-05-07 20:02:12 +08:00
88c4471500 fix(ci): change base image from expired ubuntu-22.04 to ubuntu-latest (#4273) 2025-05-07 19:06:00 +08:00
b73e2047db fix(gconv): fix scanning functionality for deep slice types 2025-05-06 13:37:45 +08:00
1534abdb05 feat(util/gpage): marked deprecated (#4230) 2025-04-02 19:56:28 +08:00
fee38b4531 feat(net/ghttp): enhance GetHeader method to support default values (#4210) 2025-03-25 20:42:30 +08:00
69e3362d0d feat: new version v2.9.0 (#4204) 2025-03-17 15:52:26 +08:00
9a61a6970f fix(database/gdb): fix transaction propagation feature (#4199) 2025-03-17 14:50:07 +08:00
abf77fac50 fix(cmd/gf): invalid binary suffix after installing binary using custom renamed file name that has suffix with . character (#4207) 2025-03-17 13:48:54 +08:00
07696fc779 feat(net/ghttp): add GetMetaTag function to retrieve metadata value for HandlerItem (#4206) 2025-03-17 09:21:00 +08:00
bc1e1019c5 refract(util/gconv): change Converter interface definition for more convenient usage (#4202) 2025-03-14 18:23:07 +08:00
bb696bb281 refract(net/ghttp): move Request.GetMetaTag to HandlerItemParsed.GetMetaTag (#4191) 2025-03-12 21:55:35 +08:00
029f324c5c feat: version v2.9.0-beta (#4189) 2025-03-09 22:31:20 +08:00
f8331bad6e feat(net/ghttp): add Request.GetMetaTag to retrieve specific meta tag value (#4185) 2025-03-09 11:17:41 +08:00
bcda48bf82 fix(net/ghttp):check parameter existence to determine using default or front-end value. (#4182) 2025-03-08 20:56:27 +08:00
a8a055f122 fix(util/gvalid): lots of memory consumed when required validation on big binary field (#4097) 2025-03-07 13:52:12 +08:00
dfe088f5cd refactor(util/gconv): add Converter feature for more flexable and extensible type converting (#4107) 2025-03-06 23:04:26 +08:00
f4074cd815 fix(net/gclient): remove default discovery for gclient when Discovery feature enabled (#4174) 2025-03-03 16:43:21 +08:00
4a65e7a629 feat: v2.9.0 (#4057) 2025-02-27 15:53:19 +08:00
ac653d3dee Merge branch 'master' into feat/v2.9.0 2025-02-27 14:36:05 +08:00
2d3ab4f9fb feat: add submodule examples (#4137) 2025-02-27 14:35:00 +08:00
bda42d18ee feat(cmd/gf): add controller comment support for command gf gen ctrl (#4169) 2025-02-27 14:21:40 +08:00
63cb3285f8 fix(net/ghttp): update response message handling in MiddlewareHandlerResponse (#4162) 2025-02-27 11:59:26 +08:00
2fa03556ef chore(util/gvalid): using 64 instead of 10 bitsize parameter for function strconv.ParseFloat although it treats 10 as 64 internally (#4154) 2025-02-20 16:32:01 +08:00
01593ad8b6 fix(ci): golangci-lint failed after upgrading go version to 1.24 (#4158) 2025-02-14 22:24:18 +08:00
42d8845d35 feat(cmd/gf): add gopackage option for command gf gen pbentity to specify go_package for generated proto files (#4141) 2025-02-14 13:39:13 +08:00
1ef1c442d3 test(os/gproc): add unit test for os/gproc (#4140) 2025-02-14 13:36:17 +08:00
7d3b055d3e fix(net/ghttp): MakeBodyRepeatableRead takes not effective when called after ParseForm (#4143) 2025-02-11 18:02:26 +08:00
a3b3c656d9 feat(database/gdb): enable transaction propagation when using tx.GetCtx() after Begin (#4121) 2025-02-11 16:09:27 +08:00
0eb229a887 feat(os/glog): add default time format 2006-01-02T15:04:05.000Z07:00 (#4134) 2025-02-11 15:59:27 +08:00
20b1987828 feat(test/gtest): add map type support for AssertNI/AssertIN (#4135) 2025-01-23 17:58:32 +08:00
e12768207e feat(cmd/gf): beautify progress bar of cli binary downloading for command gf up (#4094) 2025-01-22 19:22:36 +08:00
f9c7eae23b fix(net/ghttp): remove unused code snippet (#4131) 2025-01-22 19:22:02 +08:00
1f8845291a fix(contrib/config/polaris): it only supports json format for configuration contents, add more content formats support (#4126) 2025-01-22 19:20:21 +08:00
6bd15b0796 merge master 2025-01-22 19:17:16 +08:00
99f0fb14a1 fix(net/ghttp): BufferWriter.Flush writes additional information after custom response wrote (#4116) 2025-01-22 09:28:06 +08:00
e0f734851e fix(net/ghttp): MiddlewareHandlerResponse writes additional information after custom response wrote (#4109) 2025-01-14 09:28:19 +08:00
3f24b4da2e feat(os/gcmd): add default value display for an argument (#4083) 2025-01-13 09:26:59 +08:00
fc9093a1aa feat(cmd/gf): add ShardingPattern option for command gf gen dao to support generating dao files sharding tables (#4081) 2024-12-26 23:21:03 +08:00
Gin
f66e09717c feat(contrib/metric/otelmetric): add metrics option WithExemplarFilter support (#4061) 2024-12-26 18:30:21 +08:00
80f57d1c24 fix(database/gdb): gdb.Counter not work in OnDuplicate (#4073) 2024-12-26 18:18:35 +08:00
9ce2409659 fix(util/gpage): html.EscapeString for pagination HTML generation and URL parsing (#4079) 2024-12-26 16:21:30 +08:00
6ea1526b75 fix(ci/golangci): fix golangcl-lint git push and apply format code on Push (#4077) 2024-12-26 10:19:01 +08:00
89e5285d95 feat(net/ghttp): move plugin remove logic to Shutdown() && call Shutdown() when Run() exits (#4072) 2024-12-26 10:18:47 +08:00
e6bee78be4 Apply gci import order changes 2024-12-26 02:18:19 +00:00
96e833db6e feat(gf/gen/pbentity): add a TablesEx configuration to exclude the specified table names (#4060) 2024-12-26 10:17:51 +08:00
3a19ee9268 fix: securiry update CVE-2024-45338 for package golang.org/x/net (#4070) 2024-12-25 21:43:55 +08:00
594979c5af fix(net/ghttp): nil pointer panic error when server logger set nil (#4055) 2024-12-19 22:31:17 +08:00
4c2a78b7bf fix(database/gdb): regular expression pattern for link configuration to be compitable with tidbcloud (#4064) 2024-12-19 21:44:36 +08:00
817ac36ce2 ci: use latest go version for unit testing cases of contribution components (#4062) 2024-12-19 10:11:55 +08:00
2c1fcec88c Merge branch 'feat/v2.9.0' of github.com:gogf/gf into feat/v2.9.0 2024-12-18 20:48:05 +08:00
92eab81926 fix(database/gdb): add compatibility for old configiration with both Type and part of Link configurations (#4058) 2024-12-18 15:54:27 +08:00
a5c8b966e2 feat(util/gconv): add basic types conversion support for function Scan (#3991) 2024-12-18 10:41:09 +08:00
233295be07 fix(os/gview): search file faild from resource manager of package gres (#4024) 2024-12-18 10:39:01 +08:00
67a9db9e3e perf(contrib/drivers/pgsql): improve conversion performace for slice string (#4046) 2024-12-17 21:45:38 +08:00
e7fdf82dd8 test(net/gipv4): add unit tests (#4052) 2024-12-17 21:17:27 +08:00
f79aef6669 fix(database/gdb): fix context canceled error in transaction due to usage of TransTimeout configuration (#4037) 2024-12-17 21:15:54 +08:00
0c2d5cac19 feat: new version v2.8.3 (#4048) 2024-12-17 09:24:13 +08:00
5104f01b69 chore: update FUNDING.yml (#4049) 2024-12-17 09:23:59 +08:00
a09454accf feat(contrib/drivers/mssql): enable unit testing (#4043) 2024-12-16 11:17:47 +08:00
ac53170884 feat(contrib/registry/etcd): add retry machenism when keepalive lease expires (#4035) 2024-12-13 11:09:07 +08:00
e3e82c7351 feat(contrib/config/nacos): add OnChange callbacks configuration support (#4038) 2024-12-13 09:57:28 +08:00
ced4b57991 fix(contrib/drivers/pgsql): incompatible placeholder replacement with old version (#4036) 2024-12-13 09:29:34 +08:00
5af342adc3 fix(net/ghttp): json omitempty takes no effect in BuildParams, which is not compatible with old version (#4041) 2024-12-13 09:29:19 +08:00
5c45d3533f fix(ci/golangci): fix golangcl-lint git push (#4032) 2024-12-11 15:42:36 +08:00
d748fb6564 fix(contrib/registry/consul): update dependence of gf to v2.8.2 with relative path specified (#4029) 2024-12-11 10:28:29 +08:00
00e2f6b5dc chore: improve golangci-lint.yml, upgrade dependencies, and optimize code and comments (#4025) 2024-12-11 10:14:12 +08:00
b7c74c9a35 fix(contrib/drivers/pgsql): add unix socket connection support (#4028) 2024-12-11 09:58:26 +08:00
69969b1723 fix(contrib/registry/etcd): remove default configuration of AutoSyncInterval (#4027) 2024-12-10 20:59:44 +08:00
38bffc77e2 fix(net/ghttp): occasional ci failed by unit testing cases using gctp.GetFreePort (#3982) 2024-12-10 09:52:48 +08:00
2e788be1d3 feat(contrib/registry/consul): add consul registry support (#4016) 2024-12-09 23:12:29 +08:00
13bc192e36 feat(database/gdb): add sharding feature for schema and table (#4014) 2024-12-09 23:12:20 +08:00
bae78fbf5b feat(net/ghttp): add middleware MiddlewareGzip for compressing response content using gzip (#4008) 2024-12-09 23:12:09 +08:00
80e73da416 feat(errors/gerror): add As support (#4002) 2024-12-09 23:11:56 +08:00
5e47590165 feat(database/gdb): add WhereExists/WhereNotExists (#4015) 2024-12-09 09:24:48 +08:00
3cffa4d5d6 fix(database/gdb): CRUD typos (#4017) 2024-12-09 09:22:52 +08:00
e18331aa2c docs(cmd/gen): improve comments for command gen dao (#4007) 2024-12-07 14:19:36 +08:00
b0b84a3937 ci(gci/import): improve golangci.yml and add gci linter (#4010) 2024-12-07 14:17:33 +08:00
2066aa4803 feat(database/gdb): add transaction propagation&isolation level&readonly features (#4013) 2024-12-07 14:01:31 +08:00
b8142bf1fc feat(os/gsession): add RegenerateId/MustRegenerateId support (#4012) 2024-12-06 14:16:03 +08:00
ba968949f7 fix(database/gdb): orm tag from embedded struct is missing in with feature (#4011) 2024-12-05 22:02:47 +08:00
c9b0237fc7 feat: version v2.8.2 (#4009) 2024-12-05 20:21:19 +08:00
4ad061faff feat(contrib/drivers/pgsql): add array type varchar[] and text[] converting to Go []string support (#4000) 2024-12-05 15:50:59 +08:00
5fa33411fc chore: add example for openapi/swagger authentication (#4004) 2024-12-05 15:49:50 +08:00
c0f2ef7348 feat(gctx): rename and remove gctx functions to prevent ambiguity (#3892) 2024-12-05 14:47:39 +08:00
77cb7fb412 test(drivers/mssql): add unit testing cases of transaction (#3818) 2024-12-05 14:44:40 +08:00
7cd672d22c feat(cmd/gf): add interface functions generating for embedded struct of logic struct in command gen service (#3802) 2024-12-05 14:44:21 +08:00
e2cafa35e0 fix(cmd/gf): custom tags repeatedly added using command gf gen pb with -a option (#3966) 2024-12-05 14:42:30 +08:00
532e665841 fix(database/gdb): move Raw parameter from args to sql statement before committed to db driver (#3997) 2024-12-03 15:24:49 +08:00
2d0cd7b770 refactor(cmd/gf): change default src value to api, path to internal/packed/packed_enums.go for command gen enums (#3996) 2024-12-02 21:39:04 +08:00
2c916f8222 fix(database/gdb): issue where the Count/Value/Array query logic was incompatible with the old version when users extended the returned result fields using the Select Hook (#3995) 2024-12-01 23:47:51 +08:00
42eae41599 fix(util/gutil): code scanning alert no. 17: Potentially unsafe quoting (#3993) 2024-12-01 23:44:48 +08:00
5aa7504bb2 fix(util/gpage): code scanning alert no. 9: Potentially unsafe quoting (#3992) 2024-12-01 23:43:44 +08:00
ec6e091882 chore: fix some function names in comment (#3967) 2024-12-01 11:29:09 +08:00
c1850d4ab5 feat(net/goai): support OpenAPIv3.1 in description field for schema object (#3978) 2024-12-01 11:27:35 +08:00
9923975b1c feat(net/gipv4): add enhanced the conversion between uint32 and string (#3988) 2024-12-01 10:16:03 +08:00
e572ed01b3 fix(net/ghttp): get origin through referer (#3990) 2024-12-01 10:05:46 +08:00
16d73b5bdf fix(utils/gvalid): missing pkg path for enums pointer (#3983) 2024-11-29 18:25:13 +08:00
5521d768ff feat(cmd/gf): add typeMapping and fieldMapping feature support for command gf gen genpbentity (#3970) 2024-11-27 21:09:42 +08:00
81aed06643 feat: README updates (#3974) 2024-11-27 21:03:31 +08:00
455830b842 test(database/gdb): add more unit testing cases for Raw feature (#3962) 2024-11-23 18:35:02 +08:00
e56371e7c9 fix(cmd/gf): incorrect environment variables printing before cli does some environment changes (#3961) 2024-11-23 17:54:20 +08:00
eb8024913d feat(net/goai): add min, max, length, min-length, max-length and between support for OpenAPIv3 (#3914) 2024-11-23 15:38:52 +08:00
ee3eb8d48c fix(net/goai): embedded struct with tags also expand as properties of the parent struct (#3956) 2024-11-23 15:38:14 +08:00
15f94975db feat(net/goai): add enhanced response status interface (#3896) 2024-11-23 15:37:46 +08:00
3797d0eee4 feat: new version v2.8.1 (#3950) 2024-11-21 20:51:46 +08:00
e9ce1bde87 fix(database/gdb): incompatitable statement like Order("id", "dasc") (#3949) 2024-11-21 15:08:29 +08:00
9c8b21af7b fix(cmd/gf): incorrect make command in project template (#3946) 2024-11-20 21:47:32 +08:00
90851881cc fix(registry/zookeeper): watch service name path error with extra suffix - (#3948) 2024-11-20 20:39:05 +08:00
3090fe7f4e fix(database/gdb): recognize tinyint(1)/int(1) as bool (#3943) 2024-11-20 20:21:33 +08:00
0d1aed0741 fix(os/gcache): function Remove returns value not *gvar.Var as previous version (#3936) 2024-11-19 23:30:29 +08:00
910703ec3a chore(database/gdb): comment update for function Model.Order (#3933) 2024-11-18 18:33:59 +08:00
ec6c537def feat(cmd/gf): project template updates for command gf init (#3928) 2024-11-17 10:57:17 +08:00
bcfcda793c chore(errors/gerror): add examples (#3927) 2024-11-16 18:14:40 +08:00
138dea0f3a feat(cmd/gf): change document source from repo gf to gf-site (#3926) 2024-11-15 14:33:23 +08:00
3d4904eb3d feat(net/ghttp): remove Req/Res suffix limitation for input/output parameters of strict router handler (#3848) 2024-11-14 17:58:39 +08:00
955a76cf35 feat: new version v2.8.0 (#3924) 2024-11-14 13:26:23 +08:00
ffa6081471 fix(util/gconv): fix missing minus in string to int64 conversion (#3920) 2024-11-13 23:25:24 +08:00
6baf4338b0 fix(database/gdb): recognize field type tinyint(1) to golang type bool (#3921) 2024-11-13 23:09:01 +08:00
8c6db247b2 chore: readme updates (#3919) 2024-11-13 20:48:02 +08:00
fff2f8a24c build: downgrade fsnotify from v1.8.0 to v1.7.0 to solve data race error (#3916) 2024-11-13 12:22:23 +08:00
475e8bbae0 chore: README.md updates (#3912) 2024-11-12 21:30:46 +08:00
070efecc6e style(gtest/test): improve code (#3891) 2024-11-12 20:20:13 +08:00
a63af5d5f8 build: upgrade fsnotify from v1.7.0 to v1.8.0 to solve occasional ci failure (#3910) 2024-11-12 10:25:39 +08:00
bd2e8408e8 chore: update README.MD (#3911) 2024-11-12 09:25:37 +08:00
6c6fd7902a feat(database/gdb): remove unnecessary blank character requirement in tag for With feature of gdb.Model (#3875) 2024-11-11 21:59:26 +08:00
1b7b536d6c fix(cmd/gf): protoc file comments contain backticks and double quotes, resulting in syntax errors in the generated file of go (#3890) 2024-11-11 21:37:30 +08:00
9cc1cf1b53 fix(cmd/gf): remove dir after process done if given build file parameter is not a file but a dir name (#3908) 2024-11-11 21:32:58 +08:00
76948d93d6 test(drivers/mysql): use asserts function to replace if statement (#3849) 2024-11-11 20:54:57 +08:00
5ba165a3c0 fix(cmd/gf): go back current working directory after gf gen pb (#3895) 2024-11-11 20:42:25 +08:00
f4db846633 fix(contrib/drivers/pgsql): connection fails when postgres database password is empty (#3900) 2024-11-11 20:27:07 +08:00
e7cc2c3d9c chore: update the contributors in README.MD (#3907) 2024-11-06 22:11:23 +08:00
01cd0103e4 fix(net/gclient): Client Clone with allocated header/cookie (#3902) 2024-11-06 22:09:28 +08:00
d1872f17f7 fix(util/gconv): assigned the same value to struct field and its same name field in embedded struct failed (#3905) 2024-11-06 21:12:01 +08:00
e4c4fb591e feat(database/gdb): add Exist support for checking records existance for certain condition (#3854) 2024-10-24 15:29:03 +08:00
656668f444 feat: new version v2.8.0-beta (#3878) 2024-10-24 14:51:03 +08:00
555bb3fa6b feat(net/goai): enhance openapi doc with responses and examples (#3859) 2024-10-21 21:16:45 +08:00
e179e1d4fe fix(database/gdb): unix socket connection support for mysql (#3872) 2024-10-21 09:22:53 +08:00
7dd38a1700 feat(database/gdb): add Raw support for Fields function of gdb.Model (#3873) 2024-10-21 09:22:31 +08:00
b1d875a31f fix(util/gconv): incorrect fuzzy converting logic (#3874) 2024-10-21 09:16:50 +08:00
c18339b1a9 feat(contrib/drivers/pgsql): add InsertIgnore support (#3855) 2024-10-16 07:32:33 +08:00
5288b70567 fix(util/gconv): one parameter to same tag in multiple struct attributes mapping failed (#3822) 2024-10-14 21:34:39 +08:00
4b5f637651 feat(trace): add trace for Custom trace client and provider (#3847) 2024-10-14 21:30:27 +08:00
e3e5c89ba7 fix(os/gcmd): cannot retrieve all args if no subcommand defined for a root command (#3850) 2024-10-10 09:17:34 +08:00
4d29939f87 fix(net/goai): cannot customize OpenAPIv3 type for request parameters (#3845) 2024-10-09 13:15:46 +08:00
ae3ae8b177 test(cmd/gf): add unit testing case generating dao/do/entity files for sqlite in command gen dao (#3808) 2024-10-08 22:06:07 +08:00
7a6889817f feat(encoding/ghtml): add parameter validation for function SpecialCharsMapOrStruct (#3841) 2024-10-08 20:46:06 +08:00
a72a9ff13e fix(container/gtree): deadlock in Map/MapStrAny functions, comments update (#3840) 2024-10-08 20:45:23 +08:00
91884e7c93 fix(database/gdb): remove support of Array/Value/Count operations for result that has multiple record fields (#3839) 2024-10-08 20:42:06 +08:00
7cbc9e8533 test(os/gcache): fix unit testing occasionally failed due to too short expration duration set (#3842) 2024-10-08 13:06:11 +08:00
2301de6e8c fix(util/gutil): invalid empty parameter value check for function GetOrDefaultAny (#3844) 2024-10-08 13:05:59 +08:00
183395f0a0 fix(cmd/gf): gen service error when there's version number at the end of package import path (#3836) 2024-10-05 12:25:43 +08:00
d4fa2c82bf feat(contrib/rpc/grpcx): use grpc.NewClient instead of grpc.Dial (#3684) 2024-09-30 20:41:14 +08:00
459c8ce84e feat(os/gfsnotify): add recursive watching for created subfolders and sub-files under folders that already watched (#3830) 2024-09-30 11:24:27 +08:00
38622f966f refactor(contrib/trace/jaeger): remove trace jaeger, please use the OpenTelemetry SDKs(otlphttp&otlpgrpc) (#3825) 2024-09-29 20:31:16 +08:00
499f755d3a build(deps): bump google.golang.org/grpc from 1.51.0 to 1.56.3 in /contrib/config/polaris (#3831) 2024-09-29 17:06:02 +08:00
3f1439ac4c build(deps): bump google.golang.org/grpc from 1.51.0 to 1.56.3 in /contrib/registry/polaris (#3828) 2024-09-29 15:48:28 +08:00
0ca2ed5979 chore(contrib/config/polaris): upgrade dependent polaris library version to v1.5.8 and go version to v1.21 (#3827) 2024-09-29 11:08:07 +08:00
ee5284a1b2 chore(contrib/registry/polaris): upgrade dependent polaris library version to v1.5.8 and go version v1.21 (#3826) 2024-09-29 10:59:48 +08:00
8e7f1180c4 fix(contrib/drivers/mssql): fix mssql paging sql generate statement error (#3782) 2024-09-29 10:18:34 +08:00
3abb9477c4 ci: fix mssql docker service starting failed (#3824) 2024-09-28 21:46:23 +08:00
ab3fbddfc7 build(go.mod): upgrade minimum required go version from 1.18 to 1.20 (#3688) 2024-09-28 20:58:04 +08:00
55b92151f4 refactor(net/ghttp): enhance ghttp.StartPProfServer (#3555) 2024-09-28 18:10:53 +08:00
9589384b36 refactor(encoding/gjson): change data parameter from type any to []byte (#3542) 2024-09-28 18:10:00 +08:00
cf742233e8 refactor(net/gudp): improve implements (#3491) 2024-09-28 18:08:46 +08:00
1c97b7a982 fix(os/gcache): memory leak for LRU when adding operations more faster than deleting (#3823) 2024-09-28 18:07:11 +08:00
ea09457d84 fix(os/gcmd): argument index calculating error in multilevel command (#3807) 2024-09-28 18:02:34 +08:00
66ee52c96a fix(database/gdb): invalid order by statement generated when multiple order inputs (#3803) 2024-09-28 12:06:22 +08:00
f45f64897a fix(cmd/gf): creating logic.go empty folder when there is no correct logic service (#3815) 2024-09-28 11:28:06 +08:00
8708dc7940 test(drivers/mysql): loose unit testing for transaction (#3819) 2024-09-28 11:19:14 +08:00
79451e4624 fix(net/ghttp&gclient,contrib/rpc/grpcx): remove request and response contents in opentelemetry tracing attributes (#3810) 2024-09-26 09:50:07 +08:00
a716c6bfab feat: new version v2.7.4 (#3809) 2024-09-25 19:53:23 +08:00
5aa321dbde fix(util/gconv): unstable converting when there is an external attribute with the same name as the internal structure (#3799) 2024-09-25 19:22:15 +08:00
3f2b1cb329 feat(database/gdb): add year field type support for ORM operations (#3805) 2024-09-25 16:33:52 +08:00
ab2c3b02ac fix(cmd/gf): table and field names converted to its lower case before CamelCase converting in command gen dao (#3801) 2024-09-25 10:59:00 +08:00
76783fd72b fix(net/gclient): panic when containing @file: parameter value in json post request (#3775) 2024-09-25 10:37:32 +08:00
fsl
a1ce97ec9b feat(contrib/registry/etcd/): add DialTimeout and AutoSyncInterval option (#3698) 2024-09-24 17:01:10 +08:00
c13004e230 fix(database/gdb): support OrderRandom feature in different databases (#3794) 2024-09-24 11:58:34 +08:00
9af8393758 fix(net/goai): change default value of RequestBody.Required from true to false, add required tag support for RequestBody (#3796) 2024-09-24 11:51:53 +08:00
e15b543a5b fix(util/gvalid): retrive empty slice parameter in custom validation rule function failed (#3795) 2024-09-23 19:59:48 +08:00
8a1c97f518 fix(util/gconv): cached field indexes append issue caused incorrect field converting (#3790) 2024-09-23 19:05:32 +08:00
d8e3e9d713 fix(utils/utils_str): recognize '+' as a valid numeric sign (#3778) 2024-09-23 16:45:55 +08:00
777c2e7117 ci: fix mssql docker service failed in ci (#3792) 2024-09-23 11:50:48 +08:00
c4327f62e7 fix(net/ghttp): server shutdown not graceful using admin api /debug/admin/shutdown (#3777) 2024-09-19 14:10:16 +08:00
fd33dcb97b ci: add go version 1.23 support (#3733) 2024-09-19 10:38:20 +08:00
d8b06d056e fix(os/gcache): a little memory leak for removed timestamp key (#3779) 2024-09-14 11:05:47 +08:00
e186eab1a5 fix(debug/gdebug): incorrect package name handling in function CallerPackage (#3771) 2024-09-13 16:51:39 +08:00
6a99931798 fix(database/gdb): #3755 error parsing database link without port number (#3772) 2024-09-13 16:50:59 +08:00
4ee5bf5c45 fix(database/gdb): #3754 FieldsEx feature conflicts with soft time feature in soft time fields updating (#3773) 2024-09-13 16:50:38 +08:00
e4669387b5 fix(encoding/gxml): XML special character encoding error (#3740) 2024-09-13 10:37:15 +08:00
0e471eab38 fix(util/gconv): #3764 fix bool converting issue (#3765) 2024-09-12 21:59:38 +08:00
3d63ebfe81 fix(net/ghttp): skip common response body in common response handler for streaming content types (#3762) 2024-09-12 17:50:43 +08:00
9b318bb57f perf(database/gdb): performance improvement for struct scanning when with feature disabled (#3677) 2024-09-12 15:38:18 +08:00
6b3fb607cf fix(net/goai): fix openapi miss required tag of BizRequest when set CommonRequest (#3724) 2024-09-10 18:00:21 +08:00
bb9a3b83eb feat(database/gdb): add time field type for value converting for/from field (#3712) 2024-09-10 17:51:22 +08:00
baea1c7a7a feat: version v2.7.3 (#3763) 2024-09-09 16:39:02 +08:00
1b4ebc0812 perf(util/gconv): add cache logic to enhance performance (#3673) 2024-09-09 16:17:01 +08:00
803cb5a0bc fix(contrib/drivers/pgsql): fix insert error when data struct field has nil in PgSQL (#3679) 2024-09-09 16:16:20 +08:00
448df14860 fix(util/gconv): #3731 map type name mismatch in switch case statement (#3732) 2024-09-09 14:54:40 +08:00
467a5c1093 fix(contrib/drivers/pgsql): #3671 fix invalid pgsql insert json type (#3742) 2024-09-09 14:32:14 +08:00
26d2a98fb1 refactor(nacos-registry): use official nacos sdk instead of the third-party nacos sdk (#3745) 2024-09-09 14:27:21 +08:00
6e5ce98d23 fix(database/gdb): fix #3649 when constructing query param, gdb.Row value not directly write to Buffer (#3718) 2024-08-14 21:16:17 +08:00
a6c361dcf7 fix(os/gtime): fix gtime.Value() when time only, add time only example (#3714) 2024-08-14 21:00:39 +08:00
dc8bb809a8 fix(contrib/registry/file/v2): fix the panic caused by channel closing after resolver closed (#3691) 2024-08-14 20:44:05 +08:00
9143b26182 fix(contrib/nosql/redis): missing err nil check in function ScriptExists (#3713) 2024-07-29 20:32:59 +08:00
fsl
cd2d51ea30 build: bump google.golang.org/protobuf to v1.33.0 (#3697) 2024-07-24 19:27:28 +08:00
fsl
144ad5f263 ci: add Scorecard workflow (#3702) 2024-07-24 19:24:14 +08:00
4fdafa4517 feat(cmd/gf): project templates update for command gf init (#3704) 2024-07-24 19:15:54 +08:00
ba322ba0ac fix(cmd/gf): fix command gf up with -u option upgrading packages indirectly required would fail with higher version of go required (#3687) 2024-07-17 20:21:26 +08:00
559ae0e77e chore(.github/template): update document for github pull requests (#3666) 2024-07-02 20:56:20 +08:00
3e54839aa8 refractor(container/gtree): refactor code with gods package for rbtree (#3655) 2024-07-02 20:36:43 +08:00
2565bb3d07 refractor(container/gtree): improve function order of btree (#3656) 2024-07-02 20:35:53 +08:00
54423b6d84 refractor(container/gtree): refactor code with gods package for avltree (#3647) 2024-07-01 20:37:11 +08:00
c3cfc01cf6 refactor(container/gring): mark deprecated, package container/gring will not be maintained in future (#3665) 2024-06-27 21:12:51 +08:00
31a6ae2a19 fix(cmd/gf): remove dm driver for command gen dao as it causes building failed for some platforms (#3667) 2024-06-27 21:12:06 +08:00
b11caba5b0 version v2.7.2 (#3663) 2024-06-26 10:08:04 +08:00
8824b8b0fe os/gcron: add graceful shutdown support (#3625) 2024-06-25 21:13:51 +08:00
f8272bc5f4 database/gdb: remove duplicated SQL records in tracing events (#3659) 2024-06-25 21:11:36 +08:00
e8a2629b19 net/goai: fix: #3660, support multiple file upload parameters for OpenAPIv3 (#3662) 2024-06-25 21:01:58 +08:00
dba6c08548 net/ghttp: fix Content-Type for jsonp response from application/json to application/javascript (#3651) 2024-06-24 21:37:49 +08:00
7d464d4de2 net/ghttp: fix args issue for forkRestartProcess in graceful restarting of ghttp.Server (#3661) 2024-06-24 20:53:37 +08:00
4abb32e11b contrib/drivers/pgsql: support slice type to insert into array for pgsql (#3645) 2024-06-18 19:36:07 +08:00
74d0945fa1 gerror: fix #3633 Is performs the same as errors.Is from go stdlib (#3640) 2024-06-13 21:55:32 +08:00
ffbe9a7197 container/gtree: refactor code with gods package (#3595) 2024-06-13 21:26:53 +08:00
fba878f47a net/ghttp: update error message for duplicated routes registering (#3603) 2024-06-13 21:16:11 +08:00
88f188d0f9 cmd/gf: use automatic generating package names for go files of dao/do/entity instead of constant package names (#3639) 2024-06-13 21:13:05 +08:00
2ccbb02c71 fix: #3613 ignore automatic handling for creating/updating time if it has been specified (#3615) 2024-06-12 21:41:44 +08:00
01408f1a87 cmd/gf: delete binary file when gf run end process (#3628) 2024-06-12 21:32:24 +08:00
dea0ffcfb3 cmd/gf: add command gf doc (#3634) 2024-06-12 21:29:56 +08:00
d5825ab51c drivers/pgsql:pgsql returning id should use quotation marks,when primary key is capital (#3638) 2024-06-12 21:22:39 +08:00
753965b9a9 example: password encrypt-decrypt for database using custom implement driver (#3610) 2024-06-04 22:04:36 +08:00
ee211dbdac cmd/gf: improve gf gen ctrl using ast (#3616) 2024-06-04 21:13:23 +08:00
4d916ae73e os/gres: fix #3611 add custom prefix / support for resource packing (#3621) 2024-06-04 20:38:59 +08:00
59a775aad4 util/gvalid: add 171 number support for virtual phone number validation (#3622) 2024-06-04 20:36:28 +08:00
e3a00d7f56 cmd/gf: fix missing configuration file support for cli command pack/run/tpl/up (#3629) 2024-06-04 19:59:05 +08:00
bd8d046b83 cmd/gf: add DaMeng database driver support (#3606) 2024-05-30 21:20:46 +08:00
57583a98bc .github/workflows: remove code coverage report for folder example (#3608) 2024-05-30 21:05:35 +08:00
f8175e7113 drivers/mssql: change driver from github.com/denisenkom/go-mssqldb to github.com/microsoft/go-mssqldb (#3612) 2024-05-30 20:58:51 +08:00
6b84a37794 .github/workflows: fix warning info from node16 on timezone setting (#3614) 2024-05-30 20:55:06 +08:00
457f7abcf5 contrib/drivers: add README.zh_CN.MD (#3604) 2024-05-27 21:02:02 +08:00
9e9e42b45c cmd/gf: test gen ctrl comments (#3575) 2024-05-27 20:42:26 +08:00
8f4d5f7d74 cmd/gf: refactor gf gen service with AST (#3488) 2024-05-27 20:41:05 +08:00
b675d01418 database/gdb: add unscoped tag support for orm struct (#3464) 2024-05-22 21:52:21 +08:00
17385eeaef database/gdb: fix confusing error message in Insert/Update operations when table not exist or the table contains no fields (#3553) 2024-05-22 21:26:53 +08:00
23df83cb0b database/gdb: fix deadlock when orm operations perform in cache function from gcache (#3585) 2024-05-22 21:14:43 +08:00
2e471662f4 os/gcfg: fix file searching issue always returning the configuration file of pwd (#3592) 2024-05-22 21:14:16 +08:00
1e8f4287af contrib/registry/zookeeper: fix invalid searching prefix (#3598) 2024-05-22 21:12:21 +08:00
21c83670d6 os/gtime: fixed gtime ci fail (#3596) 2024-05-22 20:45:39 +08:00
1b23bf495a container/gmap&gset: fix deadlock when removing values during iterating (#3572) 2024-05-21 22:07:28 +08:00
15b60462a2 driver/pgsql: optimize regex for version matching (#3583) 2024-05-21 21:51:43 +08:00
1455440efa os/gcfg: fix gcfg adaptfile dogetfilepath (#3587) 2024-05-20 20:23:38 +08:00
737da954a0 util/gconv: remove unnecessary logic for function doScanList (#3588) 2024-05-20 19:42:51 +08:00
a9a0785252 util/gconv: refactor code unit testing (#3591) 2024-05-20 19:40:30 +08:00
d5561aa323 cmd/gf: add gf init app/mono-app -a (#3550) 2024-05-15 20:25:43 +08:00
cf37731d5f version: v2.7.1 (#3573) 2024-05-14 21:20:22 +08:00
0765741d99 os/gtime: fix #3558 time zone issues (#3561) 2024-05-10 17:44:45 +08:00
74338c498e ci: fix code coverage not sync to CodeCov (#3570) 2024-05-10 17:44:01 +08:00
ff28d88572 cmd/gf: fix gen enums failed in go version v1.22.1 (#3565) 2024-05-07 20:40:35 +08:00
94c7185826 util/gvalid: fix slice enums verification failed (#3566) 2024-05-07 20:36:55 +08:00
8e075fba53 contrib/sdk/httpclient: add custom response handler support, fixe #3539 (#3540) 2024-04-29 20:37:25 +08:00
3b1d1d33b8 other: update some issue templates (#3544) 2024-04-29 19:37:57 +08:00
ac6604730a cmd/gf: fix pbentity generate fail in mono-repo (#3547) 2024-04-29 19:27:15 +08:00
3cdd9ef36e cmd/gf: fix command gf gen dao for fieldMapping feature (#3549) 2024-04-29 19:22:02 +08:00
9aa426a105 database/gdb/gdb_model_soft_time: fix soft-time support fieldType:LocalTypeUint64 in Insert/Update perations (#3551) 2024-04-29 19:00:51 +08:00
5b7cae78bc feat: add custom field type mapping support for command gf gen dao (#3498) 2024-04-25 19:19:09 +08:00
cc98e5759c fix: #3200 empty content in glog handler after structure logging feature supported (#3475) 2024-04-25 19:13:50 +08:00
12ff9af431 test/gtest: add support for string type in AssertIN and AssertNI (#3537) 2024-04-24 21:04:54 +08:00
aa6d83fe1c other: enhance Issues and Pull Requests template (#3533) 2024-04-24 19:20:34 +08:00
f48ca959f7 chore: fix function names in comment (#3536) 2024-04-24 19:14:42 +08:00
59a959a361 fix: #3459 gf gen dao should ignore link configuration from file as it is passed from arguments (#3531) 2024-04-23 21:43:45 +08:00
ce57b26769 cmd/gf: fix unit testing cases for compatibility with windows (#3532) 2024-04-23 21:39:11 +08:00
adc94fd97a fix: uint testing case for signal feature of package gproc occasionally failed (#3529) 2024-04-23 21:30:33 +08:00
1013df1627 enhance: improve performance of struct converting for package gconv (#3412) 2024-04-23 21:30:06 +08:00
646ed5ea14 enhance: upgrade version of dependencies (#3526) 2024-04-22 19:59:59 +08:00
a39e6a2c62 enhance: gf gen ctrl with -merge option (#3490) 2024-04-18 20:12:02 +08:00
fa4f31f3dd chore: fix function names in comments for package otelmetric (#3493) 2024-04-18 20:04:23 +08:00
adb813fbad enhance: upgrade version of dependencies (#3494) 2024-04-18 20:02:27 +08:00
ebe567dab2 fix: missing file closding when printing downloading percent of gf cli file for command gf up (#3483) 2024-04-16 19:49:09 +08:00
bbcf49db98 fix: #3238 first column might be overwritten in interal context data in multiple goroutines querying (#3476) 2024-04-16 19:31:06 +08:00
75763735c4 enhance: improve command gf gen ctrl using AST for parsing DstFolder (#3478) 2024-04-15 20:16:44 +08:00
285e5a0580 fix: file name example/pack/packed/paked.go → example/pack/packed/packed.go (#3479) 2024-04-15 20:11:01 +08:00
2ee0c2bdac fix: sqlitecgo to support 32-bit architecture (#3480) 2024-04-15 10:03:49 +08:00
ae58dc846a fix: missing arguments on Windows platform for package gproc (#3482) 2024-04-15 09:59:35 +08:00
91f449dff8 feat: add new rule required-if-all for package gvalid (#3455) 2024-04-11 19:45:09 +08:00
2523889765 enhance: improve gf gen ctrl using AST (#3470) 2024-04-11 19:15:31 +08:00
4c6b146627 feat: add Scan method for incremental key retrieval in gredis (#3451) 2024-04-11 15:37:22 +08:00
6e2d238f56 emhace: unit testing cases update for package cmd/gf and contrib/drivers (#3453) 2024-04-10 20:55:09 +08:00
d7a0482146 fix: #3465 If the value of a string is null, the value of string is nil after the string is converted to []string (#3468) 2024-04-10 20:18:03 +08:00
b040654574 enhance: add ORM tag to the entity result of command gen dao to make entity assignment more faster (#3454) 2024-04-07 19:19:07 +08:00
505fc25a64 fix: fsnotify watcher panics when closing (#3399) 2024-04-07 14:12:03 +08:00
83ba887df7 fix: #3449 accept slice parameter as json.RawMessage for http request (#3452) 2024-04-07 14:09:52 +08:00
911f1cb1de enhance: use map iter to iterate the map instead of map keys and values (#3457) 2024-04-07 10:00:04 +08:00
1b7aea0ced feat: add metrics option and prometheus handler wraps (#3445) 2024-04-07 09:57:13 +08:00
x
db5eed17b1 fix: invalid cache key using pointer address of variable for soft time fields (#3448) 2024-04-02 20:10:16 +08:00
1ffb510a77 feat: add custom go module configuration support when initialize go project using command gf init (#3425) 2024-04-02 14:05:22 +08:00
f039393b2b fix: map converting in loop logic of validation for package gvalid (#3423) 2024-04-01 19:23:12 +08:00
00ba053ce6 enhance: use in-memory cache for soft field name and type (#3420) 2024-04-01 19:22:23 +08:00
dcf1f19ff7 enhance: Save operation support for mssql (#3365) 2024-04-01 19:18:54 +08:00
06826750ed enhance: improve Save feature for drivers oracle and dm (#3426) 2024-04-01 19:08:26 +08:00
e0a2645f4a fix: #3390 name&shor tag mapping failed to command input object for package gcmd (#3429) 2024-04-01 19:07:08 +08:00
509fdf45c6 feat: add auth support in address configuration for etcd registry (#3439) 2024-03-29 19:19:45 +08:00
1e7d897b66 fix: lost trace content in occasion when shutting down trace (#3418) 2024-03-29 10:08:58 +08:00
6df0a9ca66 fix: the cron job with precise second time pattern might be executed twice in the same time (#3437) 2024-03-28 22:09:11 +08:00
1c12f3a30d fix: http superfluous response.WriteHeader call in some scenario (#3428) 2024-03-28 22:08:54 +08:00
3a9e0e34ca fix: #3432 Add Access-Control-Expose-Headers: Content-Disposition header in ServeFileDownload (#3433) 2024-03-28 20:07:56 +08:00
8669512f42 feat: add metric feature support in goframe (#3138) 2024-03-24 21:18:30 +08:00
313d9d138f fix: unit testing cases of contrib/drivers occasionally failed by using now time assertion (#3410) 2024-03-21 21:57:33 +08:00
040118b7c6 fix: #3370 fixed process parameter parsing failed on Windows for package gproc (#3386) 2024-03-20 19:58:42 +08:00
b3f48212f1 fix: #3362 IsEmpty panics when some interface implement panics with nil receiver (#3367) 2024-03-20 19:52:12 +08:00
cade0775e8 enhance: Save operation support for contrib/drivers/dm (#3404) 2024-03-20 19:18:25 +08:00
164aad48c3 fix: unit test of dm failed occasionally (#3382) 2024-03-19 19:40:52 +08:00
04756d05a7 fix: fix lost log directory path for grapc log (#3387) 2024-03-18 19:14:31 +08:00
409041b965 enhance: support save for Oracle (#3364) 2024-03-13 20:11:45 +08:00
11f7187367 fix: unit test of dm failed occasionally (#3369) 2024-03-13 19:29:41 +08:00
4feda4c395 enhance: do not ignore error from gdb.FormatMultiLineSqlToSingle func (#3368) 2024-03-13 19:22:17 +08:00
a8713da97f enhance: cut tracing content as unicode for safety (#3342) 2024-03-13 19:21:16 +08:00
199737cd0f fix: for typo in comments for package contrib/drivers and gdb (#3366) 2024-03-12 20:40:20 +08:00
3a8f246569 fix: unit test error in PgSQL and SQLite; Unified t.Assert(err, nil) to t.AssertNil(err) (#3356) 2024-03-12 20:05:03 +08:00
607f079b23 fix: cache value assertion panic if the cache adapter is not in-memory for soft time feature of package gdb; improve converting performance for gconv.Scan (#3351) 2024-03-07 11:36:42 +08:00
cab6b89446 enhance: update contrib/drivers/README.MD (#3355) 2024-03-07 11:34:49 +08:00
6ed3038312 feat: version v2.6.4 (#3352) 2024-03-07 10:12:58 +08:00
9b48da459e enhance: add sentinel auth config for redis (#3348) 2024-03-06 19:27:52 +08:00
fbd266fad0 enhance: add Save operation support for SQLite #2764 (#3315) 2024-03-06 19:22:58 +08:00
240dadff92 fix: WherePri function wrong in pgsql #3330 (#3339) 2024-03-06 19:19:07 +08:00
290f4a3e65 fix: recognize json_valid constraint as json field type for database mariadb #2746 (#3309) 2024-03-06 19:07:31 +08:00
97fcd9d726 enhance: improve FormatUpsert implements for pgsql (#3349) 2024-03-06 19:05:13 +08:00
df15d70466 enhance: change tracing span name from request uri to router uri for http request (#3338) 2024-03-05 21:11:27 +08:00
680ae8616b fix: generated dao go files forcely cleared by command gf gen dao if clear set true (#3337) 2024-03-05 20:49:19 +08:00
4feb8219fa feat: upgrade set-go version and add go 1.22 version (#3316) 2024-03-04 20:18:31 +08:00
509cc47d3f enhance: add Save operation support for pgsql #3053 (#3324) 2024-03-04 20:17:43 +08:00
849b104c31 enhance: gproc.signal enhance #3325 (#3326) 2024-03-04 20:10:05 +08:00
ce3ef13e6a fix: otel tracing content contains invalid UTF-8 (#3340) 2024-02-29 20:22:42 +08:00
rio
c8a73f8c25 nacos-sdk-go upgrade to v2 (#3334) 2024-02-28 21:52:32 +08:00
b71ee13ccd fix error code comment on i18n defaultLanguage value (#3335) 2024-02-28 21:51:43 +08:00
a347cdc30e fix github pages ci (#3331) 2024-02-28 19:20:37 +08:00
39a88ef650 fix typo (#3332) 2024-02-27 21:09:43 +08:00
8b156e25c4 enhance mysql_z_unit_model_test (#3329) 2024-02-27 21:07:31 +08:00
eb0c4b3824 fix #3226 (#3322) 2024-02-27 20:37:49 +08:00
56ef0c0735 fix issue command gf run -w takes no effect (#3321) 2024-02-27 20:33:57 +08:00
a1a9465e52 add ExampleCache_Clear (#3310) 2024-02-27 19:42:58 +08:00
d64a31fd1a new version v2.6.3 (#3308) 2024-02-07 17:11:36 +08:00
6cdf044320 fix issue #2616 (#3307) 2024-02-07 16:47:41 +08:00
5307f0742e add # for cron pattern that can ignore seconds, which makes the cron pattern running in minimum minute like linux crontab pattern (#3306) 2024-02-07 15:38:24 +08:00
51326f3d02 fix #3245 (#3298) 2024-02-06 11:47:25 +08:00
e1fa99013a use iota to unify the enums definition (#3305) 2024-02-06 11:44:29 +08:00
72014689e4 fix issue #2643 (#3304) 2024-02-06 10:21:44 +08:00
2acdf4bb47 add field type detection for soft time field like created_at/updated_at/deleted_at to support unix timestamp or bool deleting table field (#3293) 2024-02-06 10:21:23 +08:00
85c5b7f19e fix issue #2594 (#3303) 2024-02-05 20:40:03 +08:00
42ec1a0076 fix issue #2572 (#3301) 2024-02-05 19:20:05 +08:00
553cc45e54 fix empty pwd path read from gfile.Pwd() which could cause internal error logging for gview.New (#3302) 2024-02-05 16:49:44 +08:00
7415ec32c8 fix issue #2503 (#3299) 2024-02-05 10:30:03 +08:00
14568562e3 fix issue #2552 (#3300) 2024-02-05 10:29:43 +08:00
cc79d23334 fix issue #2457 (#3297) 2024-02-02 10:57:24 +08:00
ef2b47d180 fix issue #3292 (#3294) 2024-02-01 16:02:36 +08:00
adc056f547 feat: support running commands via non-command line arguments (#3290) 2024-01-30 20:14:13 +08:00
8266a16b4e fix issue #3286 (#3289) 2024-01-30 20:03:58 +08:00
c4a51f4c2f bugfix:fix gconv map deep option not effective (#3287) 2024-01-29 19:52:04 +08:00
4ddc9c3909 add offline document link in readme.md (#3284) 2024-01-25 20:47:21 +08:00
0a2f8abb40 Update annotation for redis.toml (#3282) 2024-01-24 20:37:41 +08:00
81de5d3f25 fix workflow script for cli building and release (#3279) 2024-01-24 20:36:50 +08:00
e6d61e6e14 fix error in gerror.HasCode (#3277) 2024-01-24 20:36:32 +08:00
4fb739615b version v2.6.2 (#3276) 2024-01-22 21:53:10 +08:00
ba39323d30 improve converter feature for package gconv (#3211) 2024-01-22 21:52:54 +08:00
383937fe69 add example for ctx keys feature of package glog (#3273) 2024-01-22 21:07:40 +08:00
Bob
f919f90bf5 rename gitee issue template (#3274)
rename gitee ISSUE_TEMPLATE.MD to ISSUE_TEMPLATE
2024-01-22 21:07:04 +08:00
b4f6f06ab5 no printing internal middleware for ghttp.Server (#3271) 2024-01-22 21:05:40 +08:00
73fbca40ca add internal error logging and update comments for gclient.RequestVar (#3270) 2024-01-18 10:21:38 +08:00
e8d3fcac6b feat: upgrade gitee sync Hub Mirror Action (#3272) 2024-01-18 10:21:14 +08:00
f87182d5b8 fix workflow for gitee sync (#3269) 2024-01-17 20:27:41 +08:00
951f8921cd fix #3237 (#3267) 2024-01-17 15:35:48 +08:00
d26b7c5437 fix some wrong comment (#3265) 2024-01-16 14:08:07 +08:00
9407fda197 add example for exporting prometheus metrics using ghttp.Server (#3266) 2024-01-16 14:07:49 +08:00
905913f7be Fix gf gen service bug. Fix the issue of significant differences in the generated code every … (#3260) 2024-01-15 20:35:14 +08:00
4b8eaac73f fix issue #3232 (#3247) 2024-01-15 20:33:30 +08:00
ca242ff401 fix #3251 (#3254) 2024-01-11 22:15:22 +08:00
42e3c5f39a fix #3253 (#3255) 2024-01-11 22:14:22 +08:00
4f4d2c2f8e add MiddlewareNeverDoneCtx for package ghttp (#3250) 2024-01-06 13:03:49 +08:00
Gin
5a01798481 fix: memory leak when gcache.NewAdapterMemory with lru (#3241) 2024-01-03 20:03:19 +08:00
8af1eb693e Update README.MD (#3243) 2024-01-03 19:49:06 +08:00
335ccb32af Update Github issue template (#3234) 2024-01-02 20:42:14 +08:00
e1f2666499 add example for serve file (#3193) 2024-01-02 20:19:40 +08:00
22fcfdf755 add configuration support for logger of grpcx.Server (#3223) 2024-01-02 20:19:05 +08:00
1e21b61a19 fix typo flie -> file (#3228) 2024-01-02 20:17:54 +08:00
6abd8bd864 comments update for package gstr (#3233) 2024-01-02 20:16:51 +08:00
cy
4876ae0e2b fix:gz files are compressed repeatedly every time tick (#3236) 2024-01-02 20:10:57 +08:00
63bdf41d40 fix #3191 (#3194) 2023-12-28 20:18:29 +08:00
984cca8b82 feat: update dependent redoc js for swagger ui (#3217) 2023-12-28 20:13:21 +08:00
9f7ce42c74 enhance #3221 (#3224) 2023-12-28 20:07:07 +08:00
16a43bcb6c Add comment for Format method so that you can know Layout method. (#3230) 2023-12-26 16:19:59 +08:00
85d95e3e27 version v2.6.1 (#3222) 2023-12-21 21:12:51 +08:00
4cce8557e6 fix: #2924 (#3177) 2023-12-21 10:16:14 +08:00
d60d7674d7 fix issues for package contrib/drivers/dm (#3157) 2023-12-20 20:33:58 +08:00
7f9467d1f8 fix: #2938 (#3178) 2023-12-20 20:25:23 +08:00
d08e3ef838 fix: #2689 change sessionId in cookie (#3203) 2023-12-20 20:21:15 +08:00
645c5ff5b5 fix issue #3218 #3204 (#3220) 2023-12-19 21:58:12 +08:00
7975e391f0 Version/v2.6.0 (#3213) 2023-12-18 20:59:09 +08:00
565790036e improve gen dao to support removeFieldPrefix (#3208) 2023-12-18 20:26:43 +08:00
44819b135e fix issue #3204 (#3212) 2023-12-18 20:19:18 +08:00
bb19877430 fix: #3197 (#3206) 2023-12-18 19:11:39 +08:00
fc02e06423 doc: update readme img (#3207) 2023-12-15 15:56:08 +08:00
dd8a5dcf32 fix: #3179 (#3195) 2023-12-14 21:51:28 +08:00
33584506ab fix issue: request body was closed while retrying in callRequest method (#3199) 2023-12-14 14:18:31 +08:00
ee2cf92479 Version/v2.6.0 beta (#3183) 2023-12-04 19:34:48 +08:00
0b6dd6fb13 improve initialization performance and logging content for cmd gf (#3174) 2023-11-30 18:59:49 +08:00
993467bb3c test: add date-format test for RFC3339 (#3181) 2023-11-29 19:12:21 +08:00
c7c9f0011a fix: #2967 (#3175) 2023-11-29 19:05:21 +08:00
9aa872e705 improve map converting feature using MapOption for package gconv (#3170) 2023-11-23 18:59:04 +08:00
ea5d52cb2f fix issue #3147 (#3161) 2023-11-22 21:05:39 +08:00
b1754f8254 script updates for version upgrading (#3169) 2023-11-22 20:49:07 +08:00
83f08b3135 fix issue in Join stements with prefix specified for package gdb (#3151) 2023-11-20 20:47:26 +08:00
d3d1f94e40 Upgrade nacos sdk to latest version (#3166) 2023-11-20 20:47:00 +08:00
fc8572e8dd version v2.5.7 (#3162) 2023-11-20 10:01:54 +08:00
85acd3d31d Fix the bug that ScanAndCount and AllAndCount report errors in sqlserver (#3155) 2023-11-16 20:15:48 +08:00
9694a68211 Optimize the information display of gf -v (#3145) 2023-11-16 20:10:45 +08:00
0be8b29e42 improve gen service code (#3140) 2023-11-14 20:53:41 +08:00
5580ac9475 fix issue in cross-building failed in windows (#3152) 2023-11-14 20:10:49 +08:00
84ed66018e fix issue: Windows Platform did not handle process signal (#3154) 2023-11-14 20:00:26 +08:00
4d7f9552fe fix: gdb unsupport aliyun hologres link (#3150) 2023-11-13 22:05:53 +08:00
d4b14fd717 add gen service unit testing (#3142) 2023-11-09 20:04:05 +08:00
0bd15bdab5 fix: "gf gen dao" utils.GetModPath Return empty string in windows (#3141) 2023-11-09 20:02:47 +08:00
0b407c5e6d fix "gf gen pb" api and ctrl not working well. (#3076) 2023-11-08 21:26:51 +08:00
5f5b82188c example: log rotate (#3137) 2023-11-08 21:23:39 +08:00
a17849bc39 improve struct converting in parameter name case sensitive scenario for package gconv (#3122) 2023-11-08 21:17:55 +08:00
f3e3a5af5a feat: improve code for shutdown of otel (#3136) 2023-11-08 21:16:23 +08:00
dc71c0d28f enhance #3129 (#3134) 2023-11-06 19:27:26 +08:00
eb99f5ebfe rename function name PKCS5UnPadding to PKCS7UnPadding (#3124) 2023-11-06 19:20:07 +08:00
007fe0ea1a enhance #3063 (#3115) 2023-11-06 09:59:45 +08:00
50b04c658c improve implements and fix issues for package contrib/drivers/dm (#3128) 2023-11-06 09:52:36 +08:00
cbea89e6f7 fix duplicated route dump for package ghttp (#3116) 2023-11-02 09:48:39 +08:00
e2e12fadb0 add function CaseConvert for package gstr (#3098) 2023-11-01 19:52:07 +08:00
47eaa513c0 add unit testing cases for command gen ctrl (#3090) 2023-11-01 19:23:03 +08:00
3bbc0fdd21 add Output configuration support for command gf build in cross-buildling binary scenario (#3120) 2023-11-01 19:18:44 +08:00
9393072745 improve TemplateGenCtrlController is comments and formats (#3065) 2023-10-31 20:21:18 +08:00
e42aa64d75 improve impelements for logging file rotation in windows (#3080) 2023-10-31 20:19:01 +08:00
b6935a7285 fix(goai): example value needs to be converted just like default value (#3085) 2023-10-31 20:18:39 +08:00
b0367e4a62 fix: gRPC-Go HTTP/2 Rapid Reset vulnerability (#3095) 2023-10-31 20:17:39 +08:00
0b71bc43a8 fix issue #3099 (#3107) 2023-10-31 20:02:20 +08:00
Gin
afeca8cf9d fix: nacos mod (#3103) 2023-10-31 10:04:51 +08:00
sam
33c396fb74 fix cmd gen pbentity for generating go orm files for database postgres (#3105) 2023-10-31 10:04:07 +08:00
4903ef7887 fix issue #3100 (#3106) 2023-10-30 20:27:48 +08:00
ab5ab4c675 Add the Protocol attribute to the Redis configuration (#3109) 2023-10-30 20:11:23 +08:00
3ea61d084e fix issue #3086 (#3089) 2023-10-26 10:04:21 +08:00
2433b2ce99 ignore cmd/gf/go.work.sum from version controll (#3087) 2023-10-25 21:17:21 +08:00
927758a2a9 fix separator issue in windows os for command gf gen (#3088) 2023-10-25 21:16:05 +08:00
cb0d018fa4 feat: upgrade version and improve consul action (#3078) 2023-10-24 20:36:01 +08:00
49f69f6ade Update README.MD (#3082) 2023-10-24 20:33:10 +08:00
bcb479aabb fix issue #3077 (#3081) 2023-10-24 10:02:04 +08:00
db59f4232f add README and example cases for nacos registry (#3075) 2023-10-23 20:04:39 +08:00
aa625d24bc add example for http rate llimit (#3072) 2023-10-23 20:02:37 +08:00
36cfbaaa22 README.MD updates for cli installation (#3071) 2023-10-23 20:00:10 +08:00
f8462b5218 split ci workflow into two workflows for short (#3069) 2023-10-23 19:28:26 +08:00
b2bd12a371 version v2.5.5 (#3068) 2023-10-20 10:21:04 +08:00
acf2307eb9 fix issue #2963 (#3062) 2023-10-19 19:58:19 +08:00
93964ee231 delete repeat code in ut for package ghttp (#3058) 2023-10-18 20:04:07 +08:00
943939ba2b improve cache duration from second to millisecond for redis adapter of package gcache (#3052) 2023-10-18 20:02:23 +08:00
f1b5a223bf add go workspace for cmd/gf, to enable go install for cmd/gf (#3040) 2023-10-18 20:01:16 +08:00
bb9cd37fab add SetNoUrlEncode/NoUrlEncode functions for gclient.Client (#3041) 2023-10-17 21:19:59 +08:00
972f8c3aff improve comments for package gconv (#3057) 2023-10-17 21:09:46 +08:00
34e522306d resolve response is gzip in internalMiddlewareServerTracing (#3055) 2023-10-17 20:35:56 +08:00
7c92c2f7e8 improve comments and variable names for gcfg.AdapterFile of package gcfg (#3046) 2023-10-17 20:12:07 +08:00
5204bdb60d add option merge controlling generating controller files into one single file for command gf gen ctrl (#3045) 2023-10-17 20:11:23 +08:00
6ab8d065d1 fix:incorrect parameter passing causes captured errors to be lost (#3048) 2023-10-16 21:20:21 +08:00
d4e686226b improve version checks for ci script (#3047) 2023-10-16 21:18:23 +08:00
19d7714503 fix security issue for golang.org/x packages (#3042) 2023-10-16 20:45:43 +08:00
f464f30e6f improve comment of router feature for ghttp.Server (#3014) 2023-10-16 20:41:10 +08:00
XG
0e7d7d1eee feat: add -w/--watchPaths for subcommand gf run (#3009) 2023-10-12 21:07:51 +08:00
6af66a0201 add service registry implements using nacos (#2995) 2023-10-12 21:06:37 +08:00
81f3ad043d ci: Update action script to remove inactive labels (#3013) 2023-10-11 21:39:20 +08:00
ca7450f595 enable go cache for ci, coverage of ut testing is only available after merge of pr (#3011) 2023-10-11 21:38:43 +08:00
65192a7f92 fix issue gconv struct slice/map of json.RawMessage (#3006) (#3008) 2023-10-11 21:35:27 +08:00
8c309ac9fe fix issue #2907 (#3005) 2023-10-11 21:34:17 +08:00
7f1ce2aff3 fix issue #2904 (#3004) 2023-10-11 21:33:51 +08:00
10b67fc7b0 fix issues #2980 (#2994) 2023-10-11 21:28:53 +08:00
3cd005911d fix issue reading resource from manage in function New of package gres (#2961) 2023-10-10 20:02:52 +08:00
d10d96800f temporaryly close the testing of package kubecm to avoid disk unavailable issue (#3007) 2023-10-10 14:09:58 +08:00
35e5f1f204 feat: Migrate the service call tracing to use otlphttp or otlpgrpc for reporting (#3001) 2023-10-09 20:09:20 +08:00
1efdb72990 add direct service address support for grpc client (#2991) 2023-10-09 20:03:45 +08:00
8d925d4741 fix issue #2890 (#3002) 2023-10-09 20:00:08 +08:00
d6362cad16 add List2/List3/ListAndTrim2/ListAndTrim3 functions for package gstr (#2986) 2023-10-09 19:58:14 +08:00
00e83fed3f add function Partition for Model of package gdb (#2989) 2023-10-08 09:49:21 +08:00
02f1cc7b40 allowing use printToStdout, printToFile and printToWriter at the same time for Logger of package glog (#2990) 2023-10-07 20:46:24 +08:00
32a60c2e96 Add consul config adapter usage example. (#2988) 2023-10-07 20:19:47 +08:00
30040332a7 improve address configuration for grpc server (#2982) 2023-09-27 14:40:32 +08:00
569cbb09bf fix: improve specification version (#2987) 2023-09-26 22:03:18 +08:00
130191f4ed add in:header tag cache for http request to enhance performance (#2923) 2023-09-25 21:34:58 +08:00
e6732039c6 add consul config adapter (#2964) 2023-09-25 21:02:55 +08:00
df92c483d0 fix isue #2976, to be compatible with bad response type definition for strict route function (#2977) 2023-09-25 20:40:32 +08:00
7c9eefef3d feat: Preserve original file permissions & Default copy permissions c… (#2969) 2023-09-19 20:20:13 +08:00
42de1c1dbe improve example cases for package gi18n (#2970) 2023-09-19 20:18:43 +08:00
395df940d7 fix(gutil): panic when field is []byte(BINARY in mysql) (#2957) 2023-09-18 20:16:59 +08:00
ef1e18df19 fix: gutil.IsMap judgment logic error (#2953) 2023-09-13 19:30:02 +08:00
e684eae878 Make GTime support multiple formats (#2933) 2023-09-13 19:29:25 +08:00
5219c5c37e add ut cases for command gen dao (#2958) 2023-09-12 22:00:35 +08:00
5059abd88e upgrade dependence github.com/apolloconfig/agollo/v4 version from v4.1.1 to v4.3.1 for package contrib/config/apollo (#2949) 2023-09-12 21:20:53 +08:00
e2ed058e3b feat: upgrade action/checkout to v4 (#2948) 2023-09-12 21:20:10 +08:00
ccc959a2d3 feat: jaeger package will be removed in v2.6.0. (#2946) 2023-09-12 21:17:47 +08:00
a5a7d23792 improve g.Go (#2956) 2023-09-12 20:00:01 +08:00
5bc9acdab3 version v2.5.3 (#2945) 2023-09-11 10:19:51 +08:00
ab1970e7d6 add new function g.Go (#2943) 2023-09-11 10:18:44 +08:00
1582714325 improve signal listening for package grpcx/ghttp/gproc (#2942) 2023-09-11 10:15:08 +08:00
7391a4d45a improve trace span generating for package gctx and http tracing content for package ghttp (#2937) 2023-09-11 10:14:00 +08:00
7e16d9b63e fix codes due to static codes analysis (#2935) 2023-09-07 20:22:20 +08:00
d49dccb147 test: add unit tests regarding issue 2901 (#2930) 2023-09-05 19:30:54 +08:00
6cddfdb313 improve join feature for package gdb (#2929) 2023-09-05 19:29:28 +08:00
912316d765 add cluster mode and tls configuration support for package gredis (#2936) 2023-09-05 19:23:17 +08:00
b9e2b05f04 change interface ConvertDataForRecord to ConvertValueForField for package gdb (#2916) 2023-09-04 21:23:54 +08:00
887803e495 add structure logging handler for package glog (#2919) 2023-09-04 21:23:46 +08:00
eb11061bd2 fix: gjson encode to string expect inconformity(issue 2520) (#2928) 2023-09-04 21:19:22 +08:00
000c7a92ed ORM add function: LeftJoinOnFields,RightJoinOnFields,InnerJoinOnFields (#2921) 2023-09-04 20:33:53 +08:00
097b26f318 fix: multiple interfaces cause the original type to be inaccessible (#2915) 2023-09-04 20:11:14 +08:00
3da5e5e865 fix: gutil.IsSlice judgment logic error (#2910) 2023-09-04 20:09:55 +08:00
e60262fec9 docs: fix code comment err in Model Join case (#2884) 2023-09-04 20:05:52 +08:00
74bf1b4bc3 fix(cmd): Fix gf build examples (#2917) 2023-08-31 15:32:49 +08:00
3f69e0db36 improve error stack configuration for package gerror, add framework error stack filter for package glog (#2918) 2023-08-31 15:31:55 +08:00
7d4c59ac5a fix: OpenAPI cannot correctly identify the file type under the canoni… (#2898) 2023-08-28 21:52:22 +08:00
3841f05e02 add AdapterContent implements for gcfg.Adapter (#2892) 2023-08-28 21:49:30 +08:00
bcd409ab1c fix typo "Upadte" -> "Update" (#2906) 2023-08-28 21:48:56 +08:00
4dd43aa018 improve packed project template for command init (#2885) 2023-08-23 19:28:09 +08:00
aed695313a rewrite gmutex with sync.RWMutex (#2883) 2023-08-23 19:27:57 +08:00
cf299273c4 version v2.5.2 (#2878) 2023-08-18 09:57:25 +08:00
53323f3cf9 improve support for generic router registering (#2877) 2023-08-17 21:16:19 +08:00
24ee5341ec Fix empty map or struct convert to another map will return error. (#2863) 2023-08-17 20:59:16 +08:00
ed4d1554ab improve converter feature for package gconv (#2869) 2023-08-17 20:33:12 +08:00
ac3481ed43 it returns error when Scan to a none empty slice with empty Result for package gdb (#2858) 2023-08-17 20:29:06 +08:00
3df5969348 fix generic check with slice for ghttp (#2850) 2023-08-16 21:42:36 +08:00
ea6a773d60 fix: marked gcode.CodeInternalPanic for panic (#2860) 2023-08-14 09:53:13 +08:00
35a326e169 fix(ghttp): fix access log info format (#2853) 2023-08-10 22:12:10 +08:00
4020eb9b4c fix issue in SliceMap/Maps for package gconv when nil value in map of slice item (#2857) 2023-08-10 21:59:21 +08:00
243fe73c57 improve comment replacement regex pattern for command gen service (#2846) 2023-08-08 20:39:38 +08:00
932f8c48ef Add gconv custom converter feature. (#2828) 2023-08-07 21:15:22 +08:00
7c1be3eb63 improve data converting for DB.DoInsert/DoUpdate (#2830) 2023-08-07 21:03:56 +08:00
5de2cfbfa1 improve command gen ctrl for api parsing and interface file generating (#2836) 2023-08-07 21:02:16 +08:00
b593c00d97 fix gf gen service remove all comments. (#2845) 2023-08-07 20:42:10 +08:00
7798e96190 add more ut case for package goai (#2843) 2023-08-07 20:39:01 +08:00
55ac18d90a Update README for minimum go version requirement (#2833) 2023-08-03 21:14:48 +08:00
a409db5540 Bump golang.org/x/net from 0.0.0-20211112202133-69e39bad7dc2 to 0.7.0 in /contrib/drivers/sqlitecgo (#2834) 2023-08-03 21:13:23 +08:00
dd5d56674e Bump golang.org/x/text from 0.3.8-0.20211105212822-18b340fc7af2 to 0.3.8 in /contrib/drivers/sqlitecgo (#2835) 2023-08-03 21:12:45 +08:00
79617570ca Feat:upgrade redis v9 (#2825) 2023-08-03 20:01:36 +08:00
a4e7cc4700 fix: psgql tx unsupport LastInsertId (#2815) 2023-08-03 19:59:22 +08:00
2fbe4125dd feat: Using sqlite CGO is for building a 32-bit Windows operating system (#2743) 2023-08-03 19:58:16 +08:00
47915816b5 fix: disable map tag summary and description from the OpenAPI Operation to PathItem (#2823) 2023-08-02 20:45:58 +08:00
0f53660453 fix issue #2570 (#2819) 2023-08-02 20:41:28 +08:00
f3437dc00f add generic support for http routes registering #2227 #2457 (#2807) 2023-08-02 20:35:58 +08:00
574d63b4fd fix issue #2803 (#2805) 2023-08-01 22:06:10 +08:00
53e5a04073 change minimum golang version from v1.15 to v1.18 (#2820) 2023-08-01 21:15:28 +08:00
XG
c51785125e refactor: add default client instance for contrib/sdk/httpclient (#2814) 2023-08-01 20:45:20 +08:00
XG
5230f8304e fix issue #2816 (#2817) 2023-08-01 20:11:52 +08:00
e0e00434cc expose iClient as IClient in generated sdk for command gen ctrl (#2804) 2023-07-26 21:27:58 +08:00
b95cb3180d fix gen ctrl import path (#2800) 2023-07-25 21:50:47 +08:00
dec66dbd05 add NeverDone function for package gctx that creates and returns a never done ctx (#2784) 2023-07-25 20:45:34 +08:00
cb44c40a9c fix issue #2482 (#2789) 2023-07-25 20:28:50 +08:00
2c22f4e17d feat: improve watch for polaris registrar (#2788) 2023-07-25 20:17:17 +08:00
83fa3593b1 fix: orm generate sql wrong, issues #2782 (#2787) 2023-07-25 20:13:17 +08:00
4ad508c04d feat: add Diff feature to gmap (#2774) 2023-07-20 20:07:43 +08:00
0d52386236 improve command init and gen ctrl (#2785) 2023-07-20 20:05:40 +08:00
16a5318d32 upgrade package gopkg.in/yaml.v3 to latest stable version v3.0.1 (#2783) 2023-07-20 09:57:04 +08:00
b1da02dff6 improve import path generating for command gen ctrl (#2781) 2023-07-20 09:56:48 +08:00
b99db92113 feat: gbuild add BuiltVersion (#2754) 2023-07-19 21:15:22 +08:00
c0dff1dc16 add default time check for converting functions of gtime.Time (#2755) 2023-07-19 21:11:54 +08:00
XG
ef6ef506d6 fix issue #2775 (#2777) 2023-07-19 20:55:44 +08:00
b71ac868b7 fix gf gen ctrl import (#2771) 2023-07-19 20:15:26 +08:00
d72997da04 fix g.Wait not support OS Signal #2752 (#2768) 2023-07-19 20:06:06 +08:00
41c0dde9bf add complicated map with custom type converting support for package gconv (#2769) 2023-07-17 10:06:06 +08:00
498b72f75a improve gctx.New for none default opentelemetry provider (#2756) 2023-07-14 14:26:24 +08:00
5e231f3d61 add example for package gvalid (#2767) 2023-07-14 14:25:25 +08:00
a2fec50500 remove sharding feature from gdb.Model (#2758) 2023-07-13 21:15:53 +08:00
6d7edb1479 fix issue #2760 (#2763) 2023-07-13 21:15:07 +08:00
ce72f9a84b fix typo (#2753) 2023-07-11 19:52:49 +08:00
4fc24e1391 add endpoints configuration for ghttp.Server (#2741) 2023-07-06 21:29:33 +08:00
160bddecd3 version v2.5.0 (#2747) 2023-07-06 21:28:38 +08:00
39810a520c add redis-config Auth Username (#2684) 2023-07-06 20:58:31 +08:00
0dc47609b5 feat: improve polaris register and discovery (#2739) 2023-07-06 20:41:24 +08:00
8fb4636cb4 improve command gen service for import alias and comments handling (#2745) 2023-07-06 20:36:33 +08:00
30cf3dbbe6 add custom endpoints configuration for package grpcx (#2625) 2023-07-05 09:54:57 +08:00
c90e9311e3 fix issue #2734 (#2740) 2023-07-05 09:49:25 +08:00
ba2a7e4417 add chaining function Discovery to disable/enable discovery feature for package gclient; fix issue #2737 (#2738) 2023-07-04 20:21:12 +08:00
740dfa58a6 add sharding feature on Model for package gdb (#2732) 2023-07-04 14:42:41 +08:00
9620b15ea1 fix length check issue (#2725) 2023-07-04 09:49:09 +08:00
3fab7a341d feat(glog): add log rotation support for short-running process (#2658) 2023-06-29 20:29:33 +08:00
5804547bc5 feat: add codecov.yml ignore cmd test (#2729) 2023-06-29 20:14:31 +08:00
70d0d20750 fix issue in converting value to nil when calling IsNil return ture for gdb.Core (#2720) 2023-06-28 22:06:51 +08:00
92e21c275c Update README to demonstrate how to configure polaris (#2724) 2023-06-28 21:33:11 +08:00
8aff08581f feat:add service comments. (#2714) 2023-06-28 21:10:47 +08:00
6eb0de42f8 update context of the original http request (#2717) 2023-06-28 21:04:49 +08:00
8c4a0b61b8 fix: cmd gen dao typeMapping.Name=>typeMapping.Type (#2723) 2023-06-28 10:55:08 +08:00
22696566d6 add type mapping feature for command gf gen dao (#2722) 2023-06-28 10:06:33 +08:00
c5c2938380 improve command gen ctrl and gen service (#2711) 2023-06-19 20:47:32 +08:00
d6433de4a6 add command gen ctrl for parsing api to generate controller and sdk go files (#2708) 2023-06-15 14:16:10 +08:00
15eaac35a8 bugfix : when using otel, calling gclient *Raw methods may result in null pointer exceptions (#2697) 2023-06-12 20:52:48 +08:00
46f3196297 Update gcompress_zip.go (#2694)
Fix index out of range when zipfile has dir __MAXOSX
2023-06-12 20:46:31 +08:00
842e5a6774 fix gdb_fun.go code comments (#2687) 2023-06-12 19:52:38 +08:00
2ece368810 add new validation rule "enums" (#2690) 2023-06-07 09:48:29 +08:00
1bbfc56121 improve key words transaction for package i18n (#2652) 2023-06-06 21:03:25 +08:00
835b252b5d fix issue in Where when used in field with prefix that not match struct attribute name (#2688) 2023-06-06 20:40:32 +08:00
9bc9fc4545 improve command make version (#2676) 2023-06-06 17:10:32 +08:00
8cc5338870 fix version retrieving of goframe for command version (#2682) 2023-06-02 18:02:24 +08:00
9191003391 feat: improve golangci-lint config (#2681) 2023-06-02 17:09:45 +08:00
99236fd93b version v2.4.2 (#2679) 2023-06-02 11:44:48 +08:00
b34d560bb7 add auto sync ci from github to gitee (#2680) 2023-06-02 10:05:42 +08:00
7bb4ddcfd5 ignore binary building if option Build is empty for command build (#2678)
ignore binary building if option Build is empty for command build
2023-06-01 21:52:59 +08:00
00190abad8 add method ScanAndCount and AllAndCount for Model package gdb (#2635) 2023-06-01 21:33:40 +08:00
aa8eabd853 fix issue #2439 (#2673) 2023-05-30 11:59:00 +08:00
4914517f6b template updates for command gf init (#2671) 2023-05-29 20:12:06 +08:00
0865dbbf75 improve command up for goframe version upgrade (#2670) 2023-05-29 16:29:42 +08:00
d3a3ad0228 add oltp(http&grpc) trace support (#2641) 2023-05-29 10:00:41 +08:00
e075432c40 comment update for package contrib/drivers/mysql (#2649) 2023-05-25 22:00:57 +08:00
e816ab05de refactor: code optimization (#2667) 2023-05-25 21:58:11 +08:00
a4762d0e02 fix issue in http proxy when repeatable reading request body content (#2666) 2023-05-25 11:56:12 +08:00
2329622564 add multiple methods support for united routes registering (#2664) 2023-05-25 10:58:06 +08:00
368312c816 add multiple methods support for object route (#2663) 2023-05-24 17:21:28 +08:00
f6dbe1a40c change parameter prefix of type string to prefixes of type slice for command enums (#2662) 2023-05-24 14:12:49 +08:00
032d085619 fix issue in building binary for command docker (#2660) 2023-05-24 14:12:22 +08:00
a6fff37be8 add DumpJson for package gutil (#2651) 2023-05-24 10:04:19 +08:00
879283685d fix(CLI): install cmd path choose empty not use default (#2655) 2023-05-23 21:59:47 +08:00
0f4f2a6672 fix issue in array border exceeded in RoundRobin of package gsel (#2642) 2023-05-23 21:30:47 +08:00
ff6f5ce237 update default logging time format using SetTimeFormat (#2611) 2023-05-23 20:59:58 +08:00
dc0467e934 add WhereOrNot/WhereOrPrefixNot functions for gdb.Model (#2661) 2023-05-23 17:35:47 +08:00
f0d22fe570 doc: correct level value comment (#2653) 2023-05-22 20:29:24 +08:00
05ee4d489a new logo (#2647) 2023-05-16 09:55:21 +08:00
3c1ded22fd cli command exits with code 1 if error (#2645) 2023-05-15 15:51:28 +08:00
bda5d252b2 fix host ip retrieving for package contrib/trace/jaeger when there is no intranet ip in host (#2640) 2023-05-12 11:59:05 +08:00
0c3e66d6a0 fix: genpbentity type error, []byte => bytes (#2633) 2023-05-12 10:17:07 +08:00
f31bf76f94 feat: modify readme doc address (#2638) 2023-05-11 20:44:56 +08:00
0afedee49d fix: genpbentity invalid proto3 (#2632) 2023-05-11 20:12:58 +08:00
43d439a1cd fix: When repairing protobuf to generate controllers, if the project … (#2630) 2023-05-11 20:11:04 +08:00
b8aeb4f0ee fix missing .exe suffix for cli file for windows downloading, unable replacing self cli binary (#2622) 2023-05-08 21:21:23 +08:00
1408385612 fix duplicated fields in function TableFields of driver pgsql (#2620) 2023-05-05 21:10:05 +08:00
d6471d7d51 v2.4.1 (#2615) 2023-05-05 14:15:01 +08:00
aa9d66c53c feat: improve polaris relation and add copyright for polaris example (#2607) 2023-05-05 10:04:32 +08:00
d9a7ee3e29 use first column name for Model.Array (#2609) 2023-04-28 14:55:53 +08:00
04c70f2037 fix empty string converted to none empty string type slice (#2612) 2023-04-28 14:55:37 +08:00
2198f0cefe fix issue #2561 #2431 (#2598) 2023-04-27 11:35:46 +08:00
c6b9b4d326 fix file registry that not works on windows (#2605) 2023-04-27 11:34:54 +08:00
4c6ebe7808 http context never done (#2602) 2023-04-26 20:20:47 +08:00
a9090e4a72 fix some comments (#2600)
Signed-off-by: cui fliter <imcusg@gmail.com>
2023-04-26 19:34:22 +08:00
0126eb5470 fix: polaris discouvery relation (#2603) 2023-04-26 19:31:28 +08:00
ed63617aa0 fix file permission error when overwriting directory containing .git … (#2599) 2023-04-25 21:36:37 +08:00
30f483a524 correct makefile (#2597) 2023-04-24 21:50:10 +08:00
894f202b75 version v2.4.0 (#2595) 2023-04-24 11:44:19 +08:00
9171585b2c improve auto retrieving of ip addresses for service registering (#2593) 2023-04-23 21:58:17 +08:00
23d8ef32a3 fix: fix typo and go-staticcheck S1002 warning (#2590) 2023-04-21 10:13:59 +08:00
a031e112e5 add command gen enums (#2591) 2023-04-20 16:30:42 +08:00
da8297d770 improve AddObject to support Command/*Command parameter for package gcmd (#2587) 2023-04-18 10:09:07 +08:00
3991eb053c fix issue #2584 (#2586) 2023-04-17 17:44:24 +08:00
6fb26c44d7 fix issue converting values to custom type pointers (#2585) 2023-04-17 16:34:36 +08:00
fdc027734c add command make version to in Makefile (#2579) 2023-04-14 10:09:19 +08:00
32a7f6a0f0 feature/v2.4.0-rc4 (#2578)
* v2.4.0-rc3

* v2.4.0-rc4
2023-04-12 22:01:24 +08:00
5bbec48679 v2.4.0-rc2 (#2575) 2023-04-12 21:14:03 +08:00
d4b9ee4c61 version updates to v2.4.0-rc (#2574)
version updates
2023-04-12 20:24:20 +08:00
50b5cd50bc fix issue in New when creating concurrent-safety var for package gvar (#2573) 2023-04-12 17:38:06 +08:00
53afbd0f05 uf case update for contrib/drivers/mysql (#2569) 2023-04-12 15:36:44 +08:00
b6874eb66d update cli build action (#2563) 2023-04-12 11:54:15 +08:00
7ff7de4643 inherit context from http.Request for ghttp.Request (#2550) 2023-04-12 11:54:06 +08:00
5f148632d2 fix missing trace id in gctx.GetInitCtx (#2562) 2023-04-12 10:35:24 +08:00
c1325ef9a3 Add Filter function to garray (#2541) 2023-04-12 10:15:11 +08:00
d788b7ff5e fix issue #2529 #2487 (#2548) 2023-04-12 10:14:14 +08:00
66d0663dc5 add clickhouse support in command gf gen dao (#2557) 2023-04-12 10:14:04 +08:00
a56524ee05 add RemoveValues for package garray (#2568)
add RemoveValues for package garray
2023-04-12 10:12:28 +08:00
1aa9f2809e improve stream response for http (#2564) 2023-04-12 10:12:11 +08:00
261672e84c feat: automatic update gf for contrib (#2551) 2023-04-11 21:13:29 +08:00
6a4e39e815 change temp dir to os.TempDir for package gfile (#2547) 2023-03-29 11:58:20 +08:00
4af9ce8a81 Bump golang.org/x/crypto from 0.0.0-20200622213623-75b288015ac9 to 0.1.0 in /cmd/gf (#2546) 2023-03-28 20:03:07 +08:00
5f146720fe fix: unified go.mod dependent version (#2452) 2023-03-28 09:25:29 +08:00
67e6772d88 comment updates for gdb.Builder (#2513) 2023-03-28 09:23:08 +08:00
12e9febe9e fix issue #2516 (#2531)
* fix issue #2516

* golang ci configuration updates

* add example for default value of http request
2023-03-22 20:14:57 +08:00
676022eeb6 fix issue #2509 (#2530) 2023-03-21 22:10:41 +08:00
XG
3a8fc1e70d optimize the handling of the SIGUSR1 signal (#2532)
optimize the handling of the SIGUSR1 signal
2023-03-21 21:26:49 +08:00
0b6798acb5 add Quick mode for gtimer (#2488) 2023-03-20 10:00:55 +08:00
e721124b6c support microseconds resolution for created_at/updated_at/deleted_at (#2512) 2023-03-20 09:57:37 +08:00
b32eb30212 feat: improve polaris register and upgrade polaris-go version v1.3.0 (#2524) 2023-03-20 09:52:58 +08:00
967a39ecbe feat:upgrade polairs-go sdk version v1.3.0 for config (#2525)
feat:upgrade polairs-go sdk version v1.3.0
2023-03-20 09:52:19 +08:00
dfb7f5abfb improve error message when the router hander definition is not standrad (#2528) 2023-03-20 09:51:43 +08:00
56f5d5125b fix quick exit when double click cli to install/upgrade (#2521) 2023-03-17 17:56:41 +08:00
5083174a92 fix goreport for gofmt (#2523) 2023-03-17 17:54:14 +08:00
4a278dfd79 improve grpcx (#2522) 2023-03-17 17:51:10 +08:00
80d57ed8f9 add postForm with multi data content type support (#2508) 2023-03-14 09:57:22 +08:00
b742e222d6 improve command gen pb by adding controller go files generating (#2518) 2023-03-14 09:47:42 +08:00
ae86f66545 fix issue #2499 #2515 (#2517) 2023-03-13 22:16:57 +08:00
45e4c9e16c add tag value of in support for api definition that has meta info (#2450) 2023-03-13 19:29:30 +08:00
XG
8c07f1a42c feat: support graceful shutdown (#2469) (#2475) 2023-03-13 19:21:56 +08:00
e6c97410ef fix: cli gen service:BUG #2310 (#2485) 2023-03-13 19:17:23 +08:00
b1a55c7a32 improvement for grpcx (#2510) 2023-03-13 18:56:19 +08:00
1cd1449085 add package contrib/rpc/grpcx (#2169) 2023-03-08 14:12:51 +08:00
55690f3738 improve unit testing cases coverage to 80%+ (#2480) 2023-03-07 21:27:23 +08:00
13f6fb1929 fix issue struct attribute converting when has no json name but with omitempty tag (#2486) 2023-03-07 21:26:32 +08:00
e8088a6563 improve command gen dao by removing all dao files if clear option is true (#2502)
* improve command  by removing all dao files if clear option is true

* version updates
2023-03-07 19:32:13 +08:00
e8051bad9a fix issue in empty json name along with omitempty tag in package oai (#2500) 2023-03-07 14:17:14 +08:00
d0d41a63a6 robot translator updates (#2491) 2023-03-07 11:01:01 +08:00
853b038a47 add issue translation robot (#2490) 2023-03-06 09:50:03 +08:00
34946f6105 fix configuration of Namespace for pgsql (#2481) 2023-03-01 19:30:40 +08:00
Gin
15d88c269d fix: gredis maxActive config and duplicate connection bug (#2479) 2023-02-27 22:08:37 +08:00
cbbfd85eeb Protect RemoveValue from race condition (#2472) 2023-02-23 19:47:57 +08:00
adf90c876f improve unit testing cases (#2468) 2023-02-23 10:07:40 +08:00
b4f76b8448 fix: use keyword(like: group) as table name in sqlite (#2461) 2023-02-20 22:03:26 +08:00
ed858ebd4b Bump golang.org/x/net from 0.1.0 to 0.7.0 in /cmd/gf (#2460) 2023-02-20 22:02:31 +08:00
272b9c7afd README update for cmd/gf (#2459) 2023-02-20 22:01:36 +08:00
8dc8dd9756 fix issue #2261 (#2458) 2023-02-20 21:57:49 +08:00
a64d1001e2 improve ci by using cache feature of setup-go (#2463) 2023-02-20 21:51:54 +08:00
1513 changed files with 100518 additions and 39589 deletions

2
.codecov.yml Normal file
View File

@ -0,0 +1,2 @@
ignore:
- "cmd" # ignore cmd folders and all its contents

4
.github/FUNDING.yml vendored
View File

@ -1,6 +1,6 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: [gogf] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
@ -9,4 +9,4 @@ community_bridge: # Replace with a single Community Bridge project-name e.g., cl
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://github.com/gogf/gf#donators
custom: # custom

View File

@ -1,38 +0,0 @@
<!-- Please answer these questions before submitting your issue. Thanks! -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码否则issue可能会被延期处理 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码否则issue可能会被延期处理 -->
<!-- 为高效处理您的疑问如果觉得是BUG类问题请您务必提供可复现该问题的最小可运行代码否则issue可能会被延期处理 -->
<!-- 重要的事情说三遍! -->
### 1. What version of `Go` and system type/arch are you using?
<!--
Please paste the output of command `go version` from your terminal.
What expect to see is like: `go 1.12, linux/amd64`
-->
### 2. What version of `GoFrame` are you using?
<!-- You can find the GF version from your `go.mod`, or from the `version.go` in `GF` -->
### 3. Can this issue be re-produced with the latest release?
### 4. What did you do?
<!--
If possible, provide a copy of shortest codes for reproducing the error.
A complete runnable program is best.
-->
### 5. What did you expect to see?
### 6. What did you see instead?

71
.github/ISSUE_TEMPLATE/00-bug.yml vendored Normal file
View File

@ -0,0 +1,71 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
name: Bugs
description: GoFrame command, module, or anything else
title: "os/gtime: issue title"
labels:
- bug
body:
- type: markdown
attributes:
value: |
Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.
The issue title uses the format of the package name goes before the colon. Thanks!
标题使用包名在冒号前的格式!谢谢!
- type: input
id: go-version
attributes:
label: Go version
description: |
What version of Go are you using (`go version`)?
placeholder: ex. go version go1.20.7 darwin/arm64
validations:
required: true
- type: input
id: gf-version
attributes:
label: GoFrame version
description: |
What version of GoFrame are you using (`gf version`)?
placeholder: ex. 2.7.0
validations:
required: true
- type: dropdown
id: is-reproducible
attributes:
label: Can this bug be reproduced with the latest release?
options:
- Option Yes
- Option No
validations:
required: true
- type: textarea
id: what-did-you-do
attributes:
label: "What did you do?"
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is best."
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: "What did you see happen?"
description: Command invocations and their associated output, functions with their arguments and return results, full stacktraces for panics (upload a file if it is very long), etc. Prefer copying text output over using screenshots.
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: "What did you expect to see?"
description: Why is the current output incorrect, and any additional context we may need to understand the issue.
validations:
required: true

32
.github/ISSUE_TEMPLATE/01-enhance.yml vendored Normal file
View File

@ -0,0 +1,32 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
name: Enhancements
description: Enhance an idea for this project
title: "os/gtime: issue title"
labels:
- enhancement
body:
- type: markdown
attributes:
value: |
Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.
The issue title uses the format of the package name goes before the colon. Thanks!
标题使用包名在冒号前的格式!谢谢!
- type: textarea
id: description
attributes:
label: "Description"
description: "Please describe your idea in detail."
validations:
required: true
- type: textarea
id: additional
attributes:
label: "Additional"
validations:
required: false

48
.github/ISSUE_TEMPLATE/02-feature.yml vendored Normal file
View File

@ -0,0 +1,48 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
name: Features
description: Suggest an idea for this project
title: "os/gtime: issue title"
labels:
- feature
body:
- type: markdown
attributes:
value: |
Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.
The issue title uses the format of the package name goes before the colon. Thanks!
标题使用包名在冒号前的格式!谢谢!
- type: dropdown
id: is-problem
attributes:
label: Is your feature request related to a problem?
options:
- Option Yes
- Option No
validations:
required: true
- type: textarea
id: description-solution
attributes:
label: "Describe the solution you'd like"
validations:
required: true
- type: textarea
id: description-considered
attributes:
label: "Describe alternatives you've considered"
validations:
required: true
- type: textarea
id: additional
attributes:
label: "Additional"
validations:
required: false

25
.github/ISSUE_TEMPLATE/03-question.yml vendored Normal file
View File

@ -0,0 +1,25 @@
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
name: Questions
description: I want to ask a question
title: "os/gtime: issue title"
labels:
- question
body:
- type: markdown
attributes:
value: |
Please read the document carefully. 请先仔细阅读文档
The issue title uses the format of the package name goes before the colon. Thanks!
标题使用包名在冒号前的格式!谢谢!
- type: textarea
id: ask
attributes:
label: "What do you want to ask?"
description: "Please describe the details of your questions. 请详细描述你的问题。"
validations:
required: true

44
.github/PULL_REQUEST_TEMPLATE.MD vendored Normal file
View File

@ -0,0 +1,44 @@
**Please ensure you adhere to every item in this list.**
+ The PR title is formatted as follows: `<type>[optional scope]: <description>` For example, `fix(os/gtime): fix time zone issue`
+ `<type>` is mandatory and can be one of `fix`, `feat`, `build`, `ci`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`
+ `fix`: Used when a bug has been fixed.
+ `feat`: Used when a new feature has been added.
+ `build`: Used for modifications to the project build system, such as changes to dependencies, external interfaces, or upgrading Node version.
+ `ci`: Used for modifications to continuous integration processes, such as changes to Travis, Jenkins workflow configurations.
+ `docs`: Used for modifications to documentation, such as changes to README files, API documentation, etc.
+ `style`: Used for changes to code style, such as adjustments to indentation, spaces, blank lines, etc.
+ `refactor`: Used for code refactoring, such as changes to code structure, variable names, function names, without altering functionality.
+ `perf`: Used for performance optimization, such as improving code performance, reducing memory usage, etc.
+ `test`: Used for modifications to test cases, such as adding, deleting, or modifying test cases for code.
+ `chore`: Used for modifications to non-business-related code, such as changes to build processes or tool configurations.
+ After `<type>`, specify the affected package name or scope in parentheses, for example, `(os/gtime)`.
+ The part after the colon uses the verb tense + phrase that completes the blank in
+ Lowercase verb after the colon
+ No trailing period
+ Keep the title as short as possible. ideally under 76 characters or shorter
+ [Reference Documentation](https://www.conventionalcommits.org/en/v1.0.0/)
+ If there is a corresponding issue, add either `Fixes #1234` or `Updates #1234`
(the latter if this is not a complete fix) to this comment
+ Delete these instructions once you have read and applied them
**提交前请遵守每个事项,感谢!**
+ PR 标题格式如下:`<类型>[可选 范围]: <描述>` 例如 `fix(os/gtime): fix time zone issue`
+ `<类型>`是必须的,可以是 `fix`、`feat`、`build`、`ci`、`docs`、`style`、`refactor`、`perf`、`test`、`chore` 中的一个
+ fix: 用于修复了一个 bug
+ feat: 用于新增了一个功能
+ build: 用于修改项目构建系统,例如修改依赖库、外部接口或者升级 Node 版本等
+ ci: 用于修改持续集成流程,例如修改 Travis、Jenkins 等工作流配置
+ docs: 用于修改文档,例如修改 README 文件、API 文档等
+ style: 用于修改代码的样式,例如调整缩进、空格、空行等
+ refactor: 用于重构代码,例如修改代码结构、变量名、函数名等但不修改功能逻辑
+ perf: 用于优化性能,例如提升代码的性能、减少内存占用等
+ test: 用于修改测试用例,例如添加、删除、修改代码的测试用例等
+ chore: 用于对非业务性代码进行修改,例如修改构建流程或者工具配置等
+ `<类型>`后在括号中填写受影响的包名或范围,例如 `(os/gtime)`
+ 冒号后使用动词时态 + 短语
+ 冒号后的动词小写
+ 不要有结尾句号
+ 标题尽量保持简短,最好在 76 个字符或更短
+ [参考文档](https://www.conventionalcommits.org/zh-hans/v1.0.0/)
+ 如果有对应的 issue请在此评论中添加 `Fixes #1234`,如果不是完全修复则添加 `Updates #1234`
+ 应用这些规则后删除所有的说明

BIN
.github/logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 232 KiB

View File

@ -20,7 +20,7 @@ services:
#APOLLO_PORTAL_DB_PASSWORD: 'apollo'
apollo-db:
image: "loads/mysql:5.7"
image: "mysql:5.7"
container_name: apollo-db
environment:
TZ: Asia/Shanghai
@ -36,7 +36,7 @@ services:
- apollo-dbdata
apollo-dbdata:
image: "loads/alpine:3.8"
image: "alpine:3.8"
container_name: apollo-dbdata
volumes:
- /var/lib/mysql

View File

@ -1,6 +0,0 @@
#!/usr/bin/env bash
find . -name "*.go" | xargs gofmt -w
git diff --name-only --exit-code || if [ $? != 0 ]; then echo "Notice: gofmt check failed,please gofmt before pr." && exit 1; fi
echo "gofmt check pass."
sudo echo "127.0.0.1 local" | sudo tee -a /etc/hosts

View File

@ -1,49 +0,0 @@
#!/usr/bin/env bash
for file in `find . -name go.mod`; do
dirpath=$(dirname $file)
echo $dirpath
# package oracle needs golang >= v1.17
if [ "oracle" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.17"; then
echo "ignore oracle as go version: $(go version)"
continue 1
fi
fi
# package kuhecm needs golang >= v1.18
if [ "kubecm" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.18"; then
echo "ignore kubecm as go version: $(go version)"
continue 1
fi
fi
# package example needs golang >= v1.18
if [ "example" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.18"; then
echo "ignore example as go version: $(go version)"
continue 1
fi
fi
# package cmd/gf needs golang >= v1.18
if [ "gf" = $(basename $dirpath) ]; then
if ! go version|grep -q "1.18"; then
echo "ignore example as go version: $(go version)"
continue 1
fi
fi
cd $dirpath
go mod tidy
go build ./...
go test ./... -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
if grep -q "/gogf/gf/.*/v2" go.mod; then
sed -i "s/gogf\/gf\(\/.*\)\/v2/gogf\/gf\/v2\1/g" coverage.out
fi
cd -
done

269
.github/workflows/ci-main.yml vendored Normal file
View File

@ -0,0 +1,269 @@
# The main codes build and unit testing running workflow.
name: GoFrame Main CI
on:
push:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
pull_request:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
env:
TZ: "Asia/Shanghai"
# for unit testing cases of some components that only execute on the latest go version.
LATEST_GO_VERSION: "1.25"
jobs:
code-test:
strategy:
matrix:
# 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
# When adding new go version to the list, make sure:
# 1. Update the `LATEST_GO_VERSION` env variable.
# 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
go-version: [ "1.23", "1.24", "1.25" ]
goarch: [ "386", "amd64" ]
runs-on: ubuntu-latest
# Service containers to run with `code-test`
services:
# Etcd service.
# docker run -d --name etcd -p 2379:2379 -e ALLOW_NONE_AUTHENTICATION=yes bitnamilegacy/etcd:3.4.24
etcd:
image: bitnamilegacy/etcd:3.4.24
env:
ALLOW_NONE_AUTHENTICATION: yes
ports:
- 2379:2379
# Redis backend server.
redis:
image : redis:7.0
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 6379 on service container to the host
- 6379:6379
# MySQL backend server.
# docker run -d --name mysql \
# -p 3306:3306 \
# -e MYSQL_DATABASE=test \
# -e MYSQL_ROOT_PASSWORD=12345678 \
# mysql:5.7
mysql:
image: mysql:5.7
env:
MYSQL_DATABASE : test
MYSQL_ROOT_PASSWORD: 12345678
ports:
- 3306:3306
# MariaDb backend server.
# docker run -d --name mariadb \
# -p 3307:3306 \
# -e MYSQL_DATABASE=test \
# -e MYSQL_ROOT_PASSWORD=12345678 \
# mariadb:11.4
mariadb:
image: mariadb:11.4
env:
MARIADB_DATABASE: test
MARIADB_ROOT_PASSWORD: 12345678
ports:
- 3307:3306
# PostgreSQL backend server.
# docker run -d --name postgres \
# -p 5432:5432 \
# -e POSTGRES_PASSWORD=12345678 \
# -e POSTGRES_USER=postgres \
# -e POSTGRES_DB=test \
# -v postgres:/Users/john/Temp/postgresql/data \
# postgres:17-alpine
postgres:
image: postgres:17-alpine
env:
POSTGRES_PASSWORD: 12345678
POSTGRES_USER: postgres
POSTGRES_DB: test
TZ: Asia/Shanghai
ports:
- 5432:5432
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
# MSSQL backend server.
# docker run \
# -p 1433:1433 \
# -e ACCEPT_EULA=Y \
# -e SA_PASSWORD=LoremIpsum86 \
# -e MSSQL_USER=root \
# -e MSSQL_PASSWORD=LoremIpsum86 \
# mcr.microsoft.com/mssql/server:2022-latest
mssql:
image: mcr.microsoft.com/mssql/server:2022-latest
env:
TZ: Asia/Shanghai
ACCEPT_EULA: Y
MSSQL_SA_PASSWORD: LoremIpsum86
ports:
- 1433:1433
options: >-
--health-cmd="/opt/mssql-tools18/bin/sqlcmd -S localhost -U sa -P ${MSSQL_SA_PASSWORD} -N -C -l 30 -Q \"SELECT 1\" || exit 1"
--health-start-period 10s
--health-interval 10s
--health-timeout 5s
--health-retries 10
# ClickHouse backend server.
# docker run -d --name clickhouse \
# -p 9000:9000 -p 8123:8123 -p 9001:9001 \
# clickhouse/clickhouse-server:24.11.1.2557-alpine
clickhouse-server:
image: clickhouse/clickhouse-server:24.11.1.2557-alpine
ports:
- 9000:9000
- 8123:8123
- 9001:9001
# Polaris backend server.
# docker run -d --name polaris \
# -p 8090:8090 -p 8091:8091 -p 8093:8093 -p 9090:9090 -p 9091:9091 \
# polarismesh/polaris-standalone:v1.17.2
polaris:
image: polarismesh/polaris-standalone:v1.17.2
ports:
- 8090:8090
- 8091:8091
- 8093:8093
- 9090:9090
- 9091:9091
# Oracle 11g server.
# docker run \
# -e ORACLE_ALLOW_REMOTE=true \
# -e ORACLE_SID=XE \
# -e ORACLE_DB_USER_NAME=system \
# -e ORACLE_DB_PASSWORD=oracle \
# -p 1521:1521 \
# loads/oracle-xe-11g-r2:11.2.0
oracle-server:
image: loads/oracle-xe-11g-r2:11.2.0
env:
ORACLE_ALLOW_REMOTE: true
ORACLE_SID: XE
ORACLE_DB_USER_NAME: system
ORACLE_DB_PASSWORD: oracle
ports:
- 1521:1521
# dm8 server
# docker run -p 5236:5236 loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
dm-server:
image: loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
ports:
- 5236:5236
zookeeper:
image: zookeeper:3.8
ports:
- 2181:2181
steps:
# TODO: szenius/set-timezone update to node16
# sudo ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
- name: Setup Timezone
uses: szenius/set-timezone@v2.0
with:
timezoneLinux: "Asia/Shanghai"
- name: Checkout Repository
uses: actions/checkout@v5
- name: Start Apollo Containers
run: docker compose -f ".github/workflows/apollo/docker-compose.yml" up -d --build
- name: Start Nacos Containers
run: docker compose -f ".github/workflows/nacos/docker-compose.yml" up -d --build
- name: Start Redis Cluster Containers
run: docker compose -f ".github/workflows/redis/docker-compose.yml" up -d --build
- name: Start Consul Containers
run: docker compose -f ".github/workflows/consul/docker-compose.yml" up -d --build
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache-dependency-path: '**/go.sum'
- name: Install Protoc
uses: arduino/setup-protoc@v3
with:
version: "31.x"
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Install the protocol compiler plugins for Go
run: |
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
export PATH="$PATH:$(go env GOPATH)/bin"
- name: Before Script
run: bash .github/workflows/scripts/before_script.sh
- name: Build & Test
if: ${{ (github.event_name == 'push' && github.ref != 'refs/heads/master') || github.event_name == 'pull_request' }}
run: bash .github/workflows/scripts/ci-main.sh
- name: Build & Test & Coverage
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
run: bash .github/workflows/scripts/ci-main.sh coverage
- name: Stop Redis Cluster Containers
run: docker compose -f ".github/workflows/redis/docker-compose.yml" down
- name: Stop Apollo Containers
run: docker compose -f ".github/workflows/apollo/docker-compose.yml" down
- name: Stop Nacos Containers
run: docker compose -f ".github/workflows/nacos/docker-compose.yml" down
- name: Stop Consul Containers
run: docker compose -f ".github/workflows/consul/docker-compose.yml" down
- name: Report Coverage
uses: codecov/codecov-action@v4
# Only report coverage on the latest go version
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && matrix.go-version == env.LATEST_GO_VERSION }}
with:
flags: go-${{ matrix.go-version }}-${{ matrix.goarch }}
token: ${{ secrets.CODECOV_TOKEN }}

72
.github/workflows/ci-sub.yml vendored Normal file
View File

@ -0,0 +1,72 @@
# The sub codes build and unit testing running workflow.
# It maintains the ci of unimportant packages.
name: GoFrame Sub CI
on:
push:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
pull_request:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
env:
TZ: "Asia/Shanghai"
# for unit testing cases of some components that only execute on the latest go version.
LATEST_GO_VERSION: "1.25"
jobs:
code-test:
strategy:
matrix:
# 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
# When adding new go version to the list, make sure:
# 1. Update the `LATEST_GO_VERSION` env variable.
# 🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥🔥
go-version: [ "1.23", "1.24", "1.25" ]
goarch: [ "386", "amd64" ]
runs-on: ubuntu-latest
steps:
- name: Setup Timezone
uses: szenius/set-timezone@v2.0
with:
timezoneLinux: "Asia/Shanghai"
- name: Checkout Repository
uses: actions/checkout@v5
- name: Start Minikube
uses: medyagh/setup-minikube@master
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
cache-dependency-path: '**/go.sum'
- name: Before Script
run: bash .github/workflows/scripts/before_script.sh
- name: Build & Test
run: bash .github/workflows/scripts/ci-sub.sh

100
.github/workflows/codeql.yml vendored Normal file
View File

@ -0,0 +1,100 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: [ "master", "develop" ]
pull_request:
branches: [ "master", "develop" ]
schedule:
- cron: '0 21 * * *'
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
- language: go
build-mode: autobuild
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{matrix.language}}"

7
.github/workflows/consul/client.json vendored Normal file
View File

@ -0,0 +1,7 @@
{
"node_name": "consul-client",
"data_dir": "/consul/data",
"retry_join":[
"consul-server"
]
}

View File

@ -0,0 +1,31 @@
version: '3.7'
services:
consul-server:
image: consul:1.15
container_name: consul-server
restart: always
volumes:
- ./server.json:/consul/config/server.json:ro
networks:
- consul
ports:
- "8500:8500"
- "8600:8600/tcp"
- "8600:8600/udp"
command: "agent"
consul-client:
image: consul:1.15
container_name: consul-client
restart: always
volumes:
- ./client.json:/consul/config/client.json:ro
networks:
- consul
command: "agent"
networks:
consul:
driver: bridge

12
.github/workflows/consul/server.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"node_name": "consul-server",
"server": true,
"bootstrap" : true,
"ui_config": {
"enabled" : true
},
"data_dir": "/consul/data",
"addresses": {
"http" : "0.0.0.0"
}
}

View File

@ -0,0 +1,61 @@
name: Format Code on Push
on:
push
jobs:
format-code:
strategy:
matrix:
go-version: [ 'stable' ]
name: format-code-by-gci
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: Install gci
run: go install github.com/daixiang0/gci@latest
- name: Run gci
run: |
gci write --custom-order \
--skip-generated \
--skip-vendor \
-s standard \
-s blank \
-s default \
-s dot \
-s "prefix(github.com/gogf/gf/v2)" \
-s "prefix(github.com/gogf/gf/cmd)" \
-s "prefix(github.com/gogf/gf/contrib)" \
-s "prefix(github.com/gogf/gf/example)" \
./
- name: Check for changes
run: |
if [[ -n "$(git status --porcelain)" ]]; then
echo "HAS_CHANGES=true" >> $GITHUB_ENV
else
echo "HAS_CHANGES=false" >> $GITHUB_ENV
fi
- name: Configure Git
run: |
if [[ "$HAS_CHANGES" == 'true' ]]; then
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
else
echo "HAS_CHANGES= $HAS_CHANGES "
fi
- name: Commit and push changes
run: |
if [[ "$HAS_CHANGES" == 'true' ]]; then
git add .
git commit -m "Apply gci import order changes"
git push origin ${{ github.event.pull_request.head.ref }}
else
echo "No change to commit push"
fi
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,199 +0,0 @@
name: GoFrame Main CI
on:
push:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
pull_request:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
env:
TZ: "Asia/Shanghai"
jobs:
code-test:
runs-on: ubuntu-latest
# Service containers to run with `code-test`
services:
# Redis backend server.
redis:
image : loads/redis:7.0
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
# Maps tcp port 6379 on service container to the host
- 6379:6379
# MySQL backend server.
mysql:
image: loads/mysql:5.7
env:
MYSQL_DATABASE : test
MYSQL_ROOT_PASSWORD: 12345678
ports:
# Maps tcp port 3306 on service container to the host
- 3306:3306
# PostgreSQL backend server.
# docker run -d --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=12345678 -e POSTGRES_USER=postgres -e POSTGRES_DB=test -v postgres:/Users/john/Temp/postgresql/data loads/postgres:13
postgres:
image: loads/postgres:13
env:
POSTGRES_PASSWORD: 12345678
POSTGRES_USER: postgres
POSTGRES_DB: test
TZ: Asia/Shanghai
ports:
- 5432:5432
# Set health checks to wait until postgres has started
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
# MSSQL backend server.
mssql:
image: loads/mssqldocker:14.0.3391.2
env:
ACCEPT_EULA: Y
SA_PASSWORD: LoremIpsum86
MSSQL_DB: test
MSSQL_USER: root
MSSQL_PASSWORD: LoremIpsum86
ports:
- 1433:1433
options: >-
--health-cmd="/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P LoremIpsum86 -l 30 -Q \"SELECT 1\" || exit 1"
--health-start-period 10s
--health-interval 10s
--health-timeout 5s
--health-retries 10
# ClickHouse backend server.
# docker run -d --name clickhouse -p 9000:9000 -p 8123:8123 -p 9001:9001 loads/clickhouse-server:22.1.3.7
clickhouse-server:
image: loads/clickhouse-server:22.1.3.7
ports:
- 9000:9000
- 8123:8123
- 9001:9001
# Polaris backend server.
polaris:
image: loads/polaris-server-standalone:1.11.2
ports:
- 8090:8090
- 8091:8091
- 8093:8093
# Oracle 11g server
oracle-server:
image: loads/oracle-xe-11g-r2:11.2.0
env:
ORACLE_ALLOW_REMOTE: true
ORACLE_SID: XE
ORACLE_DB_USER_NAME: system
ORACLE_DB_PASSWORD: oracle
ports:
- 1521:1521
# dm8 server
# docker run -d --name dm -p 5236:5236 loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
dm-server:
image: loads/dm:v8.1.2.128_ent_x86_64_ctm_pack4
ports:
- 5236:5236
zookeeper:
image: loads/zookeeper:3.8
ports:
- 2181:2181
strategy:
matrix:
go-version: [ "1.15", "1.16", "1.17", "1.18" ]
goarch: [ "386", "amd64" ]
steps:
# TODO: szenius/set-timezone update to node16
- name: Setup Timezone
uses: szenius/set-timezone@v1.1
with:
timezoneLinux: "Asia/Shanghai"
- name: Checkout Repository
uses: actions/checkout@v3
- name: Start Apollo Containers
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" up -d --build
- name: Start Nacos Containers
run: docker-compose -f ".github/workflows/nacos/docker-compose.yml" up -d --build
- name: Start Redis Cluster Containers
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" up -d --build
- name: Start Minikube
uses: medyagh/setup-minikube@master
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v3
with:
go-version: ${{ matrix.go-version }}
- name: Setup Golang caches
uses: actions/cache@v3
with:
path: |
~/go/pkg/mod
~/.cache/go-build
~/Library/Caches/go-build
~\AppData\Local\go-build
key: ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
restore-keys: |
${{ runner.os }}-go-${{ matrix.go-version }}-
- name: Before Script
run: bash .github/workflows/before_script.sh
- name: Build & Test
run: bash .github/workflows/build_and_test.sh
- name: Stop Redis Cluster Containers
run: docker-compose -f ".github/workflows/redis/docker-compose.yml" down
- name: Stop Apollo Containers
run: docker-compose -f ".github/workflows/apollo/docker-compose.yml" down
- name: Stop Nacos Containers
run: docker-compose -f ".github/workflows/nacos/docker-compose.yml" down
- name: Report Coverage
uses: codecov/codecov-action@v3
with:
flags: go-${{ matrix.go-version }}-${{ matrix.goarch }}

28
.github/workflows/gitee-sync.yml vendored Normal file
View File

@ -0,0 +1,28 @@
on:
push:
branches:
- master
tags:
- "*"
name: Sync to Gitee
jobs:
run:
name: Run
runs-on: ubuntu-latest
steps:
- name: Checkout source code
uses: actions/checkout@v5
- name: Mirror GitHub to Gitee
uses: Yikun/hub-mirror-action@v1.4
with:
src: github/gogf
dst: gitee/johng
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
src_account_type: org
dst_account_type: user
timeout: 600
debug: true
force_update: true
static_list: "gf"

View File

@ -1,50 +1,52 @@
# Tencent is pleased to support the open source community by making Polaris available.
# Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
#
# Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
#
# Licensed under the BSD 3-Clause License (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://opensource.org/licenses/BSD-3-Clause
#
# 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.
# This Source Code Form is subject to the terms of the MIT License.
# If a copy of the MIT was not distributed with this file,
# You can obtain one at https://github.com/gogf/gf.
name: GolangCI-Lint
name: golangci-lint
on:
push:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
- feat/**
pull_request:
branches:
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
- master
- develop
- personal/**
- feature/**
- enhance/**
- fix/**
- feat/**
jobs:
golangci:
golang-ci:
strategy:
matrix:
go-version: [1.15.x,1.16.x,1.17.x,1.18.x]
name: golangci-lint
go-version: [ "stable" ]
name: golang-ci-lint
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@v3
- uses: actions/checkout@v3
- name: golangci-lint
uses: golangci/golangci-lint-action@v3.3.0
- name: Checkout
uses: actions/checkout@v5
with:
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
version: latest
args: --timeout 3m0s
fetch-depth: 0
- name: Setup Golang ${{ matrix.go-version }}
uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go-version }}
- name: golang-ci-lint
uses: golangci/golangci-lint-action@v8
with:
# Required: specify the golangci-lint version without the patch version to always use the latest patch.
only-new-issues: true
skip-cache: true
github-token: ${{ secrets.GITHUB_TOKEN }}
args: --config=.golangci.yml -v

View File

@ -1,12 +1,12 @@
# 规则描述每天凌晨3点(GMT+8)执行一次将最近7天没有活跃且非BUG的ISSUE设置标签:inactive
# Rule description: Execute the ISSUE once a day at 3 a.m. (GMT+8) and set the non-bug issue that has not been active in the last 7 days to inactive
name: Issue Check Inactive
on:
schedule:
- cron: "0 19 * * *"
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
env: # Set environment variables
TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)
permissions:
contents: read
@ -14,8 +14,8 @@ permissions:
jobs:
issue-check-inactive:
permissions:
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: check-inactive
@ -23,6 +23,6 @@ jobs:
with:
actions: 'check-inactive'
inactive-label: 'inactive'
inactive-day: 7
inactive-day: 30
issue-state: open
exclude-labels: 'bug,planned,$exclude-empty'

View File

@ -1,12 +1,12 @@
# 规则描述每天凌晨4点(GMT+8)执行一次将最近30天没有活跃且非BUGISSUE关闭
# RULE DESCRIPTION: EXECUTED ONCE A DAY AT 4 A.M. (GMT+8) TO CLOSE NON-BUG ISSUES THAT HAVE NOT BEEN ACTIVE IN THE LAST 30 DAYS
name: Issue Close Inactive
on:
schedule:
- cron: "0 20 * * *"
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
env: # Set environment variables
TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)
jobs:
close-issues:

View File

@ -1,4 +1,4 @@
## 规则描述当issue被标记为help wanted 时,增加评论
## Rule description: Add comments when an issue is marked as help wanted
name: Issue Labeled
@ -6,8 +6,8 @@ on:
issues:
types: [labeled]
env: # 设置环境变量
TZ: Asia/Shanghai # 时区(设置时区可使页面中的`最近更新时间`使用时区时间)
env: # Set environment variables
TZ: Asia/Shanghai # Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)
jobs:
reply-labeled:

View File

@ -1,4 +1,4 @@
# 规则描述在issue没有活跃且尚未被关闭期间若issue作者更新或评论该ISSUE则移除其inactive标签
# Rule description: If an issue author updates or comments on an issue while it is not active and has not been closed, the inactive tag will be removed
name: Issue Remove Inactive
on:
@ -7,8 +7,8 @@ on:
issue_comment:
types: [created, edited]
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
env: # Set environment variables
TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)
permissions:
contents: read
@ -17,13 +17,13 @@ jobs:
issue-remove-inactive:
permissions:
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
# pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: remove inactive
if: github.event.issue.state == 'open' && github.actor == github.event.issue.user.login
if: github.event.issue.state == 'open'
uses: actions-cool/issues-helper@v3
with:
actions: 'remove-labels'
issue-number: ${{ github.event.issue.number }}
labels: 'inactive'
labels: 'inactive'

View File

@ -1,4 +1,4 @@
# 规则描述将需要提供更多细节且暂未关闭的issue在issue作者评论后移除 need more details 标签
# Rule Description: For issues that need more details and are not yet closed, remove the "need more details" tag after the issue author comments
name: Issue Remove Need More Details
on:
@ -7,8 +7,8 @@ on:
issue_comment:
types: [created, edited]
env: # 设置环境变量
TZ: Asia/Shanghai #时区(设置时区可使页面中的`最近更新时间`使用时区时间)
env: # Set environment variables
TZ: Asia/Shanghai #Time zone (setting the time zone allows the 'Last Updated' on the page to use the time zone)
permissions:
contents: read
@ -16,8 +16,8 @@ permissions:
jobs:
issue-remove-need-more-details:
permissions:
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
issues: write # for actions-cool/issues-helper to update issues
# pull-requests: write # for actions-cool/issues-helper to update PRs
runs-on: ubuntu-latest
steps:
- name: remove need more details

19
.github/workflows/issue-translator.yml vendored Normal file
View File

@ -0,0 +1,19 @@
# https://github.com/usthe/issues-translate-action
name: 'Issue Translator'
on:
issue_comment:
types: [created]
issues:
types: [opened]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: usthe/issues-translate-action@v2.7
with:
IS_MODIFY_TITLE: true
# not require, default false. Decide whether to modify the issue title
# if true, the robot account @Issues-translate-bot must have modification permissions,
# invite @Issues-translate-bot to your project or use your custom bot.
CUSTOM_BOT_NOTE: Bot detected the issue body's language is not English, translate it automatically. 👯👭🏻🧑‍🤝‍🧑👫🧑🏿‍🤝‍🧑🏻👩🏾‍🤝‍👨🏿👬🏿

View File

@ -2,7 +2,7 @@ version: "3.8"
services:
nacos:
image: loads/nacos-server:v2.1.2
image: nacos/nacos-server:v2.1.2
container_name: nacos
env_file:
- ./env/nacos.env
@ -15,25 +15,9 @@ services:
interval: 5s
timeout: 3s
retries: 10
depends_on:
mysql:
condition: service_healthy
mysql:
build:
context: .
dockerfile: ./image/mysql/Dockerfile
container_name: mysql
env_file:
- ./env/mysql.env
healthcheck:
test: [ "CMD", "mysqladmin" ,"ping", "-h", "localhost" ]
interval: 5s
timeout: 3s
retries: 10
initializer:
image: loads/curl:latest
image: alpine/curl:latest
depends_on:
nacos:
condition: service_healthy

View File

@ -1,4 +0,0 @@
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=nacos_devtest
MYSQL_USER=nacos
MYSQL_PASSWORD=nacos

View File

@ -1,9 +1,2 @@
PREFER_HOST_MODE=hostname
MODE=standalone
SPRING_DATASOURCE_PLATFORM=mysql
MYSQL_SERVICE_HOST=mysql
MYSQL_SERVICE_DB_NAME=nacos_devtest
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_USER=nacos
MYSQL_SERVICE_PASSWORD=nacos
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true

View File

@ -1,5 +0,0 @@
FROM loads/mysql:5.7
ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/nacos-mysql.sql
RUN chown -R mysql:mysql /docker-entrypoint-initdb.d/nacos-mysql.sql
EXPOSE 3306
CMD ["mysqld", "--character-set-server=utf8mb4", "--collation-server=utf8mb4_unicode_ci"]

View File

@ -1,4 +1,4 @@
name: GoFrame CLI Build Release
name: GoFrame Release
on:
push:
@ -16,12 +16,12 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Github Code
uses: actions/checkout@v2
uses: actions/checkout@v5
- name: Set Up Golang Environment
uses: actions/setup-go@v2
uses: actions/setup-go@v5
with:
go-version: 1.17
go-version: 1.25
- name: Build CLI Binary
run: |
@ -34,7 +34,7 @@ jobs:
- name: Build CLI Binary For All Platform
run: |
cd cmd/gf
gf build main.go -n gf -a all -s all
gf build main.go -n gf -a all -s linux,windows,darwin,freebsd,netbsd,openbsd -p temp
- name: Move Files Before Release
run: |
@ -47,18 +47,18 @@ jobs:
- name: Create Github Release
id: create_release
uses: actions/create-release@v1
uses: softprops/action-gh-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: GoFrame Release ${{ github.ref }}
name: GoFrame Release ${{ github.ref_name }}
draft: false
prerelease: false
- name: Upload Release Asset
id: upload-release-asset
uses: alexellis/upload-assets@0.2.2
uses: alexellis/upload-assets@0.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:

80
.github/workflows/scorecard.yml vendored Normal file
View File

@ -0,0 +1,80 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '0 21 * * *'
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
# Uncomment the permissions below if installing in a private repository.
# contents: read
# actions: read
steps:
- name: "Checkout code"
uses: actions/checkout@v4.2.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@v2.4.1
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecard on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
# file_mode: git
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@v4.6.1
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard (optional).
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif

View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Install gci
echo "Installing gci..."
go install github.com/daixiang0/gci@latest
# Check if the GCI is installed successfully
if ! command -v gci &> /dev/null
then
echo "gci could not be installed. Please check your Go setup."
exit 1
fi
# Use GCI to format the code
echo "Running gci to format code..."
gci write \
--custom-order \
--skip-generated \
--skip-vendor \
-s standard \
-s blank \
-s default \
-s dot \
-s "prefix(github.com/gogf/gf/v2)" \
-s "prefix(github.com/gogf/gf/cmd)" \
-s "prefix(github.com/gogf/gf/contrib)" \
-s "prefix(github.com/gogf/gf/example)" \
./
# Check the code for changes
git diff --name-only --exit-code || if [ $? != 0 ]; then echo "Notice: gci check failed, please gci before pr." && exit 1; fi
echo "gci check pass."
# Add the local domain name to `/etc/hosts`
echo "Adding local domain to /etc/hosts..."
sudo echo "127.0.0.1 local" | sudo tee -a /etc/hosts

66
.github/workflows/scripts/ci-main.sh vendored Normal file
View File

@ -0,0 +1,66 @@
#!/usr/bin/env bash
coverage=$1
# update code of submodules
git clone https://github.com/gogf/examples
# update go.mod in examples directory to replace github.com/gogf/gf packages with local directory
bash .github/workflows/scripts/replace_examples_gomod.sh
# find all path that contains go.mod.
for file in `find . -name go.mod`; do
dirpath=$(dirname $file)
echo $dirpath
# ignore mssql tests as its docker service failed
# TODO remove this ignoring codes after the mssql docker service OK
if [ "mssql" = $(basename $dirpath) ]; then
continue 1
fi
# package kubecm was moved to sub ci procedure.
if [ "kubecm" = $(basename $dirpath) ]; then
continue 1
fi
# Check if it's a contrib directory or examples directory
if [[ $dirpath =~ "/contrib/" ]] || [[ $dirpath =~ "/examples/" ]]; then
# Check if go version meets the requirement
if ! go version | grep -qE "go${LATEST_GO_VERSION}"; then
echo "ignore path $dirpath as go version is not ${LATEST_GO_VERSION}: $(go version)"
continue 1
fi
# If it's examples directory, only build without tests
if [[ $dirpath =~ "/examples/" ]]; then
echo "the examples directory only needs to be built, not unit tests and coverage tests."
cd $dirpath
go mod tidy
go build ./...
cd -
continue 1
fi
fi
if [[ $file =~ "/testdata/" ]]; then
echo "ignore testdata path $file"
continue 1
fi
cd $dirpath
go mod tidy
go build ./...
# test with coverage
if [ "${coverage}" = "coverage" ]; then
go test ./... -race -coverprofile=coverage.out -covermode=atomic -coverpkg=./...,github.com/gogf/gf/... || exit 1
if grep -q "/gogf/gf/.*/v2" go.mod; then
sed -i "s/gogf\/gf\(\/.*\)\/v2/gogf\/gf\/v2\1/g" coverage.out
fi
else
go test ./... -race || exit 1
fi
cd -
done

68
.github/workflows/scripts/ci-sub.sh vendored Normal file
View File

@ -0,0 +1,68 @@
#!/usr/bin/env bash
coverage=$1
# Function to compare version numbers
version_compare() {
local ver1=$1
local ver2=$2
# Remove 'go' prefix and 'v' if present
ver1=$(echo "$ver1" | sed 's/^go//; s/^v//')
ver2=$(echo "$ver2" | sed 's/^go//; s/^v//')
# Split versions into major.minor format
local major1=$(echo "$ver1" | cut -d. -f1)
local minor1=$(echo "$ver1" | cut -d. -f2)
local major2=$(echo "$ver2" | cut -d. -f1)
local minor2=$(echo "$ver2" | cut -d. -f2)
# Compare versions: return 0 if ver1 <= ver2, 1 otherwise
if [ "$major1" -lt "$major2" ]; then
return 0
elif [ "$major1" -eq "$major2" ] && [ "$minor1" -le "$minor2" ]; then
return 0
else
return 1
fi
}
# Get current Go version
current_go_version=$(go version | grep -oE 'go[0-9]+\.[0-9]+')
# find all path that contains go.mod.
for file in `find . -name go.mod`; do
dirpath=$(dirname $file)
echo "Processing: $dirpath"
# Only process kubecm directory, skip others
if [ "kubecm" != $(basename $dirpath) ]; then
echo " Skipping: not kubecm directory"
continue
fi
cd $dirpath
# Read Go version requirement from go.mod
if [ -f "go.mod" ]; then
go_mod_version=$(grep '^go ' go.mod | awk '{print $2}' | head -1)
if [ -n "$go_mod_version" ]; then
echo " go.mod requires: go$go_mod_version"
echo " current version: $current_go_version"
# Check if go.mod version requirement is satisfied by current Go version
if version_compare "$go_mod_version" "$current_go_version"; then
echo " ✓ Version requirement satisfied, proceeding with build and test"
go mod tidy
go build ./...
go test ./... -race || exit 1
else
echo " ✗ Current Go version ($current_go_version) does not meet requirement (go$go_mod_version), skipping"
fi
fi
fi
cd -
done

View File

@ -0,0 +1,81 @@
#!/usr/bin/env bash
# Get the absolute path to the repository root
repo_root=$(pwd)
workdir=$repo_root/examples
echo "Prepare to process go.mod files in the ${workdir} directory"
# Check if examples directory exists
if [ ! -d "${workdir}" ]; then
echo "Error: examples directory not found at ${workdir}"
exit 1
fi
# Check if find command is available
if ! command -v find &> /dev/null; then
echo "Error: find command not found!"
exit 1
fi
for file in `find ${workdir} -name go.mod`; do
goModPath=$(dirname $file)
echo ""
echo "Processing dir: $goModPath"
# Calculate relative path to root
# First get the relative path from go.mod to repo root
relativePath=""
current="$goModPath"
while [ "$current" != "$repo_root" ]; do
relativePath="../$relativePath"
current=$(dirname "$current")
done
relativePath=${relativePath%/} # Remove trailing slash
echo "Relative path to root: $relativePath"
# Get all github.com/gogf/gf dependencies
# Use awk to get package names without version numbers
dependencies=$(awk '/^[[:space:]]*github\.com\/gogf\/gf\// {print $1}' "$file" | sort -u)
if [ -n "$dependencies" ]; then
echo "Found GoFrame dependencies:"
echo "$dependencies"
echo "Adding replace directives..."
# Create temporary file
temp_file="${file}.tmp"
# Remove existing replace directives and copy to temp file
sed '/^replace.*github\.com\/gogf\/gf.*/d' "$file" > "$temp_file"
# Add new replace block
echo "" >> "$temp_file"
echo "replace (" >> "$temp_file"
while IFS= read -r dep; do
# Skip empty lines
[ -z "$dep" ] && continue
# Calculate the relative path for the replacement
if [[ "$dep" == "github.com/gogf/gf/v2" ]]; then
replacement="$relativePath"
else
# Extract the path after v2 and remove trailing version
subpath=$(echo "$dep" | sed -E 's/github\.com\/gogf\/gf\/(contrib\/[^/]+\/[^/]+)\/v2.*/\1/')
replacement="$relativePath/$subpath"
fi
echo " $dep => $replacement/" >> "$temp_file"
done <<< "$dependencies"
echo ")" >> "$temp_file"
# Replace original file with temporary file
mv "$temp_file" "$file"
echo "Replace directives added to $file"
else
echo "No GoFrame dependencies found in $file"
fi
done
echo "\nAll go.mod files have been processed successfully."

50
.github/workflows/scripts/update_version.sh vendored Executable file
View File

@ -0,0 +1,50 @@
#!/usr/bin/env bash
# Check if the number of parameters is 2
if [ $# -ne 2 ]; then
echo "Invalid parameters, please execute in format: version.sh [directory] [version]"
echo "Example: version.sh ./contrib v1.0.0"
exit 1
fi
# Check if the first parameter is a directory and exists
if [ ! -d "$1" ]; then
echo "Error: Directory does not exist"
exit 1
fi
# Check if the second parameter starts with 'v'
if [[ "$2" != v* ]]; then
echo "Error: Version number does not start with 'v'"
exit 1
fi
workdir=$1
newVersion=$2
echo "Preparing to replace version numbers in all go.mod files under ${workdir} directory to ${newVersion}"
# Check if file exists
if [ -f "go.work" ]; then
# File exists, rename it
mv go.work go.work.${newVersion}
echo "Backup go.work file to avoid affecting the upgrade"
fi
for file in `find ${workdir} -name go.mod`; do
goModPath=$(dirname $file)
echo ""
echo "processing dir: $goModPath"
cd $goModPath
go mod tidy
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}" -m all | grep "^github.com/gogf/gf"
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}" -m all | grep "^github.com/gogf/gf" | xargs -L1 go get -v
go mod tidy
cd -
done
if [ -f "go.work.${newVersion}" ]; then
# File exists, rename it back
mv go.work.${newVersion} go.work
echo "Restore go.work file"
fi

View File

@ -4,27 +4,56 @@ on:
push:
# Sequence of patterns matched against refs/tags
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
env:
TZ: Asia/Shanghai
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
jobs:
build:
name: Auto Creating Tags
runs-on: ubuntu-latest
steps:
- name: Checkout Github Code
uses: actions/checkout@v2
- name: Auto Creating Tags
uses: actions/checkout@v5
- name: Auto Creating Tags For Contrib Packages
run: |
git config --global user.email "tagrobot@goframe.org"
git config --global user.name "TagRobot"
# auto create tags for contrib packages.
for file in `find contrib -name go.mod`; do
tag=$(dirname $file)/$GITHUB_REF_NAME
tag=$(dirname $file)/${{ github.ref_name }}
git tag $tag
git push origin $tag
done
- name: update dependencies
run: |
go env -w GOPRIVATE=github.com/gogf/gf
.github/workflows/scripts/update_version.sh ./cmd/gf ${{ github.ref_name }}
- name: Create Pull Request
uses: peter-evans/create-pull-request@v4
with:
commit-message: 'update gf cli to ${{ github.ref_name }}'
title: 'fix: update gf cli to ${{ github.ref_name }}'
base: master
branch: fix/${{ github.ref_name }}
delete-branch: true
- name: Commit & Push changes
uses: actions-js/push@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: fix/${{ github.ref_name }}
author_name: TagRobot
author_email: tagrobot@goframe.org
message: 'fix: update gf cli to ${{ github.ref_name }}'
- name: Auto Creating Tags For cli tool
run: |
git config --global user.email "tagrobot@goframe.org"
git config --global user.name "TagRobot"
# auto create tag for cli tool
for file in `find cmd -name go.mod -not -path "*/testdata/*"`; do
tag=$(dirname $file)/${{ github.ref_name }}
git tag $tag
git push origin $tag
done

13
.gitignore vendored
View File

@ -7,12 +7,21 @@
.settings/
.vscode/
vendor/
pkg/
bin/
**/.DS_Store
.test/
cmd/gf/main
cmd/gf/gf
temp/
example/log
go.work
go.work.sum
temp/
!cmd/gf/go.work
.windsurfrules
# Ignore for docs
node_modules
.docusaurus
output
.example/
.golangci.bck.yml

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "examples"]
path = examples
url = git@github.com:gogf/examples.git

View File

@ -1,282 +1,220 @@
## This file contains all available configuration options
## with their default values.
# See https://github.com/golangci/golangci-lint#config-file
# See https://golangci-lint.run/usage/configuration/
# Options for analysis running.
version: "2"
run:
# Exit code when at least one issue was found.
# Default: 1
concurrency: 4
go: "1.25"
modules-download-mode: readonly
issues-exit-code: 2
# Include test files or not.
# Default: true
tests: false
# Which dirs to skip: issues from them won't be reported.
# Can use regexp here: `generated.*`, regexp is applied on full path.
# Default value is empty list,
# but default dirs are skipped independently of this option's value (see skip-dirs-use-default).
# "/" will be replaced by current OS file path separator to properly work on Windows.
skip-dirs: []
# Which files to skip: they will be analyzed, but issues from them won't be reported.
# Default value is empty list,
# but there is no need to include all autogenerated files,
# we confidently recognize autogenerated files.
# If it's not please let us know.
# "/" will be replaced by current OS file path separator to properly work on Windows.
skip-files: []
# Main linters configurations.
# See https://golangci-lint.run/usage/linters
allow-parallel-runners: true
allow-serial-runners: true
linters:
# Disable all default enabled linters.
disable-all: true
# Custom enable linters we want to use.
default: none
enable:
- errcheck # Errcheck is a program for checking for unchecked errors in go programs.
- errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occasions, where the check for the returned error can be omitted.
- funlen # Tool for detection of long functions
- goconst # Finds repeated strings that could be replaced by a constant
- gocritic # Provides diagnostics that check for bugs, performance and style issues.
- gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification
- gosimple # Linter for Go source code that specializes in simplifying code
- govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
- misspell # Finds commonly misspelled English words in comments
- nolintlint # Reports ill-formed or insufficient nolint directives
- revive # Fast, configurable, extensible, flexible, and beautiful linter for Go. Drop-in replacement of golint.
- staticcheck # It's a set of rules from staticcheck. It's not the same thing as the staticcheck binary.
- typecheck # Like the front-end of a Go compiler, parses and type-checks Go code
- usestdlibvars # A linter that detect the possibility to use variables/constants from the Go standard library.
- whitespace # Tool for detection of leading and trailing whitespace
issues:
exclude-rules:
# helpers in tests often (rightfully) pass a *testing.T as their first argument
- path: _test\.go
text: "context.Context should be the first parameter of a function"
linters:
- revive
# Yes, they are, but it's okay in a test
- path: _test\.go
text: "exported func.*returns unexported type.*which can be annoying to use"
linters:
- revive
# https://github.com/go-critic/go-critic/issues/926
- linters:
- gocritic
text: "unnecessaryDefer:"
# https://golangci-lint.run/usage/linters
linters-settings:
# https://golangci-lint.run/usage/linters/#misspell
misspell:
locale: US
ignore-words:
- cancelled
# https://golangci-lint.run/usage/linters/#revive
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md
revive:
ignore-generated-header: true
severity: error
- errcheck
- errchkjson
- funlen
- goconst
- gocritic
- govet
- misspell
- nolintlint
- revive
- staticcheck
- usestdlibvars
- whitespace
settings:
funlen:
lines: 340
statements: -1
goconst:
match-constant: false
min-len: 4
min-occurrences: 30
numbers: true
min: 5
max: 20
ignore-calls: false
gocritic:
disabled-checks:
- ifElseChain
- assignOp
- appendAssign
- singleCaseSwitch
- regexpMust
- typeSwitchVar
- elseif
govet:
disable:
- asmdecl
- assign
- atomic
- atomicalign
- bools
- buildtag
- cgocall
- composites
- copylocks
- deepequalerrors
- errorsas
- fieldalignment
- findcall
- framepointer
- httpresponse
- ifaceassert
- loopclosure
- lostcancel
- nilfunc
- nilness
- reflectvaluecompare
- shift
- shadow
- sigchanyzer
- sortslice
- stdmethods
- stringintconv
- structtag
- testinggoroutine
- tests
- unmarshal
- unreachable
- unsafeptr
- unusedwrite
enable-all: true
settings:
printf:
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
unusedresult:
funcs:
- pkg.MyFunc
- context.WithCancel
stringmethods:
- MyMethod
misspell:
locale: US
ignore-rules:
- cancelled
revive:
severity: error
rules:
- name: atomic
- name: line-length-limit
arguments:
- 380
severity: error
- name: unhandled-error
severity: warning
disabled: true
- name: var-naming
arguments:
- - ID
- URL
- IP
- HTTP
- JSON
- API
- UID
- Id
- Api
- Uid
- Http
- Json
- Ip
- Url
- - VM
severity: warning
disabled: true
- name: string-format
arguments:
- - core.WriteError[1].Message
- /^([^A-Z]|$)/
- must not start with a capital letter
- - fmt.Errorf[0]
- /(^|[^\.!?])$/
- must not end in punctuation
- - panic
- /^[^\n]*$/
- must not contain line breaks
severity: warning
disabled: false
- name: function-result-limit
arguments:
- 4
severity: warning
disabled: false
staticcheck:
checks: [ "all","-S1000","-S1009","-S1016","-S1023","-S1025","-S1029","-S1034","-S1040","-SA1016","-SA1019","-SA1029","-SA4006","-SA4015","-SA6003","-SA9003","-ST1003","-QF1001","-QF1002","-QF1003","-QF1006","-QF1007","-QF1008","-QF1011","-QF1012","-ST1011" ]
initialisms: [ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS" ]
dot-import-whitelist: [ "fmt" ]
http-status-code-whitelist: [ "200", "400", "404", "500" ]
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
- name: atomic
- name: line-length-limit
severity: error
arguments: [ 380 ]
- name: unhandled-error
severity: warning
disabled: true
arguments: []
- name: var-naming
severity: warning
disabled: true
arguments:
# AllowList
- [ "ID","URL","IP","HTTP","JSON","API","UID","Id","Api","Uid","Http","Json","Ip","Url" ]
# DenyList
- [ "VM" ]
- name: string-format
severity: warning
disabled: false
arguments:
- - 'core.WriteError[1].Message'
- '/^([^A-Z]|$)/'
- must not start with a capital letter
- - 'fmt.Errorf[0]'
- '/(^|[^\.!?])$/'
- must not end in punctuation
- - panic
- '/^[^\n]*$/'
- must not contain line breaks
- name: function-result-limit
severity: warning
disabled: false
arguments: [ 4 ]
# https://golangci-lint.run/usage/linters/#funlen
funlen:
# Checks the number of lines in a function.
# If lower than 0, disable the check.
# Default: 60
lines: 330
# Checks the number of statements in a function.
# If lower than 0, disable the check.
# Default: 40
statements: -1
# https://golangci-lint.run/usage/linters/#goconst
goconst:
# Minimal length of string constant.
# Default: 3
min-len: 2
# Minimum occurrences of constant string count to trigger issue.
# Default: 3
# For subsequent optimization, the value is reduced.
min-occurrences: 30
# Ignore test files.
# Default: false
ignore-tests: true
# Look for existing constants matching the values.
# Default: true
match-constant: false
# Search also for duplicated numbers.
# Default: false
numbers: true
# Minimum value, only works with goconst.numbers
# Default: 3
min: 5
# Maximum value, only works with goconst.numbers
# Default: 3
max: 20
# Ignore when constant is not used as function argument.
# Default: true
ignore-calls: false
# https://golangci-lint.run/usage/linters/#gocritic
gocritic:
disabled-checks:
- ifElseChain
- assignOp
- appendAssign
- singleCaseSwitch
- regexpMust
- typeSwitchVar
- elseif
# https://golangci-lint.run/usage/linters/#gosimple
gosimple:
# Select the Go version to target.
# Default: 1.13
# Deprecated: use the global `run.go` instead.
go: "1.15"
# Sxxxx checks in https://staticcheck.io/docs/configuration/options/#checks
# Default: ["*"]
checks: [
"all", "-S1000", "-S1001", "-S1002", "-S1008", "-S1009", "-S1016", "-S1023", "-S1025", "-S1029", "-S1034", "-S1040"
]
# https://golangci-lint.run/usage/linters/#govet
govet:
# Report about shadowed variables.
# Default: false
check-shadowing: true
# Settings per analyzer.
settings:
# Analyzer name, run `go tool vet help` to see all analyzers.
printf:
# Comma-separated list of print function names to check (in addition to default, see `go tool vet help printf`).
# Default: []
funcs:
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf
- (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf
# shadow:
# Whether to be strict about shadowing; can be noisy.
# Default: false
# strict: false
unusedresult:
# Comma-separated list of functions whose results must be used
# (in addition to defaults context.WithCancel,context.WithDeadline,context.WithTimeout,context.WithValue,
# errors.New,fmt.Errorf,fmt.Sprint,fmt.Sprintf,sort.Reverse)
# Default []
funcs:
- pkg.MyFunc
- context.WithCancel
# Comma-separated list of names of methods of type func() string whose results must be used
# (in addition to default Error,String)
# Default []
stringmethods:
- MyMethod
# Enable all analyzers.
# Default: false
enable-all: true
# Disable analyzers by name.
# Run `go tool vet help` to see all analyzers.
# Default: []
disable:
- asmdecl
- assign
- atomic
- atomicalign
- bools
- buildtag
- cgocall
- composites
- copylocks
- deepequalerrors
- errorsas
- fieldalignment
- findcall
- framepointer
- httpresponse
- ifaceassert
- loopclosure
- lostcancel
- nilfunc
- nilness
- reflectvaluecompare
- shift
- shadow
- sigchanyzer
- sortslice
- stdmethods
- stringintconv
- structtag
- testinggoroutine
- tests
- unmarshal
- unreachable
- unsafeptr
- unusedwrite
# https://golangci-lint.run/usage/linters/#staticcheck
staticcheck:
# Select the Go version to target.
# Default: "1.13"
# Deprecated: use the global `run.go` instead.
go: "1.15"
# SAxxxx checks in https://staticcheck.io/docs/configuration/options/#checks
# Default: ["*"]
checks: [ "all","-SA1019","-SA4015","-SA1029","-SA1016","-SA9003","-SA4006","-SA6003" ]
# https://golangci-lint.run/usage/linters/#gofmt
gofmt:
# Simplify code: gofmt with `-s` option.
# Default: true
simplify: true
# Apply the rewrite rules to the source before reformatting.
# https://pkg.go.dev/cmd/gofmt
# Default: []
rewrite-rules: [ ]
# - pattern: 'interface{}'
# replacement: 'any'
# - pattern: 'a[b:len(a)]'
# replacement: 'a[b:]'
- linters:
- revive
path: _test\.go
text: context.Context should be the first parameter of a function
- linters:
- revive
path: _test\.go
text: exported func.*returns unexported type.*which can be annoying to use
- linters:
- gocritic
text: 'unnecessaryDefer:'
- linters:
- goconst
path: (.+)_test\.go
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gci
- gofmt
- goimports
settings:
gci:
sections:
- standard
- blank
- default
- dot
- prefix(github.com/gogf/gf/v2)
- prefix(github.com/gogf/gf/cmd)
- prefix(github.com/gogf/gfcontrib)
- prefix(github.com/gogf/gf/example)
custom-order: true
no-lex-order: false
gofmt:
simplify: true
rewrite-rules:
- pattern: 'interface{}'
replacement: 'any'
- pattern: 'reflect.Ptr'
replacement: 'reflect.Pointer'
- pattern: 'ioutil.ReadAll'
replacement: 'io.ReadAll'
- pattern: 'ioutil.WriteFile'
replacement: 'os.WriteFile'
- pattern: 'ioutil.ReadFile'
replacement: 'os.ReadFile'
- pattern: 'ioutil.NopCloser'
replacement: 'io.NopCloser'
goimports:
local-prefixes:
- github.com/gogf/gf/v2
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$

35
.make_tidy.sh Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env bash
workdir=.
echo "Prepare to tidy all go.mod files in the ${workdir} directory"
# check find command support or not
output=$(find "${workdir}" -name go.mod 2>&1)
if [[ $? -ne 0 ]]; then
echo "Error: please use bash or zsh to run!"
exit 1
fi
for file in `find ${workdir} -name go.mod`; do
goModPath=$(dirname $file)
echo ""
echo "processing dir: $goModPath"
if [[ $goModPath =~ "/testdata/" ]]; then
echo "ignore testdata path $goModPath"
continue 1
fi
if [[ $goModPath =~ "/examples/" ]]; then
echo "ignore examples path $goModPath"
continue 1
fi
cd $goModPath
# Remove indirect dependencies
sed -i '/\/\/ indirect/d' go.mod
go mod tidy
# Remove toolchain line if exists
sed -i '' '/^toolchain/d' go.mod
cd - > /dev/null
done

114
.make_version.sh Executable file
View File

@ -0,0 +1,114 @@
#!/usr/bin/env bash
# Function to detect OS and set sed parameters
setup_sed() {
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS
SED_INPLACE="sed -i ''"
else
# Linux/Windows Git Bash
SED_INPLACE="sed -i"
fi
}
# Initialize sed command
setup_sed
if [ $# -ne 2 ]; then
echo "Parameter exception, please execute in the format of $0 [directory] [version number]"
echo "PS$0 ./ v2.4.0"
exit 1
fi
if [ ! -d "$1" ]; then
echo "Error: Directory does not exist"
exit 1
fi
if [[ "$2" != v* ]]; then
echo "Error: Version number must start with v"
exit 1
fi
workdir=.
newVersion=$2
echo "Prepare to replace the GoFrame library version numbers in all go.mod files in the ${workdir} directory with ${newVersion}"
# check find command support or not
output=$(find "${workdir}" -name go.mod 2>&1)
if [[ $? -ne 0 ]]; then
echo "Error: please use bash or zsh to run!"
exit 1
fi
if [[ true ]]; then
# Use sed to replace the version number in version.go
$SED_INPLACE 's/VERSION = ".*"/VERSION = "'${newVersion}'"/' version.go
# Use sed to replace the version number in README.MD
$SED_INPLACE 's/version=[^"]*/version='${newVersion}'/' README.MD
fi
if [ -f "go.work" ]; then
mv go.work go.work.version.bak
echo "Back up the go.work file to avoid affecting the upgrade"
fi
for file in `find ${workdir} -name go.mod`; do
goModPath=$(dirname $file)
echo ""
echo "processing dir: $goModPath"
if [[ $goModPath =~ "/testdata/" ]]; then
echo "ignore testdata path $goModPath"
continue 1
fi
if [[ $goModPath =~ "/examples/" ]]; then
echo "ignore examples path $goModPath"
continue 1
fi
cd $goModPath
if [ $goModPath = "./cmd/gf" ]; then
mv go.work go.work.version.bak
go mod edit -replace github.com/gogf/gf/v2=../../
go mod edit -replace github.com/gogf/gf/contrib/drivers/clickhouse/v2=../../contrib/drivers/clickhouse
go mod edit -replace github.com/gogf/gf/contrib/drivers/mssql/v2=../../contrib/drivers/mssql
go mod edit -replace github.com/gogf/gf/contrib/drivers/mysql/v2=../../contrib/drivers/mysql
go mod edit -replace github.com/gogf/gf/contrib/drivers/oracle/v2=../../contrib/drivers/oracle
go mod edit -replace github.com/gogf/gf/contrib/drivers/pgsql/v2=../../contrib/drivers/pgsql
go mod edit -replace github.com/gogf/gf/contrib/drivers/sqlite/v2=../../contrib/drivers/sqlite
fi
# Remove indirect dependencies
sed -i '/\/\/ indirect/d' go.mod
go mod tidy
# Remove toolchain line if exists
$SED_INPLACE '/^toolchain/d' go.mod
# Upgrading only GoFrame related libraries, sometimes even if a version number is specified,
# it may not be possible to successfully upgrade. Please confirm before submitting the code
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}" -m all | grep "^github.com/gogf/gf"
go list -f "{{if and (not .Indirect) (not .Main)}}{{.Path}}@${newVersion}{{end}}" -m all | grep "^github.com/gogf/gf" | xargs -L1 go get -v
# Remove indirect dependencies
sed -i '/\/\/ indirect/d' go.mod
go mod tidy
# Remove toolchain line if exists
$SED_INPLACE '/^toolchain/d' go.mod
if [ $goModPath = "./cmd/gf" ]; then
go mod edit -dropreplace github.com/gogf/gf/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/clickhouse/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/mssql/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/mysql/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/oracle/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/pgsql/v2
go mod edit -dropreplace github.com/gogf/gf/contrib/drivers/sqlite/v2
mv go.work.version.bak go.work
fi
cd -
done
if [ -f "go.work.version.bak" ]; then
mv go.work.version.bak go.work
echo "Restore the go.work file"
fi

15
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,15 @@
# Contributing
Thanks for taking the time to join our community and start contributing!
## With issues
- Use the search tool before opening a new issue.
- Please provide source code and commit sha if you found a bug.
- Review existing issues and provide feedback or react to them.
## With pull requests
- Open your pull request against `master`
- Your pull request should have no more than two commits, if not you should squash them.
- It should pass all tests in the available continuous integrations systems such as GitHub CI.
- You should add/modify tests to cover your proposed code changes.
- If your pull request contains a new feature, please document it on the README.

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2017 john@goframe.org https://goframe.org
Copyright (c) 2017 GoFrame Team https://goframe.org
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -1,16 +1,77 @@
SHELL := /bin/bash
# execute "go mod tidy" on all folders that have go.mod file
.PHONY: tidy
tidy:
$(eval files=$(shell find . -name go.mod))
@set -e; \
for file in ${files}; do \
goModPath=$$(dirname $$file); \
cd $$goModPath; \
go mod tidy; \
cd -; \
done
./.make_tidy.sh
# execute "golangci-lint" to check code style
.PHONY: lint
lint:
golangci-lint run
golangci-lint run -c .golangci.yml
# make branch to=v2.4.0
.PHONY: branch
branch:
@set -e; \
newVersion=$(to); \
if [ -z "$$newVersion" ]; then \
echo "Error: 'to' variable is required. Usage: make branch to=vX.Y.Z"; \
exit 1; \
fi; \
branchName=fix/$$newVersion; \
echo "Switching to master branch..."; \
git checkout master; \
echo "Pulling latest changes from master..."; \
git pull origin master; \
echo "Creating and switching to branch $$branchName from master..."; \
git checkout -b $$branchName; \
echo "Branch $$branchName created successfully!"
# make version to=v2.4.0
.PHONY: version
version:
@set -e; \
newVersion=$(to); \
./.make_version.sh ./ $$newVersion; \
echo "make version to=$(to) done"
# make tag to=v2.4.0
.PHONY: tag
tag:
@set -e; \
newVersion=$(to); \
echo "Switching to master branch..."; \
git checkout master; \
echo "Pulling latest changes from master..."; \
git pull origin master; \
echo "Creating annotated tag $$newVersion..."; \
git tag -a $$newVersion -m "Release $$newVersion"; \
echo "Pushing tag $$newVersion..."; \
git push origin $$newVersion; \
echo "Tag $$newVersion created and pushed successfully!"
# update submodules
.PHONY: subup
subup:
@set -e; \
echo "Updating submodules..."; \
git submodule init;\
git submodule update;
# update and commit submodules
.PHONY: subsync
subsync: subup
@set -e; \
echo "";\
cd examples; \
echo "Checking for changes..."; \
if git diff-index --quiet HEAD --; then \
echo "No changes to commit"; \
else \
echo "Found changes, committing..."; \
git add -A; \
git commit -m "examples update"; \
git push origin; \
fi; \
cd ..;

127
README.MD
View File

@ -1,107 +1,46 @@
# GoFrame
<div align=center>
<img src="https://goframe.org/statics/image/gf-head-large.png" width="100"/>
[![Go Doc](https://godoc.org/github.com/gogf/gf?status.svg)](https://godoc.org/github.com/gogf/gf)
[![GoFrame CI](https://github.com/gogf/gf/actions/workflows/gf.yml/badge.svg)](https://github.com/gogf/gf/actions/workflows/gf.yml)
[![Go Report](https://goreportcard.com/badge/github.com/gogf/gf?v=1)](https://goreportcard.com/report/github.com/gogf/gf)
[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf/branch/master)
[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg)](https://github.com/gogf/gf)
<div align=center>
<img src="https://goframe.org/img/logo_full.png" width="300" alt="goframe gf logo"/>
[![Go Reference](https://pkg.go.dev/badge/github.com/gogf/gf/v2.svg)](https://pkg.go.dev/github.com/gogf/gf/v2)
[![GoFrame CI](https://github.com/gogf/gf/actions/workflows/ci-main.yml/badge.svg)](https://github.com/gogf/gf/actions/workflows/ci-main.yml)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/gogf/gf/badge)](https://scorecard.dev/viewer/?uri=github.com/gogf/gf)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/9233/badge)](https://bestpractices.coreinfrastructure.org/projects/9233)
[![Go Report Card](https://goreportcard.com/badge/github.com/gogf/gf/v2)](https://goreportcard.com/report/github.com/gogf/gf/v2)
[![Code Coverage](https://codecov.io/gh/gogf/gf/branch/master/graph/badge.svg)](https://codecov.io/gh/gogf/gf)
[![Production Ready](https://img.shields.io/badge/production-ready-blue.svg?style=flat)](https://github.com/gogf/gf)
[![License](https://img.shields.io/github/license/gogf/gf.svg?style=flat)](https://github.com/gogf/gf)
[![Release](https://img.shields.io/github/v/release/gogf/gf?style=flat)](https://github.com/gogf/gf/releases)
[![GitHub pull requests](https://img.shields.io/github/issues-pr/gogf/gf?style=flat)](https://github.com/gogf/gf/pulls)
[![GitHub closed pull requests](https://img.shields.io/github/issues-pr-closed/gogf/gf?style=flat)](https://github.com/gogf/gf/pulls?q=is%3Apr+is%3Aclosed)
[![GitHub issues](https://img.shields.io/github/issues/gogf/gf?style=flat)](https://github.com/gogf/gf/issues)
[![GitHub closed issues](https://img.shields.io/github/issues-closed/gogf/gf?style=flat)](https://github.com/gogf/gf/issues?q=is%3Aissue+is%3Aclosed)
![Stars](https://img.shields.io/github/stars/gogf/gf?style=flat)
![Forks](https://img.shields.io/github/forks/gogf/gf?style=flat)
</div>
`GoFrame` is a modular, powerful, high-performance and enterprise-class application development framework of Golang.
# Features
- modular, loosely coupled design
- rich components, out-of-the-box
- automatic codes generating for efficiency
- simple and easy to use, detailed documentation
- interface designed components, with high scalability
- fully supported tracing and error stack feature
- specially developed and powerful ORM component
- robust engineering design specifications
- convenient development CLI tool provide
- OpenTelemetry observability features support
- OpenAPIV3 documentation generating, automatically
- much, much more...ready to explore?
# Installation
Enter your repo. directory and execute following command:
## primary module
```bash
go get -u -v github.com/gogf/gf/v2
```
## cli tool
```bash
go install github.com/gogf/gf/cmd/gf/v2
```
# Limitation
```
golang version >= 1.15
```
# Architecture
<div align=center>
<img src="https://goframe.org/download/attachments/1114119/arch.png"/>
</div>
A powerful framework for faster, easier, and more efficient project development.
# Documentation
* Chinese Official Site(中文官网): [https://goframe.org](https://goframe.org/display/gf)
* GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
- GoFrame Official Site: [https://goframe.org](https://goframe.org)
- GoFrame Official Site(en): [https://goframe.org/en](https://goframe.org/en)
- GoFrame Mirror Site(中文): [https://goframe.org.cn](https://goframe.org.cn)
- GoFrame Mirror Site(github pages): [https://pages.goframe.org](https://pages.goframe.org)
- GoDoc API: [https://pkg.go.dev/github.com/gogf/gf/v2](https://pkg.go.dev/github.com/gogf/gf/v2)
# Contributors
💖 [Thanks to all the contributors who made GoFrame possible](https://github.com/gogf/gf/graphs/contributors) 💖
<a href="https://github.com/gogf/gf/graphs/contributors">
<img src="https://goframe.org/img/contributors.svg?version=v2.9.5" alt="goframe contributors"/>
</a>
# License
`GoFrame` is licensed under the [MIT License](LICENSE), 100% free and open-source, forever.
# Part Of Users
- [Tencent](https://www.tencent.com/)
- [ZTE](https://www.zte.com.cn/china/)
- [Ant Financial Services](https://www.antfin.com/)
- [VIVO](https://www.vivo.com/)
- [MedLinker](https://www.medlinker.com/)
- [KuCoin](https://www.kucoin.io/)
- [LeYouJia](https://www.leyoujia.com/)
- [IGG](https://igg.com)
- [37](https://www.37.com)
- [XiMaLaYa](https://www.ximalaya.com)
- [ZYBang](https://www.zybang.com/)
> We list part of the users here, if your company or products are using `GoFrame`, please let us know [here](https://goframe.org/pages/viewpage.action?pageId=1114415).
# Contributors
This project exists thanks to all the people who contribute. [[Contributors](https://github.com/gogf/gf/graphs/contributors)].
<a href="https://github.com/gogf/gf/graphs/contributors"><img src="https://contributors-img.web.app/image?repo=gogf/gf" /></a>
# Donators
If you love `GoFrame`, why not [buy developer a cup of coffee](https://goframe.org/pages/viewpage.action?pageId=1115633)?
# Sponsors
We appreciate any kind of sponsorship for `GoFrame` development. If you've got some interesting, please contact WeChat `389961817` / Email `john@goframe.org`.
# Thanks
<a href="https://www.jetbrains.com/?from=GoFrame"><img src="https://goframe.org/download/thumbnails/1114119/jetbrains.png" height="120" alt="JetBrains"/></a>
<a href="https://www.atlassian.com/?from=GoFrame"><img src="https://goframe.org/download/attachments/1114119/atlassian.jpg" height="120" alt="Atlassian"/></a>

View File

@ -1,5 +1,6 @@
.DEFAULT_GOAL := pack
pack: pack.template-single pack.template-mono
pack: pack.template-single pack.template-mono pack.template-mono-app
pack.template-single:
@rm -fr temp
@ -15,4 +16,21 @@ pack.template-mono:
@cd temp && git clone https://github.com/gogf/template-mono
@rm -fr temp/template-mono/.git
@cd temp && gf pack template-mono ../internal/packed/template-mono.go -n=packed -y
@rm -fr temp
# Note:
# command `sed` only works on MacOS.
# use `grep -irl 'template-single' temp| xargs sed -i'' -e 's/template-single/template-mono-app/g'` on other platforms.
pack.template-mono-app:
@rm -fr temp
@mkdir temp || exit 0
@cd temp && git clone https://github.com/gogf/template-single
@cd temp && mv template-single template-mono-app
@rm -fr temp/template-mono-app/.git
@rm -fr temp/template-mono-app/.gitattributes
@rm -fr temp/template-mono-app/.gitignore
@rm -fr temp/template-mono-app/go.mod
@rm -fr temp/template-mono-app/go.sum
@grep -irl 'template-single' temp| xargs sed -i '' -e 's/template-single/template-mono-app/g'
@cd temp && gf pack template-mono-app ../internal/packed/template-mono-app.go -n=packed -y
@rm -fr temp

View File

@ -2,39 +2,56 @@
`gf` is a powerful CLI tool for building [GoFrame](https://goframe.org) application with convenience.
## 1. Install
## 1) PreCompiled Binary
You can also install `gf` tool using pre-built binaries: https://github.com/gogf/gf/releases
You can also install `gf` tool using pre-built binaries: <https://github.com/gogf/gf/releases>
1. `Mac` & `Linux`
```shell
```shell
wget -O gf https://github.com/gogf/gf/releases/latest/download/gf_$(go env GOOS)_$(go env GOARCH) && chmod +x gf && ./gf install -y && rm ./gf
```
```
> If you're using `zsh`, you might need rename your alias by command `alias gf=gf` to resolve the conflicts between `gf` and `git fetch`.
2. `Windows`
Manually download, execute in command line it and then follow the instruction.
Manually download, execute it and then follow the instruction.
3. Database support
3. Database `sqlite` and `oracle` are not support in `gf gen` command in default as it needs `cgo` and `gcc`, you can manually make some changes to the source codes and do the building.
| DB | builtin support | remarks |
|:----------:|:---------------:|:----------------------------------------------------------------------------------------------------------------------------------------------------------------:|
| mysql | yes | - |
| mariadb | yes | - |
| tidb | yes | - |
| mssql | yes | - |
| oracle | yes | - |
| pgsql | yes | - |
| sqlite | yes | - |
| sqlitecgo | no | to support sqlite database on 32bit architecture systems, manually add package import to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
| clickhouse | no | manually add package import to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
| dm | no | manually add package import to the [source codes](./internal/cmd/cmd_gen_dao.go) and do the building. |
## 2) Manually Install
```shell
git clone https://github.com/gogf/gf && cd gf/cmd/gf && go install
```
```shell
go install github.com/gogf/gf/cmd/gf/v2@latest # latest version
go install github.com/gogf/gf/cmd/gf/v2@v2.5.5 # certain version(should be >= v2.5.5)
```
## 2. Commands
```html
$ gf
USAGE
gf COMMAND [OPTION]
COMMAND
up upgrade GoFrame version/tool to latest one in current project
env show current Golang environment variables
fix auto fixing codes after upgrading to new GoFrame version
run running go codes with hot-compiled-like feature
gen automatically generate go files for dao/do/entity/pb/pbentity
tpl template parsing and building commands
@ -60,10 +77,3 @@ ADDITIONAL
### 1). Command `gf run` returns `pipe: too many open files`
Please use `ulimit -n 65535` to enlarge your system configuration for max open files for current terminal shell session, and then `gf run`.

119
cmd/gf/gfcmd/gfcmd.go Normal file
View File

@ -0,0 +1,119 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package gfcmd provides the management of CLI commands for `gf` tool.
package gfcmd
import (
"context"
"runtime"
_ "github.com/gogf/gf/cmd/gf/v2/internal/packed"
"github.com/gogf/gf/v2/errors/gcode"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcfg"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
const cliFolderName = `hack`
// Command manages the CLI command of `gf`.
// This struct can be globally accessible and extended with custom struct.
type Command struct {
*gcmd.Command
}
// Run starts running the command according the command line arguments and options.
func (c *Command) Run(ctx context.Context) {
defer func() {
if exception := recover(); exception != nil {
if err, ok := exception.(error); ok {
mlog.Print(err.Error())
} else {
panic(gerror.NewCodef(gcode.CodeInternalPanic, "%+v", exception))
}
}
}()
// CLI configuration, using the `hack/config.yaml` in priority.
if path, _ := gfile.Search(cliFolderName); path != "" {
if adapter, ok := g.Cfg().GetAdapter().(*gcfg.AdapterFile); ok {
if err := adapter.SetPath(path); err != nil {
mlog.Fatal(err)
}
}
}
// zsh alias "git fetch" conflicts checks.
handleZshAlias()
// -y option checks.
allyes.Init()
// just run.
if err := c.RunWithError(ctx); err != nil {
// Exit with error message and exit code 1.
// It is very important to exit the command process with code 1.
mlog.Fatalf(`%+v`, err)
}
}
// GetCommand retrieves and returns the root command of CLI `gf`.
func GetCommand(ctx context.Context) (*Command, error) {
root, err := gcmd.NewFromObject(cmd.GF)
if err != nil {
return nil, err
}
err = root.AddObject(
cmd.Up,
cmd.Env,
cmd.Fix,
cmd.Run,
cmd.Gen,
cmd.Tpl,
cmd.Init,
cmd.Pack,
cmd.Build,
cmd.Docker,
cmd.Install,
cmd.Version,
cmd.Doc,
)
if err != nil {
return nil, err
}
command := &Command{
root,
}
return command, nil
}
// zsh alias "git fetch" conflicts checks.
func handleZshAlias() {
if runtime.GOOS == "windows" {
return
}
if home, err := gfile.Home(); err == nil {
zshPath := gfile.Join(home, ".zshrc")
if gfile.Exists(zshPath) {
var (
aliasCommand = `alias gf=gf`
content = gfile.GetContents(zshPath)
)
if !gstr.Contains(content, aliasCommand) {
_ = gfile.PutContentsAppend(zshPath, "\n"+aliasCommand+"\n")
}
}
}
}

View File

@ -1,59 +1,69 @@
module github.com/gogf/gf/cmd/gf/v2
go 1.18
go 1.23.0
require (
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.1.0
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.1.0
github.com/gogf/gf/v2 v2.2.2
github.com/olekukonko/tablewriter v0.0.5
golang.org/x/tools v0.2.0
github.com/gogf/gf/contrib/drivers/clickhouse/v2 v2.9.5
github.com/gogf/gf/contrib/drivers/mssql/v2 v2.9.5
github.com/gogf/gf/contrib/drivers/mysql/v2 v2.9.5
github.com/gogf/gf/contrib/drivers/oracle/v2 v2.9.5
github.com/gogf/gf/contrib/drivers/pgsql/v2 v2.9.5
github.com/gogf/gf/contrib/drivers/sqlite/v2 v2.9.5
github.com/gogf/gf/v2 v2.9.5
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f
github.com/olekukonko/tablewriter v1.1.0
github.com/schollz/progressbar/v3 v3.15.0
golang.org/x/mod v0.25.0
golang.org/x/tools v0.26.0
)
require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/clbanning/mxj/v2 v2.5.5 // indirect
github.com/denisenkom/go-mssqldb v0.11.0 // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/glebarez/go-sqlite v1.17.3 // indirect
github.com/go-logr/logr v1.2.3 // indirect
aead.dev/minisign v0.2.0 // indirect
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/ClickHouse/clickhouse-go/v2 v2.0.15 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.9.0 // indirect
github.com/glebarez/go-sqlite v1.21.2 // indirect
github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-sql-driver/mysql v1.6.0 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/grokify/html-strip-tags-go v0.0.1 // indirect
github.com/lib/pq v1.10.4 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/sijms/go-ora/v2 v2.4.20 // indirect
go.opentelemetry.io/otel v1.7.0 // indirect
go.opentelemetry.io/otel/sdk v1.7.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
golang.org/x/crypto v0.1.0 // indirect
golang.org/x/mod v0.6.0 // indirect
golang.org/x/net v0.1.0 // indirect
golang.org/x/sys v0.1.0 // indirect
golang.org/x/text v0.4.0 // indirect
github.com/go-sql-driver/mysql v1.7.1 // indirect
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
github.com/golang-sql/sqlexp v0.1.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/grokify/html-strip-tags-go v0.1.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/microsoft/go-mssqldb v1.7.1 // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/olekukonko/errors v1.1.0 // indirect
github.com/olekukonko/ll v0.0.9 // indirect
github.com/paulmach/orb v0.7.1 // indirect
github.com/pierrec/lz4/v4 v4.1.14 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/shopspring/decimal v1.3.1 // indirect
github.com/sijms/go-ora/v2 v2.7.10 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/otel v1.38.0 // indirect
go.opentelemetry.io/otel/metric v1.38.0 // indirect
go.opentelemetry.io/otel/sdk v1.38.0 // indirect
go.opentelemetry.io/otel/trace v1.38.0 // indirect
golang.org/x/crypto v0.38.0 // indirect
golang.org/x/net v0.40.0 // indirect
golang.org/x/sync v0.14.0 // indirect
golang.org/x/sys v0.35.0 // indirect
golang.org/x/term v0.32.0 // indirect
golang.org/x/text v0.25.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.16.8 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
modernc.org/sqlite v1.17.3 // indirect
)
replace (
github.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql/
github.com/gogf/gf/contrib/drivers/mysql/v2 => ../../contrib/drivers/mysql/
github.com/gogf/gf/contrib/drivers/oracle/v2 => ../../contrib/drivers/oracle/
github.com/gogf/gf/contrib/drivers/pgsql/v2 => ../../contrib/drivers/pgsql/
github.com/gogf/gf/contrib/drivers/sqlite/v2 => ../../contrib/drivers/sqlite/
github.com/gogf/gf/v2 => ../../
modernc.org/libc v1.22.5 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.5.0 // indirect
modernc.org/sqlite v1.23.1 // indirect
)

View File

@ -1,150 +1,232 @@
github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak=
github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
aead.dev/minisign v0.2.0 h1:kAWrq/hBRu4AARY6AlciO83xhNnW9UaC8YipS2uhLPk=
aead.dev/minisign v0.2.0/go.mod h1:zdq6LdSd9TbuSxchxwhpA9zEb9YXcVGoE8JakuiGaIQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1 h1:MyVTgWR8qd/Jw1Le0NZebGBUCLbtak3bJ3z1OlqZBpw=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/azkeys v1.0.1/go.mod h1:GpPjLhVR9dnUoJMyHWSPy71xY9/lcmpzIPZXmF0FCVY=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0 h1:D3occbWoio4EBLkbkevetNMAVX197GkzbUMtqjGWn80=
github.com/Azure/azure-sdk-for-go/sdk/security/keyvault/internal v1.0.0/go.mod h1:bTSOgj05NGRuHHhQwAdPnYr9TOdNmKlZTgGLL6nyAdI=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/BurntSushi/toml v1.5.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/ClickHouse/clickhouse-go v1.5.4/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
github.com/ClickHouse/clickhouse-go/v2 v2.0.15 h1:lLAZliqrZEygkxosLaW1qHyeTb4Ho7fVCZ0WKCpLocU=
github.com/ClickHouse/clickhouse-go/v2 v2.0.15/go.mod h1:Z21o82zD8FFqefOQDg93c0XITlxGbTsWQuRm588Azkk=
github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME=
github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.11.0 h1:9rHa233rhdOyrz2GcP9NM+gi2psgJZ4GWDpL/7ND8HI=
github.com/denisenkom/go-mssqldb v0.11.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/glebarez/go-sqlite v1.17.3 h1:Rji9ROVSTTfjuWD6j5B+8DtkNvPILoUC3xRhkQzGxvk=
github.com/glebarez/go-sqlite v1.17.3/go.mod h1:Hg+PQuhUy98XCxWEJEaWob8x7lhJzhNYF1nZbUiRGIY=
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/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f h1:7xfXR/BhG3JDqO1s45n65Oyx9t4E/UqDOXep6jXdLCM=
github.com/gogf/selfupdate v0.0.0-20231215043001-5c48c528462f/go.mod h1:HnYoio6S7VaFJdryKcD/r9HgX+4QzYfr00XiXUo/xz0=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0ktxqI+Sida1w446QrXBRJ0nee3SNZlA=
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/lib/pq v1.10.4 h1:SO9z7FRPzA03QhHKJrH5BXA6HU1rS4V2nIVrrNC1iYk=
github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grokify/html-strip-tags-go v0.1.0 h1:03UrQLjAny8xci+R+qjCce/MYnpNXCtgzltlQbOBae4=
github.com/grokify/html-strip-tags-go v0.1.0/go.mod h1:ZdzgfHEzAfz9X6Xe5eBLVblWIxXfYSQ40S/VKrAOGpc=
github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/microsoft/go-mssqldb v1.7.1 h1:KU/g8aWeM3Hx7IMOFpiwYiUkU+9zeISb4+tx3ScVfsM=
github.com/microsoft/go-mssqldb v1.7.1/go.mod h1:kOvZKUdrhhFQmxLZqbwUV0rHkNkZpthMITIb2Ko1IoA=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mkevac/debugcharts v0.0.0-20191222103121-ae1c48aa8615/go.mod h1:Ad7oeElCZqA1Ufj0U9/liOF4BtVepxRcTvr2ey7zTvM=
github.com/olekukonko/errors v1.1.0 h1:RNuGIh15QdDenh+hNvKrJkmxxjV4hcS50Db478Ou5sM=
github.com/olekukonko/errors v1.1.0/go.mod h1:ppzxA5jBKcO1vIpCXQ9ZqgDh8iwODz6OXIGKU8r5m4Y=
github.com/olekukonko/ll v0.0.9 h1:Y+1YqDfVkqMWuEQMclsF9HUR5+a82+dxJuL1HHSRpxI=
github.com/olekukonko/ll v0.0.9/go.mod h1:En+sEW0JNETl26+K8eZ6/W4UQ7CYSrrgg/EdIYT2H8g=
github.com/olekukonko/tablewriter v1.1.0 h1:N0LHrshF4T39KvI96fn6GT8HEjXRXYNDrDjKFDB7RIY=
github.com/olekukonko/tablewriter v1.1.0/go.mod h1:5c+EBPeSqvXnLLgkm9isDdzR3wjfBkHR9Nhfp3NWrzo=
github.com/paulmach/orb v0.7.1 h1:Zha++Z5OX/l168sqHK3k4z18LDvr+YAO/VjK0ReQ9rU=
github.com/paulmach/orb v0.7.1/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A=
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE=
github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
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/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/sijms/go-ora/v2 v2.4.20 h1:9e3z7VLBQXRAHGiIda1GEFtRhfxata0LghyMZqvLKew=
github.com/sijms/go-ora/v2 v2.4.20/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/schollz/progressbar/v3 v3.15.0 h1:cNZmcNiVyea6oofBTg80ZhVXxf3wG/JoAhqCCwopkQo=
github.com/schollz/progressbar/v3 v3.15.0/go.mod h1:ncBdc++eweU0dQoeZJ3loXoAc+bjaallHRIm8pVVeQM=
github.com/shirou/gopsutil v2.19.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shirou/w32 v0.0.0-20160930032740-bb4de0191aa4/go.mod h1:qsXQc7+bwAM3Q1u/4XEfrquwF8Lw7D7y5cD8CuHnfIc=
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/sijms/go-ora/v2 v2.7.10 h1:GSLdj0PYYgSndhsnm7b6p32OqgnwnUZSkFb3j+htfhI=
github.com/sijms/go-ora/v2 v2.7.10/go.mod h1:EHxlY6x7y9HAsdfumurRfTd+v8NrEOTR3Xl4FWlH6xk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
go.opentelemetry.io/otel v1.7.0 h1:Z2lA3Tdch0iDcrhJXDIlC94XE+bxok1F9B+4Lz/lGsM=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
go.opentelemetry.io/otel/sdk v1.7.0 h1:4OmStpcKVOfvDOgCt7UriAPtKolwIhxpnSNI/yK+1B0=
go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
go.opentelemetry.io/otel/trace v1.7.0 h1:O37Iogk1lEkMRXewVtZ1BBTVn5JEp8GrJvP92bJqC6o=
go.opentelemetry.io/otel v1.38.0 h1:RkfdswUDRimDg0m2Az18RKOsnI8UDzppJAtj01/Ymk8=
go.opentelemetry.io/otel v1.38.0/go.mod h1:zcmtmQ1+YmQM9wrNsTGV/q/uyusom3P8RxwExxkZhjM=
go.opentelemetry.io/otel/metric v1.38.0 h1:Kl6lzIYGAh5M159u9NgiRkmoMKjvbsKtYRwgfrA6WpA=
go.opentelemetry.io/otel/metric v1.38.0/go.mod h1:kB5n/QoRM8YwmUahxvI3bO34eVtQf2i4utNVLr9gEmI=
go.opentelemetry.io/otel/sdk v1.38.0 h1:l48sr5YbNf2hpCUj/FoGhW9yDkl+Ma+LrVl8qaM5b+E=
go.opentelemetry.io/otel/sdk v1.38.0/go.mod h1:ghmNdGlVemJI3+ZB5iDEuk4bWA3GkTpW+DOoZMYBVVg=
go.opentelemetry.io/otel/sdk/metric v1.38.0 h1:aSH66iL0aZqo//xXzQLYozmWrXxyFkBJ6qT5wthqPoM=
go.opentelemetry.io/otel/sdk/metric v1.38.0/go.mod h1:dg9PBnW9XdQ1Hd6ZnRz689CbtrUp0wMMs9iPcgT9EZA=
go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
go.opentelemetry.io/otel/trace v1.38.0 h1:Fxk5bKrDZJUH+AMyyIXGcFAPah0oRcT+LuNtJrmcNLE=
go.opentelemetry.io/otel/trace v1.38.0/go.mod h1:j1P9ivuFsTceSWe1oY+EeW3sc+Pp42sO++GHkg4wwhs=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.1.0 h1:MDRAIl0xIo9Io2xV565hzXHw3zVseKrJKodhohM5CjU=
golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.38.0 h1:jt+WWG8IZlBnVbomuhg2Mdq0+BBQaHbtqHEFEigjUV8=
golang.org/x/crypto v0.38.0/go.mod h1:MvrbAqul58NNYPKnOra203SB9vpuZW0e+RRZV+Ggqjw=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I=
golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI=
golang.org/x/mod v0.25.0 h1:n7a+ZbQKQA/Ysbyb0/6IbB1H/X41mKgbhfv7AfG/44w=
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.1.0 h1:hZ/3BUoy5aId7sCpA/Tc5lt8DkFgdVS2onTpJsZ/fl0=
golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
golang.org/x/net v0.40.0 h1:79Xs7wF06Gbdcg4kdCCIQArK11Z1hr5POQ6+fIYHNuY=
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ=
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191220220014-0732a990476f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220405052023-b1e9470b6e64/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/sys v0.0.0-20210228012217-479acdf4ea46/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220429233432-b5fbb4746d32/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.8-0.20211105212822-18b340fc7af2/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0=
golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg=
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4=
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE=
golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/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=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/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=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/libc v1.16.8 h1:Ux98PaOMvolgoFX/YwusFOHBnanXdGRmWgI8ciI2z4o=
modernc.org/libc v1.16.8/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI=
modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=

18
cmd/gf/go.work Normal file
View File

@ -0,0 +1,18 @@
go 1.23.0
use ./
// =====================================================================================================
// NOTE:
// Please update associated commands in ../../.set_version.sh if any of the follows replacements change.
// =====================================================================================================
replace (
github.com/gogf/gf/contrib/drivers/clickhouse/v2 => ../../contrib/drivers/clickhouse
github.com/gogf/gf/contrib/drivers/mssql/v2 => ../../contrib/drivers/mssql
github.com/gogf/gf/contrib/drivers/mysql/v2 => ../../contrib/drivers/mysql
github.com/gogf/gf/contrib/drivers/oracle/v2 => ../../contrib/drivers/oracle
github.com/gogf/gf/contrib/drivers/pgsql/v2 => ../../contrib/drivers/pgsql
github.com/gogf/gf/contrib/drivers/sqlite/v2 => ../../contrib/drivers/sqlite
github.com/gogf/gf/v2 => ../../
)

View File

@ -1,9 +1,17 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package cmd provides the management of CLI commands for `gf` tool.
package cmd
import (
"context"
"strings"
"github.com/gogf/gf/v2"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/util/gtag"
@ -12,9 +20,8 @@ import (
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
var (
GF = cGF{}
)
// GF is the management object for `gf` command line tool.
var GF = cGF{}
type cGF struct {
g.Meta `name:"gf" ad:"{cGFAd}"`
@ -48,18 +55,24 @@ func (c cGF) Index(ctx context.Context, in cGFInput) (out *cGFOutput, err error)
_, err = Version.Index(ctx, cVersionInput{})
return
}
answer := "n"
// No argument or option, do installation checks.
if !service.Install.IsInstalled() {
mlog.Print("hi, it seams it's the first time you installing gf cli.")
s := gcmd.Scanf("do you want to install gf binary to your system? [y/n]: ")
if strings.EqualFold(s, "y") {
if err = service.Install.Run(ctx); err != nil {
return
}
gcmd.Scan("press `Enter` to exit...")
if data, isInstalled := service.Install.IsInstalled(); !isInstalled {
mlog.Print("hi, it seems it's the first time you installing gf cli.")
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
} else if !data.IsSelf {
mlog.Print("hi, you have installed gf cli.")
answer = gcmd.Scanf("do you want to install gf(%s) binary to your system? [y/n]: ", gf.VERSION)
}
if strings.EqualFold(answer, "y") {
if err = service.Install.Run(ctx); err != nil {
return
}
gcmd.Scan("press `Enter` to exit...")
return
}
// Print help content.
gcmd.CommandFromCtx(ctx).Print()
return

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
@ -11,6 +17,7 @@ import (
"github.com/gogf/gf/v2/encoding/gbase64"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gbuild"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
@ -23,12 +30,10 @@ import (
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
var (
Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "internal/packed/build_pack_data.go",
}
)
var Build = cBuild{
nodeNameInConfigFile: "gfcli.build",
packedGoFileName: "internal/packed/build_pack_data.go",
}
type cBuild struct {
g.Meta `name:"build" brief:"{cBuildBrief}" dc:"{cBuildDc}" eg:"{cBuildEg}" ad:"{cBuildAd}"`
@ -37,10 +42,11 @@ type cBuild struct {
}
const (
cBuildBrief = `cross-building go project for lots of platforms`
cBuildEg = `
cBuildDefaultFile = "main.go"
cBuildBrief = `cross-building go project for lots of platforms`
cBuildEg = `
gf build main.go
gf build main.go --pack public,template
gf build main.go --ps public,template
gf build main.go --cgo
gf build main.go -m none
gf build main.go -n my-app -a all -s all
@ -57,45 +63,67 @@ It provides much more features for building binary:
`
cBuildAd = `
PLATFORMS
aix ppc64
android 386,amd64,arm,arm64
darwin amd64,arm64
dragonfly amd64
freebsd 386,amd64,arm
linux 386,amd64,arm,arm64,ppc64,ppc64le,mips,mipsle,mips64,mips64le
illumos amd64
ios arm64
js wasm
linux 386,amd64,arm,arm64,loong64,mips,mipsle,mips64,mips64le,ppc64,ppc64le,riscv64,s390x
netbsd 386,amd64,arm
openbsd 386,amd64,arm
windows 386,amd64
openbsd 386,amd64,arm,arm64
plan9 386,amd64,arm
solaris amd64
wasip1 wasm
windows 386,amd64,arm,arm64
`
// https://golang.google.cn/doc/install/source
cBuildPlatforms = `
aix ppc64
android 386
android amd64
android arm
android arm64
darwin amd64
darwin arm64
ios amd64
ios arm64
dragonfly amd64
freebsd 386
freebsd amd64
freebsd arm
illumos amd64
ios arm64
js wasm
linux 386
linux amd64
linux arm
linux arm64
linux ppc64
linux ppc64le
linux loong64
linux mips
linux mipsle
linux mips64
linux mips64le
linux ppc64
linux ppc64le
linux riscv64
linux s390x
netbsd 386
netbsd amd64
netbsd arm
openbsd 386
openbsd amd64
openbsd arm
windows 386
windows amd64
android arm
dragonfly amd64
openbsd arm64
plan9 386
plan9 amd64
plan9 arm
solaris amd64
wasip1 wasm
windows 386
windows amd64
windows arm
windows arm64
`
)
@ -116,25 +144,23 @@ type cBuildInput struct {
Arch string `short:"a" name:"arch" brief:"output binary architecture, multiple arch separated with ','"`
System string `short:"s" name:"system" brief:"output binary system, multiple os separated with ','"`
Output string `short:"o" name:"output" brief:"output binary path, used when building single binary file"`
Path string `short:"p" name:"path" brief:"output binary directory path, default is './temp'" d:"./temp"`
Path string `short:"p" name:"path" brief:"output binary directory path, default is '.'" d:"."`
Extra string `short:"e" name:"extra" brief:"extra custom \"go build\" options"`
Mod string `short:"m" name:"mod" brief:"like \"-mod\" option of \"go build\", use \"-m none\" to disable go module"`
Cgo bool `short:"c" name:"cgo" brief:"enable or disable cgo feature, it's disabled in default" orphan:"true"`
VarMap g.Map `short:"r" name:"varMap" brief:"custom built embedded variable into binary"`
PackSrc string `short:"ps" name:"packSrc" brief:"pack one or more folders into one go file before building"`
PackDst string `short:"pd" name:"packDst" brief:"temporary go file path for pack, this go file will be automatically removed after built" d:"internal/packed/build_pack_data.go"`
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, default is false" orphan:"true"`
ExitWhenError bool `short:"ew" name:"exitWhenError" brief:"exit building when any error occurs, specially for multiple arch and system buildings. default is false" orphan:"true"`
DumpENV bool `short:"de" name:"dumpEnv" brief:"dump current go build environment before building binary" orphan:"true"`
}
type cBuildOutput struct{}
func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, err error) {
// print used go env
_, _ = Env.Index(ctx, cEnvInput{})
mlog.SetHeaderPrint(true)
mlog.Debugf(`build input: %+v`, in)
mlog.Debugf(`build command input: %+v`, in)
// Necessary check.
if gproc.SearchBinary("go") == "" {
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
@ -142,14 +168,15 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
var (
parser = gcmd.ParserFromCtx(ctx)
file = parser.GetArg(2).String()
file = in.File
)
if len(file) < 1 {
if file == "" {
file = parser.GetArg(2).String()
// Check and use the main.go file.
if gfile.Exists("main.go") {
file = "main.go"
if gfile.Exists(cBuildDefaultFile) {
file = cBuildDefaultFile
} else {
mlog.Fatal("build file path cannot be empty")
mlog.Fatal("build file path is empty or main.go not found in current working directory")
}
}
if in.Name == "" {
@ -205,7 +232,7 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
if !gfile.Exists(in.PackDst) {
// Remove the go file that is automatically packed resource.
defer func() {
_ = gfile.Remove(in.PackDst)
_ = gfile.RemoveFile(in.PackDst)
mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)
}()
}
@ -229,59 +256,38 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
} else {
genv.MustSet("CGO_ENABLED", "0")
}
var (
cmd = ""
ext = ""
)
// print used go env
if in.DumpENV {
_, _ = Env.Index(ctx, cEnvInput{})
}
for system, item := range platformMap {
cmd = ""
ext = ""
if len(customSystems) > 0 && customSystems[0] != "all" && !gstr.InArray(customSystems, system) {
continue
}
for arch, _ := range item {
for arch := range item {
if len(customArches) > 0 && customArches[0] != "all" && !gstr.InArray(customArches, arch) {
continue
}
if len(customSystems) == 0 && len(customArches) == 0 {
if runtime.GOOS == "windows" {
ext = ".exe"
}
// Single binary building, output the binary to current working folder.
output := ""
if len(in.Output) > 0 {
output = "-o " + in.Output + ext
} else {
output = "-o " + in.Name + ext
}
cmd = fmt.Sprintf(`go build %s -ldflags "%s" %s %s`, output, ldFlags, in.Extra, file)
} else {
// Cross-building, output the compiled binary to specified path.
if system == "windows" {
ext = ".exe"
}
genv.MustSet("GOOS", system)
genv.MustSet("GOARCH", arch)
cmd = fmt.Sprintf(
`go build -o %s/%s/%s%s -ldflags "%s" %s%s`,
in.Path, system+"_"+arch, in.Name, ext, ldFlags, in.Extra, file,
// For example:
// `gf build`
// `gf build -o main.exe`
c.doBinaryBuild(
ctx, file,
in.Output, in.Path,
runtime.GOOS, runtime.GOARCH, in.Name, ldFlags, in.Extra,
in.ExitWhenError,
true,
)
}
mlog.Debug(cmd)
// It's not necessary printing the complete command string.
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
mlog.Print(cmdShow)
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
mlog.Printf(
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
system, arch, gstr.Trim(result),
`you may use command option "--debug" to enable debug info and check the details`,
)
if in.ExitWhenError {
os.Exit(1)
}
} else {
mlog.Debug(gstr.Trim(result))
c.doBinaryBuild(
ctx, file,
in.Output, in.Path,
system, arch, in.Name, ldFlags, in.Extra,
in.ExitWhenError,
false,
)
}
// single binary building.
if len(customSystems) == 0 && len(customArches) == 0 {
@ -295,15 +301,78 @@ buildDone:
return
}
// getBuildInVarMapJson retrieves and returns the custom build-in variables in configuration
func (c cBuild) doBinaryBuild(
ctx context.Context,
filePath string,
outputPath, dirPath string,
system, arch, name, ldFlags, extra string,
exitWhenError bool,
singleBuild bool,
) {
var (
cmd string
ext string
)
// Cross-building, output the compiled binary to specified path.
if system == "windows" {
ext = ".exe"
}
genv.MustSet("GOOS", system)
genv.MustSet("GOARCH", arch)
if outputPath != "" {
outputPath = "-o " + outputPath
} else {
if dirPath == "" {
dirPath = "."
} else {
dirPath = gstr.TrimRight(dirPath, "/")
}
if singleBuild {
outputPath = fmt.Sprintf(
"-o %s/%s%s",
dirPath, name, ext,
)
} else {
outputPath = fmt.Sprintf(
"-o %s/%s/%s%s",
dirPath, system+"_"+arch, name, ext,
)
}
}
cmd = fmt.Sprintf(
`go build %s -ldflags "%s" %s%s`,
outputPath, ldFlags, extra, filePath,
)
mlog.Debug(fmt.Sprintf("build for GOOS=%s GOARCH=%s", system, arch))
mlog.Debug(cmd)
// It's not necessary printing the complete command string, filtering ldFlags.
cmdShow, _ := gregex.ReplaceString(`\s+(-ldflags ".+?")\s+`, " ", cmd)
mlog.Print(cmdShow)
if result, err := gproc.ShellExec(ctx, cmd); err != nil {
mlog.Printf(
"failed to build, os:%s, arch:%s, error:\n%s\n\n%s\n",
system, arch, gstr.Trim(result),
`you may use command option "--debug" to enable debug info and check the details`,
)
if exitWhenError {
os.Exit(1)
}
} else {
mlog.Debug(gstr.Trim(result))
}
}
// getBuildInVarStr retrieves and returns the custom build-in variables in configuration
// file as json.
func (c cBuild) getBuildInVarStr(ctx context.Context, in cBuildInput) string {
buildInVarMap := in.VarMap
if buildInVarMap == nil {
buildInVarMap = make(g.Map)
}
buildInVarMap["builtGit"] = c.getGitCommit(ctx)
buildInVarMap["builtTime"] = gtime.Now().String()
buildInVarMap[gbuild.BuiltGit] = c.getGitCommit(ctx)
buildInVarMap[gbuild.BuiltTime] = gtime.Now().String()
buildInVarMap[gbuild.BuiltVersion] = in.Version
b, err := json.Marshal(buildInVarMap)
if err != nil {
mlog.Fatal(err)

View File

@ -0,0 +1,184 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"fmt"
"io"
"net/http"
"os"
"path"
"path/filepath"
"time"
"github.com/gogf/gf/v2/encoding/gcompress"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
const (
GitName = "gf-site"
BranchName = "gh-pages"
SiteFileName = GitName + "-" + BranchName
// DocURL is the download address of the document
DocURL = "https://github.com/gogf/" + GitName + "/archive/refs/heads/" + BranchName + ".zip"
)
var (
Doc = cDoc{}
)
type cDoc struct {
g.Meta `name:"doc" brief:"download https://pages.goframe.org/ to run locally"`
}
type cDocInput struct {
g.Meta `name:"doc" config:"gfcli.doc"`
Path string `short:"p" name:"path" brief:"download docs directory path, default is \"%temp%/goframe\""`
Port int `short:"o" name:"port" brief:"http server port, default is 8080" d:"8080"`
Update bool `short:"u" name:"update" brief:"clean docs directory and update docs"`
Clean bool `short:"c" name:"clean" brief:"clean docs directory"`
Proxy string `short:"x" name:"proxy" brief:"proxy for download, such as https://hub.gitmirror.com/;https://ghproxy.com/;https://ghproxy.net/;https://ghps.cc/"`
}
type cDocOutput struct{}
func (c cDoc) Index(ctx context.Context, in cDocInput) (out *cDocOutput, err error) {
docs := NewDocSetting(ctx, in)
mlog.Print("Directory where the document is downloaded:", docs.TempDir)
if in.Clean {
mlog.Print("Cleaning document directory")
err = docs.Clean()
if err != nil {
mlog.Print("Failed to clean document directory:", err)
return
}
return
}
if in.Update {
mlog.Print("Cleaning old document directory")
err = docs.Clean()
if err != nil {
mlog.Print("Failed to clean old document directory:", err)
return
}
}
err = docs.DownloadDoc()
if err != nil {
mlog.Print("Failed to download document:", err)
return
}
http.Handle("/", http.FileServer(http.Dir(docs.DocDir)))
mlog.Printf("Access address http://127.0.0.1:%d in %s", in.Port, docs.DocDir)
err = http.ListenAndServe(fmt.Sprintf(":%d", in.Port), nil)
if err != nil {
return nil, err
}
return
}
// DocSetting doc setting
type DocSetting struct {
TempDir string
DocURL string
DocDir string
DocZipFile string
}
// NewDocSetting new DocSetting
func NewDocSetting(ctx context.Context, in cDocInput) *DocSetting {
fileName := SiteFileName + ".zip"
tempDir := in.Path
if tempDir == "" {
tempDir = gfile.Temp("goframe/docs")
} else {
tempDir = gfile.Abs(path.Join(tempDir, "docs"))
}
return &DocSetting{
TempDir: filepath.FromSlash(tempDir),
DocDir: filepath.FromSlash(path.Join(tempDir, SiteFileName)),
DocURL: in.Proxy + DocURL,
DocZipFile: filepath.FromSlash(path.Join(tempDir, fileName)),
}
}
// Clean cleans the temporary directory
func (d *DocSetting) Clean() error {
if _, err := os.Stat(d.TempDir); err == nil {
err = gfile.RemoveAll(d.TempDir)
if err != nil {
mlog.Print("Failed to delete temporary directory:", err)
return err
}
}
return nil
}
// DownloadDoc download the document
func (d *DocSetting) DownloadDoc() error {
if _, err := os.Stat(d.TempDir); err != nil {
err = gfile.Mkdir(d.TempDir)
if err != nil {
mlog.Print("Failed to create temporary directory:", err)
return nil
}
}
// Check if the file exists
if _, err := os.Stat(d.DocDir); err == nil {
mlog.Print("Document already exists, no need to download and unzip")
return nil
}
if _, err := os.Stat(d.DocZipFile); err == nil {
mlog.Print("File already exists, no need to download")
} else {
mlog.Printf("File does not exist, start downloading: %s", d.DocURL)
startTime := time.Now()
// Download the file
resp, err := http.Get(d.DocURL)
if err != nil {
mlog.Print("Failed to download file:", err)
return err
}
defer resp.Body.Close()
// Create the file
out, err := os.Create(d.DocZipFile)
if err != nil {
mlog.Print("Failed to create file:", err)
return err
}
defer out.Close()
// Write the response body to the file
_, err = io.Copy(out, resp.Body)
if err != nil {
mlog.Print("Failed to write file:", err)
return err
}
mlog.Printf("Download successful, time-consuming: %v", time.Since(startTime))
}
mlog.Print("Start unzipping the file...")
// Unzip the file
err := gcompress.UnZipFile(d.DocZipFile, d.TempDir)
if err != nil {
mlog.Print("Failed to unzip the file, please run again:", err)
_ = gfile.RemoveFile(d.DocZipFile)
return err
}
mlog.Print("Download and unzip successful")
return nil
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
@ -72,10 +78,10 @@ func init() {
type cDockerInput struct {
g.Meta `name:"docker" config:"gfcli.docker"`
Main string `name:"MAIN" arg:"true" brief:"{cDockerMainBrief}" d:"main.go"`
Main string `name:"MAIN" arg:"true" brief:"{cDockerMainBrief}" d:"main.go"`
File string `name:"file" short:"f" brief:"{cDockerFileBrief}" d:"manifest/docker/Dockerfile"`
Shell string `name:"shell" short:"s" brief:"{cDockerShellBrief}" d:"manifest/docker/docker.sh"`
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}" d:"-a amd64 -s linux"`
Build string `name:"build" short:"b" brief:"{cDockerBuildBrief}"`
Tag string `name:"tag" short:"t" brief:"{cDockerTagBrief}"`
TagName string `name:"tagName" short:"tn" brief:"{cDockerTagNameBrief}" v:"required-with:TagPrefixes"`
TagPrefixes []string `name:"tagPrefixes" short:"tp" brief:"{cDockerTagPrefixesBrief}" v:"required-with:TagName"`
@ -91,17 +97,23 @@ func (c cDocker) Index(ctx context.Context, in cDockerInput) (out *cDockerOutput
mlog.Fatalf(`command "docker" not found in your environment, please install docker first to proceed this command`)
}
mlog.Debugf(`docker command input: %+v`, in)
// Binary build.
in.Build += " --exit"
if in.Main != "" {
if err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
return
if in.Main != "" && in.Build != "" {
in.Build += " --exitWhenError"
if in.Main != "" {
if err = gproc.ShellRun(ctx, fmt.Sprintf(`gf build %s %s`, in.Main, in.Build)); err != nil {
mlog.Debugf(`build binary failed with error: %+v`, err)
return
}
}
}
// Shell executing.
if in.Shell != "" && gfile.Exists(in.Shell) {
if err = c.exeDockerShell(ctx, in.Shell); err != nil {
mlog.Debugf(`build docker failed with error: %+v`, err)
return
}
}

View File

@ -1,14 +1,23 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"bytes"
"context"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
@ -54,10 +63,23 @@ func (c cEnv) Index(ctx context.Context, in cEnvInput) (out *cEnvOutput, err err
}
array = append(array, []string{gstr.Trim(match[1]), gstr.Trim(match[2])})
}
tw := tablewriter.NewWriter(buffer)
tw.SetColumnAlignment([]int{tablewriter.ALIGN_LEFT, tablewriter.ALIGN_LEFT})
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer,
tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.On},
},
Symbols: tw.NewSymbols(tw.StyleASCII),
})),
tablewriter.WithConfig(tablewriter.Config{
Row: tw.CellConfig{
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone},
Alignment: tw.CellAlignment{PerColumn: []tw.Align{tw.AlignLeft, tw.AlignLeft}},
ColMaxWidths: tw.CellWidth{Global: 84},
},
}),
)
table.Bulk(array)
table.Render()
mlog.Print(buffer.String())
return
}

View File

@ -1,14 +1,22 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
var (
@ -62,6 +70,7 @@ func (c cFix) doFix(in cFixInput) (err error) {
var items = []cFixItem{
{Version: "v2.3", Func: c.doFixV23},
{Version: "v2.5", Func: c.doFixV25},
}
for _, item := range items {
if gstr.CompareVersionGo(in.Version, item.Version) < 0 {
@ -96,6 +105,28 @@ func (c cFix) doFixV23(version string) error {
return gfile.ReplaceDirFunc(replaceFunc, ".", "*.go", true)
}
// doFixV25 fixes code when upgrading to GoFrame v2.5.
func (c cFix) doFixV25(version string) (err error) {
replaceFunc := func(path, content string) string {
content, err = c.doFixV25Content(content)
return content
}
return gfile.ReplaceDirFunc(replaceFunc, ".", "*.go", true)
}
func (c cFix) doFixV25Content(content string) (newContent string, err error) {
newContent = content
if gstr.Contains(content, `.BindHookHandlerByMap(`) {
var pattern = `\.BindHookHandlerByMap\((.+?), map\[string\]ghttp\.HandlerFunc`
newContent, err = gregex.ReplaceString(
pattern,
`.BindHookHandlerByMap($1, map[ghttp.HookName]ghttp.HandlerFunc`,
content,
)
}
return
}
func (c cFix) autoDetectVersion(in cFixInput) (string, error) {
var (
err error

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
@ -12,6 +18,8 @@ var (
type cGen struct {
g.Meta `name:"gen" brief:"{cGenBrief}" dc:"{cGenDc}"`
cGenDao
cGenEnums
cGenCtrl
cGenPb
cGenPbEntity
cGenService

View File

@ -0,0 +1,15 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl"
)
type (
cGenCtrl = genctrl.CGenCtrl
)

View File

@ -1,12 +1,22 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
_ "github.com/gogf/gf/contrib/drivers/clickhouse/v2"
_ "github.com/gogf/gf/contrib/drivers/mssql/v2"
_ "github.com/gogf/gf/contrib/drivers/mysql/v2"
_ "github.com/gogf/gf/contrib/drivers/oracle/v2"
_ "github.com/gogf/gf/contrib/drivers/pgsql/v2"
_ "github.com/gogf/gf/contrib/drivers/sqlite/v2"
// do not add dm in cli pre-compilation,
// the dm driver does not support certain target platforms.
// _ "github.com/gogf/gf/contrib/drivers/dm/v2"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
)

View File

@ -0,0 +1,15 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genenums"
)
type (
cGenEnums = genenums.CGenEnums
)

View File

@ -1,79 +1,13 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
)
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb"
type (
cGenPb struct{}
cGenPbInput struct {
g.Meta `name:"pb" brief:"parse proto files and generate protobuf go files"`
}
cGenPbOutput struct{}
cGenPb = genpb.CGenPb
)
func (c cGenPb) Pb(ctx context.Context, in cGenPbInput) (out *cGenPbOutput, err error) {
// Necessary check.
if gproc.SearchBinary("protoc") == "" {
mlog.Fatalf(`command "protoc" not found in your environment, please install protoc first to proceed this command`)
}
// protocol fold checks.
protoFolder := "protocol"
if !gfile.Exists(protoFolder) {
mlog.Fatalf(`proto files folder "%s" does not exist`, protoFolder)
}
// folder scanning.
files, err := gfile.ScanDirFile(protoFolder, "*.proto", true)
if err != nil {
mlog.Fatal(err)
}
if len(files) == 0 {
mlog.Fatalf(`no proto files found in folder "%s"`, protoFolder)
}
dirSet := gset.NewStrSet()
for _, file := range files {
dirSet.Add(gfile.Dir(file))
}
var (
servicePath = gfile.RealPath(".")
goPathSrc = gfile.RealPath(gfile.Join(genv.Get("GOPATH").String(), "src"))
)
dirSet.Iterator(func(protoDirPath string) bool {
parsingCommand := fmt.Sprintf(
"protoc --gofast_out=plugins=grpc:. %s/*.proto -I%s",
protoDirPath,
servicePath,
)
if goPathSrc != "" {
parsingCommand += " -I" + goPathSrc
}
mlog.Print(parsingCommand)
if output, err := gproc.ShellExec(ctx, parsingCommand); err != nil {
mlog.Print(output)
mlog.Fatal(err)
}
return true
})
// Custom replacement.
//pbFolder := "protobuf"
//_, _ = gfile.ScanDirFileFunc(pbFolder, "*.go", true, func(path string) string {
// content := gfile.GetContents(path)
// content = gstr.ReplaceByArray(content, g.SliceStr{
// `gtime "gtime"`, `gtime "github.com/gogf/gf/v2/os/gtime"`,
// })
// _ = gfile.PutContents(path, content)
// utils.GoFmt(path)
// return path
//})
mlog.Print("done!")
return
}

View File

@ -1,411 +1,13 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"bytes"
"context"
"fmt"
"strings"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
import "github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity"
type (
cGenPbEntity struct{}
cGenPbEntityInput struct {
g.Meta `name:"pbentity" config:"{cGenPbEntityConfig}" brief:"{cGenPbEntityBrief}" eg:"{cGenPbEntityEg}" ad:"{cGenPbEntityAd}"`
Path string `name:"path" short:"p" brief:"{cGenPbEntityBriefPath}"`
Package string `name:"package" short:"k" brief:"{cGenPbEntityBriefPackage}"`
Link string `name:"link" short:"l" brief:"{cGenPbEntityBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{cGenPbEntityBriefTables}"`
Prefix string `name:"prefix" short:"f" brief:"{cGenPbEntityBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{cGenPbEntityBriefRemovePrefix}"`
NameCase string `name:"nameCase" short:"n" brief:"{cGenPbEntityBriefNameCase}" d:"Camel"`
JsonCase string `name:"jsonCase" short:"j" brief:"{cGenPbEntityBriefJsonCase}" d:"CamelLower"`
Option string `name:"option" short:"o" brief:"{cGenPbEntityBriefOption}"`
}
cGenPbEntityOutput struct{}
cGenPbEntityInternalInput struct {
cGenPbEntityInput
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
}
cGenPbEntity = genpbentity.CGenPbEntity
)
const (
cGenPbEntityConfig = `gfcli.gen.pbentity`
cGenPbEntityBrief = `generate entity message files in protobuf3 format`
cGenPbEntityEg = `
gf gen pbentity
gf gen pbentity -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen pbentity -p ./protocol/demos/entity -t user,user_detail,user_login
gf gen pbentity -r user_
`
cGenPbEntityAd = `
CONFIGURATION SUPPORT
Options are also supported by configuration file.
It's suggested using configuration file instead of command line arguments making producing.
The configuration node name is "gf.gen.pbentity", which also supports multiple databases, for example(config.yaml):
gfcli:
gen:
- pbentity:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
path: "protocol/demos/entity"
tables: "order,products"
package: "demos"
- pbentity:
link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
path: "protocol/demos/entity"
prefix: "primary_"
tables: "user, userDetail"
package: "demos"
option: |
option go_package = "protobuf/demos";
option java_package = "protobuf/demos";
option php_namespace = "protobuf/demos";
`
cGenPbEntityBriefPath = `directory path for generated files`
cGenPbEntityBriefPackage = `package name for all entity proto files`
cGenPbEntityBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
cGenPbEntityBriefTables = `generate models only for given tables, multiple table names separated with ','`
cGenPbEntityBriefPrefix = `add specified prefix for all entity names and entity proto files`
cGenPbEntityBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
cGenPbEntityBriefOption = `extra protobuf options`
cGenPbEntityBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
`
cGenPbEntityBriefNameCase = `
case for message attribute names, default is "Camel":
| Case | Example |
|---------------- |--------------------|
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString | default
| Snake | any_kind_of_string |
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
cGenPbEntityBriefJsonCase = `
case for message json tag, cases are the same as "nameCase", default "CamelLower".
set it to "none" to ignore json tag generating.
`
)
func init() {
gtag.Sets(g.MapStrStr{
`cGenPbEntityConfig`: cGenPbEntityConfig,
`cGenPbEntityBrief`: cGenPbEntityBrief,
`cGenPbEntityEg`: cGenPbEntityEg,
`cGenPbEntityAd`: cGenPbEntityAd,
`cGenPbEntityBriefPath`: cGenPbEntityBriefPath,
`cGenPbEntityBriefPackage`: cGenPbEntityBriefPackage,
`cGenPbEntityBriefLink`: cGenPbEntityBriefLink,
`cGenPbEntityBriefTables`: cGenPbEntityBriefTables,
`cGenPbEntityBriefPrefix`: cGenPbEntityBriefPrefix,
`cGenPbEntityBriefRemovePrefix`: cGenPbEntityBriefRemovePrefix,
`cGenPbEntityBriefGroup`: cGenPbEntityBriefGroup,
`cGenPbEntityBriefNameCase`: cGenPbEntityBriefNameCase,
`cGenPbEntityBriefJsonCase`: cGenPbEntityBriefJsonCase,
`cGenPbEntityBriefOption`: cGenPbEntityBriefOption,
})
}
func (c cGenPbEntity) PbEntity(ctx context.Context, in cGenPbEntityInput) (out *cGenPbEntityOutput, err error) {
var (
config = g.Cfg()
)
if config.Available(ctx) {
v := config.MustGet(ctx, cGenPbEntityConfig)
if v.IsSlice() {
for i := 0; i < len(v.Interfaces()); i++ {
doGenPbEntityForArray(ctx, i, in)
}
} else {
doGenPbEntityForArray(ctx, -1, in)
}
} else {
doGenPbEntityForArray(ctx, -1, in)
}
mlog.Print("done!")
return
}
func doGenPbEntityForArray(ctx context.Context, index int, in cGenPbEntityInput) {
var (
err error
db gdb.DB
)
if index >= 0 {
err = g.Cfg().MustGet(
ctx,
fmt.Sprintf(`%s.%d`, cGenPbEntityConfig, index),
).Scan(&in)
if err != nil {
mlog.Fatalf(`invalid configuration of "%s": %+v`, cGenPbEntityConfig, err)
}
}
if in.Package == "" {
mlog.Fatal("package name should not be empty")
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
// It uses user passed database configuration.
if in.Link != "" {
var (
tempGroup = gtime.TimestampNanoStr()
match, _ = gregex.MatchString(`([a-z]+):(.+)`, in.Link)
)
if len(match) == 3 {
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
Type: gstr.Trim(match[1]),
Link: gstr.Trim(match[2]),
})
db, _ = gdb.Instance(tempGroup)
}
} else {
db = g.DB()
}
if db == nil {
mlog.Fatal("database initialization failed")
}
tableNames := ([]string)(nil)
if in.Tables != "" {
tableNames = gstr.SplitAndTrim(in.Tables, ",")
} else {
tableNames, err = db.Tables(context.TODO())
if err != nil {
mlog.Fatalf("fetching tables failed: \n %v", err)
}
}
for _, tableName := range tableNames {
newTableName := tableName
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
generatePbEntityContentFile(ctx, db, cGenPbEntityInternalInput{
cGenPbEntityInput: in,
TableName: tableName,
NewTableName: newTableName,
})
}
}
// generatePbEntityContentFile generates the protobuf files for given table.
func generatePbEntityContentFile(ctx context.Context, db gdb.DB, in cGenPbEntityInternalInput) {
fieldMap, err := db.TableFields(ctx, in.TableName)
if err != nil {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", in.TableName, err)
}
// Change the `newTableName` if `Prefix` is given.
newTableName := "Entity_" + in.Prefix + in.NewTableName
var (
tableNameCamelCase = gstr.CaseCamel(newTableName)
tableNameSnakeCase = gstr.CaseSnake(newTableName)
entityMessageDefine = generateEntityMessageDefinition(tableNameCamelCase, fieldMap, in)
fileName = gstr.Trim(tableNameSnakeCase, "-_.")
path = gfile.Join(in.Path, fileName+".proto")
)
entityContent := gstr.ReplaceByMap(getTplPbEntityContent(""), g.MapStrStr{
"{PackageName}": in.Package,
"{OptionContent}": in.Option,
"{EntityMessage}": entityMessageDefine,
})
if err := gfile.PutContents(path, strings.TrimSpace(entityContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
mlog.Print("generated:", path)
}
}
// generateEntityMessageDefinition generates and returns the message definition for specified table.
func generateEntityMessageDefinition(entityName string, fieldMap map[string]*gdb.TableField, in cGenPbEntityInternalInput) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForPbEntity(fieldMap)
)
for index, name := range names {
array[index] = generateMessageFieldForPbEntity(index+1, fieldMap[name], in)
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
stContent := buffer.String()
// Let's do this hack of table writer for indent!
stContent = gstr.Replace(stContent, " #", "")
buffer.Reset()
buffer.WriteString(fmt.Sprintf("message %s {\n", entityName))
buffer.WriteString(stContent)
buffer.WriteString("}")
return buffer.String()
}
// generateMessageFieldForPbEntity generates and returns the message definition for specified field.
func generateMessageFieldForPbEntity(index int, field *gdb.TableField, in cGenPbEntityInternalInput) []string {
var (
typeName string
comment string
jsonTagStr string
)
t, _ := gregex.ReplaceString(`\(.+\)`, "", field.Type)
t = gstr.Split(gstr.Trim(t), " ")[0]
t = gstr.ToLower(t)
switch t {
case "binary", "varbinary", "blob", "tinyblob", "mediumblob", "longblob":
typeName = "bytes"
case "bit", "int", "tinyint", "small_int", "smallint", "medium_int", "mediumint", "serial":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "uint32"
} else {
typeName = "int32"
}
case "int8", "big_int", "bigint", "bigserial":
if gstr.ContainsI(field.Type, "unsigned") {
typeName = "uint64"
} else {
typeName = "int64"
}
case "real":
typeName = "float"
case "float", "double", "decimal", "smallmoney":
typeName = "double"
case "bool":
typeName = "bool"
case "datetime", "timestamp", "date", "time":
typeName = "int64"
default:
// Auto detecting type.
switch {
case strings.Contains(t, "int"):
typeName = "int"
case strings.Contains(t, "text") || strings.Contains(t, "char"):
typeName = "string"
case strings.Contains(t, "float") || strings.Contains(t, "double"):
typeName = "double"
case strings.Contains(t, "bool"):
typeName = "bool"
case strings.Contains(t, "binary") || strings.Contains(t, "blob"):
typeName = "bytes"
case strings.Contains(t, "date") || strings.Contains(t, "time"):
typeName = "int64"
default:
typeName = "string"
}
}
comment = gstr.ReplaceByArray(field.Comment, g.SliceStr{
"\n", " ",
"\r", " ",
})
comment = gstr.Trim(comment)
comment = gstr.Replace(comment, `\n`, " ")
comment, _ = gregex.ReplaceString(`\s{2,}`, ` `, comment)
if jsonTagName := formatCase(field.Name, in.JsonCase); jsonTagName != "" {
jsonTagStr = fmt.Sprintf(`[(gogoproto.jsontag) = "%s"]`, jsonTagName)
// beautiful indent.
if index < 10 {
// 3 spaces
jsonTagStr = " " + jsonTagStr
} else if index < 100 {
// 2 spaces
jsonTagStr = " " + jsonTagStr
} else {
// 1 spaces
jsonTagStr = " " + jsonTagStr
}
}
return []string{
" #" + typeName,
" #" + formatCase(field.Name, in.NameCase),
" #= " + gconv.String(index) + jsonTagStr + ";",
" #" + fmt.Sprintf(`// %s`, comment),
}
}
func getTplPbEntityContent(tplEntityPath string) string {
if tplEntityPath != "" {
return gfile.GetContents(tplEntityPath)
}
return consts.TemplatePbEntityMessageContent
}
// formatCase call gstr.Case* function to convert the s to specified case.
func formatCase(str, caseStr string) string {
switch gstr.ToLower(caseStr) {
case gstr.ToLower("Camel"):
return gstr.CaseCamel(str)
case gstr.ToLower("CamelLower"):
return gstr.CaseCamelLower(str)
case gstr.ToLower("Kebab"):
return gstr.CaseKebab(str)
case gstr.ToLower("KebabScreaming"):
return gstr.CaseKebabScreaming(str)
case gstr.ToLower("Snake"):
return gstr.CaseSnake(str)
case gstr.ToLower("SnakeFirstUpper"):
return gstr.CaseSnakeFirstUpper(str)
case gstr.ToLower("SnakeScreaming"):
return gstr.CaseSnakeScreaming(str)
case "none":
return ""
}
return str
}
func sortFieldKeyForPbEntity(fieldMap map[string]*gdb.TableField) []string {
names := make(map[int]string)
for _, field := range fieldMap {
names[field.Index] = field.Name
}
var (
result = make([]string, len(names))
i = 0
j = 0
)
for {
if len(names) == 0 {
break
}
if val, ok := names[i]; ok {
result[j] = val
j++
delete(names, i)
}
i++
}
return result
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (

View File

@ -1,8 +1,15 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"fmt"
"os"
"strings"
"github.com/gogf/gf/v2/frame/g"
@ -10,13 +17,16 @@ import (
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gres"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/allyes"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
var (
// Init .
Init = cInit{}
)
@ -25,18 +35,24 @@ type cInit struct {
}
const (
cInitRepoPrefix = `github.com/gogf/`
cInitMonoRepo = `template-mono`
cInitSingleRepo = `template-single`
cInitBrief = `create and initialize an empty GoFrame project`
cInitEg = `
cInitRepoPrefix = `github.com/gogf/`
cInitMonoRepo = `template-mono`
cInitMonoRepoApp = `template-mono-app`
cInitSingleRepo = `template-single`
cInitBrief = `create and initialize an empty GoFrame project`
cInitEg = `
gf init my-project
gf init my-mono-repo -m
gf init my-mono-repo -a
`
cInitNameBrief = `
name for the project. It will create a folder with NAME in current directory.
The NAME will also be the module name for the project.
`
// cInitGitDir the git directory
cInitGitDir = ".git"
// cInitGitignore the gitignore file
cInitGitignore = ".gitignore"
)
func init() {
@ -48,32 +64,41 @@ func init() {
}
type cInitInput struct {
g.Meta `name:"init"`
Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"`
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
g.Meta `name:"init"`
Name string `name:"NAME" arg:"true" v:"required" brief:"{cInitNameBrief}"`
Mono bool `name:"mono" short:"m" brief:"initialize a mono-repo instead a single-repo" orphan:"true"`
MonoApp bool `name:"monoApp" short:"a" brief:"initialize a mono-repo-app instead a single-repo" orphan:"true"`
Update bool `name:"update" short:"u" brief:"update to the latest goframe version" orphan:"true"`
Module string `name:"module" short:"g" brief:"custom go module"`
}
type cInitOutput struct{}
func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err error) {
var overwrote = false
if !gfile.IsEmpty(in.Name) && !allyes.Check() {
s := gcmd.Scanf(`the folder "%s" is not empty, files might be overwrote, continue? [y/n]: `, in.Name)
if strings.EqualFold(s, "n") {
return
}
overwrote = true
}
mlog.Print("initializing...")
// Create project folder and files.
var (
templateRepoName string
gitignoreFile = in.Name + "/" + cInitGitignore
)
if in.Mono {
templateRepoName = cInitMonoRepo
} else if in.MonoApp {
templateRepoName = cInitMonoRepoApp
} else {
templateRepoName = cInitSingleRepo
}
err = gres.Export(templateRepoName, in.Name, gres.ExportOption{
RemovePrefix: templateRepoName,
})
@ -81,14 +106,45 @@ func (c cInit) Index(ctx context.Context, in cInitInput) (out *cInitOutput, err
return
}
// build ignoreFiles from the .gitignore file
ignoreFiles := make([]string, 0, 10)
ignoreFiles = append(ignoreFiles, cInitGitDir)
// in.MonoApp is a mono-repo-app, it should ignore the .gitignore file
if overwrote && !in.MonoApp {
err = gfile.ReadLines(gitignoreFile, func(line string) error {
// Add only hidden files or directories
// If other directories are added, it may cause the entire directory to be ignored
// such as 'main' in the .gitignore file, but the path is ' D:\main\my-project '
if line != "" && strings.HasPrefix(line, ".") {
ignoreFiles = append(ignoreFiles, line)
}
return nil
})
// if not found the .gitignore file will skip os.ErrNotExist error
if err != nil && !os.IsNotExist(err) {
return
}
}
// Get template name and module name.
if in.Module == "" {
in.Module = gfile.Basename(gfile.RealPath(in.Name))
}
if in.MonoApp {
pwd := gfile.Pwd() + string(os.PathSeparator) + in.Name
in.Module = utils.GetImportPath(pwd)
}
// Replace template name to project name.
err = gfile.ReplaceDir(
cInitRepoPrefix+templateRepoName,
gfile.Basename(gfile.RealPath(in.Name)),
in.Name,
"*",
true,
)
err = gfile.ReplaceDirFunc(func(path, content string) string {
for _, ignoreFile := range ignoreFiles {
if strings.Contains(path, ignoreFile) {
return content
}
}
return gstr.Replace(gfile.GetContents(path), cInitRepoPrefix+templateRepoName, in.Module)
}, in.Name, "*", true)
if err != nil {
return
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
@ -57,7 +63,7 @@ func init() {
}
type cPackInput struct {
g.Meta `name:"pack"`
g.Meta `name:"pack" config:"gfcli.pack"`
Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`

View File

@ -1,10 +1,19 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/gogf/gf/v2/container/gtype"
"github.com/gogf/gf/v2/frame/g"
@ -18,19 +27,18 @@ import (
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
var (
Run = cRun{}
)
var Run = cRun{}
type cRun struct {
g.Meta `name:"run" usage:"{cRunUsage}" brief:"{cRunBrief}" eg:"{cRunEg}" dc:"{cRunDc}"`
}
type cRunApp struct {
File string // Go run file name.
Path string // Directory storing built binary.
Options string // Extra "go run" options.
Args string // Custom arguments.
File string // Go run file name.
Path string // Directory storing built binary.
Options string // Extra "go run" options.
Args string // Custom arguments.
WatchPaths []string // Watch paths for live reload.
}
const (
@ -40,94 +48,125 @@ const (
gf run main.go
gf run main.go --args "server -p 8080"
gf run main.go -mod=vendor
gf run main.go -w "manifest/config/*.yaml"
`
cRunDc = `
The "run" command is used for running go codes with hot-compiled-like feature,
which compiles and runs the go codes asynchronously when codes change.
`
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "manifest/output" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
cRunFileBrief = `building file path.`
cRunPathBrief = `output directory path for built binary file. it's "./" in default`
cRunExtraBrief = `the same options as "go run"/"go build" except some options as follows defined`
cRunArgsBrief = `custom arguments for your process`
cRunWatchPathsBrief = `watch additional paths for live reload, separated by ",". i.e. "manifest/config/*.yaml"`
)
var (
process *gproc.Process
)
var process *gproc.Process
func init() {
gtag.Sets(g.MapStrStr{
`cRunUsage`: cRunUsage,
`cRunBrief`: cRunBrief,
`cRunEg`: cRunEg,
`cRunDc`: cRunDc,
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
`cRunUsage`: cRunUsage,
`cRunBrief`: cRunBrief,
`cRunEg`: cRunEg,
`cRunDc`: cRunDc,
`cRunFileBrief`: cRunFileBrief,
`cRunPathBrief`: cRunPathBrief,
`cRunExtraBrief`: cRunExtraBrief,
`cRunArgsBrief`: cRunArgsBrief,
`cRunWatchPathsBrief`: cRunWatchPathsBrief,
})
}
type (
cRunInput struct {
g.Meta `name:"run"`
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
g.Meta `name:"run" config:"gfcli.run"`
File string `name:"FILE" arg:"true" brief:"{cRunFileBrief}" v:"required"`
Path string `name:"path" short:"p" brief:"{cRunPathBrief}" d:"./"`
Extra string `name:"extra" short:"e" brief:"{cRunExtraBrief}"`
Args string `name:"args" short:"a" brief:"{cRunArgsBrief}"`
WatchPaths []string `name:"watchPaths" short:"w" brief:"{cRunWatchPathsBrief}"`
}
cRunOutput struct{}
)
func (c cRun) Index(ctx context.Context, in cRunInput) (out *cRunOutput, err error) {
if !gfile.Exists(in.File) {
mlog.Fatalf(`given file "%s" not found`, in.File)
}
if !gfile.IsFile(in.File) {
mlog.Fatalf(`given "%s" is not a file`, in.File)
}
// Necessary check.
if gproc.SearchBinary("go") == "" {
mlog.Fatalf(`command "go" not found in your environment, please install golang first to proceed this command`)
}
if len(in.WatchPaths) == 1 {
in.WatchPaths = strings.Split(in.WatchPaths[0], ",")
mlog.Printf("watchPaths: %v", in.WatchPaths)
}
app := &cRunApp{
File: in.File,
Path: in.Path,
Options: in.Extra,
Args: in.Args,
File: in.File,
Path: filepath.FromSlash(in.Path),
Options: in.Extra,
Args: in.Args,
WatchPaths: in.WatchPaths,
}
dirty := gtype.NewBool()
_, err = gfsnotify.Add(gfile.RealPath("."), func(event *gfsnotify.Event) {
outputPath := app.genOutputPath()
callbackFunc := func(event *gfsnotify.Event) {
if !event.IsWrite() && !event.IsCreate() && !event.IsRemove() && !event.IsRename() {
return
}
if gfile.ExtName(event.Path) != "go" {
return
}
// Variable `dirty` is used for running the changes only one in one second.
if !dirty.Cas(false, true) {
return
}
// With some delay in case of multiple code changes in very short interval.
gtimer.SetTimeout(ctx, 1500*gtime.MS, func(ctx context.Context) {
defer dirty.Set(false)
mlog.Printf(`go file changes: %s`, event.String())
app.Run(ctx)
mlog.Printf(`watched file changes: %s`, event.String())
app.Run(ctx, outputPath)
})
})
if err != nil {
mlog.Fatal(err)
}
go app.Run(ctx)
if len(app.WatchPaths) > 0 {
for _, path := range app.WatchPaths {
_, err = gfsnotify.Add(gfile.RealPath(path), callbackFunc)
if err != nil {
mlog.Fatal(err)
}
}
} else {
_, err = gfsnotify.Add(gfile.RealPath("."), callbackFunc)
if err != nil {
mlog.Fatal(err)
}
}
go app.Run(ctx, outputPath)
gproc.AddSigHandlerShutdown(func(sig os.Signal) {
app.End(ctx, sig, outputPath)
os.Exit(0)
})
gproc.Listen()
select {}
}
func (app *cRunApp) Run(ctx context.Context) {
func (app *cRunApp) Run(ctx context.Context, outputPath string) {
// Rebuild and run the codes.
renamePath := ""
mlog.Printf("build: %s", app.File)
outputPath := gfile.Join(app.Path, gfile.Name(app.File))
if runtime.GOOS == "windows" {
outputPath += ".exe"
if gfile.Exists(outputPath) {
renamePath = outputPath + "~"
if err := gfile.Rename(outputPath, renamePath); err != nil {
mlog.Print(err)
}
}
}
// In case of `pipe: too many open files` error.
// Build the app.
buildCommand := fmt.Sprintf(
@ -146,7 +185,6 @@ func (app *cRunApp) Run(ctx context.Context) {
if process != nil {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
//return
}
}
// Run the binary file.
@ -165,3 +203,81 @@ func (app *cRunApp) Run(ctx context.Context) {
mlog.Printf("build running pid: %d", pid)
}
}
func (app *cRunApp) End(ctx context.Context, sig os.Signal, outputPath string) {
// Delete the binary file.
// firstly, kill the process.
if process != nil {
if sig != nil && runtime.GOOS != "windows" {
if err := process.Signal(sig); err != nil {
mlog.Debugf("send signal to process error: %s", err.Error())
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
}
} else {
waitCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
done := make(chan error, 1)
go func() {
select {
case <-waitCtx.Done():
done <- waitCtx.Err()
case done <- process.Wait():
}
}()
err := <-done
if err != nil {
mlog.Debugf("process wait error: %s", err.Error())
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
}
} else {
mlog.Debug("process exited gracefully")
}
}
} else {
if err := process.Kill(); err != nil {
mlog.Debugf("kill process error: %s", err.Error())
}
}
}
if err := gfile.RemoveFile(outputPath); err != nil {
mlog.Printf("delete binary file error: %s", err.Error())
} else {
mlog.Printf("deleted binary file: %s", outputPath)
}
}
func (app *cRunApp) genOutputPath() (outputPath string) {
var renamePath string
outputPath = gfile.Join(app.Path, gfile.Name(app.File))
if runtime.GOOS == "windows" {
outputPath += ".exe"
if gfile.Exists(outputPath) {
renamePath = outputPath + "~"
if err := gfile.Rename(outputPath, renamePath); err != nil {
mlog.Print(err)
}
}
}
return filepath.FromSlash(outputPath)
}
func matchWatchPaths(watchPaths []string, eventPath string) bool {
for _, path := range watchPaths {
absPath, err := filepath.Abs(path)
if err != nil {
mlog.Printf("match watchPath '%s' error: %s", path, err.Error())
continue
}
matched, err := filepath.Match(absPath, eventPath)
if err != nil {
mlog.Printf("match watchPath '%s' error: %s", path, err.Error())
continue
}
if matched {
return true
}
}
return false
}

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
@ -33,7 +39,7 @@ like json/xml/yaml/toml/ini.
cTplParseEg = `
gf tpl parse -p ./template -v values.json -r
gf tpl parse -p ./template -v values.json -n *.tpl -r
gf tpl parse -p ./template -v values.json -d '${,}}' -r
gf tpl parse -p ./template -v values.json -d '${{,}}' -r
gf tpl parse -p ./template -v values.json -o ./template.parsed
`
cTplSupportValuesFilePattern = `*.json,*.xml,*.yaml,*.yml,*.toml,*.ini`
@ -41,7 +47,7 @@ gf tpl parse -p ./template -v values.json -o ./template.parsed
type (
cTplParseInput struct {
g.Meta `name:"parse" brief:"{cTplParseBrief}" eg:"{cTplParseEg}"`
g.Meta `name:"parse" config:"gfcli.tpl.parse" brief:"{cTplParseBrief}" eg:"{cTplParseEg}"`
Path string `name:"path" short:"p" brief:"template file or folder path" v:"required"`
Pattern string `name:"pattern" short:"n" brief:"template file pattern when path is a folder, default is:*" d:"*"`
Recursive bool `name:"recursive" short:"c" brief:"recursively parsing files if path is folder, default is:true" d:"true"`
@ -63,7 +69,7 @@ func init() {
}
func (c *cTpl) Parse(ctx context.Context, in cTplParseInput) (out *cTplParseOutput, err error) {
if in.Output == "" && in.Replace == false {
if in.Output == "" && !in.Replace {
return nil, gerror.New(`parameter output and replace should not be both empty`)
}
delimiters := gstr.SplitAndTrim(in.Delimiters, ",")

View File

@ -1,18 +1,28 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"fmt"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
"github.com/gogf/gf/v2/container/gset"
"runtime"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/selfupdate"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/genv"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
var (
@ -30,7 +40,11 @@ gf up
gf up -a
gf up -c
gf up -cf
gf up -a -m=install
gf up -a -m=install -p=github.com/gogf/gf/cmd/gf/v2@latest
`
cliMethodHttpDownload = "http"
cliMethodGoInstall = "install"
)
func init() {
@ -40,10 +54,14 @@ func init() {
}
type cUpInput struct {
g.Meta `name:"up" config:"gfcli.up"`
All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
g.Meta `name:"up" config:"gfcli.up"`
All bool `name:"all" short:"a" brief:"upgrade both version and cli, auto fix codes" orphan:"true"`
Cli bool `name:"cli" short:"c" brief:"also upgrade CLI tool" orphan:"true"`
Fix bool `name:"fix" short:"f" brief:"auto fix codes(it only make sense if cli is to be upgraded)" orphan:"true"`
CliDownloadingMethod string `name:"cli-download-method" short:"m" brief:"cli upgrade method: http=download binary via HTTP GET, install=upgrade via go install" d:"http"`
// CliModulePath specifies the module path for CLI installation via go install.
// This is used when CliDownloadingMethod is set to "install".
CliModulePath string `name:"cli-module-path" short:"p" brief:"custom cli module path for upgrade CLI tool with go install method" d:"github.com/gogf/gf/cmd/gf/v2@latest"`
}
type cUpOutput struct{}
@ -67,7 +85,7 @@ func (c cUp) Index(ctx context.Context, in cUpInput) (out *cUpOutput, err error)
}
if in.Cli {
if err = c.doUpgradeCLI(ctx); err != nil {
if err = c.doUpgradeCLI(ctx, in); err != nil {
return nil, err
}
}
@ -117,6 +135,8 @@ func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeV
if gfile.Exists(goModPath) {
var packages []Package
err = gfile.ReadLines(goModPath, func(line string) error {
line = gstr.Trim(line)
line = gstr.TrimLeftStr(line, "require ")
line = gstr.Trim(line)
if gstr.HasPrefix(line, gfPackage) {
array := gstr.SplitAndTrim(line, " ")
@ -132,8 +152,9 @@ func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeV
}
for _, pkg := range packages {
mlog.Printf(`upgrading "%s" from "%s" to "latest"`, pkg.Name, pkg.Version)
// go get -u
command := fmt.Sprintf(`cd %s && go get -u %s@latest`, dirPath, pkg.Name)
mlog.Printf(`running command: go get %s@latest`, pkg.Name)
// go get @latest
command := fmt.Sprintf(`cd %s && go get %s@latest`, dirPath, pkg.Name)
if err = gproc.ShellRun(ctx, command); err != nil {
return
}
@ -158,8 +179,22 @@ func (c cUp) doUpgradeVersion(ctx context.Context, in cUpInput) (out *doUpgradeV
}
// doUpgradeCLI downloads the new version binary with process.
func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
func (c cUp) doUpgradeCLI(ctx context.Context, in cUpInput) (err error) {
mlog.Print(`start upgrading cli...`)
fmt.Println(` cli upgrade method:`, in.CliDownloadingMethod)
switch in.CliDownloadingMethod {
case cliMethodHttpDownload:
return c.doUpgradeCLIWithHttpDownload(ctx)
case cliMethodGoInstall:
return c.doUpgradeCLIWithGoInstall(ctx, in)
default:
mlog.Fatalf(`invalid cli upgrade method: "%s", please use "http" or "install"`, in.CliDownloadingMethod)
}
return
}
func (c cUp) doUpgradeCLIWithHttpDownload(ctx context.Context) (err error) {
mlog.Print(`start upgrading cli with http get download...`)
var (
downloadUrl = fmt.Sprintf(
`https://github.com/gogf/gf/releases/latest/download/gf_%s_%s`,
@ -167,6 +202,11 @@ func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
)
localSaveFilePath = gfile.SelfPath() + "~"
)
if runtime.GOOS == "windows" {
downloadUrl += ".exe"
}
mlog.Printf(`start downloading "%s" to "%s", it may take some time`, downloadUrl, localSaveFilePath)
err = utils.HTTPDownloadFileWithPercent(downloadUrl, localSaveFilePath)
if err != nil {
@ -176,7 +216,7 @@ func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
defer func() {
mlog.Printf(`new version cli binary is successfully installed to "%s"`, gfile.SelfPath())
mlog.Printf(`remove temporary buffer file "%s"`, localSaveFilePath)
_ = gfile.Remove(localSaveFilePath)
_ = gfile.RemoveFile(localSaveFilePath)
}()
// It fails if file not exist or its size is less than 1MB.
@ -184,17 +224,49 @@ func (c cUp) doUpgradeCLI(ctx context.Context) (err error) {
mlog.Fatalf(`download "%s" to "%s" failed`, downloadUrl, localSaveFilePath)
}
// It replaces self binary with new version cli binary.
switch runtime.GOOS {
case "windows":
if err := gfile.Rename(localSaveFilePath, gfile.SelfPath()); err != nil {
mlog.Fatalf(`install failed: %s`, err.Error())
}
newFile, err := gfile.Open(localSaveFilePath)
if err != nil {
return err
}
// selfupdate
err = selfupdate.Apply(newFile, selfupdate.Options{})
if err != nil {
return err
}
return
}
default:
if err := gfile.PutBytes(gfile.SelfPath(), gfile.GetBytes(localSaveFilePath)); err != nil {
mlog.Fatalf(`install failed: %s`, err.Error())
}
func (c cUp) doUpgradeCLIWithGoInstall(ctx context.Context, in cUpInput) (err error) {
mlog.Print(`upgrading cli with go install...`)
if !genv.Contains("GOPATH") {
mlog.Fatal(`"GOPATH" environment variable does not exist, please check your go installation`)
}
command := fmt.Sprintf(`go install %s`, in.CliModulePath)
mlog.Printf(`running command: %s`, command)
err = gproc.ShellRun(ctx, command)
if err != nil {
return err
}
cliFilePath := gfile.Join(genv.Get("GOPATH").String(), "bin/gf")
if runtime.GOOS == "windows" {
cliFilePath += ".exe"
}
// It fails if file not exist or its size is less than 1MB.
if !gfile.Exists(cliFilePath) || gfile.Size(cliFilePath) < 1024*1024 {
mlog.Fatalf(`go install %s failed, "%s" does not exist or its size is less than 1MB`, in.CliModulePath, cliFilePath)
}
newFile, err := gfile.Open(cliFilePath)
if err != nil {
return err
}
// selfupdate
err = selfupdate.Apply(newFile, selfupdate.Options{})
if err != nil {
return err
}
return
}

View File

@ -1,14 +1,25 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"bytes"
"context"
"fmt"
"runtime"
"strings"
"time"
"github.com/gogf/gf/v2"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gbuild"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
@ -19,6 +30,10 @@ var (
Version = cVersion{}
)
const (
defaultIndent = "{{indent}}"
)
type cVersion struct {
g.Meta `name:"version" brief:"show version information of current binary"`
}
@ -30,40 +45,98 @@ type cVersionInput struct {
type cVersionOutput struct{}
func (c cVersion) Index(ctx context.Context, in cVersionInput) (*cVersionOutput, error) {
info := gbuild.Info()
if info.Git == "" {
info.Git = "none"
}
mlog.Printf(`GoFrame CLI Tool %s, https://goframe.org`, gf.VERSION)
gfVersion, err := c.getGFVersionOfCurrentProject()
if err != nil {
gfVersion = err.Error()
detailBuffer := &detailBuffer{}
detailBuffer.WriteString(fmt.Sprintf("%s", gf.VERSION))
detailBuffer.appendLine(0, "Welcome to GoFrame!")
detailBuffer.appendLine(0, "Env Detail:")
goVersion, ok := getGoVersion()
if ok {
detailBuffer.appendLine(1, fmt.Sprintf("Go Version: %s", goVersion))
detailBuffer.appendLine(1, fmt.Sprintf("GF Version(go.mod): %s", getGoFrameVersion(2)))
} else {
gfVersion = gfVersion + " in current go.mod"
}
mlog.Printf(`GoFrame Version: %s`, gfVersion)
mlog.Printf(`CLI Installed At: %s`, gfile.SelfPath())
if info.GoFrame == "" {
mlog.Print(`Current is a custom installed version, no installation information.`)
return nil, nil
v, err := c.getGFVersionOfCurrentProject()
if err == nil {
detailBuffer.appendLine(1, fmt.Sprintf("GF Version(go.mod): %s", v))
} else {
detailBuffer.appendLine(1, fmt.Sprintf("GF Version(go.mod): %s", err.Error()))
}
}
mlog.Print(gstr.Trim(fmt.Sprintf(`
CLI Built Detail:
Go Version: %s
GF Version: %s
Git Commit: %s
Build Time: %s
`, info.Golang, info.GoFrame, info.Git, info.Time)))
detailBuffer.appendLine(0, "CLI Detail:")
detailBuffer.appendLine(1, fmt.Sprintf("Installed At: %s", gfile.SelfPath()))
info := gbuild.Info()
if info.GoFrame == "" {
detailBuffer.appendLine(1, fmt.Sprintf("Built Go Version: %s", runtime.Version()))
detailBuffer.appendLine(1, fmt.Sprintf("Built GF Version: %s", gf.VERSION))
} else {
if info.Git == "" {
info.Git = "none"
}
detailBuffer.appendLine(1, fmt.Sprintf("Built Go Version: %s", info.Golang))
detailBuffer.appendLine(1, fmt.Sprintf("Built GF Version: %s", info.GoFrame))
detailBuffer.appendLine(1, fmt.Sprintf("Git Commit: %s", info.Git))
detailBuffer.appendLine(1, fmt.Sprintf("Built Time: %s", info.Time))
}
detailBuffer.appendLine(0, "Others Detail:")
detailBuffer.appendLine(1, "Docs: https://goframe.org")
detailBuffer.appendLine(1, fmt.Sprintf("Now : %s", time.Now().Format(time.RFC3339)))
mlog.Print(detailBuffer.replaceAllIndent(" "))
return nil, nil
}
// detailBuffer is a buffer for detail information.
type detailBuffer struct {
bytes.Buffer
}
// appendLine appends a line to the buffer with given indent level.
func (d *detailBuffer) appendLine(indentLevel int, line string) {
d.WriteString(fmt.Sprintf("\n%s%s", strings.Repeat(defaultIndent, indentLevel), line))
}
// replaceAllIndent replaces the tab with given indent string and prints the buffer content.
func (d *detailBuffer) replaceAllIndent(indentStr string) string {
return strings.ReplaceAll(d.String(), defaultIndent, indentStr)
}
// getGoFrameVersion returns the goframe version of current project using.
func getGoFrameVersion(indentLevel int) (gfVersion string) {
pkgInfo, err := gproc.ShellExec(context.Background(), `go list -f "{{if (not .Main)}}{{.Path}}@{{.Version}}{{end}}" -m all`)
if err != nil {
return "cannot find go.mod"
}
pkgList := gstr.Split(pkgInfo, "\n")
for _, v := range pkgList {
if strings.HasPrefix(v, "github.com/gogf/gf") {
gfVersion += fmt.Sprintf("\n%s%s", strings.Repeat(defaultIndent, indentLevel), v)
}
}
return
}
// getGoVersion returns the go version
func getGoVersion() (goVersion string, ok bool) {
goVersion, err := gproc.ShellExec(context.Background(), "go version")
if err != nil {
return "", false
}
goVersion = gstr.TrimLeftStr(goVersion, "go version ")
goVersion = gstr.TrimRightStr(goVersion, "\n")
return goVersion, true
}
// getGFVersionOfCurrentProject checks and returns the GoFrame version current project using.
func (c cVersion) getGFVersionOfCurrentProject() (string, error) {
goModPath := gfile.Join(gfile.Pwd(), "go.mod")
if gfile.Exists(goModPath) {
lines := gstr.SplitAndTrim(gfile.GetContents(goModPath), "\n")
for _, line := range lines {
line = gstr.Trim(line)
line = gstr.TrimLeftStr(line, "require ")
line = gstr.Trim(line)
// Version 1.
match, err := gregex.MatchString(`^github\.com/gogf/gf\s+(.+)$`, line)

View File

@ -0,0 +1,38 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"context"
"fmt"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/test/gtest"
)
var (
ctx = context.Background()
testDB gdb.DB
link = "mysql:root:12345678@tcp(127.0.0.1:3306)/test?loc=Local&parseTime=true"
)
func init() {
var err error
testDB, err = gdb.New(gdb.ConfigNode{
Link: link,
})
if err != nil {
panic(err)
}
}
func dropTableWithDb(db gdb.DB, table string) {
dropTableStmt := fmt.Sprintf("DROP TABLE IF EXISTS `%s`", table)
if _, err := db.Exec(ctx, dropTableStmt); err != nil {
gtest.Error(err)
}
}

View File

@ -0,0 +1,151 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"testing"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/text/gstr"
)
func Test_Build_Single(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
buildPath = gtest.DataPath(`build`, `single`)
pwd = gfile.Pwd()
binaryName = `t.test`
binaryPath = gtest.DataPath(`build`, `single`, binaryName)
f = cBuild{}
)
defer gfile.Chdir(pwd)
defer gfile.Remove(binaryPath)
err := gfile.Chdir(buildPath)
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), false)
_, err = f.Index(ctx, cBuildInput{
File: cBuildDefaultFile,
Name: binaryName,
})
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), true)
})
}
func Test_Build_Single_Output(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
buildPath = gtest.DataPath(`build`, `single`)
pwd = gfile.Pwd()
binaryName = `tt`
binaryDirPath = gtest.DataPath(`build`, `single`, `tt`)
binaryPath = gtest.DataPath(`build`, `single`, `tt`, binaryName)
f = cBuild{}
)
defer gfile.Chdir(pwd)
defer gfile.Remove(binaryDirPath)
err := gfile.Chdir(buildPath)
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), false)
_, err = f.Index(ctx, cBuildInput{
Output: "./tt/tt",
})
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), true)
})
}
func Test_Build_Single_Path(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
buildPath = gtest.DataPath(`build`, `single`)
pwd = gfile.Pwd()
dirName = "ttt"
binaryName = `main`
binaryDirPath = gtest.DataPath(`build`, `single`, dirName)
binaryPath = gtest.DataPath(`build`, `single`, dirName, binaryName)
f = cBuild{}
)
defer gfile.Chdir(pwd)
defer gfile.Remove(binaryDirPath)
err := gfile.Chdir(buildPath)
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), false)
_, err = f.Index(ctx, cBuildInput{
Path: "ttt",
})
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), true)
})
}
func Test_Build_Single_VarMap(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
buildPath = gtest.DataPath(`build`, `varmap`)
pwd = gfile.Pwd()
binaryName = `main`
binaryPath = gtest.DataPath(`build`, `varmap`, binaryName)
f = cBuild{}
)
defer gfile.Chdir(pwd)
defer gfile.Remove(binaryPath)
err := gfile.Chdir(buildPath)
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), false)
_, err = f.Index(ctx, cBuildInput{
VarMap: map[string]any{
"a": "1",
"b": "2",
},
})
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPath), true)
result, err := gproc.ShellExec(ctx, binaryPath)
t.AssertNil(err)
t.Assert(gstr.Contains(result, `a: 1`), true)
t.Assert(gstr.Contains(result, `b: 2`), true)
})
}
func Test_Build_Multiple(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
buildPath = gtest.DataPath(`build`, `multiple`)
pwd = gfile.Pwd()
binaryDirPath = gtest.DataPath(`build`, `multiple`, `temp`)
binaryPathLinux = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `linux_amd64`, `ttt`)
binaryPathWindows = gtest.DataPath(`build`, `multiple`, `temp`, `v1.1`, `windows_amd64`, `ttt.exe`)
f = cBuild{}
)
defer gfile.Chdir(pwd)
defer gfile.Remove(binaryDirPath)
err := gfile.Chdir(buildPath)
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPathLinux), false)
t.Assert(gfile.Exists(binaryPathWindows), false)
_, err = f.Index(ctx, cBuildInput{
File: "multiple.go",
Name: "ttt",
Version: "v1.1",
Arch: "amd64",
System: "linux, windows",
Path: "temp",
})
t.AssertNil(err)
t.Assert(gfile.Exists(binaryPathLinux), true)
t.Assert(gfile.Exists(binaryPathWindows), true)
})
}

View File

@ -0,0 +1,24 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"testing"
"github.com/gogf/gf/v2/test/gtest"
)
func Test_Fix_doFixV25Content(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
content = gtest.DataContent(`fix`, `fix25_content.go`)
f = cFix{}
)
_, err := f.doFixV25Content(content)
t.AssertNil(err)
})
}

View File

@ -0,0 +1,310 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"path/filepath"
"testing"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genctrl"
)
func Test_Gen_Ctrl_Default(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
path = gfile.Temp(guid.S())
apiFolder = gtest.DataPath("genctrl", "api")
in = genctrl.CGenCtrlInput{
SrcFolder: apiFolder,
DstFolder: path,
WatchFile: "",
SdkPath: "",
SdkStdVersion: false,
SdkNoV1: false,
Clear: false,
Merge: false,
}
)
err := gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
t.AssertNil(err)
// apiInterface file
var (
genApi = apiFolder + filepath.FromSlash("/article/article.go")
genApiExpect = apiFolder + filepath.FromSlash("/article/article_expect.go")
)
defer gfile.Remove(genApi)
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
path + filepath.FromSlash("/article/article.go"),
path + filepath.FromSlash("/article/article_new.go"),
path + filepath.FromSlash("/article/article_v1_create.go"),
path + filepath.FromSlash("/article/article_v1_get_list.go"),
path + filepath.FromSlash("/article/article_v1_get_one.go"),
path + filepath.FromSlash("/article/article_v1_update.go"),
path + filepath.FromSlash("/article/article_v2_create.go"),
path + filepath.FromSlash("/article/article_v2_update.go"),
})
// content
testPath := gtest.DataPath("genctrl", "controller")
expectFiles := []string{
testPath + filepath.FromSlash("/article/article.go"),
testPath + filepath.FromSlash("/article/article_new.go"),
testPath + filepath.FromSlash("/article/article_v1_create.go"),
testPath + filepath.FromSlash("/article/article_v1_get_list.go"),
testPath + filepath.FromSlash("/article/article_v1_get_one.go"),
testPath + filepath.FromSlash("/article/article_v1_update.go"),
testPath + filepath.FromSlash("/article/article_v2_create.go"),
testPath + filepath.FromSlash("/article/article_v2_update.go"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func expectFilesContent(t *gtest.T, paths []string, expectPaths []string) {
for i, expectFile := range expectPaths {
val := gfile.GetContents(paths[i])
expect := gfile.GetContents(expectFile)
t.Assert(val, expect)
}
}
// gf gen ctrl -m
// In the same module, different API files are added
func Test_Gen_Ctrl_UseMerge_AddNewFile(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
ctrlPath = gfile.Temp(guid.S())
//ctrlPath = gtest.DataPath("issue", "3460", "controller")
apiFolder = gtest.DataPath("genctrl-merge", "add_new_file", "api")
in = genctrl.CGenCtrlInput{
SrcFolder: apiFolder,
DstFolder: ctrlPath,
Merge: true,
}
)
const testNewApiFile = `
package v1
import "github.com/gogf/gf/v2/frame/g"
type DictTypeAddReq struct {
g.Meta
}
type DictTypeAddRes struct {
}
`
err := gfile.Mkdir(ctrlPath)
t.AssertNil(err)
defer gfile.Remove(ctrlPath)
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
t.AssertNil(err)
var (
genApi = filepath.Join(apiFolder, "/dict/dict.go")
genApiExpect = filepath.Join(apiFolder, "/dict/dict_expect.go")
)
defer gfile.Remove(genApi)
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
genCtrlFiles, err := gfile.ScanDir(ctrlPath, "*.go", true)
t.AssertNil(err)
t.Assert(genCtrlFiles, []string{
filepath.Join(ctrlPath, "/dict/dict.go"),
filepath.Join(ctrlPath, "/dict/dict_new.go"),
filepath.Join(ctrlPath, "/dict/dict_v1_dict_type.go"),
})
expectCtrlPath := gtest.DataPath("genctrl-merge", "add_new_file", "controller")
expectFiles := []string{
filepath.Join(expectCtrlPath, "/dict/dict.go"),
filepath.Join(expectCtrlPath, "/dict/dict_new.go"),
filepath.Join(expectCtrlPath, "/dict/dict_v1_dict_type.go"),
}
// Line Feed maybe \r\n or \n
expectFilesContent(t, genCtrlFiles, expectFiles)
// Add a new API file
newApiFilePath := filepath.Join(apiFolder, "/dict/v1/test_new.go")
err = gfile.PutContents(newApiFilePath, testNewApiFile)
t.AssertNil(err)
defer gfile.Remove(newApiFilePath)
// Then execute the command
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
t.AssertNil(err)
genApi = filepath.Join(apiFolder, "/dict.go")
genApiExpect = filepath.Join(apiFolder, "/dict_add_new_ctrl_expect.gotest")
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
genCtrlFiles = append(genCtrlFiles, filepath.Join(ctrlPath, "/dict/dict_v1_test_new.go"))
// Use the gotest suffix, otherwise the IDE will delete the import
expectFiles = append(expectFiles, filepath.Join(expectCtrlPath, "/dict/dict_v1_test_new.gotest"))
// Line Feed maybe \r\n or \n
expectFilesContent(t, genCtrlFiles, expectFiles)
})
}
// gf gen ctrl -m
// In the same module, Add the same file to the API
func Test_Gen_Ctrl_UseMerge_AddNewCtrl(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
ctrlPath = gfile.Temp(guid.S())
//ctrlPath = gtest.DataPath("issue", "3460", "controller")
apiFolder = gtest.DataPath("genctrl-merge", "add_new_ctrl", "api")
in = genctrl.CGenCtrlInput{
SrcFolder: apiFolder,
DstFolder: ctrlPath,
Merge: true,
}
)
err := gfile.Mkdir(ctrlPath)
t.AssertNil(err)
defer gfile.Remove(ctrlPath)
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
t.AssertNil(err)
var (
genApi = filepath.Join(apiFolder, "/dict/dict.go")
genApiExpect = filepath.Join(apiFolder, "/dict/dict_expect.go")
)
defer gfile.Remove(genApi)
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
genCtrlFiles, err := gfile.ScanDir(ctrlPath, "*.go", true)
t.AssertNil(err)
t.Assert(genCtrlFiles, []string{
filepath.Join(ctrlPath, "/dict/dict.go"),
filepath.Join(ctrlPath, "/dict/dict_new.go"),
filepath.Join(ctrlPath, "/dict/dict_v1_dict_type.go"),
})
expectCtrlPath := gtest.DataPath("genctrl-merge", "add_new_ctrl", "controller")
expectFiles := []string{
filepath.Join(expectCtrlPath, "/dict/dict.go"),
filepath.Join(expectCtrlPath, "/dict/dict_new.go"),
filepath.Join(expectCtrlPath, "/dict/dict_v1_dict_type.go"),
}
// Line Feed maybe \r\n or \n
expectFilesContent(t, genCtrlFiles, expectFiles)
const testNewApiFile = `
type DictTypeAddReq struct {
g.Meta
}
type DictTypeAddRes struct {
}
`
dictModuleFileName := filepath.Join(apiFolder, "/dict/v1/dict_type.go")
// Save the contents of the file before the changes
apiFileContents := gfile.GetContents(dictModuleFileName)
// Add a new API file
err = gfile.PutContentsAppend(dictModuleFileName, testNewApiFile)
t.AssertNil(err)
//==================================
// Then execute the command
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
t.AssertNil(err)
genApi = filepath.Join(apiFolder, "/dict.go")
genApiExpect = filepath.Join(apiFolder, "/dict_add_new_ctrl_expect.gotest")
t.Assert(gfile.GetContents(genApi), gfile.GetContents(genApiExpect))
// Use the gotest suffix, otherwise the IDE will delete the import
expectFiles[2] = filepath.Join(expectCtrlPath, "/dict/dict_v1_test_new.gotest")
// Line Feed maybe \r\n or \n
expectFilesContent(t, genCtrlFiles, expectFiles)
// Restore the contents of the original API file
err = gfile.PutContents(dictModuleFileName, apiFileContents)
t.AssertNil(err)
})
}
// https://github.com/gogf/gf/issues/3460
func Test_Gen_Ctrl_UseMerge_Issue3460(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
ctrlPath = gfile.Temp(guid.S())
//ctrlPath = gtest.DataPath("issue", "3460", "controller")
apiFolder = gtest.DataPath("issue", "3460", "api")
in = genctrl.CGenCtrlInput{
SrcFolder: apiFolder,
DstFolder: ctrlPath,
WatchFile: "",
SdkPath: "",
SdkStdVersion: false,
SdkNoV1: false,
Clear: false,
Merge: true,
}
)
err := gfile.Mkdir(ctrlPath)
t.AssertNil(err)
defer gfile.Remove(ctrlPath)
_, err = genctrl.CGenCtrl{}.Ctrl(ctx, in)
t.AssertNil(err)
files, err := gfile.ScanDir(ctrlPath, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.Join(ctrlPath, "/hello/hello.go"),
filepath.Join(ctrlPath, "/hello/hello_new.go"),
filepath.Join(ctrlPath, "/hello/hello_v1_req.go"),
filepath.Join(ctrlPath, "/hello/hello_v2_req.go"),
})
expectCtrlPath := gtest.DataPath("issue", "3460", "controller")
expectFiles := []string{
filepath.Join(expectCtrlPath, "/hello/hello.go"),
filepath.Join(expectCtrlPath, "/hello/hello_new.go"),
filepath.Join(expectCtrlPath, "/hello/hello_v1_req.go"),
filepath.Join(expectCtrlPath, "/hello/hello_v2_req.go"),
}
// Line Feed maybe \r\n or \n
for i, expectFile := range expectFiles {
val := gfile.GetContents(files[i])
expect := gfile.GetContents(expectFile)
t.Assert(val, expect)
}
})
}

View File

@ -0,0 +1,462 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"fmt"
"path/filepath"
"testing"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcfg"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
)
// https://github.com/gogf/gf/issues/2572
func Test_Gen_Dao_Issue2572(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table1 = "user1"
table2 = "user2"
issueDirPath = gtest.DataPath(`issue`, `2572`)
)
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql1.sql`)))
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2572`, `sql2.sql`)))
defer dropTableWithDb(db, table1)
defer dropTableWithDb(db, table2)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: "",
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "SnakeScreaming",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: false,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Copy(issueDirPath, path)
t.AssertNil(err)
defer gfile.Remove(path)
pwd := gfile.Pwd()
err = gfile.Chdir(path)
t.AssertNil(err)
defer gfile.Chdir(pwd)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(len(generatedFiles), 8)
for i, generatedFile := range generatedFiles {
generatedFiles[i] = gstr.TrimLeftStr(generatedFile, path)
}
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/internal/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/internal/user_2.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/user_2.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/do/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/do/user_2.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/entity/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/entity/user_2.go")), true)
})
}
// https://github.com/gogf/gf/issues/2616
func Test_Gen_Dao_Issue2616(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table1 = "user1"
table2 = "user2"
issueDirPath = gtest.DataPath(`issue`, `2616`)
)
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql1.sql`)))
t.AssertNil(execSqlFile(db, gtest.DataPath(`issue`, `2616`, `sql2.sql`)))
defer dropTableWithDb(db, table1)
defer dropTableWithDb(db, table2)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: "",
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "SnakeScreaming",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: false,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Copy(issueDirPath, path)
t.AssertNil(err)
defer gfile.Remove(path)
pwd := gfile.Pwd()
err = gfile.Chdir(path)
t.AssertNil(err)
defer gfile.Chdir(pwd)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(len(generatedFiles), 8)
for i, generatedFile := range generatedFiles {
generatedFiles[i] = gstr.TrimLeftStr(generatedFile, path)
}
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/internal/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/internal/user_2.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/dao/user_2.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/do/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/do/user_2.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/entity/user_1.go")), true)
t.Assert(gstr.InArray(generatedFiles,
filepath.FromSlash("/model/entity/user_2.go")), true)
// Key string to check if overwrite the dao files.
// dao user1 is not be overwritten as configured in config.yaml.
// dao user2 is to be overwritten as configured in config.yaml.
var (
keyStr = `// I am not overwritten.`
daoUser1Content = gfile.GetContents(path + "/dao/user_1.go")
daoUser2Content = gfile.GetContents(path + "/dao/user_2.go")
)
t.Assert(gstr.Contains(daoUser1Content, keyStr), true)
t.Assert(gstr.Contains(daoUser2Content, keyStr), false)
})
}
// https://github.com/gogf/gf/issues/2746
func Test_Gen_Dao_Issue2746(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
mdb gdb.DB
link2746 = "mariadb:root:12345678@tcp(127.0.0.1:3307)/test?loc=Local&parseTime=true"
table = "issue2746"
sqlContent = fmt.Sprintf(
gtest.DataContent(`issue`, `2746`, `sql.sql`),
table,
)
)
mdb, err = gdb.New(gdb.ConfigNode{
Link: link2746,
})
t.AssertNil(err)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = mdb.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(mdb, table)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link2746,
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "SnakeScreaming",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: true,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
var (
file = filepath.FromSlash(path + "/model/entity/issue_2746.go")
expectContent = gtest.DataContent(`issue`, `2746`, `issue_2746.go`)
)
t.Assert(expectContent, gfile.GetContents(file))
})
}
// https://github.com/gogf/gf/issues/3459
func Test_Gen_Dao_Issue3459(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`gendao`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
confDir = gtest.DataPath("issue", "3459")
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link,
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "SnakeScreaming",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: false,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
}
)
err = g.Cfg().GetAdapter().(*gcfg.AdapterFile).SetPath(confDir)
t.AssertNil(err)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
// for go mod import path auto retrieve.
err = gfile.Copy(
gtest.DataPath("gendao", "go.mod.txt"),
gfile.Join(path, "go.mod"),
)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.FromSlash(path + "/dao/internal/table_user.go"),
filepath.FromSlash(path + "/dao/table_user.go"),
filepath.FromSlash(path + "/model/do/table_user.go"),
filepath.FromSlash(path + "/model/entity/table_user.go"),
})
// content
testPath := gtest.DataPath("gendao", "generated_user")
expectFiles := []string{
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
filepath.FromSlash(testPath + "/dao/table_user.go"),
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
// https://github.com/gogf/gf/issues/3749
func Test_Gen_Dao_Issue3749(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`issue`, `3749`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link,
Group: group,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
// for go mod import path auto retrieve.
err = gfile.Copy(
gtest.DataPath("gendao", "go.mod.txt"),
gfile.Join(path, "go.mod"),
)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.FromSlash(path + "/dao/internal/table_user.go"),
filepath.FromSlash(path + "/dao/table_user.go"),
filepath.FromSlash(path + "/model/do/table_user.go"),
filepath.FromSlash(path + "/model/entity/table_user.go"),
})
// content
testPath := gtest.DataPath(`issue`, `3749`)
expectFiles := []string{
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
filepath.FromSlash(testPath + "/dao/table_user.go"),
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}

View File

@ -0,0 +1,89 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"testing"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
)
func Test_Gen_Dao_Sharding(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
tableSingle = "single_table"
table1 = "users_0001"
table2 = "users_0002"
table3 = "orders_0001"
table4 = "orders_0002"
sqlFilePath = gtest.DataPath(`gendao`, `sharding`, `sharding.sql`)
)
dropTableWithDb(db, tableSingle)
dropTableWithDb(db, table1)
dropTableWithDb(db, table2)
dropTableWithDb(db, table3)
dropTableWithDb(db, table4)
t.AssertNil(execSqlFile(db, sqlFilePath))
defer dropTableWithDb(db, tableSingle)
defer dropTableWithDb(db, table1)
defer dropTableWithDb(db, table2)
defer dropTableWithDb(db, table3)
defer dropTableWithDb(db, table4)
var (
path = gfile.Temp(guid.S())
// path = "/Users/john/Temp/gen_dao_sharding"
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link,
Group: group,
Prefix: "",
ShardingPattern: []string{
`users_?`,
`orders_?`,
},
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
pwd := gfile.Pwd()
err = gfile.Chdir(path)
t.AssertNil(err)
defer gfile.Chdir(pwd)
defer gfile.RemoveAll(path)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
generatedFiles, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(len(generatedFiles), 12)
var (
daoSingleTableContent = gfile.GetContents(gfile.Join(path, "dao", "single_table.go"))
daoUsersContent = gfile.GetContents(gfile.Join(path, "dao", "users.go"))
daoOrdersContent = gfile.GetContents(gfile.Join(path, "dao", "orders.go"))
)
t.Assert(gstr.Contains(daoSingleTableContent, "SingleTable = singleTableDao{internal.NewSingleTableDao()}"), true)
t.Assert(gstr.Contains(daoUsersContent, "Users = usersDao{internal.NewUsersDao(usersShardingHandler)}"), true)
t.Assert(gstr.Contains(daoUsersContent, "m.Sharding(gdb.ShardingConfig{"), true)
t.Assert(gstr.Contains(daoOrdersContent, "Orders = ordersDao{internal.NewOrdersDao(ordersShardingHandler)}"), true)
t.Assert(gstr.Contains(daoOrdersContent, "m.Sharding(gdb.ShardingConfig{"), true)
})
}

View File

@ -0,0 +1,414 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"fmt"
"path/filepath"
"testing"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/gendao"
)
func Test_Gen_Dao_Default(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`gendao`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link,
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "SnakeScreaming",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: false,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
// for go mod import path auto retrieve.
err = gfile.Copy(
gtest.DataPath("gendao", "go.mod.txt"),
gfile.Join(path, "go.mod"),
)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.FromSlash(path + "/dao/internal/table_user.go"),
filepath.FromSlash(path + "/dao/table_user.go"),
filepath.FromSlash(path + "/model/do/table_user.go"),
filepath.FromSlash(path + "/model/entity/table_user.go"),
})
// content
testPath := gtest.DataPath("gendao", "generated_user")
expectFiles := []string{
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
filepath.FromSlash(testPath + "/dao/table_user.go"),
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func Test_Gen_Dao_TypeMapping(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`gendao`, `user.tpl.sql`),
table,
)
)
defer dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link,
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: false,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
"int": {
Type: "int64",
Import: "",
},
"decimal": {
Type: "decimal.Decimal",
Import: "github.com/shopspring/decimal",
},
},
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
// for go mod import path auto retrieve.
err = gfile.Copy(
gtest.DataPath("gendao", "go.mod.txt"),
gfile.Join(path, "go.mod"),
)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.FromSlash(path + "/dao/internal/table_user.go"),
filepath.FromSlash(path + "/dao/table_user.go"),
filepath.FromSlash(path + "/model/do/table_user.go"),
filepath.FromSlash(path + "/model/entity/table_user.go"),
})
// content
testPath := gtest.DataPath("gendao", "generated_user_type_mapping")
expectFiles := []string{
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
filepath.FromSlash(testPath + "/dao/table_user.go"),
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func Test_Gen_Dao_FieldMapping(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`gendao`, `user.tpl.sql`),
table,
)
)
defer dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: link,
Tables: "",
TablesEx: "",
Group: group,
Prefix: "",
RemovePrefix: "",
JsonCase: "",
ImportPrefix: "",
DaoPath: "",
DoPath: "",
EntityPath: "",
TplDaoIndexPath: "",
TplDaoInternalPath: "",
TplDaoDoPath: "",
TplDaoEntityPath: "",
StdTime: false,
WithTime: false,
GJsonSupport: false,
OverwriteDao: false,
DescriptionTag: false,
NoJsonTag: false,
NoModelComment: false,
Clear: false,
GenTable: false,
TypeMapping: map[gendao.DBFieldTypeName]gendao.CustomAttributeType{
"int": {
Type: "int64",
Import: "",
},
},
FieldMapping: map[gendao.DBTableFieldName]gendao.CustomAttributeType{
"table_user.score": {
Type: "decimal.Decimal",
Import: "github.com/shopspring/decimal",
},
},
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
// for go mod import path auto retrieve.
err = gfile.Copy(
gtest.DataPath("gendao", "go.mod.txt"),
gfile.Join(path, "go.mod"),
)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.FromSlash(path + "/dao/internal/table_user.go"),
filepath.FromSlash(path + "/dao/table_user.go"),
filepath.FromSlash(path + "/model/do/table_user.go"),
filepath.FromSlash(path + "/model/entity/table_user.go"),
})
// content
testPath := gtest.DataPath("gendao", "generated_user_field_mapping")
expectFiles := []string{
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
filepath.FromSlash(testPath + "/dao/table_user.go"),
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func execSqlFile(db gdb.DB, filePath string, args ...any) error {
sqlContent := fmt.Sprintf(
gfile.GetContents(filePath),
args...,
)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err := db.Exec(ctx, v); err != nil {
return err
}
}
return nil
}
func Test_Gen_Dao_Sqlite3(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
table = "table_user"
path = gfile.Temp(guid.S())
linkSqlite3 = fmt.Sprintf("sqlite::@file(%s/db.sqlite3)", path)
sqlContent = fmt.Sprintf(
gtest.DataContent(`gendao`, `sqlite3`, `user.sqlite3.sql`),
table,
)
)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
dbSqlite3, err := gdb.New(gdb.ConfigNode{
Link: linkSqlite3,
})
t.AssertNil(err)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if v == "" {
continue
}
if _, err = dbSqlite3.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
var (
group = "test"
in = gendao.CGenDaoInput{
Path: path,
Link: linkSqlite3,
Group: group,
Tables: table,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
// for go mod import path auto retrieve.
err = gfile.Copy(
gtest.DataPath("gendao", "go.mod.txt"),
gfile.Join(path, "go.mod"),
)
t.AssertNil(err)
_, err = gendao.CGenDao{}.Dao(ctx, in)
t.AssertNil(err)
defer gfile.Remove(path)
// files
files, err := gfile.ScanDir(path, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
filepath.FromSlash(path + "/dao/internal/table_user.go"),
filepath.FromSlash(path + "/dao/table_user.go"),
filepath.FromSlash(path + "/model/do/table_user.go"),
filepath.FromSlash(path + "/model/entity/table_user.go"),
})
// content
testPath := gtest.DataPath("gendao", "generated_user_sqlite3")
expectFiles := []string{
filepath.FromSlash(testPath + "/dao/internal/table_user.go"),
filepath.FromSlash(testPath + "/dao/table_user.go"),
filepath.FromSlash(testPath + "/model/do/table_user.go"),
filepath.FromSlash(testPath + "/model/entity/table_user.go"),
}
for i := range files {
//_ = gfile.PutContents(expectFiles[i], gfile.GetContents(files[i]))
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}

View File

@ -0,0 +1,90 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"path/filepath"
"testing"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpb"
)
func TestGenPbIssue3882(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
outputPath = gfile.Temp(guid.S())
outputApiPath = filepath.Join(outputPath, "api")
outputCtrlPath = filepath.Join(outputPath, "controller")
protobufFolder = gtest.DataPath("issue", "3882")
in = genpb.CGenPbInput{
Path: protobufFolder,
OutputApi: outputApiPath,
OutputCtrl: outputCtrlPath,
}
err error
)
err = gfile.Mkdir(outputApiPath)
t.AssertNil(err)
err = gfile.Mkdir(outputCtrlPath)
t.AssertNil(err)
defer gfile.Remove(outputPath)
_, err = genpb.CGenPb{}.Pb(ctx, in)
t.AssertNil(err)
var (
genContent = gfile.GetContents(filepath.Join(outputApiPath, "issue3882.pb.go"))
exceptText = `dc:"Some comment on field with 'one' 'two' 'three' in the comment."`
)
t.Assert(gstr.Contains(genContent, exceptText), true)
})
}
// This issue only occurs when executing multiple times
// and the subsequent OutputApi is the parent directory of the previous execution
func TestGenPbIssue3953(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
outputPath = gfile.Temp("f" + guid.S())
outputApiPath = filepath.Join(outputPath, "api")
outputCtrlPath = filepath.Join(outputPath, "controller")
protobufFolder = gtest.DataPath("issue", "3953")
in = genpb.CGenPbInput{
Path: protobufFolder,
OutputApi: outputApiPath,
OutputCtrl: outputCtrlPath,
}
err error
)
err = gfile.Mkdir(outputApiPath)
t.AssertNil(err)
err = gfile.Mkdir(outputCtrlPath)
t.AssertNil(err)
defer gfile.Remove(outputPath)
_, err = genpb.CGenPb{}.Pb(ctx, in)
// do twice,and set outputApi to outputPath
in.OutputApi = outputPath
_, err = genpb.CGenPb{}.Pb(ctx, in)
t.AssertNil(err)
var (
genContent = gfile.GetContents(filepath.Join(outputApiPath, "issue3953.pb.go"))
// The old version would have appeared `v:"required" v:"required"`
// but the new version of the code will appear `v:"required"` only once
notExceptText = `v:"required" v:"required"`
)
t.Assert(gstr.Contains(genContent, notExceptText), false)
})
}

View File

@ -0,0 +1,511 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"fmt"
"path/filepath"
"testing"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genpbentity"
)
func Test_Gen_Pbentity_Default(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "unittest",
Link: link,
Tables: "",
Prefix: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "",
JsonCase: "",
Option: "",
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
// files
files, err := gfile.ScanDir(path, "*.proto", false)
t.AssertNil(err)
t.Assert(files, []string{
path + filepath.FromSlash("/table_user.proto"),
})
// contents
testPath := gtest.DataPath("genpbentity", "generated")
expectFiles := []string{
testPath + filepath.FromSlash("/table_user.proto"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func Test_Gen_Pbentity_NameCase_SnakeScreaming(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "unittest",
Link: link,
Tables: "",
Prefix: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "SnakeScreaming",
JsonCase: "",
Option: "",
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
// files
files, err := gfile.ScanDir(path, "*.proto", false)
t.AssertNil(err)
t.Assert(files, []string{
path + filepath.FromSlash("/table_user.proto"),
})
// contents
testPath := gtest.DataPath("genpbentity", "generated")
expectFiles := []string{
testPath + filepath.FromSlash("/table_user_snake_screaming.proto"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
// https://github.com/gogf/gf/issues/3545
func Test_Issue_3545(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "",
Link: link,
Tables: "",
Prefix: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "",
JsonCase: "",
Option: "",
TypeMapping: nil,
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
// files
files, err := gfile.ScanDir(path, "*.proto", false)
t.AssertNil(err)
t.Assert(files, []string{
path + filepath.FromSlash("/table_user.proto"),
})
// contents
testPath := gtest.DataPath("issue", "3545")
expectFiles := []string{
testPath + filepath.FromSlash("/table_user.proto"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
// https://github.com/gogf/gf/issues/3685
func Test_Issue_3685(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`issue`, `3685`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "",
Link: link,
Tables: "",
Prefix: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "",
JsonCase: "",
Option: "",
TypeMapping: map[genpbentity.DBFieldTypeName]genpbentity.CustomAttributeType{
"json": {
Type: "google.protobuf.Value",
Import: "google/protobuf/struct.proto",
},
},
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
// files
files, err := gfile.ScanDir(path, "*.proto", false)
t.AssertNil(err)
t.Assert(files, []string{
path + filepath.FromSlash("/table_user.proto"),
})
// contents
testPath := gtest.DataPath("issue", "3685")
expectFiles := []string{
testPath + filepath.FromSlash("/table_user.proto"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
// https://github.com/gogf/gf/issues/3955
func Test_Issue_3955(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table1 = "table_user_a"
table2 = "table_user_b"
sqlContent = fmt.Sprintf(
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
table1,
)
sqlContent2 = fmt.Sprintf(
gtest.DataContent(`genpbentity`, `user.tpl.sql`),
table2,
)
)
dropTableWithDb(db, table1)
dropTableWithDb(db, table2)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
array = gstr.SplitAndTrim(sqlContent2, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table1)
defer dropTableWithDb(db, table2)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "unittest",
Link: link,
Tables: "",
Prefix: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "",
JsonCase: "",
Option: "",
TablesEx: "table_user_a",
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
files, err := gfile.ScanDir(path, "*.proto", false)
t.AssertNil(err)
t.AssertEQ(len(files), 1)
t.Assert(files, []string{
path + filepath.FromSlash("/table_user_b.proto"),
})
expectFiles := []string{
path + filepath.FromSlash("/table_user_b.proto"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func Test_Issue_4330_TypeMapping_Ineffective(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
table = "table_user"
sqlContent = fmt.Sprintf(
gtest.DataContent(`issue`, `3685`, `user.tpl.sql`),
table,
)
)
dropTableWithDb(db, table)
array := gstr.SplitAndTrim(sqlContent, ";")
for _, v := range array {
if _, err = db.Exec(ctx, v); err != nil {
t.AssertNil(err)
}
}
defer dropTableWithDb(db, table)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "",
Link: link,
Tables: "",
Prefix: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "",
JsonCase: "",
Option: "",
TypeMapping: map[genpbentity.DBFieldTypeName]genpbentity.CustomAttributeType{
"json": {
Type: "google.protobuf.Value",
Import: "google/protobuf/struct.proto",
},
"decimal": {
Type: "double",
},
},
FieldMapping: nil,
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
// files
files, err := gfile.ScanDir(path, "*.proto", false)
t.AssertNil(err)
t.Assert(files, []string{
path + filepath.FromSlash("/table_user.proto"),
})
// contents
testPath := gtest.DataPath("issue", "4330")
expectFiles := []string{
testPath + filepath.FromSlash("/issue4330_double.proto"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
func Test_Gen_Pbentity_Sharding(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
err error
db = testDB
tableSingle = "single_table"
table1 = "users_0001"
table2 = "users_0002"
table3 = "orders_0001"
table4 = "orders_0002"
sqlFilePath = gtest.DataPath(`gendao`, `sharding`, `sharding.sql`)
)
dropTableWithDb(db, tableSingle)
dropTableWithDb(db, table1)
dropTableWithDb(db, table2)
dropTableWithDb(db, table3)
dropTableWithDb(db, table4)
t.AssertNil(execSqlFile(db, sqlFilePath))
defer dropTableWithDb(db, tableSingle)
defer dropTableWithDb(db, table1)
defer dropTableWithDb(db, table2)
defer dropTableWithDb(db, table3)
defer dropTableWithDb(db, table4)
var (
path = gfile.Temp(guid.S())
in = genpbentity.CGenPbEntityInput{
Path: path,
Package: "unittest",
Link: link,
Tables: "",
RemovePrefix: "",
RemoveFieldPrefix: "",
NameCase: "",
JsonCase: "",
Option: "",
TypeMapping: nil,
FieldMapping: nil,
ShardingPattern: []string{
`users_?`,
`orders_?`,
},
}
)
err = gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genpbentity.CGenPbEntity{}.PbEntity(ctx, in)
t.AssertNil(err)
// files
t.AssertNil(err)
generatedFiles, err := gfile.ScanDir(path, "*.proto", true)
t.Assert(len(generatedFiles), 3)
var (
msgSingleTableContent = gfile.GetContents(gfile.Join(path, "single_table.proto"))
msgUsersContent = gfile.GetContents(gfile.Join(path, "users.proto"))
msgOrdersContent = gfile.GetContents(gfile.Join(path, "orders.proto"))
)
t.Assert(gstr.Contains(msgSingleTableContent, "message SingleTable {"), true)
t.Assert(gstr.Contains(msgUsersContent, "message Users {"), true)
t.Assert(gstr.Contains(msgOrdersContent, "message Orders {"), true)
})
}

View File

@ -0,0 +1,158 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package cmd
import (
"path/filepath"
"testing"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/test/gtest"
"github.com/gogf/gf/v2/util/guid"
"github.com/gogf/gf/v2/util/gutil"
"github.com/gogf/gf/cmd/gf/v2/internal/cmd/genservice"
)
func Test_Gen_Service_Default(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
path = gfile.Temp(guid.S())
dstFolder = path + filepath.FromSlash("/service")
srvFolder = gtest.DataPath("genservice", "logic")
in = genservice.CGenServiceInput{
SrcFolder: srvFolder,
DstFolder: dstFolder,
DstFileNameCase: "Snake",
WatchFile: "",
StPattern: "",
Packages: nil,
ImportPrefix: "",
Clear: false,
}
)
err := gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genservice.CGenService{}.Service(ctx, in)
t.AssertNil(err)
// logic file
var (
genSrv = srvFolder + filepath.FromSlash("/logic.go")
genSrvExpect = srvFolder + filepath.FromSlash("/logic_expect.go")
)
defer gfile.Remove(genSrv)
t.Assert(gfile.GetContents(genSrv), gfile.GetContents(genSrvExpect))
// files
files, err := gfile.ScanDir(dstFolder, "*.go", true)
t.AssertNil(err)
t.Assert(files, []string{
dstFolder + filepath.FromSlash("/article.go"),
dstFolder + filepath.FromSlash("/base.go"),
dstFolder + filepath.FromSlash("/delivery.go"),
dstFolder + filepath.FromSlash("/user.go"),
})
// contents
testPath := gtest.DataPath("genservice", "service")
expectFiles := []string{
testPath + filepath.FromSlash("/article.go"),
testPath + filepath.FromSlash("/base.go"),
testPath + filepath.FromSlash("/delivery.go"),
testPath + filepath.FromSlash("/user.go"),
}
for i := range files {
t.Assert(gfile.GetContents(files[i]), gfile.GetContents(expectFiles[i]))
}
})
}
// https://github.com/gogf/gf/issues/3328
func Test_Issue3328(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
path = gfile.Temp(guid.S())
dstFolder = path + filepath.FromSlash("/service")
srvFolder = gtest.DataPath("issue", "3328", "logic")
logicGoPath = srvFolder + filepath.FromSlash("/logic.go")
in = genservice.CGenServiceInput{
SrcFolder: srvFolder,
DstFolder: dstFolder,
DstFileNameCase: "Snake",
WatchFile: "",
StPattern: "",
Packages: nil,
ImportPrefix: "",
Clear: false,
}
)
gfile.Remove(logicGoPath)
defer gfile.Remove(logicGoPath)
err := gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genservice.CGenService{}.Service(ctx, in)
t.AssertNil(err)
files, err := gfile.ScanDir(srvFolder, "*", true)
for _, file := range files {
if file == logicGoPath {
if gfile.IsDir(logicGoPath) {
t.Fatalf("%s should not is folder", logicGoPath)
}
}
}
})
}
// https://github.com/gogf/gf/issues/3835
func Test_Issue3835(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var (
path = gfile.Temp(guid.S())
dstFolder = path + filepath.FromSlash("/service")
srvFolder = gtest.DataPath("issue", "3835", "logic")
in = genservice.CGenServiceInput{
SrcFolder: srvFolder,
DstFolder: dstFolder,
DstFileNameCase: "Snake",
WatchFile: "",
StPattern: "",
Packages: nil,
ImportPrefix: "",
Clear: false,
}
)
err := gutil.FillStructWithDefault(&in)
t.AssertNil(err)
err = gfile.Mkdir(path)
t.AssertNil(err)
defer gfile.Remove(path)
_, err = genservice.CGenService{}.Service(ctx, in)
t.AssertNil(err)
// contents
var (
genFile = dstFolder + filepath.FromSlash("/issue_3835.go")
expectFile = gtest.DataPath("issue", "3835", "service", "issue_3835.go")
)
t.Assert(gfile.GetContents(genFile), gfile.GetContents(expectFile))
})
}

View File

@ -0,0 +1,238 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"context"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
const (
CGenCtrlConfig = `gfcli.gen.ctrl`
CGenCtrlUsage = `gf gen ctrl [OPTION]`
CGenCtrlBrief = `parse api definitions to generate controller/sdk go files`
CGenCtrlEg = `
gf gen ctrl
`
CGenCtrlBriefSrcFolder = `source folder path to be parsed. default: api`
CGenCtrlBriefDstFolder = `destination folder path storing automatically generated go files. default: internal/controller`
CGenCtrlBriefWatchFile = `used in file watcher, it re-generates go files only if given file is under srcFolder`
CGenCtrlBriefSdkPath = `also generate SDK go files for api definitions to specified directory`
CGenCtrlBriefSdkStdVersion = `use standard version prefix for generated sdk request path`
CGenCtrlBriefSdkNoV1 = `do not add version suffix for interface module name if version is v1`
CGenCtrlBriefClear = `auto delete generated and unimplemented controller go files if api definitions are missing`
CGenCtrlControllerMerge = `generate all controller files into one go file by name of api definition source go file`
)
const (
PatternCtrlDefinition = `func\s+\(.+?\)\s+\w+\(.+?\*(\w+)\.(\w+)Req\)\s+\(.+?\*(\w+)\.(\w+)Res,\s+\w+\s+error\)\s+{`
)
const (
genCtrlFileLockSeconds = 10
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenCtrlConfig`: CGenCtrlConfig,
`CGenCtrlUsage`: CGenCtrlUsage,
`CGenCtrlBrief`: CGenCtrlBrief,
`CGenCtrlEg`: CGenCtrlEg,
`CGenCtrlBriefSrcFolder`: CGenCtrlBriefSrcFolder,
`CGenCtrlBriefDstFolder`: CGenCtrlBriefDstFolder,
`CGenCtrlBriefWatchFile`: CGenCtrlBriefWatchFile,
`CGenCtrlBriefSdkPath`: CGenCtrlBriefSdkPath,
`CGenCtrlBriefSdkStdVersion`: CGenCtrlBriefSdkStdVersion,
`CGenCtrlBriefSdkNoV1`: CGenCtrlBriefSdkNoV1,
`CGenCtrlBriefClear`: CGenCtrlBriefClear,
`CGenCtrlControllerMerge`: CGenCtrlControllerMerge,
})
}
type (
CGenCtrl struct{}
CGenCtrlInput struct {
g.Meta `name:"ctrl" config:"{CGenCtrlConfig}" usage:"{CGenCtrlUsage}" brief:"{CGenCtrlBrief}" eg:"{CGenCtrlEg}"`
SrcFolder string `short:"s" name:"srcFolder" brief:"{CGenCtrlBriefSrcFolder}" d:"api"`
DstFolder string `short:"d" name:"dstFolder" brief:"{CGenCtrlBriefDstFolder}" d:"internal/controller"`
WatchFile string `short:"w" name:"watchFile" brief:"{CGenCtrlBriefWatchFile}"`
SdkPath string `short:"k" name:"sdkPath" brief:"{CGenCtrlBriefSdkPath}"`
SdkStdVersion bool `short:"v" name:"sdkStdVersion" brief:"{CGenCtrlBriefSdkStdVersion}" orphan:"true"`
SdkNoV1 bool `short:"n" name:"sdkNoV1" brief:"{CGenCtrlBriefSdkNoV1}" orphan:"true"`
Clear bool `short:"c" name:"clear" brief:"{CGenCtrlBriefClear}" orphan:"true"`
Merge bool `short:"m" name:"merge" brief:"{CGenCtrlControllerMerge}" orphan:"true"`
}
CGenCtrlOutput struct{}
)
func (c CGenCtrl) Ctrl(ctx context.Context, in CGenCtrlInput) (out *CGenCtrlOutput, err error) {
if in.WatchFile != "" {
err = c.generateByWatchFile(
in.WatchFile, in.SdkPath, in.SdkStdVersion, in.SdkNoV1, in.Clear, in.Merge,
)
mlog.Print(`done!`)
return
}
if !gfile.Exists(in.SrcFolder) {
mlog.Fatalf(`source folder path "%s" does not exist`, in.SrcFolder)
}
// retrieve all api modules.
apiModuleFolderPaths, err := gfile.ScanDir(in.SrcFolder, "*", false)
if err != nil {
return nil, err
}
for _, apiModuleFolderPath := range apiModuleFolderPaths {
if !gfile.IsDir(apiModuleFolderPath) {
continue
}
// generate go files by api module.
var (
module = gfile.Basename(apiModuleFolderPath)
dstModuleFolderPath = gfile.Join(in.DstFolder, module)
)
err = c.generateByModule(
apiModuleFolderPath, dstModuleFolderPath, in.SdkPath,
in.SdkStdVersion, in.SdkNoV1, in.Clear, in.Merge,
)
if err != nil {
return nil, err
}
}
mlog.Print(`done!`)
return
}
func (c CGenCtrl) generateByWatchFile(watchFile, sdkPath string, sdkStdVersion, sdkNoV1, clear, merge bool) (err error) {
// File lock to avoid multiple processes.
var (
flockFilePath = gfile.Temp("gf.cli.gen.service.lock")
flockContent = gfile.GetContents(flockFilePath)
)
if flockContent != "" {
if gtime.Timestamp()-gconv.Int64(flockContent) < genCtrlFileLockSeconds {
// If another generating process is running, it just exits.
mlog.Debug(`another "gen service" process is running, exit`)
return
}
}
defer gfile.RemoveFile(flockFilePath)
_ = gfile.PutContents(flockFilePath, gtime.TimestampStr())
// check this updated file is an api file.
// watch file should be in standard goframe project structure.
var (
apiVersionPath = gfile.Dir(watchFile)
apiModuleFolderPath = gfile.Dir(apiVersionPath)
shouldBeNameOfAPi = gfile.Basename(gfile.Dir(apiModuleFolderPath))
)
if shouldBeNameOfAPi != "api" {
return nil
}
// watch file should have api definitions.
if gfile.Exists(watchFile) {
structsInfo, err := c.getStructsNameInSrc(watchFile)
if err != nil {
return err
}
if len(structsInfo) == 0 {
return nil
}
}
var (
projectRootPath = gfile.Dir(gfile.Dir(apiModuleFolderPath))
module = gfile.Basename(apiModuleFolderPath)
dstModuleFolderPath = gfile.Join(projectRootPath, "internal", "controller", module)
)
return c.generateByModule(
apiModuleFolderPath, dstModuleFolderPath, sdkPath, sdkStdVersion, sdkNoV1, clear, merge,
)
}
// parseApiModule parses certain api and generate associated go files by certain module, not all api modules.
func (c CGenCtrl) generateByModule(
apiModuleFolderPath, dstModuleFolderPath, sdkPath string,
sdkStdVersion, sdkNoV1, clear, merge bool,
) (err error) {
// parse src and dst folder go files.
apiItemsInSrc, err := c.getApiItemsInSrc(apiModuleFolderPath)
if err != nil {
return err
}
apiItemsInDst, err := c.getApiItemsInDst(dstModuleFolderPath)
if err != nil {
return err
}
// generate api interface go files.
if err = newApiInterfaceGenerator().Generate(apiModuleFolderPath, apiItemsInSrc); err != nil {
return
}
// generate controller go files.
// api filtering for already implemented api controllers.
var (
alreadyImplementedCtrlSet = gset.NewStrSet()
toBeImplementedApiItems = make([]apiItem, 0)
)
for _, item := range apiItemsInDst {
alreadyImplementedCtrlSet.Add(item.String())
}
for _, item := range apiItemsInSrc {
if alreadyImplementedCtrlSet.Contains(item.String()) {
continue
}
toBeImplementedApiItems = append(toBeImplementedApiItems, item)
}
if len(toBeImplementedApiItems) > 0 {
err = newControllerGenerator().Generate(dstModuleFolderPath, toBeImplementedApiItems, merge)
if err != nil {
return
}
}
// delete unimplemented controllers if api definitions are missing.
if clear {
var (
apiDefinitionSet = gset.NewStrSet()
extraApiItemsInCtrl = make([]apiItem, 0)
)
for _, item := range apiItemsInSrc {
apiDefinitionSet.Add(item.String())
}
for _, item := range apiItemsInDst {
if apiDefinitionSet.Contains(item.String()) {
continue
}
extraApiItemsInCtrl = append(extraApiItemsInCtrl, item)
}
if len(extraApiItemsInCtrl) > 0 {
err = newControllerClearer().Clear(dstModuleFolderPath, extraApiItemsInCtrl)
if err != nil {
return
}
}
}
// generate sdk go files.
if sdkPath != "" {
if err = newApiSdkGenerator().Generate(apiItemsInSrc, sdkPath, sdkStdVersion, sdkNoV1); err != nil {
return
}
}
return
}

View File

@ -0,0 +1,37 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"fmt"
"github.com/gogf/gf/v2/text/gstr"
)
type apiItem struct {
Import string `eg:"demo.com/api/user/v1"`
FileName string `eg:"user"`
Module string `eg:"user"`
Version string `eg:"v1"`
MethodName string `eg:"GetList"`
Comment string `eg:"GetList get list"`
}
func (a apiItem) String() string {
return gstr.Join([]string{
a.Import, a.Module, a.Version, a.MethodName,
}, ",")
}
// GetComment returns the comment of apiItem.
func (a apiItem) GetComment() string {
if a.Comment == "" {
return ""
}
// format for handling comments
return fmt.Sprintf("\n// %s %s", a.MethodName, a.Comment)
}

View File

@ -0,0 +1,95 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"bytes"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
)
type structInfo struct {
structName string
comment string
}
// getStructsNameInSrc retrieves all struct names and comment
// that end in "Req" and have "g.Meta" in their body.
func (c CGenCtrl) getStructsNameInSrc(filePath string) (structInfos []*structInfo, err error) {
var (
fileContent = gfile.GetContents(filePath)
fileSet = token.NewFileSet()
)
node, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments)
if err != nil {
return
}
ast.Inspect(node, func(n ast.Node) bool {
if typeSpec, ok := n.(*ast.TypeSpec); ok {
structName := typeSpec.Name.Name
if !gstr.HasSuffix(structName, "Req") {
// ignore struct name that do not end in "Req"
return true
}
if structType, ok := typeSpec.Type.(*ast.StructType); ok {
var buf bytes.Buffer
if err := printer.Fprint(&buf, fileSet, structType); err != nil {
return false
}
// ignore struct name that match a request, but has no g.Meta in its body.
if !gstr.Contains(buf.String(), `g.Meta`) {
return true
}
comment := typeSpec.Doc.Text()
// remove the struct name from the comment
if gstr.HasPrefix(comment, structName) {
comment = gstr.TrimLeftStr(comment, structName, 1)
}
// remove the comment \n or space
comment = gstr.Trim(comment)
structInfos = append(structInfos, &structInfo{
structName: structName,
comment: comment,
})
}
}
return true
})
return
}
// getImportsInDst retrieves all import paths in the file.
func (c CGenCtrl) getImportsInDst(filePath string) (imports []string, err error) {
var (
fileContent = gfile.GetContents(filePath)
fileSet = token.NewFileSet()
)
node, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments)
if err != nil {
return
}
ast.Inspect(node, func(n ast.Node) bool {
if imp, ok := n.(*ast.ImportSpec); ok {
imports = append(imports, imp.Path.Value)
}
return true
})
return
}

View File

@ -0,0 +1,43 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"bytes"
"go/ast"
"go/parser"
"go/printer"
"go/token"
"github.com/gogf/gf/v2/os/gfile"
)
// getFuncInDst retrieves all function declarations and bodies in the file.
func (c *controllerClearer) getFuncInDst(filePath string) (funcs []string, err error) {
var (
fileContent = gfile.GetContents(filePath)
fileSet = token.NewFileSet()
)
node, err := parser.ParseFile(fileSet, "", fileContent, parser.ParseComments)
if err != nil {
return
}
ast.Inspect(node, func(n ast.Node) bool {
if fun, ok := n.(*ast.FuncDecl); ok {
var buf bytes.Buffer
if err := printer.Fprint(&buf, fileSet, fun); err != nil {
return false
}
funcs = append(funcs, buf.String())
}
return true
})
return
}

View File

@ -0,0 +1,137 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
func (c CGenCtrl) getApiItemsInSrc(apiModuleFolderPath string) (items []apiItem, err error) {
var importPath string
// The second level folders: versions.
apiVersionFolderPaths, err := gfile.ScanDir(apiModuleFolderPath, "*", false)
if err != nil {
return nil, err
}
for _, apiVersionFolderPath := range apiVersionFolderPaths {
if !gfile.IsDir(apiVersionFolderPath) {
continue
}
// The second level folders: versions.
apiFileFolderPaths, err := gfile.ScanDir(apiVersionFolderPath, "*.go", false)
if err != nil {
return nil, err
}
importPath = utils.GetImportPath(apiVersionFolderPath)
for _, apiFileFolderPath := range apiFileFolderPaths {
if gfile.IsDir(apiFileFolderPath) {
continue
}
structsInfo, err := c.getStructsNameInSrc(apiFileFolderPath)
if err != nil {
return nil, err
}
for _, s := range structsInfo {
// remove end "Req"
methodName := gstr.TrimRightStr(s.structName, "Req", 1)
item := apiItem{
Import: gstr.Trim(importPath, `"`),
FileName: gfile.Name(apiFileFolderPath),
Module: gfile.Basename(apiModuleFolderPath),
Version: gfile.Basename(apiVersionFolderPath),
MethodName: methodName,
Comment: s.comment,
}
items = append(items, item)
}
}
}
return
}
func (c CGenCtrl) getApiItemsInDst(dstFolder string) (items []apiItem, err error) {
if !gfile.Exists(dstFolder) {
return nil, nil
}
type importItem struct {
Path string
Alias string
}
filePaths, err := gfile.ScanDir(dstFolder, "*.go", true)
if err != nil {
return nil, err
}
for _, filePath := range filePaths {
var (
array []string
importItems []importItem
importLines []string
module = gfile.Basename(gfile.Dir(filePath))
)
importLines, err = c.getImportsInDst(filePath)
if err != nil {
return nil, err
}
// retrieve all imports.
for _, importLine := range importLines {
array = gstr.SplitAndTrim(importLine, " ")
if len(array) == 2 {
importItems = append(importItems, importItem{
Path: gstr.Trim(array[1], `"`),
Alias: array[0],
})
} else {
importItems = append(importItems, importItem{
Path: gstr.Trim(array[0], `"`),
})
}
}
// retrieve all api usages.
// retrieve it without using AST, but use regular expressions to retrieve.
// It's because the api definition is simple and regular.
// Use regular expressions to get better performance.
fileContent := gfile.GetContents(filePath)
matches, err := gregex.MatchAllString(PatternCtrlDefinition, fileContent)
if err != nil {
return nil, err
}
for _, match := range matches {
// try to find the import path of the api.
var (
importPath string
version = match[1]
methodName = match[2] // not the function name, but the method name in api definition.
)
for _, item := range importItems {
if item.Alias != "" {
if item.Alias == version {
importPath = item.Path
break
}
continue
}
if gfile.Basename(item.Path) == version {
importPath = item.Path
break
}
}
item := apiItem{
Import: gstr.Trim(importPath, `"`),
Module: module,
Version: gfile.Basename(importPath),
MethodName: methodName,
}
items = append(items, item)
}
}
return
}

View File

@ -0,0 +1,231 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"fmt"
"path/filepath"
"strings"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
type controllerGenerator struct{}
func newControllerGenerator() *controllerGenerator {
return &controllerGenerator{}
}
func (c *controllerGenerator) Generate(dstModuleFolderPath string, apiModuleApiItems []apiItem, merge bool) (err error) {
var (
doneApiItemSet = gset.NewStrSet()
)
for _, item := range apiModuleApiItems {
if doneApiItemSet.Contains(item.String()) {
continue
}
// retrieve all api items of the same module.
var (
subItems = c.getSubItemsByModuleAndVersion(apiModuleApiItems, item.Module, item.Version)
importPath = gstr.Replace(gfile.Dir(item.Import), "\\", "/", -1)
)
if err = c.doGenerateCtrlNewByModuleAndVersion(
dstModuleFolderPath, item.Module, item.Version, importPath,
); err != nil {
return
}
// use -merge
if merge {
err = c.doGenerateCtrlMergeItem(dstModuleFolderPath, subItems, doneApiItemSet)
continue
}
for _, subItem := range subItems {
err = c.doGenerateCtrlItem(dstModuleFolderPath, subItem)
if err != nil {
return
}
doneApiItemSet.Add(subItem.String())
}
}
return
}
func (c *controllerGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) {
for _, item := range items {
if item.Module == module && item.Version == version {
subItems = append(subItems, item)
}
}
return
}
func (c *controllerGenerator) doGenerateCtrlNewByModuleAndVersion(
dstModuleFolderPath, module, version, importPath string,
) (err error) {
var (
moduleFilePath = filepath.FromSlash(gfile.Join(dstModuleFolderPath, module+".go"))
moduleFilePathNew = filepath.FromSlash(gfile.Join(dstModuleFolderPath, module+"_new.go"))
ctrlName = fmt.Sprintf(`Controller%s`, gstr.UcFirst(version))
interfaceName = fmt.Sprintf(`%s.I%s%s`, module, gstr.CaseCamel(module), gstr.UcFirst(version))
newFuncName = fmt.Sprintf(`New%s`, gstr.UcFirst(version))
newFuncNameDefinition = fmt.Sprintf(`func %s()`, newFuncName)
alreadyCreated bool
)
if !gfile.Exists(moduleFilePath) {
content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerEmpty, g.MapStrStr{
"{Module}": module,
})
if err = gfile.PutContents(moduleFilePath, gstr.TrimLeft(content)); err != nil {
return err
}
mlog.Printf(`generated: %s`, gfile.RealPath(moduleFilePath))
}
if !gfile.Exists(moduleFilePathNew) {
content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerNewEmpty, g.MapStrStr{
"{Module}": module,
"{ImportPath}": fmt.Sprintf(`"%s"`, importPath),
})
if err = gfile.PutContents(moduleFilePathNew, gstr.TrimLeft(content)); err != nil {
return err
}
mlog.Printf(`generated: %s`, gfile.RealPath(moduleFilePathNew))
}
filePaths, err := gfile.ScanDir(dstModuleFolderPath, "*.go", false)
if err != nil {
return err
}
for _, filePath := range filePaths {
if gstr.Contains(gfile.GetContents(filePath), newFuncNameDefinition) {
alreadyCreated = true
break
}
}
if !alreadyCreated {
content := gstr.ReplaceByMap(consts.TemplateGenCtrlControllerNewFunc, g.MapStrStr{
"{CtrlName}": ctrlName,
"{NewFuncName}": newFuncName,
"{InterfaceName}": interfaceName,
})
err = gfile.PutContentsAppend(moduleFilePathNew, content)
if err != nil {
return err
}
}
return
}
func (c *controllerGenerator) doGenerateCtrlItem(dstModuleFolderPath string, item apiItem) (err error) {
var (
methodNameSnake = gstr.CaseSnake(item.MethodName)
ctrlName = fmt.Sprintf(`Controller%s`, gstr.UcFirst(item.Version))
methodFilePath = filepath.FromSlash(gfile.Join(dstModuleFolderPath, fmt.Sprintf(
`%s_%s_%s.go`, item.Module, item.Version, methodNameSnake,
)))
)
var content string
if gfile.Exists(methodFilePath) {
content = gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{
"{Module}": item.Module,
"{CtrlName}": ctrlName,
"{Version}": item.Version,
"{MethodName}": item.MethodName,
"{MethodComment}": item.GetComment(),
})
if gstr.Contains(gfile.GetContents(methodFilePath), fmt.Sprintf(`func (c *%v) %v(`, ctrlName, item.MethodName)) {
return
}
if err = gfile.PutContentsAppend(methodFilePath, gstr.TrimLeft(content)); err != nil {
return err
}
} else {
content = gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFunc, g.MapStrStr{
"{Module}": item.Module,
"{ImportPath}": item.Import,
"{CtrlName}": ctrlName,
"{Version}": item.Version,
"{MethodName}": item.MethodName,
"{MethodComment}": item.GetComment(),
})
if err = gfile.PutContents(methodFilePath, gstr.TrimLeft(content)); err != nil {
return err
}
}
mlog.Printf(`generated: %s`, gfile.RealPath(methodFilePath))
return
}
// use -merge
func (c *controllerGenerator) doGenerateCtrlMergeItem(dstModuleFolderPath string, apiItems []apiItem, doneApiSet *gset.StrSet) (err error) {
type controllerFileItem struct {
module string
version string
importPath string
// Each ctrlFileItem has multiple CTRLs
controllers strings.Builder
}
// It is possible that there are multiple files under one module
ctrlFileItemMap := make(map[string]*controllerFileItem)
for _, api := range apiItems {
ctrlFileItem, found := ctrlFileItemMap[api.FileName]
if !found {
ctrlFileItem = &controllerFileItem{
module: api.Module,
version: api.Version,
controllers: strings.Builder{},
importPath: api.Import,
}
ctrlFileItemMap[api.FileName] = ctrlFileItem
}
ctrl := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlControllerMethodFuncMerge, g.MapStrStr{
"{Module}": api.Module,
"{CtrlName}": fmt.Sprintf(`Controller%s`, gstr.UcFirst(api.Version)),
"{Version}": api.Version,
"{MethodName}": api.MethodName,
"{MethodComment}": api.GetComment(),
}))
ctrlFileItem.controllers.WriteString(ctrl)
doneApiSet.Add(api.String())
}
for ctrlFileName, ctrlFileItem := range ctrlFileItemMap {
ctrlFilePath := gfile.Join(dstModuleFolderPath, fmt.Sprintf(
`%s_%s_%s.go`, ctrlFileItem.module, ctrlFileItem.version, ctrlFileName,
))
// This logic is only followed when a new ctrlFileItem is generated
// Most of the rest of the time, the following logic is followed
if !gfile.Exists(ctrlFilePath) {
ctrlFileHeader := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlControllerHeader, g.MapStrStr{
"{Module}": ctrlFileItem.module,
"{ImportPath}": ctrlFileItem.importPath,
}))
err = gfile.PutContents(ctrlFilePath, ctrlFileHeader)
if err != nil {
return err
}
}
if err = gfile.PutContentsAppend(ctrlFilePath, ctrlFileItem.controllers.String()); err != nil {
return err
}
mlog.Printf(`generated: %s`, gfile.RealPath(ctrlFilePath))
}
return
}

View File

@ -0,0 +1,57 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"fmt"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
type controllerClearer struct{}
func newControllerClearer() *controllerClearer {
return &controllerClearer{}
}
func (c *controllerClearer) Clear(dstModuleFolderPath string, extraApiItemsInCtrl []apiItem) (err error) {
for _, item := range extraApiItemsInCtrl {
if err = c.doClear(dstModuleFolderPath, item); err != nil {
return err
}
}
return
}
func (c *controllerClearer) doClear(dstModuleFolderPath string, item apiItem) (err error) {
var (
methodNameSnake = gstr.CaseSnake(item.MethodName)
methodFilePath = gfile.Join(dstModuleFolderPath, fmt.Sprintf(
`%s_%s_%s.go`, item.Module, item.Version, methodNameSnake,
))
)
funcs, err := c.getFuncInDst(methodFilePath)
if err != nil {
return err
}
if len(funcs) > 1 {
// One line.
if !gstr.Contains(funcs[0], "\n") && gstr.Contains(funcs[0], `CodeNotImplemented`) {
mlog.Printf(
`remove unimplemented and of no api definitions controller file: %s`,
methodFilePath,
)
err = gfile.RemoveFile(methodFilePath)
}
}
return
}

View File

@ -0,0 +1,118 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"fmt"
"path/filepath"
"github.com/gogf/gf/v2/container/gmap"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gconv"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
type apiInterfaceGenerator struct{}
func newApiInterfaceGenerator() *apiInterfaceGenerator {
return &apiInterfaceGenerator{}
}
func (c *apiInterfaceGenerator) Generate(apiModuleFolderPath string, apiModuleApiItems []apiItem) (err error) {
if len(apiModuleApiItems) == 0 {
return nil
}
var firstApiItem = apiModuleApiItems[0]
if err = c.doGenerate(apiModuleFolderPath, firstApiItem.Module, apiModuleApiItems); err != nil {
return
}
return
}
func (c *apiInterfaceGenerator) doGenerate(apiModuleFolderPath string, module string, items []apiItem) (err error) {
var (
moduleFilePath = filepath.FromSlash(gfile.Join(apiModuleFolderPath, fmt.Sprintf(`%s.go`, module)))
importPathMap = gmap.NewListMap()
importPaths []string
)
// if there's already exist file that with the same but not auto generated go file,
// it uses another file name.
if !utils.IsFileDoNotEdit(moduleFilePath) {
moduleFilePath = filepath.FromSlash(gfile.Join(apiModuleFolderPath, fmt.Sprintf(`%s.if.go`, module)))
}
// all import paths.
importPathMap.Set("\t"+`"context"`+"\n", 1)
for _, item := range items {
importPathMap.Set(fmt.Sprintf("\t"+`"%s"`, item.Import), 1)
}
importPaths = gconv.Strings(importPathMap.Keys())
// interface definitions.
var (
doneApiItemSet = gset.NewStrSet()
interfaceDefinition string
interfaceContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlApiInterface, g.MapStrStr{
"{Module}": module,
"{ImportPaths}": gstr.Join(importPaths, "\n"),
}))
)
for _, item := range items {
if doneApiItemSet.Contains(item.String()) {
continue
}
// retrieve all api items of the same module.
subItems := c.getSubItemsByModuleAndVersion(items, item.Module, item.Version)
var (
method string
methods = make([]string, 0)
interfaceName = fmt.Sprintf(`I%s%s`, gstr.CaseCamel(item.Module), gstr.UcFirst(item.Version))
)
for _, subItem := range subItems {
method = fmt.Sprintf(
"\t%s(ctx context.Context, req *%s.%sReq) (res *%s.%sRes, err error)",
subItem.MethodName, subItem.Version, subItem.MethodName, subItem.Version, subItem.MethodName,
)
methods = append(methods, method)
doneApiItemSet.Add(subItem.String())
}
interfaceDefinition += fmt.Sprintf("type %s interface {", interfaceName)
interfaceDefinition += "\n"
interfaceDefinition += gstr.Join(methods, "\n")
interfaceDefinition += "\n"
interfaceDefinition += fmt.Sprintf("}")
interfaceDefinition += "\n\n"
}
interfaceContent = gstr.TrimLeft(gstr.ReplaceByMap(interfaceContent, g.MapStrStr{
"{Interfaces}": gstr.TrimRightStr(interfaceDefinition, "\n", 2),
}))
err = gfile.PutContents(moduleFilePath, interfaceContent)
mlog.Printf(`generated: %s`, gfile.RealPath(moduleFilePath))
return
}
func (c *apiInterfaceGenerator) getSubItemsByModule(items []apiItem, module string) (subItems []apiItem) {
for _, item := range items {
if item.Module == module {
subItems = append(subItems, item)
}
}
return
}
func (c *apiInterfaceGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) {
for _, item := range items {
if item.Module == module && item.Version == version {
subItems = append(subItems, item)
}
}
return
}

View File

@ -0,0 +1,199 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package genctrl
import (
"fmt"
"path/filepath"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
)
type apiSdkGenerator struct{}
func newApiSdkGenerator() *apiSdkGenerator {
return &apiSdkGenerator{}
}
func (c *apiSdkGenerator) Generate(apiModuleApiItems []apiItem, sdkFolderPath string, sdkStdVersion, sdkNoV1 bool) (err error) {
if err = c.doGenerateSdkPkgFile(sdkFolderPath); err != nil {
return
}
var doneApiItemSet = gset.NewStrSet()
for _, item := range apiModuleApiItems {
if doneApiItemSet.Contains(item.String()) {
continue
}
// retrieve all api items of the same module.
subItems := c.getSubItemsByModuleAndVersion(apiModuleApiItems, item.Module, item.Version)
if err = c.doGenerateSdkIClient(sdkFolderPath, item.Import, item.Module, item.Version, sdkNoV1); err != nil {
return
}
if err = c.doGenerateSdkImplementer(
subItems, sdkFolderPath, item.Import, item.Module, item.Version, sdkStdVersion, sdkNoV1,
); err != nil {
return
}
for _, subItem := range subItems {
doneApiItemSet.Add(subItem.String())
}
}
return
}
func (c *apiSdkGenerator) doGenerateSdkPkgFile(sdkFolderPath string) (err error) {
var (
pkgName = gfile.Basename(sdkFolderPath)
pkgFilePath = filepath.FromSlash(gfile.Join(sdkFolderPath, fmt.Sprintf(`%s.go`, pkgName)))
fileContent string
)
if gfile.Exists(pkgFilePath) {
return nil
}
fileContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkPkgNew, g.MapStrStr{
"{PkgName}": pkgName,
}))
err = gfile.PutContents(pkgFilePath, fileContent)
mlog.Printf(`generated: %s`, gfile.RealPath(pkgFilePath))
return
}
func (c *apiSdkGenerator) doGenerateSdkIClient(
sdkFolderPath, versionImportPath, module, version string, sdkNoV1 bool,
) (err error) {
var (
fileContent string
isDirty bool
isExist bool
pkgName = gfile.Basename(sdkFolderPath)
funcName = gstr.CaseCamel(module) + gstr.UcFirst(version)
interfaceName = fmt.Sprintf(`I%s`, funcName)
moduleImportPath = gstr.Replace(fmt.Sprintf(`"%s"`, gfile.Dir(versionImportPath)), "\\", "/", -1)
iClientFilePath = filepath.FromSlash(gfile.Join(sdkFolderPath, fmt.Sprintf(`%s.iclient.go`, pkgName)))
interfaceFuncDefinition = fmt.Sprintf(
`%s() %s.%s`,
gstr.CaseCamel(module)+gstr.UcFirst(version), module, interfaceName,
)
)
if sdkNoV1 && version == "v1" {
interfaceFuncDefinition = fmt.Sprintf(
`%s() %s.%s`,
gstr.CaseCamel(module), module, interfaceName,
)
}
if isExist = gfile.Exists(iClientFilePath); isExist {
fileContent = gfile.GetContents(iClientFilePath)
} else {
fileContent = gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkIClient, g.MapStrStr{
"{PkgName}": pkgName,
}))
}
// append the import path to current import paths.
if !gstr.Contains(fileContent, moduleImportPath) {
isDirty = true
// It is without using AST, because it is from a template.
fileContent, err = gregex.ReplaceString(
`(import \([\s\S]*?)\)`,
fmt.Sprintf("$1\t%s\n)", moduleImportPath),
fileContent,
)
if err != nil {
return
}
}
// append the function definition to interface definition.
if !gstr.Contains(fileContent, interfaceFuncDefinition) {
isDirty = true
// It is without using AST, because it is from a template.
fileContent, err = gregex.ReplaceString(
`(type IClient interface {[\s\S]*?)}`,
fmt.Sprintf("$1\t%s\n}", interfaceFuncDefinition),
fileContent,
)
if err != nil {
return
}
}
if isDirty {
err = gfile.PutContents(iClientFilePath, fileContent)
if isExist {
mlog.Printf(`updated: %s`, gfile.RealPath(iClientFilePath))
} else {
mlog.Printf(`generated: %s`, gfile.RealPath(iClientFilePath))
}
}
return
}
func (c *apiSdkGenerator) doGenerateSdkImplementer(
items []apiItem, sdkFolderPath, versionImportPath, module, version string, sdkStdVersion, sdkNoV1 bool,
) (err error) {
var (
pkgName = gfile.Basename(sdkFolderPath)
moduleNameCamel = gstr.CaseCamel(module)
moduleNameSnake = gstr.CaseSnake(module)
moduleImportPath = gstr.Replace(gfile.Dir(versionImportPath), "\\", "/", -1)
versionPrefix = ""
implementerName = moduleNameCamel + gstr.UcFirst(version)
implementerFilePath = filepath.FromSlash(gfile.Join(sdkFolderPath, fmt.Sprintf(
`%s_%s_%s.go`, pkgName, moduleNameSnake, version,
)))
)
if sdkNoV1 && version == "v1" {
implementerName = moduleNameCamel
}
// implementer file template.
var importPaths = make([]string, 0)
importPaths = append(importPaths, fmt.Sprintf("\t\"%s\"", moduleImportPath))
importPaths = append(importPaths, fmt.Sprintf("\t\"%s\"", versionImportPath))
implementerFileContent := gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementer, g.MapStrStr{
"{PkgName}": pkgName,
"{ImportPaths}": gstr.Join(importPaths, "\n"),
"{ImplementerName}": implementerName,
}))
// implementer new function definition.
if sdkStdVersion {
versionPrefix = fmt.Sprintf(`/api/%s`, version)
}
implementerFileContent += gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementerNew, g.MapStrStr{
"{Module}": module,
"{VersionPrefix}": versionPrefix,
"{ImplementerName}": implementerName,
}))
// implementer functions definitions.
for _, item := range items {
implementerFileContent += gstr.TrimLeft(gstr.ReplaceByMap(consts.TemplateGenCtrlSdkImplementerFunc, g.MapStrStr{
"{Version}": item.Version,
"{MethodName}": item.MethodName,
"{ImplementerName}": implementerName,
"{MethodComment}": item.GetComment(),
}))
implementerFileContent += "\n"
}
err = gfile.PutContents(implementerFilePath, implementerFileContent)
mlog.Printf(`generated: %s`, gfile.RealPath(implementerFilePath))
return
}
func (c *apiSdkGenerator) getSubItemsByModuleAndVersion(items []apiItem, module, version string) (subItems []apiItem) {
for _, item := range items {
if item.Module == module && item.Version == version {
subItems = append(subItems, item)
}
}
return
}

Binary file not shown.

View File

@ -1,3 +1,9 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gendao
import (
@ -5,181 +11,121 @@ import (
"fmt"
"strings"
"github.com/olekukonko/tablewriter"
"github.com/olekukonko/tablewriter/renderer"
"github.com/olekukonko/tablewriter/tw"
"golang.org/x/mod/modfile"
"github.com/gogf/gf/v2/container/garray"
"github.com/gogf/gf/v2/container/gset"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gproc"
"github.com/gogf/gf/v2/os/gtime"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/v2/util/gtag"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
const (
CGenDaoConfig = `gfcli.gen.dao`
CGenDaoUsage = `gf gen dao [OPTION]`
CGenDaoBrief = `automatically generate go files for dao/do/entity`
CGenDaoEg = `
gf gen dao
gf gen dao -l "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
gf gen dao -p ./model -g user-center -t user,user_detail,user_login
gf gen dao -r user_
`
CGenDaoAd = `
CONFIGURATION SUPPORT
Options are also supported by configuration file.
It's suggested using configuration file instead of command line arguments making producing.
The configuration node name is "gfcli.gen.dao", which also supports multiple databases, for example(config.yaml):
gfcli:
gen:
dao:
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/test"
tables: "order,products"
jsonCase: "CamelLower"
- link: "mysql:root:12345678@tcp(127.0.0.1:3306)/primary"
path: "./my-app"
prefix: "primary_"
tables: "user, userDetail"
`
CGenDaoBriefPath = `directory path for generated files`
CGenDaoBriefLink = `database configuration, the same as the ORM configuration of GoFrame`
CGenDaoBriefTables = `generate models only for given tables, multiple table names separated with ','`
CGenDaoBriefTablesEx = `generate models excluding given tables, multiple table names separated with ','`
CGenDaoBriefPrefix = `add prefix for all table of specified link/database tables`
CGenDaoBriefRemovePrefix = `remove specified prefix of the table, multiple prefix separated with ','`
CGenDaoBriefStdTime = `use time.Time from stdlib instead of gtime.Time for generated time/date fields of tables`
CGenDaoBriefWithTime = `add created time for auto produced go files`
CGenDaoBriefGJsonSupport = `use gJsonSupport to use *gjson.Json instead of string for generated json fields of tables`
CGenDaoBriefImportPrefix = `custom import prefix for generated go files`
CGenDaoBriefDaoPath = `directory path for storing generated dao files under path`
CGenDaoBriefDoPath = `directory path for storing generated do files under path`
CGenDaoBriefEntityPath = `directory path for storing generated entity files under path`
CGenDaoBriefOverwriteDao = `overwrite all dao files both inside/outside internal folder`
CGenDaoBriefModelFile = `custom file name for storing generated model content`
CGenDaoBriefModelFileForDao = `custom file name generating model for DAO operations like Where/Data. It's empty in default`
CGenDaoBriefDescriptionTag = `add comment to description tag for each field`
CGenDaoBriefNoJsonTag = `no json tag will be added for each field`
CGenDaoBriefNoModelComment = `no model comment will be added for each field`
CGenDaoBriefClear = `delete all generated go files that do not exist in database`
CGenDaoBriefGroup = `
specifying the configuration group name of database for generated ORM instance,
it's not necessary and the default value is "default"
`
CGenDaoBriefJsonCase = `
generated json tag case for model struct, cases are as follows:
| Case | Example |
|---------------- |--------------------|
| Camel | AnyKindOfString |
| CamelLower | anyKindOfString | default
| Snake | any_kind_of_string |
| SnakeScreaming | ANY_KIND_OF_STRING |
| SnakeFirstUpper | rgb_code_md5 |
| Kebab | any-kind-of-string |
| KebabScreaming | ANY-KIND-OF-STRING |
`
CGenDaoBriefTplDaoIndexPath = `template file path for dao index file`
CGenDaoBriefTplDaoInternalPath = `template file path for dao internal file`
CGenDaoBriefTplDaoDoPathPath = `template file path for dao do file`
CGenDaoBriefTplDaoEntityPath = `template file path for dao entity file`
tplVarTableName = `{TplTableName}`
tplVarTableNameCamelCase = `{TplTableNameCamelCase}`
tplVarTableNameCamelLowerCase = `{TplTableNameCamelLowerCase}`
tplVarPackageImports = `{TplPackageImports}`
tplVarImportPrefix = `{TplImportPrefix}`
tplVarStructDefine = `{TplStructDefine}`
tplVarColumnDefine = `{TplColumnDefine}`
tplVarColumnNames = `{TplColumnNames}`
tplVarGroupName = `{TplGroupName}`
tplVarDatetimeStr = `{TplDatetimeStr}`
tplVarCreatedAtDatetimeStr = `{TplCreatedAtDatetimeStr}`
)
var (
createdAt = gtime.Now()
)
func init() {
gtag.Sets(g.MapStrStr{
`CGenDaoConfig`: CGenDaoConfig,
`CGenDaoUsage`: CGenDaoUsage,
`CGenDaoBrief`: CGenDaoBrief,
`CGenDaoEg`: CGenDaoEg,
`CGenDaoAd`: CGenDaoAd,
`CGenDaoBriefPath`: CGenDaoBriefPath,
`CGenDaoBriefLink`: CGenDaoBriefLink,
`CGenDaoBriefTables`: CGenDaoBriefTables,
`CGenDaoBriefTablesEx`: CGenDaoBriefTablesEx,
`CGenDaoBriefPrefix`: CGenDaoBriefPrefix,
`CGenDaoBriefRemovePrefix`: CGenDaoBriefRemovePrefix,
`CGenDaoBriefStdTime`: CGenDaoBriefStdTime,
`CGenDaoBriefWithTime`: CGenDaoBriefWithTime,
`CGenDaoBriefDaoPath`: CGenDaoBriefDaoPath,
`CGenDaoBriefDoPath`: CGenDaoBriefDoPath,
`CGenDaoBriefEntityPath`: CGenDaoBriefEntityPath,
`CGenDaoBriefGJsonSupport`: CGenDaoBriefGJsonSupport,
`CGenDaoBriefImportPrefix`: CGenDaoBriefImportPrefix,
`CGenDaoBriefOverwriteDao`: CGenDaoBriefOverwriteDao,
`CGenDaoBriefModelFile`: CGenDaoBriefModelFile,
`CGenDaoBriefModelFileForDao`: CGenDaoBriefModelFileForDao,
`CGenDaoBriefDescriptionTag`: CGenDaoBriefDescriptionTag,
`CGenDaoBriefNoJsonTag`: CGenDaoBriefNoJsonTag,
`CGenDaoBriefNoModelComment`: CGenDaoBriefNoModelComment,
`CGenDaoBriefClear`: CGenDaoBriefClear,
`CGenDaoBriefGroup`: CGenDaoBriefGroup,
`CGenDaoBriefJsonCase`: CGenDaoBriefJsonCase,
`CGenDaoBriefTplDaoIndexPath`: CGenDaoBriefTplDaoIndexPath,
`CGenDaoBriefTplDaoInternalPath`: CGenDaoBriefTplDaoInternalPath,
`CGenDaoBriefTplDaoDoPathPath`: CGenDaoBriefTplDaoDoPathPath,
`CGenDaoBriefTplDaoEntityPath`: CGenDaoBriefTplDaoEntityPath,
})
}
type (
CGenDao struct{}
CGenDaoInput struct {
g.Meta `name:"dao" config:"{CGenDaoConfig}" usage:"{CGenDaoUsage}" brief:"{CGenDaoBrief}" eg:"{CGenDaoEg}" ad:"{CGenDaoAd}"`
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
Path string `name:"path" short:"p" brief:"{CGenDaoBriefPath}" d:"internal"`
Link string `name:"link" short:"l" brief:"{CGenDaoBriefLink}"`
Tables string `name:"tables" short:"t" brief:"{CGenDaoBriefTables}"`
TablesEx string `name:"tablesEx" short:"x" brief:"{CGenDaoBriefTablesEx}"`
ShardingPattern []string `name:"shardingPattern" short:"sp" brief:"{CGenDaoBriefShardingPattern}"`
Group string `name:"group" short:"g" brief:"{CGenDaoBriefGroup}" d:"default"`
Prefix string `name:"prefix" short:"f" brief:"{CGenDaoBriefPrefix}"`
RemovePrefix string `name:"removePrefix" short:"r" brief:"{CGenDaoBriefRemovePrefix}"`
RemoveFieldPrefix string `name:"removeFieldPrefix" short:"rf" brief:"{CGenDaoBriefRemoveFieldPrefix}"`
JsonCase string `name:"jsonCase" short:"j" brief:"{CGenDaoBriefJsonCase}" d:"CamelLower"`
ImportPrefix string `name:"importPrefix" short:"i" brief:"{CGenDaoBriefImportPrefix}"`
DaoPath string `name:"daoPath" short:"d" brief:"{CGenDaoBriefDaoPath}" d:"dao"`
TablePath string `name:"tablePath" short:"tp" brief:"{CGenDaoBriefTablePath}" d:"table"`
DoPath string `name:"doPath" short:"o" brief:"{CGenDaoBriefDoPath}" d:"model/do"`
EntityPath string `name:"entityPath" short:"e" brief:"{CGenDaoBriefEntityPath}" d:"model/entity"`
TplDaoTablePath string `name:"tplDaoTablePath" short:"t0" brief:"{CGenDaoBriefTplDaoTablePath}"`
TplDaoIndexPath string `name:"tplDaoIndexPath" short:"t1" brief:"{CGenDaoBriefTplDaoIndexPath}"`
TplDaoInternalPath string `name:"tplDaoInternalPath" short:"t2" brief:"{CGenDaoBriefTplDaoInternalPath}"`
TplDaoDoPath string `name:"tplDaoDoPath" short:"t3" brief:"{CGenDaoBriefTplDaoDoPathPath}"`
TplDaoEntityPath string `name:"tplDaoEntityPath" short:"t4" brief:"{CGenDaoBriefTplDaoEntityPath}"`
StdTime bool `name:"stdTime" short:"s" brief:"{CGenDaoBriefStdTime}" orphan:"true"`
WithTime bool `name:"withTime" short:"w" brief:"{CGenDaoBriefWithTime}" orphan:"true"`
GJsonSupport bool `name:"gJsonSupport" short:"n" brief:"{CGenDaoBriefGJsonSupport}" orphan:"true"`
OverwriteDao bool `name:"overwriteDao" short:"v" brief:"{CGenDaoBriefOverwriteDao}" orphan:"true"`
DescriptionTag bool `name:"descriptionTag" short:"c" brief:"{CGenDaoBriefDescriptionTag}" orphan:"true"`
NoJsonTag bool `name:"noJsonTag" short:"k" brief:"{CGenDaoBriefNoJsonTag}" orphan:"true"`
NoModelComment bool `name:"noModelComment" short:"m" brief:"{CGenDaoBriefNoModelComment}" orphan:"true"`
Clear bool `name:"clear" short:"a" brief:"{CGenDaoBriefClear}" orphan:"true"`
GenTable bool `name:"genTable" short:"gt" brief:"{CGenDaoBriefGenTable}" orphan:"true"`
TypeMapping map[DBFieldTypeName]CustomAttributeType `name:"typeMapping" short:"y" brief:"{CGenDaoBriefTypeMapping}" orphan:"true"`
FieldMapping map[DBTableFieldName]CustomAttributeType `name:"fieldMapping" short:"fm" brief:"{CGenDaoBriefFieldMapping}" orphan:"true"`
// internal usage purpose.
genItems *CGenDaoInternalGenItems
}
CGenDaoOutput struct{}
CGenDaoInternalInput struct {
CGenDaoInput
DB gdb.DB
TableNames []string
NewTableNames []string
ModName string // Module name of current golang project, which is used for import purpose.
DB gdb.DB
TableNames []string
NewTableNames []string
ShardingTableSet *gset.StrSet
}
DBTableFieldName = string
DBFieldTypeName = string
CustomAttributeType struct {
Type string `brief:"custom attribute type name"`
Import string `brief:"custom import for this type"`
}
)
var (
createdAt = gtime.Now()
tplView = gview.New()
defaultTypeMapping = map[DBFieldTypeName]CustomAttributeType{
"decimal": {
Type: "float64",
},
"money": {
Type: "float64",
},
"numeric": {
Type: "float64",
},
"smallmoney": {
Type: "float64",
},
}
// tablewriter Options
twRenderer = tablewriter.WithRenderer(renderer.NewBlueprint(tw.Rendition{
Borders: tw.Border{Top: tw.Off, Bottom: tw.Off, Left: tw.Off, Right: tw.Off},
Settings: tw.Settings{
Separators: tw.Separators{BetweenRows: tw.Off, BetweenColumns: tw.Off},
},
Symbols: tw.NewSymbols(tw.StyleASCII),
}))
twConfig = tablewriter.WithConfig(tablewriter.Config{
Row: tw.CellConfig{
Formatting: tw.CellFormatting{AutoWrap: tw.WrapNone},
},
})
)
func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput, err error) {
if g.Cfg().Available(ctx) {
in.genItems = newCGenDaoInternalGenItems()
if in.Link != "" {
doGenDaoForArray(ctx, -1, in)
} else if g.Cfg().Available(ctx) {
v := g.Cfg().MustGet(ctx, CGenDaoConfig)
if v.IsSlice() {
for i := 0; i < len(v.Interfaces()); i++ {
@ -191,6 +137,7 @@ func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput,
} else {
doGenDaoForArray(ctx, -1, in)
}
doClear(in.genItems)
mlog.Print("done!")
return
}
@ -198,9 +145,8 @@ func (c CGenDao) Dao(ctx context.Context, in CGenDaoInput) (out *CGenDaoOutput,
// doGenDaoForArray implements the "gen dao" command for configuration array.
func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
var (
err error
db gdb.DB
modName string // Go module name, eg: github.com/gogf/gf.
err error
db gdb.DB
)
if index >= 0 {
err = g.Cfg().MustGet(
@ -215,27 +161,16 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
mlog.Fatalf(`path "%s" does not exist`, in.Path)
}
removePrefixArray := gstr.SplitAndTrim(in.RemovePrefix, ",")
if in.ImportPrefix == "" {
if !gfile.Exists("go.mod") {
mlog.Fatal("go.mod does not exist in current working directory")
}
var (
goModContent = gfile.GetContents("go.mod")
match, _ = gregex.MatchString(`^module\s+(.+)\s*`, goModContent)
)
if len(match) > 1 {
modName = gstr.Trim(match[1])
} else {
mlog.Fatal("module name does not found in go.mod")
}
}
// It uses user passed database configuration.
if in.Link != "" {
var tempGroup = gtime.TimestampNanoStr()
gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
err = gdb.AddConfigNode(tempGroup, gdb.ConfigNode{
Link: in.Link,
})
if err != nil {
mlog.Fatalf(`database configuration failed: %+v`, err)
}
if db, err = gdb.Instance(tempGroup); err != nil {
mlog.Fatalf(`database initialization failed: %+v`, err)
}
@ -258,29 +193,102 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
// Table excluding.
if in.TablesEx != "" {
array := garray.NewStrArrayFrom(tableNames)
for _, v := range gstr.SplitAndTrim(in.TablesEx, ",") {
array.RemoveValue(v)
for _, p := range gstr.SplitAndTrim(in.TablesEx, ",") {
if gstr.Contains(p, "*") || gstr.Contains(p, "?") {
p = gstr.ReplaceByMap(p, map[string]string{
"\r": "",
"\n": "",
})
p = gstr.ReplaceByMap(p, map[string]string{
"*": "\r",
"?": "\n",
})
p = gregex.Quote(p)
p = gstr.ReplaceByMap(p, map[string]string{
"\r": ".*",
"\n": ".",
})
for _, v := range array.Clone().Slice() {
if gregex.IsMatchString(p, v) {
array.RemoveValue(v)
}
}
} else {
array.RemoveValue(p)
}
}
tableNames = array.Slice()
}
// merge default typeMapping to input typeMapping.
if in.TypeMapping == nil {
in.TypeMapping = defaultTypeMapping
} else {
for key, typeMapping := range defaultTypeMapping {
if _, ok := in.TypeMapping[key]; !ok {
in.TypeMapping[key] = typeMapping
}
}
}
// Generating dao & model go files one by one according to given table name.
newTableNames := make([]string, len(tableNames))
var (
newTableNames = make([]string, len(tableNames))
shardingNewTableSet = gset.NewStrSet()
)
for i, tableName := range tableNames {
newTableName := tableName
for _, v := range removePrefixArray {
newTableName = gstr.TrimLeftStr(newTableName, v, 1)
}
if len(in.ShardingPattern) > 0 {
for _, pattern := range in.ShardingPattern {
var (
match []string
regPattern = gstr.Replace(pattern, "?", `(.+)`)
)
match, err = gregex.MatchString(regPattern, newTableName)
if err != nil {
mlog.Fatalf(`invalid sharding pattern "%s": %+v`, pattern, err)
}
if len(match) < 2 {
continue
}
newTableName = gstr.Replace(pattern, "?", "")
newTableName = gstr.Trim(newTableName, `_.-`)
if shardingNewTableSet.Contains(newTableName) {
tableNames[i] = ""
continue
}
// Add prefix to sharding table name, if not, the isSharding check would not match.
shardingNewTableSet.Add(in.Prefix + newTableName)
}
}
newTableName = in.Prefix + newTableName
newTableNames[i] = newTableName
if tableNames[i] != "" {
// If shardingNewTableSet contains newTableName (tableName is empty), it should not be added to tableNames, make it empty and filter later.
newTableNames[i] = newTableName
}
}
tableNames = garray.NewStrArrayFrom(tableNames).FilterEmpty().Slice()
newTableNames = garray.NewStrArrayFrom(newTableNames).FilterEmpty().Slice() // Filter empty table names. make sure that newTableNames and tableNames have the same length.
in.genItems.Scale()
// Dao: index and internal.
generateDao(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ShardingTableSet: shardingNewTableSet,
})
// Table: table fields.
generateTable(ctx, CGenDaoInternalInput{
CGenDaoInput: in,
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ShardingTableSet: shardingNewTableSet,
})
// Do.
generateDo(ctx, CGenDaoInternalInput{
@ -288,7 +296,6 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
// Entity.
generateEntity(ctx, CGenDaoInternalInput{
@ -296,15 +303,13 @@ func doGenDaoForArray(ctx context.Context, index int, in CGenDaoInput) {
DB: db,
TableNames: tableNames,
NewTableNames: newTableNames,
ModName: modName,
})
in.genItems.SetClear(in.Clear)
}
func getImportPartContent(source string, isDo bool) string {
var (
packageImportsArray = garray.NewStrArray()
)
func getImportPartContent(ctx context.Context, source string, isDo bool, appendImports []string) string {
var packageImportsArray = garray.NewStrArray()
if isDo {
packageImportsArray.Append(`"github.com/gogf/gf/v2/frame/g"`)
}
@ -321,6 +326,33 @@ func getImportPartContent(source string, isDo bool) string {
packageImportsArray.Append(`"github.com/gogf/gf/v2/encoding/gjson"`)
}
// Check and update imports in go.mod
if len(appendImports) > 0 {
goModPath := utils.GetModPath()
if goModPath == "" {
mlog.Fatal("go.mod not found in current project")
}
mod, err := modfile.Parse(goModPath, gfile.GetBytes(goModPath), nil)
if err != nil {
mlog.Fatalf("parse go.mod failed: %+v", err)
}
for _, appendImport := range appendImports {
found := false
for _, require := range mod.Require {
if gstr.Contains(appendImport, require.Mod.Path) {
found = true
break
}
}
if !found {
if err = gproc.ShellRun(ctx, `go get `+appendImport); err != nil {
mlog.Fatalf(`%+v`, err)
}
}
packageImportsArray.Append(fmt.Sprintf(`"%s"`, appendImport))
}
}
// Generate and write content to golang file.
packageImportsStr := ""
if packageImportsArray.Len() > 0 {
@ -329,13 +361,15 @@ func getImportPartContent(source string, isDo bool) string {
return packageImportsStr
}
func replaceDefaultVar(in CGenDaoInternalInput, origin string) string {
var tplCreatedAtDatetimeStr string
var tplDatetimeStr string = createdAt.String()
func assignDefaultVar(view *gview.View, in CGenDaoInternalInput) {
var (
tplCreatedAtDatetimeStr string
tplDatetimeStr = createdAt.String()
)
if in.WithTime {
tplCreatedAtDatetimeStr = fmt.Sprintf(`Created at %s`, tplDatetimeStr)
}
return gstr.ReplaceByMap(origin, g.MapStrStr{
view.Assigns(g.Map{
tplVarDatetimeStr: tplDatetimeStr,
tplVarCreatedAtDatetimeStr: tplCreatedAtDatetimeStr,
})

View File

@ -1,22 +1,46 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gendao
import (
"context"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gstr"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/utils"
)
func doClear(ctx context.Context, dirPath string) {
files, err := gfile.ScanDirFile(dirPath, "*.go", true)
if err != nil {
mlog.Fatal(err)
func doClear(items *CGenDaoInternalGenItems) {
var allGeneratedFilePaths = make([]string, 0)
for _, item := range items.Items {
allGeneratedFilePaths = append(allGeneratedFilePaths, item.GeneratedFilePaths...)
}
for _, file := range files {
if utils.IsFileDoNotEdit(file) {
if err = gfile.Remove(file); err != nil {
for i, v := range allGeneratedFilePaths {
allGeneratedFilePaths[i] = gfile.RealPath(v)
}
for _, item := range items.Items {
if !item.Clear {
continue
}
doClearItem(item, allGeneratedFilePaths)
}
}
func doClearItem(item CGenDaoInternalGenItem, allGeneratedFilePaths []string) {
var generatedFilePaths = make([]string, 0)
for _, dirPath := range item.StorageDirPaths {
filePaths, err := gfile.ScanDirFile(dirPath, "*.go", true)
if err != nil {
mlog.Fatal(err)
}
generatedFilePaths = append(generatedFilePaths, filePaths...)
}
for _, filePath := range generatedFilePaths {
if !gstr.InArray(allGeneratedFilePaths, filePath) {
if err := gfile.RemoveFile(filePath); err != nil {
mlog.Print(err)
}
}

View File

@ -1,17 +1,25 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gendao
import (
"bytes"
"context"
"fmt"
"path/filepath"
"strings"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gstr"
"github.com/olekukonko/tablewriter"
"github.com/gogf/gf/cmd/gf/v2/internal/consts"
"github.com/gogf/gf/cmd/gf/v2/internal/utility/mlog"
@ -23,26 +31,32 @@ func generateDao(ctx context.Context, in CGenDaoInternalInput) {
dirPathDao = gfile.Join(in.Path, in.DaoPath)
dirPathDaoInternal = gfile.Join(dirPathDao, "internal")
)
if in.Clear {
doClear(ctx, dirPathDao)
}
in.genItems.AppendDirPath(dirPathDao)
for i := 0; i < len(in.TableNames); i++ {
var (
realTableName = in.TableNames[i]
newTableName = in.NewTableNames[i]
)
generateDaoSingle(ctx, generateDaoSingleInput{
CGenDaoInternalInput: in,
TableName: in.TableNames[i],
NewTableName: in.NewTableNames[i],
TableName: realTableName,
NewTableName: newTableName,
DirPathDao: dirPathDao,
DirPathDaoInternal: dirPathDaoInternal,
IsSharding: in.ShardingTableSet.Contains(newTableName),
})
}
}
type generateDaoSingleInput struct {
CGenDaoInternalInput
TableName string // TableName specifies the table name of the table.
NewTableName string // NewTableName specifies the prefix-stripped name of the table.
// TableName specifies the table name of the table.
TableName string
// NewTableName specifies the prefix-stripped or custom edited name of the table.
NewTableName string
DirPathDao string
DirPathDaoInternal string
IsSharding bool
}
// generateDaoSingle generates the dao and model content of given table.
@ -53,23 +67,13 @@ func generateDaoSingle(ctx context.Context, in generateDaoSingleInput) {
mlog.Fatalf(`fetching tables fields failed for table "%s": %+v`, in.TableName, err)
}
var (
dirRealPath = gfile.RealPath(in.Path)
tableNameCamelCase = gstr.CaseCamel(in.NewTableName)
tableNameCamelLowerCase = gstr.CaseCamelLower(in.NewTableName)
tableNameCamelCase = formatFieldName(in.NewTableName, FieldNameCaseCamel)
tableNameCamelLowerCase = formatFieldName(in.NewTableName, FieldNameCaseCamelLower)
tableNameSnakeCase = gstr.CaseSnake(in.NewTableName)
importPrefix = in.ImportPrefix
)
if importPrefix == "" {
if dirRealPath == "" {
dirRealPath = in.Path
importPrefix = dirRealPath
importPrefix = gstr.Trim(dirRealPath, "./")
} else {
importPrefix = gstr.Replace(dirRealPath, gfile.Pwd(), "")
}
importPrefix = gstr.Replace(importPrefix, gfile.Separator, "/")
importPrefix = gstr.Join(g.SliceStr{in.ModName, importPrefix, in.DaoPath}, "/")
importPrefix, _ = gregex.ReplaceString(`\/{2,}`, `/`, gstr.Trim(importPrefix, "/"))
importPrefix = utils.GetImportPath(gfile.Join(in.Path, in.DaoPath))
} else {
importPrefix = gstr.Join(g.SliceStr{importPrefix, in.DaoPath}, "/")
}
@ -110,22 +114,35 @@ type generateDaoIndexInput struct {
}
func generateDaoIndex(in generateDaoIndexInput) {
path := gfile.Join(in.DirPathDao, in.FileName+".go")
path := filepath.FromSlash(gfile.Join(in.DirPathDao, in.FileName+".go"))
// It should add path to result slice whenever it would generate the path file or not.
in.genItems.AppendGeneratedFilePath(path)
if in.OverwriteDao || !gfile.Exists(path) {
indexContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoIndexPath, consts.TemplateGenDaoIndexContent),
g.MapStrStr{
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarTableNameCamelCase: in.TableNameCamelCase,
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
})
indexContent = replaceDefaultVar(in.CGenDaoInternalInput, indexContent)
if err := gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
var (
ctx = context.Background()
tplContent = getTemplateFromPathOrDefault(
in.TplDaoIndexPath, consts.TemplateGenDaoIndexContent,
)
)
tplView.ClearAssigns()
tplView.Assigns(gview.Params{
tplVarTableSharding: in.IsSharding,
tplVarTableShardingPrefix: in.NewTableName + "_",
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarTableNameCamelCase: in.TableNameCamelCase,
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
tplVarPackageName: filepath.Base(in.DaoPath),
})
indexContent, err := tplView.ParseContent(ctx, tplContent)
if err != nil {
mlog.Fatalf("parsing template content failed: %v", err)
}
if err = gfile.PutContents(path, strings.TrimSpace(indexContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", path)
mlog.Print("generated:", gfile.RealPath(path))
}
}
}
@ -140,49 +157,63 @@ type generateDaoInternalInput struct {
}
func generateDaoInternal(in generateDaoInternalInput) {
path := gfile.Join(in.DirPathDaoInternal, in.FileName+".go")
modelContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoInternalPath, consts.TemplateGenDaoInternalContent),
g.MapStrStr{
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarGroupName: in.Group,
tplVarTableNameCamelCase: in.TableNameCamelCase,
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap)),
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap)),
})
modelContent = replaceDefaultVar(in.CGenDaoInternalInput, modelContent)
var (
ctx = context.Background()
removeFieldPrefixArray = gstr.SplitAndTrim(in.RemoveFieldPrefix, ",")
tplContent = getTemplateFromPathOrDefault(
in.TplDaoInternalPath, consts.TemplateGenDaoInternalContent,
)
)
tplView.ClearAssigns()
tplView.Assigns(gview.Params{
tplVarImportPrefix: in.ImportPrefix,
tplVarTableName: in.TableName,
tplVarGroupName: in.Group,
tplVarTableNameCamelCase: in.TableNameCamelCase,
tplVarTableNameCamelLowerCase: in.TableNameCamelLowerCase,
tplVarColumnDefine: gstr.Trim(generateColumnDefinitionForDao(in.FieldMap, removeFieldPrefixArray)),
tplVarColumnNames: gstr.Trim(generateColumnNamesForDao(in.FieldMap, removeFieldPrefixArray)),
})
assignDefaultVar(tplView, in.CGenDaoInternalInput)
modelContent, err := tplView.ParseContent(ctx, tplContent)
if err != nil {
mlog.Fatalf("parsing template content failed: %v", err)
}
path := filepath.FromSlash(gfile.Join(in.DirPathDaoInternal, in.FileName+".go"))
in.genItems.AppendGeneratedFilePath(path)
if err := gfile.PutContents(path, strings.TrimSpace(modelContent)); err != nil {
mlog.Fatalf("writing content to '%s' failed: %v", path, err)
} else {
utils.GoFmt(path)
mlog.Print("generated:", path)
mlog.Print("generated:", gfile.RealPath(path))
}
}
// generateColumnNamesForDao generates and returns the column names assignment content of column struct
// for specified table.
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField, removeFieldPrefixArray []string) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForDao(fieldMap)
)
for index, name := range names {
field := fieldMap[name]
newFiledName := field.Name
for _, v := range removeFieldPrefixArray {
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
}
array[index] = []string{
" #" + gstr.CaseCamel(field.Name) + ":",
" #" + formatFieldName(newFiledName, FieldNameCaseCamel) + ":",
fmt.Sprintf(` #"%s",`, field.Name),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
namesContent := buffer.String()
// Let's do this hack of table writer for indent!
namesContent = gstr.Replace(namesContent, " #", "")
@ -192,12 +223,13 @@ func generateColumnNamesForDao(fieldMap map[string]*gdb.TableField) string {
}
// generateColumnDefinitionForDao generates and returns the column names definition for specified table.
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string {
func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField, removeFieldPrefixArray []string) string {
var (
buffer = bytes.NewBuffer(nil)
array = make([][]string, len(fieldMap))
names = sortFieldKeyForDao(fieldMap)
)
for index, name := range names {
var (
field = fieldMap[name]
@ -206,19 +238,19 @@ func generateColumnDefinitionForDao(fieldMap map[string]*gdb.TableField) string
"\r", " ",
}))
)
newFiledName := field.Name
for _, v := range removeFieldPrefixArray {
newFiledName = gstr.TrimLeftStr(newFiledName, v, 1)
}
array[index] = []string{
" #" + gstr.CaseCamel(field.Name),
" #" + formatFieldName(newFiledName, FieldNameCaseCamel),
" # " + "string",
" #" + fmt.Sprintf(`// %s`, comment),
}
}
tw := tablewriter.NewWriter(buffer)
tw.SetBorder(false)
tw.SetRowLine(false)
tw.SetAutoWrapText(false)
tw.SetColumnSeparator("")
tw.AppendBulk(array)
tw.Render()
table := tablewriter.NewTable(buffer, twRenderer, twConfig)
table.Bulk(array)
table.Render()
defineContent := buffer.String()
// Let's do this hack of table writer for indent!
defineContent = gstr.Replace(defineContent, " #", "")

View File

@ -1,12 +1,19 @@
// Copyright GoFrame gf Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gendao
import (
"context"
"fmt"
"path/filepath"
"strings"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/os/gview"
"github.com/gogf/gf/v2/text/gregex"
"github.com/gogf/gf/v2/text/gstr"
@ -16,10 +23,8 @@ import (
)
func generateDo(ctx context.Context, in CGenDaoInternalInput) {
var dirPathDo = gfile.Join(in.Path, in.DoPath)
if in.Clear {
doClear(ctx, dirPathDo)
}
var dirPathDo = filepath.FromSlash(gfile.Join(in.Path, in.DoPath))
in.genItems.AppendDirPath(dirPathDo)
in.NoJsonTag = true
in.DescriptionTag = false
in.NoModelComment = false
@ -30,53 +35,66 @@ func generateDo(ctx context.Context, in CGenDaoInternalInput) {
mlog.Fatalf("fetching tables fields failed for table '%s':\n%v", tableName, err)
}
var (
newTableName = in.NewTableNames[i]
doFilePath = gfile.Join(dirPathDo, gstr.CaseSnake(newTableName)+".go")
structDefinition = generateStructDefinition(ctx, generateStructDefinitionInput{
newTableName = in.NewTableNames[i]
doFilePath = gfile.Join(dirPathDo, gstr.CaseSnake(newTableName)+".go")
structDefinition, _ = generateStructDefinition(ctx, generateStructDefinitionInput{
CGenDaoInternalInput: in,
TableName: tableName,
StructName: gstr.CaseCamel(newTableName),
StructName: formatFieldName(newTableName, FieldNameCaseCamel),
FieldMap: fieldMap,
IsDo: true,
})
)
// replace all types to interface{}.
// replace all types to any.
structDefinition, _ = gregex.ReplaceStringFuncMatch(
"([A-Z]\\w*?)\\s+([\\w\\*\\.]+?)\\s+(//)",
structDefinition,
func(match []string) string {
// If the type is already a pointer/slice/map, it does nothing.
if !gstr.HasPrefix(match[2], "*") && !gstr.HasPrefix(match[2], "[]") && !gstr.HasPrefix(match[2], "map") {
return fmt.Sprintf(`%s interface{} %s`, match[1], match[3])
return fmt.Sprintf(`%s any %s`, match[1], match[3])
}
return match[0]
},
)
modelContent := generateDoContent(
ctx,
in,
tableName,
gstr.CaseCamel(newTableName),
formatFieldName(newTableName, FieldNameCaseCamel),
structDefinition,
)
in.genItems.AppendGeneratedFilePath(doFilePath)
err = gfile.PutContents(doFilePath, strings.TrimSpace(modelContent))
if err != nil {
mlog.Fatalf(`writing content to "%s" failed: %v`, doFilePath, err)
} else {
utils.GoFmt(doFilePath)
mlog.Print("generated:", doFilePath)
mlog.Print("generated:", gfile.RealPath(doFilePath))
}
}
}
func generateDoContent(in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string) string {
doContent := gstr.ReplaceByMap(
getTemplateFromPathOrDefault(in.TplDaoDoPath, consts.TemplateGenDaoDoContent),
g.MapStrStr{
tplVarTableName: tableName,
tplVarPackageImports: getImportPartContent(structDefine, true),
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarStructDefine: structDefine,
})
doContent = replaceDefaultVar(in, doContent)
func generateDoContent(
ctx context.Context, in CGenDaoInternalInput, tableName, tableNameCamelCase, structDefine string,
) string {
var (
tplContent = getTemplateFromPathOrDefault(
in.TplDaoDoPath, consts.TemplateGenDaoDoContent,
)
)
tplView.ClearAssigns()
tplView.Assigns(gview.Params{
tplVarTableName: tableName,
tplVarPackageImports: getImportPartContent(ctx, structDefine, true, nil),
tplVarTableNameCamelCase: tableNameCamelCase,
tplVarStructDefine: structDefine,
tplVarPackageName: filepath.Base(in.DoPath),
})
assignDefaultVar(tplView, in)
doContent, err := tplView.ParseContent(ctx, tplContent)
if err != nil {
mlog.Fatalf("parsing template content failed: %v", err)
}
return doContent
}

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