github.com/v2fly/tools@v0.100.0/godoc/corpus.go (about)

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