...
Run Format

Source file src/cmd/doc/dirs.go

Documentation: cmd/doc

  // Copyright 2015 The Go Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style
  // license that can be found in the LICENSE file.
  
  package main
  
  import (
  	"go/build"
  	"log"
  	"os"
  	"path"
  	"path/filepath"
  	"strings"
  )
  
  // Dirs is a structure for scanning the directory tree.
  // Its Next method returns the next Go source directory it finds.
  // Although it can be used to scan the tree multiple times, it
  // only walks the tree once, caching the data it finds.
  type Dirs struct {
  	scan   chan string // directories generated by walk.
  	paths  []string    // Cache of known paths.
  	offset int         // Counter for Next.
  }
  
  var dirs Dirs
  
  func init() {
  	dirs.paths = make([]string, 0, 1000)
  	dirs.scan = make(chan string)
  	go dirs.walk()
  }
  
  // Reset puts the scan back at the beginning.
  func (d *Dirs) Reset() {
  	d.offset = 0
  }
  
  // Next returns the next directory in the scan. The boolean
  // is false when the scan is done.
  func (d *Dirs) Next() (string, bool) {
  	if d.offset < len(d.paths) {
  		path := d.paths[d.offset]
  		d.offset++
  		return path, true
  	}
  	path, ok := <-d.scan
  	if !ok {
  		return "", false
  	}
  	d.paths = append(d.paths, path)
  	d.offset++
  	return path, ok
  }
  
  // walk walks the trees in GOROOT and GOPATH.
  func (d *Dirs) walk() {
  	d.bfsWalkRoot(build.Default.GOROOT)
  	for _, root := range splitGopath() {
  		d.bfsWalkRoot(root)
  	}
  	close(d.scan)
  }
  
  // bfsWalkRoot walks a single directory hierarchy in breadth-first lexical order.
  // Each Go source directory it finds is delivered on d.scan.
  func (d *Dirs) bfsWalkRoot(root string) {
  	root = path.Join(root, "src")
  
  	// this is the queue of directories to examine in this pass.
  	this := []string{}
  	// next is the queue of directories to examine in the next pass.
  	next := []string{root}
  
  	for len(next) > 0 {
  		this, next = next, this[0:0]
  		for _, dir := range this {
  			fd, err := os.Open(dir)
  			if err != nil {
  				log.Print(err)
  				continue
  			}
  			entries, err := fd.Readdir(0)
  			fd.Close()
  			if err != nil {
  				log.Print(err)
  				continue
  			}
  			hasGoFiles := false
  			for _, entry := range entries {
  				name := entry.Name()
  				// For plain files, remember if this directory contains any .go
  				// source files, but ignore them otherwise.
  				if !entry.IsDir() {
  					if !hasGoFiles && strings.HasSuffix(name, ".go") {
  						hasGoFiles = true
  					}
  					continue
  				}
  				// Entry is a directory.
  				// No .git or other dot nonsense please.
  				if strings.HasPrefix(name, ".") {
  					continue
  				}
  				// Remember this (fully qualified) directory for the next pass.
  				next = append(next, filepath.Join(dir, name))
  			}
  			if hasGoFiles {
  				// It's a candidate.
  				d.scan <- dir
  			}
  		}
  
  	}
  }
  

View as plain text