diff --git a/.gitignore b/.gitignore
index 143e3c3c5..bec9782b8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ cbuild
cmd/gf/main
cmd/gf/gf
go.work
+temp/
diff --git a/cmd/gf/internal/cmd/cmd_build.go b/cmd/gf/internal/cmd/cmd_build.go
index 0b72b496b..5a72e4d76 100644
--- a/cmd/gf/internal/cmd/cmd_build.go
+++ b/cmd/gf/internal/cmd/cmd_build.go
@@ -204,7 +204,9 @@ func (c cBuild) Index(ctx context.Context, in cBuildInput) (out *cBuildOutput, e
mlog.Printf(`remove the automatically generated resource go file: %s`, in.PackDst)
}()
}
- packCmd := fmt.Sprintf(`gf pack %s %s`, in.PackSrc, in.PackDst)
+ // remove black space in separator.
+ in.PackSrc, _ = gregex.ReplaceString(`,\s+`, `,`, in.PackSrc)
+ packCmd := fmt.Sprintf(`gf pack %s %s --keepPath=true`, in.PackSrc, in.PackDst)
mlog.Print(packCmd)
gproc.MustShellRun(ctx, packCmd)
}
diff --git a/cmd/gf/internal/cmd/cmd_pack.go b/cmd/gf/internal/cmd/cmd_pack.go
index a54905837..c60c8e6ea 100644
--- a/cmd/gf/internal/cmd/cmd_pack.go
+++ b/cmd/gf/internal/cmd/cmd_pack.go
@@ -37,28 +37,31 @@ gf pack /var/www/public packed/data.go -n=packed
destination file path for packed file. if extension of the filename is ".go" and "-n" option is given,
it enables packing SRC to go file, or else it packs SRC into a binary file.
`
- cPackNameBrief = `package name for output go file, it's set as its directory name if no name passed`
- cPackPrefixBrief = `prefix for each file packed into the resource file`
+ cPackNameBrief = `package name for output go file, it's set as its directory name if no name passed`
+ cPackPrefixBrief = `prefix for each file packed into the resource file`
+ cPackKeepPathBrief = `keep the source path from system to resource file, usually for relative path`
)
func init() {
gtag.Sets(g.MapStrStr{
- `cPackUsage`: cPackUsage,
- `cPackBrief`: cPackBrief,
- `cPackEg`: cPackEg,
- `cPackSrcBrief`: cPackSrcBrief,
- `cPackDstBrief`: cPackDstBrief,
- `cPackNameBrief`: cPackNameBrief,
- `cPackPrefixBrief`: cPackPrefixBrief,
+ `cPackUsage`: cPackUsage,
+ `cPackBrief`: cPackBrief,
+ `cPackEg`: cPackEg,
+ `cPackSrcBrief`: cPackSrcBrief,
+ `cPackDstBrief`: cPackDstBrief,
+ `cPackNameBrief`: cPackNameBrief,
+ `cPackPrefixBrief`: cPackPrefixBrief,
+ `cPackKeepPathBrief`: cPackKeepPathBrief,
})
}
type cPackInput struct {
- g.Meta `name:"pack"`
- Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
- Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
- Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`
- Prefix string `name:"prefix" short:"p" brief:"{cPackPrefixBrief}"`
+ g.Meta `name:"pack"`
+ Src string `name:"SRC" arg:"true" v:"required" brief:"{cPackSrcBrief}"`
+ Dst string `name:"DST" arg:"true" v:"required" brief:"{cPackDstBrief}"`
+ Name string `name:"name" short:"n" brief:"{cPackNameBrief}"`
+ Prefix string `name:"prefix" short:"p" brief:"{cPackPrefixBrief}"`
+ KeepPath bool `name:"keepPath" short:"k" brief:"{cPackKeepPathBrief}" orphan:"true"`
}
type cPackOutput struct{}
@@ -75,12 +78,16 @@ func (c cPack) Index(ctx context.Context, in cPackInput) (out *cPackOutput, err
if in.Name == "" && gfile.ExtName(in.Dst) == "go" {
in.Name = gfile.Basename(gfile.Dir(in.Dst))
}
+ var option = gres.Option{
+ Prefix: in.Prefix,
+ KeepPath: in.KeepPath,
+ }
if in.Name != "" {
- if err = gres.PackToGoFile(in.Src, in.Dst, in.Name, in.Prefix); err != nil {
+ if err = gres.PackToGoFileWithOption(in.Src, in.Dst, in.Name, option); err != nil {
mlog.Fatalf("pack failed: %v", err)
}
} else {
- if err = gres.PackToFile(in.Src, in.Dst, in.Prefix); err != nil {
+ if err = gres.PackToFileWithOption(in.Src, in.Dst, option); err != nil {
mlog.Fatalf("pack failed: %v", err)
}
}
diff --git a/example/pack/hack/config.yaml b/example/pack/hack/config.yaml
new file mode 100644
index 000000000..9dec998f1
--- /dev/null
+++ b/example/pack/hack/config.yaml
@@ -0,0 +1,9 @@
+gfcli:
+ build:
+ name: "pack"
+ arch: "amd64"
+ system: "darwin"
+ packSrc: "resource/public,manifest/i18n"
+ packDst: "packed/build_packed_data.go"
+ mod: ""
+ cgo: 0
\ No newline at end of file
diff --git a/example/pack/main.go b/example/pack/main.go
new file mode 100644
index 000000000..28256030d
--- /dev/null
+++ b/example/pack/main.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ _ "github.com/gogf/gf/example/pack/packed"
+
+ "github.com/gogf/gf/v2/frame/g"
+ "github.com/gogf/gf/v2/i18n/gi18n"
+ "github.com/gogf/gf/v2/net/ghttp"
+ "github.com/gogf/gf/v2/os/gres"
+)
+
+func main() {
+ gres.Dump()
+
+ s := g.Server()
+ s.SetPort(8199)
+ s.SetServerRoot("resource/public")
+ s.BindHandler("/i18n", func(r *ghttp.Request) {
+ var (
+ lang = r.Get("lang", "zh-CN").String()
+ ctx = gi18n.WithLanguage(r.Context(), lang)
+ content string
+ )
+ content = g.I18n().T(ctx, `{#hello} {#world}!`)
+ r.Response.Write(content)
+ })
+ s.Run()
+}
diff --git a/example/pack/manifest/i18n/ja.yaml b/example/pack/manifest/i18n/ja.yaml
new file mode 100644
index 000000000..a8abe1be1
--- /dev/null
+++ b/example/pack/manifest/i18n/ja.yaml
@@ -0,0 +1,2 @@
+hello: "こんにちは"
+world: "世界"
\ No newline at end of file
diff --git a/example/pack/manifest/i18n/ru.yaml b/example/pack/manifest/i18n/ru.yaml
new file mode 100644
index 000000000..182ec5eec
--- /dev/null
+++ b/example/pack/manifest/i18n/ru.yaml
@@ -0,0 +1,2 @@
+hello: "Привет"
+world: "мир"
\ No newline at end of file
diff --git a/example/pack/manifest/i18n/zh-CN.yaml b/example/pack/manifest/i18n/zh-CN.yaml
new file mode 100644
index 000000000..38f96cc1f
--- /dev/null
+++ b/example/pack/manifest/i18n/zh-CN.yaml
@@ -0,0 +1,2 @@
+hello: "你好"
+world: "世界"
\ No newline at end of file
diff --git a/example/pack/packed/paked.go b/example/pack/packed/paked.go
new file mode 100644
index 000000000..e20ab1e95
--- /dev/null
+++ b/example/pack/packed/paked.go
@@ -0,0 +1 @@
+package packed
diff --git a/example/pack/resource/public/index.html b/example/pack/resource/public/index.html
new file mode 100644
index 000000000..6d1907228
--- /dev/null
+++ b/example/pack/resource/public/index.html
@@ -0,0 +1,8 @@
+
+
+ Hello World
+
+
+ Hello World!
+
+
\ No newline at end of file
diff --git a/i18n/gi18n/gi18n_manager.go b/i18n/gi18n/gi18n_manager.go
index 94aee52cc..4492cbb10 100644
--- a/i18n/gi18n/gi18n_manager.go
+++ b/i18n/gi18n/gi18n_manager.go
@@ -39,8 +39,14 @@ type Options struct {
}
var (
- defaultLanguage = "en" // defaultDelimiters defines the default language if user does not specified in options.
- defaultDelimiters = []string{"{#", "}"} // defaultDelimiters defines the default key variable delimiters.
+ // defaultDelimiters defines the default language if user does not specify in options.
+ defaultLanguage = "en"
+
+ // defaultDelimiters defines the default key variable delimiters.
+ defaultDelimiters = []string{"{#", "}"}
+
+ // i18n files searching folders.
+ searchFolders = []string{"manifest/i18n", "manifest/config/i18n", "i18n"}
)
// New creates and returns a new i18n manager.
@@ -73,13 +79,15 @@ func New(options ...Options) *Manager {
// DefaultOptions creates and returns a default options for i18n manager.
func DefaultOptions() Options {
- var (
- path = "i18n"
- realPath, _ = gfile.Search(path)
- )
- if realPath != "" {
- path = realPath
- // To avoid of the source path of GF: github.com/gogf/i18n/gi18n
+ var path string
+ for _, folder := range searchFolders {
+ path, _ = gfile.Search(folder)
+ if path != "" {
+ break
+ }
+ }
+ if path != "" {
+ // To avoid of the source path of GoFrame: github.com/gogf/i18n/gi18n
if gfile.Exists(path + gfile.Separator + "gi18n") {
path = ""
}
diff --git a/os/gres/gres_func.go b/os/gres/gres_func.go
index 9e302a734..d2bc6abd6 100644
--- a/os/gres/gres_func.go
+++ b/os/gres/gres_func.go
@@ -33,20 +33,33 @@ func init() {
`
)
+// Option contains the extra options for Pack functions.
+type Option struct {
+ Prefix string // The file path prefix for each file item in resource manager.
+ KeepPath bool // Keep the passed path when packing, usually for relative path.
+}
+
// Pack packs the path specified by `srcPaths` into bytes.
// The unnecessary parameter `keyPrefix` indicates the prefix for each file
// packed into the result bytes.
//
// Note that parameter `srcPaths` supports multiple paths join with ','.
+//
+// Deprecated, use PackWithOption instead.
func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
- var (
- buffer = bytes.NewBuffer(nil)
- headerPrefix = ""
- )
+ option := Option{}
if len(keyPrefix) > 0 && keyPrefix[0] != "" {
- headerPrefix = keyPrefix[0]
+ option.Prefix = keyPrefix[0]
}
- err := zipPathWriter(srcPaths, buffer, headerPrefix)
+ return PackWithOption(srcPaths, option)
+}
+
+// PackWithOption packs the path specified by `srcPaths` into bytes.
+//
+// Note that parameter `srcPaths` supports multiple paths join with ','.
+func PackWithOption(srcPaths string, option Option) ([]byte, error) {
+ var buffer = bytes.NewBuffer(nil)
+ err := zipPathWriter(srcPaths, buffer, option)
if err != nil {
return nil, err
}
@@ -59,6 +72,8 @@ func Pack(srcPaths string, keyPrefix ...string) ([]byte, error) {
// packed into the result bytes.
//
// Note that parameter `srcPaths` supports multiple paths join with ','.
+//
+// Deprecated, use PackToFileWithOption instead.
func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
data, err := Pack(srcPaths, keyPrefix...)
if err != nil {
@@ -67,6 +82,17 @@ func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
return gfile.PutBytes(dstPath, data)
}
+// PackToFileWithOption packs the path specified by `srcPaths` to target file `dstPath`.
+//
+// Note that parameter `srcPaths` supports multiple paths join with ','.
+func PackToFileWithOption(srcPaths, dstPath string, option Option) error {
+ data, err := PackWithOption(srcPaths, option)
+ if err != nil {
+ return err
+ }
+ return gfile.PutBytes(dstPath, data)
+}
+
// PackToGoFile packs the path specified by `srcPaths` to target go file `goFilePath`
// with given package name `pkgName`.
//
@@ -74,6 +100,8 @@ func PackToFile(srcPaths, dstPath string, keyPrefix ...string) error {
// packed into the result bytes.
//
// Note that parameter `srcPaths` supports multiple paths join with ','.
+//
+// Deprecated, use PackToGoFileWithOption instead.
func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) error {
data, err := Pack(srcPath, keyPrefix...)
if err != nil {
@@ -85,6 +113,21 @@ func PackToGoFile(srcPath, goFilePath, pkgName string, keyPrefix ...string) erro
)
}
+// PackToGoFileWithOption packs the path specified by `srcPaths` to target go file `goFilePath`
+// with given package name `pkgName`.
+//
+// Note that parameter `srcPaths` supports multiple paths join with ','.
+func PackToGoFileWithOption(srcPath, goFilePath, pkgName string, option Option) error {
+ data, err := PackWithOption(srcPath, option)
+ if err != nil {
+ return err
+ }
+ return gfile.PutContents(
+ goFilePath,
+ fmt.Sprintf(gstr.TrimLeft(packedGoSourceTemplate), pkgName, gbase64.EncodeToString(data)),
+ )
+}
+
// Unpack unpacks the content specified by `path` to []*File.
func Unpack(path string) ([]*File, error) {
realPath, err := gfile.Search(path)
diff --git a/os/gres/gres_func_zip.go b/os/gres/gres_func_zip.go
index cb3ecb045..23bf17f0f 100644
--- a/os/gres/gres_func_zip.go
+++ b/os/gres/gres_func_zip.go
@@ -8,7 +8,6 @@ package gres
import (
"archive/zip"
- "context"
"io"
"os"
"strings"
@@ -16,7 +15,6 @@ import (
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/internal/fileinfo"
- "github.com/gogf/gf/v2/internal/intlog"
"github.com/gogf/gf/v2/os/gfile"
"github.com/gogf/gf/v2/text/gregex"
)
@@ -26,12 +24,12 @@ import (
//
// Note that the parameter `paths` can be either a directory or a file, which
// supports multiple paths join with ','.
-func zipPathWriter(paths string, writer io.Writer, prefix ...string) error {
+func zipPathWriter(paths string, writer io.Writer, option ...Option) 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 {
+ if err := doZipPathWriter(path, zipWriter, option...); err != nil {
return err
}
}
@@ -42,41 +40,53 @@ func zipPathWriter(paths string, writer io.Writer, prefix ...string) error {
// The parameter `exclude` specifies the exclusive file path that is not compressed to `zipWriter`,
// commonly the destination zip file path.
// The unnecessary parameter `prefix` indicates the path prefix for zip file.
-func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix ...string) error {
+func doZipPathWriter(srcPath string, zipWriter *zip.Writer, option ...Option) error {
var (
- err error
- files []string
+ err error
+ files []string
+ usedOption Option
+ absolutePath string
)
- path, err = gfile.Search(path)
+ if len(option) > 0 {
+ usedOption = option[0]
+ }
+ absolutePath, err = gfile.Search(srcPath)
if err != nil {
return err
}
- if gfile.IsDir(path) {
- files, err = gfile.ScanDir(path, "*", true)
+ if gfile.IsDir(absolutePath) {
+ files, err = gfile.ScanDir(absolutePath, "*", true)
if err != nil {
return err
}
} else {
- files = []string{path}
+ files = []string{absolutePath}
}
- headerPrefix := ""
- if len(prefix) > 0 && prefix[0] != "" {
- headerPrefix = prefix[0]
- }
- headerPrefix = strings.TrimRight(headerPrefix, `\/`)
- if len(headerPrefix) > 0 && gfile.IsDir(path) {
+ headerPrefix := strings.TrimRight(usedOption.Prefix, `\/`)
+ if headerPrefix != "" && gfile.IsDir(absolutePath) {
headerPrefix += "/"
}
+
if headerPrefix == "" {
- headerPrefix = gfile.Basename(path)
+ if usedOption.KeepPath {
+ // It keeps the path from file system to zip info in resource manager.
+ // Usually for relative path, it makes little sense for absolute path.
+ headerPrefix = srcPath
+ } else {
+ headerPrefix = gfile.Basename(absolutePath)
+ }
}
headerPrefix = strings.Replace(headerPrefix, `//`, `/`, -1)
for _, file := range files {
- if exclude == file {
- intlog.Printf(context.TODO(), `exclude file path: %s`, file)
- continue
- }
- subFilePath := file[len(path):]
+ // It here calculates the file name prefix, especially packing the directory.
+ // Eg:
+ // path: dir1
+ // file: dir1/dir2/file
+ // file[len(absolutePath):] => /dir2/file
+ // gfile.Dir(subFilePath) => /dir2
+ var subFilePath string
+ // Normal handling: remove the `absolutePath`(source directory path) for file.
+ subFilePath = file[len(absolutePath):]
if subFilePath != "" {
subFilePath = gfile.Dir(subFilePath)
}
@@ -86,17 +96,20 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix
}
// Add all directories to zip archive.
if headerPrefix != "" {
- var name string
- path = headerPrefix
+ var (
+ name string
+ tmpPath = headerPrefix
+ )
for {
- name = strings.Replace(gfile.Basename(path), `\`, `/`, -1)
- if err = zipFileVirtual(fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), path, zipWriter); err != nil {
+ name = strings.Replace(gfile.Basename(tmpPath), `\`, `/`, -1)
+ err = zipFileVirtual(fileinfo.New(name, 0, os.ModeDir|os.ModePerm, time.Now()), tmpPath, zipWriter)
+ if err != nil {
return err
}
- if path == `/` || !strings.Contains(path, `/`) {
+ if tmpPath == `/` || !strings.Contains(tmpPath, `/`) {
break
}
- path = gfile.Dir(path)
+ tmpPath = gfile.Dir(tmpPath)
}
}
return nil
@@ -106,24 +119,29 @@ func doZipPathWriter(path string, exclude string, zipWriter *zip.Writer, prefix
// The parameter `prefix` indicates the path prefix for zip file.
func zipFile(path string, prefix string, zw *zip.Writer) error {
prefix = strings.Replace(prefix, `//`, `/`, -1)
+
file, err := os.Open(path)
if err != nil {
- err = gerror.Wrapf(err, `os.Open failed for file "%s"`, path)
+ err = gerror.Wrapf(err, `os.Open failed for path "%s"`, path)
return nil
}
defer file.Close()
+
info, err := file.Stat()
if err != nil {
- err = gerror.Wrapf(err, `read file stat failed for file "%s"`, path)
+ err = gerror.Wrapf(err, `read file stat failed for path "%s"`, path)
return err
}
+
header, err := createFileHeader(info, prefix)
if err != nil {
return err
}
if !info.IsDir() {
+ // Default compression level.
header.Method = zip.Deflate
}
+ // Zip header containing the info of a zip file.
writer, err := zw.CreateHeader(header)
if err != nil {
err = gerror.Wrapf(err, `create zip header failed for %#v`, header)
diff --git a/os/gres/gres_resource.go b/os/gres/gres_resource.go
index 1289246d8..0e45eca75 100644
--- a/os/gres/gres_resource.go
+++ b/os/gres/gres_resource.go
@@ -277,7 +277,7 @@ func (r *Resource) Dump() {
r.tree.Iterator(func(key, value interface{}) bool {
info = value.(*File).FileInfo()
fmt.Printf(
- "%v %7s %s\n",
+ "%v %8s %s\n",
gtime.New(info.ModTime()).ISO8601(),
gfile.FormatSize(info.Size()),
key,