adding gres package for resource feature

This commit is contained in:
john
2019-08-10 23:36:38 +08:00
parent d03180ff4d
commit 7ecc47e127
17 changed files with 329 additions and 40 deletions

10
.example/os/gres/gres.go Normal file
View File

@ -0,0 +1,10 @@
package main
import (
_ "github.com/gogf/gf/.example/os/gres/testdata"
"github.com/gogf/gf/os/gres"
)
func main() {
gres.Dump()
}

9
.example/os/gres/testdata/testdata.go vendored Normal file
View File

@ -0,0 +1,9 @@
package testdata
import "github.com/gogf/gf/os/gres"
func init() {
if err := gres.Add([]byte{80, 75, 3, 4, 20, 0, 8, 0, 0, 0, 147, 110, 10, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 9, 0, 47, 100, 105, 114, 49, 85, 84, 5, 0, 1, 38, 204, 78, 93, 80, 75, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 75, 3, 4, 20, 0, 8, 0, 0, 0, 147, 110, 10, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 9, 0, 47, 100, 105, 114, 49, 47, 116, 101, 115, 116, 49, 85, 84, 5, 0, 1, 38, 204, 78, 93, 116, 101, 115, 116, 49, 32, 99, 111, 110, 116, 101, 110, 116, 10, 80, 75, 7, 8, 130, 50, 74, 209, 14, 0, 0, 0, 14, 0, 0, 0, 80, 75, 3, 4, 20, 0, 8, 0, 0, 0, 154, 110, 10, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 9, 0, 47, 100, 105, 114, 50, 85, 84, 5, 0, 1, 53, 204, 78, 93, 80, 75, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 75, 3, 4, 20, 0, 8, 0, 0, 0, 154, 110, 10, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 9, 0, 47, 100, 105, 114, 50, 47, 116, 101, 115, 116, 50, 85, 84, 5, 0, 1, 53, 204, 78, 93, 116, 101, 115, 116, 50, 32, 99, 111, 110, 116, 101, 110, 116, 10, 80, 75, 7, 8, 129, 137, 125, 58, 14, 0, 0, 0, 14, 0, 0, 0, 80, 75, 1, 2, 20, 3, 20, 0, 8, 0, 0, 0, 147, 110, 10, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 9, 0, 0, 0, 0, 0, 0, 0, 16, 0, 255, 65, 0, 0, 0, 0, 47, 100, 105, 114, 49, 85, 84, 5, 0, 1, 38, 204, 78, 93, 80, 75, 1, 2, 20, 3, 20, 0, 8, 0, 0, 0, 147, 110, 10, 79, 130, 50, 74, 209, 14, 0, 0, 0, 14, 0, 0, 0, 11, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, 129, 60, 0, 0, 0, 47, 100, 105, 114, 49, 47, 116, 101, 115, 116, 49, 85, 84, 5, 0, 1, 38, 204, 78, 93, 80, 75, 1, 2, 20, 3, 20, 0, 8, 0, 0, 0, 154, 110, 10, 79, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 9, 0, 0, 0, 0, 0, 0, 0, 16, 0, 255, 65, 140, 0, 0, 0, 47, 100, 105, 114, 50, 85, 84, 5, 0, 1, 53, 204, 78, 93, 80, 75, 1, 2, 20, 3, 20, 0, 8, 0, 0, 0, 154, 110, 10, 79, 129, 137, 125, 58, 14, 0, 0, 0, 14, 0, 0, 0, 11, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 182, 129, 200, 0, 0, 0, 47, 100, 105, 114, 50, 47, 116, 101, 115, 116, 50, 85, 84, 5, 0, 1, 53, 204, 78, 93, 80, 75, 5, 6, 0, 0, 0, 0, 4, 0, 4, 0, 252, 0, 0, 0, 24, 1, 0, 0, 0, 0}); err != nil {
panic(err)
}
}

View File

@ -9,38 +9,44 @@ package gcompress
import (
"archive/zip"
"bytes"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/text/gstr"
"io"
"os"
"path/filepath"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/text/gstr"
"strings"
)
// Zip compresses <path> to <dest> using zip compressing algorithm.
// ZipPath compresses <path> to <dest> using zip compressing algorithm.
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
func ZipPath(path, dest string, prefix ...string) error {
d, err := os.Create(dest)
writer, err := os.Create(dest)
if err != nil {
return err
}
defer d.Close()
w := zip.NewWriter(d)
defer w.Close()
files, err := gfile.ScanDir(path, "*.*", true)
defer writer.Close()
return ZipPathWriter(path, writer, prefix...)
}
// ZipPathWriter compresses <path> to <writer> using zip compressing algorithm.
// The unnecessary parameter <prefix> indicates the path prefix for zip file.
func ZipPathWriter(path string, writer io.Writer, prefix ...string) error {
pathRealPath, err := gfile.Search(path)
if err != nil {
return err
}
zipWriter := zip.NewWriter(writer)
defer zipWriter.Close()
files, err := gfile.ScanDir(path, "*", true)
if err != nil {
return err
}
pathRealPath := gfile.RealPath(path)
destRealPath := gfile.RealPath(dest)
headerPrefix := ""
if len(prefix) > 0 {
headerPrefix = prefix[0]
}
for _, file := range files {
if destRealPath == file {
continue
}
err := zipFile(file, headerPrefix+gfile.Dir(file[len(pathRealPath):]), w)
err := zipFile(file, headerPrefix+gfile.Dir(file[len(pathRealPath):]), zipWriter)
if err != nil {
return err
}
@ -137,18 +143,20 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
return err
}
if len(prefix) > 0 {
header.Name = prefix + "/" + header.Name
prefix = strings.Replace(prefix, `\`, `/`, -1)
prefix = strings.TrimRight(prefix, `/`)
header.Name = prefix + `/` + header.Name
} else {
header.Name = header.Name
}
writer, err := zw.CreateHeader(header)
if err != nil {
return err
}
if _, err = io.Copy(writer, file); err != nil {
return err
if !info.IsDir() {
if _, err = io.Copy(writer, file); err != nil {
return err
}
}
return nil
}

View File

@ -0,0 +1,26 @@
// 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"
"strconv"
)
func Export(b []byte) string {
buffer := bytes.NewBuffer(nil)
buffer.WriteString("[]byte{")
for k, v := range b {
if k > 0 {
buffer.WriteByte(',')
}
buffer.WriteString(strconv.Itoa(int(v)))
}
buffer.WriteString("}")
return buffer.String()
}

View File

@ -4,8 +4,8 @@
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
// Package strutils provides some string functions for internal usage.
package strutils
// Package utilstr provides some string functions for internal usage.
package utilstr
import "strings"

68
os/gres/gres.go Normal file
View File

@ -0,0 +1,68 @@
// 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 gres
import (
"archive/zip"
"bytes"
"fmt"
"github.com/gogf/gf/container/gtree"
"github.com/gogf/gf/encoding/gcompress"
"github.com/gogf/gf/internal/utilbytes"
"github.com/gogf/gf/os/gfile"
"strings"
)
type Resource struct {
Name string
}
var (
resTree = gtree.NewBTree(10, func(v1, v2 interface{}) int {
return strings.Compare(v1.(string), v2.(string))
})
)
func Add(content []byte) error {
reader, err := zip.NewReader(bytes.NewReader(content), int64(len(content)))
if err != nil {
return err
}
for _, file := range reader.File {
resTree.Set(file.Name, file)
}
return nil
}
func Dump() {
resTree.Iterator(func(key, value interface{}) bool {
fmt.Printf("%7s %s\n", gfile.FormatSize(value.(*zip.File).FileInfo().Size()), key)
return true
})
}
func Export(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
buffer := bytes.NewBuffer(nil)
err := gcompress.ZipPathWriter(srcPath, buffer, keyPrefix...)
if err != nil {
return err
}
return gfile.PutContents(
goFilePath,
fmt.Sprintf(
`package %s
import "github.com/gogf/gf/os/gres"
func init() {
if err := gres.Add(%s); err != nil {
panic(err)
}
}
`, pkgName, utilbytes.Export(buffer.Bytes())),
)
}

16
os/gres/gres_file.go Normal file
View File

@ -0,0 +1,16 @@
// 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 gres
import (
"archive/zip"
)
// File implements os.FileInfo interface for a given path and size.
type File struct {
*zip.File
}

116
os/gres/gres_http.go Normal file
View File

@ -0,0 +1,116 @@
// 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 gres
//var (
// defaultFileTimestamp = time.Now()
//)
//
//// HttpFile implements http.File interface for a no-directory file with content.
//type HttpFile struct {
// *bytes.Reader
// io.Closer
// File
//}
//
//func NewHttpFile(name string, content []byte, timestamp time.Time) *HttpFile {
// if timestamp.IsZero() {
// timestamp = defaultFileTimestamp
// }
// return &HttpFile{
// bytes.NewReader(content),
// ioutil.NopCloser(nil),
// File{name, false, int64(len(content)), timestamp},
// }
//}
//
//func (f *HttpFile) Readdir(count int) ([]os.FileInfo, error) {
// return nil, errors.New("not a directory")
//}
//
//func (f *HttpFile) Size() int64 {
// return f.S
//}
//
//func (f *HttpFile) Stat() (os.FileInfo, error) {
// return f.FileInfo(), nil
//}
//
//// HttpDirectory implements http.File interface for a directory
//type HttpDirectory struct {
// HttpFile
// ChildrenRead int
// Children []os.FileInfo
//}
//
//func NewHttpDirectory(name string, children []string, fs *HttpFileSystem) *HttpDirectory {
// infos := make([]os.FileInfo, 0, len(children))
// for _, child := range children {
// _, err := fs.List(filepath.Join(name, child))
// infos = append(infos, &File{child, err == nil, 0, time.Time{}})
// }
// return &HttpDirectory{
// HttpFile{
// bytes.NewReader(nil),
// ioutil.NopCloser(nil),
// File{name, true, 0, time.Time{}},
// },
// 0,
// infos,
// }
//}
//
//func (f *HttpDirectory) Readdir(count int) ([]os.FileInfo, error) {
// if count <= 0 {
// return f.Children, nil
// }
// if f.ChildrenRead+count > len(f.Children) {
// count = len(f.Children) - f.ChildrenRead
// }
// rv := f.Children[f.ChildrenRead : f.ChildrenRead+count]
// f.ChildrenRead += count
// return rv, nil
//}
//
//func (f *HttpDirectory) Stat() (os.FileInfo, error) {
// return f.FileInfo(), nil
//}
//
//// HttpFileSystem implements http.FileSystem, allowing embedded files to be served from net/http package.
//type HttpFileSystem struct {
// Data func(path string) ([]byte, error) // Data should return content of file in path if exists
// List func(path string) ([]string, error) // List should return list of files in the path
// Info func(path string) (os.FileInfo, error) // Info should return the info of file in path if exists
// Prefix string // Prefix would be prepended to http requests
//}
//
//func (fs *HttpFileSystem) Open(name string) (http.File, error) {
// name = path.Join(fs.Prefix, name)
// if len(name) > 0 && name[0] == '/' {
// name = name[1:]
// }
// if b, err := fs.Data(name); err == nil {
// timestamp := defaultFileTimestamp
// if fs.Info != nil {
// if info, err := fs.Info(name); err == nil {
// timestamp = info.ModTime()
// }
// }
// return NewHttpFile(name, b, timestamp), nil
// }
// if children, err := fs.List(name); err == nil {
// return NewHttpDirectory(name, children, fs), nil
// } else {
// // If the error is not found, return an error that will
// // result in a 404 error. Otherwise the server returns
// // a 500 error for files not found.
// if strings.Contains(err.Error(), "not found") {
// return nil, os.ErrNotExist
// }
// return nil, err
// }
//}

25
os/gres/gres_test.go Normal file
View File

@ -0,0 +1,25 @@
// 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 gres_test
import (
"github.com/gogf/gf/debug/gdebug"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/os/gres"
"github.com/gogf/gf/test/gtest"
"testing"
)
func Test_Export(t *testing.T) {
gtest.Case(t, func() {
srcPath := gfile.Dir(gdebug.CallerFilePath()) + "/testdata/files"
goFilePath := gfile.Dir(gdebug.CallerFilePath()) + "/testdata/testdata.go"
pkgName := "testdata"
err := gres.Export(srcPath, goFilePath, pkgName)
gtest.Assert(err, nil)
})
}

1
os/gres/testdata/files/dir1/test1 vendored Normal file
View File

@ -0,0 +1 @@
test1 content

1
os/gres/testdata/files/dir2/test2 vendored Normal file
View File

@ -0,0 +1 @@
test2 content

9
os/gres/testdata/testdata.go vendored Normal file
View File

@ -0,0 +1,9 @@
package testdata
import "github.com/gogf/gf/os/gres"
func init() {
if err := gres.Add([]byte{80,75,3,4,20,0,8,0,0,0,147,110,10,79,0,0,0,0,0,0,0,0,0,0,0,0,5,0,9,0,47,100,105,114,49,85,84,5,0,1,38,204,78,93,80,75,7,8,0,0,0,0,0,0,0,0,0,0,0,0,80,75,3,4,20,0,8,0,0,0,147,110,10,79,0,0,0,0,0,0,0,0,0,0,0,0,11,0,9,0,47,100,105,114,49,47,116,101,115,116,49,85,84,5,0,1,38,204,78,93,116,101,115,116,49,32,99,111,110,116,101,110,116,10,80,75,7,8,130,50,74,209,14,0,0,0,14,0,0,0,80,75,3,4,20,0,8,0,0,0,154,110,10,79,0,0,0,0,0,0,0,0,0,0,0,0,5,0,9,0,47,100,105,114,50,85,84,5,0,1,53,204,78,93,80,75,7,8,0,0,0,0,0,0,0,0,0,0,0,0,80,75,3,4,20,0,8,0,0,0,154,110,10,79,0,0,0,0,0,0,0,0,0,0,0,0,11,0,9,0,47,100,105,114,50,47,116,101,115,116,50,85,84,5,0,1,53,204,78,93,116,101,115,116,50,32,99,111,110,116,101,110,116,10,80,75,7,8,129,137,125,58,14,0,0,0,14,0,0,0,80,75,1,2,20,3,20,0,8,0,0,0,147,110,10,79,0,0,0,0,0,0,0,0,0,0,0,0,5,0,9,0,0,0,0,0,0,0,16,0,255,65,0,0,0,0,47,100,105,114,49,85,84,5,0,1,38,204,78,93,80,75,1,2,20,3,20,0,8,0,0,0,147,110,10,79,130,50,74,209,14,0,0,0,14,0,0,0,11,0,9,0,0,0,0,0,0,0,0,0,182,129,60,0,0,0,47,100,105,114,49,47,116,101,115,116,49,85,84,5,0,1,38,204,78,93,80,75,1,2,20,3,20,0,8,0,0,0,154,110,10,79,0,0,0,0,0,0,0,0,0,0,0,0,5,0,9,0,0,0,0,0,0,0,16,0,255,65,140,0,0,0,47,100,105,114,50,85,84,5,0,1,53,204,78,93,80,75,1,2,20,3,20,0,8,0,0,0,154,110,10,79,129,137,125,58,14,0,0,0,14,0,0,0,11,0,9,0,0,0,0,0,0,0,0,0,182,129,200,0,0,0,47,100,105,114,50,47,116,101,115,116,50,85,84,5,0,1,53,204,78,93,80,75,5,6,0,0,0,0,4,0,4,0,252,0,0,0,24,1,0,0,0,0}); err != nil {
panic(err)
}
}

View File

@ -16,7 +16,7 @@ import (
"unicode"
"unicode/utf8"
"github.com/gogf/gf/internal/strutils"
"github.com/gogf/gf/internal/utilstr"
"github.com/gogf/gf/util/gconv"
@ -98,7 +98,7 @@ func ReplaceIByArray(origin string, array []string) string {
// ReplaceByMap returns a copy of <origin>,
// which is replaced by a map in unordered way, case-sensitively.
func ReplaceByMap(origin string, replaces map[string]string) string {
return strutils.ReplaceByMap(origin, replaces)
return utilstr.ReplaceByMap(origin, replaces)
}
// ReplaceIByMap returns a copy of <origin>,
@ -122,7 +122,7 @@ func ToUpper(s string) string {
// UcFirst returns a copy of the string s with the first letter mapped to its upper case.
func UcFirst(s string) string {
return strutils.UcFirst(s)
return utilstr.UcFirst(s)
}
// LcFirst returns a copy of the string s with the first letter mapped to its lower case.
@ -143,17 +143,17 @@ func UcWords(str string) string {
// IsLetterLower tests whether the given byte b is in lower case.
func IsLetterLower(b byte) bool {
return strutils.IsLetterLower(b)
return utilstr.IsLetterLower(b)
}
// IsLetterUpper tests whether the given byte b is in upper case.
func IsLetterUpper(b byte) bool {
return strutils.IsLetterUpper(b)
return utilstr.IsLetterUpper(b)
}
// IsNumeric tests whether the given string s is numeric.
func IsNumeric(s string) bool {
return strutils.IsNumeric(s)
return utilstr.IsNumeric(s)
}
// SubStr returns a portion of string <str> specified by the <start> and <length> parameters.

View File

@ -12,7 +12,7 @@ import (
"strings"
"github.com/gogf/gf/internal/empty"
"github.com/gogf/gf/internal/strutils"
"github.com/gogf/gf/internal/utilstr"
)
// Map converts any variable <value> to map[string]interface{}.
@ -117,7 +117,7 @@ func Map(value interface{}, tags ...string) map[string]interface{} {
for i := 0; i < rv.NumField(); i++ {
// Only convert the public attributes.
fieldName := rt.Field(i).Name
if !strutils.IsLetterUpper(fieldName[0]) {
if !utilstr.IsLetterUpper(fieldName[0]) {
continue
}
name = ""

View File

@ -11,7 +11,7 @@ import (
"fmt"
"reflect"
"github.com/gogf/gf/internal/strutils"
"github.com/gogf/gf/internal/utilstr"
)
// SliceInt is alias of Ints.
@ -364,7 +364,7 @@ func Interfaces(i interface{}) []interface{} {
rt := rv.Type()
for i := 0; i < rv.NumField(); i++ {
// Only public attributes.
if !strutils.IsLetterUpper(rt.Field(i).Name[0]) {
if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
continue
}
array = append(array, rv.Field(i).Interface())

View File

@ -13,7 +13,7 @@ import (
"strings"
"github.com/gogf/gf/internal/structs"
"github.com/gogf/gf/internal/strutils"
"github.com/gogf/gf/internal/utilstr"
)
// Struct maps the params key-value pairs to the corresponding struct object's properties.
@ -92,7 +92,7 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
elemType := elem.Type()
for i := 0; i < elem.NumField(); i++ {
// Only do converting to public attributes.
if !strutils.IsLetterUpper(elemType.Field(i).Name[0]) {
if !utilstr.IsLetterUpper(elemType.Field(i).Name[0]) {
continue
}
attrMap[elemType.Field(i).Name] = struct{}{}
@ -100,8 +100,8 @@ func Struct(params interface{}, pointer interface{}, mapping ...map[string]strin
for mapK, mapV := range paramsMap {
name := ""
for _, checkName := range []string{
strutils.UcFirst(mapK),
strutils.ReplaceByMap(mapK, map[string]string{
utilstr.UcFirst(mapK),
utilstr.ReplaceByMap(mapK, map[string]string{
"_": "",
"-": "",
" ": "",
@ -159,7 +159,7 @@ func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]s
rt := rv.Type()
for i := 0; i < rv.NumField(); i++ {
// Only do converting to public attributes.
if !strutils.IsLetterUpper(rt.Field(i).Name[0]) {
if !utilstr.IsLetterUpper(rt.Field(i).Name[0]) {
continue
}
trv := rv.Field(i)

View File

@ -9,7 +9,7 @@ package gconv
import (
"time"
"github.com/gogf/gf/internal/strutils"
"github.com/gogf/gf/internal/utilstr"
"github.com/gogf/gf/os/gtime"
)
@ -26,7 +26,7 @@ func Time(i interface{}, format ...string) time.Time {
// If <i> is numeric, then it converts <i> as nanoseconds.
func Duration(i interface{}) time.Duration {
s := String(i)
if !strutils.IsNumeric(s) {
if !utilstr.IsNumeric(s) {
d, _ := time.ParseDuration(s)
return d
}
@ -47,7 +47,7 @@ func GTime(i interface{}, format ...string) *gtime.Time {
t, _ := gtime.StrToTimeFormat(s, format[0])
return t
}
if strutils.IsNumeric(s) {
if utilstr.IsNumeric(s) {
return gtime.NewFromTimeStamp(Int64(s))
} else {
t, _ := gtime.StrToTime(s)