mirror of
https://github.com/beego/bee.git
synced 2024-11-25 15:00:55 +00:00
cf7aef47f0
Moved logging to the new logging infrastructure by removing the use of ColorLog() function. Added more documentation. Also fixed some typos in comments and function names.
253 lines
4.8 KiB
Go
253 lines
4.8 KiB
Go
// Copyright 2013 bee authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"compress/gzip"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
)
|
|
|
|
var cmdBale = &Command{
|
|
UsageLine: "bale",
|
|
Short: "packs non-Go files to Go source files",
|
|
Long: `
|
|
Bale command compress all the static files in to a single binary file.
|
|
|
|
This is usefull to not have to carry static files including js, css, images
|
|
and views when publishing a project.
|
|
|
|
auto-generate unpack function to main package then run it during the runtime.
|
|
This is mainly used for zealots who are requiring 100% Go code.
|
|
|
|
`,
|
|
}
|
|
|
|
func init() {
|
|
cmdBale.Run = runBale
|
|
}
|
|
|
|
func runBale(cmd *Command, args []string) int {
|
|
ShowShortVersionBanner()
|
|
|
|
err := loadConfig()
|
|
if err != nil {
|
|
logger.Fatalf("Failed to load configuration: %s", err)
|
|
}
|
|
|
|
os.RemoveAll("bale")
|
|
os.Mkdir("bale", os.ModePerm)
|
|
|
|
// Pack and compress data
|
|
for _, p := range conf.Bale.Dirs {
|
|
if !isExist(p) {
|
|
logger.Warnf("Skipped directory: %s", p)
|
|
continue
|
|
}
|
|
logger.Infof("Packaging directory: %s", p)
|
|
filepath.Walk(p, walkFn)
|
|
}
|
|
|
|
// Generate auto-uncompress function.
|
|
buf := new(bytes.Buffer)
|
|
buf.WriteString(fmt.Sprintf(BaleHeader, conf.Bale.Import,
|
|
strings.Join(resFiles, "\",\n\t\t\""),
|
|
strings.Join(resFiles, ",\n\t\tbale.R")))
|
|
|
|
fw, err := os.Create("bale.go")
|
|
if err != nil {
|
|
logger.Fatalf("Failed to create file: %s", err)
|
|
}
|
|
defer fw.Close()
|
|
|
|
_, err = fw.Write(buf.Bytes())
|
|
if err != nil {
|
|
logger.Fatalf("Failed to write data: %s", err)
|
|
}
|
|
|
|
logger.Success("Baled resources successfully!")
|
|
return 0
|
|
}
|
|
|
|
const (
|
|
// BaleHeader ...
|
|
BaleHeader = `package main
|
|
|
|
import(
|
|
"os"
|
|
"strings"
|
|
"path"
|
|
|
|
"%s"
|
|
)
|
|
|
|
func isExist(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil || os.IsExist(err)
|
|
}
|
|
|
|
func init() {
|
|
files := []string{
|
|
"%s",
|
|
}
|
|
|
|
funcs := []func() []byte{
|
|
bale.R%s,
|
|
}
|
|
|
|
for i, f := range funcs {
|
|
fp := getFilePath(files[i])
|
|
if !isExist(fp) {
|
|
saveFile(fp, f())
|
|
}
|
|
}
|
|
}
|
|
|
|
func getFilePath(name string) string {
|
|
name = strings.Replace(name, "_4_", "/", -1)
|
|
name = strings.Replace(name, "_3_", " ", -1)
|
|
name = strings.Replace(name, "_2_", "-", -1)
|
|
name = strings.Replace(name, "_1_", ".", -1)
|
|
name = strings.Replace(name, "_0_", "_", -1)
|
|
return name
|
|
}
|
|
|
|
func saveFile(filePath string, b []byte) (int, error) {
|
|
os.MkdirAll(path.Dir(filePath), os.ModePerm)
|
|
fw, err := os.Create(filePath)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer fw.Close()
|
|
return fw.Write(b)
|
|
}
|
|
`
|
|
)
|
|
|
|
var resFiles = make([]string, 0, 10)
|
|
|
|
func walkFn(resPath string, info os.FileInfo, err error) error {
|
|
if info.IsDir() || filterSuffix(resPath) {
|
|
return nil
|
|
}
|
|
|
|
// Open resource files
|
|
fr, err := os.Open(resPath)
|
|
if err != nil {
|
|
logger.Fatalf("Failed to read file: %s", err)
|
|
}
|
|
|
|
// Convert path
|
|
resPath = strings.Replace(resPath, "_", "_0_", -1)
|
|
resPath = strings.Replace(resPath, ".", "_1_", -1)
|
|
resPath = strings.Replace(resPath, "-", "_2_", -1)
|
|
resPath = strings.Replace(resPath, " ", "_3_", -1)
|
|
sep := "/"
|
|
if runtime.GOOS == "windows" {
|
|
sep = "\\"
|
|
}
|
|
resPath = strings.Replace(resPath, sep, "_4_", -1)
|
|
|
|
// Create corresponding Go source files
|
|
os.MkdirAll(path.Dir(resPath), os.ModePerm)
|
|
fw, err := os.Create("bale/" + resPath + ".go")
|
|
if err != nil {
|
|
logger.Fatalf("Failed to create file: %s", err)
|
|
}
|
|
defer fw.Close()
|
|
|
|
// Write header
|
|
fmt.Fprintf(fw, Header, resPath)
|
|
|
|
// Copy and compress data
|
|
gz := gzip.NewWriter(&ByteWriter{Writer: fw})
|
|
io.Copy(gz, fr)
|
|
gz.Close()
|
|
|
|
// Write footer.
|
|
fmt.Fprint(fw, Footer)
|
|
|
|
resFiles = append(resFiles, resPath)
|
|
return nil
|
|
}
|
|
|
|
func filterSuffix(name string) bool {
|
|
for _, s := range conf.Bale.IngExt {
|
|
if strings.HasSuffix(name, s) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
const (
|
|
// Header ...
|
|
Header = `package bale
|
|
|
|
import(
|
|
"bytes"
|
|
"compress/gzip"
|
|
"io"
|
|
)
|
|
|
|
func R%s() []byte {
|
|
gz, err := gzip.NewReader(bytes.NewBuffer([]byte{`
|
|
// Footer ...
|
|
Footer = `
|
|
}))
|
|
|
|
if err != nil {
|
|
panic("Unpack resources failed: " + err.Error())
|
|
}
|
|
|
|
var b bytes.Buffer
|
|
io.Copy(&b, gz)
|
|
gz.Close()
|
|
|
|
return b.Bytes()
|
|
}`
|
|
)
|
|
|
|
var newline = []byte{'\n'}
|
|
|
|
// ByteWriter ...
|
|
type ByteWriter struct {
|
|
io.Writer
|
|
c int
|
|
}
|
|
|
|
func (w *ByteWriter) Write(p []byte) (n int, err error) {
|
|
if len(p) == 0 {
|
|
return
|
|
}
|
|
|
|
for n = range p {
|
|
if w.c%12 == 0 {
|
|
w.Writer.Write(newline)
|
|
w.c = 0
|
|
}
|
|
fmt.Fprintf(w.Writer, "0x%02x,", p[n])
|
|
w.c++
|
|
}
|
|
n++
|
|
return
|
|
}
|