Skip to content

Commit

Permalink
Generate separate data and common files.
Browse files Browse the repository at this point in the history
The goal is to resolve #23, to make it possible to use vfsgen multiple
times in same package.

Previously, that would cause an error because the same types would be
defined in each generated file.

The approach to solve that is to generate two files:

-	VFS data file
-	common type definitions file

This avoids the multiple declaration issues in an efficient way.

A downside is having 2 files as generated output, instead of one.
  • Loading branch information
dmitshur committed Dec 23, 2016
1 parent b96cc88 commit c1e2560
Show file tree
Hide file tree
Showing 6 changed files with 265 additions and 227 deletions.
70 changes: 43 additions & 27 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,22 @@ import (
func Generate(input http.FileSystem, opt Options) error {
opt.fillMissing()

// Create output file.
f, err := os.Create(opt.Filename)
// Create common output file.
f, err := os.Create(opt.CommonFilename)
if err != nil {
return err
}

err = t.ExecuteTemplate(f, "Common", opt)
if err != nil {
f.Close()
return err
}

f.Close()

// Create data output file.
f, err = os.Create(opt.DataFilename)
if err != nil {
return err
}
Expand All @@ -45,11 +59,6 @@ func Generate(input http.FileSystem, opt Options) error {
return err
}

err = t.ExecuteTemplate(f, "Trailer", toc)
if err != nil {
return err
}

// Trim any potential excess.
cur, err := f.Seek(0, io.SeekCurrent)
if err != nil {
Expand Down Expand Up @@ -241,17 +250,14 @@ var t = template.Must(template.New("").Funcs(template.FuncMap{
{{end}}package {{.PackageName}}
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
pathpkg "path"
"time"
)
// We imported "os", but may end up not using it. Avoid unused import error.
var _ os.FileInfo
{{comment .VariableComment}}
var {{.VariableName}} = func() http.FileSystem {
mustUnmarshalTextTime := func(text string) time.Time {
Expand Down Expand Up @@ -307,7 +313,24 @@ var {{.VariableName}} = func() http.FileSystem {
{{define "Trailer"}}
{{define "Common"}}// Code generated by vfsgen; DO NOT EDIT
{{with .BuildTags}}// +build {{.}}
{{end}}package {{.PackageName}}
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"net/http"
"os"
pathpkg "path"
"time"
)
type vfsgen۰FS map[string]interface{}
func (fs vfsgen۰FS) Open(path string) (http.File, error) {
Expand All @@ -317,7 +340,7 @@ func (fs vfsgen۰FS) Open(path string) (http.File, error) {
return nil, &os.PathError{Op: "open", Path: path, Err: os.ErrNotExist}
}
switch f := f.(type) {{"{"}}{{if .HasCompressedFile}}
switch f := f.(type) {
case *vfsgen۰CompressedFileInfo:
gr, err := gzip.NewReader(bytes.NewReader(f.compressedContent))
if err != nil {
Expand All @@ -327,12 +350,12 @@ func (fs vfsgen۰FS) Open(path string) (http.File, error) {
return &vfsgen۰CompressedFile{
vfsgen۰CompressedFileInfo: f,
gr: gr,
}, nil{{end}}{{if .HasFile}}
}, nil
case *vfsgen۰FileInfo:
return &vfsgen۰File{
vfsgen۰FileInfo: f,
Reader: bytes.NewReader(f.content),
}, nil{{end}}
}, nil
case *vfsgen۰DirInfo:
return &vfsgen۰Dir{
vfsgen۰DirInfo: f,
Expand All @@ -342,7 +365,7 @@ func (fs vfsgen۰FS) Open(path string) (http.File, error) {
panic(fmt.Sprintf("unexpected type %T", f))
}
}
{{if .HasCompressedFile}}
// vfsgen۰CompressedFileInfo is a static definition of a gzip compressed file.
type vfsgen۰CompressedFileInfo struct {
name string
Expand Down Expand Up @@ -413,11 +436,7 @@ func (f *vfsgen۰CompressedFile) Seek(offset int64, whence int) (int64, error) {
func (f *vfsgen۰CompressedFile) Close() error {
return f.gr.Close()
}
{{else}}
// We already imported "compress/gzip" and "io/ioutil", but ended up not using them. Avoid unused import error.
var _ = gzip.Reader{}
var _ = ioutil.Discard
{{end}}{{if .HasFile}}
// vfsgen۰FileInfo is a static definition of an uncompressed file (because it's not worth gzip compressing).
type vfsgen۰FileInfo struct {
name string
Expand Down Expand Up @@ -448,10 +467,7 @@ type vfsgen۰File struct {
func (f *vfsgen۰File) Close() error {
return nil
}
{{else}}
// We already imported "bytes", but ended up not using it. Avoid unused import error.
var _ = bytes.Reader{}
{{end}}
// vfsgen۰DirInfo is a static definition of a directory.
type vfsgen۰DirInfo struct {
name string
Expand Down
12 changes: 7 additions & 5 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,20 +79,22 @@ func TestGenerate_buildAndGofmt(t *testing.T) {
}

for _, test := range tests {
filename := filepath.Join(tempDir, test.filename)
dataFilename := filepath.Join(tempDir, test.filename)
commonFilename := filepath.Join(tempDir, "vfsgencommon.go")

err = vfsgen.Generate(test.fs, vfsgen.Options{
Filename: filename,
PackageName: "test",
DataFilename: dataFilename,
CommonFilename: commonFilename,
PackageName: "test",
})
if err != nil {
t.Fatalf("vfsgen.Generate() failed: %v", err)
}

if out, err := exec.Command("go", "build", filename).CombinedOutput(); err != nil {
if out, err := exec.Command("go", "build", dataFilename, commonFilename).CombinedOutput(); err != nil {
t.Errorf("err: %v\nout: %s", err, out)
}
if out, err := exec.Command("gofmt", "-d", "-s", filename).Output(); err != nil || len(out) != 0 {
if out, err := exec.Command("gofmt", "-d", "-s", dataFilename, commonFilename).Output(); err != nil || len(out) != 0 {
t.Errorf("gofmt issue\nerr: %v\nout: %s", err, out)
}
}
Expand Down
15 changes: 11 additions & 4 deletions options.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@ import (

// Options for vfsgen code generation.
type Options struct {
// Filename of the generated Go code output (including extension).
// DataFilename is the filename of the generated VFS data Go code (including extension).
// If left empty, it defaults to "{{toLower .VariableName}}_vfsdata.go".
Filename string
DataFilename string

// CommonFilename is the filename of the generated common vfsgen Go code (including extension).
// If left empty, it defaults to "vfsgencommon.go".
CommonFilename string

// PackageName is the name of the package in the generated code.
// If left empty, it defaults to "main".
Expand All @@ -33,11 +37,14 @@ func (opt *Options) fillMissing() {
if opt.PackageName == "" {
opt.PackageName = "main"
}
if opt.CommonFilename == "" {
opt.CommonFilename = "vfsgencommon.go"
}
if opt.VariableName == "" {
opt.VariableName = "assets"
}
if opt.Filename == "" {
opt.Filename = fmt.Sprintf("%s_vfsdata.go", strings.ToLower(opt.VariableName))
if opt.DataFilename == "" {
opt.DataFilename = fmt.Sprintf("%s_vfsdata.go", strings.ToLower(opt.VariableName))
}
if opt.VariableComment == "" {
opt.VariableComment = fmt.Sprintf("%s statically implements the virtual filesystem provided to vfsgen.", opt.VariableName)
Expand Down
5 changes: 3 additions & 2 deletions test/test_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ func main() {
}))

err := vfsgen.Generate(fs, vfsgen.Options{
Filename: "test_vfsdata_test.go",
PackageName: "test_test",
DataFilename: "test_vfsdata_test.go",
CommonFilename: "vfsgencommon_test.go",
PackageName: "test_test",
})
if err != nil {
log.Fatalln(err)
Expand Down
Loading

0 comments on commit c1e2560

Please sign in to comment.