update to work with go modules

This commit is contained in:
amanbolat 2018-12-30 01:20:08 +08:00 committed by Dan Markham
parent bbb4825a38
commit b0dd5b45a5
No known key found for this signature in database
GPG Key ID: 7994037517927D77
4 changed files with 135 additions and 63 deletions

View File

@ -126,7 +126,14 @@ func copy(to, from string) error {
// run runs a single command and returns an error if it does not succeed. // run runs a single command and returns an error if it does not succeed.
// os/exec should have this function, to be honest. // os/exec should have this function, to be honest.
func run(name string, arg ...string) error { func run(name string, arg ...string) error {
return runInDir(".", name, arg...)
}
// runInDir runs a single command in directory dir and returns an error if
// it does not succeed.
func runInDir(dir, name string, arg ...string) error {
cmd := exec.Command(name, arg...) cmd := exec.Command(name, arg...)
cmd.Dir = dir
cmd.Stdout = os.Stdout cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
return cmd.Run() return cmd.Run()

7
go.mod
View File

@ -1 +1,8 @@
module github.com/amanbolat/enumer module github.com/amanbolat/enumer
go 1.12
require (
github.com/pascaldekloe/name v0.0.0-20180628100202-0fd16699aae1
golang.org/x/tools v0.0.0-20190404132500-923d25813098
)

View File

@ -10,6 +10,9 @@
package main package main
import ( import (
"io/ioutil"
"os"
"path/filepath"
"strings" "strings"
"testing" "testing"
) )
@ -1048,9 +1051,26 @@ func TestGolden(t *testing.T) {
func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, generateSQL, generateText bool, prefix string) { func runGoldenTest(t *testing.T, test Golden, generateJSON, generateYAML, generateSQL, generateText bool, prefix string) {
var g Generator var g Generator
input := "package test\n" + test.input
file := test.name + ".go" file := test.name + ".go"
g.parsePackage(".", []string{file}, input) input := "package test\n" + test.input
dir, err := ioutil.TempDir("", "stringer")
if err != nil {
t.Error(err)
}
defer func() {
err = os.RemoveAll(dir)
if err != nil {
t.Error(err)
}
}()
absFile := filepath.Join(dir, file)
err = ioutil.WriteFile(absFile, []byte(input), 0644)
if err != nil {
t.Error(err)
}
g.parsePackage([]string{absFile}, nil)
// Extract the name and type of the constant from the first line. // Extract the name and type of the constant from the first line.
tokens := strings.SplitN(test.input, " ", 3) tokens := strings.SplitN(test.input, " ", 3)
if len(tokens) != 3 { if len(tokens) != 3 {

View File

@ -13,13 +13,12 @@ import (
"flag" "flag"
"fmt" "fmt"
"go/ast" "go/ast"
"go/build"
exact "go/constant" exact "go/constant"
"go/format" "go/format"
"go/importer" "go/importer"
"go/parser"
"go/token" "go/token"
"go/types" "go/types"
"golang.org/x/tools/go/packages"
"io/ioutil" "io/ioutil"
"log" "log"
"os" "os"
@ -79,12 +78,14 @@ func main() {
if len(args) == 1 && isDirectory(args[0]) { if len(args) == 1 && isDirectory(args[0]) {
dir = args[0] dir = args[0]
g.parsePackageDir(args[0]) // g.parsePackageDir(args[0])
} else { } else {
dir = filepath.Dir(args[0]) dir = filepath.Dir(args[0])
g.parsePackageFiles(args) // g.parsePackageFiles(args)
} }
g.parsePackage(args, []string{})
// Print the header and package clause. // Print the header and package clause.
g.Printf("// Code generated by \"enumer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " ")) g.Printf("// Code generated by \"enumer %s\"; DO NOT EDIT.\n", strings.Join(os.Args[1:], " "))
g.Printf("\n") g.Printf("\n")
@ -146,8 +147,10 @@ type File struct {
pkg *Package // Package to which this file belongs. pkg *Package // Package to which this file belongs.
file *ast.File // Parsed AST. file *ast.File // Parsed AST.
// These fields are reset for each type being generated. // These fields are reset for each type being generated.
typeName string // Name of the constant type. typeName string // Name of the constant type.
values []Value // Accumulator for constant values of that type. values []Value // Accumulator for constant values of that type.
trimPrefix string
lineComment bool
} }
// Package holds information about a Go package // Package holds information about a Go package
@ -159,71 +162,106 @@ type Package struct {
typesPkg *types.Package typesPkg *types.Package
} }
// parsePackageDir parses the package residing in the directory. // // parsePackageDir parses the package residing in the directory.
func (g *Generator) parsePackageDir(directory string) { // func (g *Generator) parsePackageDir(directory string) {
pkg, err := build.Default.ImportDir(directory, 0) // pkg, err := build.Default.ImportDir(directory, 0)
// if err != nil {
// log.Fatalf("cannot process directory %s: %s", directory, err)
// }
// var names []string
// names = append(names, pkg.GoFiles...)
// names = append(names, pkg.CgoFiles...)
// // TODO: Need to think about constants in test files. Maybe write type_string_test.go
// // in a separate pass? For later.
// // names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
// names = append(names, pkg.SFiles...)
// names = prefixDirectory(directory, names)
// g.parsePackage(directory, names, nil)
// }
//
// // parsePackageFiles parses the package occupying the named files.
// func (g *Generator) parsePackageFiles(names []string) {
// g.parsePackage(".", names, nil)
// }
// // prefixDirectory places the directory name on the beginning of each name in the list.
// func prefixDirectory(directory string, names []string) []string {
// if directory == "." {
// return names
// }
// ret := make([]string, len(names))
// for i, n := range names {
// ret[i] = filepath.Join(directory, n)
// }
// return ret
// }
// parsePackage analyzes the single package constructed from the patterns and tags.
// parsePackage exits if there is an error.
func (g *Generator) parsePackage(patterns []string, tags []string) {
cfg := &packages.Config{
Mode: packages.LoadSyntax,
// TODO: Need to think about constants in test files. Maybe write type_string_test.go
// in a separate pass? For later.
Tests: false,
}
pkgs, err := packages.Load(cfg, patterns...)
if err != nil { if err != nil {
log.Fatalf("cannot process directory %s: %s", directory, err) log.Fatal(err)
} }
var names []string if len(pkgs) != 1 {
names = append(names, pkg.GoFiles...) log.Fatalf("error: %d packages found", len(pkgs))
names = append(names, pkg.CgoFiles...) }
// TODO: Need to think about constants in test files. Maybe write type_string_test.go g.addPackage(pkgs[0])
// in a separate pass? For later.
// names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
names = append(names, pkg.SFiles...)
names = prefixDirectory(directory, names)
g.parsePackage(directory, names, nil)
} }
// parsePackageFiles parses the package occupying the named files. // addPackage adds a type checked Package and its syntax files to the generator.
func (g *Generator) parsePackageFiles(names []string) { func (g *Generator) addPackage(pkg *packages.Package) {
g.parsePackage(".", names, nil) g.pkg = &Package{
} name: pkg.Name,
defs: pkg.TypesInfo.Defs,
files: make([]*File, len(pkg.Syntax)),
}
// prefixDirectory places the directory name on the beginning of each name in the list. for i, file := range pkg.Syntax {
func prefixDirectory(directory string, names []string) []string { g.pkg.files[i] = &File{
if directory == "." { file: file,
return names pkg: g.pkg,
}
} }
ret := make([]string, len(names))
for i, n := range names {
ret[i] = filepath.Join(directory, n)
}
return ret
} }
// parsePackage analyzes the single package constructed from the named files. // parsePackage analyzes the single package constructed from the named files.
// If text is non-nil, it is a string to be used instead of the content of the file, // If text is non-nil, it is a string to be used instead of the content of the file,
// to be used for testing. parsePackage exits if there is an error. // to be used for testing. parsePackage exits if there is an error.
func (g *Generator) parsePackage(directory string, names []string, text interface{}) { // func (g *Generator) parsePackagee(directory string, names []string, text interface{}) {
var files []*File // var files []*File
var astFiles []*ast.File // var astFiles []*ast.File
g.pkg = new(Package) // g.pkg = new(Package)
fs := token.NewFileSet() // fs := token.NewFileSet()
for _, n := range names { // for _, n := range names {
if !strings.HasSuffix(n, ".go") { // if !strings.HasSuffix(n, ".go") {
continue // continue
} // }
parsedFile, err := parser.ParseFile(fs, n, text, 0) // parsedFile, err := parser.ParseFile(fs, n, text, 0)
if err != nil { // if err != nil {
log.Fatalf("parsing package: %s: %s", n, err) // log.Fatalf("parsing package: %s: %s", n, err)
} // }
astFiles = append(astFiles, parsedFile) // astFiles = append(astFiles, parsedFile)
files = append(files, &File{ // files = append(files, &File{
file: parsedFile, // file: parsedFile,
pkg: g.pkg, // pkg: g.pkg,
}) // })
} // }
if len(astFiles) == 0 { // if len(astFiles) == 0 {
log.Fatalf("%s: no buildable Go files", directory) // log.Fatalf("%s: no buildable Go files", directory)
} // }
g.pkg.name = astFiles[0].Name.Name // g.pkg.name = astFiles[0].Name.Name
g.pkg.files = files // g.pkg.files = files
g.pkg.dir = directory // g.pkg.dir = directory
// Type check the package. // // Type check the package.
g.pkg.check(fs, astFiles) // g.pkg.check(fs, astFiles)
} // }
// check type-checks the package. The package must be OK to proceed. // check type-checks the package. The package must be OK to proceed.
func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) { func (pkg *Package) check(fs *token.FileSet, astFiles []*ast.File) {