mirror of
https://gitee.com/johng/gf
synced 2026-06-07 10:22:11 +08:00
merge master
This commit is contained in:
226
README.MD
226
README.MD
@ -40,6 +40,7 @@ golang version >= 1.10
|
||||
|
||||
# Quick Start
|
||||
|
||||
## Hello World
|
||||
```go
|
||||
package main
|
||||
|
||||
@ -56,8 +57,231 @@ func main() {
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Rich Router
|
||||
```go
|
||||
package main
|
||||
|
||||
[View More..](https://goframe.org/start/index)
|
||||
import (
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
"github.com/gogf/gf/g"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/{class}-{course}/:name/*act", func(r *ghttp.Request) {
|
||||
r.Response.Writeln(r.Get("class"))
|
||||
r.Response.Writeln(r.Get("course"))
|
||||
r.Response.Writeln(r.Get("name"))
|
||||
r.Response.Writeln(r.Get("act"))
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Group Routers
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
type Object struct {}
|
||||
|
||||
func (o *Object) Show(r *ghttp.Request) {
|
||||
r.Response.Writeln("Object Show")
|
||||
}
|
||||
|
||||
func (o *Object) Delete(r *ghttp.Request) {
|
||||
r.Response.Writeln("Object REST Delete")
|
||||
}
|
||||
|
||||
func Handler(r *ghttp.Request) {
|
||||
r.Response.Writeln("Handler")
|
||||
}
|
||||
|
||||
func HookHandler(r *ghttp.Request) {
|
||||
r.Response.Writeln("Hook Handler")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
obj := new(Object)
|
||||
group := s.Group("/api")
|
||||
group.ALL ("*", HookHandler, ghttp.HOOK_BEFORE_SERVE)
|
||||
group.ALL ("/handler", Handler)
|
||||
group.ALL ("/obj", obj)
|
||||
group.GET ("/obj/showit", obj, "Show")
|
||||
group.REST("/obj/rest", obj)
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
or
|
||||
```go
|
||||
func main() {
|
||||
s := g.Server()
|
||||
obj := new(Object)
|
||||
s.Group("/api").Bind([]ghttp.GroupItem{
|
||||
{"ALL", "*", HookHandler, ghttp.HOOK_BEFORE_SERVE},
|
||||
{"ALL", "/handler", Handler},
|
||||
{"ALL", "/obj", obj},
|
||||
{"GET", "/obj/showit", obj, "Show"},
|
||||
{"REST", "/obj/rest", obj},
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Multi ports & domains
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func Hello1(r *ghttp.Request) {
|
||||
r.Response.Write("127.0.0.1: Hello1!")
|
||||
}
|
||||
|
||||
func Hello2(r *ghttp.Request) {
|
||||
r.Response.Write("localhost: Hello2!")
|
||||
}
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.Domain("127.0.0.1").BindHandler("/", Hello1)
|
||||
s.Domain("localhost").BindHandler("/", Hello2)
|
||||
s.SetPort(8100, 8200, 8300)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## Template Engine
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/net/ghttp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
s := g.Server()
|
||||
s.BindHandler("/template", func(r *ghttp.Request) {
|
||||
r.Response.WriteTpl("index.tpl", g.Map{
|
||||
"id": 123,
|
||||
"name": "john",
|
||||
})
|
||||
})
|
||||
s.SetPort(8199)
|
||||
s.Run()
|
||||
}
|
||||
```
|
||||
## File Uploading
|
||||
```go
|
||||
func Upload(r *ghttp.Request) {
|
||||
if f, h, e := r.FormFile("upload-file"); e == nil {
|
||||
defer f.Close()
|
||||
name := gfile.Basename(h.Filename)
|
||||
buffer := make([]byte, h.Size)
|
||||
f.Read(buffer)
|
||||
gfile.PutBinContents("/tmp/" + name, buffer)
|
||||
r.Response.Write(name + " uploaded successly")
|
||||
} else {
|
||||
r.Response.Write(e.Error())
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ORM Operations
|
||||
|
||||
### 1. Retrieving instance
|
||||
```go
|
||||
db := g.DB()
|
||||
db := g.DB("user-center")
|
||||
```
|
||||
### 2. Chaining Operations
|
||||
|
||||
`Where + string`
|
||||
```go
|
||||
// SELECT * FROM user WHERE uid>1 LIMIT 0,10
|
||||
r, err := db.Table("user").Where("uid > ?", 1).Limit(0, 10).Select()
|
||||
|
||||
// SELECT uid,name FROM user WHERE uid>1 LIMIT 0,10
|
||||
r, err := db.Table("user").Fileds("uid,name").Where("uid > ?", 1).Limit(0, 10).Select()
|
||||
|
||||
// SELECT * FROM user WHERE uid=1
|
||||
r, err := db.Table("user").Where("u.uid=1",).One()
|
||||
r, err := db.Table("user").Where("u.uid", 1).One()
|
||||
r, err := db.Table("user").Where("u.uid=?", 1).One()
|
||||
// SELECT * FROM user WHERE (uid=1) AND (name='john')
|
||||
r, err := db.Table("user").Where("uid", 1).Where("name", "john").One()
|
||||
r, err := db.Table("user").Where("uid=?", 1).And("name=?", "john").One()
|
||||
// SELECT * FROM user WHERE (uid=1) OR (name='john')
|
||||
r, err := db.Table("user").Where("uid=?", 1).Or("name=?", "john").One()
|
||||
```
|
||||
`Where + map`
|
||||
```go
|
||||
// SELECT * FROM user WHERE uid=1 AND name='john'
|
||||
r, err := db.Table("user").Where(g.Map{"uid" : 1, "name" : "john"}).One()
|
||||
// SELECT * FROM user WHERE uid=1 AND age>18
|
||||
r, err := db.Table("user").Where(g.Map{"uid" : 1, "age>" : 18}).One()
|
||||
```
|
||||
`Where + struct/*struct`
|
||||
```go
|
||||
type User struct {
|
||||
Id int `json:"uid"`
|
||||
UserName string `gconv:"name"`
|
||||
}
|
||||
// SELECT * FROM user WHERE uid =1 AND name='john'
|
||||
r, err := db.Table("user").Where(User{ Id : 1, UserName : "john"}).One()
|
||||
// SELECT * FROM user WHERE uid =1
|
||||
r, err := db.Table("user").Where(&User{ Id : 1}).One()
|
||||
```
|
||||
### 3. Update & Delete
|
||||
```go
|
||||
// UPDATE user SET name='john guo' WHERE name='john'
|
||||
r, err := db.Table("user").Data(gdb.Map{"name" : "john guo"}).Where("name=?", "john").Update()
|
||||
r, err := db.Table("user").Data("name='john guo'").Where("name=?", "john").Update()
|
||||
// UPDATE user SET status=1 ORDER BY login_time asc LIMIT 10
|
||||
r, err := db.Table("user").Data("status", 1).OrderBy("login_time asc").Limit(10).Update
|
||||
|
||||
// DELETE FROM user WHERE uid=10
|
||||
r, err := db.Table("user").Where("uid=?", 10).Delete()
|
||||
// DELETE FROM user ORDER BY login_time asc LIMIT 10
|
||||
r, err := db.Table("user").OrderBy("login_time asc").Limit(10).Delete()
|
||||
```
|
||||
### 4. Insert & Replace & Save
|
||||
```go
|
||||
r, err := db.Table("user").Data(g.Map{"name": "john"}).Insert()
|
||||
r, err := db.Table("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()
|
||||
r, err := db.Table("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()
|
||||
```
|
||||
### 5. Transaction
|
||||
```go
|
||||
if tx, err := db.Begin(); err == nil {
|
||||
r, err := tx.Save("user", g.Map{
|
||||
"uid" : 1,
|
||||
"name" : "john",
|
||||
})
|
||||
tx.Commit()
|
||||
}
|
||||
```
|
||||
### 6. Error Handling
|
||||
```go
|
||||
func GetOrderInfo(id int) (order *Order, err error) {
|
||||
err = g.DB().Table("order").Where("id", id).Struct(&order)
|
||||
if err != nil && err == sql.ErrNoRows {
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
```
|
||||
|
||||
[More Features...](https://goframe.org/start/index)
|
||||
|
||||
|
||||
# License
|
||||
|
||||
@ -58,33 +58,6 @@ func (v *Var) Interface() interface{} {
|
||||
return v.Val()
|
||||
}
|
||||
|
||||
// Time converts and returns <v> as time.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) Time(format ...string) time.Time {
|
||||
return gconv.Time(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Duration converts and returns <v> as time.Duration.
|
||||
// If value of <v> is string, then it uses time.ParseDuration for conversion.
|
||||
func (v *Var) Duration() time.Duration {
|
||||
return gconv.Duration(v.Val())
|
||||
}
|
||||
|
||||
// GTime converts and returns <v> as *gtime.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) GTime(format ...string) *gtime.Time {
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <objPointer>.
|
||||
// The parameter <objPointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// IsNil checks whether <v> is nil.
|
||||
func (v *Var) IsNil() bool {
|
||||
return v.Val() == nil
|
||||
@ -184,3 +157,57 @@ func (v *Var) Strings() []string {
|
||||
func (v *Var) Interfaces() []interface{} {
|
||||
return gconv.Interfaces(v.Val())
|
||||
}
|
||||
|
||||
// Time converts and returns <v> as time.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) Time(format ...string) time.Time {
|
||||
return gconv.Time(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Duration converts and returns <v> as time.Duration.
|
||||
// If value of <v> is string, then it uses time.ParseDuration for conversion.
|
||||
func (v *Var) Duration() time.Duration {
|
||||
return gconv.Duration(v.Val())
|
||||
}
|
||||
|
||||
// GTime converts and returns <v> as *gtime.Time.
|
||||
// The parameter <format> specifies the format of the time string using gtime,
|
||||
// eg: Y-m-d H:i:s.
|
||||
func (v *Var) GTime(format ...string) *gtime.Time {
|
||||
return gconv.GTime(v.Val(), format...)
|
||||
}
|
||||
|
||||
// Map converts <v> to map[string]interface{}.
|
||||
func (v *Var) Map(tags ...string) map[string]interface{} {
|
||||
return gconv.Map(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// MapDeep converts <v> to map[string]interface{} recursively.
|
||||
func (v *Var) MapDeep(tags ...string) map[string]interface{} {
|
||||
return gconv.MapDeep(v.Val(), tags...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <pointer>.
|
||||
// The parameter <pointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) Struct(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Struct(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// Struct maps value of <v> to <pointer> recursively.
|
||||
// The parameter <pointer> should be a pointer to a struct instance.
|
||||
// The parameter <mapping> is used to specify the key-to-attribute mapping rules.
|
||||
func (v *Var) StructDeep(pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.StructDeep(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// Structs converts <v> to given struct slice.
|
||||
func (v *Var) Structs(pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return gconv.Structs(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
// StructsDeep converts <v> to given struct slice recursively.
|
||||
func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return gconv.StructsDeep(v.Val(), pointer, mapping...)
|
||||
}
|
||||
|
||||
@ -673,6 +673,21 @@ func TestModel_Where(t *testing.T) {
|
||||
gtest.Assert(err, nil)
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// slice
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Where("id=? AND nickname=?", g.Slice{3, "T3"}...).One()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Where("passport like ? and nickname like ?", g.Slice{"t3", "T3"}...).One()
|
||||
if err != nil {
|
||||
gtest.Fatal(err)
|
||||
}
|
||||
gtest.Assert(result["id"].Int(), 3)
|
||||
})
|
||||
// map
|
||||
gtest.Case(t, func() {
|
||||
result, err := db.Table("user").Where(g.Map{"id": 3, "nickname": "T3"}).One()
|
||||
|
||||
@ -22,10 +22,7 @@ func Encode(src []byte) []byte {
|
||||
func Decode(dst []byte) ([]byte, error) {
|
||||
src := make([]byte, base64.StdEncoding.DecodedLen(len(dst)))
|
||||
n, err := base64.StdEncoding.Decode(src, dst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return src[:n], nil
|
||||
return src[:n], err
|
||||
}
|
||||
|
||||
// EncodeString encodes bytes with BASE64 algorithm.
|
||||
|
||||
@ -266,11 +266,32 @@ func (j *Json) GetToVar(pattern string, pointer interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetToStruct gets the value by specified <pattern>,
|
||||
// and converts it to specified object <objPointer>.
|
||||
// The <objPointer> should be the pointer to an object.
|
||||
func (j *Json) GetToStruct(pattern string, pointer interface{}) error {
|
||||
return gconv.Struct(j.Get(pattern), pointer)
|
||||
// GetStruct gets the value by specified <pattern>,
|
||||
// and converts it to specified object <pointer>.
|
||||
// The <pointer> should be the pointer to an object.
|
||||
func (j *Json) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Struct(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructDeep does GetStruct recursively.
|
||||
func (j *Json) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.StructDeep(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructs converts any slice to given struct slice.
|
||||
func (j *Json) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.Structs(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructsDeep converts any slice to given struct slice recursively.
|
||||
func (j *Json) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return gconv.StructsDeep(j.Get(pattern), pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetToStruct is alias of GetStruct.
|
||||
// Deprecated.
|
||||
func (j *Json) GetToStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return j.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// ToMap converts current Json object to map[string]interface{}.
|
||||
@ -290,7 +311,7 @@ func (j *Json) ToArray() []interface{} {
|
||||
}
|
||||
|
||||
// ToStruct converts current Json object to specified object.
|
||||
// The <objPointer> should be a pointer type.
|
||||
// The <pointer> should be a pointer type.
|
||||
func (j *Json) ToStruct(pointer interface{}) error {
|
||||
j.mu.RLock()
|
||||
defer j.mu.RUnlock()
|
||||
|
||||
@ -145,11 +145,32 @@ func (p *Parser) GetToVar(pattern string, pointer interface{}) error {
|
||||
return p.json.GetToVar(pattern, pointer)
|
||||
}
|
||||
|
||||
// GetToStruct gets the value by specified <pattern>,
|
||||
// GetStruct gets the value by specified <pattern>,
|
||||
// and converts it to specified object <pointer>.
|
||||
// The <pointer> should be the pointer to a struct.
|
||||
func (p *Parser) GetToStruct(pattern string, pointer interface{}) error {
|
||||
return p.json.GetToStruct(pattern, pointer)
|
||||
// The <pointer> should be the pointer to an object.
|
||||
func (p *Parser) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructDeep does GetStruct recursively.
|
||||
func (p *Parser) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStructDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructs converts any slice to given struct slice.
|
||||
func (p *Parser) GetStructs(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStructs(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetStructsDeep converts any slice to given struct slice recursively.
|
||||
func (p *Parser) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStructsDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// GetToStruct is alias of GetStruct.
|
||||
// Deprecated.
|
||||
func (p *Parser) GetToStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
return p.json.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
|
||||
// Set sets value with specified <pattern>.
|
||||
|
||||
@ -154,5 +154,5 @@ func (r *Request) GetPostToStruct(pointer interface{}, mapping ...map[string]str
|
||||
for k, v := range r.GetPostMap() {
|
||||
params[k] = v
|
||||
}
|
||||
return gconv.Struct(params, pointer, tagMap)
|
||||
return gconv.StructDeep(params, pointer, tagMap)
|
||||
}
|
||||
|
||||
@ -489,14 +489,41 @@ func (c *Config) GetGTime(pattern string, format ...string) *gtime.Time {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Config) GetToStruct(pattern string, pointer interface{}, def ...interface{}) error {
|
||||
func (c *Config) GetStruct(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetToStruct(pattern, pointer)
|
||||
return j.GetStruct(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
// Deprecated. See Clear.
|
||||
func (c *Config) GetStructDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetStructDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
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 errors.New("config file not found")
|
||||
}
|
||||
|
||||
func (c *Config) GetStructsDeep(pattern string, pointer interface{}, mapping ...map[string]string) error {
|
||||
if j := c.getJson(); j != nil {
|
||||
return j.GetStructsDeep(pattern, pointer, mapping...)
|
||||
}
|
||||
return errors.New("config file not found")
|
||||
}
|
||||
|
||||
// Deprecated.
|
||||
func (c *Config) GetToStruct(pattern string, pointer interface{}) error {
|
||||
return c.GetStruct(pattern, pointer)
|
||||
}
|
||||
|
||||
// Reload is alias of Clear.
|
||||
// Deprecated.
|
||||
func (c *Config) Reload() {
|
||||
c.jsons.Clear()
|
||||
}
|
||||
|
||||
@ -11,11 +11,8 @@ import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/user"
|
||||
@ -24,6 +21,11 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/gogf/gf/g/container/gtype"
|
||||
"github.com/gogf/gf/g/text/gregex"
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
"github.com/gogf/gf/g/util/gconv"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -142,29 +144,109 @@ func Rename(src string, dst string) error {
|
||||
return Move(src, dst)
|
||||
}
|
||||
|
||||
// Copy file from <src> to <dst>.
|
||||
// Copy file/directory from <src> to <dst>.
|
||||
//
|
||||
// @TODO directory copy support.
|
||||
// If <src> is file, it calls CopyFile to implements copy feature,
|
||||
// or else it calls CopyDir.
|
||||
func Copy(src string, dst string) error {
|
||||
srcFile, err := Open(src)
|
||||
if IsFile(src) {
|
||||
return CopyFile(src, dst)
|
||||
}
|
||||
return CopyDir(src, dst)
|
||||
}
|
||||
|
||||
// CopyFile copies the contents of the file named src to the file named
|
||||
// by dst. The file will be created if it does not already exist. If the
|
||||
// destination file exists, all it's contents will be replaced by the contents
|
||||
// of the source file. The file mode will be copied from the source and
|
||||
// the copied data is synced/flushed to stable storage.
|
||||
// Thanks: https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04
|
||||
func CopyFile(src, dst string) (err error) {
|
||||
in, err := os.Open(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if e := in.Close(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
out, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
defer func() {
|
||||
if e := out.Close(); e != nil {
|
||||
err = e
|
||||
}
|
||||
}()
|
||||
_, err = io.Copy(out, in)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = out.Sync()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = os.Chmod(dst, si.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// CopyDir recursively copies a directory tree, attempting to preserve permissions.
|
||||
// Source directory must exist, destination directory must *not* exist.
|
||||
// Symlinks are ignored and skipped.
|
||||
func CopyDir(src string, dst string) (err error) {
|
||||
src = filepath.Clean(src)
|
||||
dst = filepath.Clean(dst)
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
dstFile, err := Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
if !si.IsDir() {
|
||||
return fmt.Errorf("source is not a directory")
|
||||
}
|
||||
defer dstFile.Close()
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
_, err = os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return
|
||||
}
|
||||
err = dstFile.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
if err == nil {
|
||||
return fmt.Errorf("destination already exists")
|
||||
}
|
||||
return nil
|
||||
err = os.MkdirAll(dst, si.Mode())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
entries, err := ioutil.ReadDir(src)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
if entry.IsDir() {
|
||||
err = CopyDir(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
// Skip symlinks.
|
||||
if entry.Mode()&os.ModeSymlink != 0 {
|
||||
continue
|
||||
}
|
||||
err = CopyFile(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DirNames returns sub-file names of given directory <path>.
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
package gfile_test
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gogf/gf/g/os/gfile"
|
||||
"github.com/gogf/gf/g/test/gtest"
|
||||
)
|
||||
|
||||
func TestIsDir(t *testing.T) {
|
||||
@ -677,3 +678,71 @@ func TestMainPkgPath(t *testing.T) {
|
||||
gtest.Assert(reads, "")
|
||||
})
|
||||
}
|
||||
|
||||
func TestCopyFile(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var (
|
||||
paths string = "/testfile_copyfile1.txt"
|
||||
topath string = "/testfile_copyfile2.txt"
|
||||
)
|
||||
|
||||
createTestFile(paths, "")
|
||||
defer delTestFiles(paths)
|
||||
|
||||
gtest.Assert(gfile.CopyFile(testpath()+paths, testpath()+topath), nil)
|
||||
defer delTestFiles(topath)
|
||||
|
||||
gtest.Assert(gfile.IsFile(testpath()+topath), true)
|
||||
gtest.AssertNE(gfile.CopyFile("", ""), nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestCopyDir(t *testing.T) {
|
||||
gtest.Case(t, func() {
|
||||
var (
|
||||
dirpath1 string = "/testcopydir1"
|
||||
dirpath2 string = "/testcopydir2"
|
||||
)
|
||||
|
||||
havelist1 := []string{
|
||||
"t1.txt",
|
||||
"t2.txt",
|
||||
}
|
||||
|
||||
createDir(dirpath1)
|
||||
for _, v := range havelist1 {
|
||||
createTestFile(dirpath1+"/"+v, "")
|
||||
}
|
||||
defer delTestFiles(dirpath1)
|
||||
|
||||
yfolder := testpath() + dirpath1
|
||||
tofolder := testpath() + dirpath2
|
||||
|
||||
if gfile.IsDir(tofolder) {
|
||||
gtest.Assert(gfile.Remove(tofolder), nil)
|
||||
gtest.Assert(gfile.Remove(""), nil)
|
||||
}
|
||||
|
||||
gtest.Assert(gfile.CopyDir(yfolder, tofolder), nil)
|
||||
defer delTestFiles(tofolder)
|
||||
|
||||
// 检查复制后的旧文件夹是否真实存在
|
||||
gtest.Assert(gfile.IsDir(yfolder), true)
|
||||
|
||||
// 检查复制后的旧文件夹中的文件是否真实存在
|
||||
for _, v := range havelist1 {
|
||||
gtest.Assert(gfile.IsFile(yfolder+"/"+v), true)
|
||||
}
|
||||
|
||||
// 检查复制后的新文件夹是否真实存在
|
||||
gtest.Assert(gfile.IsDir(tofolder), true)
|
||||
|
||||
// 检查复制后的新文件夹中的文件是否真实存在
|
||||
for _, v := range havelist1 {
|
||||
gtest.Assert(gfile.IsFile(tofolder+"/"+v), true)
|
||||
}
|
||||
|
||||
gtest.Assert(gfile.Remove(tofolder), nil)
|
||||
gtest.Assert(gfile.Remove(""), nil)
|
||||
})
|
||||
}
|
||||
|
||||
@ -7,8 +7,6 @@
|
||||
package gfsnotify
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/gogf/gf/g/container/glist"
|
||||
)
|
||||
|
||||
@ -23,7 +21,7 @@ func (w *Watcher) startWatchLoop() {
|
||||
|
||||
// 监听事件
|
||||
case ev := <-w.watcher.Events:
|
||||
fmt.Println("ev:", ev.String())
|
||||
//fmt.Println("ev:", ev.String())
|
||||
w.cache.SetIfNotExist(ev.String(), func() interface{} {
|
||||
w.events.Push(&Event{
|
||||
event: ev,
|
||||
|
||||
@ -14,6 +14,46 @@ import (
|
||||
"github.com/gogf/gf/g/text/gstr"
|
||||
)
|
||||
|
||||
// SliceInt is alias of Ints.
|
||||
func SliceInt(i interface{}) []int {
|
||||
return Ints(i)
|
||||
}
|
||||
|
||||
// SliceStr is alias of Strings.
|
||||
func SliceStr(i interface{}) []string {
|
||||
return Strings(i)
|
||||
}
|
||||
|
||||
// SliceAny is alias of Interfaces.
|
||||
func SliceAny(i interface{}) []interface{} {
|
||||
return Interfaces(i)
|
||||
}
|
||||
|
||||
// SliceFloat is alias of Floats.
|
||||
func SliceFloat(i interface{}) []float64 {
|
||||
return Floats(i)
|
||||
}
|
||||
|
||||
// SliceMap is alias of Maps.
|
||||
func SliceMap(i interface{}) []map[string]interface{} {
|
||||
return Maps(i)
|
||||
}
|
||||
|
||||
// SliceMapDeep is alias of MapsDeep.
|
||||
func SliceMapDeep(i interface{}) []map[string]interface{} {
|
||||
return MapsDeep(i)
|
||||
}
|
||||
|
||||
// SliceStruct is alias of Structs.
|
||||
func SliceStruct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return Structs(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// SliceStructDeep is alias of StructsDeep.
|
||||
func SliceStructDeep(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return StructsDeep(params, pointer, mapping...)
|
||||
}
|
||||
|
||||
// Ints converts <i> to []int.
|
||||
func Ints(i interface{}) []int {
|
||||
if i == nil {
|
||||
@ -350,6 +390,26 @@ func Maps(i interface{}) []map[string]interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
// MapsDeep converts <i> to []map[string]interface{} recursively.
|
||||
func MapsDeep(i interface{}) []map[string]interface{} {
|
||||
if i == nil {
|
||||
return nil
|
||||
}
|
||||
if r, ok := i.([]map[string]interface{}); ok {
|
||||
return r
|
||||
} else {
|
||||
array := Interfaces(i)
|
||||
if len(array) == 0 {
|
||||
return nil
|
||||
}
|
||||
list := make([]map[string]interface{}, len(array))
|
||||
for k, v := range array {
|
||||
list[k] = MapDeep(v)
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
// Structs converts any slice to given struct slice.
|
||||
func Structs(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
|
||||
return doStructs(params, pointer, false, mapping...)
|
||||
|
||||
@ -1,27 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gogf/gf/g"
|
||||
"github.com/gogf/gf/g/util/gvalid"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"github.com/gogf/gf/g/encoding/gbase64"
|
||||
)
|
||||
|
||||
func main() {
|
||||
type Pass struct {
|
||||
Pass1 string `valid:"password1@required|same:password2#请输入您的密码|您两次输入的密码不一致"`
|
||||
Pass2 string `valid:"password2@required|same:password1#请再次输入您的密码|您两次输入的密码不一致"`
|
||||
}
|
||||
type User struct {
|
||||
Id int
|
||||
Name string `valid:"name@required#请输入您的姓名"`
|
||||
Pass Pass
|
||||
}
|
||||
user := &User{
|
||||
Name: "john",
|
||||
Pass: Pass{
|
||||
Pass1: "1",
|
||||
Pass2: "2",
|
||||
},
|
||||
}
|
||||
err := gvalid.CheckStruct(user, nil)
|
||||
g.Dump(err.Maps())
|
||||
data := "HwHsGhXMaGc==="
|
||||
datab, err := gbase64.Decode([]byte(data))
|
||||
fmt.Println(err)
|
||||
fmt.Println(datab)
|
||||
fmt.Println(string(datab))
|
||||
|
||||
s, e := base64.StdEncoding.DecodeString(data)
|
||||
fmt.Println(e)
|
||||
fmt.Println(string(s))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user