improve gcompress/gres for packing files

This commit is contained in:
John
2019-09-03 23:18:54 +08:00
parent cd00ac446b
commit 7fad4b686c
16 changed files with 203 additions and 41 deletions

View File

@ -11,11 +11,11 @@ func main() {
gres.Dump()
v := g.View()
v.SetPath("/template/layout1")
v.SetPath("files/template/layout1")
s := g.Server()
s.SetIndexFolder(true)
s.SetServerRoot("/root")
s.SetServerRoot("files/root")
s.BindHandler("/template", func(r *ghttp.Request) {
r.Response.WriteTpl("layout.html")
})

View File

@ -12,7 +12,7 @@ func main() {
g.Config().SetFileName("my.ini")
g.Dump(g.Config().Get("redis"))
g.Config().SetPath("/config-custom")
g.Config().SetPath("config-custom")
g.Config().SetFileName("my.ini")
g.Dump(g.Config().Get("redis"))

View File

@ -1,14 +1,15 @@
package main
import (
"github.com/gogf/gf/frame/g"
"github.com/gogf/gf/os/gres"
_ "github.com/gogf/gf/os/gres/testdata"
)
func main() {
gres.Dump()
g.Dump(gres.ScanDir("/root/image", "*"))
//file := gres.Get("www")
//fmt.Println(file.Open())
//g.Dump(gres.ScanDir("/root/image", "*"))
//g.Dump(gres.Scan("/root/image/", "*", true))
//g.Dump(gres.Scan("/template", "*"))
//g.Dump(gres.Scan("/template/layout2", "*.html", true))

View File

@ -12,7 +12,7 @@ func main() {
gres.Dump()
v := g.View()
v.SetPath("/template/layout1")
v.SetPath("files/template/layout1")
s, err := v.Parse("layout.html")
fmt.Println(err)
fmt.Println(s)

View File

@ -12,7 +12,7 @@ func main() {
gres.Dump()
v := g.View()
v.SetPath("/template/layout2")
v.SetPath("files/template/layout2")
s, err := v.Parse("layout.html", g.Map{
"mainTpl": "main/main1.html",
})

View File

@ -8,6 +8,7 @@
package gset
import (
"encoding/json"
"strings"
"github.com/gogf/gf/internal/rwmutex"
@ -324,3 +325,8 @@ func (set *Set) Pops(size int) []interface{} {
}
return array
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (set *Set) MarshalJSON() ([]byte, error) {
return json.Marshal(set.Slice())
}

View File

@ -8,6 +8,7 @@
package gset
import (
"encoding/json"
"strings"
"github.com/gogf/gf/internal/rwmutex"
@ -318,3 +319,8 @@ func (set *IntSet) Pops(size int) []int {
}
return array
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (set *IntSet) MarshalJSON() ([]byte, error) {
return json.Marshal(set.Slice())
}

View File

@ -8,6 +8,7 @@
package gset
import (
"encoding/json"
"strings"
"github.com/gogf/gf/internal/rwmutex"
@ -319,3 +320,8 @@ func (set *StringSet) Pops(size int) []string {
}
return array
}
// MarshalJSON implements the interface MarshalJSON for json.Marshal.
func (set *StringSet) MarshalJSON() ([]byte, error) {
return json.Marshal(set.Slice())
}

View File

@ -13,56 +13,90 @@ import (
"os"
"path/filepath"
"strings"
"time"
"github.com/gogf/gf/internal/fileinfo"
"github.com/gogf/gf/os/gfile"
"github.com/gogf/gf/text/gstr"
)
// ZipPath compresses <path> to <dest> using zip compressing algorithm.
// ZipPath compresses <paths> 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 {
//
// Note that parameter <paths> supports multiple paths join with ','.
func ZipPath(paths, dest string, prefix ...string) error {
writer, err := os.Create(dest)
if err != nil {
return err
}
defer writer.Close()
return ZipPathWriter(path, writer, prefix...)
return ZipPathWriter(paths, writer, prefix...)
}
// ZipPathWriter compresses <path> to <writer> using zip compressing algorithm.
// ZipPathWriter compresses <paths> 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 {
//
// Note that parameter <paths> supports multiple paths join with ','.
func ZipPathWriter(paths string, writer io.Writer, prefix ...string) error {
zipWriter := zip.NewWriter(writer)
defer zipWriter.Close()
for _, path := range strings.Split(paths, ",") {
path = strings.TrimSpace(path)
if err := doZipPathWriter(path, zipWriter, prefix...); err != nil {
return err
}
}
return nil
}
func doZipPathWriter(path string, zipWriter *zip.Writer, prefix ...string) error {
realPath, 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
}
headerPrefix := ""
if len(prefix) > 0 {
if len(prefix) > 0 && prefix[0] != "" {
headerPrefix = prefix[0]
}
headerPrefix = strings.Trim(headerPrefix, "\\/")
// If path is a directory, add it to the zip prefix.
if gfile.IsDir(realPath) {
headerPrefix = headerPrefix + "/" + gfile.Basename(realPath)
headerPrefix = strings.TrimRight(headerPrefix, "\\/")
if gfile.IsDir(path) {
if len(headerPrefix) > 0 {
headerPrefix += "/"
}
headerPrefix = headerPrefix + gfile.Basename(path)
}
headerPrefix = strings.Replace(headerPrefix, "//", "/", -1)
for _, file := range files {
err := zipFile(file, headerPrefix+gfile.Dir(file[len(realPath):]), zipWriter)
if err != nil {
return err
}
}
// Add prefix to zip archive.
path = headerPrefix
for {
err := zipFileVirtual(fileinfo.New(gfile.Basename(path), 0, os.ModeDir, time.Now()), path, zipWriter)
if err != nil {
return err
}
if path == "/" || !strings.Contains(path, "/") {
break
}
path = gfile.Dir(path)
}
return nil
}
// UnZipFile decompresses <archive> to <dest> using zip compressing algorithm.
// The parameter <path> specifies the unzipped path of <archive>,
// which can be used to specify part of the archive file to unzip.
//
// Note thate the parameter <dest> should be a directory.
func UnZipFile(archive, dest string, path ...string) error {
readerCloser, err := zip.OpenReader(archive)
if err != nil {
@ -75,6 +109,8 @@ func UnZipFile(archive, dest string, path ...string) error {
// UnZipContent decompresses <data> to <dest> using zip compressing algorithm.
// The parameter <path> specifies the unzipped path of <archive>,
// which can be used to specify part of the archive file to unzip.
//
// Note thate the parameter <dest> should be a directory.
func UnZipContent(data []byte, dest string, path ...string) error {
reader, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
@ -144,17 +180,10 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
if err != nil {
return err
}
header, err := zip.FileInfoHeader(info)
header, err := createFileHeader(info, prefix)
if err != nil {
return err
}
if len(prefix) > 0 {
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
@ -166,3 +195,28 @@ func zipFile(path string, prefix string, zw *zip.Writer) error {
}
return nil
}
func zipFileVirtual(info os.FileInfo, path string, zw *zip.Writer) error {
header, err := createFileHeader(info, "")
if err != nil {
return err
}
header.Name = path
if _, err := zw.CreateHeader(header); err != nil {
return err
}
return nil
}
func createFileHeader(info os.FileInfo, prefix string) (*zip.FileHeader, error) {
header, err := zip.FileInfoHeader(info)
if err != nil {
return nil, err
}
if len(prefix) > 0 {
prefix = strings.Replace(prefix, `\`, `/`, -1)
prefix = strings.TrimRight(prefix, `/`)
header.Name = prefix + `/` + header.Name
}
return header, nil
}

View File

@ -0,0 +1,53 @@
// 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 fileinfo provides virtual os.FileInfo for given information.
package fileinfo
import (
"os"
"time"
)
type Info struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func New(name string, size int64, mode os.FileMode, modTime time.Time) *Info {
return &Info{
name: name,
size: size,
mode: mode,
modTime: modTime,
}
}
func (i *Info) Name() string {
return i.name
}
func (i *Info) Size() int64 {
return i.size
}
func (i *Info) IsDir() bool {
return i.mode.IsDir()
}
func (i *Info) Mode() os.FileMode {
return i.mode
}
func (i *Info) ModTime() time.Time {
return i.modTime
}
func (i *Info) Sys() interface{} {
return nil
}

View File

@ -38,6 +38,10 @@ type Config struct {
vc *gtype.Bool // Whether do violence check in value index searching. It affects the performance when set true(false in default).
}
var (
resourceTryFiles = []string{"", "/", "config/", "config", "/config", "/config/"}
)
// New returns a new configuration management object.
// The parameter <file> specifies the default configuration file name for reading.
func New(file ...string) *Config {
@ -257,7 +261,7 @@ func (c *Config) FilePath(file ...string) (path string) {
c.paths.RLockFunc(func(array []string) {
for _, prefix := range array {
// Firstly checking the resource manager.
for _, v := range []string{"/", "/config", "/config/"} {
for _, v := range resourceTryFiles {
if file := gres.Get(prefix + v + name); file != nil {
path = file.Name()
return
@ -274,7 +278,7 @@ func (c *Config) FilePath(file ...string) (path string) {
})
// Checking the configuration file in default paths.
if path == "" && !gres.IsEmpty() {
for _, v := range []string{"", "/", "/config", "/config/"} {
for _, v := range resourceTryFiles {
if file := gres.Get(v + name); file != nil {
path = file.Name()
return

View File

@ -29,34 +29,44 @@ func init() {
`
)
// Pack packs the path specified by <srcPath> into bytes.
// Pack packs the path specified by <srcPaths> into bytes.
// The unnecessary parameter <keyPrefix> indicates the prefix for each file
// packed into the result bytes.
func Pack(srcPath string, keyPrefix ...string) ([]byte, error) {
//
// Note that parameter <srcPaths> supports multiple paths join with ','.
func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
buffer := bytes.NewBuffer(nil)
err := gcompress.ZipPathWriter(srcPath, buffer, keyPrefix...)
headerPrefix := ""
if len(keyPrefix) > 0 && keyPrefix[0] != "" {
headerPrefix = keyPrefix[0]
}
err := gcompress.ZipPathWriter(srcPaths, buffer, headerPrefix)
if err != nil {
return nil, err
}
return buffer.Bytes(), nil
}
// PackToFile packs the path specified by <srcPath> to target file <dstPath>.
// PackToFile packs the path specified by <srcPaths> to target file <dstPath>.
// The unnecessary parameter <keyPrefix> indicates the prefix for each file
// packed into the result bytes.
func PackToFile(srcPath, dstPath string, keyPrefix ...string) error {
data, err := Pack(srcPath, keyPrefix...)
//
// Note that parameter <srcPaths> supports multiple paths join with ','.
func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
data, err := Pack(srcPaths, keyPrefix...)
if err != nil {
return err
}
return gfile.PutBytes(dstPath, data)
}
// PackToGoFile packs the path specified by <srcPath> to target go file <goFilePath>
// PackToGoFile packs the path specified by <srcPaths> to target go file <goFilePath>
// with given package name <pkgName>.
//
// The unnecessary parameter <keyPrefix> indicates the prefix for each file
// packed into the result bytes.
//
// Note that parameter <srcPaths> supports multiple paths join with ','.
func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
data, err := Pack(srcPath, keyPrefix...)
if err != nil {

View File

@ -8,11 +8,12 @@ package gres
import (
"fmt"
"github.com/gogf/gf/os/gtime"
"os"
"path/filepath"
"strings"
"github.com/gogf/gf/os/gtime"
"github.com/gogf/gf/container/gtree"
"github.com/gogf/gf/os/gfile"
)

View File

@ -14,7 +14,7 @@ import (
"github.com/gogf/gf/test/gtest"
)
func Test_Export(t *testing.T) {
func Test_Pack(t *testing.T) {
gtest.Case(t, func() {
srcPath := gdebug.CallerDirectory() + "/testdata/files"
goFilePath := gdebug.CallerDirectory() + "/testdata/testdata.go"
@ -23,3 +23,23 @@ func Test_Export(t *testing.T) {
gtest.Assert(err, nil)
})
}
func Test_PackWithPrefix1(t *testing.T) {
gtest.Case(t, func() {
srcPath := gdebug.CallerDirectory() + "/testdata/files"
goFilePath := gdebug.CallerDirectory() + "/testdata/testdata.go"
pkgName := "testdata"
err := gres.PackToGoFile(srcPath, goFilePath, pkgName, "www/gf-site/test")
gtest.Assert(err, nil)
})
}
func Test_PackWithPrefix2(t *testing.T) {
gtest.Case(t, func() {
srcPath := gdebug.CallerDirectory() + "/testdata/files"
goFilePath := gdebug.CallerDirectory() + "/testdata/testdata.go"
pkgName := "testdata"
err := gres.PackToGoFile(srcPath, goFilePath, pkgName, "/var/www/gf-site/test")
gtest.Assert(err, nil)
})
}

File diff suppressed because one or more lines are too long

View File

@ -38,7 +38,8 @@ const (
var (
// Templates cache map for template folder.
// TODO Note that there's no expiring logic for this map.
templates = gmap.NewStrAnyMap(true)
templates = gmap.NewStrAnyMap(true)
resourceTryFiles = []string{"template/", "template", "/template", "/template/"}
)
// getTemplate returns the template object associated with given template folder <path>.
@ -116,7 +117,7 @@ func (view *View) searchFile(file string) (path string, folder string, err error
}
// Checking the configuration file in default paths.
if path == "" && !gres.IsEmpty() {
for _, v := range []string{"/template", "/template/"} {
for _, v := range resourceTryFiles {
if file := gres.Get(v + file); file != nil {
path = file.Name()
folder = gfile.Dir(path)