fork of https://github.com/sourcegraph/zoekt
0

Configure Feed

Select the types of activity you want to include in your feed.

1// Copyright 2017 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package ctags 16 17import ( 18 "fmt" 19 "log" 20 "os" 21 "time" 22 23 goctags "github.com/sourcegraph/go-ctags" 24) 25 26type Entry = goctags.Entry 27 28// CTagsParser wraps go-ctags and delegates to the right process (like universal-ctags or scip-ctags). 29// It is only safe for single-threaded use. This wrapper also enforces a timeout on parsing a single 30// document, which is important since documents can occasionally hang universal-ctags. 31// documents which hang universal-ctags. 32type CTagsParser struct { 33 bins ParserBinMap 34 parsers map[CTagsParserType]goctags.Parser 35} 36 37// parseTimeout is how long we wait for a response for parsing a single file 38// in ctags. 1 minute is a very conservative timeout which we should only hit 39// if ctags hangs. 40const parseTimeout = time.Minute 41 42func NewCTagsParser(bins ParserBinMap) CTagsParser { 43 return CTagsParser{bins: bins, parsers: make(map[CTagsParserType]goctags.Parser)} 44} 45 46type parseResult struct { 47 entries []*Entry 48 err error 49} 50 51func (lp *CTagsParser) Parse(name string, content []byte, typ CTagsParserType) ([]*Entry, error) { 52 if lp.parsers[typ] == nil { 53 parser, err := lp.newParserProcess(typ) 54 if parser == nil || err != nil { 55 return nil, err 56 } 57 lp.parsers[typ] = parser 58 } 59 60 deadline := time.NewTimer(parseTimeout) 61 defer deadline.Stop() 62 63 parser := lp.parsers[typ] 64 recv := make(chan parseResult, 1) 65 go func() { 66 entry, err := parser.Parse(name, content) 67 recv <- parseResult{entries: entry, err: err} 68 }() 69 70 select { 71 case resp := <-recv: 72 return resp.entries, resp.err 73 case <-deadline.C: 74 // Error out since ctags hanging is a sign something bad is happening. 75 return nil, fmt.Errorf("ctags timedout after %s parsing %s", parseTimeout, name) 76 } 77} 78 79func (lp *CTagsParser) newParserProcess(typ CTagsParserType) (goctags.Parser, error) { 80 bin := lp.bins[typ] 81 if bin == "" { 82 // This happens if CTagsMustSucceed is false and we didn't find the binary 83 return nil, nil 84 } 85 86 opts := goctags.Options{Bin: bin} 87 parserType := ParserToString(typ) 88 if debug { 89 opts.Info = log.New(os.Stderr, "CTAGS ("+parserType+") INF: ", log.LstdFlags) 90 opts.Debug = log.New(os.Stderr, "CTAGS ("+parserType+") DBG: ", log.LstdFlags) 91 } 92 return goctags.New(opts) 93} 94 95func (lp *CTagsParser) Close() { 96 for _, parser := range lp.parsers { 97 parser.Close() 98 } 99}