mirror of
https://gitee.com/johng/gf.git
synced 2024-11-29 18:57:44 +08:00
parent
e756f284be
commit
2598745e50
1
.gitignore
vendored
1
.gitignore
vendored
@ -17,3 +17,4 @@ cbuild
|
||||
cmd/gf/main
|
||||
cmd/gf/gf
|
||||
go.work
|
||||
temp/
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
9
example/pack/hack/config.yaml
Normal file
9
example/pack/hack/config.yaml
Normal 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
28
example/pack/main.go
Normal 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()
|
||||
}
|
2
example/pack/manifest/i18n/ja.yaml
Normal file
2
example/pack/manifest/i18n/ja.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
hello: "こんにちは"
|
||||
world: "世界"
|
2
example/pack/manifest/i18n/ru.yaml
Normal file
2
example/pack/manifest/i18n/ru.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
hello: "Привет"
|
||||
world: "мир"
|
2
example/pack/manifest/i18n/zh-CN.yaml
Normal file
2
example/pack/manifest/i18n/zh-CN.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
hello: "你好"
|
||||
world: "世界"
|
1
example/pack/packed/paked.go
Normal file
1
example/pack/packed/paked.go
Normal file
@ -0,0 +1 @@
|
||||
package packed
|
8
example/pack/resource/public/index.html
Normal file
8
example/pack/resource/public/index.html
Normal file
@ -0,0 +1,8 @@
|
||||
<html>
|
||||
<head>
|
||||
<title>Hello World</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Hello World!</h1>
|
||||
</body>
|
||||
</html>
|
@ -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 = ""
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user