Compare commits

...

8 Commits

38 changed files with 332 additions and 241 deletions

View File

@ -5,4 +5,8 @@
[redis]
default = "127.0.0.1:6379,0"
cache = "127.0.0.1:6379,1"
cache = "127.0.0.1:6379,1"
[viewer]
delimiters = ["${", "}"]
autoencode = true

View File

@ -1,14 +1,11 @@
package main
import (
"fmt"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/gfile"
)
func main() {
g.Dump(gfile.ScanDirFile("/Users/john/Temp/test", "Dockerfile", true))
//if err := gfile.ReplaceDir("gf-empty", "app", "/Users/john/Temp/test", "*.*", true); err != nil {
// glog.Fatal("content replacing failed,", err.Error())
//}
fmt.Println(g.Cfg().FilePath())
g.Cfg().Dump()
}

View File

@ -41,27 +41,6 @@ golang version >= 1.10
<img src="https://goframe.org/images/arch.png?v=10"/>
</div>
# Quick Start
```go
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Write("Hello World")
})
s.Run()
}
```
[More Features...](https://goframe.org/start/index)
# License

View File

@ -51,27 +51,6 @@ golang版本 >= 1.11
接口文档:[https://godoc.org/github.com/gogf/gf](https://godoc.org/github.com/gogf/gf)
# 使用
```go
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
)
func main() {
s := g.Server()
s.BindHandler("/", func(r *ghttp.Request) {
r.Response.Write("Hello World")
})
s.Run()
}
```
[更多..](https://goframe.org/start/index)
# 协议
`GF` 使用非常友好的 [MIT](LICENSE) 开源协议进行发布,永久`100%`开源免费。

View File

@ -57,7 +57,7 @@ func (v *Bool) Val() bool {
}
// Cas executes the compare-and-swap operation for value.
func (v *Bool) Cas(old, new bool) bool {
func (v *Bool) Cas(old, new bool) (swapped bool) {
var oldInt32, newInt32 int32
if old {
oldInt32 = 1

View File

@ -49,7 +49,7 @@ func (v *Byte) Add(delta byte) (new byte) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Byte) Cas(old, new byte) bool {
func (v *Byte) Cas(old, new byte) (swapped bool) {
return atomic.CompareAndSwapInt32(&v.value, int32(old), int32(new))
}

View File

@ -62,7 +62,7 @@ func (v *Float32) Add(delta float32) (new float32) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Float32) Cas(old, new float32) bool {
func (v *Float32) Cas(old, new float32) (swapped bool) {
return atomic.CompareAndSwapUint32(&v.value, math.Float32bits(old), math.Float32bits(new))
}

View File

@ -62,7 +62,7 @@ func (v *Float64) Add(delta float64) (new float64) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Float64) Cas(old, new float64) bool {
func (v *Float64) Cas(old, new float64) (swapped bool) {
return atomic.CompareAndSwapUint64(&v.value, math.Float64bits(old), math.Float64bits(new))
}

View File

@ -49,7 +49,7 @@ func (v *Int) Add(delta int) (new int) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Int) Cas(old, new int) bool {
func (v *Int) Cas(old, new int) (swapped bool) {
return atomic.CompareAndSwapInt64(&v.value, int64(old), int64(new))
}

View File

@ -49,7 +49,7 @@ func (v *Int32) Add(delta int32) (new int32) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Int32) Cas(old, new int32) bool {
func (v *Int32) Cas(old, new int32) (swapped bool) {
return atomic.CompareAndSwapInt32(&v.value, old, new)
}

View File

@ -49,7 +49,7 @@ func (v *Int64) Add(delta int64) (new int64) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Int64) Cas(old, new int64) bool {
func (v *Int64) Cas(old, new int64) (swapped bool) {
return atomic.CompareAndSwapInt64(&v.value, old, new)
}

View File

@ -49,7 +49,7 @@ func (v *Uint) Add(delta uint) (new uint) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Uint) Cas(old, new uint) bool {
func (v *Uint) Cas(old, new uint) (swapped bool) {
return atomic.CompareAndSwapUint64(&v.value, uint64(old), uint64(new))
}

View File

@ -49,7 +49,7 @@ func (v *Uint32) Add(delta uint32) (new uint32) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Uint32) Cas(old, new uint32) bool {
func (v *Uint32) Cas(old, new uint32) (swapped bool) {
return atomic.CompareAndSwapUint32(&v.value, old, new)
}

View File

@ -49,7 +49,7 @@ func (v *Uint64) Add(delta uint64) (new uint64) {
}
// Cas executes the compare-and-swap operation for value.
func (v *Uint64) Cas(old, new uint64) bool {
func (v *Uint64) Cas(old, new uint64) (swapped bool) {
return atomic.CompareAndSwapUint64(&v.value, old, new)
}

View File

@ -49,6 +49,12 @@ func BenchmarkInt_Add(b *testing.B) {
}
}
func BenchmarkInt_Cas(b *testing.B) {
for i := 0; i < b.N; i++ {
it.Cas(i, i)
}
}
func BenchmarkInt32_Set(b *testing.B) {
for i := int32(0); i < int32(b.N); i++ {
it32.Set(i)

View File

@ -844,16 +844,12 @@ func (m *Model) Count(where ...interface{}) (int, error) {
if len(where) > 0 {
return m.Where(where[0], where[1:]...).Count()
}
defer func(fields string) {
m.fields = fields
}(m.fields)
if m.fields == "" || m.fields == "*" {
m.fields = "COUNT(1)"
} else {
m.fields = fmt.Sprintf(`COUNT(%s)`, m.fields)
countFields := "COUNT(1)"
if m.fields != "" && m.fields != "*" {
countFields = fmt.Sprintf(`COUNT(%s)`, m.fields)
}
condition, conditionArgs := m.formatCondition(false)
s := fmt.Sprintf("SELECT %s FROM %s %s", m.fields, m.tables, condition)
s := fmt.Sprintf("SELECT %s FROM %s %s", countFields, m.tables, condition)
if len(m.groupBy) > 0 {
s = fmt.Sprintf("SELECT COUNT(1) FROM (%s) count_alias", s)
}

View File

@ -86,11 +86,19 @@ func (bs *dbBase) convertValue(fieldValue []byte, fieldType string) interface{}
return gconv.Int(string(fieldValue))
case strings.Contains(t, "time"):
t, _ := gtime.StrToTime(string(fieldValue))
s := string(fieldValue)
t, err := gtime.StrToTime(s)
if err != nil {
return s
}
return t.String()
case strings.Contains(t, "date"):
t, _ := gtime.StrToTime(string(fieldValue))
s := string(fieldValue)
t, err := gtime.StrToTime(s)
if err != nil {
return s
}
return t.Format("Y-m-d")
default:

View File

@ -24,6 +24,7 @@ func Test_Types(t *testing.T) {
%s blob NOT NULL,
%s binary(8) NOT NULL,
%s date NOT NULL,
%s time NOT NULL,
%s decimal(5,2) NOT NULL,
%s double NOT NULL,
%s bit(2) NOT NULL,
@ -31,7 +32,8 @@ func Test_Types(t *testing.T) {
%s bool NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
`, "`blob`", "`binary`", "`date`", "`decimal`", "`double`", "`bit`", "`tinyint`", "`bool`")); err != nil {
`, "`blob`", "`binary`", "`date`", "`time`",
"`decimal`", "`double`", "`bit`", "`tinyint`", "`bool`")); err != nil {
gtest.Error(err)
}
defer dropTable("types")
@ -40,6 +42,7 @@ func Test_Types(t *testing.T) {
"blob": "i love gf",
"binary": []byte("abcdefgh"),
"date": "2018-10-24",
"time": "10:00:01",
"decimal": 123.456,
"double": 123.456,
"bit": 2,
@ -57,6 +60,7 @@ func Test_Types(t *testing.T) {
gtest.Assert(one["blob"].String(), data["blob"])
gtest.Assert(one["binary"].String(), data["binary"])
gtest.Assert(one["date"].String(), data["date"])
gtest.Assert(one["time"].String(), data["time"])
gtest.Assert(one["decimal"].String(), 123.46)
gtest.Assert(one["double"].String(), data["double"])
gtest.Assert(one["bit"].Int(), data["bit"])

View File

@ -6,78 +6,3 @@
// Package gcompress provides kinds of compression algorithms for binary/bytes data.
package gcompress
import (
"bytes"
"compress/gzip"
"compress/zlib"
"io"
)
// Zlib compresses <data> with zlib algorithm.
func Zlib(data []byte) ([]byte, error) {
if data == nil || len(data) < 13 {
return data, nil
}
var in bytes.Buffer
var err error
w := zlib.NewWriter(&in)
if _, err = w.Write(data); err != nil {
return nil, err
}
if err = w.Close(); err != nil {
return in.Bytes(), err
}
return in.Bytes(), nil
}
// UnZlib decompresses <data> with zlib algorithm.
func UnZlib(data []byte) ([]byte, error) {
if data == nil || len(data) < 13 {
return data, nil
}
b := bytes.NewReader(data)
var out bytes.Buffer
var err error
r, err := zlib.NewReader(b)
if err != nil {
return nil, err
}
if _, err = io.Copy(&out, r); err != nil {
return nil, err
}
return out.Bytes(), nil
}
// Gzip compresses <data> with gzip algorithm.
func Gzip(data []byte) ([]byte, error) {
var buf bytes.Buffer
var err error
zip := gzip.NewWriter(&buf)
_, err = zip.Write(data)
if err != nil {
return nil, err
}
if err = zip.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// UnGzip decompresses <data> with gzip algorithm.
func UnGzip(data []byte) ([]byte, error) {
var buf bytes.Buffer
content := bytes.NewReader(data)
zipData, err := gzip.NewReader(content)
if err != nil {
return nil, err
}
if _, err = io.Copy(&buf, zipData); err != nil {
return nil, err
}
if err = zipData.Close(); err != nil {
return buf.Bytes(), err
}
return buf.Bytes(), nil
}

View File

@ -0,0 +1,55 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). 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 gcompress
import (
"bytes"
"compress/gzip"
"io"
)
// Gzip compresses <data> with gzip algorithm.
// The optional parameter <level> specifies the compression level from
// 1 to 9 which means from none to the best compression.
//
// Note that it returns error if given <level> is invalid.
func Gzip(data []byte, level ...int) ([]byte, error) {
var writer *gzip.Writer
var buf bytes.Buffer
var err error
if len(level) > 0 {
writer, err = gzip.NewWriterLevel(&buf, level[0])
if err != nil {
return nil, err
}
} else {
writer = gzip.NewWriter(&buf)
}
if _, err = writer.Write(data); err != nil {
return nil, err
}
if err = writer.Close(); err != nil {
return nil, err
}
return buf.Bytes(), nil
}
// UnGzip decompresses <data> with gzip algorithm.
func UnGzip(data []byte) ([]byte, error) {
var buf bytes.Buffer
reader, err := gzip.NewReader(bytes.NewReader(data))
if err != nil {
return nil, err
}
if _, err = io.Copy(&buf, reader); err != nil {
return nil, err
}
if err = reader.Close(); err != nil {
return buf.Bytes(), err
}
return buf.Bytes(), nil
}

View File

@ -24,7 +24,8 @@ import (
// ZipPath compresses <paths> to <dest> using zip compressing algorithm.
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
//
// Note that parameter <paths> supports multiple paths join with ','.
// Note that the parameter <paths> can be either a directory or a file, which
// supports multiple paths join with ','.
func ZipPath(paths, dest string, prefix ...string) error {
writer, err := os.Create(dest)
if err != nil {
@ -37,7 +38,8 @@ func ZipPath(paths, dest string, prefix ...string) error {
// ZipPathWriter compresses <paths> to <writer> using zip compressing algorithm.
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
//
// Note that parameter <paths> supports multiple paths join with ','.
// Note that the parameter <paths> can be either a directory or a file, which
// supports multiple paths join with ','.
func ZipPathWriter(paths string, writer io.Writer, prefix ...string) error {
zipWriter := zip.NewWriter(writer)
defer zipWriter.Close()
@ -51,24 +53,30 @@ func ZipPathWriter(paths string, writer io.Writer, prefix ...string) error {
}
func doZipPathWriter(path string, zipWriter *zip.Writer, prefix ...string) error {
var err error
var files []string
realPath, err := gfile.Search(path)
if err != nil {
return err
}
files, err := gfile.ScanDir(path, "*", true)
if err != nil {
return err
if gfile.IsDir(path) {
files, err = gfile.ScanDir(path, "*", true)
if err != nil {
return err
}
} else {
files = []string{path}
}
headerPrefix := ""
if len(prefix) > 0 && prefix[0] != "" {
headerPrefix = prefix[0]
}
headerPrefix = strings.TrimRight(headerPrefix, "\\/")
if gfile.IsDir(path) {
if len(headerPrefix) > 0 {
headerPrefix += "/"
}
headerPrefix = headerPrefix + gfile.Basename(path)
if len(headerPrefix) > 0 && gfile.IsDir(path) {
headerPrefix += "/"
}
if headerPrefix == "" {
headerPrefix = gfile.Basename(path)
}
headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
for _, file := range files {

View File

@ -0,0 +1,50 @@
// Copyright 2017 gf Author(https://github.com/gogf/gf). 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 gcompress provides kinds of compression algorithms for binary/bytes data.
package gcompress
import (
"bytes"
"compress/zlib"
"io"
)
// Zlib compresses <data> with zlib algorithm.
func Zlib(data []byte) ([]byte, error) {
if data == nil || len(data) < 13 {
return data, nil
}
var in bytes.Buffer
var err error
w := zlib.NewWriter(&in)
if _, err = w.Write(data); err != nil {
return nil, err
}
if err = w.Close(); err != nil {
return in.Bytes(), err
}
return in.Bytes(), nil
}
// UnZlib decompresses <data> with zlib algorithm.
func UnZlib(data []byte) ([]byte, error) {
if data == nil || len(data) < 13 {
return data, nil
}
b := bytes.NewReader(data)
var out bytes.Buffer
var err error
r, err := zlib.NewReader(b)
if err != nil {
return nil, err
}
if _, err = io.Copy(&out, r); err != nil {
return nil, err
}
return out.Bytes(), nil
}

View File

@ -1,23 +0,0 @@
// Copyright 2019 gf Author(https://github.com/gogf/gf). 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 utibytes provides some bytes functions for internal usage.
package utilbytes
import (
"bytes"
"fmt"
)
func Export(b []byte) string {
buffer := bytes.NewBuffer(nil)
buffer.WriteString(`[]byte("`)
for _, v := range b {
fmt.Fprintf(buffer, `\x%02x`, v)
}
buffer.WriteString(`")`)
return buffer.String()
}

View File

@ -90,16 +90,24 @@ func (r *Response) ServeFileDownload(path string, name ...string) {
r.Server.serveFile(r.Request, serveFile)
}
// RedirectTo redirects client to another location using http status 302.
func (r *Response) RedirectTo(location string) {
// RedirectTo redirects client to another location.
// The optional parameter <code> specifies the http status code for redirecting,
// which commonly can be 301 or 302. It's 302 in default.
func (r *Response) RedirectTo(location string, code ...int) {
r.Header().Set("Location", location)
r.WriteHeader(http.StatusFound)
if len(code) > 0 {
r.WriteHeader(code[0])
} else {
r.WriteHeader(http.StatusFound)
}
r.Request.Exit()
}
// RedirectBack redirects client back to referer using http status 302.
func (r *Response) RedirectBack() {
r.RedirectTo(r.Request.GetReferer())
// RedirectBack redirects client back to referer.
// The optional parameter <code> specifies the http status code for redirecting,
// which commonly can be 301 or 302. It's 302 in default.
func (r *Response) RedirectBack(code ...int) {
r.RedirectTo(r.Request.GetReferer(), code...)
}
// BufferString returns the buffered content as []byte.

View File

@ -20,28 +20,36 @@ import (
"github.com/gogf/gf/util/gconv"
)
// 静态文件目录映射关系对象
// staticPathItem is the item struct for static path configuration.
type staticPathItem struct {
prefix string // 映射的URI前缀
path string // 静态文件目录绝对路径
prefix string // The router URI.
path string // The static path.
}
// 设置http server参数 - IndexFiles默认展示文件index.html, index.htm
func (s *Server) SetIndexFiles(index []string) {
s.config.IndexFiles = index
// SetIndexFiles sets the index files for server.
func (s *Server) SetIndexFiles(indexFiles []string) {
s.config.IndexFiles = indexFiles
}
// 允许展示访问目录的文件列表
// GetIndexFiles retrieves and returns the index files from server.
func (s *Server) GetIndexFiles() []string {
return s.config.IndexFiles
}
// SetIndexFolder enables/disables listing the sub-files if requesting a directory.
func (s *Server) SetIndexFolder(enabled bool) {
s.config.IndexFolder = enabled
}
// 是否开启/关闭静态文件服务,当关闭时仅提供动态接口服务,路由性能会得到一定提升
// SetFileServerEnabled enables/disables the static file service.
// It's the main switch for the static file service. When static file service configuration
// functions like SetServerRoot, AddSearchPath and AddStaticPath are called, this configuration
// is automatically enabled.
func (s *Server) SetFileServerEnabled(enabled bool) {
s.config.FileServerEnabled = enabled
}
// 设置http server参数 - ServerRoot
// SetServerRoot sets the document root for static service.
func (s *Server) SetServerRoot(root string) {
realPath := root
if !gres.Contains(realPath) {
@ -56,7 +64,7 @@ func (s *Server) SetServerRoot(root string) {
s.config.FileServerEnabled = true
}
// 添加静态文件搜索**目录**,必须给定目录的绝对路径
// AddSearchPath add searching directory path for static file service.
func (s *Server) AddSearchPath(path string) {
realPath := path
if !gres.Contains(realPath) {
@ -70,7 +78,7 @@ func (s *Server) AddSearchPath(path string) {
s.config.FileServerEnabled = true
}
// 添加URI与静态**目录**的映射
// AddStaticPath sets the uri to static directory path mapping for static file service.
func (s *Server) AddStaticPath(prefix string, path string) {
realPath := path
if !gres.Contains(realPath) {

View File

@ -24,11 +24,11 @@ import (
"github.com/gogf/gf/os/gtime"
)
// 服务静态文件信息
// staticServeFile is the file struct for static service.
type staticServeFile struct {
file *gres.File // 资源文件
path string // 文件路径
dir bool // 是否目录
file *gres.File // Resource file object.
path string // File path.
dir bool // Is directory.
}
// 默认HTTP Server处理入口http包底层默认使用了gorutine异步处理请求所以这里不再异步执行
@ -172,7 +172,8 @@ func (s *Server) handleRequest(w http.ResponseWriter, r *http.Request) {
}
}
// 查找静态文件的绝对路径
// searchStaticFile searches the file with given URI.
// It returns a file struct specifying the file information.
func (s *Server) searchStaticFile(uri string) *staticServeFile {
var file *gres.File
var path string
@ -185,7 +186,6 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
if len(uri) > len(item.prefix) && uri[len(item.prefix)] != '/' {
continue
}
// Firstly searching resource manager.
file = gres.GetWithIndex(item.path+uri[len(item.prefix):], s.config.IndexFiles)
if file != nil {
return &staticServeFile{
@ -193,7 +193,6 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
dir: file.FileInfo().IsDir(),
}
}
// Secondly searching the file system.
path, dir = gspath.Search(item.path, uri[len(item.prefix):], s.config.IndexFiles...)
if path != "" {
return &staticServeFile{
@ -205,10 +204,9 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
}
}
}
// 其次查找root和search path
// Secondly search the root and searching paths.
if len(s.config.SearchPaths) > 0 {
for _, p := range s.config.SearchPaths {
// 优先检索资源管理器
file = gres.GetWithIndex(p+uri, s.config.IndexFiles)
if file != nil {
return &staticServeFile{
@ -216,7 +214,6 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
dir: file.FileInfo().IsDir(),
}
}
// 其次检索文件系统
if path, dir = gspath.Search(p, uri, s.config.IndexFiles...); path != "" {
return &staticServeFile{
path: path,
@ -225,7 +222,7 @@ func (s *Server) searchStaticFile(uri string) *staticServeFile {
}
}
}
// 最后通过资源对象+URI进行文件检索
// Lastly search the resource manager.
if len(s.config.StaticPaths) == 0 && len(s.config.SearchPaths) == 0 {
if file = gres.GetWithIndex(uri, s.config.IndexFiles); file != nil {
return &staticServeFile{

View File

@ -0,0 +1,60 @@
// Copyright 2018 gf Author(https://github.com/gogf/gf). 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.
// static service testing.
package ghttp_test
import (
"fmt"
"testing"
"time"
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/net/ghttp"
. "github.com/gogf/gf/test/gtest"
)
func TestServer_EnablePProf(t *testing.T) {
Case(t, func() {
p := ports.PopRand()
s := g.Server(p)
s.EnablePProf("/pprof")
s.SetDumpRouterMap(false)
s.SetPort(p)
s.Start()
defer s.Shutdown()
time.Sleep(100 * time.Millisecond)
client := ghttp.NewClient()
client.SetPrefix(fmt.Sprintf("http://127.0.0.1:%d", p))
r, err := client.Get("/pprof/index")
Assert(err, nil)
Assert(r.StatusCode, 200)
r.Close()
r, err = client.Get("/pprof/cmdline")
Assert(err, nil)
Assert(r.StatusCode, 200)
r.Close()
//r, err = client.Get("/pprof/profile")
//Assert(err, nil)
//Assert(r.StatusCode, 200)
//r.Close()
r, err = client.Get("/pprof/symbol")
Assert(err, nil)
Assert(r.StatusCode, 200)
r.Close()
r, err = client.Get("/pprof/trace")
Assert(err, nil)
Assert(r.StatusCode, 200)
r.Close()
})
}

View File

@ -63,18 +63,18 @@ func GetNameByAddr(ipAddress string) (string, error) {
}
// Ip2long converts ip address to an uint32 integer.
func Ip2long(ipAddress string) uint32 {
ip := net.ParseIP(ipAddress)
if ip == nil {
func Ip2long(ip string) uint32 {
netIp := net.ParseIP(ip)
if netIp == nil {
return 0
}
return binary.BigEndian.Uint32(ip.To4())
return binary.BigEndian.Uint32(netIp.To4())
}
// Long2ip converts an uint32 integer ip address to its string type address.
func Long2ip(properAddress uint32) string {
func Long2ip(long uint32) string {
ipByte := make([]byte, 4)
binary.BigEndian.PutUint32(ipByte, properAddress)
binary.BigEndian.PutUint32(ipByte, long)
return net.IP(ipByte).String()
}

View File

@ -77,7 +77,7 @@ func ParseWithArgs(args []string, supportedOptions map[string]bool, strict ...bo
} else {
if parser.isOptionValid(option) {
if parser.isOptionNeedArgument(option) {
if i+1 < len(args) {
if i < len(args)-1 {
parser.setOptionValue(option, args[i+1])
i += 2
continue
@ -171,8 +171,14 @@ func (p *Parser) GetOpt(name string, def ...string) string {
}
// GetOptVar returns the option value named <name> as *gvar.Var.
func (p *Parser) GetOptVar(name string, def ...string) *gvar.Var {
return gvar.New(p.GetOpt(name, def...))
func (p *Parser) GetOptVar(name string, def ...interface{}) *gvar.Var {
if p.ContainsOpt(name) {
return gvar.New(p.GetOpt(name))
}
if len(def) > 0 {
return gvar.New(def[0])
}
return gvar.New(nil)
}
// GetOptAll returns all parsed options.
@ -181,7 +187,7 @@ func (p *Parser) GetOptAll() map[string]string {
}
// ContainsOpt checks whether option named <name> exist in the arguments.
func (p *Parser) ContainsOpt(name string, def ...string) bool {
func (p *Parser) ContainsOpt(name string) bool {
_, ok := p.parsedOptions[name]
return ok
}

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,7 @@ var (
// Add unpacks and adds the <content> into the default resource object.
// The unnecessary parameter <prefix> indicates the prefix
// for each file storing into current resource object.
func Add(content []byte, prefix ...string) error {
func Add(content string, prefix ...string) error {
return defaultResource.Add(content, prefix...)
}

View File

@ -9,10 +9,11 @@ package gres
import (
"archive/zip"
"bytes"
"encoding/hex"
"fmt"
"github.com/gogf/gf/util/gconv"
"github.com/gogf/gf/encoding/gcompress"
"github.com/gogf/gf/internal/utilbytes"
"github.com/gogf/gf/os/gfile"
)
@ -22,7 +23,7 @@ const (
import "github.com/gogf/gf/os/gres"
func init() {
if err := gres.Add(%s); err != nil {
if err := gres.Add("%s"); err != nil {
panic(err)
}
}
@ -44,7 +45,8 @@ func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
// Gzip the data bytes to reduce the size.
return gcompress.Gzip(buffer.Bytes(), 9)
}
// PackToFile packs the path specified by <srcPaths> to target file <dstPath>.
@ -73,7 +75,8 @@ func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) erro
return err
}
return gfile.PutContents(
goFilePath, fmt.Sprintf(gPACKAGE_TEMPLATE, pkgName, utilbytes.Export(data)),
goFilePath,
fmt.Sprintf(gPACKAGE_TEMPLATE, pkgName, bytesToHexStr(data)),
)
}
@ -83,12 +86,16 @@ func Unpack(path string) ([]*File, error) {
if err != nil {
return nil, err
}
return UnpackContent(gfile.GetBytes(realPath))
return UnpackContent(gfile.GetContents(realPath))
}
// UnpackContent unpacks the content to []*File.
func UnpackContent(content []byte) ([]*File, error) {
reader, err := zip.NewReader(bytes.NewReader(content), int64(len(content)))
func UnpackContent(content string) ([]*File, error) {
data, err := gcompress.UnGzip(hexStrToBytes(content))
if err != nil {
return nil, err
}
reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil, err
}
@ -98,3 +105,18 @@ func UnpackContent(content []byte) ([]*File, error) {
}
return array, nil
}
// bytesToHexString converts binary content to hex string content.
func bytesToHexStr(b []byte) string {
dst := make([]byte, hex.EncodedLen(len(b)))
hex.Encode(dst, b)
return gconv.UnsafeBytesToStr(dst)
}
// hexStrToBytes converts hex string content to []byte.
func hexStrToBytes(s string) []byte {
src := gconv.UnsafeStrToBytes(s)
dst := make([]byte, hex.DecodedLen(len(src)))
hex.Decode(dst, src)
return dst
}

View File

@ -38,7 +38,7 @@ func New() *Resource {
// Add unpacks and adds the <content> into current resource object.
// The unnecessary parameter <prefix> indicates the prefix
// for each file storing into current resource object.
func (r *Resource) Add(content []byte, prefix ...string) error {
func (r *Resource) Add(content string, prefix ...string) error {
files, err := UnpackContent(content)
if err != nil {
return err
@ -62,7 +62,7 @@ func (r *Resource) Load(path string, prefix ...string) error {
if err != nil {
return err
}
return r.Add(gfile.GetBytes(realPath), prefix...)
return r.Add(gfile.GetContents(realPath), prefix...)
}
// Get returns the file with given path.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -47,6 +47,14 @@ func Test_NewFromStrFormat(t *testing.T) {
t.Error("test fail")
}
})
gtest.Case(t, func() {
t1 := gtime.NewFromStrFormat("2019/2/1", "Y/n/j")
gtest.Assert(t1.Format("Y-m-d"), "2019-02-01")
t2 := gtime.NewFromStrFormat("2019/10/12", "Y/n/j")
gtest.Assert(t2.Format("Y-m-d"), "2019-10-12")
})
}
func Test_NewFromStrLayout(t *testing.T) {

View File

@ -16,6 +16,8 @@ import (
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/text/gstr"
"github.com/gogf/gf/util/gconv"
htmltpl "html/template"
)
// funcDump implements build-in template function: dump
@ -85,7 +87,8 @@ func (view *View) funcGe(value, other interface{}) bool {
}
// funcInclude implements build-in template function: include
func (view *View) funcInclude(file interface{}, data ...map[string]interface{}) string {
// Note that configuration AutoEncode does not affect the output of this function.
func (view *View) funcInclude(file interface{}, data ...map[string]interface{}) htmltpl.HTML {
var m map[string]interface{} = nil
if len(data) > 0 {
m = data[0]
@ -97,9 +100,9 @@ func (view *View) funcInclude(file interface{}, data ...map[string]interface{})
// It will search the file internally.
content, err := view.Parse(path, m)
if err != nil {
return err.Error()
return htmltpl.HTML(err.Error())
}
return content
return htmltpl.HTML(content)
}
// funcText implements build-in template function: text

View File

@ -1,4 +1,4 @@
package gf
const VERSION = "v1.11.2"
const VERSION = "v1.11.3"
const AUTHORS = "john<john@goframe.org>"