mirror of
				https://github.com/beego/bee.git
				synced 2025-10-30 10:43:22 +00:00 
			
		
		
		
	Merge pull request #19 from Unknwon/master
Added func getControllerInfo
This commit is contained in:
		| @@ -1,5 +1,10 @@ | ||||
| bee | ||||
| === | ||||
|  | ||||
| [](https://drone.io/github.com/astaxie/bee/latest) | ||||
|  | ||||
| Bee is a tool for managing beego framework. | ||||
| Bee is a tool for managing beego framework. | ||||
|  | ||||
| ## License | ||||
|  | ||||
| [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html). | ||||
							
								
								
									
										282
									
								
								autorouter.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										282
									
								
								autorouter.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,282 @@ | ||||
| // Copyright 2013 Bee Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"go/ast" | ||||
| 	gobuild "go/build" | ||||
| 	"go/doc" | ||||
| 	"go/parser" | ||||
| 	"go/token" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| var cmdRouter = &Command{ | ||||
| 	UsageLine: "router", | ||||
| 	Short:     "auto-generate routers for the app controllers", | ||||
| 	Long: ` | ||||
|    | ||||
| `, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	cmdRouter.Run = autoRouter | ||||
| } | ||||
|  | ||||
| func autoRouter(cmd *Command, args []string) { | ||||
| 	fmt.Println("[INFO] Starting auto-generating routers...") | ||||
| } | ||||
|  | ||||
| // getControllerInfo returns controllers that embeded "beego.controller" | ||||
| // and their methods of package in given path. | ||||
| func getControllerInfo(path string) (map[string][]string, error) { | ||||
| 	now := time.Now() | ||||
| 	path = strings.TrimSuffix(path, "/") | ||||
| 	dir, err := os.Open(path) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	fis, err := dir.Readdir(0) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	files := make([]*source, 0, len(fis)) | ||||
| 	for _, fi := range fis { | ||||
| 		// Only load go files. | ||||
| 		if strings.HasSuffix(fi.Name(), ".go") { | ||||
| 			f, err := os.Open(path + "/" + fi.Name()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			p := make([]byte, fi.Size()) | ||||
| 			_, err = f.Read(p) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
|  | ||||
| 			f.Close() | ||||
| 			files = append(files, &source{ | ||||
| 				name: path + "/" + fi.Name(), | ||||
| 				data: p, | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	rw := &routerWalker{ | ||||
| 		pdoc: &Package{ | ||||
| 			ImportPath: path, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	cm := make(map[string][]string) | ||||
| 	pdoc, err := rw.build(files) | ||||
| 	for _, t := range pdoc.Types { | ||||
| 		// Check if embeded "beego.Controller". | ||||
| 		if strings.Index(t.Decl, "beego.Controller") > -1 { | ||||
| 			for _, f := range t.Methods { | ||||
| 				cm[t.Name] = append(cm[t.Name], f.Name) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	fmt.Println(time.Since(now)) | ||||
| 	return cm, nil | ||||
| } | ||||
|  | ||||
| // A source describles a source code file. | ||||
| type source struct { | ||||
| 	name string | ||||
| 	data []byte | ||||
| } | ||||
|  | ||||
| func (s *source) Name() string       { return s.name } | ||||
| func (s *source) Size() int64        { return int64(len(s.data)) } | ||||
| func (s *source) Mode() os.FileMode  { return 0 } | ||||
| func (s *source) ModTime() time.Time { return time.Time{} } | ||||
| func (s *source) IsDir() bool        { return false } | ||||
| func (s *source) Sys() interface{}   { return nil } | ||||
|  | ||||
| // A routerWalker holds the state used when building the documentation. | ||||
| type routerWalker struct { | ||||
| 	pdoc *Package | ||||
| 	srcs map[string]*source // Source files. | ||||
| 	fset *token.FileSet | ||||
| 	buf  []byte // scratch space for printNode method. | ||||
| } | ||||
|  | ||||
| // Package represents full information and documentation for a package. | ||||
| type Package struct { | ||||
| 	ImportPath string | ||||
|  | ||||
| 	// Top-level declarations. | ||||
| 	Types []*Type | ||||
| } | ||||
|  | ||||
| // Type represents structs and interfaces. | ||||
| type Type struct { | ||||
| 	Name    string // Type name. | ||||
| 	Decl    string | ||||
| 	Methods []*Func // Exported methods. | ||||
| } | ||||
|  | ||||
| // Func represents functions | ||||
| type Func struct { | ||||
| 	Name string | ||||
| } | ||||
|  | ||||
| // build generates data from source files. | ||||
| func (w *routerWalker) build(srcs []*source) (*Package, error) { | ||||
| 	// Add source files to walker, I skipped references here. | ||||
| 	w.srcs = make(map[string]*source) | ||||
| 	for _, src := range srcs { | ||||
| 		w.srcs[src.name] = src | ||||
| 	} | ||||
|  | ||||
| 	w.fset = token.NewFileSet() | ||||
|  | ||||
| 	// Find the package and associated files. | ||||
| 	ctxt := gobuild.Context{ | ||||
| 		GOOS:          runtime.GOOS, | ||||
| 		GOARCH:        runtime.GOARCH, | ||||
| 		CgoEnabled:    true, | ||||
| 		JoinPath:      path.Join, | ||||
| 		IsAbsPath:     path.IsAbs, | ||||
| 		SplitPathList: func(list string) []string { return strings.Split(list, ":") }, | ||||
| 		IsDir:         func(path string) bool { panic("unexpected") }, | ||||
| 		HasSubdir:     func(root, dir string) (rel string, ok bool) { panic("unexpected") }, | ||||
| 		ReadDir:       func(dir string) (fi []os.FileInfo, err error) { return w.readDir(dir) }, | ||||
| 		OpenFile:      func(path string) (r io.ReadCloser, err error) { return w.openFile(path) }, | ||||
| 		Compiler:      "gc", | ||||
| 	} | ||||
|  | ||||
| 	bpkg, err := ctxt.ImportDir(w.pdoc.ImportPath, 0) | ||||
| 	// Continue if there are no Go source files; we still want the directory info. | ||||
| 	_, nogo := err.(*gobuild.NoGoError) | ||||
| 	if err != nil { | ||||
| 		if nogo { | ||||
| 			err = nil | ||||
| 		} else { | ||||
| 			return nil, errors.New("routerWalker.build -> " + err.Error()) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Parse the Go files | ||||
| 	files := make(map[string]*ast.File) | ||||
| 	for _, name := range append(bpkg.GoFiles, bpkg.CgoFiles...) { | ||||
| 		file, err := parser.ParseFile(w.fset, name, w.srcs[name].data, parser.ParseComments) | ||||
| 		if err != nil { | ||||
| 			return nil, errors.New("routerWalker.build -> parse go files: " + err.Error()) | ||||
| 		} | ||||
| 		files[name] = file | ||||
| 	} | ||||
|  | ||||
| 	apkg, _ := ast.NewPackage(w.fset, files, simpleImporter, nil) | ||||
|  | ||||
| 	mode := doc.Mode(0) | ||||
| 	if w.pdoc.ImportPath == "builtin" { | ||||
| 		mode |= doc.AllDecls | ||||
| 	} | ||||
|  | ||||
| 	pdoc := doc.New(apkg, w.pdoc.ImportPath, mode) | ||||
|  | ||||
| 	w.pdoc.Types = w.types(pdoc.Types) | ||||
|  | ||||
| 	return w.pdoc, err | ||||
| } | ||||
|  | ||||
| func (w *routerWalker) funcs(fdocs []*doc.Func) []*Func { | ||||
| 	var result []*Func | ||||
| 	for _, d := range fdocs { | ||||
| 		result = append(result, &Func{ | ||||
| 			Name: d.Name, | ||||
| 		}) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func (w *routerWalker) types(tdocs []*doc.Type) []*Type { | ||||
| 	var result []*Type | ||||
| 	for _, d := range tdocs { | ||||
| 		result = append(result, &Type{ | ||||
| 			Decl:    w.printDecl(d.Decl), | ||||
| 			Name:    d.Name, | ||||
| 			Methods: w.funcs(d.Methods), | ||||
| 		}) | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| func (w *routerWalker) printDecl(decl ast.Node) string { | ||||
| 	var d Code | ||||
| 	d, w.buf = printDecl(decl, w.fset, w.buf) | ||||
| 	return d.Text | ||||
| } | ||||
|  | ||||
| func (w *routerWalker) readDir(dir string) ([]os.FileInfo, error) { | ||||
| 	if dir != w.pdoc.ImportPath { | ||||
| 		panic("unexpected") | ||||
| 	} | ||||
| 	fis := make([]os.FileInfo, 0, len(w.srcs)) | ||||
| 	for _, src := range w.srcs { | ||||
| 		fis = append(fis, src) | ||||
| 	} | ||||
| 	return fis, nil | ||||
| } | ||||
|  | ||||
| func (w *routerWalker) openFile(path string) (io.ReadCloser, error) { | ||||
| 	if strings.HasPrefix(path, w.pdoc.ImportPath+"/") { | ||||
| 		if src, ok := w.srcs[path[len(w.pdoc.ImportPath)+1:]]; ok { | ||||
| 			return ioutil.NopCloser(bytes.NewReader(src.data)), nil | ||||
| 		} | ||||
| 	} | ||||
| 	panic("unexpected") | ||||
| } | ||||
|  | ||||
| func simpleImporter(imports map[string]*ast.Object, path string) (*ast.Object, error) { | ||||
| 	pkg := imports[path] | ||||
| 	if pkg == nil { | ||||
| 		// Guess the package name without importing it. Start with the last | ||||
| 		// element of the path. | ||||
| 		name := path[strings.LastIndex(path, "/")+1:] | ||||
|  | ||||
| 		// Trim commonly used prefixes and suffixes containing illegal name | ||||
| 		// runes. | ||||
| 		name = strings.TrimSuffix(name, ".go") | ||||
| 		name = strings.TrimSuffix(name, "-go") | ||||
| 		name = strings.TrimPrefix(name, "go.") | ||||
| 		name = strings.TrimPrefix(name, "go-") | ||||
| 		name = strings.TrimPrefix(name, "biogo.") | ||||
|  | ||||
| 		// It's also common for the last element of the path to contain an | ||||
| 		// extra "go" prefix, but not always. TODO: examine unresolved ids to | ||||
| 		// detect when trimming the "go" prefix is appropriate. | ||||
|  | ||||
| 		pkg = ast.NewObj(ast.Pkg, name) | ||||
| 		pkg.Data = ast.NewScope(nil) | ||||
| 		imports[path] = pkg | ||||
| 	} | ||||
| 	return pkg, nil | ||||
| } | ||||
							
								
								
									
										9
									
								
								autorouter_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								autorouter_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestGetControllerInfo(t *testing.T) { | ||||
| 	getControllerInfo("testdata/router/") | ||||
| } | ||||
							
								
								
									
										15
									
								
								bee.go
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								bee.go
									
									
									
									
									
								
							| @@ -1,3 +1,17 @@ | ||||
| // Copyright 2013 Bee Authors | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| // Bee is a tool for developling applications based on beego framework. | ||||
| package main | ||||
|  | ||||
| @@ -61,6 +75,7 @@ var commands = []*Command{ | ||||
| 	cmdRun, | ||||
| 	cmdPack, | ||||
| 	cmdApiapp, | ||||
| 	cmdRouter, | ||||
| 	//cmdReStart, | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										11
									
								
								bee.json
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								bee.json
									
									
									
									
									
								
							| @@ -1,9 +1,12 @@ | ||||
| { | ||||
| 	"go_install": false, | ||||
| 	"dir_structure":{ | ||||
| 		"controllers": "", | ||||
| 		"models": "" | ||||
| 		"models": "", | ||||
| 		"others": [] | ||||
| 	}, | ||||
| 	"files": [ | ||||
| 		"main.go" | ||||
| 	] | ||||
| 	"main_files":{ | ||||
| 		"main.go": "", | ||||
| 		"others": [] | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										262
									
								
								code.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								code.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,262 @@ | ||||
| // Copyright 2011 Gary Burd | ||||
| // Copyright 2013 Unknown | ||||
| // | ||||
| // Licensed under the Apache License, Version 2.0 (the "License"): you may | ||||
| // not use this file except in compliance with the License. You may obtain | ||||
| // a copy of the License at | ||||
| // | ||||
| //     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| // | ||||
| // Unless required by applicable law or agreed to in writing, software | ||||
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | ||||
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | ||||
| // License for the specific language governing permissions and limitations | ||||
| // under the License. | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"go/ast" | ||||
| 	"go/printer" | ||||
| 	"go/scanner" | ||||
| 	"go/token" | ||||
| 	"math" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	notPredeclared = iota | ||||
| 	predeclaredType | ||||
| 	predeclaredConstant | ||||
| 	predeclaredFunction | ||||
| ) | ||||
|  | ||||
| // predeclared represents the set of all predeclared identifiers. | ||||
| var predeclared = map[string]int{ | ||||
| 	"bool":       predeclaredType, | ||||
| 	"byte":       predeclaredType, | ||||
| 	"complex128": predeclaredType, | ||||
| 	"complex64":  predeclaredType, | ||||
| 	"error":      predeclaredType, | ||||
| 	"float32":    predeclaredType, | ||||
| 	"float64":    predeclaredType, | ||||
| 	"int16":      predeclaredType, | ||||
| 	"int32":      predeclaredType, | ||||
| 	"int64":      predeclaredType, | ||||
| 	"int8":       predeclaredType, | ||||
| 	"int":        predeclaredType, | ||||
| 	"rune":       predeclaredType, | ||||
| 	"string":     predeclaredType, | ||||
| 	"uint16":     predeclaredType, | ||||
| 	"uint32":     predeclaredType, | ||||
| 	"uint64":     predeclaredType, | ||||
| 	"uint8":      predeclaredType, | ||||
| 	"uint":       predeclaredType, | ||||
| 	"uintptr":    predeclaredType, | ||||
|  | ||||
| 	"true":  predeclaredConstant, | ||||
| 	"false": predeclaredConstant, | ||||
| 	"iota":  predeclaredConstant, | ||||
| 	"nil":   predeclaredConstant, | ||||
|  | ||||
| 	"append":  predeclaredFunction, | ||||
| 	"cap":     predeclaredFunction, | ||||
| 	"close":   predeclaredFunction, | ||||
| 	"complex": predeclaredFunction, | ||||
| 	"copy":    predeclaredFunction, | ||||
| 	"delete":  predeclaredFunction, | ||||
| 	"imag":    predeclaredFunction, | ||||
| 	"len":     predeclaredFunction, | ||||
| 	"make":    predeclaredFunction, | ||||
| 	"new":     predeclaredFunction, | ||||
| 	"panic":   predeclaredFunction, | ||||
| 	"print":   predeclaredFunction, | ||||
| 	"println": predeclaredFunction, | ||||
| 	"real":    predeclaredFunction, | ||||
| 	"recover": predeclaredFunction, | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	ExportLinkAnnotation AnnotationKind = iota | ||||
| 	AnchorAnnotation | ||||
| 	CommentAnnotation | ||||
| 	PackageLinkAnnotation | ||||
| 	BuiltinAnnotation | ||||
| ) | ||||
|  | ||||
| // annotationVisitor collects annotations. | ||||
| type annotationVisitor struct { | ||||
| 	annotations []Annotation | ||||
| } | ||||
|  | ||||
| func (v *annotationVisitor) add(kind AnnotationKind, importPath string) { | ||||
| 	v.annotations = append(v.annotations, Annotation{Kind: kind, ImportPath: importPath}) | ||||
| } | ||||
|  | ||||
| func (v *annotationVisitor) ignoreName() { | ||||
| 	v.add(-1, "") | ||||
| } | ||||
|  | ||||
| func (v *annotationVisitor) Visit(n ast.Node) ast.Visitor { | ||||
| 	switch n := n.(type) { | ||||
| 	case *ast.TypeSpec: | ||||
| 		v.ignoreName() | ||||
| 		ast.Walk(v, n.Type) | ||||
| 	case *ast.FuncDecl: | ||||
| 		if n.Recv != nil { | ||||
| 			ast.Walk(v, n.Recv) | ||||
| 		} | ||||
| 		v.ignoreName() | ||||
| 		ast.Walk(v, n.Type) | ||||
| 	case *ast.Field: | ||||
| 		for _ = range n.Names { | ||||
| 			v.ignoreName() | ||||
| 		} | ||||
| 		ast.Walk(v, n.Type) | ||||
| 	case *ast.ValueSpec: | ||||
| 		for _ = range n.Names { | ||||
| 			v.add(AnchorAnnotation, "") | ||||
| 		} | ||||
| 		if n.Type != nil { | ||||
| 			ast.Walk(v, n.Type) | ||||
| 		} | ||||
| 		for _, x := range n.Values { | ||||
| 			ast.Walk(v, x) | ||||
| 		} | ||||
| 	case *ast.Ident: | ||||
| 		switch { | ||||
| 		case n.Obj == nil && predeclared[n.Name] != notPredeclared: | ||||
| 			v.add(BuiltinAnnotation, "") | ||||
| 		case n.Obj != nil && ast.IsExported(n.Name): | ||||
| 			v.add(ExportLinkAnnotation, "") | ||||
| 		default: | ||||
| 			v.ignoreName() | ||||
| 		} | ||||
| 	case *ast.SelectorExpr: | ||||
| 		if x, _ := n.X.(*ast.Ident); x != nil { | ||||
| 			if obj := x.Obj; obj != nil && obj.Kind == ast.Pkg { | ||||
| 				if spec, _ := obj.Decl.(*ast.ImportSpec); spec != nil { | ||||
| 					if path, err := strconv.Unquote(spec.Path.Value); err == nil { | ||||
| 						v.add(PackageLinkAnnotation, path) | ||||
| 						if path == "C" { | ||||
| 							v.ignoreName() | ||||
| 						} else { | ||||
| 							v.add(ExportLinkAnnotation, path) | ||||
| 						} | ||||
| 						return nil | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		ast.Walk(v, n.X) | ||||
| 		v.ignoreName() | ||||
| 	default: | ||||
| 		return v | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func printDecl(decl ast.Node, fset *token.FileSet, buf []byte) (Code, []byte) { | ||||
| 	v := &annotationVisitor{} | ||||
| 	ast.Walk(v, decl) | ||||
|  | ||||
| 	buf = buf[:0] | ||||
| 	err := (&printer.Config{Mode: printer.UseSpaces, Tabwidth: 4}).Fprint(sliceWriter{&buf}, fset, decl) | ||||
| 	if err != nil { | ||||
| 		return Code{Text: err.Error()}, buf | ||||
| 	} | ||||
|  | ||||
| 	var annotations []Annotation | ||||
| 	var s scanner.Scanner | ||||
| 	fset = token.NewFileSet() | ||||
| 	file := fset.AddFile("", fset.Base(), len(buf)) | ||||
| 	s.Init(file, buf, nil, scanner.ScanComments) | ||||
| loop: | ||||
| 	for { | ||||
| 		pos, tok, lit := s.Scan() | ||||
| 		switch tok { | ||||
| 		case token.EOF: | ||||
| 			break loop | ||||
| 		case token.COMMENT: | ||||
| 			p := file.Offset(pos) | ||||
| 			e := p + len(lit) | ||||
| 			if p > math.MaxInt16 || e > math.MaxInt16 { | ||||
| 				break loop | ||||
| 			} | ||||
| 			annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)}) | ||||
| 		case token.IDENT: | ||||
| 			if len(v.annotations) == 0 { | ||||
| 				// Oops! | ||||
| 				break loop | ||||
| 			} | ||||
| 			annotation := v.annotations[0] | ||||
| 			v.annotations = v.annotations[1:] | ||||
| 			if annotation.Kind == -1 { | ||||
| 				continue | ||||
| 			} | ||||
| 			p := file.Offset(pos) | ||||
| 			e := p + len(lit) | ||||
| 			if p > math.MaxInt16 || e > math.MaxInt16 { | ||||
| 				break loop | ||||
| 			} | ||||
| 			annotation.Pos = int16(p) | ||||
| 			annotation.End = int16(e) | ||||
| 			if len(annotations) > 0 && annotation.Kind == ExportLinkAnnotation { | ||||
| 				prev := annotations[len(annotations)-1] | ||||
| 				if prev.Kind == PackageLinkAnnotation && | ||||
| 					prev.ImportPath == annotation.ImportPath && | ||||
| 					prev.End+1 == annotation.Pos { | ||||
| 					// merge with previous | ||||
| 					annotation.Pos = prev.Pos | ||||
| 					annotations[len(annotations)-1] = annotation | ||||
| 					continue loop | ||||
| 				} | ||||
| 			} | ||||
| 			annotations = append(annotations, annotation) | ||||
| 		} | ||||
| 	} | ||||
| 	return Code{Text: string(buf), Annotations: annotations}, buf | ||||
| } | ||||
|  | ||||
| type AnnotationKind int16 | ||||
|  | ||||
| type Annotation struct { | ||||
| 	Pos, End   int16 | ||||
| 	Kind       AnnotationKind | ||||
| 	ImportPath string | ||||
| } | ||||
|  | ||||
| type Code struct { | ||||
| 	Text        string | ||||
| 	Annotations []Annotation | ||||
| } | ||||
|  | ||||
| func commentAnnotations(src string) []Annotation { | ||||
| 	var annotations []Annotation | ||||
| 	var s scanner.Scanner | ||||
| 	fset := token.NewFileSet() | ||||
| 	file := fset.AddFile("", fset.Base(), len(src)) | ||||
| 	s.Init(file, []byte(src), nil, scanner.ScanComments) | ||||
| 	for { | ||||
| 		pos, tok, lit := s.Scan() | ||||
| 		switch tok { | ||||
| 		case token.EOF: | ||||
| 			return annotations | ||||
| 		case token.COMMENT: | ||||
| 			p := file.Offset(pos) | ||||
| 			e := p + len(lit) | ||||
| 			if p > math.MaxInt16 || e > math.MaxInt16 { | ||||
| 				return annotations | ||||
| 			} | ||||
| 			annotations = append(annotations, Annotation{Kind: CommentAnnotation, Pos: int16(p), End: int16(e)}) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| type sliceWriter struct{ p *[]byte } | ||||
|  | ||||
| func (w sliceWriter) Write(p []byte) (int, error) { | ||||
| 	*w.p = append(*w.p, p...) | ||||
| 	return len(p), nil | ||||
| } | ||||
							
								
								
									
										20
									
								
								run.go
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								run.go
									
									
									
									
									
								
							| @@ -36,11 +36,19 @@ func init() { | ||||
|  | ||||
| var appname string | ||||
| var conf struct { | ||||
| 	// Indicates whether execute "go install" before "go build". | ||||
| 	GoInstall bool `json:"go_install"` | ||||
|  | ||||
| 	DirStruct struct { | ||||
| 		Controllers string | ||||
| 		Models      string | ||||
| 		Others      []string // Other directories. | ||||
| 	} `json:"dir_structure"` | ||||
| 	Files []string | ||||
|  | ||||
| 	MainFiles struct { | ||||
| 		Main   string   `json:"main.go"` | ||||
| 		Others []string // Others files of package main. | ||||
| 	} `json:"main_files"` | ||||
| } | ||||
|  | ||||
| func runApp(cmd *Command, args []string) { | ||||
| @@ -58,8 +66,10 @@ func runApp(cmd *Command, args []string) { | ||||
| 	var paths []string | ||||
| 	paths = append(paths, | ||||
| 		path.Join(crupath, conf.DirStruct.Controllers), | ||||
| 		path.Join(crupath, conf.DirStruct.Models)) | ||||
| 	paths = append(paths, conf.Files...) | ||||
| 		path.Join(crupath, conf.DirStruct.Models), | ||||
| 		path.Join(crupath, conf.MainFiles.Main)) | ||||
| 	paths = append(paths, conf.DirStruct.Others...) | ||||
| 	paths = append(paths, conf.MainFiles.Others...) | ||||
|  | ||||
| 	NewWatcher(paths) | ||||
| 	appname = args[0] | ||||
| @@ -71,6 +81,7 @@ func runApp(cmd *Command, args []string) { | ||||
|  | ||||
| // loadConfig loads customized configuration. | ||||
| func loadConfig() error { | ||||
| 	fmt.Println("[INFO] Detect bee.json") | ||||
| 	f, err := os.Open("bee.json") | ||||
| 	if err != nil { | ||||
| 		// Use default. | ||||
| @@ -91,5 +102,8 @@ func loadConfig() error { | ||||
| 	if len(conf.DirStruct.Models) == 0 { | ||||
| 		conf.DirStruct.Models = "models" | ||||
| 	} | ||||
| 	if len(conf.MainFiles.Main) == 0 { | ||||
| 		conf.MainFiles.Main = "main.go" | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										28
									
								
								testdata/router/router.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								testdata/router/router.go
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| package router | ||||
|  | ||||
| import ( | ||||
| 	"github.com/astaxie/beego" | ||||
| ) | ||||
|  | ||||
| type Router struct { | ||||
| 	beego.Controller | ||||
| } | ||||
|  | ||||
| func (this *Router) Get() { | ||||
|  | ||||
| } | ||||
|  | ||||
| func (this *Router) Post() { | ||||
|  | ||||
| } | ||||
|  | ||||
| type Controller struct { | ||||
| } | ||||
|  | ||||
| func (this *Controller) Put() { | ||||
|  | ||||
| } | ||||
|  | ||||
| func (this *Controller) Delete() { | ||||
|  | ||||
| } | ||||
							
								
								
									
										21
									
								
								watch.go
									
									
									
									
									
								
							
							
						
						
									
										21
									
								
								watch.go
									
									
									
									
									
								
							| @@ -72,10 +72,23 @@ func Autobuild() { | ||||
| 	fmt.Println("[INFO] Start building...") | ||||
| 	path, _ := os.Getwd() | ||||
| 	os.Chdir(path) | ||||
| 	bcmd := exec.Command("go", "build") | ||||
| 	bcmd.Stdout = os.Stdout | ||||
| 	bcmd.Stderr = os.Stderr | ||||
| 	err := bcmd.Run() | ||||
|  | ||||
| 	var err error | ||||
| 	// For applications use full import path like "github.com/.../.." | ||||
| 	// are able to use "go install" to reduce build time. | ||||
| 	if conf.GoInstall { | ||||
| 		icmd := exec.Command("go", "install") | ||||
| 		icmd.Stdout = os.Stdout | ||||
| 		icmd.Stderr = os.Stderr | ||||
| 		err = icmd.Run() | ||||
| 	} | ||||
|  | ||||
| 	if err == nil { | ||||
| 		bcmd := exec.Command("go", "build") | ||||
| 		bcmd.Stdout = os.Stdout | ||||
| 		bcmd.Stderr = os.Stderr | ||||
| 		err = bcmd.Run() | ||||
| 	} | ||||
|  | ||||
| 	if err != nil { | ||||
| 		fmt.Println("[ERRO] ============== Build failed ===================") | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 astaxie
					astaxie