1// Copyright 2013 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package godoc 6 7import ( 8 "errors" 9 pathpkg "path" 10 "sync" 11 "time" 12 13 "golang.org/x/tools/godoc/analysis" 14 "golang.org/x/tools/godoc/util" 15 "golang.org/x/tools/godoc/vfs" 16) 17 18// A Corpus holds all the state related to serving and indexing a 19// collection of Go code. 20// 21// Construct a new Corpus with NewCorpus, then modify options, 22// then call its Init method. 23type Corpus struct { 24 fs vfs.FileSystem 25 26 // Verbose logging. 27 Verbose bool 28 29 // IndexEnabled controls whether indexing is enabled. 30 IndexEnabled bool 31 32 // IndexFiles specifies a glob pattern specifying index files. 33 // If not empty, the index is read from these files in sorted 34 // order. 35 IndexFiles string 36 37 // IndexThrottle specifies the indexing throttle value 38 // between 0.0 and 1.0. At 0.0, the indexer always sleeps. 39 // At 1.0, the indexer never sleeps. Because 0.0 is useless 40 // and redundant with setting IndexEnabled to false, the 41 // zero value for IndexThrottle means 0.9. 42 IndexThrottle float64 43 44 // IndexInterval specifies the time to sleep between reindexing 45 // all the sources. 46 // If zero, a default is used. If negative, the index is only 47 // built once. 48 IndexInterval time.Duration 49 50 // IndexDocs enables indexing of Go documentation. 51 // This will produce search results for exported types, functions, 52 // methods, variables, and constants, and will link to the godoc 53 // documentation for those identifiers. 54 IndexDocs bool 55 56 // IndexGoCode enables indexing of Go source code. 57 // This will produce search results for internal and external identifiers 58 // and will link to both declarations and uses of those identifiers in 59 // source code. 60 IndexGoCode bool 61 62 // IndexFullText enables full-text indexing. 63 // This will provide search results for any matching text in any file that 64 // is indexed, including non-Go files (see whitelisted in index.go). 65 // Regexp searching is supported via full-text indexing. 66 IndexFullText bool 67 68 // MaxResults optionally specifies the maximum results for indexing. 69 MaxResults int 70 71 // SummarizePackage optionally specifies a function to 72 // summarize a package. It exists as an optimization to 73 // avoid reading files to parse package comments. 74 // 75 // If SummarizePackage returns false for ok, the caller 76 // ignores all return values and parses the files in the package 77 // as if SummarizePackage were nil. 78 // 79 // If showList is false, the package is hidden from the 80 // package listing. 81 SummarizePackage func(pkg string) (summary string, showList, ok bool) 82 83 // IndexDirectory optionally specifies a function to determine 84 // whether the provided directory should be indexed. The dir 85 // will be of the form "/src/cmd/6a", "/doc/play", 86 // "/src/io", etc. 87 // If nil, all directories are indexed if indexing is enabled. 88 IndexDirectory func(dir string) bool 89 90 testDir string // TODO(bradfitz,adg): migrate old godoc flag? looks unused. 91 92 // Send a value on this channel to trigger a metadata refresh. 93 // It is buffered so that if a signal is not lost if sent 94 // during a refresh. 95 refreshMetadataSignal chan bool 96 97 // file system information 98 fsTree util.RWValue // *Directory tree of packages, updated with each sync (but sync code is removed now) 99 fsModified util.RWValue // timestamp of last call to invalidateIndex 100 docMetadata util.RWValue // mapping from paths to *Metadata 101 102 // SearchIndex is the search index in use. 103 searchIndex util.RWValue 104 105 // Analysis is the result of type and pointer analysis. 106 Analysis analysis.Result 107 108 // flag to check whether a corpus is initialized or not 109 initMu sync.RWMutex 110 initDone bool 111 112 // pkgAPIInfo contains the information about which package API 113 // features were added in which version of Go. 114 pkgAPIInfo apiVersions 115} 116 117// NewCorpus returns a new Corpus from a filesystem. 118// The returned corpus has all indexing enabled and MaxResults set to 1000. 119// Change or set any options on Corpus before calling the Corpus.Init method. 120func NewCorpus(fs vfs.FileSystem) *Corpus { 121 c := &Corpus{ 122 fs: fs, 123 refreshMetadataSignal: make(chan bool, 1), 124 125 MaxResults: 1000, 126 IndexEnabled: true, 127 IndexDocs: true, 128 IndexGoCode: true, 129 IndexFullText: true, 130 } 131 return c 132} 133 134func (c *Corpus) CurrentIndex() (*Index, time.Time) { 135 v, t := c.searchIndex.Get() 136 idx, _ := v.(*Index) 137 return idx, t 138} 139 140func (c *Corpus) FSModifiedTime() time.Time { 141 _, ts := c.fsModified.Get() 142 return ts 143} 144 145// Init initializes Corpus, once options on Corpus are set. 146// It must be called before any subsequent method calls. 147func (c *Corpus) Init() error { 148 if err := c.initFSTree(); err != nil { 149 return err 150 } 151 c.updateMetadata() 152 go c.refreshMetadataLoop() 153 154 c.initMu.Lock() 155 c.initDone = true 156 c.initMu.Unlock() 157 return nil 158} 159 160func (c *Corpus) initFSTree() error { 161 dir := c.newDirectory(pathpkg.Join("/", c.testDir), -1) 162 if dir == nil { 163 return errors.New("godoc: corpus fstree is nil") 164 } 165 c.fsTree.Set(dir) 166 c.invalidateIndex() 167 return nil 168} 169