github.com/dahs81/otto@v0.2.1-0.20160126165905-6400716cf085/appfile/detect/config.go (about) 1 package detect 2 3 import ( 4 "bufio" 5 "fmt" 6 "os" 7 "path/filepath" 8 "regexp" 9 ) 10 11 // Config is the format of the configuration files 12 type Config struct { 13 Detectors []*Detector 14 } 15 16 // Merge merges another config into this one. This will modify this 17 // Config object. Detectors in c2 are tried after detectors in this 18 // Config. Conflicts are ignored as lower priority detectors, meaning that 19 // if two detectors are for type "go", both will be tried. 20 func (c *Config) Merge(c2 *Config) error { 21 c.Detectors = append(c.Detectors, c2.Detectors...) 22 return nil 23 } 24 25 // Detector is something that detects a single type. 26 type Detector struct { 27 // Type is the type that will match if this detector matches 28 Type string 29 30 // File is a list of file globs to look for. If any are found, it is 31 // a match. 32 File []string 33 34 // Contents is a content matcher. The key is a filename and the 35 // path is the file contents regular expression. 36 Contents map[string]string 37 38 // Priority is used to break ties when two detectors conflict. 39 // The detector with the higher (larger number) priority wins. 40 // This defaults to 0. Negative numbers can be used to lower 41 // priority and positive numbers can be used to increase it. 42 // 43 // In most cases, a priority never needs to be set. Please set this 44 // with care. 45 Priority int 46 } 47 48 // Detect will return true if this detector matches within the given 49 // directory. 50 func (d *Detector) Detect(dir string) (bool, error) { 51 // First test files 52 for _, pattern := range d.File { 53 matches, err := filepath.Glob(filepath.Join(dir, pattern)) 54 if err != nil { 55 return false, err 56 } 57 if len(matches) > 0 { 58 return true, nil 59 } 60 } 61 62 // Test contents 63 for k, v := range d.Contents { 64 path := filepath.Join(dir, k) 65 if _, err := os.Stat(path); err != nil { 66 continue 67 } 68 69 if ok, err := d.matchContents(path, v); err != nil { 70 return false, err 71 } else if ok { 72 return true, nil 73 } 74 } 75 76 return false, nil 77 } 78 79 func (d *Detector) matchContents(path string, raw string) (bool, error) { 80 f, err := os.Open(path) 81 if err != nil { 82 return false, err 83 } 84 defer f.Close() 85 86 re, err := regexp.Compile(raw) 87 if err != nil { 88 return false, err 89 } 90 91 return re.MatchReader(bufio.NewReader(f)), nil 92 } 93 94 func (d *Detector) GoString() string { 95 return fmt.Sprintf("*%#v", *d) 96 }