forked from lug/matterbridge
		
	
		
			
				
	
	
		
			139 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			139 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package rice
 | 
						|
 | 
						|
import (
 | 
						|
	"archive/zip"
 | 
						|
	"log"
 | 
						|
	"os"
 | 
						|
	"path/filepath"
 | 
						|
	"strings"
 | 
						|
	"time"
 | 
						|
 | 
						|
	"github.com/daaku/go.zipexe"
 | 
						|
	"github.com/kardianos/osext"
 | 
						|
)
 | 
						|
 | 
						|
// appendedBox defines an appended box
 | 
						|
type appendedBox struct {
 | 
						|
	Name  string                   // box name
 | 
						|
	Files map[string]*appendedFile // appended files (*zip.File) by full path
 | 
						|
}
 | 
						|
 | 
						|
type appendedFile struct {
 | 
						|
	zipFile  *zip.File
 | 
						|
	dir      bool
 | 
						|
	dirInfo  *appendedDirInfo
 | 
						|
	children []*appendedFile
 | 
						|
	content  []byte
 | 
						|
}
 | 
						|
 | 
						|
// appendedBoxes is a public register of appendes boxes
 | 
						|
var appendedBoxes = make(map[string]*appendedBox)
 | 
						|
 | 
						|
func init() {
 | 
						|
	// find if exec is appended
 | 
						|
	thisFile, err := osext.Executable()
 | 
						|
	if err != nil {
 | 
						|
		return // not appended or cant find self executable
 | 
						|
	}
 | 
						|
	closer, rd, err := zipexe.OpenCloser(thisFile)
 | 
						|
	if err != nil {
 | 
						|
		return // not appended
 | 
						|
	}
 | 
						|
	defer closer.Close()
 | 
						|
 | 
						|
	for _, f := range rd.File {
 | 
						|
		// get box and file name from f.Name
 | 
						|
		fileParts := strings.SplitN(strings.TrimLeft(filepath.ToSlash(f.Name), "/"), "/", 2)
 | 
						|
		boxName := fileParts[0]
 | 
						|
		var fileName string
 | 
						|
		if len(fileParts) > 1 {
 | 
						|
			fileName = fileParts[1]
 | 
						|
		}
 | 
						|
 | 
						|
		// find box or create new one if doesn't exist
 | 
						|
		box := appendedBoxes[boxName]
 | 
						|
		if box == nil {
 | 
						|
			box = &appendedBox{
 | 
						|
				Name:  boxName,
 | 
						|
				Files: make(map[string]*appendedFile),
 | 
						|
			}
 | 
						|
			appendedBoxes[boxName] = box
 | 
						|
		}
 | 
						|
 | 
						|
		// create and add file to box
 | 
						|
		af := &appendedFile{
 | 
						|
			zipFile: f,
 | 
						|
		}
 | 
						|
		if f.Comment == "dir" {
 | 
						|
			af.dir = true
 | 
						|
			af.dirInfo = &appendedDirInfo{
 | 
						|
				name: filepath.Base(af.zipFile.Name),
 | 
						|
				//++ TODO: use zip modtime when that is set correctly: af.zipFile.ModTime()
 | 
						|
				time: time.Now(),
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			// this is a file, we need it's contents so we can create a bytes.Reader when the file is opened
 | 
						|
			// make a new byteslice
 | 
						|
			af.content = make([]byte, af.zipFile.FileInfo().Size())
 | 
						|
			// ignore reading empty files from zip (empty file still is a valid file to be read though!)
 | 
						|
			if len(af.content) > 0 {
 | 
						|
				// open io.ReadCloser
 | 
						|
				rc, err := af.zipFile.Open()
 | 
						|
				if err != nil {
 | 
						|
					af.content = nil // this will cause an error when the file is being opened or seeked (which is good)
 | 
						|
					// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet..
 | 
						|
					log.Printf("error opening appended file %s: %v", af.zipFile.Name, err)
 | 
						|
				} else {
 | 
						|
					_, err = rc.Read(af.content)
 | 
						|
					rc.Close()
 | 
						|
					if err != nil {
 | 
						|
						af.content = nil // this will cause an error when the file is being opened or seeked (which is good)
 | 
						|
						// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet..
 | 
						|
						log.Printf("error reading data for appended file %s: %v", af.zipFile.Name, err)
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// add appendedFile to box file list
 | 
						|
		box.Files[fileName] = af
 | 
						|
 | 
						|
		// add to parent dir (if any)
 | 
						|
		dirName := filepath.Dir(fileName)
 | 
						|
		if dirName == "." {
 | 
						|
			dirName = ""
 | 
						|
		}
 | 
						|
		if fileName != "" { // don't make box root dir a child of itself
 | 
						|
			if dir := box.Files[dirName]; dir != nil {
 | 
						|
				dir.children = append(dir.children, af)
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// implements os.FileInfo.
 | 
						|
// used for Readdir()
 | 
						|
type appendedDirInfo struct {
 | 
						|
	name string
 | 
						|
	time time.Time
 | 
						|
}
 | 
						|
 | 
						|
func (adi *appendedDirInfo) Name() string {
 | 
						|
	return adi.name
 | 
						|
}
 | 
						|
func (adi *appendedDirInfo) Size() int64 {
 | 
						|
	return 0
 | 
						|
}
 | 
						|
func (adi *appendedDirInfo) Mode() os.FileMode {
 | 
						|
	return os.ModeDir
 | 
						|
}
 | 
						|
func (adi *appendedDirInfo) ModTime() time.Time {
 | 
						|
	return adi.time
 | 
						|
}
 | 
						|
func (adi *appendedDirInfo) IsDir() bool {
 | 
						|
	return true
 | 
						|
}
 | 
						|
func (adi *appendedDirInfo) Sys() interface{} {
 | 
						|
	return nil
 | 
						|
}
 |