Documentation ¶
Index ¶
- Variables
- func ContainingDirectory(ctxt *build.Context, child, stopAt string, tombstones ...string) (string, error)
- func FindProjectRoot(ctxt *build.Context, path string, extra ...string) (string, error)
- func HasSubdir(ctxt *build.Context, root, dir string) (rel string, ok bool)
- func HasSubdirFunc(ctxt *build.Context) func(root, dir string) (rel string, ok bool)
- func ScopedContext(orig *build.Context, pkgdirs ...string) (*build.Context, error)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultProjectTombstones = []string{
".git",
"go.mod",
"go.work",
"glide.yaml",
"Gopkg.toml",
}
DefaultProjectTombstones are the files used by FindProjectRoot to determine the root of a project.
Functions ¶
func ContainingDirectory ¶
func ContainingDirectory(ctxt *build.Context, child, stopAt string, tombstones ...string) (string, error)
ContainingDirectory finds the parent directory of child containing an entry named by tombstones. The child directory must be absolute.
The stopAt argument is optional and is used to abort the search early. If specified it must be an absolute path and a parent of the child directory.
// This should return ctxt.GOPATH+"/src/github.com/charlievieth/buildutil" // since it contains a "go.mod" file. ContainingDirectory( ctxt, ctxt.GOPATH+"/src", ctxt.GOPATH+"/src/github.com/charlievieth/buildutil/contextutil", "go.mod", )
func FindProjectRoot ¶
FindProjectRoot finds the root directory of the project containing path, which can be a file or a directory. The project root is determined to be the directory containing any entry with a name in DefaultProjectTombstones. The extra argument specifies additional tombstone names (".svn").
The build.Context is used for file system access and to limit the search space if path is a child of GOROOT or GOPATH. Otherwise, all parent directories of path are searched.
If path is not absolute it is joined with build.Context.Dir (if set) or the current working directory.
os.ErrNotExist is returned if the project directory was not found.
func HasSubdir ¶
HasSubdir calls ctxt.HasSubdir (if not nil) or else uses the local file system to answer the question. It is significantly faster than the default build.Context.hasSubdir() method as it tries to avoid calls to filepath.EvalSymlinks.
func HasSubdirFunc ¶ added in v0.0.15
HasSubdirFunc returns a function that can be used for build.Context.HasSubdir field and is significantly faster than the default implementation.
func ScopedContext ¶
ScopedContext returns a build.Context with a ReadDir that is scoped to the directories listed by pkgdirs and the GOROOT. That is, ReadDir when called with an ancestor of pkgdirs will only return immediate ancestors (that lead to the pkgdirs). When called with any of the pkgdirs, GOROOT, or any of their children all results are returned (same as ioutil.ReadDir).
A scoped context is designed to limit the search scope of tools that walk the entire GOPATH (e.g. "golang.org/x/tools/refactor/rename"), which can greatly speed up processing time.
// In the below example we limit the search path to "/go/src/pkg/buildutil". ctxt, _ := ScopedContext(&build.Default, "/go/src/pkg/buildutil") ctxt.ReadDir("/go") // => ["src"] ctxt.ReadDir("/go/src") // => ["pkg"] ctxt.ReadDir("/go/src/pkg") // => ["buildutil"] ctxt.ReadDir("/go/src/pkg/buildutil") // => [ALL ENTRIES] ctxt.ReadDir("/go/src/pkg/buildutil/contextutil") // => [ALL ENTRIES]
Example ¶
package main import ( "fmt" "go/build" "io/ioutil" "os" "path/filepath" "strings" "github.com/charlievieth/buildutil/contextutil" ) func printReadDir(ctxt *build.Context, path string) { // Remove leading temp directory name := strings.TrimPrefix(filepath.ToSlash(path), filepath.ToSlash(ctxt.GOPATH)+"/") fmt.Printf("ReadDir(%q)\n", name) fis, err := ctxt.ReadDir(path) if err != nil { if !os.IsNotExist(err) { panic(err) } fmt.Printf(" open %s: %s\n", name, os.ErrNotExist) return } for _, fi := range fis { if fi.IsDir() { fmt.Printf(" %s/\n", fi.Name()) } else { fmt.Printf(" %s\n", fi.Name()) } } } func main() { // Create a fake GOPATH and populate it with some files // // src // └── p // ├── p1 // │ ├── c1 // │ │ ├── fc1.go // │ │ └── fc2.go // │ ├── f1.go // │ └── f2.go // └── p2 // └── nope.go // gopath, err := ioutil.TempDir("", "contextutil.*") if err != nil { panic(err) } defer os.RemoveAll(gopath) pkg1 := filepath.Join(gopath, "src/p/p1") sub1 := filepath.Join(gopath, "src/p/p1/c1") // subdirectory of pkg1 pkg2 := filepath.Join(gopath, "src/p/p2") for _, name := range []string{ filepath.Join(pkg1, "f1.go"), filepath.Join(pkg1, "f2.go"), filepath.Join(sub1, "fc1.go"), filepath.Join(sub1, "fc2.go"), filepath.Join(pkg2, "nope.go"), } { if err := os.MkdirAll(filepath.Dir(name), 0755); err != nil { panic(err) } err := os.WriteFile(name, []byte(name), 0644) if err != nil { panic(err) } } // Scope context to path pkg1 ("$GOPATH/src/p/p1") orig := build.Default orig.GOPATH = gopath ctxt, err := contextutil.ScopedContext(&orig, pkg1) if err != nil { panic(err) } // Reading $GOPATH/src/p will only return "p1" since // that is what we scoped the Context to. printReadDir(ctxt, filepath.Dir(pkg1)) // Reading p1 or any of it's subdirectories returns // all results (same as ioutil.ReadDir()) printReadDir(ctxt, pkg1) printReadDir(ctxt, sub1) // Reading a directory outside of the scope returns no results. printReadDir(ctxt, pkg2) }
Output: ReadDir("src/p") p1/ ReadDir("src/p/p1") c1/ f1.go f2.go ReadDir("src/p/p1/c1") fc1.go fc2.go ReadDir("src/p/p2") open src/p/p2: file does not exist
Types ¶
This section is empty.