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  }