diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 86fb55226..d4ca188d2 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -67,5 +67,7 @@ jobs:
run: GOARCH=amd64 go test -v ./... -race -coverprofile=coverage.txt -covermode=atomic
- name: Report Coverage
- run: bash <(curl -s https://codecov.io/bash)
+ uses: codecov/codecov-action@v2
+ with:
+ flags: go-${{ matrix.go }}
diff --git a/README.MD b/README.MD
index dda9ad1a5..8e00bb4fa 100644
--- a/README.MD
+++ b/README.MD
@@ -75,7 +75,7 @@ The `Web` component performance of `GoFrame`, please refer to third-party projec
# Contributors
This project exists thanks to all the people who contribute. [[Contributors](https://github.com/gogf/gf/graphs/contributors)].
-
+
# Donators
diff --git a/README_ZH.MD b/README_ZH.MD
index 79b22cfde..172ad307f 100644
--- a/README_ZH.MD
+++ b/README_ZH.MD
@@ -91,7 +91,7 @@ golang版本 >= 1.11
# 贡献
感谢所有参与`GoFrame`开发的贡献者。 [[贡献者列表](https://github.com/gogf/gf/graphs/contributors)].
-
+
# 捐赠
diff --git a/container/gtype/gtype.go b/container/gtype/gtype.go
index b43e7f7d6..d6711f2a1 100644
--- a/container/gtype/gtype.go
+++ b/container/gtype/gtype.go
@@ -4,14 +4,11 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
-// Package gtype provides kinds of high performance and concurrent-safe basic variable types.
+// Package gtype provides high performance and concurrent-safe basic variable types.
package gtype
-// Type is alias of Interface.
-type Type = Interface
-
// New is alias of NewInterface.
// See NewInterface.
-func New(value ...interface{}) *Type {
+func New(value ...interface{}) *Interface {
return NewInterface(value...)
}
diff --git a/container/gtype/gtype_bool.go b/container/gtype/gtype_bool.go
index 4b7e45909..e24b5cd21 100644
--- a/container/gtype/gtype_bool.go
+++ b/container/gtype/gtype_bool.go
@@ -51,7 +51,7 @@ func (v *Bool) Set(value bool) (old bool) {
return
}
-// Val atomically loads and returns t.valueue.
+// Val atomically loads and returns t.value.
func (v *Bool) Val() bool {
return atomic.LoadInt32(&v.value) > 0
}
diff --git a/container/gtype/gtype_float32.go b/container/gtype/gtype_float32.go
index 7da59ce87..364a979f0 100644
--- a/container/gtype/gtype_float32.go
+++ b/container/gtype/gtype_float32.go
@@ -11,7 +11,6 @@ import (
"math"
"strconv"
"sync/atomic"
- "unsafe"
)
// Float32 is a struct for concurrent-safe operation for type float32.
@@ -51,7 +50,7 @@ func (v *Float32) Add(delta float32) (new float32) {
old := math.Float32frombits(v.value)
new = old + delta
if atomic.CompareAndSwapUint32(
- (*uint32)(unsafe.Pointer(&v.value)),
+ &v.value,
math.Float32bits(old),
math.Float32bits(new),
) {
diff --git a/container/gtype/gtype_float64.go b/container/gtype/gtype_float64.go
index 340bdef00..dcf68aa7d 100644
--- a/container/gtype/gtype_float64.go
+++ b/container/gtype/gtype_float64.go
@@ -11,7 +11,6 @@ import (
"math"
"strconv"
"sync/atomic"
- "unsafe"
)
// Float64 is a struct for concurrent-safe operation for type float64.
@@ -51,7 +50,7 @@ func (v *Float64) Add(delta float64) (new float64) {
old := math.Float64frombits(v.value)
new = old + delta
if atomic.CompareAndSwapUint64(
- (*uint64)(unsafe.Pointer(&v.value)),
+ &v.value,
math.Float64bits(old),
math.Float64bits(new),
) {
diff --git a/container/gtype/gtype_z_unit_bytes_test.go b/container/gtype/gtype_z_unit_bytes_test.go
index 49145d290..468673eb1 100644
--- a/container/gtype/gtype_z_unit_bytes_test.go
+++ b/container/gtype/gtype_z_unit_bytes_test.go
@@ -22,7 +22,7 @@ func Test_Bytes(t *testing.T) {
t.AssertEQ(iClone.Set([]byte("123")), []byte("abc"))
t.AssertEQ(iClone.Val(), []byte("123"))
- //空参测试
+ // 空参测试
i1 := gtype.NewBytes()
t.AssertEQ(i1.Val(), nil)
})
diff --git a/database/gdb/gdb.go b/database/gdb/gdb.go
index 35e392caa..d9a7813ec 100644
--- a/database/gdb/gdb.go
+++ b/database/gdb/gdb.go
@@ -265,6 +265,7 @@ type (
)
const (
+ defaultModelSafe = false
queryTypeNormal = 0
queryTypeCount = 1
unionTypeNormal = 0
diff --git a/database/gdb/gdb_model.go b/database/gdb/gdb_model.go
index 717ab6e01..1398c3454 100644
--- a/database/gdb/gdb_model.go
+++ b/database/gdb/gdb_model.go
@@ -132,7 +132,7 @@ func (c *Core) Model(tableNameQueryOrStruct ...interface{}) *Model {
tableStr = c.QuotePrefixTableName(tableNames[0])
}
}
- return &Model{
+ m := &Model{
db: c.db,
tablesInit: tableStr,
tables: tableStr,
@@ -142,6 +142,10 @@ func (c *Core) Model(tableNameQueryOrStruct ...interface{}) *Model {
filter: true,
extraArgs: extraArgs,
}
+ if defaultModelSafe {
+ m.safe = true
+ }
+ return m
}
// Raw creates and returns a model based on a raw sql not a table.
@@ -154,7 +158,7 @@ func (c *Core) Raw(rawSql string, args ...interface{}) *Model {
return model
}
-// Raw creates and returns a model based on a raw sql not a table.
+// Raw sets current model as a raw sql model.
// Example:
// db.Raw("SELECT * FROM `user` WHERE `name` = ?", "john").Scan(&result)
// See Core.Raw.
@@ -169,7 +173,7 @@ func (tx *TX) Raw(rawSql string, args ...interface{}) *Model {
return tx.Model().Raw(rawSql, args...)
}
-// With creates and returns an ORM model based on meta data of given object.
+// With creates and returns an ORM model based on metadata of given object.
func (c *Core) With(objects ...interface{}) *Model {
return c.db.Model().With(objects...)
}
diff --git a/database/gdb/gdb_model_condition.go b/database/gdb/gdb_model_condition.go
index 9a6d4ac50..bcf73bb9c 100644
--- a/database/gdb/gdb_model_condition.go
+++ b/database/gdb/gdb_model_condition.go
@@ -236,16 +236,6 @@ func (m *Model) WhereOrNotNull(columns ...string) *Model {
return model
}
-// Group sets the "GROUP BY" statement for the model.
-func (m *Model) Group(groupBy ...string) *Model {
- if len(groupBy) > 0 {
- model := m.getModel()
- model.groupBy = m.db.GetCore().QuoteString(gstr.Join(groupBy, ","))
- return model
- }
- return m
-}
-
// And adds "AND" condition to the where statement.
// Deprecated, use Where instead.
func (m *Model) And(where interface{}, args ...interface{}) *Model {
@@ -267,11 +257,17 @@ func (m *Model) Or(where interface{}, args ...interface{}) *Model {
return m.WhereOr(where, args...)
}
-// GroupBy is alias of Model.Group.
-// See Model.Group.
-// Deprecated, use Group instead.
-func (m *Model) GroupBy(groupBy string) *Model {
- return m.Group(groupBy)
+// Group sets the "GROUP BY" statement for the model.
+func (m *Model) Group(groupBy ...string) *Model {
+ if len(groupBy) == 0 {
+ return m
+ }
+ model := m.getModel()
+ if model.groupBy != "" {
+ model.groupBy += ","
+ }
+ model.groupBy = model.db.GetCore().QuoteString(strings.Join(groupBy, ","))
+ return model
}
// Order sets the "ORDER BY" statement for the model.
@@ -283,7 +279,7 @@ func (m *Model) Order(orderBy ...string) *Model {
if model.orderBy != "" {
model.orderBy += ","
}
- model.orderBy = m.db.GetCore().QuoteString(strings.Join(orderBy, " "))
+ model.orderBy = model.db.GetCore().QuoteString(strings.Join(orderBy, " "))
return model
}
@@ -292,12 +288,7 @@ func (m *Model) OrderAsc(column string) *Model {
if len(column) == 0 {
return m
}
- model := m.getModel()
- if model.orderBy != "" {
- model.orderBy += ","
- }
- model.orderBy = m.db.GetCore().QuoteWord(column) + " ASC"
- return model
+ return m.Order(column + " ASC")
}
// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
@@ -305,12 +296,7 @@ func (m *Model) OrderDesc(column string) *Model {
if len(column) == 0 {
return m
}
- model := m.getModel()
- if model.orderBy != "" {
- model.orderBy += ","
- }
- model.orderBy = m.db.GetCore().QuoteWord(column) + " DESC"
- return model
+ return m.Order(column + " DESC")
}
// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
@@ -320,13 +306,6 @@ func (m *Model) OrderRandom() *Model {
return model
}
-// OrderBy is alias of Model.Order.
-// See Model.Order.
-// Deprecated, use Order instead.
-func (m *Model) OrderBy(orderBy string) *Model {
- return m.Order(orderBy)
-}
-
// Limit sets the "LIMIT" statement for the model.
// The parameter `limit` can be either one or two number, if passed two number is passed,
// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
diff --git a/database/gdb/gdb_model_with.go b/database/gdb/gdb_model_with.go
index 014df31a5..d780d1f30 100644
--- a/database/gdb/gdb_model_with.go
+++ b/database/gdb/gdb_model_with.go
@@ -7,6 +7,7 @@
package gdb
import (
+ "database/sql"
"fmt"
"github.com/gogf/gf/errors/gcode"
"reflect"
@@ -156,7 +157,8 @@ func (m *Model) doWithScanStruct(pointer interface{}) error {
model = model.Order(parsedTagOutput.Order)
}
err = model.Fields(fieldKeys).Where(relatedSourceName, relatedTargetValue).Scan(bindToReflectValue)
- if err != nil {
+ // It ignores sql.ErrNoRows in with feature.
+ if err != nil && err != sql.ErrNoRows {
return err
}
}
@@ -265,7 +267,8 @@ func (m *Model) doWithScanStructs(pointer interface{}) error {
err = model.Fields(fieldKeys).
Where(relatedSourceName, relatedTargetValue).
ScanList(pointer, fieldName, parsedTagOutput.With)
- if err != nil {
+ // It ignores sql.ErrNoRows in with feature.
+ if err != nil && err != sql.ErrNoRows {
return err
}
}
diff --git a/database/gdb/gdb_z_mysql_association_with_test.go b/database/gdb/gdb_z_mysql_association_with_test.go
index aef619da9..c9e7414e2 100644
--- a/database/gdb/gdb_z_mysql_association_with_test.go
+++ b/database/gdb/gdb_z_mysql_association_with_test.go
@@ -1992,6 +1992,7 @@ PRIMARY KEY (id)
})
}
+// https://github.com/gogf/gf/issues/1401
func Test_With_Feature_Issue1401(t *testing.T) {
var (
table1 = "parcels"
@@ -2032,3 +2033,65 @@ func Test_With_Feature_Issue1401(t *testing.T) {
t.Assert(parcelDetail.Items[0].ParcelId, 3)
})
}
+
+// https://github.com/gogf/gf/issues/1412
+func Test_With_Feature_Issue1412(t *testing.T) {
+ var (
+ table1 = "parcels"
+ table2 = "items"
+ )
+ array := gstr.SplitAndTrim(gtest.TestDataContent(`issue1412.sql`), ";")
+ for _, v := range array {
+ if _, err := db.Exec(v); err != nil {
+ gtest.Error(err)
+ }
+ }
+ defer dropTable(table1)
+ defer dropTable(table2)
+
+ gtest.C(t, func(t *gtest.T) {
+ type Items struct {
+ gmeta.Meta `orm:"table:items"`
+ Id int `json:"id"`
+ Name string `json:"name"`
+ }
+
+ type ParcelRsp struct {
+ gmeta.Meta `orm:"table:parcels"`
+ Id int `json:"id"`
+ ItemId int `json:"item_id"`
+ Items Items `json:"items" orm:"with:Id=ItemId"`
+ }
+
+ entity := &ParcelRsp{}
+ err := db.Model("parcels").With(Items{}).Where("id=3").Scan(&entity)
+ t.AssertNil(err)
+ t.Assert(entity.Id, 3)
+ t.Assert(entity.ItemId, 0)
+ t.Assert(entity.Items.Id, 0)
+ t.Assert(entity.Items.Name, "")
+ })
+
+ gtest.C(t, func(t *gtest.T) {
+ type Items struct {
+ gmeta.Meta `orm:"table:items"`
+ Id int `json:"id"`
+ Name string `json:"name"`
+ }
+
+ type ParcelRsp struct {
+ gmeta.Meta `orm:"table:parcels"`
+ Id int `json:"id"`
+ ItemId int `json:"item_id"`
+ Items Items `json:"items" orm:"with:Id=ItemId"`
+ }
+
+ entity := &ParcelRsp{}
+ err := db.Model("parcels").With(Items{}).Where("id=30000").Scan(&entity)
+ t.AssertNE(err, nil)
+ t.Assert(entity.Id, 0)
+ t.Assert(entity.ItemId, 0)
+ t.Assert(entity.Items.Id, 0)
+ t.Assert(entity.Items.Name, "")
+ })
+}
diff --git a/database/gdb/gdb_z_mysql_method_test.go b/database/gdb/gdb_z_mysql_method_test.go
index b571a1da3..c3e7f7aa5 100644
--- a/database/gdb/gdb_z_mysql_method_test.go
+++ b/database/gdb/gdb_z_mysql_method_test.go
@@ -1313,14 +1313,14 @@ func Test_Model_InnerJoin(t *testing.T) {
t.Assert(n, 5)
- result, err := db.Model(table1+" u1").InnerJoin(table2+" u2", "u1.id = u2.id").OrderBy("u1.id").Select()
+ result, err := db.Model(table1+" u1").InnerJoin(table2+" u2", "u1.id = u2.id").Order("u1.id").Select()
if err != nil {
t.Fatal(err)
}
t.Assert(len(result), 5)
- result, err = db.Model(table1+" u1").InnerJoin(table2+" u2", "u1.id = u2.id").Where("u1.id > ?", 1).OrderBy("u1.id").Select()
+ result, err = db.Model(table1+" u1").InnerJoin(table2+" u2", "u1.id = u2.id").Where("u1.id > ?", 1).Order("u1.id").Select()
if err != nil {
t.Fatal(err)
}
diff --git a/database/gdb/gdb_z_mysql_model_test.go b/database/gdb/gdb_z_mysql_model_test.go
index f9f95fcef..b113d771e 100644
--- a/database/gdb/gdb_z_mysql_model_test.go
+++ b/database/gdb/gdb_z_mysql_model_test.go
@@ -1225,7 +1225,7 @@ func Test_Model_GroupBy(t *testing.T) {
defer dropTable(table)
gtest.C(t, func(t *gtest.T) {
- result, err := db.Model(table).GroupBy("id").Select()
+ result, err := db.Model(table).Group("id").All()
t.AssertNil(err)
t.Assert(len(result), TableSize)
t.Assert(result[0]["nickname"].String(), "name_1")
diff --git a/database/gdb/testdata/issue1412.sql b/database/gdb/testdata/issue1412.sql
new file mode 100644
index 000000000..453fca783
--- /dev/null
+++ b/database/gdb/testdata/issue1412.sql
@@ -0,0 +1,30 @@
+-- ----------------------------
+-- Table structure for items
+-- ----------------------------
+CREATE TABLE `items` (
+ `id` int(11) NOT NULL,
+ `name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of items
+-- ----------------------------
+INSERT INTO `items` VALUES (1, '金秋产品1');
+INSERT INTO `items` VALUES (2, '金秋产品2');
+
+-- ----------------------------
+-- Table structure for parcels
+-- ----------------------------
+CREATE TABLE `parcels` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `item_id` int(11) NULL DEFAULT NULL,
+ PRIMARY KEY (`id`) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
+
+-- ----------------------------
+-- Records of parcels
+-- ----------------------------
+INSERT INTO `parcels` VALUES (1, 1);
+INSERT INTO `parcels` VALUES (2, 2);
+INSERT INTO `parcels` VALUES (3, 0);
\ No newline at end of file
diff --git a/encoding/gjson/gjson_z_example_conversion_test.go b/encoding/gjson/gjson_z_example_conversion_test.go
index d2f4bdd9f..f7b01f48c 100644
--- a/encoding/gjson/gjson_z_example_conversion_test.go
+++ b/encoding/gjson/gjson_z_example_conversion_test.go
@@ -48,10 +48,10 @@ func Example_conversionNormalFormats() {
// ======================
// YAML:
// users:
- // array:
- // - John
- // - Ming
- // count: 1
+ // array:
+ // - John
+ // - Ming
+ // count: 1
//
// ======================
// TOML:
diff --git a/encoding/gurl/url_test.go b/encoding/gurl/url_test.go
index c992caea3..1ba6ab154 100644
--- a/encoding/gurl/url_test.go
+++ b/encoding/gurl/url_test.go
@@ -13,9 +13,11 @@ import (
"github.com/gogf/gf/test/gtest"
)
-var urlStr string = `https://golang.org/x/crypto?go-get=1 +`
-var urlEncode string = `https%3A%2F%2Fgolang.org%2Fx%2Fcrypto%3Fgo-get%3D1+%2B`
-var rawUrlEncode string = `https%3A%2F%2Fgolang.org%2Fx%2Fcrypto%3Fgo-get%3D1%20%2B`
+var (
+ urlStr = `https://golang.org/x/crypto?go-get=1 +`
+ urlEncode = `https%3A%2F%2Fgolang.org%2Fx%2Fcrypto%3Fgo-get%3D1+%2B`
+ rawUrlEncode = `https%3A%2F%2Fgolang.org%2Fx%2Fcrypto%3Fgo-get%3D1%20%2B`
+)
func TestEncodeAndDecode(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
diff --git a/encoding/gxml/gxml.go b/encoding/gxml/gxml.go
index cf831bd28..57f393336 100644
--- a/encoding/gxml/gxml.go
+++ b/encoding/gxml/gxml.go
@@ -10,7 +10,7 @@ package gxml
import (
"strings"
- "github.com/clbanning/mxj"
+ "github.com/clbanning/mxj/v2"
"github.com/gogf/gf/encoding/gcharset"
"github.com/gogf/gf/text/gregex"
)
@@ -48,7 +48,7 @@ func Encode(m map[string]interface{}, rootTag ...string) ([]byte, error) {
return mxj.Map(m).Xml(rootTag...)
}
-// Encode encodes map to a XML format content as bytes with indent.
+// EncodeWithIndent encodes map to an XML format content as bytes with indent.
// The optional parameter is used to specify the XML root tag.
func EncodeWithIndent(m map[string]interface{}, rootTag ...string) ([]byte, error) {
return mxj.Map(m).XmlIndent("", "\t", rootTag...)
@@ -68,7 +68,7 @@ func ToJson(content []byte) ([]byte, error) {
}
}
-// convert converts the encoding of given XML content from XML root tag into UTF-8 encoding content.
+// convert does convert the encoding of given XML content from XML root tag into UTF-8 encoding content.
func convert(xml []byte) (res []byte, err error) {
patten := `<\?xml.*encoding\s*=\s*['|"](.*?)['|"].*\?>`
matchStr, err := gregex.MatchString(patten, string(xml))
diff --git a/encoding/gxml/gxml_test.go b/encoding/gxml/gxml_test.go
index 8d9989a6d..cf901cd12 100644
--- a/encoding/gxml/gxml_test.go
+++ b/encoding/gxml/gxml_test.go
@@ -55,7 +55,7 @@ func buildXml(charset string, str string) (string, string) {
return srcXml, dstXml
}
-//测试XML中字符集的转换
+// 测试XML中字符集的转换
func Test_XmlToJson(t *testing.T) {
for _, v := range testData {
srcXml, dstXml := buildXml(v.otherEncoding, v.utf8)
diff --git a/encoding/gyaml/gyaml.go b/encoding/gyaml/gyaml.go
index 95c531b57..255ccfed7 100644
--- a/encoding/gyaml/gyaml.go
+++ b/encoding/gyaml/gyaml.go
@@ -9,7 +9,7 @@ package gyaml
import (
"github.com/gogf/gf/internal/json"
- "gopkg.in/yaml.v3"
+ "gopkg.in/yaml.v2"
"github.com/gogf/gf/util/gconv"
)
diff --git a/frame/gins/gins.go b/frame/gins/gins.go
index 719cf9bba..ca9843967 100644
--- a/frame/gins/gins.go
+++ b/frame/gins/gins.go
@@ -12,31 +12,31 @@ import (
)
var (
- // instances is the instance map for common used components.
- instances = gmap.NewStrAnyMap(true)
+ // localInstances is the instance map for common used components.
+ localInstances = gmap.NewStrAnyMap(true)
)
// Get returns the instance by given name.
func Get(name string) interface{} {
- return instances.Get(name)
+ return localInstances.Get(name)
}
// Set sets a instance object to the instance manager with given name.
func Set(name string, instance interface{}) {
- instances.Set(name, instance)
+ localInstances.Set(name, instance)
}
// GetOrSet returns the instance by name,
// or set instance to the instance manager if it does not exist and returns this instance.
func GetOrSet(name string, instance interface{}) interface{} {
- return instances.GetOrSet(name, instance)
+ return localInstances.GetOrSet(name, instance)
}
// GetOrSetFunc returns the instance by name,
// or sets instance with returned value of callback function `f` if it does not exist
// and then returns this instance.
func GetOrSetFunc(name string, f func() interface{}) interface{} {
- return instances.GetOrSetFunc(name, f)
+ return localInstances.GetOrSetFunc(name, f)
}
// GetOrSetFuncLock returns the instance by name,
@@ -46,11 +46,11 @@ func GetOrSetFunc(name string, f func() interface{}) interface{} {
// GetOrSetFuncLock differs with GetOrSetFunc function is that it executes function `f`
// with mutex.Lock of the hash map.
func GetOrSetFuncLock(name string, f func() interface{}) interface{} {
- return instances.GetOrSetFuncLock(name, f)
+ return localInstances.GetOrSetFuncLock(name, f)
}
// SetIfNotExist sets to the map if the `name` does not exist, then returns true.
// It returns false if exists, and `instance` would be ignored.
func SetIfNotExist(name string, instance interface{}) bool {
- return instances.SetIfNotExist(name, instance)
+ return localInstances.SetIfNotExist(name, instance)
}
diff --git a/frame/gins/gins_database.go b/frame/gins/gins_database.go
index 8d722a10d..a6143dd76 100644
--- a/frame/gins/gins_database.go
+++ b/frame/gins/gins_database.go
@@ -12,6 +12,7 @@ import (
"github.com/gogf/gf/errors/gcode"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/intlog"
+ "github.com/gogf/gf/os/gcfg"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gutil"
@@ -25,59 +26,79 @@ const (
configNodeNameDatabase = "database"
)
-// Database returns an instance of database ORM object
-// with specified configuration group name.
+// Database returns an instance of database ORM object with specified configuration group name.
+// Note that it panics if any error occurs duration instance creating.
func Database(name ...string) gdb.DB {
- group := gdb.DefaultGroupName
+ var (
+ ctx = context.Background()
+ group = gdb.DefaultGroupName
+ )
+
if len(name) > 0 && name[0] != "" {
group = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameDatabase, group)
- db := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ db := localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ // It ignores returned error to avoid file no found error while it's not necessary.
var (
configMap map[string]interface{}
- configNodeKey string
+ configNodeKey = configNodeNameDatabase
)
// It firstly searches the configuration of the instance name.
- if Config().Available() {
- configNodeKey, _ = gutil.MapPossibleItemByKey(
- Config().GetMap("."),
- configNodeNameDatabase,
- )
- if configNodeKey == "" {
- configNodeKey = configNodeNameDatabase
+ if configData, _ := Config().Data(ctx); len(configData) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configData, configNodeNameDatabase); v != "" {
+ configNodeKey = v
}
- configMap = Config().GetMap(configNodeKey)
+ }
+ if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
+ configMap = v.Map()
}
if len(configMap) == 0 && !gdb.IsConfigured() {
- configFilePath, _ := Config().GetFilePath()
- if configFilePath == "" {
- exampleFileName := "config.example.toml"
- if exampleConfigFilePath, _ := Config().GetFilePath(exampleFileName); exampleConfigFilePath != "" {
- panic(gerror.NewCodef(
- gcode.CodeMissingConfiguration,
- `configuration file "%s" not found, but found "%s", did you miss renaming the example configuration file?`,
- Config().GetFileName(),
- exampleFileName,
- ))
- } else {
- panic(gerror.NewCodef(
- gcode.CodeMissingConfiguration,
- `configuration file "%s" not found, did you miss the configuration file or the misspell the configuration file name?`,
- Config().GetFileName(),
- ))
+ // File configuration object checks.
+ var (
+ err error
+ configFilePath string
+ )
+ if fileConfig, ok := Config().GetAdapter().(*gcfg.AdapterFile); ok {
+ if configFilePath, err = fileConfig.GetFilePath(); configFilePath == "" {
+ exampleFileName := "config.example.toml"
+ if exampleConfigFilePath, _ := fileConfig.GetFilePath(exampleFileName); exampleConfigFilePath != "" {
+ err = gerror.WrapCodef(
+ gcode.CodeMissingConfiguration,
+ err,
+ `configuration file "%s" not found, but found "%s", did you miss renaming the example configuration file?`,
+ fileConfig.GetFileName(),
+ exampleFileName,
+ )
+ } else {
+ err = gerror.WrapCodef(
+ gcode.CodeMissingConfiguration,
+ err,
+ `configuration file "%s" not found, did you miss the configuration file or the misspell the configuration file name?`,
+ fileConfig.GetFileName(),
+ )
+ }
+ if err != nil {
+ panic(err)
+ }
}
}
- panic(gerror.NewCodef(
- gcode.CodeMissingConfiguration,
- `database initialization failed: "%s" node not found, is configuration file or configuration node missing?`,
- configNodeNameDatabase,
- ))
+ // Panic if nothing found in Config object or in gdb configuration.
+ if len(configMap) == 0 && !gdb.IsConfigured() {
+ err = gerror.WrapCodef(
+ gcode.CodeMissingConfiguration,
+ err,
+ `database initialization failed: "%s" node not found, is configuration file or configuration node missing?`,
+ configNodeNameDatabase,
+ )
+ panic(err)
+ }
}
+
if len(configMap) == 0 {
configMap = make(map[string]interface{})
}
- // Parse `m` as map-slice and adds it to gdb's global configurations.
+ // Parse `m` as map-slice and adds it to global configurations for package gdb.
for g, groupConfig := range configMap {
cg := gdb.ConfigGroup{}
switch value := groupConfig.(type) {
@@ -94,11 +115,11 @@ func Database(name ...string) gdb.DB {
}
if len(cg) > 0 {
if gdb.GetConfig(group) == nil {
- intlog.Printf(context.TODO(), "add configuration for group: %s, %#v", g, cg)
+ intlog.Printf(ctx, "add configuration for group: %s, %#v", g, cg)
gdb.SetConfigGroup(g, cg)
} else {
- intlog.Printf(context.TODO(), "ignore configuration as it already exists for group: %s, %#v", g, cg)
- intlog.Printf(context.TODO(), "%s, %#v", g, cg)
+ intlog.Printf(ctx, "ignore configuration as it already exists for group: %s, %#v", g, cg)
+ intlog.Printf(ctx, "%s, %#v", g, cg)
}
}
}
@@ -112,27 +133,33 @@ func Database(name ...string) gdb.DB {
if len(cg) > 0 {
if gdb.GetConfig(group) == nil {
- intlog.Printf(context.TODO(), "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
+ intlog.Printf(ctx, "add configuration for group: %s, %#v", gdb.DefaultGroupName, cg)
gdb.SetConfigGroup(gdb.DefaultGroupName, cg)
} else {
- intlog.Printf(context.TODO(), "ignore configuration as it already exists for group: %s, %#v", gdb.DefaultGroupName, cg)
- intlog.Printf(context.TODO(), "%s, %#v", gdb.DefaultGroupName, cg)
+ intlog.Printf(ctx, "ignore configuration as it already exists for group: %s, %#v", gdb.DefaultGroupName, cg)
+ intlog.Printf(ctx, "%s, %#v", gdb.DefaultGroupName, cg)
}
}
}
+
// Create a new ORM object with given configurations.
if db, err := gdb.New(name...); err == nil {
- if Config().Available() {
- // Initialize logger for ORM.
- var loggerConfigMap map[string]interface{}
- loggerConfigMap = Config().GetMap(fmt.Sprintf("%s.%s", configNodeKey, configNodeNameLogger))
- if len(loggerConfigMap) == 0 {
- loggerConfigMap = Config().GetMap(configNodeKey)
+ // Initialize logger for ORM.
+ var (
+ loggerConfigMap map[string]interface{}
+ loggerNodeName = fmt.Sprintf("%s.%s", configNodeKey, configNodeNameLogger)
+ )
+ if v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {
+ loggerConfigMap = v.Map()
+ }
+ if len(loggerConfigMap) == 0 {
+ if v, _ := Config().Get(ctx, configNodeKey); !v.IsEmpty() {
+ loggerConfigMap = v.Map()
}
- if len(loggerConfigMap) > 0 {
- if err := db.GetLogger().SetConfigWithMap(loggerConfigMap); err != nil {
- panic(err)
- }
+ }
+ if len(loggerConfigMap) > 0 {
+ if err = db.GetLogger().SetConfigWithMap(loggerConfigMap); err != nil {
+ panic(err)
}
}
return db
@@ -158,7 +185,7 @@ func parseDBConfigNode(value interface{}) *gdb.ConfigNode {
if err != nil {
panic(err)
}
- // To be compatible with old version.
+ // Be compatible with old version.
if _, v := gutil.MapPossibleItemByKey(nodeMap, "LinkInfo"); v != nil {
node.Link = gconv.String(v)
}
diff --git a/frame/gins/gins_log.go b/frame/gins/gins_log.go
index 30018f031..dfd87b6b5 100644
--- a/frame/gins/gins_log.go
+++ b/frame/gins/gins_log.go
@@ -7,6 +7,7 @@
package gins
import (
+ "context"
"fmt"
"github.com/gogf/gf/os/glog"
"github.com/gogf/gf/util/gutil"
@@ -19,29 +20,44 @@ const (
// Log returns an instance of glog.Logger.
// The parameter `name` is the name for the instance.
+// Note that it panics if any error occurs duration instance creating.
func Log(name ...string) *glog.Logger {
- instanceName := glog.DefaultName
+ var (
+ ctx = context.Background()
+ instanceName = glog.DefaultName
+ )
if len(name) > 0 && name[0] != "" {
instanceName = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameLogger, instanceName)
- return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
logger := glog.Instance(instanceName)
// To avoid file no found error while it's not necessary.
- if Config().Available() {
- var m map[string]interface{}
- nodeKey, _ := gutil.MapPossibleItemByKey(Config().GetMap("."), configNodeNameLogger)
- if nodeKey == "" {
- nodeKey = configNodeNameLogger
+ var (
+ configMap map[string]interface{}
+ loggerNodeName = configNodeNameLogger
+ )
+ // Try to find possible `loggerNodeName` in case-insensitive way.
+ if configData, _ := Config().Data(ctx); len(configData) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configData, configNodeNameLogger); v != "" {
+ loggerNodeName = v
}
- m = Config().GetMap(fmt.Sprintf(`%s.%s`, nodeKey, instanceName))
- if len(m) == 0 {
- m = Config().GetMap(nodeKey)
+ }
+ // Retrieve certain logger configuration by logger name.
+ certainLoggerNodeName := fmt.Sprintf(`%s.%s`, loggerNodeName, instanceName)
+ if v, _ := Config().Get(ctx, certainLoggerNodeName); !v.IsEmpty() {
+ configMap = v.Map()
+ }
+ // Retrieve global logger configuration if configuration for certain logger name does not exist.
+ if len(configMap) == 0 {
+ if v, _ := Config().Get(ctx, loggerNodeName); !v.IsEmpty() {
+ configMap = v.Map()
}
- if len(m) > 0 {
- if err := logger.SetConfigWithMap(m); err != nil {
- panic(err)
- }
+ }
+ // Set logger config if config map is not empty.
+ if len(configMap) > 0 {
+ if err := logger.SetConfigWithMap(configMap); err != nil {
+ panic(err)
}
}
return logger
diff --git a/frame/gins/gins_redis.go b/frame/gins/gins_redis.go
index ef0ad47f4..bf3ab73b7 100644
--- a/frame/gins/gins_redis.go
+++ b/frame/gins/gins_redis.go
@@ -7,8 +7,11 @@
package gins
import (
+ "context"
"fmt"
"github.com/gogf/gf/database/gredis"
+ "github.com/gogf/gf/errors/gcode"
+ "github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/util/gutil"
)
@@ -19,42 +22,46 @@ const (
)
// Redis returns an instance of redis client with specified configuration group name.
+// Note that it panics if any error occurs duration instance creating.
func Redis(name ...string) *gredis.Redis {
- config := Config()
- group := gredis.DefaultGroupName
+ var (
+ ctx = context.Background()
+ group = gredis.DefaultGroupName
+ )
if len(name) > 0 && name[0] != "" {
group = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameRedis, group)
- result := instances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ result := localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
// If already configured, it returns the redis instance.
if _, ok := gredis.GetConfig(group); ok {
return gredis.Instance(group)
}
// Or else, it parses the default configuration file and returns a new redis instance.
- var m map[string]interface{}
- if _, v := gutil.MapPossibleItemByKey(Config().GetMap("."), configNodeNameRedis); v != nil {
- m = gconv.Map(v)
+ var (
+ configMap map[string]interface{}
+ )
+
+ if configData, err := Config().Data(ctx); err != nil {
+ panic(gerror.WrapCode(gcode.CodeOperationFailed, err, `retrieving redis configuration failed`))
+ } else {
+ if _, v := gutil.MapPossibleItemByKey(configData, configNodeNameRedis); v != nil {
+ configMap = gconv.Map(v)
+ }
}
- if len(m) > 0 {
- if v, ok := m[group]; ok {
+
+ if len(configMap) > 0 {
+ if v, ok := configMap[group]; ok {
redisConfig, err := gredis.ConfigFromStr(gconv.String(v))
if err != nil {
panic(err)
}
return gredis.New(redisConfig)
} else {
- panic(fmt.Sprintf(`configuration for redis not found for group "%s"`, group))
+ panic(fmt.Sprintf(`missing configuration for redis group "%s"`, group))
}
} else {
- filepath, err := config.GetFilePath()
- if err != nil {
- panic(err)
- }
- panic(fmt.Sprintf(
- `incomplete configuration for redis: "redis" node not found in config file "%s"`,
- filepath,
- ))
+ panic(`missing configuration for redis: "redis" node not found`)
}
return nil
})
diff --git a/frame/gins/gins_server.go b/frame/gins/gins_server.go
index e73eadaa8..3dcdd65c4 100644
--- a/frame/gins/gins_server.go
+++ b/frame/gins/gins_server.go
@@ -7,8 +7,11 @@
package gins
import (
+ "context"
"fmt"
+ "github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/net/ghttp"
+ "github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/util/gutil"
)
@@ -18,43 +21,61 @@ const (
)
// Server returns an instance of http server with specified name.
+// Note that it panics if any error occurs duration instance creating.
func Server(name ...interface{}) *ghttp.Server {
- instanceKey := fmt.Sprintf("%s.%v", frameCoreComponentNameServer, name)
- return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
- s := ghttp.GetServer(name...)
- // To avoid file no found error while it's not necessary.
- if Config().Available() {
- var (
- serverConfigMap map[string]interface{}
- serverLoggerConfigMap map[string]interface{}
- )
- nodeKey, _ := gutil.MapPossibleItemByKey(Config().GetMap("."), configNodeNameServer)
- if nodeKey == "" {
- nodeKey = configNodeNameServer
+ var (
+ ctx = context.Background()
+ instanceName = ghttp.DefaultServerName
+ instanceKey = fmt.Sprintf("%s.%v", frameCoreComponentNameServer, name)
+ )
+ if len(name) > 0 && name[0] != "" {
+ instanceName = gconv.String(name[0])
+ }
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ s := ghttp.GetServer(instanceName)
+ // It ignores returned error to avoid file no found error while it's not necessary.
+ var (
+ serverConfigMap map[string]interface{}
+ serverLoggerConfigMap map[string]interface{}
+ configNodeName = configNodeNameServer
+ )
+ if configData, _ := Config().Data(ctx); len(configData) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configData, configNodeNameServer); v != "" {
+ configNodeName = v
}
- // Server configuration.
- serverConfigMap = Config().GetMap(fmt.Sprintf(`%s.%s`, nodeKey, s.GetName()))
- if len(serverConfigMap) == 0 {
- serverConfigMap = Config().GetMap(nodeKey)
- }
- if len(serverConfigMap) > 0 {
- if err := s.SetConfigWithMap(serverConfigMap); err != nil {
- panic(err)
- }
- }
- // Server logger configuration.
- serverLoggerConfigMap = Config().GetMap(
- fmt.Sprintf(`%s.%s.%s`, nodeKey, s.GetName(), configNodeNameLogger),
- )
- if len(serverLoggerConfigMap) > 0 {
- if err := s.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil {
- panic(err)
- }
- }
- // As it might use template feature,
- // it initialize the view instance as well.
- _ = getViewInstance()
}
+ // Server configuration.
+ certainConfigNodeName := fmt.Sprintf(`%s.%s`, configNodeName, s.GetName())
+ if v, _ := Config().Get(ctx, certainConfigNodeName); !v.IsEmpty() {
+ serverConfigMap = v.Map()
+ }
+ if len(serverConfigMap) == 0 {
+ if v, _ := Config().Get(ctx, configNodeName); !v.IsEmpty() {
+ serverConfigMap = v.Map()
+ }
+ }
+ if len(serverConfigMap) > 0 {
+ if err := s.SetConfigWithMap(serverConfigMap); err != nil {
+ panic(err)
+ }
+ } else {
+ // The configuration is not necessary, so it just prints internal logs.
+ intlog.Printf(ctx, `missing configuration for HTTP server "%s"`, instanceName)
+ }
+
+ // Server logger configuration checks.
+ serverLoggerNodeName := fmt.Sprintf(`%s.%s.%s`, configNodeName, s.GetName(), configNodeNameLogger)
+ if v, _ := Config().Get(ctx, serverLoggerNodeName); !v.IsEmpty() {
+ serverLoggerConfigMap = v.Map()
+ }
+ if len(serverLoggerConfigMap) > 0 {
+ if err := s.Logger().SetConfigWithMap(serverLoggerConfigMap); err != nil {
+ panic(err)
+ }
+ }
+ // As it might use template feature,
+ // it initializes the view instance as well.
+ _ = getViewInstance()
return s
}).(*ghttp.Server)
}
diff --git a/frame/gins/gins_view.go b/frame/gins/gins_view.go
index c67cef1ac..83914a12a 100644
--- a/frame/gins/gins_view.go
+++ b/frame/gins/gins_view.go
@@ -7,6 +7,7 @@
package gins
import (
+ "context"
"fmt"
"github.com/gogf/gf/os/gview"
"github.com/gogf/gf/util/gutil"
@@ -19,38 +20,48 @@ const (
// View returns an instance of View with default settings.
// The parameter `name` is the name for the instance.
+// Note that it panics if any error occurs duration instance creating.
func View(name ...string) *gview.View {
instanceName := gview.DefaultName
if len(name) > 0 && name[0] != "" {
instanceName = name[0]
}
instanceKey := fmt.Sprintf("%s.%s", frameCoreComponentNameViewer, instanceName)
- return instances.GetOrSetFuncLock(instanceKey, func() interface{} {
+ return localInstances.GetOrSetFuncLock(instanceKey, func() interface{} {
return getViewInstance(instanceName)
}).(*gview.View)
}
func getViewInstance(name ...string) *gview.View {
- instanceName := gview.DefaultName
+ var (
+ ctx = context.Background()
+ instanceName = gview.DefaultName
+ )
if len(name) > 0 && name[0] != "" {
instanceName = name[0]
}
view := gview.Instance(instanceName)
// To avoid file no found error while it's not necessary.
- if Config().Available() {
- var m map[string]interface{}
- nodeKey, _ := gutil.MapPossibleItemByKey(Config().GetMap("."), configNodeNameViewer)
- if nodeKey == "" {
- nodeKey = configNodeNameViewer
+ var (
+ configMap map[string]interface{}
+ configNodeName = configNodeNameViewer
+ )
+ if configData, _ := Config().Data(ctx); len(configData) > 0 {
+ if v, _ := gutil.MapPossibleItemByKey(configData, configNodeNameViewer); v != "" {
+ configNodeName = v
}
- m = Config().GetMap(fmt.Sprintf(`%s.%s`, nodeKey, instanceName))
- if len(m) == 0 {
- m = Config().GetMap(nodeKey)
+ }
+ if v, _ := Config().Get(ctx, fmt.Sprintf(`%s.%s`, configNodeName, instanceName)); !v.IsEmpty() {
+ configMap = v.Map()
+ }
+ if len(configMap) == 0 {
+ if v, _ := Config().Get(ctx, configNodeName); !v.IsEmpty() {
+ configMap = v.Map()
}
- if len(m) > 0 {
- if err := view.SetConfigWithMap(m); err != nil {
- panic(err)
- }
+ }
+ if len(configMap) > 0 {
+ if err := view.SetConfigWithMap(configMap); err != nil {
+ panic(err)
}
}
return view
diff --git a/frame/gins/gins_z_unit_config_test.go b/frame/gins/gins_z_unit_config_test.go
index 0057b347b..2893939d4 100644
--- a/frame/gins/gins_z_unit_config_test.go
+++ b/frame/gins/gins_z_unit_config_test.go
@@ -7,6 +7,7 @@
package gins_test
import (
+ "context"
"fmt"
"github.com/gogf/gf/debug/gdebug"
"github.com/gogf/gf/frame/gins"
@@ -21,6 +22,7 @@ import (
)
var (
+ ctx = context.Background()
configContent = gfile.GetContents(
gdebug.TestDataPath("config", "config.toml"),
)
@@ -48,14 +50,14 @@ func Test_Config2(t *testing.T) {
err = gfile.PutContents(gfile.Join(dirPath, name), configContent)
t.Assert(err, nil)
- err = gins.Config().AddPath(dirPath)
+ err = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)
t.Assert(err, nil)
- defer gins.Config().Clear()
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
- t.Assert(gins.Config().Get("test"), "v=1")
- t.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0")
+ t.Assert(gins.Config().MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config().MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config().MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
// for gfsnotify callbacks to refresh cache of config file
time.Sleep(500 * time.Millisecond)
@@ -72,14 +74,14 @@ func Test_Config2(t *testing.T) {
err = gfile.PutContents(gfile.Join(dirPath, name), configContent)
t.Assert(err, nil)
- err = gins.Config().AddPath(dirPath)
+ err = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)
t.Assert(err, nil)
- defer gins.Config().Clear()
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
- t.Assert(gins.Config().Get("test"), "v=1")
- t.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0")
+ t.Assert(gins.Config().MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config().MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config().MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
// for gfsnotify callbacks to refresh cache of config file
time.Sleep(500 * time.Millisecond)
@@ -98,15 +100,15 @@ func Test_Config3(t *testing.T) {
err = gfile.PutContents(gfile.Join(dirPath, name), configContent)
t.Assert(err, nil)
- err = gins.Config("test").AddPath(dirPath)
+ err = gins.Config("test").GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)
t.Assert(err, nil)
- defer gins.Config("test").Clear()
- gins.Config("test").SetFileName("test.toml")
+ defer gins.Config("test").GetAdapter().(*gcfg.AdapterFile).Clear()
+ gins.Config("test").GetAdapter().(*gcfg.AdapterFile).SetFileName("test.toml")
- t.Assert(gins.Config("test").Get("test"), "v=1")
- t.Assert(gins.Config("test").Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config("test").Get("redis.disk"), "127.0.0.1:6379,0")
+ t.Assert(gins.Config("test").MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config("test").MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config("test").MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
// for gfsnotify callbacks to refresh cache of config file
time.Sleep(500 * time.Millisecond)
@@ -122,15 +124,15 @@ func Test_Config3(t *testing.T) {
err = gfile.PutContents(gfile.Join(dirPath, name), configContent)
t.Assert(err, nil)
- err = gins.Config("test").AddPath(dirPath)
+ err = gins.Config("test").GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)
t.Assert(err, nil)
- defer gins.Config("test").Clear()
- gins.Config("test").SetFileName("test.toml")
+ defer gins.Config("test").GetAdapter().(*gcfg.AdapterFile).Clear()
+ gins.Config("test").GetAdapter().(*gcfg.AdapterFile).SetFileName("test.toml")
- t.Assert(gins.Config("test").Get("test"), "v=1")
- t.Assert(gins.Config("test").Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config("test").Get("redis.disk"), "127.0.0.1:6379,0")
+ t.Assert(gins.Config("test").MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config("test").MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config("test").MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
// for gfsnotify callbacks to refresh cache of config file for next unit testing case.
time.Sleep(500 * time.Millisecond)
@@ -144,12 +146,12 @@ func Test_Config4(t *testing.T) {
err := gfile.PutContents(file, configContent)
t.Assert(err, nil)
defer gfile.Remove(file)
- defer gins.Config().Clear()
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
- t.Assert(gins.Config().AddPath(path), nil)
- t.Assert(gins.Config().Get("test"), "v=1")
- t.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0")
+ t.Assert(gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)
+ t.Assert(gins.Config().MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config().MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config().MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
time.Sleep(500 * time.Millisecond)
@@ -159,11 +161,11 @@ func Test_Config4(t *testing.T) {
err := gfile.PutContents(file, configContent)
t.Assert(err, nil)
defer gfile.Remove(file)
- defer gins.Config().Clear()
- t.Assert(gins.Config().AddPath(path), nil)
- t.Assert(gins.Config().Get("test"), "v=1")
- t.Assert(gins.Config().Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config().Get("redis.disk"), "127.0.0.1:6379,0")
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
+ t.Assert(gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)
+ t.Assert(gins.Config().MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config().MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config().MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
time.Sleep(500 * time.Millisecond)
@@ -173,12 +175,12 @@ func Test_Config4(t *testing.T) {
err := gfile.PutContents(file, configContent)
t.Assert(err, nil)
defer gfile.Remove(file)
- defer gins.Config("test").Clear()
- gins.Config("test").SetFileName("test.toml")
- t.Assert(gins.Config("test").AddPath(path), nil)
- t.Assert(gins.Config("test").Get("test"), "v=1")
- t.Assert(gins.Config("test").Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config("test").Get("redis.disk"), "127.0.0.1:6379,0")
+ defer gins.Config("test").GetAdapter().(*gcfg.AdapterFile).Clear()
+ gins.Config("test").GetAdapter().(*gcfg.AdapterFile).SetFileName("test.toml")
+ t.Assert(gins.Config("test").GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)
+ t.Assert(gins.Config("test").MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config("test").MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config("test").MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
time.Sleep(500 * time.Millisecond)
@@ -188,12 +190,12 @@ func Test_Config4(t *testing.T) {
err := gfile.PutContents(file, configContent)
t.Assert(err, nil)
defer gfile.Remove(file)
- defer gins.Config().Clear()
- gins.Config("test").SetFileName("test.toml")
- t.Assert(gins.Config("test").AddPath(path), nil)
- t.Assert(gins.Config("test").Get("test"), "v=1")
- t.Assert(gins.Config("test").Get("database.default.1.host"), "127.0.0.1")
- t.Assert(gins.Config("test").Get("redis.disk"), "127.0.0.1:6379,0")
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
+ gins.Config("test").GetAdapter().(*gcfg.AdapterFile).SetFileName("test.toml")
+ t.Assert(gins.Config("test").GetAdapter().(*gcfg.AdapterFile).AddPath(path), nil)
+ t.Assert(gins.Config("test").MustGet(ctx, "test"), "v=1")
+ t.Assert(gins.Config("test").MustGet(ctx, "database.default.1.host"), "127.0.0.1")
+ t.Assert(gins.Config("test").MustGet(ctx, "redis.disk"), "127.0.0.1:6379,0")
})
}
func Test_Basic2(t *testing.T) {
@@ -206,6 +208,6 @@ func Test_Basic2(t *testing.T) {
_ = gfile.Remove(path)
}()
- t.Assert(gins.Config().Get("log-path"), "logs")
+ t.Assert(gins.Config().MustGet(ctx, "log-path"), "logs")
})
}
diff --git a/frame/gins/gins_z_unit_database_test.go b/frame/gins/gins_z_unit_database_test.go
index 2693a27e7..9ffb016ff 100644
--- a/frame/gins/gins_z_unit_database_test.go
+++ b/frame/gins/gins_z_unit_database_test.go
@@ -9,6 +9,7 @@ package gins_test
import (
"github.com/gogf/gf/debug/gdebug"
"github.com/gogf/gf/frame/gins"
+ "github.com/gogf/gf/os/gcfg"
"github.com/gogf/gf/os/gtime"
"testing"
"time"
@@ -32,10 +33,10 @@ func Test_Database(t *testing.T) {
err = gfile.PutContents(gfile.Join(dirPath, name), databaseContent)
t.Assert(err, nil)
- err = gins.Config().AddPath(dirPath)
+ err = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)
t.Assert(err, nil)
- defer gins.Config().Clear()
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
// for gfsnotify callbacks to refresh cache of config file
time.Sleep(500 * time.Millisecond)
diff --git a/frame/gins/gins_z_unit_redis_test.go b/frame/gins/gins_z_unit_redis_test.go
index 6ac44f85f..06a30129a 100644
--- a/frame/gins/gins_z_unit_redis_test.go
+++ b/frame/gins/gins_z_unit_redis_test.go
@@ -9,6 +9,7 @@ package gins_test
import (
"github.com/gogf/gf/debug/gdebug"
"github.com/gogf/gf/frame/gins"
+ "github.com/gogf/gf/os/gcfg"
"github.com/gogf/gf/os/gtime"
"testing"
"time"
@@ -33,10 +34,10 @@ func Test_Redis(t *testing.T) {
err = gfile.PutContents(gfile.Join(dirPath, name), redisContent)
t.Assert(err, nil)
- err = gins.Config().AddPath(dirPath)
+ err = gins.Config().GetAdapter().(*gcfg.AdapterFile).AddPath(dirPath)
t.Assert(err, nil)
- defer gins.Config().Clear()
+ defer gins.Config().GetAdapter().(*gcfg.AdapterFile).Clear()
// for gfsnotify callbacks to refresh cache of config file
time.Sleep(500 * time.Millisecond)
diff --git a/frame/gins/gins_z_unit_view_test.go b/frame/gins/gins_z_unit_view_test.go
index 084c09705..b8c3bbb83 100644
--- a/frame/gins/gins_z_unit_view_test.go
+++ b/frame/gins/gins_z_unit_view_test.go
@@ -54,9 +54,9 @@ func Test_View_Config(t *testing.T) {
// view1 test1
gtest.C(t, func(t *gtest.T) {
dirPath := gdebug.TestDataPath("view1")
- gcfg.SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
- defer gcfg.ClearContent()
- defer instances.Clear()
+ Config().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
+ defer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()
+ defer localInstances.Clear()
view := View("test1")
t.AssertNE(view, nil)
@@ -76,9 +76,9 @@ func Test_View_Config(t *testing.T) {
// view1 test2
gtest.C(t, func(t *gtest.T) {
dirPath := gdebug.TestDataPath("view1")
- gcfg.SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
- defer gcfg.ClearContent()
- defer instances.Clear()
+ Config().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
+ defer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()
+ defer localInstances.Clear()
view := View("test2")
t.AssertNE(view, nil)
@@ -98,9 +98,9 @@ func Test_View_Config(t *testing.T) {
// view2
gtest.C(t, func(t *gtest.T) {
dirPath := gdebug.TestDataPath("view2")
- gcfg.SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
- defer gcfg.ClearContent()
- defer instances.Clear()
+ Config().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
+ defer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()
+ defer localInstances.Clear()
view := View()
t.AssertNE(view, nil)
@@ -120,9 +120,9 @@ func Test_View_Config(t *testing.T) {
// view2
gtest.C(t, func(t *gtest.T) {
dirPath := gdebug.TestDataPath("view2")
- gcfg.SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
- defer gcfg.ClearContent()
- defer instances.Clear()
+ Config().GetAdapter().(*gcfg.AdapterFile).SetContent(gfile.GetContents(gfile.Join(dirPath, "config.toml")))
+ defer Config().GetAdapter().(*gcfg.AdapterFile).ClearContent()
+ defer localInstances.Clear()
view := View("test100")
t.AssertNE(view, nil)
diff --git a/go.mod b/go.mod
index fc660eac6..1343ded26 100644
--- a/go.mod
+++ b/go.mod
@@ -4,18 +4,17 @@ go 1.14
require (
github.com/BurntSushi/toml v0.4.1
- github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28
+ github.com/clbanning/mxj/v2 v2.5.5
github.com/fatih/color v1.12.0
github.com/fsnotify/fsnotify v1.5.1
github.com/go-sql-driver/mysql v1.6.0
github.com/gomodule/redigo v1.8.5
github.com/gorilla/websocket v1.4.2
- github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf
+ github.com/grokify/html-strip-tags-go v0.0.1
github.com/olekukonko/tablewriter v0.0.5
- go.opentelemetry.io/otel v1.0.0-RC3
- go.opentelemetry.io/otel/oteltest v1.0.0-RC3
- go.opentelemetry.io/otel/trace v1.0.0-RC3
+ go.opentelemetry.io/otel v1.0.0
+ go.opentelemetry.io/otel/trace v1.0.0
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023
golang.org/x/text v0.3.6
- gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
+ gopkg.in/yaml.v2 v2.4.0
)
diff --git a/go.sum b/go.sum
index 269310b56..e3486a097 100644
--- a/go.sum
+++ b/go.sum
@@ -1,7 +1,7 @@
github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw=
github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28 h1:LdXxtjzvZYhhUaonAaAKArG3pyC67kGL3YY+6hGG8G4=
-github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/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=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.12.0 h1:mRhaKNwANqRgUBGKmnI5ZxEk7QXmjQeCcuYFMX2bfcc=
@@ -16,8 +16,8 @@ github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf h1:wIOAyJMMen0ELGiFzlmqxdcV1yGbkyHBAB6PolcNbLA=
-github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
+github.com/grokify/html-strip-tags-go v0.0.1 h1:0fThFwLbW7P/kOiTBs03FsJSV9RM2M/Q/MOnCQxKMo0=
+github.com/grokify/html-strip-tags-go v0.0.1/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
@@ -32,12 +32,10 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-go.opentelemetry.io/otel v1.0.0-RC3 h1:kvwiyEkiUT/JaadXzVLI/R1wDO934A7r3Bs2wEe6wqA=
-go.opentelemetry.io/otel v1.0.0-RC3/go.mod h1:Ka5j3ua8tZs4Rkq4Ex3hwgBgOchyPVq5S6P2lz//nKQ=
-go.opentelemetry.io/otel/oteltest v1.0.0-RC3 h1:MjaeegZTaX0Bv9uB9CrdVjOFM/8slRjReoWoV9xDCpY=
-go.opentelemetry.io/otel/oteltest v1.0.0-RC3/go.mod h1:xpzajI9JBRr7gX63nO6kAmImmYIAtuQblZ36Z+LfCjE=
-go.opentelemetry.io/otel/trace v1.0.0-RC3 h1:9F0ayEvlxv8BmNmPbU005WK7hC+7KbOazCPZjNa1yME=
-go.opentelemetry.io/otel/trace v1.0.0-RC3/go.mod h1:VUt2TUYd8S2/ZRX09ZDFZQwn2RqfMB5MzO17jBojGxo=
+go.opentelemetry.io/otel v1.0.0 h1:qTTn6x71GVBvoafHK/yaRUmFzI4LcONZD0/kXxl5PHI=
+go.opentelemetry.io/otel v1.0.0/go.mod h1:AjRVh9A5/5DE7S+mZtTR6t8vpKKryam+0lREnfmS4cg=
+go.opentelemetry.io/otel/trace v1.0.0 h1:TSBr8GTEtKevYMG/2d21M989r5WJYVimhTHBKVEZuh4=
+go.opentelemetry.io/otel/trace v1.0.0/go.mod h1:PXTWqayeFUlJV1YDNhsJYB184+IvAH814St6o6ajzIs=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023 h1:ADo5wSpq2gqaCGQWzk7S5vd//0iyyLeAratkEoG5dLE=
golang.org/x/net v0.0.0-20210520170846-37e1c6afe023/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -55,6 +53,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
+gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/net/ghttp/ghttp.go b/net/ghttp/ghttp.go
index 7e7febfe3..b9354f3f9 100644
--- a/net/ghttp/ghttp.go
+++ b/net/ghttp/ghttp.go
@@ -107,9 +107,9 @@ const (
HookAfterOutput = "HOOK_AFTER_OUTPUT"
ServerStatusStopped = 0
ServerStatusRunning = 1
+ DefaultServerName = "default"
+ DefaultDomainName = "default"
supportedHttpMethods = "GET,PUT,POST,DELETE,PATCH,HEAD,CONNECT,OPTIONS,TRACE"
- defaultServerName = "default"
- defaultDomainName = "default"
defaultMethod = "ALL"
handlerTypeHandler = 1
handlerTypeObject = 2
diff --git a/net/ghttp/ghttp_middleware_tracing.go b/net/ghttp/ghttp_middleware_tracing.go
index 052b4ee7e..aa28222ad 100644
--- a/net/ghttp/ghttp_middleware_tracing.go
+++ b/net/ghttp/ghttp_middleware_tracing.go
@@ -8,19 +8,21 @@ package ghttp
import (
"fmt"
+ "io/ioutil"
+ "net/http"
+
"github.com/gogf/gf"
"github.com/gogf/gf/internal/utils"
"github.com/gogf/gf/net/ghttp/internal/client"
"github.com/gogf/gf/net/ghttp/internal/httputil"
"github.com/gogf/gf/net/gtrace"
"github.com/gogf/gf/text/gstr"
+ "github.com/gogf/gf/util/gconv"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
- "io/ioutil"
- "net/http"
)
const (
@@ -56,8 +58,8 @@ func MiddlewareServerTracing(r *Request) {
r.Body = utils.NewReadCloser(reqBodyContentBytes, false)
span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
- attribute.Any(tracingEventHttpRequestHeaders, httputil.HeaderToMap(r.Header)),
- attribute.Any(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx)),
+ attribute.String(tracingEventHttpRequestHeaders, gconv.String(httputil.HeaderToMap(r.Header))),
+ attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ctx).String()),
attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
string(reqBodyContentBytes),
gtrace.MaxContentLogSize(),
@@ -82,7 +84,7 @@ func MiddlewareServerTracing(r *Request) {
)
span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
- attribute.Any(tracingEventHttpResponseHeaders, httputil.HeaderToMap(r.Response.Header())),
+ attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(r.Response.Header()))),
attribute.String(tracingEventHttpResponseBody, resBodyContent),
))
return
diff --git a/net/ghttp/ghttp_request_param_post.go b/net/ghttp/ghttp_request_param_post.go
deleted file mode 100644
index 8ddfa17ab..000000000
--- a/net/ghttp/ghttp_request_param_post.go
+++ /dev/null
@@ -1,215 +0,0 @@
-// Copyright GoFrame 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 ghttp
-
-import (
- "github.com/gogf/gf/container/gvar"
- "github.com/gogf/gf/util/gconv"
-)
-
-// GetPost retrieves and returns parameter from form and body.
-// It returns if does not exist in neither form nor body.
-// It returns nil if is not passed.
-//
-// Note that if there're multiple parameters with the same name, the parameters are retrieved
-// and overwrote in order of priority: form > body.
-//
-// Deprecated, use GetForm instead.
-func (r *Request) GetPost(key string, def ...interface{}) interface{} {
- r.parseForm()
- if len(r.formMap) > 0 {
- if v, ok := r.formMap[key]; ok {
- return v
- }
- }
- r.parseBody()
- if len(r.bodyMap) > 0 {
- if v, ok := r.bodyMap[key]; ok {
- return v
- }
- }
- if len(def) > 0 {
- return def[0]
- }
- return nil
-}
-
-// Deprecated, use GetFormVar instead.
-func (r *Request) GetPostVar(key string, def ...interface{}) *gvar.Var {
- return gvar.New(r.GetPost(key, def...))
-}
-
-// Deprecated, use GetFormString instead.
-func (r *Request) GetPostString(key string, def ...interface{}) string {
- return r.GetPostVar(key, def...).String()
-}
-
-// Deprecated, use GetFormBool instead.
-func (r *Request) GetPostBool(key string, def ...interface{}) bool {
- return r.GetPostVar(key, def...).Bool()
-}
-
-// Deprecated, use GetFormInt instead.
-func (r *Request) GetPostInt(key string, def ...interface{}) int {
- return r.GetPostVar(key, def...).Int()
-}
-
-// Deprecated, use GetFormInt32 instead.
-func (r *Request) GetPostInt32(key string, def ...interface{}) int32 {
- return r.GetPostVar(key, def...).Int32()
-}
-
-// Deprecated, use GetFormInt64 instead.
-func (r *Request) GetPostInt64(key string, def ...interface{}) int64 {
- return r.GetPostVar(key, def...).Int64()
-}
-
-// Deprecated, use GetFormInts instead.
-func (r *Request) GetPostInts(key string, def ...interface{}) []int {
- return r.GetPostVar(key, def...).Ints()
-}
-
-// Deprecated, use GetFormUint instead.
-func (r *Request) GetPostUint(key string, def ...interface{}) uint {
- return r.GetPostVar(key, def...).Uint()
-}
-
-// Deprecated, use GetFormUint32 instead.
-func (r *Request) GetPostUint32(key string, def ...interface{}) uint32 {
- return r.GetPostVar(key, def...).Uint32()
-}
-
-// Deprecated, use GetFormUint64 instead.
-func (r *Request) GetPostUint64(key string, def ...interface{}) uint64 {
- return r.GetPostVar(key, def...).Uint64()
-}
-
-// Deprecated, use GetFormFloat32 instead.
-func (r *Request) GetPostFloat32(key string, def ...interface{}) float32 {
- return r.GetPostVar(key, def...).Float32()
-}
-
-// Deprecated, use GetFormFloat64 instead.
-func (r *Request) GetPostFloat64(key string, def ...interface{}) float64 {
- return r.GetPostVar(key, def...).Float64()
-}
-
-// Deprecated, use GetFormFloats instead.
-func (r *Request) GetPostFloats(key string, def ...interface{}) []float64 {
- return r.GetPostVar(key, def...).Floats()
-}
-
-// Deprecated, use GetFormArray instead.
-func (r *Request) GetPostArray(key string, def ...interface{}) []string {
- return r.GetPostVar(key, def...).Strings()
-}
-
-// Deprecated, use GetFormStrings instead.
-func (r *Request) GetPostStrings(key string, def ...interface{}) []string {
- return r.GetPostVar(key, def...).Strings()
-}
-
-// Deprecated, use GetFormInterfaces instead.
-func (r *Request) GetPostInterfaces(key string, def ...interface{}) []interface{} {
- return r.GetPostVar(key, def...).Interfaces()
-}
-
-// GetPostMap retrieves and returns all parameters in the form and body passed from client
-// as map. The parameter specifies the keys retrieving from client parameters,
-// the associated values are the default values if the client does not pass.
-//
-// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
-// in order of priority: form > body.
-//
-// Deprecated.
-func (r *Request) GetPostMap(kvMap ...map[string]interface{}) map[string]interface{} {
- r.parseForm()
- r.parseBody()
- var ok, filter bool
- if len(kvMap) > 0 && kvMap[0] != nil {
- filter = true
- }
- m := make(map[string]interface{}, len(r.formMap)+len(r.bodyMap))
- for k, v := range r.bodyMap {
- if filter {
- if _, ok = kvMap[0][k]; !ok {
- continue
- }
- }
- m[k] = v
- }
- for k, v := range r.formMap {
- if filter {
- if _, ok = kvMap[0][k]; !ok {
- continue
- }
- }
- m[k] = v
- }
- // Check none exist parameters and assign it with default value.
- if filter {
- for k, v := range kvMap[0] {
- if _, ok = m[k]; !ok {
- m[k] = v
- }
- }
- }
- return m
-}
-
-// GetPostMapStrStr retrieves and returns all parameters in the form and body passed from client
-// as map[string]string. The parameter specifies the keys
-// retrieving from client parameters, the associated values are the default values if the client
-// does not pass.
-//
-// Deprecated.
-func (r *Request) GetPostMapStrStr(kvMap ...map[string]interface{}) map[string]string {
- postMap := r.GetPostMap(kvMap...)
- if len(postMap) > 0 {
- m := make(map[string]string, len(postMap))
- for k, v := range postMap {
- m[k] = gconv.String(v)
- }
- return m
- }
- return nil
-}
-
-// GetPostMapStrVar retrieves and returns all parameters in the form and body passed from client
-// as map[string]*gvar.Var. The parameter specifies the keys
-// retrieving from client parameters, the associated values are the default values if the client
-// does not pass.
-//
-// Deprecated.
-func (r *Request) GetPostMapStrVar(kvMap ...map[string]interface{}) map[string]*gvar.Var {
- postMap := r.GetPostMap(kvMap...)
- if len(postMap) > 0 {
- m := make(map[string]*gvar.Var, len(postMap))
- for k, v := range postMap {
- m[k] = gvar.New(v)
- }
- return m
- }
- return nil
-}
-
-// GetPostStruct retrieves all parameters in the form and body passed from client
-// and converts them to given struct object. Note that the parameter is a pointer
-// to the struct object. The optional parameter is used to specify the key to
-// attribute mapping.
-//
-// Deprecated.
-func (r *Request) GetPostStruct(pointer interface{}, mapping ...map[string]string) error {
- return gconv.Struct(r.GetPostMap(), pointer, mapping...)
-}
-
-// GetPostToStruct is alias of GetQueryStruct. See GetPostStruct.
-//
-// Deprecated.
-func (r *Request) GetPostToStruct(pointer interface{}, mapping ...map[string]string) error {
- return r.GetPostStruct(pointer, mapping...)
-}
diff --git a/net/ghttp/ghttp_request_param_query.go b/net/ghttp/ghttp_request_param_query.go
index b108b4b3c..13c8624dc 100644
--- a/net/ghttp/ghttp_request_param_query.go
+++ b/net/ghttp/ghttp_request_param_query.go
@@ -25,7 +25,7 @@ func (r *Request) SetQuery(key string, value interface{}) {
// and request body. It returns if does not exist in the query and is given,
// or else it returns nil.
//
-// Note that if there're multiple parameters with the same name, the parameters are retrieved
+// Note that if there are multiple parameters with the same name, the parameters are retrieved
// and overwrote in order of priority: query > body.
func (r *Request) GetQuery(key string, def ...interface{}) interface{} {
r.parseQuery()
@@ -116,7 +116,7 @@ func (r *Request) GetQueryInterfaces(key string, def ...interface{}) []interface
// as map. The parameter specifies the keys retrieving from client parameters,
// the associated values are the default values if the client does not pass.
//
-// Note that if there're multiple parameters with the same name, the parameters are retrieved and overwrote
+// Note that if there are multiple parameters with the same name, the parameters are retrieved and overwrote
// in order of priority: query > body.
func (r *Request) GetQueryMap(kvMap ...map[string]interface{}) map[string]interface{} {
r.parseQuery()
diff --git a/net/ghttp/ghttp_request_param_request.go b/net/ghttp/ghttp_request_param_request.go
index 2e62a1992..8b4cc13d8 100644
--- a/net/ghttp/ghttp_request_param_request.go
+++ b/net/ghttp/ghttp_request_param_request.go
@@ -20,7 +20,7 @@ import (
//
// GetRequest is one of the most commonly used functions for retrieving parameters.
//
-// Note that if there're multiple parameters with the same name, the parameters are
+// Note that if there are multiple parameters with the same name, the parameters are
// retrieved and overwrote in order of priority: router < query < body < form < custom.
func (r *Request) GetRequest(key string, def ...interface{}) interface{} {
value := r.GetParam(key)
@@ -167,7 +167,7 @@ func (r *Request) GetRequestInterfaces(key string, def ...interface{}) []interfa
//
// GetRequestMap is one of the most commonly used functions for retrieving parameters.
//
-// Note that if there're multiple parameters with the same name, the parameters are retrieved
+// Note that if there are multiple parameters with the same name, the parameters are retrieved
// and overwrote in order of priority: router < query < body < form < custom.
func (r *Request) GetRequestMap(kvMap ...map[string]interface{}) map[string]interface{} {
r.parseQuery()
diff --git a/net/ghttp/ghttp_response_view.go b/net/ghttp/ghttp_response_view.go
index 47da241dc..d8892b9a1 100644
--- a/net/ghttp/ghttp_response_view.go
+++ b/net/ghttp/ghttp_response_view.go
@@ -92,8 +92,8 @@ func (r *Response) buildInVars(params ...map[string]interface{}) map[string]inte
})
// Note that it should assign no Config variable to template
// if there's no configuration file.
- if c := gcfg.Instance(); c.Available() {
- m["Config"] = c.Map()
+ if v, _ := gcfg.Instance().Data(r.Request.Context()); len(v) > 0 {
+ m["Config"] = v
}
return m
}
diff --git a/net/ghttp/ghttp_server.go b/net/ghttp/ghttp_server.go
index 1b2eef058..7442eecd7 100644
--- a/net/ghttp/ghttp_server.go
+++ b/net/ghttp/ghttp_server.go
@@ -88,7 +88,7 @@ func serverProcessInit() {
// Note that the parameter should be unique for different servers. It returns an existing
// server instance if given is already existing in the server mapping.
func GetServer(name ...interface{}) *Server {
- serverName := defaultServerName
+ serverName := DefaultServerName
if len(name) > 0 && name[0] != "" {
serverName = gconv.String(name[0])
}
diff --git a/net/ghttp/ghttp_server_pprof.go b/net/ghttp/ghttp_server_pprof.go
index cef4f2d35..dcc0e93b3 100644
--- a/net/ghttp/ghttp_server_pprof.go
+++ b/net/ghttp/ghttp_server_pprof.go
@@ -32,7 +32,7 @@ func StartPProfServer(port int, pattern ...string) {
// EnablePProf enables PProf feature for server.
func (s *Server) EnablePProf(pattern ...string) {
- s.Domain(defaultDomainName).EnablePProf(pattern...)
+ s.Domain(DefaultDomainName).EnablePProf(pattern...)
}
// EnablePProf enables PProf feature for server of specified domain.
diff --git a/net/ghttp/ghttp_server_router.go b/net/ghttp/ghttp_server_router.go
index 83d061b5e..ac0261f82 100644
--- a/net/ghttp/ghttp_server_router.go
+++ b/net/ghttp/ghttp_server_router.go
@@ -39,7 +39,7 @@ func (s *Server) routerMapKey(hook, method, path, domain string) string {
// parsePattern parses the given pattern to domain, method and path variable.
func (s *Server) parsePattern(pattern string) (domain, method, path string, err error) {
path = strings.TrimSpace(pattern)
- domain = defaultDomainName
+ domain = DefaultDomainName
method = defaultMethod
if array, err := gregex.MatchString(`([a-zA-Z]+):(.+)`, pattern); len(array) > 1 && err == nil {
path = strings.TrimSpace(array[2])
diff --git a/net/ghttp/ghttp_server_router_serve.go b/net/ghttp/ghttp_server_router_serve.go
index 17fd011c1..9ca95702d 100644
--- a/net/ghttp/ghttp_server_router_serve.go
+++ b/net/ghttp/ghttp_server_router_serve.go
@@ -106,7 +106,7 @@ func (s *Server) searchHandlers(method, path, domain string) (parsedItems []*han
)
// Default domain has the most priority when iteration.
- for _, domain := range []string{defaultDomainName, domain} {
+ for _, domain := range []string{DefaultDomainName, domain} {
p, ok := s.serveTree[domain]
if !ok {
continue
diff --git a/net/ghttp/ghttp_server_status.go b/net/ghttp/ghttp_server_status.go
index 7cc627abd..a41776b40 100644
--- a/net/ghttp/ghttp_server_status.go
+++ b/net/ghttp/ghttp_server_status.go
@@ -12,7 +12,7 @@ import (
// getStatusHandler retrieves and returns the handler for given status code.
func (s *Server) getStatusHandler(status int, r *Request) []HandlerFunc {
- domains := []string{r.GetHost(), defaultDomainName}
+ domains := []string{r.GetHost(), DefaultDomainName}
for _, domain := range domains {
if f, ok := s.statusHandlerMap[s.statusHandlerKey(status, domain)]; ok {
return f
@@ -37,7 +37,7 @@ func (s *Server) statusHandlerKey(status int, domain string) string {
// BindStatusHandler registers handler for given status code.
func (s *Server) BindStatusHandler(status int, handler HandlerFunc) {
- s.addStatusHandler(s.statusHandlerKey(status, defaultDomainName), handler)
+ s.addStatusHandler(s.statusHandlerKey(status, DefaultDomainName), handler)
}
// BindStatusHandlerByMap registers handler for given status code using map.
diff --git a/net/ghttp/ghttp_unit_request_test.go b/net/ghttp/ghttp_unit_request_test.go
index 96ba9a375..cc8de827c 100644
--- a/net/ghttp/ghttp_unit_request_test.go
+++ b/net/ghttp/ghttp_unit_request_test.go
@@ -95,39 +95,7 @@ func Test_Params_Basic(t *testing.T) {
r.Response.Write(r.GetMapStrStr()["a"])
}
})
- // POST
- s.BindHandler("/post", func(r *ghttp.Request) {
- if r.GetPost("array") != nil {
- r.Response.Write(r.GetPost("array"))
- }
- if r.GetPost("slice") != nil {
- r.Response.Write(r.GetPost("slice"))
- }
- if r.GetPost("bool") != nil {
- r.Response.Write(r.GetPostBool("bool"))
- }
- if r.GetPost("float32") != nil {
- r.Response.Write(r.GetPostFloat32("float32"))
- }
- if r.GetPost("float64") != nil {
- r.Response.Write(r.GetPostFloat64("float64"))
- }
- if r.GetPost("int") != nil {
- r.Response.Write(r.GetPostInt("int"))
- }
- if r.GetPost("uint") != nil {
- r.Response.Write(r.GetPostUint("uint"))
- }
- if r.GetPost("string") != nil {
- r.Response.Write(r.GetPostString("string"))
- }
- if r.GetPost("map") != nil {
- r.Response.Write(r.GetPostMap()["map"].(map[string]interface{})["b"])
- }
- if r.GetPost("a") != nil {
- r.Response.Write(r.GetPostMapStrStr()["a"])
- }
- })
+
// DELETE
s.BindHandler("/delete", func(r *ghttp.Request) {
if r.Get("array") != nil {
@@ -330,21 +298,6 @@ func Test_Params_Basic(t *testing.T) {
t.Assert(client.PutContent("/put", "map[a]=1&map[b]=2"), `2`)
t.Assert(client.PutContent("/put", "a=1&b=2"), `1`)
- // POST
- t.Assert(client.PostContent("/post", "array[]=1&array[]=2"), `["1","2"]`)
- t.Assert(client.PostContent("/post", "slice=1&slice=2"), `2`)
- t.Assert(client.PostContent("/post", "bool=1"), `true`)
- t.Assert(client.PostContent("/post", "bool=0"), `false`)
- t.Assert(client.PostContent("/post", "float32=0.11"), `0.11`)
- t.Assert(client.PostContent("/post", "float64=0.22"), `0.22`)
- t.Assert(client.PostContent("/post", "int=-10000"), `-10000`)
- t.Assert(client.PostContent("/post", "int=10000"), `10000`)
- t.Assert(client.PostContent("/post", "uint=10000"), `10000`)
- t.Assert(client.PostContent("/post", "uint=9"), `9`)
- t.Assert(client.PostContent("/post", "string=key"), `key`)
- t.Assert(client.PostContent("/post", "map[a]=1&map[b]=2"), `2`)
- t.Assert(client.PostContent("/post", "a=1&b=2"), `1`)
-
// DELETE
t.Assert(client.DeleteContent("/delete", "array[]=1&array[]=2"), `["1","2"]`)
t.Assert(client.DeleteContent("/delete", "slice=1&slice=2"), `2`)
@@ -458,9 +411,6 @@ func Test_Params_Priority(t *testing.T) {
s.BindHandler("/query", func(r *ghttp.Request) {
r.Response.Write(r.GetQuery("a"))
})
- s.BindHandler("/post", func(r *ghttp.Request) {
- r.Response.Write(r.GetPost("a"))
- })
s.BindHandler("/form", func(r *ghttp.Request) {
r.Response.Write(r.GetForm("a"))
})
@@ -485,7 +435,6 @@ func Test_Params_Priority(t *testing.T) {
client.SetPrefix(prefix)
t.Assert(client.GetContent("/query?a=1", "a=100"), "100")
- t.Assert(client.PostContent("/post?a=1", "a=100"), "100")
t.Assert(client.PostContent("/form?a=1", "a=100"), "100")
t.Assert(client.PutContent("/form?a=1", "a=100"), "100")
t.Assert(client.GetContent("/request?a=1", "a=100"), "100")
diff --git a/net/ghttp/internal/client/client_tracing.go b/net/ghttp/internal/client/client_tracing.go
index 567ea6c14..138a71966 100644
--- a/net/ghttp/internal/client/client_tracing.go
+++ b/net/ghttp/internal/client/client_tracing.go
@@ -8,19 +8,21 @@ package client
import (
"fmt"
+ "io/ioutil"
+ "net/http"
+ "net/http/httptrace"
+
"github.com/gogf/gf"
"github.com/gogf/gf/internal/utils"
"github.com/gogf/gf/net/ghttp/internal/httputil"
"github.com/gogf/gf/net/gtrace"
"github.com/gogf/gf/text/gstr"
+ "github.com/gogf/gf/util/gconv"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/codes"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
- "io/ioutil"
- "net/http"
- "net/http/httptrace"
)
const (
@@ -70,7 +72,7 @@ func MiddlewareTracing(c *Client, r *http.Request) (response *Response, err erro
response.Body = utils.NewReadCloser(reqBodyContentBytes, false)
span.AddEvent(tracingEventHttpResponse, trace.WithAttributes(
- attribute.Any(tracingEventHttpResponseHeaders, httputil.HeaderToMap(response.Header)),
+ attribute.String(tracingEventHttpResponseHeaders, gconv.String(httputil.HeaderToMap(response.Header))),
attribute.String(tracingEventHttpResponseBody, gstr.StrLimit(
string(reqBodyContentBytes),
gtrace.MaxContentLogSize(),
diff --git a/net/ghttp/internal/client/client_tracing_tracer.go b/net/ghttp/internal/client/client_tracing_tracer.go
index ef4733f45..4cfcfd27b 100644
--- a/net/ghttp/internal/client/client_tracing_tracer.go
+++ b/net/ghttp/internal/client/client_tracing_tracer.go
@@ -10,18 +10,20 @@ import (
"context"
"crypto/tls"
"fmt"
- "github.com/gogf/gf/internal/utils"
- "github.com/gogf/gf/net/gtrace"
- "github.com/gogf/gf/text/gstr"
- "go.opentelemetry.io/otel/attribute"
- "go.opentelemetry.io/otel/codes"
- "go.opentelemetry.io/otel/trace"
"io/ioutil"
"net/http"
"net/http/httptrace"
"net/textproto"
"strings"
"sync"
+
+ "github.com/gogf/gf/internal/utils"
+ "github.com/gogf/gf/net/gtrace"
+ "github.com/gogf/gf/text/gstr"
+ "github.com/gogf/gf/util/gconv"
+ "go.opentelemetry.io/otel/attribute"
+ "go.opentelemetry.io/otel/codes"
+ "go.opentelemetry.io/otel/trace"
)
type clientTracer struct {
@@ -147,8 +149,8 @@ func (ct *clientTracer) wroteRequest(info httptrace.WroteRequestInfo) {
}
ct.span.AddEvent(tracingEventHttpRequest, trace.WithAttributes(
- attribute.Any(tracingEventHttpRequestHeaders, ct.headers),
- attribute.Any(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ct.Context)),
+ attribute.String(tracingEventHttpRequestHeaders, gconv.String(ct.headers)),
+ attribute.String(tracingEventHttpRequestBaggage, gtrace.GetBaggageMap(ct.Context).String()),
attribute.String(tracingEventHttpRequestBody, gstr.StrLimit(
string(ct.requestBody),
gtrace.MaxContentLogSize(),
diff --git a/net/gtrace/gtrace.go b/net/gtrace/gtrace.go
index 6d847474b..1325ddd32 100644
--- a/net/gtrace/gtrace.go
+++ b/net/gtrace/gtrace.go
@@ -9,6 +9,9 @@ package gtrace
import (
"context"
+ "os"
+ "strings"
+
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/container/gvar"
"github.com/gogf/gf/net/gipv4"
@@ -17,8 +20,6 @@ import (
"go.opentelemetry.io/otel/attribute"
"go.opentelemetry.io/otel/propagation"
"go.opentelemetry.io/otel/trace"
- "os"
- "strings"
)
const (
diff --git a/net/gtrace/gtrace_baggage.go b/net/gtrace/gtrace_baggage.go
index d04834645..1e9a89606 100644
--- a/net/gtrace/gtrace_baggage.go
+++ b/net/gtrace/gtrace_baggage.go
@@ -8,6 +8,7 @@ package gtrace
import (
"context"
+
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/container/gvar"
"github.com/gogf/gf/util/gconv"
diff --git a/net/gtrace/gtrace_carrier.go b/net/gtrace/gtrace_carrier.go
index 997f2ea91..4cce90236 100644
--- a/net/gtrace/gtrace_carrier.go
+++ b/net/gtrace/gtrace_carrier.go
@@ -14,12 +14,12 @@ import (
// Carrier is the storage medium used by a TextMapPropagator.
type Carrier map[string]interface{}
+// NewCarrier creates and returns a Carrier.
func NewCarrier(data ...map[string]interface{}) Carrier {
if len(data) > 0 && data[0] != nil {
return data[0]
- } else {
- return make(map[string]interface{})
}
+ return make(map[string]interface{})
}
// Get returns the value associated with the passed key.
@@ -41,6 +41,7 @@ func (c Carrier) Keys() []string {
return keys
}
+// MustMarshal .returns the JSON encoding of c
func (c Carrier) MustMarshal() []byte {
b, err := json.Marshal(c)
if err != nil {
@@ -49,10 +50,12 @@ func (c Carrier) MustMarshal() []byte {
return b
}
+// String converts and returns current Carrier as string.
func (c Carrier) String() string {
return string(c.MustMarshal())
}
+// UnmarshalJSON implements interface UnmarshalJSON for package json.
func (c Carrier) UnmarshalJSON(b []byte) error {
carrier := NewCarrier(nil)
return json.UnmarshalUseNumber(b, carrier)
diff --git a/net/gtrace/gtrace_span.go b/net/gtrace/gtrace_span.go
index 72f88c418..0d7fb240b 100644
--- a/net/gtrace/gtrace_span.go
+++ b/net/gtrace/gtrace_span.go
@@ -8,9 +8,11 @@ package gtrace
import (
"context"
+
"go.opentelemetry.io/otel/trace"
)
+// Span warps trace.Span for compatibility and extension.
type Span struct {
trace.Span
}
diff --git a/net/gtrace/gtrace_tracer.go b/net/gtrace/gtrace_tracer.go
index 8394fcebf..47d2baa72 100644
--- a/net/gtrace/gtrace_tracer.go
+++ b/net/gtrace/gtrace_tracer.go
@@ -11,11 +11,12 @@ import (
"go.opentelemetry.io/otel/trace"
)
+// Tracer warps trace.Tracer for compatibility and extension.
type Tracer struct {
trace.Tracer
}
-// Tracer is a short function for retrieving Tracer.
+// NewTracer Tracer is a short function for retrieving Tracer.
func NewTracer(name ...string) *Tracer {
tracerName := ""
if len(name) > 0 {
diff --git a/net/gtrace/gtrace_unit_carrier_test.go b/net/gtrace/gtrace_unit_carrier_test.go
index 095250c92..f5beceec9 100644
--- a/net/gtrace/gtrace_unit_carrier_test.go
+++ b/net/gtrace/gtrace_unit_carrier_test.go
@@ -8,12 +8,12 @@ package gtrace_test
import (
"context"
+ "testing"
+
"github.com/gogf/gf/net/gtrace"
"github.com/gogf/gf/test/gtest"
"go.opentelemetry.io/otel"
- "go.opentelemetry.io/otel/oteltest"
"go.opentelemetry.io/otel/trace"
- "testing"
)
const (
@@ -51,14 +51,15 @@ func TestNewCarrier(t *testing.T) {
SpanID: spanID,
TraceFlags: trace.FlagsSampled,
}))
- ctx, _ = oteltest.DefaultTracer().Start(ctx, "inject")
+
+ ctx, _ = otel.Tracer("").Start(ctx, "inject")
carrier1 := gtrace.NewCarrier()
otel.GetTextMapPropagator().Inject(ctx, carrier1)
- t.Assert(carrier1.String(), `{"traceparent":"00-4bf92f3577b34da6a3ce929d0e0e4736-0000000000000002-01"}`)
+ t.Assert(carrier1.String(), `{"traceparent":"00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"}`)
ctx = otel.GetTextMapPropagator().Extract(ctx, carrier1)
gotSc := trace.SpanContextFromContext(ctx)
t.Assert(gotSc.TraceID().String(), traceID.String())
- t.Assert(gotSc.SpanID().String(), "0000000000000002")
+ t.Assert(gotSc.SpanID().String(), "00f067aa0ba902b7")
})
}
diff --git a/os/gbuild/gbuild.go b/os/gbuild/gbuild.go
index c44cd57fa..01aca70cf 100644
--- a/os/gbuild/gbuild.go
+++ b/os/gbuild/gbuild.go
@@ -14,16 +14,16 @@ import (
"github.com/gogf/gf/encoding/gbase64"
"github.com/gogf/gf/internal/intlog"
"github.com/gogf/gf/internal/json"
- "github.com/gogf/gf/util/gconv"
"runtime"
)
var (
- builtInVarStr = "" // Raw variable base64 string.
+ builtInVarStr = "" // Raw variable base64 string, which is injected by go build flags.
builtInVarMap = map[string]interface{}{} // Binary custom variable map decoded.
)
func init() {
+ // The `builtInVarStr` is injected by go build flags.
if builtInVarStr != "" {
err := json.UnmarshalUseNumber(gbase64.MustDecodeString(builtInVarStr), &builtInVarMap)
if err != nil {
@@ -39,37 +39,27 @@ func init() {
// Info returns the basic built information of the binary as map.
// Note that it should be used with gf-cli tool "gf build",
-// which injects necessary information into the binary.
+// which automatically injects necessary information into the binary.
func Info() map[string]string {
return map[string]string{
- "gf": GetString("gfVersion"),
- "go": GetString("goVersion"),
- "git": GetString("builtGit"),
- "time": GetString("builtTime"),
+ "gf": Get("gfVersion").String(),
+ "go": Get("goVersion").String(),
+ "git": Get("builtGit").String(),
+ "time": Get("builtTime").String(),
}
}
// Get retrieves and returns the build-in binary variable with given name.
-func Get(name string, def ...interface{}) interface{} {
+func Get(name string, def ...interface{}) *gvar.Var {
if v, ok := builtInVarMap[name]; ok {
- return v
+ return gvar.New(v)
}
if len(def) > 0 {
- return def[0]
+ return gvar.New(def[0])
}
return nil
}
-// GetVar retrieves and returns the build-in binary variable of given name as gvar.Var.
-func GetVar(name string, def ...interface{}) *gvar.Var {
- return gvar.New(Get(name, def...))
-}
-
-// GetString retrieves and returns the build-in binary variable of given name as string.
-func GetString(name string, def ...interface{}) string {
- return gconv.String(Get(name, def...))
-}
-
// Map returns the custom build-in variable map.
func Map() map[string]interface{} {
return builtInVarMap
diff --git a/os/gbuild/gbuild_test.go b/os/gbuild/gbuild_test.go
new file mode 100644
index 000000000..e53bf3a21
--- /dev/null
+++ b/os/gbuild/gbuild_test.go
@@ -0,0 +1,39 @@
+// Copyright GoFrame 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 gbuild_test
+
+import (
+ "github.com/gogf/gf/os/gbuild"
+ "github.com/gogf/gf/test/gtest"
+ "testing"
+)
+
+func Test_Info(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gbuild.Info(), map[string]string{
+ "gf": "",
+ "go": "",
+ "git": "",
+ "time": "",
+ })
+ })
+}
+
+func Test_Get(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gbuild.Get(`none`), nil)
+ })
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gbuild.Get(`none`, 1), 1)
+ })
+}
+
+func Test_Map(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ t.Assert(gbuild.Map(), map[string]interface{}{})
+ })
+}
diff --git a/os/gcache/gcache_adapter.go b/os/gcache/gcache_adapter.go
index af2e23b17..e6553fed7 100644
--- a/os/gcache/gcache_adapter.go
+++ b/os/gcache/gcache_adapter.go
@@ -14,9 +14,7 @@ import (
// Adapter is the core adapter for cache features implements.
//
-// Note that the implements should guarantee the concurrent safety calling its functions.
-// You can implement one or more functions if necessary, it is suggested returning gcode.CodeNotImplemented error
-// for those unimplemented functions.
+// Note that the implementer itself should guarantee the concurrent safety of these functions.
type Adapter interface {
// Set sets cache with `key`-`value` pair, which is expired after `duration`.
//
diff --git a/os/gcache/gcache_adapter_memory.go b/os/gcache/gcache_adapter_memory.go
index 47ac9fae5..5d2e570a1 100644
--- a/os/gcache/gcache_adapter_memory.go
+++ b/os/gcache/gcache_adapter_memory.go
@@ -54,7 +54,7 @@ const (
)
// NewAdapterMemory creates and returns a new memory cache object.
-func NewAdapterMemory(lruCap ...int) Adapter {
+func NewAdapterMemory(lruCap ...int) *AdapterMemory {
c := &AdapterMemory{
data: newAdapterMemoryData(),
lruGetList: glist.New(true),
diff --git a/os/gcache/gcache_cache.go b/os/gcache/gcache_cache.go
index 66bc7a9f9..37f431224 100644
--- a/os/gcache/gcache_cache.go
+++ b/os/gcache/gcache_cache.go
@@ -30,7 +30,7 @@ func New(lruCap ...int) *Cache {
}
// Here may be a "timer leak" if adapter is manually changed from memory adapter.
// Do not worry about this, as adapter is less changed, and it does nothing if it's not used.
- gtimer.AddSingleton(time.Second, memAdapter.(*AdapterMemory).syncEventAndClearExpired)
+ gtimer.AddSingleton(time.Second, memAdapter.syncEventAndClearExpired)
return c
}
diff --git a/os/gcfg/gcfg.go b/os/gcfg/gcfg.go
index ec8bf5153..e522512a3 100644
--- a/os/gcfg/gcfg.go
+++ b/os/gcfg/gcfg.go
@@ -9,97 +9,141 @@ package gcfg
import (
"context"
- "github.com/gogf/gf/container/garray"
+ "fmt"
"github.com/gogf/gf/container/gmap"
+ "github.com/gogf/gf/container/gvar"
"github.com/gogf/gf/internal/intlog"
- "github.com/gogf/gf/os/gcmd"
)
-// Config is the configuration manager.
type Config struct {
- defaultName string // Default configuration file name.
- searchPaths *garray.StrArray // Searching path array.
- jsonMap *gmap.StrAnyMap // The pared JSON objects for configuration files.
- violenceCheck bool // Whether do violence check in value index searching. It affects the performance when set true(false in default).
+ adapter Adapter
+ dataMap *gmap.StrAnyMap
}
const (
- DefaultName = "config" // DefaultName is the default group name for instance usage.
- DefaultConfigFile = "config.toml" // DefaultConfigFile is the default configuration file name.
- commandEnvKeyForFile = "gf.gcfg.file" // commandEnvKeyForFile is the configuration key for command argument or environment configuring file name.
- commandEnvKeyForPath = "gf.gcfg.path" // commandEnvKeyForPath is the configuration key for command argument or environment configuring directory path.
- commandEnvKeyForErrorPrint = "gf.gcfg.errorprint" // commandEnvKeyForErrorPrint is used to specify the key controlling error printing to stdout.
+ DefaultName = "config" // DefaultName is the default group name for instance usage.
)
-var (
- supportedFileTypes = []string{"toml", "yaml", "yml", "json", "ini", "xml"} // All supported file types suffixes.
- resourceTryFiles = []string{"", "/", "config/", "config", "/config", "/config/"} // Prefix array for trying searching in resource manager.
- instances = gmap.NewStrAnyMap(true) // Instances map containing configuration instances.
- customConfigContentMap = gmap.NewStrStrMap(true) // Customized configuration content.
-)
-
-// SetContent sets customized configuration content for specified `file`.
-// The `file` is unnecessary param, default is DefaultConfigFile.
-func SetContent(content string, file ...string) {
- name := DefaultConfigFile
- if len(file) > 0 {
- name = file[0]
+// New creates and returns a Config object with default adapter of AdapterFile.
+func New() (*Config, error) {
+ adapterFile, err := NewAdapterFile()
+ if err != nil {
+ return nil, err
}
- // Clear file cache for instances which cached `name`.
- instances.LockFunc(func(m map[string]interface{}) {
- if customConfigContentMap.Contains(name) {
- for _, v := range m {
- v.(*Config).jsonMap.Remove(name)
+ return &Config{
+ adapter: adapterFile,
+ dataMap: gmap.NewStrAnyMap(true),
+ }, nil
+}
+
+// NewWithAdapter creates and returns a Config object with given adapter.
+func NewWithAdapter(adapter Adapter) *Config {
+ return &Config{
+ adapter: adapter,
+ dataMap: gmap.NewStrAnyMap(true),
+ }
+}
+
+// Instance returns an instance of Config with default settings.
+// The parameter `name` is the name for the instance. But very note that, if the file "name.toml"
+// exists in the configuration directory, it then sets it as the default configuration file. The
+// toml file type is the default configuration file type.
+func Instance(name ...string) *Config {
+ key := DefaultName
+ if len(name) > 0 && name[0] != "" {
+ key = name[0]
+ }
+ return localInstances.GetOrSetFuncLock(key, func() interface{} {
+ adapter, err := NewAdapterFile()
+ if err != nil {
+ intlog.Error(context.Background(), err)
+ return nil
+ }
+ // If it's not using default configuration or its configuration file is not available,
+ // it searches the possible configuration file according to the name and all supported
+ // file types.
+ if key != DefaultName || !adapter.Available() {
+ for _, fileType := range supportedFileTypes {
+ if file := fmt.Sprintf(`%s.%s`, key, fileType); adapter.Available(file) {
+ adapter.SetFileName(file)
+ break
+ }
}
}
- customConfigContentMap.Set(name, content)
- })
+ return NewWithAdapter(adapter)
+ }).(*Config)
}
-// GetContent returns customized configuration content for specified `file`.
-// The `file` is unnecessary param, default is DefaultConfigFile.
-func GetContent(file ...string) string {
- name := DefaultConfigFile
- if len(file) > 0 {
- name = file[0]
- }
- return customConfigContentMap.Get(name)
+// SetAdapter sets the adapter of current Config object.
+func (c *Config) SetAdapter(adapter Adapter) {
+ c.adapter = adapter
}
-// RemoveContent removes the global configuration with specified `file`.
-// If `name` is not passed, it removes configuration of the default group name.
-func RemoveContent(file ...string) {
- name := DefaultConfigFile
- if len(file) > 0 {
- name = file[0]
- }
- // Clear file cache for instances which cached `name`.
- instances.LockFunc(func(m map[string]interface{}) {
- if customConfigContentMap.Contains(name) {
- for _, v := range m {
- v.(*Config).jsonMap.Remove(name)
- }
- customConfigContentMap.Remove(name)
+// GetAdapter returns the adapter of current Config object.
+func (c *Config) GetAdapter() Adapter {
+ return c.adapter
+}
+
+// Set sets value with specified `pattern`.
+// It supports hierarchical data access by char separator, which is '.' in default.
+// It is commonly used for updates certain configuration value in runtime.
+func (c *Config) Set(ctx context.Context, pattern string, value interface{}) {
+ c.dataMap.Set(pattern, value)
+}
+
+// Get retrieves and returns value by specified `pattern`.
+// It returns all values of current Json object if `pattern` is given empty or string ".".
+// It returns nil if no value found by `pattern`.
+//
+// It returns a default value specified by `def` if value for `pattern` is not found.
+func (c *Config) Get(ctx context.Context, pattern string, def ...interface{}) (*gvar.Var, error) {
+ var (
+ err error
+ value interface{}
+ )
+ if value = c.dataMap.Get(pattern); value == nil {
+ value, err = c.adapter.Get(ctx, pattern)
+ if err != nil {
+ return nil, err
}
- })
-
- intlog.Printf(context.TODO(), `RemoveContent: %s`, name)
-}
-
-// ClearContent removes all global configuration contents.
-func ClearContent() {
- customConfigContentMap.Clear()
- // Clear cache for all instances.
- instances.LockFunc(func(m map[string]interface{}) {
- for _, v := range m {
- v.(*Config).jsonMap.Clear()
+ if value == nil && len(def) > 0 {
+ return gvar.New(def[0]), nil
}
+ }
+ return gvar.New(value), nil
+}
+
+// Data retrieves and returns all configuration data as map type.
+func (c *Config) Data(ctx context.Context) (data map[string]interface{}, err error) {
+ adapterData, err := c.adapter.Data(ctx)
+ if err != nil {
+ return nil, err
+ }
+ data = make(map[string]interface{})
+ for k, v := range adapterData {
+ data[k] = v
+ }
+ c.dataMap.Iterator(func(k string, v interface{}) bool {
+ data[k] = v
+ return true
})
-
- intlog.Print(context.TODO(), `RemoveConfig`)
+ return
}
-// errorPrint checks whether printing error to stdout.
-func errorPrint() bool {
- return gcmd.GetOptWithEnv(commandEnvKeyForErrorPrint, true).Bool()
+// MustGet acts as function Get, but it panics if error occurs.
+func (c *Config) MustGet(ctx context.Context, pattern string, def ...interface{}) *gvar.Var {
+ v, err := c.Get(ctx, pattern, def...)
+ if err != nil {
+ panic(err)
+ }
+ return gvar.New(v)
+}
+
+// MustData acts as function Data, but it panics if error occurs.
+func (c *Config) MustData(ctx context.Context) map[string]interface{} {
+ v, err := c.Data(ctx)
+ if err != nil {
+ panic(err)
+ }
+ return v
}
diff --git a/os/gcfg/gcfg_adaper.go b/os/gcfg/gcfg_adaper.go
new file mode 100644
index 000000000..3d37d3edd
--- /dev/null
+++ b/os/gcfg/gcfg_adaper.go
@@ -0,0 +1,20 @@
+// Copyright GoFrame 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 gcfg
+
+import "context"
+
+// Adapter is the interface for configuration retrieving.
+type Adapter interface {
+ // Get retrieves and returns value by specified `pattern`.
+ Get(ctx context.Context, pattern string) (value interface{}, err error)
+
+ // Data retrieves and returns all configuration data as map type.
+ // Note that this function may lead lots of memory usage if configuration data is too large,
+ // you can implement this function if necessary.
+ Data(ctx context.Context) (data map[string]interface{}, err error)
+}
diff --git a/os/gcfg/gcfg_adapter_file.go b/os/gcfg/gcfg_adapter_file.go
new file mode 100644
index 000000000..96ba02f76
--- /dev/null
+++ b/os/gcfg/gcfg_adapter_file.go
@@ -0,0 +1,275 @@
+// Copyright GoFrame 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 gcfg
+
+import (
+ "context"
+ "github.com/gogf/gf/container/garray"
+ "github.com/gogf/gf/container/gmap"
+ "github.com/gogf/gf/container/gvar"
+ "github.com/gogf/gf/encoding/gjson"
+ "github.com/gogf/gf/errors/gcode"
+ "github.com/gogf/gf/errors/gerror"
+ "github.com/gogf/gf/internal/intlog"
+ "github.com/gogf/gf/os/gcmd"
+ "github.com/gogf/gf/os/gfile"
+ "github.com/gogf/gf/os/gfsnotify"
+ "github.com/gogf/gf/os/gres"
+ "github.com/gogf/gf/util/gmode"
+)
+
+type AdapterFile struct {
+ defaultName string // Default configuration file name.
+ searchPaths *garray.StrArray // Searching path array.
+ jsonMap *gmap.StrAnyMap // The pared JSON objects for configuration files.
+ violenceCheck bool // Whether it does violence check in value index searching. It affects the performance when set true(false in default).
+}
+
+const (
+ DefaultConfigFile = "config.toml" // DefaultConfigFile is the default configuration file name.
+ commandEnvKeyForFile = "gf.gcfg.file" // commandEnvKeyForFile is the configuration key for command argument or environment configuring file name.
+ commandEnvKeyForPath = "gf.gcfg.path" // commandEnvKeyForPath is the configuration key for command argument or environment configuring directory path.
+)
+
+var (
+ supportedFileTypes = []string{"toml", "yaml", "yml", "json", "ini", "xml"} // All supported file types suffixes.
+ resourceTryFiles = []string{"", "/", "config/", "config", "/config", "/config/"} // Prefix array for trying searching in resource manager.
+ localInstances = gmap.NewStrAnyMap(true) // Instances map containing configuration instances.
+ customConfigContentMap = gmap.NewStrStrMap(true) // Customized configuration content.
+)
+
+// NewAdapterFile returns a new configuration management object.
+// The parameter `file` specifies the default configuration file name for reading.
+func NewAdapterFile(file ...string) (*AdapterFile, error) {
+ var (
+ err error
+ name = DefaultConfigFile
+ )
+ if len(file) > 0 {
+ name = file[0]
+ } else {
+ // Custom default configuration file name from command line or environment.
+ if customFile := gcmd.GetOptWithEnv(commandEnvKeyForFile).String(); customFile != "" {
+ name = customFile
+ }
+ }
+ c := &AdapterFile{
+ defaultName: name,
+ searchPaths: garray.NewStrArray(true),
+ jsonMap: gmap.NewStrAnyMap(true),
+ }
+ // Customized dir path from env/cmd.
+ if customPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); customPath != "" {
+ if gfile.Exists(customPath) {
+ if err = c.SetPath(customPath); err != nil {
+ return nil, err
+ }
+ } else {
+ return nil, gerror.Newf(`configuration directory path "%s" does not exist`, customPath)
+ }
+ } else {
+ // ================================================================================
+ // Automatic searching directories.
+ // It does not affect adapter object cresting if these directories do not exist.
+ // ================================================================================
+
+ // Dir path of working dir.
+ if err := c.AddPath(gfile.Pwd()); err != nil {
+ intlog.Error(context.TODO(), err)
+ }
+
+ // Dir path of main package.
+ if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) {
+ if err := c.AddPath(mainPath); err != nil {
+ intlog.Error(context.TODO(), err)
+ }
+ }
+
+ // Dir path of binary.
+ if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) {
+ if err := c.AddPath(selfPath); err != nil {
+ intlog.Error(context.TODO(), err)
+ }
+ }
+ }
+ return c, nil
+}
+
+// SetViolenceCheck sets whether to perform hierarchical conflict checking.
+// This feature needs to be enabled when there is a level symbol in the key name.
+// It is off in default.
+//
+// Note that, turning on this feature is quite expensive, and it is not recommended
+// allowing separators in the key names. It is best to avoid this on the application side.
+func (c *AdapterFile) SetViolenceCheck(check bool) {
+ c.violenceCheck = check
+ c.Clear()
+}
+
+// SetFileName sets the default configuration file name.
+func (c *AdapterFile) SetFileName(name string) {
+ c.defaultName = name
+}
+
+// GetFileName returns the default configuration file name.
+func (c *AdapterFile) GetFileName() string {
+ return c.defaultName
+}
+
+// Get retrieves and returns value by specified `pattern`.
+// It returns all values of current Json object if `pattern` is given empty or string ".".
+// It returns nil if no value found by `pattern`.
+//
+// We can also access slice item by its index number in `pattern` like:
+// "list.10", "array.0.name", "array.0.1.id".
+//
+// It returns a default value specified by `def` if value for `pattern` is not found.
+func (c *AdapterFile) Get(ctx context.Context, pattern string) (value interface{}, err error) {
+ j, err := c.getJson()
+ if err != nil {
+ return nil, err
+ }
+ if j != nil {
+ return j.Get(pattern), nil
+ }
+ return nil, nil
+}
+
+// Data retrieves and returns all configuration data as map type.
+func (c *AdapterFile) Data(ctx context.Context) (data map[string]interface{}, err error) {
+ j, err := c.getJson()
+ if err != nil {
+ return nil, err
+ }
+ if j != nil {
+ return j.GetVar(".").Map(), nil
+ }
+ return nil, nil
+}
+
+// MustGet acts as function Get, but it panics if error occurs.
+func (c *AdapterFile) MustGet(ctx context.Context, pattern string) *gvar.Var {
+ v, err := c.Get(ctx, pattern)
+ if err != nil {
+ panic(err)
+ }
+ return gvar.New(v)
+}
+
+// Clear removes all parsed configuration files content cache,
+// which will force reload configuration content from file.
+func (c *AdapterFile) Clear() {
+ c.jsonMap.Clear()
+}
+
+// Dump prints current Json object with more manually readable.
+func (c *AdapterFile) Dump() {
+ if j, _ := c.getJson(); j != nil {
+ j.Dump()
+ }
+}
+
+// Available checks and returns whether configuration of given `file` is available.
+func (c *AdapterFile) Available(fileName ...string) bool {
+ var (
+ usedFileName string
+ )
+ if len(fileName) > 0 && fileName[0] != "" {
+ usedFileName = fileName[0]
+ } else {
+ usedFileName = c.defaultName
+ }
+ if path, _ := c.GetFilePath(usedFileName); path != "" {
+ return true
+ }
+ if c.GetContent(usedFileName) != "" {
+ return true
+ }
+ return false
+}
+
+// autoCheckAndAddMainPkgPathToSearchPaths automatically checks and adds directory path of package main
+// to the searching path list if it's currently in development environment.
+func (c *AdapterFile) autoCheckAndAddMainPkgPathToSearchPaths() {
+ if gmode.IsDevelop() {
+ mainPkgPath := gfile.MainPkgPath()
+ if mainPkgPath != "" {
+ if !c.searchPaths.Contains(mainPkgPath) {
+ c.searchPaths.Append(mainPkgPath)
+ }
+ }
+ }
+}
+
+// getJson returns a *gjson.Json object for the specified `file` content.
+// It would print error if file reading fails. It returns nil if any error occurs.
+func (c *AdapterFile) getJson(fileName ...string) (configJson *gjson.Json, err error) {
+ var (
+ usedFileName = c.defaultName
+ )
+ if len(fileName) > 0 && fileName[0] != "" {
+ usedFileName = fileName[0]
+ } else {
+ usedFileName = c.defaultName
+ }
+ result := c.jsonMap.GetOrSetFuncLock(usedFileName, func() interface{} {
+ var (
+ content string
+ filePath string
+ )
+ // The configured content can be any kind of data type different from its file type.
+ isFromConfigContent := true
+ if content = c.GetContent(usedFileName); content == "" {
+ isFromConfigContent = false
+ filePath, err = c.GetFilePath(usedFileName)
+ if err != nil {
+ return nil
+ }
+ if filePath == "" {
+ return nil
+ }
+ if file := gres.Get(filePath); file != nil {
+ content = string(file.Content())
+ } else {
+ content = gfile.GetContents(filePath)
+ }
+ }
+ // Note that the underlying configuration json object operations are concurrent safe.
+ dataType := gfile.ExtName(usedFileName)
+ if gjson.IsValidDataType(dataType) && !isFromConfigContent {
+ configJson, err = gjson.LoadContentType(dataType, content, true)
+ } else {
+ configJson, err = gjson.LoadContent(content, true)
+ }
+ if err == nil {
+ configJson.SetViolenceCheck(c.violenceCheck)
+ // Add monitor for this configuration file,
+ // any changes of this file will refresh its cache in Config object.
+ if filePath != "" && !gres.Contains(filePath) {
+ _, err = gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
+ c.jsonMap.Remove(usedFileName)
+ })
+ if err != nil {
+ return nil
+ }
+ }
+ return configJson
+ }
+ if err != nil {
+ if filePath != "" {
+ err = gerror.WrapCodef(gcode.CodeOperationFailed, err, `load config file "%s" failed`, filePath)
+ } else {
+ err = gerror.WrapCode(gcode.CodeOperationFailed, err, `load configuration failed`)
+ }
+ }
+ return nil
+ })
+ if result != nil {
+ return result.(*gjson.Json), err
+ }
+ return
+}
diff --git a/os/gcfg/gcfg_adapter_file_content.go b/os/gcfg/gcfg_adapter_file_content.go
new file mode 100644
index 000000000..2d6d4fd5c
--- /dev/null
+++ b/os/gcfg/gcfg_adapter_file_content.go
@@ -0,0 +1,84 @@
+// Copyright GoFrame 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 gcfg
+
+import (
+ "context"
+ "github.com/gogf/gf/internal/intlog"
+)
+
+// SetContent sets customized configuration content for specified `file`.
+// The `file` is unnecessary param, default is DefaultConfigFile.
+func (c *AdapterFile) SetContent(content string, file ...string) {
+ name := DefaultConfigFile
+ if len(file) > 0 {
+ name = file[0]
+ }
+ // Clear file cache for instances which cached `name`.
+ localInstances.LockFunc(func(m map[string]interface{}) {
+ if customConfigContentMap.Contains(name) {
+ for _, v := range m {
+ if configInstance, ok := v.(*Config); ok {
+ if fileConfig, ok := configInstance.GetAdapter().(*AdapterFile); ok {
+ fileConfig.jsonMap.Remove(name)
+ }
+ }
+ }
+ }
+ customConfigContentMap.Set(name, content)
+ })
+}
+
+// GetContent returns customized configuration content for specified `file`.
+// The `file` is unnecessary param, default is DefaultConfigFile.
+func (c *AdapterFile) GetContent(file ...string) string {
+ name := DefaultConfigFile
+ if len(file) > 0 {
+ name = file[0]
+ }
+ return customConfigContentMap.Get(name)
+}
+
+// RemoveContent removes the global configuration with specified `file`.
+// If `name` is not passed, it removes configuration of the default group name.
+func (c *AdapterFile) RemoveContent(file ...string) {
+ name := DefaultConfigFile
+ if len(file) > 0 {
+ name = file[0]
+ }
+ // Clear file cache for instances which cached `name`.
+ localInstances.LockFunc(func(m map[string]interface{}) {
+ if customConfigContentMap.Contains(name) {
+ for _, v := range m {
+ if configInstance, ok := v.(*Config); ok {
+ if fileConfig, ok := configInstance.GetAdapter().(*AdapterFile); ok {
+ fileConfig.jsonMap.Remove(name)
+ }
+ }
+ }
+ customConfigContentMap.Remove(name)
+ }
+ })
+
+ intlog.Printf(context.TODO(), `RemoveContent: %s`, name)
+}
+
+// ClearContent removes all global configuration contents.
+func (c *AdapterFile) ClearContent() {
+ customConfigContentMap.Clear()
+ // Clear cache for all instances.
+ localInstances.LockFunc(func(m map[string]interface{}) {
+ for _, v := range m {
+ if configInstance, ok := v.(*Config); ok {
+ if fileConfig, ok := configInstance.GetAdapter().(*AdapterFile); ok {
+ fileConfig.jsonMap.Clear()
+ }
+ }
+ }
+ })
+ intlog.Print(context.TODO(), `RemoveConfig`)
+}
diff --git a/os/gcfg/gcfg_adapter_file_path.go b/os/gcfg/gcfg_adapter_file_path.go
new file mode 100644
index 000000000..486a27a78
--- /dev/null
+++ b/os/gcfg/gcfg_adapter_file_path.go
@@ -0,0 +1,208 @@
+// Copyright GoFrame 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 gcfg
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+ "github.com/gogf/gf/errors/gcode"
+ "github.com/gogf/gf/errors/gerror"
+ "github.com/gogf/gf/internal/intlog"
+ "github.com/gogf/gf/os/gfile"
+ "github.com/gogf/gf/os/gres"
+ "github.com/gogf/gf/os/gspath"
+ "github.com/gogf/gf/text/gstr"
+)
+
+// SetPath sets the configuration directory path for file search.
+// The parameter `path` can be absolute or relative path,
+// but absolute path is strongly recommended.
+func (c *AdapterFile) SetPath(path string) (err error) {
+ var (
+ isDir = false
+ realPath = ""
+ )
+ if file := gres.Get(path); file != nil {
+ realPath = path
+ isDir = file.FileInfo().IsDir()
+ } else {
+ // Absolute path.
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ // Relative path.
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, v := range array {
+ if path, _ := gspath.Search(v, path); path != "" {
+ realPath = path
+ break
+ }
+ }
+ })
+ }
+ if realPath != "" {
+ isDir = gfile.IsDir(realPath)
+ }
+ }
+ // Path not exist.
+ if realPath == "" {
+ buffer := bytes.NewBuffer(nil)
+ if c.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf(`SetPath failed: cannot find directory "%s" in following paths:`, path))
+ c.searchPaths.RLockFunc(func(array []string) {
+ for k, v := range array {
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf(`SetPath failed: path "%s" does not exist`, path))
+ }
+ return gerror.NewCode(gcode.CodeOperationFailed, buffer.String())
+ }
+ // Should be a directory.
+ if !isDir {
+ return gerror.NewCodef(
+ gcode.CodeInvalidParameter,
+ `SetPath failed: path "%s" should be directory type`,
+ path,
+ )
+ }
+ // Repeated path check.
+ if c.searchPaths.Search(realPath) != -1 {
+ return nil
+ }
+ c.jsonMap.Clear()
+ c.searchPaths.Clear()
+ c.searchPaths.Append(realPath)
+ intlog.Print(context.TODO(), "SetPath:", realPath)
+ return nil
+}
+
+// AddPath adds an absolute or relative path to the search paths.
+func (c *AdapterFile) AddPath(path string) (err error) {
+ var (
+ isDir = false
+ realPath = ""
+ )
+ // It firstly checks the resource manager,
+ // and then checks the filesystem for the path.
+ if file := gres.Get(path); file != nil {
+ realPath = path
+ isDir = file.FileInfo().IsDir()
+ } else {
+ // Absolute path.
+ realPath = gfile.RealPath(path)
+ if realPath == "" {
+ // Relative path.
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, v := range array {
+ if path, _ := gspath.Search(v, path); path != "" {
+ realPath = path
+ break
+ }
+ }
+ })
+ }
+ if realPath != "" {
+ isDir = gfile.IsDir(realPath)
+ }
+ }
+ if realPath == "" {
+ buffer := bytes.NewBuffer(nil)
+ if c.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf(`AddPath failed: cannot find directory "%s" in following paths:`, path))
+ c.searchPaths.RLockFunc(func(array []string) {
+ for k, v := range array {
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf(`AddPath failed: path "%s" does not exist`, path))
+ }
+ return gerror.NewCode(gcode.CodeOperationFailed, buffer.String())
+ }
+ if !isDir {
+ return gerror.NewCodef(gcode.CodeInvalidParameter, `AddPath failed: path "%s" should be directory type`, path)
+ }
+ // Repeated path check.
+ if c.searchPaths.Search(realPath) != -1 {
+ return nil
+ }
+ c.searchPaths.Append(realPath)
+ intlog.Print(context.TODO(), "AddPath:", realPath)
+ return nil
+}
+
+// GetFilePath returns the absolute configuration file path for the given filename by `file`.
+// If `file` is not passed, it returns the configuration file path of the default name.
+// It returns an empty `path` string and an error if the given `file` does not exist.
+func (c *AdapterFile) GetFilePath(fileName ...string) (path string, err error) {
+ var (
+ usedFileName = c.defaultName
+ )
+ if len(fileName) > 0 {
+ usedFileName = fileName[0]
+ }
+ // Searching resource manager.
+ if !gres.IsEmpty() {
+ for _, v := range resourceTryFiles {
+ if file := gres.Get(v + usedFileName); file != nil {
+ path = file.Name()
+ return
+ }
+ }
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, prefix := range array {
+ for _, v := range resourceTryFiles {
+ if file := gres.Get(prefix + v + usedFileName); file != nil {
+ path = file.Name()
+ return
+ }
+ }
+ }
+ })
+ }
+ c.autoCheckAndAddMainPkgPathToSearchPaths()
+ // Searching the file system.
+ c.searchPaths.RLockFunc(func(array []string) {
+ for _, prefix := range array {
+ prefix = gstr.TrimRight(prefix, `\/`)
+ if path, _ = gspath.Search(prefix, usedFileName); path != "" {
+ return
+ }
+ if path, _ = gspath.Search(prefix+gfile.Separator+"config", usedFileName); path != "" {
+ return
+ }
+ }
+ })
+ // If it cannot find the path of `file`, it formats and returns a detailed error.
+ if path == "" {
+ var (
+ buffer = bytes.NewBuffer(nil)
+ )
+ if c.searchPaths.Len() > 0 {
+ buffer.WriteString(fmt.Sprintf(
+ `config file "%s" not found in resource manager or the following system searching paths:`,
+ usedFileName,
+ ))
+ c.searchPaths.RLockFunc(func(array []string) {
+ index := 1
+ for _, v := range array {
+ v = gstr.TrimRight(v, `\/`)
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v))
+ index++
+ buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v+gfile.Separator+"config"))
+ index++
+ }
+ })
+ } else {
+ buffer.WriteString(fmt.Sprintf(`cannot find config file "%s" with no path configured`, usedFileName))
+ }
+ err = gerror.NewCode(gcode.CodeOperationFailed, buffer.String())
+ }
+ return
+}
diff --git a/os/gcfg/gcfg_config.go b/os/gcfg/gcfg_config.go
deleted file mode 100644
index 14fc71f4a..000000000
--- a/os/gcfg/gcfg_config.go
+++ /dev/null
@@ -1,424 +0,0 @@
-// Copyright GoFrame 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 gcfg
-
-import (
- "bytes"
- "context"
- "fmt"
- "github.com/gogf/gf/container/garray"
- "github.com/gogf/gf/container/gmap"
- "github.com/gogf/gf/encoding/gjson"
- "github.com/gogf/gf/errors/gcode"
- "github.com/gogf/gf/errors/gerror"
- "github.com/gogf/gf/internal/intlog"
- "github.com/gogf/gf/os/gcmd"
- "github.com/gogf/gf/os/gfile"
- "github.com/gogf/gf/os/gfsnotify"
- "github.com/gogf/gf/os/glog"
- "github.com/gogf/gf/os/gres"
- "github.com/gogf/gf/os/gspath"
- "github.com/gogf/gf/text/gstr"
- "github.com/gogf/gf/util/gmode"
-)
-
-// New returns a new configuration management object.
-// The parameter `file` specifies the default configuration file name for reading.
-func New(file ...string) *Config {
- name := DefaultConfigFile
- if len(file) > 0 {
- name = file[0]
- } else {
- // Custom default configuration file name from command line or environment.
- if customFile := gcmd.GetOptWithEnv(commandEnvKeyForFile).String(); customFile != "" {
- name = customFile
- }
- }
- c := &Config{
- defaultName: name,
- searchPaths: garray.NewStrArray(true),
- jsonMap: gmap.NewStrAnyMap(true),
- }
- // Customized dir path from env/cmd.
- if customPath := gcmd.GetOptWithEnv(commandEnvKeyForPath).String(); customPath != "" {
- if gfile.Exists(customPath) {
- _ = c.SetPath(customPath)
- } else {
- if errorPrint() {
- glog.Errorf("[gcfg] Configuration directory path does not exist: %s", customPath)
- }
- }
- } else {
- // Dir path of working dir.
- if err := c.AddPath(gfile.Pwd()); err != nil {
- intlog.Error(context.TODO(), err)
- }
-
- // Dir path of main package.
- if mainPath := gfile.MainPkgPath(); mainPath != "" && gfile.Exists(mainPath) {
- if err := c.AddPath(mainPath); err != nil {
- intlog.Error(context.TODO(), err)
- }
- }
-
- // Dir path of binary.
- if selfPath := gfile.SelfDir(); selfPath != "" && gfile.Exists(selfPath) {
- if err := c.AddPath(selfPath); err != nil {
- intlog.Error(context.TODO(), err)
- }
- }
- }
- return c
-}
-
-// Instance returns an instance of Config with default settings.
-// The parameter `name` is the name for the instance. But very note that, if the file "name.toml"
-// exists in the configuration directory, it then sets it as the default configuration file. The
-// toml file type is the default configuration file type.
-func Instance(name ...string) *Config {
- key := DefaultName
- if len(name) > 0 && name[0] != "" {
- key = name[0]
- }
- return instances.GetOrSetFuncLock(key, func() interface{} {
- c := New()
- // If it's not using default configuration or its configuration file is not available,
- // it searches the possible configuration file according to the name and all supported
- // file types.
- if key != DefaultName || !c.Available() {
- for _, fileType := range supportedFileTypes {
- if file := fmt.Sprintf(`%s.%s`, key, fileType); c.Available(file) {
- c.SetFileName(file)
- break
- }
- }
- }
- return c
- }).(*Config)
-}
-
-// SetPath sets the configuration directory path for file search.
-// The parameter `path` can be absolute or relative path,
-// but absolute path is strongly recommended.
-func (c *Config) SetPath(path string) error {
- var (
- isDir = false
- realPath = ""
- )
- if file := gres.Get(path); file != nil {
- realPath = path
- isDir = file.FileInfo().IsDir()
- } else {
- // Absolute path.
- realPath = gfile.RealPath(path)
- if realPath == "" {
- // Relative path.
- c.searchPaths.RLockFunc(func(array []string) {
- for _, v := range array {
- if path, _ := gspath.Search(v, path); path != "" {
- realPath = path
- break
- }
- }
- })
- }
- if realPath != "" {
- isDir = gfile.IsDir(realPath)
- }
- }
- // Path not exist.
- if realPath == "" {
- buffer := bytes.NewBuffer(nil)
- if c.searchPaths.Len() > 0 {
- buffer.WriteString(fmt.Sprintf("[gcfg] SetPath failed: cannot find directory \"%s\" in following paths:", path))
- c.searchPaths.RLockFunc(func(array []string) {
- for k, v := range array {
- buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
- }
- })
- } else {
- buffer.WriteString(fmt.Sprintf(`[gcfg] SetPath failed: path "%s" does not exist`, path))
- }
- err := gerror.NewCode(gcode.CodeOperationFailed, buffer.String())
- if errorPrint() {
- glog.Error(err)
- }
- return err
- }
- // Should be a directory.
- if !isDir {
- err := gerror.NewCodef(
- gcode.CodeInvalidParameter,
- `[gcfg] SetPath failed: path "%s" should be directory type`,
- path,
- )
- if errorPrint() {
- glog.Error(err)
- }
- return err
- }
- // Repeated path check.
- if c.searchPaths.Search(realPath) != -1 {
- return nil
- }
- c.jsonMap.Clear()
- c.searchPaths.Clear()
- c.searchPaths.Append(realPath)
- intlog.Print(context.TODO(), "SetPath:", realPath)
- return nil
-}
-
-// SetViolenceCheck sets whether to perform hierarchical conflict checking.
-// This feature needs to be enabled when there is a level symbol in the key name.
-// It is off in default.
-//
-// Note that, turning on this feature is quite expensive, and it is not recommended
-// allowing separators in the key names. It is best to avoid this on the application side.
-func (c *Config) SetViolenceCheck(check bool) {
- c.violenceCheck = check
- c.Clear()
-}
-
-// AddPath adds an absolute or relative path to the search paths.
-func (c *Config) AddPath(path string) error {
- var (
- isDir = false
- realPath = ""
- )
- // It firstly checks the resource manager,
- // and then checks the filesystem for the path.
- if file := gres.Get(path); file != nil {
- realPath = path
- isDir = file.FileInfo().IsDir()
- } else {
- // Absolute path.
- realPath = gfile.RealPath(path)
- if realPath == "" {
- // Relative path.
- c.searchPaths.RLockFunc(func(array []string) {
- for _, v := range array {
- if path, _ := gspath.Search(v, path); path != "" {
- realPath = path
- break
- }
- }
- })
- }
- if realPath != "" {
- isDir = gfile.IsDir(realPath)
- }
- }
- if realPath == "" {
- buffer := bytes.NewBuffer(nil)
- if c.searchPaths.Len() > 0 {
- buffer.WriteString(fmt.Sprintf("[gcfg] AddPath failed: cannot find directory \"%s\" in following paths:", path))
- c.searchPaths.RLockFunc(func(array []string) {
- for k, v := range array {
- buffer.WriteString(fmt.Sprintf("\n%d. %s", k+1, v))
- }
- })
- } else {
- buffer.WriteString(fmt.Sprintf(`[gcfg] AddPath failed: path "%s" does not exist`, path))
- }
- err := gerror.NewCode(gcode.CodeOperationFailed, buffer.String())
- if errorPrint() {
- glog.Error(err)
- }
- return err
- }
- if !isDir {
- err := gerror.NewCodef(gcode.CodeInvalidParameter, `[gcfg] AddPath failed: path "%s" should be directory type`, path)
- if errorPrint() {
- glog.Error(err)
- }
- return err
- }
- // Repeated path check.
- if c.searchPaths.Search(realPath) != -1 {
- return nil
- }
- c.searchPaths.Append(realPath)
- intlog.Print(context.TODO(), "AddPath:", realPath)
- return nil
-}
-
-// SetFileName sets the default configuration file name.
-func (c *Config) SetFileName(name string) *Config {
- c.defaultName = name
- return c
-}
-
-// GetFileName returns the default configuration file name.
-func (c *Config) GetFileName() string {
- return c.defaultName
-}
-
-// Available checks and returns whether configuration of given `file` is available.
-func (c *Config) Available(file ...string) bool {
- var name string
- if len(file) > 0 && file[0] != "" {
- name = file[0]
- } else {
- name = c.defaultName
- }
- if path, _ := c.GetFilePath(name); path != "" {
- return true
- }
- if GetContent(name) != "" {
- return true
- }
- return false
-}
-
-// GetFilePath returns the absolute configuration file path for the given filename by `file`.
-// If `file` is not passed, it returns the configuration file path of the default name.
-// It returns an empty `path` string and an error if the given `file` does not exist.
-func (c *Config) GetFilePath(file ...string) (path string, err error) {
- name := c.defaultName
- if len(file) > 0 {
- name = file[0]
- }
- // Searching resource manager.
- if !gres.IsEmpty() {
- for _, v := range resourceTryFiles {
- if file := gres.Get(v + name); file != nil {
- path = file.Name()
- return
- }
- }
- c.searchPaths.RLockFunc(func(array []string) {
- for _, prefix := range array {
- for _, v := range resourceTryFiles {
- if file := gres.Get(prefix + v + name); file != nil {
- path = file.Name()
- return
- }
- }
- }
- })
- }
- c.autoCheckAndAddMainPkgPathToSearchPaths()
- // Searching the file system.
- c.searchPaths.RLockFunc(func(array []string) {
- for _, prefix := range array {
- prefix = gstr.TrimRight(prefix, `\/`)
- if path, _ = gspath.Search(prefix, name); path != "" {
- return
- }
- if path, _ = gspath.Search(prefix+gfile.Separator+"config", name); path != "" {
- return
- }
- }
- })
- // If it cannot find the path of `file`, it formats and returns a detailed error.
- if path == "" {
- var (
- buffer = bytes.NewBuffer(nil)
- )
- if c.searchPaths.Len() > 0 {
- buffer.WriteString(fmt.Sprintf(`[gcfg] cannot find config file "%s" in resource manager or the following paths:`, name))
- c.searchPaths.RLockFunc(func(array []string) {
- index := 1
- for _, v := range array {
- v = gstr.TrimRight(v, `\/`)
- buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v))
- index++
- buffer.WriteString(fmt.Sprintf("\n%d. %s", index, v+gfile.Separator+"config"))
- index++
- }
- })
- } else {
- buffer.WriteString(fmt.Sprintf("[gcfg] cannot find config file \"%s\" with no path configured", name))
- }
- err = gerror.NewCode(gcode.CodeOperationFailed, buffer.String())
- }
- return
-}
-
-// autoCheckAndAddMainPkgPathToSearchPaths automatically checks and adds directory path of package main
-// to the searching path list if it's currently in development environment.
-func (c *Config) autoCheckAndAddMainPkgPathToSearchPaths() {
- if gmode.IsDevelop() {
- mainPkgPath := gfile.MainPkgPath()
- if mainPkgPath != "" {
- if !c.searchPaths.Contains(mainPkgPath) {
- c.searchPaths.Append(mainPkgPath)
- }
- }
- }
-}
-
-// getJson returns a *gjson.Json object for the specified `file` content.
-// It would print error if file reading fails. It return nil if any error occurs.
-func (c *Config) getJson(file ...string) *gjson.Json {
- var name string
- if len(file) > 0 && file[0] != "" {
- name = file[0]
- } else {
- name = c.defaultName
- }
- r := c.jsonMap.GetOrSetFuncLock(name, func() interface{} {
- var (
- err error
- content string
- filePath string
- )
- // The configured content can be any kind of data type different from its file type.
- isFromConfigContent := true
- if content = GetContent(name); content == "" {
- isFromConfigContent = false
- filePath, err = c.GetFilePath(name)
- if err != nil && errorPrint() {
- glog.Error(err)
- }
- if filePath == "" {
- return nil
- }
- if file := gres.Get(filePath); file != nil {
- content = string(file.Content())
- } else {
- content = gfile.GetContents(filePath)
- }
- }
- // Note that the underlying configuration json object operations are concurrent safe.
- var (
- j *gjson.Json
- )
- dataType := gfile.ExtName(name)
- if gjson.IsValidDataType(dataType) && !isFromConfigContent {
- j, err = gjson.LoadContentType(dataType, content, true)
- } else {
- j, err = gjson.LoadContent(content, true)
- }
- if err == nil {
- j.SetViolenceCheck(c.violenceCheck)
- // Add monitor for this configuration file,
- // any changes of this file will refresh its cache in Config object.
- if filePath != "" && !gres.Contains(filePath) {
- _, err = gfsnotify.Add(filePath, func(event *gfsnotify.Event) {
- c.jsonMap.Remove(name)
- })
- if err != nil && errorPrint() {
- glog.Error(err)
- }
- }
- return j
- }
- if errorPrint() {
- if filePath != "" {
- glog.Criticalf(`[gcfg] load config file "%s" failed: %s`, filePath, err.Error())
- } else {
- glog.Criticalf(`[gcfg] load configuration failed: %s`, err.Error())
- }
- }
- return nil
- })
- if r != nil {
- return r.(*gjson.Json)
- }
- return nil
-}
diff --git a/os/gcfg/gcfg_config_api.go b/os/gcfg/gcfg_config_api.go
deleted file mode 100644
index f3adb7c9c..000000000
--- a/os/gcfg/gcfg_config_api.go
+++ /dev/null
@@ -1,403 +0,0 @@
-// Copyright GoFrame 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 gcfg
-
-import (
- "github.com/gogf/gf/errors/gcode"
- "github.com/gogf/gf/errors/gerror"
- "time"
-
- "github.com/gogf/gf/encoding/gjson"
-
- "github.com/gogf/gf/container/gvar"
- "github.com/gogf/gf/os/gtime"
-)
-
-// Set sets value with specified `pattern`.
-// It supports hierarchical data access by char separator, which is '.' in default.
-// It is commonly used for updates certain configuration value in runtime.
-func (c *Config) Set(pattern string, value interface{}) error {
- if j := c.getJson(); j != nil {
- return j.Set(pattern, value)
- }
- return nil
-}
-
-// Get retrieves and returns value by specified `pattern`.
-// It returns all values of current Json object if `pattern` is given empty or string ".".
-// It returns nil if no value found by `pattern`.
-//
-// We can also access slice item by its index number in `pattern` like:
-// "list.10", "array.0.name", "array.0.1.id".
-//
-// It returns a default value specified by `def` if value for `pattern` is not found.
-func (c *Config) Get(pattern string, def ...interface{}) interface{} {
- if j := c.getJson(); j != nil {
- return j.Get(pattern, def...)
- }
- return nil
-}
-
-// GetVar returns a gvar.Var with value by given `pattern`.
-func (c *Config) GetVar(pattern string, def ...interface{}) *gvar.Var {
- if j := c.getJson(); j != nil {
- return j.GetVar(pattern, def...)
- }
- return gvar.New(nil)
-}
-
-// Contains checks whether the value by specified `pattern` exist.
-func (c *Config) Contains(pattern string) bool {
- if j := c.getJson(); j != nil {
- return j.Contains(pattern)
- }
- return false
-}
-
-// GetMap retrieves and returns the value by specified `pattern` as map[string]interface{}.
-func (c *Config) GetMap(pattern string, def ...interface{}) map[string]interface{} {
- if j := c.getJson(); j != nil {
- return j.GetMap(pattern, def...)
- }
- return nil
-}
-
-// GetMapStrStr retrieves and returns the value by specified `pattern` as map[string]string.
-func (c *Config) GetMapStrStr(pattern string, def ...interface{}) map[string]string {
- if j := c.getJson(); j != nil {
- return j.GetMapStrStr(pattern, def...)
- }
- return nil
-}
-
-// GetArray retrieves the value by specified `pattern`,
-// and converts it to a slice of []interface{}.
-func (c *Config) GetArray(pattern string, def ...interface{}) []interface{} {
- if j := c.getJson(); j != nil {
- return j.GetArray(pattern, def...)
- }
- return nil
-}
-
-// GetBytes retrieves the value by specified `pattern` and converts it to []byte.
-func (c *Config) GetBytes(pattern string, def ...interface{}) []byte {
- if j := c.getJson(); j != nil {
- return j.GetBytes(pattern, def...)
- }
- return nil
-}
-
-// GetString retrieves the value by specified `pattern` and converts it to string.
-func (c *Config) GetString(pattern string, def ...interface{}) string {
- if j := c.getJson(); j != nil {
- return j.GetString(pattern, def...)
- }
- return ""
-}
-
-// GetStrings retrieves the value by specified `pattern` and converts it to []string.
-func (c *Config) GetStrings(pattern string, def ...interface{}) []string {
- if j := c.getJson(); j != nil {
- return j.GetStrings(pattern, def...)
- }
- return nil
-}
-
-// GetInterfaces is alias of GetArray.
-// See GetArray.
-func (c *Config) GetInterfaces(pattern string, def ...interface{}) []interface{} {
- if j := c.getJson(); j != nil {
- return j.GetInterfaces(pattern, def...)
- }
- return nil
-}
-
-// GetBool retrieves the value by specified `pattern`,
-// converts and returns it as bool.
-// It returns false when value is: "", 0, false, off, nil;
-// or returns true instead.
-func (c *Config) GetBool(pattern string, def ...interface{}) bool {
- if j := c.getJson(); j != nil {
- return j.GetBool(pattern, def...)
- }
- return false
-}
-
-// GetFloat32 retrieves the value by specified `pattern` and converts it to float32.
-func (c *Config) GetFloat32(pattern string, def ...interface{}) float32 {
- if j := c.getJson(); j != nil {
- return j.GetFloat32(pattern, def...)
- }
- return 0
-}
-
-// GetFloat64 retrieves the value by specified `pattern` and converts it to float64.
-func (c *Config) GetFloat64(pattern string, def ...interface{}) float64 {
- if j := c.getJson(); j != nil {
- return j.GetFloat64(pattern, def...)
- }
- return 0
-}
-
-// GetFloats retrieves the value by specified `pattern` and converts it to []float64.
-func (c *Config) GetFloats(pattern string, def ...interface{}) []float64 {
- if j := c.getJson(); j != nil {
- return j.GetFloats(pattern, def...)
- }
- return nil
-}
-
-// GetInt retrieves the value by specified `pattern` and converts it to int.
-func (c *Config) GetInt(pattern string, def ...interface{}) int {
- if j := c.getJson(); j != nil {
- return j.GetInt(pattern, def...)
- }
- return 0
-}
-
-// GetInt8 retrieves the value by specified `pattern` and converts it to int8.
-func (c *Config) GetInt8(pattern string, def ...interface{}) int8 {
- if j := c.getJson(); j != nil {
- return j.GetInt8(pattern, def...)
- }
- return 0
-}
-
-// GetInt16 retrieves the value by specified `pattern` and converts it to int16.
-func (c *Config) GetInt16(pattern string, def ...interface{}) int16 {
- if j := c.getJson(); j != nil {
- return j.GetInt16(pattern, def...)
- }
- return 0
-}
-
-// GetInt32 retrieves the value by specified `pattern` and converts it to int32.
-func (c *Config) GetInt32(pattern string, def ...interface{}) int32 {
- if j := c.getJson(); j != nil {
- return j.GetInt32(pattern, def...)
- }
- return 0
-}
-
-// GetInt64 retrieves the value by specified `pattern` and converts it to int64.
-func (c *Config) GetInt64(pattern string, def ...interface{}) int64 {
- if j := c.getJson(); j != nil {
- return j.GetInt64(pattern, def...)
- }
- return 0
-}
-
-// GetInts retrieves the value by specified `pattern` and converts it to []int.
-func (c *Config) GetInts(pattern string, def ...interface{}) []int {
- if j := c.getJson(); j != nil {
- return j.GetInts(pattern, def...)
- }
- return nil
-}
-
-// GetUint retrieves the value by specified `pattern` and converts it to uint.
-func (c *Config) GetUint(pattern string, def ...interface{}) uint {
- if j := c.getJson(); j != nil {
- return j.GetUint(pattern, def...)
- }
- return 0
-}
-
-// GetUint8 retrieves the value by specified `pattern` and converts it to uint8.
-func (c *Config) GetUint8(pattern string, def ...interface{}) uint8 {
- if j := c.getJson(); j != nil {
- return j.GetUint8(pattern, def...)
- }
- return 0
-}
-
-// GetUint16 retrieves the value by specified `pattern` and converts it to uint16.
-func (c *Config) GetUint16(pattern string, def ...interface{}) uint16 {
- if j := c.getJson(); j != nil {
- return j.GetUint16(pattern, def...)
- }
- return 0
-}
-
-// GetUint32 retrieves the value by specified `pattern` and converts it to uint32.
-func (c *Config) GetUint32(pattern string, def ...interface{}) uint32 {
- if j := c.getJson(); j != nil {
- return j.GetUint32(pattern, def...)
- }
- return 0
-}
-
-// GetUint64 retrieves the value by specified `pattern` and converts it to uint64.
-func (c *Config) GetUint64(pattern string, def ...interface{}) uint64 {
- if j := c.getJson(); j != nil {
- return j.GetUint64(pattern, def...)
- }
- return 0
-}
-
-// GetTime retrieves the value by specified `pattern` and converts it to time.Time.
-func (c *Config) GetTime(pattern string, format ...string) time.Time {
- if j := c.getJson(); j != nil {
- return j.GetTime(pattern, format...)
- }
- return time.Time{}
-}
-
-// GetDuration retrieves the value by specified `pattern` and converts it to time.Duration.
-func (c *Config) GetDuration(pattern string, def ...interface{}) time.Duration {
- if j := c.getJson(); j != nil {
- return j.GetDuration(pattern, def...)
- }
- return 0
-}
-
-// GetGTime retrieves the value by specified `pattern` and converts it to *gtime.Time.
-func (c *Config) GetGTime(pattern string, format ...string) *gtime.Time {
- if j := c.getJson(); j != nil {
- return j.GetGTime(pattern, format...)
- }
- return nil
-}
-
-// GetJson gets the value by specified `pattern`,
-// and converts it to a un-concurrent-safe Json object.
-func (c *Config) GetJson(pattern string, def ...interface{}) *gjson.Json {
- if j := c.getJson(); j != nil {
- return j.GetJson(pattern, def...)
- }
- return nil
-}
-
-// GetJsons gets the value by specified `pattern`,
-// and converts it to a slice of un-concurrent-safe Json object.
-func (c *Config) GetJsons(pattern string, def ...interface{}) []*gjson.Json {
- if j := c.getJson(); j != nil {
- return j.GetJsons(pattern, def...)
- }
- return nil
-}
-
-// GetJsonMap gets the value by specified `pattern`,
-// and converts it to a map of un-concurrent-safe Json object.
-func (c *Config) GetJsonMap(pattern string, def ...interface{}) map[string]*gjson.Json {
- if j := c.getJson(); j != nil {
- return j.GetJsonMap(pattern, def...)
- }
- return nil
-}
-
-// GetStruct retrieves the value by specified `pattern` and converts it to specified object
-// `pointer`. The `pointer` should be the pointer to an object.
-func (c *Config) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.GetStruct(pattern, pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// GetStructs converts any slice to given struct slice.
-func (c *Config) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.GetStructs(pattern, pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// GetMapToMap retrieves the value by specified `pattern` and converts it to specified map variable.
-// See gconv.MapToMap.
-func (c *Config) GetMapToMap(pattern string, pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.GetMapToMap(pattern, pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// GetMapToMaps retrieves the value by specified `pattern` and converts it to specified map slice
-// variable.
-// See gconv.MapToMaps.
-func (c *Config) GetMapToMaps(pattern string, pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.GetMapToMaps(pattern, pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// GetMapToMapsDeep retrieves the value by specified `pattern` and converts it to specified map slice
-// variable recursively.
-// See gconv.MapToMapsDeep.
-func (c *Config) GetMapToMapsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.GetMapToMapsDeep(pattern, pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// Map converts current Json object to map[string]interface{}. It returns nil if fails.
-func (c *Config) Map() map[string]interface{} {
- if j := c.getJson(); j != nil {
- return j.Map()
- }
- return nil
-}
-
-// Array converts current Json object to []interface{}.
-// It returns nil if fails.
-func (c *Config) Array() []interface{} {
- if j := c.getJson(); j != nil {
- return j.Array()
- }
- return nil
-}
-
-// Struct converts current Json object to specified object.
-// The `pointer` should be a pointer type of *struct.
-func (c *Config) Struct(pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.Struct(pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// Structs converts current Json object to specified object slice.
-// The `pointer` should be a pointer type of []struct/*struct.
-func (c *Config) Structs(pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.Structs(pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// MapToMap converts current Json object to specified map variable.
-// The parameter of `pointer` should be type of *map.
-func (c *Config) MapToMap(pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.MapToMap(pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// MapToMaps converts current Json object to specified map variable slice.
-// The parameter of `pointer` should be type of []map/*map.
-func (c *Config) MapToMaps(pointer interface{}, mapping ...map[string]string) error {
- if j := c.getJson(); j != nil {
- return j.MapToMaps(pointer, mapping...)
- }
- return gerror.NewCode(gcode.CodeMissingConfiguration, "configuration not found")
-}
-
-// Clear removes all parsed configuration files content cache,
-// which will force reload configuration content from file.
-func (c *Config) Clear() {
- c.jsonMap.Clear()
-}
-
-// Dump prints current Json object with more manually readable.
-func (c *Config) Dump() {
- if j := c.getJson(); j != nil {
- j.Dump()
- }
-}
diff --git a/os/gcfg/gcfg_z_example_pattern_test.go b/os/gcfg/gcfg_z_example_pattern_test.go
deleted file mode 100644
index a5ba919d5..000000000
--- a/os/gcfg/gcfg_z_example_pattern_test.go
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright GoFrame 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 gcfg_test
-
-import (
- "fmt"
- "github.com/gogf/gf/frame/g"
- "github.com/gogf/gf/internal/intlog"
- "github.com/gogf/gf/os/gcfg"
-)
-
-func Example_mapSliceChange() {
- intlog.SetEnabled(false)
- defer intlog.SetEnabled(true)
- // For testing/example only.
- content := `{"map":{"key":"value"}, "slice":[59,90]}`
- gcfg.SetContent(content)
- defer gcfg.RemoveContent()
-
- m := g.Cfg().GetMap("map")
- fmt.Println(m)
-
- // Change the key-value pair.
- m["key"] = "john"
-
- // It changes the underlying key-value pair.
- fmt.Println(g.Cfg().GetMap("map"))
-
- s := g.Cfg().GetArray("slice")
- fmt.Println(s)
-
- // Change the value of specified index.
- s[0] = 100
-
- // It changes the underlying slice.
- fmt.Println(g.Cfg().GetArray("slice"))
-
- // output:
- // map[key:value]
- // map[key:john]
- // [59 90]
- // [100 90]
-}
diff --git a/os/gcfg/gcfg_z_init_test.go b/os/gcfg/gcfg_z_init_test.go
new file mode 100644
index 000000000..01918f810
--- /dev/null
+++ b/os/gcfg/gcfg_z_init_test.go
@@ -0,0 +1,15 @@
+// Copyright GoFrame 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.
+
+// go test *.go -bench=".*" -benchmem
+
+package gcfg_test
+
+import "context"
+
+var (
+ ctx = context.TODO()
+)
diff --git a/os/gcfg/gcfg_z_unit_adapter_file_test.go b/os/gcfg/gcfg_z_unit_adapter_file_test.go
new file mode 100644
index 000000000..6c84522d9
--- /dev/null
+++ b/os/gcfg/gcfg_z_unit_adapter_file_test.go
@@ -0,0 +1,100 @@
+// Copyright GoFrame 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.
+
+// go test *.go -bench=".*" -benchmem
+
+package gcfg_test
+
+import (
+ "github.com/gogf/gf/os/gcfg"
+ "github.com/gogf/gf/test/gtest"
+ "testing"
+)
+
+func TestAdapterFile_SetPath(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ c, err := gcfg.NewAdapterFile("config.yml")
+ t.AssertNil(err)
+
+ err = c.SetPath("/tmp")
+ t.AssertNil(err)
+
+ err = c.SetPath("gcfg.go")
+ t.AssertNE(err, nil)
+
+ v, err := c.Get(ctx, "name")
+ t.AssertNE(err, nil)
+ t.Assert(v, nil)
+ })
+}
+
+func TestAdapterFile_AddPath(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ c, err := gcfg.NewAdapterFile("config.yml")
+ t.AssertNil(err)
+
+ err = c.AddPath("/tmp")
+ t.AssertNil(err)
+
+ err = c.AddPath("gcfg.go")
+ t.AssertNE(err, nil)
+
+ v, err := c.Get(ctx, "name")
+ t.AssertNE(err, nil)
+ t.Assert(v, nil)
+ })
+}
+
+func TestAdapterFile_SetViolenceCheck(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ c, err := gcfg.NewAdapterFile("config.yml")
+ t.AssertNil(err)
+ c.SetViolenceCheck(true)
+ v, err := c.Get(ctx, "name")
+ t.AssertNE(err, nil)
+ t.Assert(v, nil)
+ })
+}
+
+func TestAdapterFile_FilePath(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ c, err := gcfg.NewAdapterFile("config.yml")
+ t.AssertNil(err)
+
+ path, _ := c.GetFilePath("tmp")
+ t.Assert(path, "")
+
+ path, _ = c.GetFilePath("tmp")
+ t.Assert(path, "")
+ })
+}
+
+func TestAdapterFile_Content(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ c, err := gcfg.NewAdapterFile()
+ t.AssertNil(err)
+
+ c.SetContent("gf", "config.yml")
+ t.Assert(c.GetContent("config.yml"), "gf")
+ c.SetContent("gf1", "config.yml")
+ t.Assert(c.GetContent("config.yml"), "gf1")
+ c.RemoveContent("config.yml")
+ c.ClearContent()
+ t.Assert(c.GetContent("name"), "")
+ })
+}
+
+func TestAdapterFile_With_UTF8_BOM(t *testing.T) {
+ gtest.C(t, func(t *gtest.T) {
+ c, err := gcfg.NewAdapterFile("test-cfg-with-utf8-bom")
+ t.AssertNil(err)
+
+ t.Assert(c.SetPath("testdata"), nil)
+ c.SetFileName("cfg-with-utf8-bom.toml")
+ t.Assert(c.MustGet(ctx, "test.testInt"), 1)
+ t.Assert(c.MustGet(ctx, "test.testStr"), "test")
+ })
+}
diff --git a/os/gcfg/gcfg_z_unit_basic_test.go b/os/gcfg/gcfg_z_unit_basic_test.go
index 51fd92638..290dc2cc3 100644
--- a/os/gcfg/gcfg_z_unit_basic_test.go
+++ b/os/gcfg/gcfg_z_unit_basic_test.go
@@ -9,22 +9,15 @@
package gcfg_test
import (
- "os"
"testing"
"github.com/gogf/gf/os/gtime"
- "github.com/gogf/gf/encoding/gjson"
- "github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/gcfg"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/test/gtest"
)
-func init() {
- os.Setenv("GF_GCFG_ERRORPRINT", "false")
-}
-
func Test_Basic1(t *testing.T) {
config := `
v1 = 1
@@ -42,46 +35,10 @@ array = [1,2,3]
t.Assert(err, nil)
defer gfile.Remove(path)
- c := gcfg.New()
- t.Assert(c.Get("v1"), 1)
- t.AssertEQ(c.GetInt("v1"), 1)
- t.AssertEQ(c.GetInt8("v1"), int8(1))
- t.AssertEQ(c.GetInt16("v1"), int16(1))
- t.AssertEQ(c.GetInt32("v1"), int32(1))
- t.AssertEQ(c.GetInt64("v1"), int64(1))
- t.AssertEQ(c.GetUint("v1"), uint(1))
- t.AssertEQ(c.GetUint8("v1"), uint8(1))
- t.AssertEQ(c.GetUint16("v1"), uint16(1))
- t.AssertEQ(c.GetUint32("v1"), uint32(1))
- t.AssertEQ(c.GetUint64("v1"), uint64(1))
-
- t.AssertEQ(c.GetVar("v1").String(), "1")
- t.AssertEQ(c.GetVar("v1").Bool(), true)
- t.AssertEQ(c.GetVar("v2").String(), "true")
- t.AssertEQ(c.GetVar("v2").Bool(), true)
-
- t.AssertEQ(c.GetString("v1"), "1")
- t.AssertEQ(c.GetFloat32("v4"), float32(1.23))
- t.AssertEQ(c.GetFloat64("v4"), float64(1.23))
- t.AssertEQ(c.GetString("v2"), "true")
- t.AssertEQ(c.GetBool("v2"), true)
- t.AssertEQ(c.GetBool("v3"), false)
-
- t.AssertEQ(c.Contains("v1"), true)
- t.AssertEQ(c.Contains("v2"), true)
- t.AssertEQ(c.Contains("v3"), true)
- t.AssertEQ(c.Contains("v4"), true)
- t.AssertEQ(c.Contains("v5"), false)
-
- t.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
- t.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
- t.AssertEQ(c.GetArray("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetInterfaces("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetMap("redis"), map[string]interface{}{
- "disk": "127.0.0.1:6379,0",
- "cache": "127.0.0.1:6379,1",
- })
- filepath, _ := c.GetFilePath()
+ c, err := gcfg.New()
+ t.AssertNil(err)
+ t.Assert(c.MustGet(ctx, "v1"), 1)
+ filepath, _ := c.GetAdapter().(*gcfg.AdapterFile).GetFilePath()
t.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)
})
}
@@ -96,8 +53,9 @@ func Test_Basic2(t *testing.T) {
_ = gfile.Remove(path)
}()
- c := gcfg.New()
- t.Assert(c.Get("log-path"), "logs")
+ c, err := gcfg.New()
+ t.AssertNil(err)
+ t.Assert(c.MustGet(ctx, "log-path"), "logs")
})
}
@@ -112,49 +70,12 @@ array = [1,2,3]
disk = "127.0.0.1:6379,0"
cache = "127.0.0.1:6379,1"
`
- gcfg.SetContent(content)
- defer gcfg.ClearContent()
-
gtest.C(t, func(t *gtest.T) {
- c := gcfg.New()
- t.Assert(c.Get("v1"), 1)
- t.AssertEQ(c.GetInt("v1"), 1)
- t.AssertEQ(c.GetInt8("v1"), int8(1))
- t.AssertEQ(c.GetInt16("v1"), int16(1))
- t.AssertEQ(c.GetInt32("v1"), int32(1))
- t.AssertEQ(c.GetInt64("v1"), int64(1))
- t.AssertEQ(c.GetUint("v1"), uint(1))
- t.AssertEQ(c.GetUint8("v1"), uint8(1))
- t.AssertEQ(c.GetUint16("v1"), uint16(1))
- t.AssertEQ(c.GetUint32("v1"), uint32(1))
- t.AssertEQ(c.GetUint64("v1"), uint64(1))
-
- t.AssertEQ(c.GetVar("v1").String(), "1")
- t.AssertEQ(c.GetVar("v1").Bool(), true)
- t.AssertEQ(c.GetVar("v2").String(), "true")
- t.AssertEQ(c.GetVar("v2").Bool(), true)
-
- t.AssertEQ(c.GetString("v1"), "1")
- t.AssertEQ(c.GetFloat32("v4"), float32(1.23))
- t.AssertEQ(c.GetFloat64("v4"), float64(1.23))
- t.AssertEQ(c.GetString("v2"), "true")
- t.AssertEQ(c.GetBool("v2"), true)
- t.AssertEQ(c.GetBool("v3"), false)
-
- t.AssertEQ(c.Contains("v1"), true)
- t.AssertEQ(c.Contains("v2"), true)
- t.AssertEQ(c.Contains("v3"), true)
- t.AssertEQ(c.Contains("v4"), true)
- t.AssertEQ(c.Contains("v5"), false)
-
- t.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
- t.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
- t.AssertEQ(c.GetArray("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetInterfaces("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetMap("redis"), map[string]interface{}{
- "disk": "127.0.0.1:6379,0",
- "cache": "127.0.0.1:6379,1",
- })
+ c, err := gcfg.New()
+ t.AssertNil(err)
+ c.GetAdapter().(*gcfg.AdapterFile).SetContent(content)
+ defer c.GetAdapter().(*gcfg.AdapterFile).ClearContent()
+ t.Assert(c.MustGet(ctx, "v1"), 1)
})
}
@@ -184,43 +105,38 @@ func Test_SetFileName(t *testing.T) {
_ = gfile.Remove(path)
}()
- c := gcfg.New()
+ config, err := gcfg.New()
+ t.AssertNil(err)
+ c := config.GetAdapter().(*gcfg.AdapterFile)
c.SetFileName(path)
- t.Assert(c.Get("v1"), 1)
- t.AssertEQ(c.GetInt("v1"), 1)
- t.AssertEQ(c.GetInt8("v1"), int8(1))
- t.AssertEQ(c.GetInt16("v1"), int16(1))
- t.AssertEQ(c.GetInt32("v1"), int32(1))
- t.AssertEQ(c.GetInt64("v1"), int64(1))
- t.AssertEQ(c.GetUint("v1"), uint(1))
- t.AssertEQ(c.GetUint8("v1"), uint8(1))
- t.AssertEQ(c.GetUint16("v1"), uint16(1))
- t.AssertEQ(c.GetUint32("v1"), uint32(1))
- t.AssertEQ(c.GetUint64("v1"), uint64(1))
+ t.Assert(c.MustGet(ctx, "v1"), 1)
+ t.AssertEQ(c.MustGet(ctx, "v1").Int(), 1)
+ t.AssertEQ(c.MustGet(ctx, "v1").Int8(), int8(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Int16(), int16(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Int32(), int32(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Int64(), int64(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Uint(), uint(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Uint8(), uint8(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Uint16(), uint16(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Uint32(), uint32(1))
+ t.AssertEQ(c.MustGet(ctx, "v1").Uint64(), uint64(1))
- t.AssertEQ(c.GetVar("v1").String(), "1")
- t.AssertEQ(c.GetVar("v1").Bool(), true)
- t.AssertEQ(c.GetVar("v2").String(), "true")
- t.AssertEQ(c.GetVar("v2").Bool(), true)
+ t.AssertEQ(c.MustGet(ctx, "v1").String(), "1")
+ t.AssertEQ(c.MustGet(ctx, "v1").Bool(), true)
+ t.AssertEQ(c.MustGet(ctx, "v2").String(), "true")
+ t.AssertEQ(c.MustGet(ctx, "v2").Bool(), true)
- t.AssertEQ(c.GetString("v1"), "1")
- t.AssertEQ(c.GetFloat32("v4"), float32(1.234))
- t.AssertEQ(c.GetFloat64("v4"), float64(1.234))
- t.AssertEQ(c.GetString("v2"), "true")
- t.AssertEQ(c.GetBool("v2"), true)
- t.AssertEQ(c.GetBool("v3"), false)
+ t.AssertEQ(c.MustGet(ctx, "v1").String(), "1")
+ t.AssertEQ(c.MustGet(ctx, "v4").Float32(), float32(1.234))
+ t.AssertEQ(c.MustGet(ctx, "v4").Float64(), float64(1.234))
+ t.AssertEQ(c.MustGet(ctx, "v2").String(), "true")
+ t.AssertEQ(c.MustGet(ctx, "v2").Bool(), true)
+ t.AssertEQ(c.MustGet(ctx, "v3").Bool(), false)
- t.AssertEQ(c.Contains("v1"), true)
- t.AssertEQ(c.Contains("v2"), true)
- t.AssertEQ(c.Contains("v3"), true)
- t.AssertEQ(c.Contains("v4"), true)
- t.AssertEQ(c.Contains("v5"), false)
-
- t.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
- t.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
- t.AssertEQ(c.GetArray("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetInterfaces("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetMap("redis"), map[string]interface{}{
+ t.AssertEQ(c.MustGet(ctx, "array").Ints(), []int{1, 2, 3})
+ t.AssertEQ(c.MustGet(ctx, "array").Strings(), []string{"1", "2", "3"})
+ t.AssertEQ(c.MustGet(ctx, "array").Interfaces(), []interface{}{1, 2, 3})
+ t.AssertEQ(c.MustGet(ctx, "redis").Map(), map[string]interface{}{
"disk": "127.0.0.1:6379,0",
"cache": "127.0.0.1:6379,1",
})
@@ -229,67 +145,7 @@ func Test_SetFileName(t *testing.T) {
})
}
-func TestCfg_New(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- os.Setenv("GF_GCFG_PATH", "config")
- c := gcfg.New("config.yml")
- t.Assert(c.Get("name"), nil)
- t.Assert(c.GetFileName(), "config.yml")
-
- configPath := gfile.Pwd() + gfile.Separator + "config"
- _ = gfile.Mkdir(configPath)
- defer gfile.Remove(configPath)
-
- c = gcfg.New("config.yml")
- t.Assert(c.Get("name"), nil)
-
- _ = os.Unsetenv("GF_GCFG_PATH")
- c = gcfg.New("config.yml")
- t.Assert(c.Get("name"), nil)
- })
-}
-
-func TestCfg_SetPath(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- c := gcfg.New("config.yml")
- err := c.SetPath("tmp")
- t.AssertNE(err, nil)
- err = c.SetPath("gcfg.go")
- t.AssertNE(err, nil)
- t.Assert(c.Get("name"), nil)
- })
-}
-
-func TestCfg_SetViolenceCheck(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- c := gcfg.New("config.yml")
- c.SetViolenceCheck(true)
- t.Assert(c.Get("name"), nil)
- })
-}
-
-func TestCfg_AddPath(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- c := gcfg.New("config.yml")
- err := c.AddPath("tmp")
- t.AssertNE(err, nil)
- err = c.AddPath("gcfg.go")
- t.AssertNE(err, nil)
- t.Assert(c.Get("name"), nil)
- })
-}
-
-func TestCfg_FilePath(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- c := gcfg.New("config.yml")
- path, _ := c.GetFilePath("tmp")
- t.Assert(path, "")
- path, _ = c.GetFilePath("tmp")
- t.Assert(path, "")
- })
-}
-
-func TestCfg_et(t *testing.T) {
+func TestCfg_Set(t *testing.T) {
config := `log-path = "logs"`
gtest.C(t, func(t *gtest.T) {
path := gcfg.DefaultConfigFile
@@ -297,16 +153,18 @@ func TestCfg_et(t *testing.T) {
t.Assert(err, nil)
defer gfile.Remove(path)
- c := gcfg.New()
- t.Assert(c.Get("log-path"), "logs")
+ adapterFile, err := gcfg.NewAdapterFile()
+ t.AssertNil(err)
+ t.Assert(adapterFile.MustGet(ctx, "log-path"), "logs")
- err = c.Set("log-path", "custom-logs")
+ c := gcfg.NewWithAdapter(adapterFile)
+ c.Set(ctx, "log-path", "custom-logs")
t.Assert(err, nil)
- t.Assert(c.Get("log-path"), "custom-logs")
+ t.Assert(c.MustGet(ctx, "log-path"), "custom-logs")
})
}
-func TestCfg_Get(t *testing.T) {
+func TestCfg_Get_WrongConfigFile(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var err error
configPath := gfile.TempDir(gtime.TimestampNanoStr())
@@ -323,82 +181,13 @@ func TestCfg_Get(t *testing.T) {
"wrong config",
)
t.Assert(err, nil)
- c := gcfg.New("config.yml")
- t.Assert(c.Get("name"), nil)
- t.Assert(c.GetVar("name").Val(), nil)
- t.Assert(c.Contains("name"), false)
- t.Assert(c.GetMap("name"), nil)
- t.Assert(c.GetArray("name"), nil)
- t.Assert(c.GetString("name"), "")
- t.Assert(c.GetStrings("name"), nil)
- t.Assert(c.GetInterfaces("name"), nil)
- t.Assert(c.GetBool("name"), false)
- t.Assert(c.GetFloat32("name"), 0)
- t.Assert(c.GetFloat64("name"), 0)
- t.Assert(c.GetFloats("name"), nil)
- t.Assert(c.GetInt("name"), 0)
- t.Assert(c.GetInt8("name"), 0)
- t.Assert(c.GetInt16("name"), 0)
- t.Assert(c.GetInt32("name"), 0)
- t.Assert(c.GetInt64("name"), 0)
- t.Assert(c.GetInts("name"), nil)
- t.Assert(c.GetUint("name"), 0)
- t.Assert(c.GetUint8("name"), 0)
- t.Assert(c.GetUint16("name"), 0)
- t.Assert(c.GetUint32("name"), 0)
- t.Assert(c.GetUint64("name"), 0)
- t.Assert(c.GetTime("name").Format("2006-01-02"), "0001-01-01")
- t.Assert(c.GetGTime("name"), nil)
- t.Assert(c.GetDuration("name").String(), "0s")
- name := struct {
- Name string
- }{}
- t.Assert(c.GetStruct("name", &name) == nil, false)
+ adapterFile, err := gcfg.NewAdapterFile("config.yml")
+ t.AssertNil(err)
- c.Clear()
-
- arr, _ := gjson.Encode(
- g.Map{
- "name": "gf",
- "time": "2019-06-12",
- "person": g.Map{"name": "gf"},
- "floats": g.Slice{1, 2, 3},
- },
- )
- err = gfile.PutBytes(
- gfile.Join(configPath, "config.yml"),
- arr,
- )
- t.Assert(err, nil)
- t.Assert(c.GetTime("time").Format("2006-01-02"), "2019-06-12")
- t.Assert(c.GetGTime("time").Format("Y-m-d"), "2019-06-12")
- t.Assert(c.GetDuration("time").String(), "0s")
-
- err = c.GetStruct("person", &name)
- t.Assert(err, nil)
- t.Assert(name.Name, "gf")
- t.Assert(c.GetFloats("floats") == nil, false)
- })
-}
-
-func TestCfg_Config(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- gcfg.SetContent("gf", "config.yml")
- t.Assert(gcfg.GetContent("config.yml"), "gf")
- gcfg.SetContent("gf1", "config.yml")
- t.Assert(gcfg.GetContent("config.yml"), "gf1")
- gcfg.RemoveContent("config.yml")
- gcfg.ClearContent()
- t.Assert(gcfg.GetContent("name"), "")
- })
-}
-
-func TestCfg_With_UTF8_BOM(t *testing.T) {
- gtest.C(t, func(t *gtest.T) {
- cfg := g.Cfg("test-cfg-with-utf8-bom")
- t.Assert(cfg.SetPath("testdata"), nil)
- cfg.SetFileName("cfg-with-utf8-bom.toml")
- t.Assert(cfg.GetInt("test.testInt"), 1)
- t.Assert(cfg.GetString("test.testStr"), "test")
+ c := gcfg.NewWithAdapter(adapterFile)
+ v, err := c.Get(ctx, "name")
+ t.AssertNE(err, nil)
+ t.Assert(v, nil)
+ adapterFile.Clear()
})
}
diff --git a/os/gcfg/gcfg_z_unit_instance_test.go b/os/gcfg/gcfg_z_unit_instance_test.go
index 879a5461d..621d6f183 100644
--- a/os/gcfg/gcfg_z_unit_instance_test.go
+++ b/os/gcfg/gcfg_z_unit_instance_test.go
@@ -9,6 +9,7 @@
package gcfg
import (
+ "context"
"github.com/gogf/gf/container/gmap"
"github.com/gogf/gf/debug/gdebug"
"github.com/gogf/gf/os/genv"
@@ -17,6 +18,10 @@ import (
"testing"
)
+var (
+ ctx = context.TODO()
+)
+
func Test_Instance_Basic(t *testing.T) {
config := `
array = [1.0, 2.0, 3.0]
@@ -39,45 +44,8 @@ v4 = "1.234"
}()
c := Instance()
- t.Assert(c.Get("v1"), 1)
- t.AssertEQ(c.GetInt("v1"), 1)
- t.AssertEQ(c.GetInt8("v1"), int8(1))
- t.AssertEQ(c.GetInt16("v1"), int16(1))
- t.AssertEQ(c.GetInt32("v1"), int32(1))
- t.AssertEQ(c.GetInt64("v1"), int64(1))
- t.AssertEQ(c.GetUint("v1"), uint(1))
- t.AssertEQ(c.GetUint8("v1"), uint8(1))
- t.AssertEQ(c.GetUint16("v1"), uint16(1))
- t.AssertEQ(c.GetUint32("v1"), uint32(1))
- t.AssertEQ(c.GetUint64("v1"), uint64(1))
-
- t.AssertEQ(c.GetVar("v1").String(), "1")
- t.AssertEQ(c.GetVar("v1").Bool(), true)
- t.AssertEQ(c.GetVar("v2").String(), "true")
- t.AssertEQ(c.GetVar("v2").Bool(), true)
-
- t.AssertEQ(c.GetString("v1"), "1")
- t.AssertEQ(c.GetFloat32("v4"), float32(1.234))
- t.AssertEQ(c.GetFloat64("v4"), float64(1.234))
- t.AssertEQ(c.GetString("v2"), "true")
- t.AssertEQ(c.GetBool("v2"), true)
- t.AssertEQ(c.GetBool("v3"), false)
-
- t.AssertEQ(c.Contains("v1"), true)
- t.AssertEQ(c.Contains("v2"), true)
- t.AssertEQ(c.Contains("v3"), true)
- t.AssertEQ(c.Contains("v4"), true)
- t.AssertEQ(c.Contains("v5"), false)
-
- t.AssertEQ(c.GetInts("array"), []int{1, 2, 3})
- t.AssertEQ(c.GetStrings("array"), []string{"1", "2", "3"})
- t.AssertEQ(c.GetArray("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetInterfaces("array"), []interface{}{1, 2, 3})
- t.AssertEQ(c.GetMap("redis"), map[string]interface{}{
- "disk": "127.0.0.1:6379,0",
- "cache": "127.0.0.1:6379,1",
- })
- filepath, _ := c.GetFilePath()
+ t.Assert(c.MustGet(ctx, "v1"), 1)
+ filepath, _ := c.GetAdapter().(*AdapterFile).GetFilePath()
t.AssertEQ(filepath, gfile.Pwd()+gfile.Separator+path)
})
}
@@ -92,28 +60,28 @@ func Test_Instance_AutoLocateConfigFile(t *testing.T) {
t.AssertNil(gfile.Chdir(gdebug.TestDataPath()))
defer gfile.Chdir(pwd)
t.Assert(Instance("c1") != nil, true)
- t.Assert(Instance("c1").Get("my-config"), "1")
- t.Assert(Instance("folder1/c1").Get("my-config"), "2")
+ t.Assert(Instance("c1").MustGet(ctx, "my-config"), "1")
+ t.Assert(Instance("folder1/c1").MustGet(ctx, "my-config"), "2")
})
// Automatically locate the configuration file with supported file extensions.
gtest.C(t, func(t *gtest.T) {
pwd := gfile.Pwd()
t.AssertNil(gfile.Chdir(gdebug.TestDataPath("folder1")))
defer gfile.Chdir(pwd)
- t.Assert(Instance("c2").Get("my-config"), 2)
+ t.Assert(Instance("c2").MustGet(ctx, "my-config"), 2)
})
// Default configuration file.
gtest.C(t, func(t *gtest.T) {
- instances.Clear()
+ localInstances.Clear()
pwd := gfile.Pwd()
t.AssertNil(gfile.Chdir(gdebug.TestDataPath("default")))
defer gfile.Chdir(pwd)
- t.Assert(Instance().Get("my-config"), 1)
+ t.Assert(Instance().MustGet(ctx, "my-config"), 1)
- instances.Clear()
+ localInstances.Clear()
t.AssertNil(genv.Set("GF_GCFG_FILE", "config.json"))
defer genv.Set("GF_GCFG_FILE", "")
- t.Assert(Instance().Get("my-config"), 2)
+ t.Assert(Instance().MustGet(ctx, "my-config"), 2)
})
}
@@ -122,9 +90,9 @@ func Test_Instance_EnvPath(t *testing.T) {
genv.Set("GF_GCFG_PATH", gdebug.TestDataPath("envpath"))
defer genv.Set("GF_GCFG_PATH", "")
t.Assert(Instance("c3") != nil, true)
- t.Assert(Instance("c3").Get("my-config"), "3")
- t.Assert(Instance("c4").Get("my-config"), "4")
- instances = gmap.NewStrAnyMap(true)
+ t.Assert(Instance("c3").MustGet(ctx, "my-config"), "3")
+ t.Assert(Instance("c4").MustGet(ctx, "my-config"), "4")
+ localInstances = gmap.NewStrAnyMap(true)
})
}
@@ -134,7 +102,7 @@ func Test_Instance_EnvFile(t *testing.T) {
defer genv.Set("GF_GCFG_PATH", "")
genv.Set("GF_GCFG_FILE", "c6.json")
defer genv.Set("GF_GCFG_FILE", "")
- t.Assert(Instance().Get("my-config"), "6")
- instances = gmap.NewStrAnyMap(true)
+ t.Assert(Instance().MustGet(ctx, "my-config"), "6")
+ localInstances = gmap.NewStrAnyMap(true)
})
}
diff --git a/os/gsession/gsession.go b/os/gsession/gsession.go
index ee1d15fc9..07b0661c5 100644
--- a/os/gsession/gsession.go
+++ b/os/gsession/gsession.go
@@ -14,6 +14,7 @@ import (
)
var (
+ // ErrorDisabled is used for marking certain interface function not used.
ErrorDisabled = gerror.NewOption(gerror.Option{
Text: "this feature is disabled in this storage",
Code: gcode.CodeNotSupported,
diff --git a/util/grand/grand.go b/util/grand/grand.go
index 63a71618d..77478cee4 100644
--- a/util/grand/grand.go
+++ b/util/grand/grand.go
@@ -10,7 +10,6 @@ package grand
import (
"encoding/binary"
"time"
- "unsafe"
)
var (
@@ -20,7 +19,7 @@ var (
characters = letters + digits + symbols // 94
)
-// Intn returns a int number which is between 0 and max: [0, max).
+// Intn returns an int number which is between 0 and max: [0, max).
//
// Note that:
// 1. The `max` can only be greater than 0, or else it returns `max` directly;
@@ -95,7 +94,7 @@ func S(n int, symbols ...bool) string {
b[i] = characters[numberBytes[i]%62]
}
}
- return *(*string)(unsafe.Pointer(&b))
+ return string(b)
}
// D returns a random time.Duration between min and max: [min, max].
@@ -147,7 +146,7 @@ func Digits(n int) string {
for i := range b {
b[i] = digits[numberBytes[i]%10]
}
- return *(*string)(unsafe.Pointer(&b))
+ return string(b)
}
// Letters returns a random string which contains only letters, and its length is `n`.
@@ -162,7 +161,7 @@ func Letters(n int) string {
for i := range b {
b[i] = letters[numberBytes[i]%52]
}
- return *(*string)(unsafe.Pointer(&b))
+ return string(b)
}
// Symbols returns a random string which contains only symbols, and its length is `n`.
@@ -177,7 +176,7 @@ func Symbols(n int) string {
for i := range b {
b[i] = symbols[numberBytes[i]%32]
}
- return *(*string)(unsafe.Pointer(&b))
+ return string(b)
}
// Perm returns, as a slice of n int numbers, a pseudo-random permutation of the integers [0,n).