diff --git a/builder.go b/builder.go new file mode 100644 index 0000000..66b193e --- /dev/null +++ b/builder.go @@ -0,0 +1,129 @@ +package godog + +import ( + "bytes" + "go/ast" + "go/format" + "go/parser" + "go/token" + "log" + "os" + "path/filepath" + "strings" + + "golang.org/x/tools/imports" +) + +var mainTpl = `package main + +import ( + "github.com/DATA-DOG/godog" + "os" +) + +func main() { + godog.Run() + os.Exit(0) +} +` + +type builder struct { + files map[string]*ast.File + fset *token.FileSet +} + +func newBuilder() *builder { + return &builder{ + files: make(map[string]*ast.File), + fset: token.NewFileSet(), + } +} + +func (b *builder) parseFile(path string) error { + f, err := parser.ParseFile(b.fset, path, nil, 0) + if err != nil { + return err + } + b.deleteMainFunc(f) + b.deleteImports(f) + b.files[f.Name.Name] = f + return nil +} + +func (b *builder) deleteImports(f *ast.File) { + var decls []ast.Decl + for _, d := range f.Decls { + fun, ok := d.(*ast.GenDecl) + if !ok { + decls = append(decls, d) + continue + } + if fun.Tok != token.IMPORT { + decls = append(decls, fun) + } + } + f.Decls = decls +} + +func (b *builder) deleteMainFunc(f *ast.File) { + var decls []ast.Decl + for _, d := range f.Decls { + fun, ok := d.(*ast.FuncDecl) + if !ok { + decls = append(decls, d) + continue + } + if fun.Name.Name != "main" { + decls = append(decls, fun) + } + } + f.Decls = decls +} + +func (b *builder) merge() (*ast.File, error) { + f, err := parser.ParseFile(b.fset, "", mainTpl, 0) + if err != nil { + log.Println("fail here") + return nil, err + } + b.deleteImports(f) + b.files["main.go"] = f + + pkg, _ := ast.NewPackage(b.fset, b.files, nil, nil) + pkg.Name = "main" + + return ast.MergePackageFiles(pkg, ast.FilterImportDuplicates), nil +} + +// Build creates a runnable godog executable +// from current package go files +func Build() ([]byte, error) { + b := newBuilder() + err := filepath.Walk(".", func(path string, file os.FileInfo, err error) error { + if file.IsDir() && file.Name() != "." { + return filepath.SkipDir + } + if err == nil && strings.HasSuffix(path, ".go") { + if err := b.parseFile(path); err != nil { + return err + } + } + return err + }) + if err != nil { + return nil, err + } + + merged, err := b.merge() + if err != nil { + return nil, err + } + + var buf bytes.Buffer + + if err := format.Node(&buf, b.fset, merged); err != nil { + return nil, err + } + + return imports.Process("", buf.Bytes(), nil) +} diff --git a/cmd/godog/main.go b/cmd/godog/main.go index 1e96901..f968eb8 100644 --- a/cmd/godog/main.go +++ b/cmd/godog/main.go @@ -1,5 +1,29 @@ package main +import ( + "os" + + "github.com/DATA-DOG/godog" +) + func main() { - // well, not runnable yet + builtFile := os.TempDir() + "/godog_build.go" + if err := os.Remove(builtFile); err != nil && !os.IsNotExist(err) { + panic(err) + } + + buf, err := godog.Build() + if err != nil { + panic(err) + } + + w, err := os.Create(builtFile) + if err != nil { + panic(err) + } + _, err = w.Write(buf) + if err != nil { + panic(err) + } + w.Close() } diff --git a/runner.go b/runner.go new file mode 100644 index 0000000..1cf1f1b --- /dev/null +++ b/runner.go @@ -0,0 +1,7 @@ +package godog + +import "log" + +func Run() { + log.Println("running godoc, num registered steps:", len(stepHandlers)) +} diff --git a/steps_test.go b/steps_test.go new file mode 100644 index 0000000..0e64ec7 --- /dev/null +++ b/steps_test.go @@ -0,0 +1,14 @@ +package godog + +import ( + "log" + "regexp" +) + +func init() { + f := StepHandlerFunc(func(args ...interface{}) error { + log.Println("step triggered") + return nil + }) + Step(regexp.MustCompile("hello"), f) +}