complete rewrite, added basic documentation
This commit is contained in:
		
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
								
							| @ -0,0 +1,28 @@ | |||||||
|  | togo | ||||||
|  | ==== | ||||||
|  | togo converts files to Go source code as a byte array. | ||||||
|  | togo is based on (but is a complete rewrite of) | ||||||
|  | [Franco Lazzarino's togo](https://github.com/flazz/togo). | ||||||
|  |  | ||||||
|  |  | ||||||
|  | usage | ||||||
|  | ----- | ||||||
|  | togo is designed to be embedded in your Go project for a dependency free | ||||||
|  | way to manage assets. | ||||||
|  |  | ||||||
|  | First, copy `main.go` from togo into a subdirectory in your | ||||||
|  | project (for example, a subdirectory named `togo`.) | ||||||
|  |  | ||||||
|  | Next, add comments to indicate to go generate that you wish to run | ||||||
|  | your local copy of togo to build assets. | ||||||
|  |  | ||||||
|  |     //go:generate go run ./togo -n Favicon_ico -i assets/favicon.ico -p static -o static/favicon_ico.go | ||||||
|  |  | ||||||
|  | togo takes some basic arguments: | ||||||
|  |  | ||||||
|  | Argument | Description | ||||||
|  | -------- | ----------- | ||||||
|  | -p | generated package name | ||||||
|  | -n | generated variable name | ||||||
|  | -i | input file name | ||||||
|  | -o | output file name | ||||||
|  | |||||||
							
								
								
									
										147
									
								
								main.go
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								main.go
									
									
									
									
									
								
							| @ -1,111 +1,88 @@ | |||||||
| package main | package main | ||||||
|  |  | ||||||
| import ( | import ( | ||||||
| 	"bytes" |  | ||||||
| 	"flag" | 	"flag" | ||||||
| 	"go/format" | 	"fmt" | ||||||
| 	"io" | 	"io" | ||||||
| 	"io/ioutil" |  | ||||||
| 	"log" | 	"log" | ||||||
| 	"os" | 	"os" | ||||||
| 	"text/template" | 	"time" | ||||||
| ) | ) | ||||||
|  |  | ||||||
| const chunkSize = 0x10 |  | ||||||
|  |  | ||||||
| const tmpl = ` |  | ||||||
| package {{.Pkg}} |  | ||||||
|  |  | ||||||
| var {{.Name}} = []byte{ |  | ||||||
|     // {{ len .Value }} bytes from {{ .InputPath }} |  | ||||||
| 	{{ range .Chunks -}} |  | ||||||
| 		{{ range . }} {{ printf "0x%02x" . }}, {{ end }} |  | ||||||
| 	{{ end }} |  | ||||||
| } |  | ||||||
| ` |  | ||||||
|  |  | ||||||
| var t *template.Template |  | ||||||
|  |  | ||||||
| func init() { |  | ||||||
| 	t = template.Must(template.New("constfile").Parse(tmpl)) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| type file struct { |  | ||||||
| 	Pkg, Name, InputPath string |  | ||||||
| 	Value                []byte |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (f *file) Chunks() [][]byte { |  | ||||||
| 	return chunks(f.Value, chunkSize) |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func chunks(b []byte, n int) [][]byte { |  | ||||||
| 	var c [][]byte |  | ||||||
|  |  | ||||||
| 	nChks := len(b) / n |  | ||||||
|  |  | ||||||
| 	for i := 0; i < nChks; i++ { |  | ||||||
| 		m := i * n |  | ||||||
| 		c = append(c, b[m:m+n]) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if r := len(b) % n; r > 0 { |  | ||||||
| 		m := n * nChks |  | ||||||
| 		c = append(c, b[m:m+r]) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (f *file) Read() (err error) { |  | ||||||
| 	f.Value, err = ioutil.ReadFile(f.InputPath) |  | ||||||
| 	return |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func (f *file) Render(w io.Writer) error { |  | ||||||
| 	outputPath := f.InputPath + ".go" |  | ||||||
| 	var buf bytes.Buffer |  | ||||||
| 	if err := t.Execute(&buf, &f); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	b, err := format.Source(buf.Bytes()) |  | ||||||
| 	if err != nil { |  | ||||||
| 		log.Fatal(err) |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	if err := ioutil.WriteFile(outputPath, b, os.ModePerm); err != nil { |  | ||||||
| 		return err |  | ||||||
| 	} |  | ||||||
|  |  | ||||||
| 	return nil |  | ||||||
| } |  | ||||||
|  |  | ||||||
| func main() { | func main() { | ||||||
|  | 	pkg := flag.String("p", "", "package") | ||||||
| 	var f file | 	name := flag.String("n", "", "const name") | ||||||
| 	flag.StringVar(&f.Pkg, "pkg", "", "package") | 	inputfn := flag.String("i", "", "input file") | ||||||
| 	flag.StringVar(&f.Name, "name", "", "const name") | 	outputfn := flag.String("o", "", "output file") | ||||||
| 	flag.StringVar(&f.InputPath, "input", "", "input file") |  | ||||||
| 	flag.Parse() | 	flag.Parse() | ||||||
|  |  | ||||||
| 	if f.Pkg == "" { | 	if *pkg == "" { | ||||||
| 		log.Fatal("pkg required") | 		log.Fatal("pkg required") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if f.Name == "" { | 	if *name == "" { | ||||||
| 		log.Fatal("name required") | 		log.Fatal("name required") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if f.InputPath == "" { | 	if *inputfn == "" { | ||||||
| 		log.Fatal("input file required") | 		log.Fatal("input file required") | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := f.Read(); err != nil { | 	if *outputfn == "" { | ||||||
| 		log.Fatal(err) | 		*outputfn = *inputfn + ".go" | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	if err := f.Render(os.Stdout); err != nil { | 	omod := fmod(*outputfn) | ||||||
|  | 	imod := fmod(*inputfn) | ||||||
|  | 	if omod.After(imod) { | ||||||
|  | 		log.Printf("Refusing to update %s\n", *outputfn) | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	ifile, err := os.Open(*inputfn) | ||||||
|  | 	if err != nil { | ||||||
| 		log.Fatal(err) | 		log.Fatal(err) | ||||||
| 	} | 	} | ||||||
|  | 	defer ifile.Close() | ||||||
|  |  | ||||||
|  | 	ofile, err := os.OpenFile(*outputfn, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0660) | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	defer ofile.Close() | ||||||
|  |  | ||||||
|  | 	fmt.Fprintf(ofile, "package %s\n\nvar %s = []byte{", *pkg, *name) | ||||||
|  |  | ||||||
|  | 	buf := make([]byte, 4096) | ||||||
|  | 	for c := 0; ; { | ||||||
|  | 		i, err := ifile.Read(buf) | ||||||
|  | 		if err != nil { | ||||||
|  | 			if err != io.EOF { | ||||||
|  | 				log.Fatal(err) | ||||||
|  | 			} | ||||||
|  | 			break | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		for j := 0; j < i; j++ { | ||||||
|  | 			if (c % 13) == 0 { | ||||||
|  | 				fmt.Fprintf(ofile, "\n\t") | ||||||
|  | 			} else { | ||||||
|  | 				fmt.Fprintf(ofile, " ") | ||||||
|  | 			} | ||||||
|  | 			fmt.Fprintf(ofile, "0x%02x,", buf[j]) | ||||||
|  | 			c++ | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	fmt.Fprintf(ofile, "\n}\n") | ||||||
|  | } | ||||||
|  |  | ||||||
|  | func fmod(fn string) time.Time { | ||||||
|  | 	fi, err := os.Stat(fn) | ||||||
|  | 	if err != nil { | ||||||
|  | 		if os.IsNotExist(err) { | ||||||
|  | 			return time.Time{} | ||||||
|  | 		} | ||||||
|  | 		log.Fatal(err) | ||||||
|  | 	} | ||||||
|  | 	return fi.ModTime() | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Christopher Ramey
						Christopher Ramey