mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	* Inital routes to git refs api * Git refs API implementation * Update swagger * Fix copyright * Make swagger happy add basic test * Fix test * Fix test again :)
		
			
				
	
	
		
			186 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package ssh_config
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"strings"
 | 
						|
)
 | 
						|
 | 
						|
type sshParser struct {
 | 
						|
	flow          chan token
 | 
						|
	config        *Config
 | 
						|
	tokensBuffer  []token
 | 
						|
	currentTable  []string
 | 
						|
	seenTableKeys []string
 | 
						|
	// /etc/ssh parser or local parser - used to find the default for relative
 | 
						|
	// filepaths in the Include directive
 | 
						|
	system bool
 | 
						|
	depth  uint8
 | 
						|
}
 | 
						|
 | 
						|
type sshParserStateFn func() sshParserStateFn
 | 
						|
 | 
						|
// Formats and panics an error message based on a token
 | 
						|
func (p *sshParser) raiseErrorf(tok *token, msg string, args ...interface{}) {
 | 
						|
	// TODO this format is ugly
 | 
						|
	panic(tok.Position.String() + ": " + fmt.Sprintf(msg, args...))
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) raiseError(tok *token, err error) {
 | 
						|
	if err == ErrDepthExceeded {
 | 
						|
		panic(err)
 | 
						|
	}
 | 
						|
	// TODO this format is ugly
 | 
						|
	panic(tok.Position.String() + ": " + err.Error())
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) run() {
 | 
						|
	for state := p.parseStart; state != nil; {
 | 
						|
		state = state()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) peek() *token {
 | 
						|
	if len(p.tokensBuffer) != 0 {
 | 
						|
		return &(p.tokensBuffer[0])
 | 
						|
	}
 | 
						|
 | 
						|
	tok, ok := <-p.flow
 | 
						|
	if !ok {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	p.tokensBuffer = append(p.tokensBuffer, tok)
 | 
						|
	return &tok
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) getToken() *token {
 | 
						|
	if len(p.tokensBuffer) != 0 {
 | 
						|
		tok := p.tokensBuffer[0]
 | 
						|
		p.tokensBuffer = p.tokensBuffer[1:]
 | 
						|
		return &tok
 | 
						|
	}
 | 
						|
	tok, ok := <-p.flow
 | 
						|
	if !ok {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	return &tok
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) parseStart() sshParserStateFn {
 | 
						|
	tok := p.peek()
 | 
						|
 | 
						|
	// end of stream, parsing is finished
 | 
						|
	if tok == nil {
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
 | 
						|
	switch tok.typ {
 | 
						|
	case tokenComment, tokenEmptyLine:
 | 
						|
		return p.parseComment
 | 
						|
	case tokenKey:
 | 
						|
		return p.parseKV
 | 
						|
	case tokenEOF:
 | 
						|
		return nil
 | 
						|
	default:
 | 
						|
		p.raiseErrorf(tok, fmt.Sprintf("unexpected token %q\n", tok))
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) parseKV() sshParserStateFn {
 | 
						|
	key := p.getToken()
 | 
						|
	hasEquals := false
 | 
						|
	val := p.getToken()
 | 
						|
	if val.typ == tokenEquals {
 | 
						|
		hasEquals = true
 | 
						|
		val = p.getToken()
 | 
						|
	}
 | 
						|
	comment := ""
 | 
						|
	tok := p.peek()
 | 
						|
	if tok == nil {
 | 
						|
		tok = &token{typ: tokenEOF}
 | 
						|
	}
 | 
						|
	if tok.typ == tokenComment && tok.Position.Line == val.Position.Line {
 | 
						|
		tok = p.getToken()
 | 
						|
		comment = tok.val
 | 
						|
	}
 | 
						|
	if strings.ToLower(key.val) == "match" {
 | 
						|
		// https://github.com/kevinburke/ssh_config/issues/6
 | 
						|
		p.raiseErrorf(val, "ssh_config: Match directive parsing is unsupported")
 | 
						|
		return nil
 | 
						|
	}
 | 
						|
	if strings.ToLower(key.val) == "host" {
 | 
						|
		strPatterns := strings.Split(val.val, " ")
 | 
						|
		patterns := make([]*Pattern, 0)
 | 
						|
		for i := range strPatterns {
 | 
						|
			if strPatterns[i] == "" {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			pat, err := NewPattern(strPatterns[i])
 | 
						|
			if err != nil {
 | 
						|
				p.raiseErrorf(val, "Invalid host pattern: %v", err)
 | 
						|
				return nil
 | 
						|
			}
 | 
						|
			patterns = append(patterns, pat)
 | 
						|
		}
 | 
						|
		p.config.Hosts = append(p.config.Hosts, &Host{
 | 
						|
			Patterns:   patterns,
 | 
						|
			Nodes:      make([]Node, 0),
 | 
						|
			EOLComment: comment,
 | 
						|
			hasEquals:  hasEquals,
 | 
						|
		})
 | 
						|
		return p.parseStart
 | 
						|
	}
 | 
						|
	lastHost := p.config.Hosts[len(p.config.Hosts)-1]
 | 
						|
	if strings.ToLower(key.val) == "include" {
 | 
						|
		inc, err := NewInclude(strings.Split(val.val, " "), hasEquals, key.Position, comment, p.system, p.depth+1)
 | 
						|
		if err == ErrDepthExceeded {
 | 
						|
			p.raiseError(val, err)
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
		if err != nil {
 | 
						|
			p.raiseErrorf(val, "Error parsing Include directive: %v", err)
 | 
						|
			return nil
 | 
						|
		}
 | 
						|
		lastHost.Nodes = append(lastHost.Nodes, inc)
 | 
						|
		return p.parseStart
 | 
						|
	}
 | 
						|
	kv := &KV{
 | 
						|
		Key:          key.val,
 | 
						|
		Value:        val.val,
 | 
						|
		Comment:      comment,
 | 
						|
		hasEquals:    hasEquals,
 | 
						|
		leadingSpace: uint16(key.Position.Col) - 1,
 | 
						|
		position:     key.Position,
 | 
						|
	}
 | 
						|
	lastHost.Nodes = append(lastHost.Nodes, kv)
 | 
						|
	return p.parseStart
 | 
						|
}
 | 
						|
 | 
						|
func (p *sshParser) parseComment() sshParserStateFn {
 | 
						|
	comment := p.getToken()
 | 
						|
	lastHost := p.config.Hosts[len(p.config.Hosts)-1]
 | 
						|
	lastHost.Nodes = append(lastHost.Nodes, &Empty{
 | 
						|
		Comment: comment.val,
 | 
						|
		// account for the "#" as well
 | 
						|
		leadingSpace: comment.Position.Col - 2,
 | 
						|
		position:     comment.Position,
 | 
						|
	})
 | 
						|
	return p.parseStart
 | 
						|
}
 | 
						|
 | 
						|
func parseSSH(flow chan token, system bool, depth uint8) *Config {
 | 
						|
	result := newConfig()
 | 
						|
	result.position = Position{1, 1}
 | 
						|
	parser := &sshParser{
 | 
						|
		flow:          flow,
 | 
						|
		config:        result,
 | 
						|
		tokensBuffer:  make([]token, 0),
 | 
						|
		currentTable:  make([]string, 0),
 | 
						|
		seenTableKeys: make([]string, 0),
 | 
						|
		system:        system,
 | 
						|
		depth:         depth,
 | 
						|
	}
 | 
						|
	parser.run()
 | 
						|
	return result
 | 
						|
}
 |