229 lines
		
	
	
		
			4.6 KiB
		
	
	
	
		
			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
 | |
| }
 |