Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
John Guo 2022-10-14 10:10:27 +08:00 committed by GitHub
parent e756f284be
commit 2598745e50
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 195 additions and 64 deletions

1
.gitignore vendored
View File

@ -17,3 +17,4 @@ cbuild
cmd/gf/main
cmd/gf/gf
go.work
temp/

View File

@ -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)
}

View File

@ -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)
}
}

View File

@ -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

28
example/pack/main.go Normal file
View File

@ -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()
}

View File

@ -0,0 +1,2 @@
hello: "こんにちは"
world: "世界"

View File

@ -0,0 +1,2 @@
hello: "Привет"
world: "мир"

View File

@ -0,0 +1,2 @@
hello: "你好"
world: "世界"

View File

@ -0,0 +1 @@
package packed

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>

View File

@ -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 = ""
}

View File

@ -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)

View File

@ -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)

View File

@ -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,