github.com/unirita/cuto@v0.9.8-0.20160830082821-aa6652f877b7/flowgen/converter/parser.go (about)

     1  package converter
     2  
     3  import (
     4  	"errors"
     5  	"io/ioutil"
     6  	"regexp"
     7  	"strings"
     8  )
     9  
    10  const (
    11  	arrow  = "->"
    12  	gHead  = "["
    13  	gTerm  = "]"
    14  	gDelim = ","
    15  	tmpGW  = ":gw"
    16  )
    17  
    18  // Parse parses flow description from file.
    19  func ParseFile(filepath string) (Element, error) {
    20  	buf, err := ioutil.ReadFile(filepath)
    21  	if err != nil {
    22  		return nil, err
    23  	}
    24  
    25  	return ParseString(string(buf))
    26  }
    27  
    28  // ParseString parses flow description from string.
    29  // If it successed, returns head element of flow.
    30  func ParseString(str string) (Element, error) {
    31  	str = ignoreSpaceChars(str)
    32  	extracted, gws, err := extractGateways(str)
    33  
    34  	var head Element = nil
    35  	elmStrs := strings.Split(extracted, arrow)
    36  	isFirst := true
    37  	var current Element
    38  	var pre Element
    39  	var tmpGWIndex = 0
    40  	for _, elmStr := range elmStrs {
    41  		if elmStr == tmpGW {
    42  			if tmpGWIndex > len(gws) {
    43  				return nil, errors.New("Gateway parse error.")
    44  			}
    45  			current = gws[tmpGWIndex]
    46  			tmpGWIndex++
    47  		} else {
    48  			current, err = parseJob(elmStr)
    49  			if err != nil {
    50  				return nil, err
    51  			}
    52  		}
    53  
    54  		if isFirst {
    55  			head = current
    56  			isFirst = false
    57  		} else {
    58  			pre.SetNext(current)
    59  		}
    60  		pre = current
    61  	}
    62  	return head, nil
    63  }
    64  
    65  func ignoreSpaceChars(str string) string {
    66  	ptn := regexp.MustCompile(`\s`)
    67  	return ptn.ReplaceAllLiteralString(str, "")
    68  }
    69  
    70  func extractGateways(str string) (string, []*Gateway, error) {
    71  	ptn := regexp.MustCompile(`\[.+?\]`)
    72  	gws := make([]*Gateway, 0)
    73  
    74  	gwStrs := ptn.FindAllString(str, -1)
    75  	for _, gwStr := range gwStrs {
    76  		gw, err := parseGateway(gwStr)
    77  		if err != nil {
    78  			return str, nil, err
    79  		}
    80  		gws = append(gws, gw)
    81  	}
    82  
    83  	str = ptn.ReplaceAllString(str, tmpGW)
    84  	return str, gws, nil
    85  }
    86  
    87  func parseJob(str string) (*Job, error) {
    88  	if err := validateJobName(str); err != nil {
    89  		return nil, err
    90  	}
    91  	return NewJob(str), nil
    92  }
    93  
    94  func validateJobName(str string) error {
    95  	if len(str) == 0 {
    96  		return errors.New("Empty job name found.")
    97  	}
    98  
    99  	ptn := regexp.MustCompile(`[\[\]\\/:*?<>$&,\-]`)
   100  	if ptn.MatchString(str) {
   101  		return errors.New("Irregal character found in job name.")
   102  	}
   103  
   104  	return nil
   105  }
   106  
   107  func parseGateway(str string) (*Gateway, error) {
   108  	str = strings.TrimLeft(str, gHead)
   109  	str = strings.TrimRight(str, gTerm)
   110  
   111  	p := NewGateway()
   112  
   113  	pathStrs := strings.Split(str, gDelim)
   114  	for _, pathStr := range pathStrs {
   115  		jobNames := strings.Split(pathStr, arrow)
   116  		isFirst := true
   117  		var preJob *Job
   118  		for _, jobName := range jobNames {
   119  			j, err := parseJob(jobName)
   120  			if err != nil {
   121  				return nil, err
   122  			}
   123  
   124  			if isFirst {
   125  				p.AddPathHead(j)
   126  				isFirst = false
   127  			} else {
   128  				preJob.SetNext(j)
   129  			}
   130  			preJob = j
   131  		}
   132  	}
   133  
   134  	return p, nil
   135  }