| // Copyright 2013 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 godoc |
| |
| import ( |
| "errors" |
| pathpkg "path" |
| "time" |
| |
| "golang.org/x/tools/godoc/analysis" |
| "golang.org/x/tools/godoc/util" |
| "golang.org/x/tools/godoc/vfs" |
| ) |
| |
| // A Corpus holds all the state related to serving and indexing a |
| // collection of Go code. |
| // |
| // Construct a new Corpus with NewCorpus, then modify options, |
| // then call its Init method. |
| type Corpus struct { |
| fs vfs.FileSystem |
| |
| // Verbose logging. |
| Verbose bool |
| |
| // IndexEnabled controls whether indexing is enabled. |
| IndexEnabled bool |
| |
| // IndexFiles specifies a glob pattern specifying index files. |
| // If not empty, the index is read from these files in sorted |
| // order. |
| IndexFiles string |
| |
| // IndexThrottle specifies the indexing throttle value |
| // between 0.0 and 1.0. At 0.0, the indexer always sleeps. |
| // At 1.0, the indexer never sleeps. Because 0.0 is useless |
| // and redundant with setting IndexEnabled to false, the |
| // zero value for IndexThrottle means 0.9. |
| IndexThrottle float64 |
| |
| // IndexInterval specifies the time to sleep between reindexing |
| // all the sources. |
| // If zero, a default is used. If negative, the index is only |
| // built once. |
| IndexInterval time.Duration |
| |
| // IndexDocs enables indexing of Go documentation. |
| // This will produce search results for exported types, functions, |
| // methods, variables, and constants, and will link to the godoc |
| // documentation for those identifiers. |
| IndexDocs bool |
| |
| // IndexGoCode enables indexing of Go source code. |
| // This will produce search results for internal and external identifiers |
| // and will link to both declarations and uses of those identifiers in |
| // source code. |
| IndexGoCode bool |
| |
| // IndexFullText enables full-text indexing. |
| // This will provide search results for any matching text in any file that |
| // is indexed, including non-Go files (see whitelisted in index.go). |
| // Regexp searching is supported via full-text indexing. |
| IndexFullText bool |
| |
| // MaxResults optionally specifies the maximum results for indexing. |
| MaxResults int |
| |
| // SummarizePackage optionally specifies a function to |
| // summarize a package. It exists as an optimization to |
| // avoid reading files to parse package comments. |
| // |
| // If SummarizePackage returns false for ok, the caller |
| // ignores all return values and parses the files in the package |
| // as if SummarizePackage were nil. |
| // |
| // If showList is false, the package is hidden from the |
| // package listing. |
| SummarizePackage func(pkg string) (summary string, showList, ok bool) |
| |
| // IndexDirectory optionally specifies a function to determine |
| // whether the provided directory should be indexed. The dir |
| // will be of the form "/src/cmd/6a", "/doc/play", |
| // "/src/io", etc. |
| // If nil, all directories are indexed if indexing is enabled. |
| IndexDirectory func(dir string) bool |
| |
| testDir string // TODO(bradfitz,adg): migrate old godoc flag? looks unused. |
| |
| // Send a value on this channel to trigger a metadata refresh. |
| // It is buffered so that if a signal is not lost if sent |
| // during a refresh. |
| refreshMetadataSignal chan bool |
| |
| // file system information |
| fsTree util.RWValue // *Directory tree of packages, updated with each sync (but sync code is removed now) |
| fsModified util.RWValue // timestamp of last call to invalidateIndex |
| docMetadata util.RWValue // mapping from paths to *Metadata |
| |
| // SearchIndex is the search index in use. |
| searchIndex util.RWValue |
| |
| // Analysis is the result of type and pointer analysis. |
| Analysis analysis.Result |
| } |
| |
| // NewCorpus returns a new Corpus from a filesystem. |
| // The returned corpus has all indexing enabled and MaxResults set to 1000. |
| // Change or set any options on Corpus before calling the Corpus.Init method. |
| func NewCorpus(fs vfs.FileSystem) *Corpus { |
| c := &Corpus{ |
| fs: fs, |
| refreshMetadataSignal: make(chan bool, 1), |
| |
| MaxResults: 1000, |
| IndexEnabled: true, |
| IndexDocs: true, |
| IndexGoCode: true, |
| IndexFullText: true, |
| } |
| return c |
| } |
| |
| func (c *Corpus) CurrentIndex() (*Index, time.Time) { |
| v, t := c.searchIndex.Get() |
| idx, _ := v.(*Index) |
| return idx, t |
| } |
| |
| func (c *Corpus) FSModifiedTime() time.Time { |
| _, ts := c.fsModified.Get() |
| return ts |
| } |
| |
| // Init initializes Corpus, once options on Corpus are set. |
| // It must be called before any subsequent method calls. |
| func (c *Corpus) Init() error { |
| // TODO(bradfitz): do this in a goroutine because newDirectory might block for a long time? |
| // It used to be sometimes done in a goroutine before, at least in HTTP server mode. |
| if err := c.initFSTree(); err != nil { |
| return err |
| } |
| c.updateMetadata() |
| go c.refreshMetadataLoop() |
| return nil |
| } |
| |
| func (c *Corpus) initFSTree() error { |
| dir := c.newDirectory(pathpkg.Join("/", c.testDir), -1) |
| if dir == nil { |
| return errors.New("godoc: corpus fstree is nil") |
| } |
| c.fsTree.Set(dir) |
| c.invalidateIndex() |
| return nil |
| } |