From 8669057681b44d3bbfb8914918437326d3983d2b Mon Sep 17 00:00:00 2001 From: John Date: Sat, 6 Jul 2019 21:44:31 +0800 Subject: [PATCH 01/10] remove debug line --- g/os/gfsnotify/gfsnotify_watcher_loop.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/g/os/gfsnotify/gfsnotify_watcher_loop.go b/g/os/gfsnotify/gfsnotify_watcher_loop.go index 0fe2215a3..1199fb65f 100644 --- a/g/os/gfsnotify/gfsnotify_watcher_loop.go +++ b/g/os/gfsnotify/gfsnotify_watcher_loop.go @@ -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, From 8cfdc8f27fa4046664788f3e4ac42ecfcd2f5126 Mon Sep 17 00:00:00 2001 From: skiy Date: Mon, 8 Jul 2019 01:26:00 +0800 Subject: [PATCH 02/10] file and folder copy --- g/os/gfile/gfile.go | 104 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/g/os/gfile/gfile.go b/g/os/gfile/gfile.go index 81db327e2..931f3d9f1 100644 --- a/g/os/gfile/gfile.go +++ b/g/os/gfile/gfile.go @@ -16,6 +16,7 @@ import ( "github.com/gogf/gf/g/text/gstr" "github.com/gogf/gf/g/util/gconv" "io" + "io/ioutil" "os" "os/exec" "os/user" @@ -450,3 +451,106 @@ func MainPkgPath() string { func TempDir() string { return os.TempDir() } + +// https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 +// 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. +func CopyFile(src, dst string) (err error) { + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + + 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 + } + if !si.IsDir() { + return fmt.Errorf("source is not a directory") + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return + } + if err == nil { + return fmt.Errorf("destination already exists") + } + + 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 +} \ No newline at end of file From 7c4431ceebe788c4f95aa11fd1301fd997177d0f Mon Sep 17 00:00:00 2001 From: skiy Date: Mon, 8 Jul 2019 11:37:02 +0800 Subject: [PATCH 03/10] add copyfile & copydir test --- g/os/gfile/gfile.go | 11 +++--- g/os/gfile/gfile_z_test.go | 73 ++++++++++++++++++++++++++++++++++++-- go.mod | 2 ++ 3 files changed, 79 insertions(+), 7 deletions(-) diff --git a/g/os/gfile/gfile.go b/g/os/gfile/gfile.go index 931f3d9f1..22cda24e2 100644 --- a/g/os/gfile/gfile.go +++ b/g/os/gfile/gfile.go @@ -11,10 +11,6 @@ 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" @@ -25,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 ( @@ -553,4 +554,4 @@ func CopyDir(src string, dst string) (err error) { } return -} \ No newline at end of file +} diff --git a/g/os/gfile/gfile_z_test.go b/g/os/gfile/gfile_z_test.go index b7d438434..44b8008ed 100644 --- a/g/os/gfile/gfile_z_test.go +++ b/g/os/gfile/gfile_z_test.go @@ -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) + }) +} diff --git a/go.mod b/go.mod index ef37cb8d6..081d99cd0 100644 --- a/go.mod +++ b/go.mod @@ -1 +1,3 @@ module github.com/gogf/gf + +go 1.12 From 3b0012ec30d930b98e3fa859edd78427e5886f6d Mon Sep 17 00:00:00 2001 From: john Date: Tue, 9 Jul 2019 08:07:50 +0800 Subject: [PATCH 04/10] fix issue in gbase64.Decode --- g/encoding/gbase64/gbase64.go | 5 +---- geg/other/test.go | 29 +++++++++++------------------ 2 files changed, 12 insertions(+), 22 deletions(-) diff --git a/g/encoding/gbase64/gbase64.go b/g/encoding/gbase64/gbase64.go index e19733002..0a01680ff 100644 --- a/g/encoding/gbase64/gbase64.go +++ b/g/encoding/gbase64/gbase64.go @@ -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. diff --git a/geg/other/test.go b/geg/other/test.go index 9454d714c..381a581b9 100644 --- a/geg/other/test.go +++ b/geg/other/test.go @@ -1,26 +1,19 @@ package main import ( + "encoding/base64" "fmt" - - "github.com/gogf/gf/g" + "github.com/gogf/gf/g/encoding/gbase64" ) -type User struct { - Uid int - Name string -} - func main() { - if r, err := g.DB().Table("user").Where("uid=?", 1).One(); r != nil { - u := new(User) - if err := r.ToStruct(u); err == nil { - fmt.Println(" uid:", u.Uid) - fmt.Println("name:", u.Name) - } else { - fmt.Println(err) - } - } else if err != nil { - fmt.Println(err) - } + 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)) } From c84e62febe97c4d721aa4e0700a7001ebf18def2 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 9 Jul 2019 08:47:23 +0800 Subject: [PATCH 05/10] add morte unit test cases for gdb.Model --- g/database/gdb/gdb_unit_model_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/g/database/gdb/gdb_unit_model_test.go b/g/database/gdb/gdb_unit_model_test.go index 1daf31db4..7b47901da 100644 --- a/g/database/gdb/gdb_unit_model_test.go +++ b/g/database/gdb/gdb_unit_model_test.go @@ -652,6 +652,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() From 6a93d166c5e5c38883da30412fa2029313839d69 Mon Sep 17 00:00:00 2001 From: john Date: Tue, 9 Jul 2019 09:43:53 +0800 Subject: [PATCH 06/10] improve gjson/gparser/gvar/gcfg with adding more converting functions --- g/container/gvar/gvar.go | 81 ++++++++++++++++++++----------- g/encoding/gjson/gjson_api.go | 33 ++++++++++--- g/encoding/gparser/gparser_api.go | 29 +++++++++-- g/net/ghttp/ghttp_request_post.go | 2 +- g/os/gcfg/gcfg.go | 33 +++++++++++-- g/util/gconv/gconv_slice.go | 60 +++++++++++++++++++++++ 6 files changed, 197 insertions(+), 41 deletions(-) diff --git a/g/container/gvar/gvar.go b/g/container/gvar/gvar.go index 05b3098e8..bbf3543d9 100644 --- a/g/container/gvar/gvar.go +++ b/g/container/gvar/gvar.go @@ -58,33 +58,6 @@ func (v *Var) Interface() interface{} { return v.Val() } -// Time converts and returns as time.Time. -// The parameter 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 as time.Duration. -// If value of is string, then it uses time.ParseDuration for conversion. -func (v *Var) Duration() time.Duration { - return gconv.Duration(v.Val()) -} - -// GTime converts and returns as *gtime.Time. -// The parameter 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 to . -// The parameter should be a pointer to a struct instance. -// The parameter 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 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 as time.Time. +// The parameter 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 as time.Duration. +// If value of is string, then it uses time.ParseDuration for conversion. +func (v *Var) Duration() time.Duration { + return gconv.Duration(v.Val()) +} + +// GTime converts and returns as *gtime.Time. +// The parameter 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 to map[string]interface{}. +func (v *Var) Map(tags ...string) map[string]interface{} { + return gconv.Map(v.Val(), tags...) +} + +// MapDeep converts to map[string]interface{} recursively. +func (v *Var) MapDeep(tags ...string) map[string]interface{} { + return gconv.MapDeep(v.Val(), tags...) +} + +// Struct maps value of to . +// The parameter should be a pointer to a struct instance. +// The parameter 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 to recursively. +// The parameter should be a pointer to a struct instance. +// The parameter 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 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 to given struct slice recursively. +func (v *Var) StructsDeep(pointer interface{}, mapping ...map[string]string) (err error) { + return gconv.StructsDeep(v.Val(), pointer, mapping...) +} diff --git a/g/encoding/gjson/gjson_api.go b/g/encoding/gjson/gjson_api.go index b83316d30..a03a50f60 100644 --- a/g/encoding/gjson/gjson_api.go +++ b/g/encoding/gjson/gjson_api.go @@ -266,11 +266,32 @@ func (j *Json) GetToVar(pattern string, pointer interface{}) error { return nil } -// GetToStruct gets the value by specified , -// and converts it to specified object . -// The 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 , +// and converts it to specified object . +// The 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 should be a pointer type. +// The should be a pointer type. func (j *Json) ToStruct(pointer interface{}) error { j.mu.RLock() defer j.mu.RUnlock() diff --git a/g/encoding/gparser/gparser_api.go b/g/encoding/gparser/gparser_api.go index 659b2c7dc..2b5261a09 100644 --- a/g/encoding/gparser/gparser_api.go +++ b/g/encoding/gparser/gparser_api.go @@ -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 , +// GetStruct gets the value by specified , // and converts it to specified object . -// The should be the pointer to a struct. -func (p *Parser) GetToStruct(pattern string, pointer interface{}) error { - return p.json.GetToStruct(pattern, pointer) +// The 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 . diff --git a/g/net/ghttp/ghttp_request_post.go b/g/net/ghttp/ghttp_request_post.go index 6a594fd1b..193544256 100644 --- a/g/net/ghttp/ghttp_request_post.go +++ b/g/net/ghttp/ghttp_request_post.go @@ -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) } diff --git a/g/os/gcfg/gcfg.go b/g/os/gcfg/gcfg.go index 1badfa033..adb3fa570 100644 --- a/g/os/gcfg/gcfg.go +++ b/g/os/gcfg/gcfg.go @@ -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() } diff --git a/g/util/gconv/gconv_slice.go b/g/util/gconv/gconv_slice.go index d9f57d500..2b7178bae 100644 --- a/g/util/gconv/gconv_slice.go +++ b/g/util/gconv/gconv_slice.go @@ -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 to []int. func Ints(i interface{}) []int { if i == nil { @@ -350,6 +390,26 @@ func Maps(i interface{}) []map[string]interface{} { } } +// MapsDeep converts 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...) From 3619a46f528847af0c750b09ba23dc68d8033c3b Mon Sep 17 00:00:00 2001 From: John Date: Tue, 9 Jul 2019 10:23:25 +0800 Subject: [PATCH 07/10] README updates --- README.MD | 323 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 322 insertions(+), 1 deletion(-) diff --git a/README.MD b/README.MD index ab18f553f..7d5d91bac 100644 --- a/README.MD +++ b/README.MD @@ -40,6 +40,7 @@ golang version >= 1.10 # Quick Start +## Hello World ```go package main @@ -57,7 +58,327 @@ func main() { } ``` -[View More..](https://goframe.org/start/index) +## Rich Router +```go +package main + +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 + +#### 1). Basic +`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() +``` +Complex one: +```go +conditions := g.Map{ + "title like ?" : "%九寨%", + "online" : 1, + "hits between ? and ?" : g.Slice{1, 10}, + "exp > 0" : nil, + "category" : g.Slice{100, 200}, +} +result, err := db.Table("article").Where(conditions).All() +// SELECT * FROM article WHERE title like '%九寨%' AND online=1 AND hits between 1 and 10 AND exp > 0 AND category IN(100,200) +``` + +#### 2). `join` +```go +// SELECT u.*,ud.site FROM user u LEFT JOIN user_detail ud ON u.uid=ud.uid WHERE u.uid=1 LIMIT 1 +r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid=?", 1).One() + +// SELECT ud.site FROM user u RIGHT JOIN user_detail ud ON u.uid=ud.uid WHERE u.uid=1 LIMIT 1 +r, err := db.Table("user u").RightJoin("user_detail ud", "u.uid=ud.uid").Fields("ud.site").Where("u.uid=?", 1).Value() + +// SELECT u.*,ud.site FROM user u INNER JOIN user_detail ud ON u.uid=ud.uid GROUP BY city ORDER BY register_time asc +r, err := db.Table("user u").InnerJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.city").GroupBy("city").OrderBy("register_time asc").Select() + +// SELECT u.*,ud.city FROM user u,user_detail ud WHERE u.uid=ud.uid +r, err := db.Table("user u,user_detail ud").Where("u.uid=ud.uid").Fields("u.*,ud.city").All() +``` + +#### 3). `select in` +```go +// SELECT * FROM user WHERE uid IN(100,10000,90000) +r, err := db.Table("user").Where("uid IN(?,?,?)", 100, 10000, 90000).All() +// SELECT * FROM user WHERE gender=1 AND uid IN(100,10000,90000) +r, err := db.Table("user").Where("gender=? AND uid IN(?)", 1, g.Slice{100, 10000, 90000}).All() +// SELECT COUNT(*) FROM user WHERE age in(18,50) +r, err := db.Table("user").Where("age IN(?,?)", 18, 50).Count() +``` +With `map`: +```go +// SELECT * FROM user WHERE gender=1 AND uid IN(100,10000,90000) +r, err := db.Table("user").Where(g.Map{ + "gender" : 1, + "uid" : g.Slice{100,10000,90000}, +}).All() +``` +With `struct`: +```go +type User struct { + Id []int `gconv:"uid"` + Gender int `gconv:"gender"` +} +// SELECT * FROM user WHERE uid IN(100,10000,90000) AND gender=1 +r, err := db.Table("user").Where(User{ + "gender" : 1, + "uid" : []int{100, 10000, 90000}, +}).All() +``` + +#### 4). `like` +```go +// SELECT * FROM user WHERE name like '%john%' +r, err := db.Table("user").Where("name like ?", "%john%").Select() +// SELECT * FROM user WHERE birthday like '1990-%' +r, err := db.Table("user").Where("birthday like ?", "1990-%").Select() +``` + +#### 5). `sum` +```go +// SELECT SUM(score) FROM user WHERE uid=1 +r, err := db.Table("user").Fields("SUM(score)").Where("uid=?", 1).Value() +``` + +#### 6). `count` +```go +// SELECT COUNT(1) FROM user WHERE `birthday`='1990-10-01' +r, err := db.Table("user").Where("birthday=?", "1990-10-01").Count() +// SELECT COUNT(uid) FROM user WHERE `birthday`='1990-10-01' +r, err := db.Table("user").Fields("uid").Where("birthday=?", "1990-10-01").Count() +``` + +#### 7). `distinct` +```go +// SELECT DISTINCT uid,name FROM user +r, err := db.Table("user").Fields("DISTINCT uid,name").Select() +``` + +### 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 From 1dbda3872b12a92219bea4dc10cade0f69a4ebf8 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 9 Jul 2019 10:25:59 +0800 Subject: [PATCH 08/10] README updates --- README.MD | 84 ------------------------------------------------------- 1 file changed, 84 deletions(-) diff --git a/README.MD b/README.MD index 7d5d91bac..15ac4eb61 100644 --- a/README.MD +++ b/README.MD @@ -212,7 +212,6 @@ db := g.DB("user-center") ``` ### 2. Chaining Operations -#### 1). Basic `Where + string` ```go // SELECT * FROM user WHERE uid>1 LIMIT 0,10 @@ -249,91 +248,8 @@ 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() ``` -Complex one: -```go -conditions := g.Map{ - "title like ?" : "%九寨%", - "online" : 1, - "hits between ? and ?" : g.Slice{1, 10}, - "exp > 0" : nil, - "category" : g.Slice{100, 200}, -} -result, err := db.Table("article").Where(conditions).All() -// SELECT * FROM article WHERE title like '%九寨%' AND online=1 AND hits between 1 and 10 AND exp > 0 AND category IN(100,200) -``` -#### 2). `join` -```go -// SELECT u.*,ud.site FROM user u LEFT JOIN user_detail ud ON u.uid=ud.uid WHERE u.uid=1 LIMIT 1 -r, err := db.Table("user u").LeftJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.site").Where("u.uid=?", 1).One() -// SELECT ud.site FROM user u RIGHT JOIN user_detail ud ON u.uid=ud.uid WHERE u.uid=1 LIMIT 1 -r, err := db.Table("user u").RightJoin("user_detail ud", "u.uid=ud.uid").Fields("ud.site").Where("u.uid=?", 1).Value() - -// SELECT u.*,ud.site FROM user u INNER JOIN user_detail ud ON u.uid=ud.uid GROUP BY city ORDER BY register_time asc -r, err := db.Table("user u").InnerJoin("user_detail ud", "u.uid=ud.uid").Fields("u.*,ud.city").GroupBy("city").OrderBy("register_time asc").Select() - -// SELECT u.*,ud.city FROM user u,user_detail ud WHERE u.uid=ud.uid -r, err := db.Table("user u,user_detail ud").Where("u.uid=ud.uid").Fields("u.*,ud.city").All() -``` - -#### 3). `select in` -```go -// SELECT * FROM user WHERE uid IN(100,10000,90000) -r, err := db.Table("user").Where("uid IN(?,?,?)", 100, 10000, 90000).All() -// SELECT * FROM user WHERE gender=1 AND uid IN(100,10000,90000) -r, err := db.Table("user").Where("gender=? AND uid IN(?)", 1, g.Slice{100, 10000, 90000}).All() -// SELECT COUNT(*) FROM user WHERE age in(18,50) -r, err := db.Table("user").Where("age IN(?,?)", 18, 50).Count() -``` -With `map`: -```go -// SELECT * FROM user WHERE gender=1 AND uid IN(100,10000,90000) -r, err := db.Table("user").Where(g.Map{ - "gender" : 1, - "uid" : g.Slice{100,10000,90000}, -}).All() -``` -With `struct`: -```go -type User struct { - Id []int `gconv:"uid"` - Gender int `gconv:"gender"` -} -// SELECT * FROM user WHERE uid IN(100,10000,90000) AND gender=1 -r, err := db.Table("user").Where(User{ - "gender" : 1, - "uid" : []int{100, 10000, 90000}, -}).All() -``` - -#### 4). `like` -```go -// SELECT * FROM user WHERE name like '%john%' -r, err := db.Table("user").Where("name like ?", "%john%").Select() -// SELECT * FROM user WHERE birthday like '1990-%' -r, err := db.Table("user").Where("birthday like ?", "1990-%").Select() -``` - -#### 5). `sum` -```go -// SELECT SUM(score) FROM user WHERE uid=1 -r, err := db.Table("user").Fields("SUM(score)").Where("uid=?", 1).Value() -``` - -#### 6). `count` -```go -// SELECT COUNT(1) FROM user WHERE `birthday`='1990-10-01' -r, err := db.Table("user").Where("birthday=?", "1990-10-01").Count() -// SELECT COUNT(uid) FROM user WHERE `birthday`='1990-10-01' -r, err := db.Table("user").Fields("uid").Where("birthday=?", "1990-10-01").Count() -``` - -#### 7). `distinct` -```go -// SELECT DISTINCT uid,name FROM user -r, err := db.Table("user").Fields("DISTINCT uid,name").Select() -``` ### 3. Update & Delete ```go From 7ad66db491b2f9a2f43c47400372a9f46bec66bc Mon Sep 17 00:00:00 2001 From: John Date: Tue, 9 Jul 2019 10:27:47 +0800 Subject: [PATCH 09/10] README updates --- README.MD | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/README.MD b/README.MD index 15ac4eb61..aa3e5a7f8 100644 --- a/README.MD +++ b/README.MD @@ -57,7 +57,6 @@ func main() { s.Run() } ``` - ## Rich Router ```go package main @@ -135,9 +134,7 @@ func main() { s.Run() } ``` - ## Multi ports & domains - ```go package main @@ -162,9 +159,7 @@ func main() { s.Run() } ``` - ## Template Engine - ```go package main @@ -185,9 +180,7 @@ func main() { s.Run() } ``` - ## File Uploading - ```go func Upload(r *ghttp.Request) { if f, h, e := r.FormFile("upload-file"); e == nil { @@ -248,9 +241,6 @@ 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' @@ -264,14 +254,12 @@ 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 { @@ -282,7 +270,6 @@ if tx, err := db.Begin(); err == nil { tx.Commit() } ``` - ### 6. Error Handling ```go func GetOrderInfo(id int) (order *Order, err error) { From a7d30dd1d543a3c4ab6eefef6bb73ed96292a25a Mon Sep 17 00:00:00 2001 From: john Date: Tue, 9 Jul 2019 11:02:33 +0800 Subject: [PATCH 10/10] improve gfile --- g/os/gfile/gfile.go | 213 ++++++++++++++++++++------------------------ go.mod | 1 - 2 files changed, 95 insertions(+), 119 deletions(-) diff --git a/g/os/gfile/gfile.go b/g/os/gfile/gfile.go index 22cda24e2..717ffae7e 100644 --- a/g/os/gfile/gfile.go +++ b/g/os/gfile/gfile.go @@ -144,29 +144,109 @@ func Rename(src string, dst string) error { return Move(src, dst) } -// Copy file from to . +// Copy file/directory from to . // -// @TODO directory copy support. +// If 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 . @@ -452,106 +532,3 @@ func MainPkgPath() string { func TempDir() string { return os.TempDir() } - -// https://gist.github.com/r0l1/92462b38df26839a3ca324697c8cba04 -// 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. -func CopyFile(src, dst string) (err error) { - in, err := os.Open(src) - if err != nil { - return - } - defer in.Close() - - 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 - } - if !si.IsDir() { - return fmt.Errorf("source is not a directory") - } - - _, err = os.Stat(dst) - if err != nil && !os.IsNotExist(err) { - return - } - if err == nil { - return fmt.Errorf("destination already exists") - } - - 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 -} diff --git a/go.mod b/go.mod index 081d99cd0..28729e4f6 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,2 @@ module github.com/gogf/gf -go 1.12