github.com/mfycheng/glide@v0.11.2-0.20160818232903-be8a502f4bc4/gom/parser.go (about)

     1  package gom
     2  
     3  // This is copied + slightly adapted from gom's `gomfile.go` file.
     4  //
     5  // gom's license is MIT-style.
     6  
     7  import (
     8  	"bufio"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"regexp"
    13  	"strings"
    14  )
    15  
    16  var qx = `'[^']*'|"[^"]*"`
    17  var kx = `:[a-z][a-z0-9_]*`
    18  var ax = `(?:\s*` + kx + `\s*|,\s*` + kx + `\s*)`
    19  var reGroup = regexp.MustCompile(`\s*group\s+((?:` + kx + `\s*|,\s*` + kx + `\s*)*)\s*do\s*$`)
    20  var reEnd = regexp.MustCompile(`\s*end\s*$`)
    21  var reGom = regexp.MustCompile(`^\s*gom\s+(` + qx + `)\s*((?:,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*))*)$`)
    22  var reOptions = regexp.MustCompile(`(,\s*` + kx + `\s*=>\s*(?:` + qx + `|\s*\[\s*` + ax + `*\s*\]\s*)\s*)`)
    23  
    24  func unquote(name string) string {
    25  	name = strings.TrimSpace(name)
    26  	if len(name) > 2 {
    27  		if (name[0] == '\'' && name[len(name)-1] == '\'') || (name[0] == '"' && name[len(name)-1] == '"') {
    28  			return name[1 : len(name)-1]
    29  		}
    30  	}
    31  	return name
    32  }
    33  
    34  func parseOptions(line string, options map[string]interface{}) {
    35  	ss := reOptions.FindAllStringSubmatch(line, -1)
    36  	reA := regexp.MustCompile(ax)
    37  	for _, s := range ss {
    38  		kvs := strings.SplitN(strings.TrimSpace(s[0])[1:], "=>", 2)
    39  		kvs[0], kvs[1] = strings.TrimSpace(kvs[0]), strings.TrimSpace(kvs[1])
    40  		if kvs[1][0] == '[' {
    41  			as := reA.FindAllStringSubmatch(kvs[1][1:len(kvs[1])-1], -1)
    42  			a := []string{}
    43  			for i := range as {
    44  				it := strings.TrimSpace(as[i][0])
    45  				if strings.HasPrefix(it, ",") {
    46  					it = strings.TrimSpace(it[1:])
    47  				}
    48  				if strings.HasPrefix(it, ":") {
    49  					it = strings.TrimSpace(it[1:])
    50  				}
    51  				a = append(a, it)
    52  			}
    53  			options[kvs[0][1:]] = a
    54  		} else {
    55  			options[kvs[0][1:]] = unquote(kvs[1])
    56  		}
    57  	}
    58  }
    59  
    60  // Gom represents configuration from Gom.
    61  type Gom struct {
    62  	name    string
    63  	options map[string]interface{}
    64  }
    65  
    66  func parseGomfile(filename string) ([]Gom, error) {
    67  	f, err := os.Open(filename + ".lock")
    68  	if err != nil {
    69  		f, err = os.Open(filename)
    70  		if err != nil {
    71  			return nil, err
    72  		}
    73  	}
    74  	br := bufio.NewReader(f)
    75  
    76  	goms := make([]Gom, 0)
    77  
    78  	n := 0
    79  	skip := 0
    80  	valid := true
    81  	var envs []string
    82  	for {
    83  		n++
    84  		lb, _, err := br.ReadLine()
    85  		if err != nil {
    86  			if err == io.EOF {
    87  				return goms, nil
    88  			}
    89  			return nil, err
    90  		}
    91  		line := strings.TrimSpace(string(lb))
    92  		if line == "" || strings.HasPrefix(line, "#") {
    93  			continue
    94  		}
    95  
    96  		name := ""
    97  		options := make(map[string]interface{})
    98  		var items []string
    99  		if reGroup.MatchString(line) {
   100  			envs = strings.Split(reGroup.FindStringSubmatch(line)[1], ",")
   101  			for i := range envs {
   102  				envs[i] = strings.TrimSpace(envs[i])[1:]
   103  			}
   104  			valid = true
   105  			continue
   106  		} else if reEnd.MatchString(line) {
   107  			if !valid {
   108  				skip--
   109  				if skip < 0 {
   110  					return nil, fmt.Errorf("Syntax Error at line %d", n)
   111  				}
   112  			}
   113  			valid = false
   114  			envs = nil
   115  			continue
   116  		} else if skip > 0 {
   117  			continue
   118  		} else if reGom.MatchString(line) {
   119  			items = reGom.FindStringSubmatch(line)[1:]
   120  			name = unquote(items[0])
   121  			parseOptions(items[1], options)
   122  		} else {
   123  			return nil, fmt.Errorf("Syntax Error at line %d", n)
   124  		}
   125  		if envs != nil {
   126  			options["group"] = envs
   127  		}
   128  		goms = append(goms, Gom{name, options})
   129  	}
   130  }