forked from lug/matterbridge
		
	
		
			
				
	
	
		
			205 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			5.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package main
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/gob"
 | |
| 	"fmt"
 | |
| 	"go/build"
 | |
| 	"io"
 | |
| 	"io/ioutil"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| 	"text/template"
 | |
| 
 | |
| 	"github.com/GeertJohan/go.rice/embedded"
 | |
| 	"github.com/akavel/rsrc/coff"
 | |
| )
 | |
| 
 | |
| type sizedReader struct {
 | |
| 	*bytes.Reader
 | |
| }
 | |
| 
 | |
| func (s sizedReader) Size() int64 {
 | |
| 	return int64(s.Len())
 | |
| }
 | |
| 
 | |
| var tmplEmbeddedSysoHelper *template.Template
 | |
| 
 | |
| func init() {
 | |
| 	var err error
 | |
| 	tmplEmbeddedSysoHelper, err = template.New("embeddedSysoHelper").Parse(`package {{.Package}}
 | |
| // ############# GENERATED CODE #####################
 | |
| // ## This file was generated by the rice tool.
 | |
| // ## Do not edit unless you know what you're doing.
 | |
| // ##################################################
 | |
| 
 | |
| // extern char _bricebox_{{.Symname}}[], _ericebox_{{.Symname}};
 | |
| // int get_{{.Symname}}_length() {
 | |
| // 	return &_ericebox_{{.Symname}} - _bricebox_{{.Symname}};
 | |
| // }
 | |
| import "C"
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"encoding/gob"
 | |
| 	"github.com/GeertJohan/go.rice/embedded"
 | |
| 	"unsafe"
 | |
| )
 | |
| 
 | |
| func init() {
 | |
| 	ptr := unsafe.Pointer(&C._bricebox_{{.Symname}})
 | |
| 	bts := C.GoBytes(ptr, C.get_{{.Symname}}_length())
 | |
| 	embeddedBox := &embedded.EmbeddedBox{}
 | |
| 	err := gob.NewDecoder(bytes.NewReader(bts)).Decode(embeddedBox)
 | |
| 	if err != nil {
 | |
| 		panic("error decoding embedded box: "+err.Error())
 | |
| 	}
 | |
| 	embeddedBox.Link()
 | |
| 	embedded.RegisterEmbeddedBox(embeddedBox.Name, embeddedBox)
 | |
| }`)
 | |
| 	if err != nil {
 | |
| 		panic("could not parse template embeddedSysoHelper: " + err.Error())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| type embeddedSysoHelperData struct {
 | |
| 	Package string
 | |
| 	Symname string
 | |
| }
 | |
| 
 | |
| func operationEmbedSyso(pkg *build.Package) {
 | |
| 
 | |
| 	regexpSynameReplacer := regexp.MustCompile(`[^a-z0-9_]`)
 | |
| 
 | |
| 	boxMap := findBoxes(pkg)
 | |
| 
 | |
| 	// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
 | |
| 	if len(boxMap) == 0 {
 | |
| 		fmt.Println("no calls to rice.FindBox() found")
 | |
| 		return
 | |
| 	}
 | |
| 
 | |
| 	verbosef("\n")
 | |
| 
 | |
| 	for boxname := range boxMap {
 | |
| 		// find path and filename for this box
 | |
| 		boxPath := filepath.Join(pkg.Dir, boxname)
 | |
| 		boxFilename := strings.Replace(boxname, "/", "-", -1)
 | |
| 		boxFilename = strings.Replace(boxFilename, "..", "back", -1)
 | |
| 		boxFilename = strings.Replace(boxFilename, ".", "-", -1)
 | |
| 
 | |
| 		// verbose info
 | |
| 		verbosef("embedding box '%s'\n", boxname)
 | |
| 		verbosef("\tto file %s\n", boxFilename)
 | |
| 
 | |
| 		// read box metadata
 | |
| 		boxInfo, ierr := os.Stat(boxPath)
 | |
| 		if ierr != nil {
 | |
| 			fmt.Printf("Error: unable to access box at %s\n", boxPath)
 | |
| 			os.Exit(1)
 | |
| 		}
 | |
| 
 | |
| 		// create box datastructure (used by template)
 | |
| 		box := &embedded.EmbeddedBox{
 | |
| 			Name:      boxname,
 | |
| 			Time:      boxInfo.ModTime(),
 | |
| 			EmbedType: embedded.EmbedTypeSyso,
 | |
| 			Files:     make(map[string]*embedded.EmbeddedFile),
 | |
| 			Dirs:      make(map[string]*embedded.EmbeddedDir),
 | |
| 		}
 | |
| 
 | |
| 		// fill box datastructure with file data
 | |
| 		filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
 | |
| 			if err != nil {
 | |
| 				fmt.Printf("error walking box: %s\n", err)
 | |
| 				os.Exit(1)
 | |
| 			}
 | |
| 
 | |
| 			filename := strings.TrimPrefix(path, boxPath)
 | |
| 			filename = strings.Replace(filename, "\\", "/", -1)
 | |
| 			filename = strings.TrimPrefix(filename, "/")
 | |
| 			if info.IsDir() {
 | |
| 				embeddedDir := &embedded.EmbeddedDir{
 | |
| 					Filename:   filename,
 | |
| 					DirModTime: info.ModTime(),
 | |
| 				}
 | |
| 				verbosef("\tincludes dir: '%s'\n", embeddedDir.Filename)
 | |
| 				box.Dirs[embeddedDir.Filename] = embeddedDir
 | |
| 
 | |
| 				// add tree entry (skip for root, it'll create a recursion)
 | |
| 				if embeddedDir.Filename != "" {
 | |
| 					pathParts := strings.Split(embeddedDir.Filename, "/")
 | |
| 					parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
 | |
| 					parentDir.ChildDirs = append(parentDir.ChildDirs, embeddedDir)
 | |
| 				}
 | |
| 			} else {
 | |
| 				embeddedFile := &embedded.EmbeddedFile{
 | |
| 					Filename:    filename,
 | |
| 					FileModTime: info.ModTime(),
 | |
| 					Content:     "",
 | |
| 				}
 | |
| 				verbosef("\tincludes file: '%s'\n", embeddedFile.Filename)
 | |
| 				contentBytes, err := ioutil.ReadFile(path)
 | |
| 				if err != nil {
 | |
| 					fmt.Printf("error reading file content while walking box: %s\n", err)
 | |
| 					os.Exit(1)
 | |
| 				}
 | |
| 				embeddedFile.Content = string(contentBytes)
 | |
| 				box.Files[embeddedFile.Filename] = embeddedFile
 | |
| 			}
 | |
| 			return nil
 | |
| 		})
 | |
| 
 | |
| 		// encode embedded box to gob file
 | |
| 		boxGobBuf := &bytes.Buffer{}
 | |
| 		err := gob.NewEncoder(boxGobBuf).Encode(box)
 | |
| 		if err != nil {
 | |
| 			fmt.Printf("error encoding box to gob: %v\n", err)
 | |
| 			os.Exit(1)
 | |
| 		}
 | |
| 
 | |
| 		verbosef("gob-encoded embeddedBox is %d bytes large\n", boxGobBuf.Len())
 | |
| 
 | |
| 		// write coff
 | |
| 		symname := regexpSynameReplacer.ReplaceAllString(boxname, "_")
 | |
| 		createCoffSyso(boxname, symname, "386", boxGobBuf.Bytes())
 | |
| 		createCoffSyso(boxname, symname, "amd64", boxGobBuf.Bytes())
 | |
| 
 | |
| 		// write go
 | |
| 		sysoHelperData := embeddedSysoHelperData{
 | |
| 			Package: pkg.Name,
 | |
| 			Symname: symname,
 | |
| 		}
 | |
| 		fileSysoHelper, err := os.Create(boxFilename + ".rice-box.go")
 | |
| 		if err != nil {
 | |
| 			fmt.Printf("error creating syso helper: %v\n", err)
 | |
| 			os.Exit(1)
 | |
| 		}
 | |
| 		err = tmplEmbeddedSysoHelper.Execute(fileSysoHelper, sysoHelperData)
 | |
| 		if err != nil {
 | |
| 			fmt.Printf("error executing tmplEmbeddedSysoHelper: %v\n", err)
 | |
| 			os.Exit(1)
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func createCoffSyso(boxFilename string, symname string, arch string, data []byte) {
 | |
| 	boxCoff := coff.NewRDATA()
 | |
| 	switch arch {
 | |
| 	case "386":
 | |
| 	case "amd64":
 | |
| 		boxCoff.FileHeader.Machine = 0x8664
 | |
| 	default:
 | |
| 		panic("invalid arch")
 | |
| 	}
 | |
| 	boxCoff.AddData("_bricebox_"+symname, sizedReader{bytes.NewReader(data)})
 | |
| 	boxCoff.AddData("_ericebox_"+symname, io.NewSectionReader(strings.NewReader("\000\000"), 0, 2)) // TODO: why? copied from rsrc, which copied it from as-generated
 | |
| 	boxCoff.Freeze()
 | |
| 	err := writeCoff(boxCoff, boxFilename+"_"+arch+".rice-box.syso")
 | |
| 	if err != nil {
 | |
| 		fmt.Printf("error writing %s coff/.syso: %v\n", arch, err)
 | |
| 		os.Exit(1)
 | |
| 	}
 | |
| }
 | 
