From 8924ef944a3a9f0e24cf7d2e7158d6b6accc360f Mon Sep 17 00:00:00 2001 From: Unknown Date: Sun, 19 May 2013 15:11:27 -0400 Subject: [PATCH] clean code: walker.go --- doc/github.go | 71 +++++++++++++++++------- doc/struct.go | 16 +++--- doc/walker.go | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++ install.go | 2 +- 4 files changed, 206 insertions(+), 30 deletions(-) create mode 100644 doc/walker.go diff --git a/doc/github.go b/doc/github.go index 7eaa5fd38..0c2f41493 100644 --- a/doc/github.go +++ b/doc/github.go @@ -127,32 +127,65 @@ func GetGithubDoc(client *http.Client, match map[string]string, commit string) ( if err != nil { return nil, nil, err } + } - /*localF, _ := os.Open(absPath) - fbytes := make([]byte, f.FileInfo().Size()) - n, _ := localF.Read(fbytes) - - // Check if Go source file. - if n > 0 && strings.HasSuffix(absPath, ".go") { - files = append(files, &source{ - name: srcName, - data: fbytes, - }) - }*/ + pkg := &Package{ + ImportPath: importPath, + AbsPath: installPath, + Commit: commit, } + var imports []string + // Check if need to check imports. if isCheckImport { + for _, d := range dirs { + dir, err := os.Open(d) + if err != nil { + return nil, nil, err + } + defer dir.Close() + + // Get file info slice. + fis, err := dir.Readdir(0) + if err != nil { + return nil, nil, err + } - } else { + files := make([]*source, 0, 10) + for _, fi := range fis { + // Only handle files. + if strings.HasSuffix(fi.Name(), ".go") { + f, err := os.Open(d + "/" + fi.Name()) + if err != nil { + return nil, nil, err + } + defer f.Close() + + fbytes := make([]byte, fi.Size()) + _, err = f.Read(fbytes) + if err != nil { + return nil, nil, err + } + + files = append(files, &source{ + name: importPath + "/" + fi.Name(), + data: fbytes, + }) + } + } + // Check if has Go source files. + if len(files) > 0 { + w := &walker{ImportPath: importPath} + importPkgs, err := w.build(files) + if err != nil { + return nil, nil, err + } + imports = append(imports, importPkgs...) + } + } } - /*pkg := &Package{ - ImportPath: importPath, - AbsPath: installPath, - Commit: commit, - Dirs: dirs, - }*/ - return nil, nil, nil + return pkg, imports, err } diff --git a/doc/struct.go b/doc/struct.go index b04be3093..d92bf03a6 100644 --- a/doc/struct.go +++ b/doc/struct.go @@ -21,17 +21,13 @@ type Package struct { // Imports. Imports []string - - // Directories. - Dirs []string } // source is source code file. type source struct { - name string - browseURL string - rawURL string - data []byte + rawURL string + name string + data []byte } func (s *source) Name() string { return s.name } @@ -43,7 +39,7 @@ func (s *source) Sys() interface{} { return nil } // walker holds the state used when building the documentation. type walker struct { - pkg *Package - srcs map[string]*source // Source files. - fset *token.FileSet + ImportPath string + srcs map[string]*source // Source files. + fset *token.FileSet } diff --git a/doc/walker.go b/doc/walker.go new file mode 100644 index 000000000..b5cce47e7 --- /dev/null +++ b/doc/walker.go @@ -0,0 +1,147 @@ +// 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 doc + +import ( + "bytes" + "errors" + "go/ast" + "go/build" + "go/parser" + "go/token" + "io" + "io/ioutil" + "os" + "path" + "runtime" + "strings" + /* + "fmt" + "regexp" + "time"*/ + + //"github.com/GPMGo/gpm/models" + //"github.com/GPMGo/gpm/utils" +) + +type sliceWriter struct{ p *[]byte } + +func (w sliceWriter) Write(p []byte) (int, error) { + *w.p = append(*w.p, p...) + return len(p), nil +} + +func (w *walker) readDir(dir string) ([]os.FileInfo, error) { + if dir != w.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 *walker) openFile(path string) (io.ReadCloser, error) { + if strings.HasPrefix(path, w.ImportPath+"/") { + if src, ok := w.srcs[path[len(w.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 +} + +// build gets imports from source files. +func (w *walker) build(srcs []*source) ([]string, 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 := build.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.ImportPath, 0) + // Continue if there are no Go source files; we still want the directory info. + _, nogo := err.(*build.NoGoError) + if err != nil { + if nogo { + err = nil + } else { + return nil, errors.New("doc.walker.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 { + //beego.Error("doc.walker.build():", err) + continue + } + files[name] = file + } + + var imports []string + /* for _, v := range bpkg.Imports { + // Skip strandard library. + + }*/ + return imports, err +} diff --git a/install.go b/install.go index e1cfeaa0f..1d0424cda 100644 --- a/install.go +++ b/install.go @@ -128,7 +128,7 @@ func downloadPackages(pkgs, commits []string) { case utils.IsValidRemotePath(p) && !downloadCache[p]: // Download package. pkg, imports := downloadPackage(p, commits[i]) - if imports != nil { + if len(imports) > 0 { // Need to download dependencies. tags := make([]string, len(imports)) downloadPackages(imports, tags)