serviceman/vendor/github.com/UnnoTed/fileb0x/custom/custom.go

229 lines
4.6 KiB
Go

package custom
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path"
"strings"
"github.com/UnnoTed/fileb0x/compression"
"github.com/UnnoTed/fileb0x/dir"
"github.com/UnnoTed/fileb0x/file"
"github.com/UnnoTed/fileb0x/updater"
"github.com/UnnoTed/fileb0x/utils"
"github.com/bmatcuk/doublestar"
"github.com/karrick/godirwalk"
)
const hextable = "0123456789abcdef"
// SharedConfig holds needed data from config package
// without causing import cycle
type SharedConfig struct {
Output string
Compression *compression.Gzip
Updater updater.Config
}
// Custom is a set of files with dedicaTed customization
type Custom struct {
Files []string
Base string
Prefix string
Tags string
Exclude []string
Replace []Replacer
}
var (
xx = []byte(`\x`)
start = []byte(`[]byte("`)
)
const lowerhex = "0123456789abcdef"
// Parse the files transforming them into a byte string and inserting the file
// into a map of files
func (c *Custom) Parse(files *map[string]*file.File, dirs **dir.Dir, config *SharedConfig) error {
to := *files
dirList := *dirs
var newList []string
for _, customFile := range c.Files {
// get files from glob
list, err := doublestar.Glob(customFile)
if err != nil {
return err
}
// insert files from glob into the new list
newList = append(newList, list...)
}
// copy new list
c.Files = newList
// 0 files in the list
if len(c.Files) == 0 {
return errors.New("No files found")
}
// loop through files from glob
for _, customFile := range c.Files {
// gives error when file doesn't exist
if !utils.Exists(customFile) {
return fmt.Errorf("File [%s] doesn't exist", customFile)
}
cb := func(fpath string, d *godirwalk.Dirent) error {
if config.Updater.Empty && !config.Updater.IsUpdating {
log.Println("empty mode")
return nil
}
// only files will be processed
if d != nil && d.IsDir() {
return nil
}
originalPath := fpath
fpath = utils.FixPath(fpath)
var fixedPath string
if c.Prefix != "" || c.Base != "" {
c.Base = strings.TrimPrefix(c.Base, "./")
if strings.HasPrefix(fpath, c.Base) {
fixedPath = c.Prefix + fpath[len(c.Base):]
} else {
if c.Base != "" {
fixedPath = c.Prefix + fpath
}
}
fixedPath = utils.FixPath(fixedPath)
} else {
fixedPath = utils.FixPath(fpath)
}
// check for excluded files
for _, excludedFile := range c.Exclude {
m, err := doublestar.Match(c.Prefix+excludedFile, fixedPath)
if err != nil {
return err
}
if m {
return nil
}
}
info, err := os.Stat(fpath)
if err != nil {
return err
}
if info.Name() == config.Output {
return nil
}
// get file's content
content, err := ioutil.ReadFile(fpath)
if err != nil {
return err
}
replaced := false
// loop through replace list
for _, r := range c.Replace {
// check if path matches the pattern from property: file
matched, err := doublestar.Match(c.Prefix+r.File, fixedPath)
if err != nil {
return err
}
if matched {
for pattern, word := range r.Replace {
content = []byte(strings.Replace(string(content), pattern, word, -1))
replaced = true
}
}
}
// compress the content
if config.Compression.Options != nil {
content, err = config.Compression.Compress(content)
if err != nil {
return err
}
}
dst := make([]byte, len(content)*4)
for i := 0; i < len(content); i++ {
dst[i*4] = byte('\\')
dst[i*4+1] = byte('x')
dst[i*4+2] = hextable[content[i]>>4]
dst[i*4+3] = hextable[content[i]&0x0f]
}
f := file.NewFile()
f.OriginalPath = originalPath
f.ReplacedText = replaced
f.Data = `[]byte("` + string(dst) + `")`
f.Name = info.Name()
f.Path = fixedPath
f.Tags = c.Tags
f.Base = c.Base
f.Prefix = c.Prefix
f.Modified = info.ModTime().String()
if _, ok := to[fixedPath]; ok {
f.Tags = to[fixedPath].Tags
}
// insert dir to dirlist so it can be created on b0x's init()
dirList.Insert(path.Dir(fixedPath))
// insert file into file list
to[fixedPath] = f
return nil
}
customFile = utils.FixPath(customFile)
// unlike filepath.walk, godirwalk will only walk dirs
f, err := os.Open(customFile)
if err != nil {
return err
}
defer f.Close()
fs, err := f.Stat()
if err != nil {
return err
}
if fs.IsDir() {
if err := godirwalk.Walk(customFile, &godirwalk.Options{
Unsorted: true,
Callback: cb,
}); err != nil {
return err
}
} else {
if err := cb(customFile, nil); err != nil {
return err
}
}
}
return nil
}