1package git
2
3import (
4	"bufio"
5	"os"
6	"path/filepath"
7	"regexp"
8	"strings"
9
10	"github.com/mitchellh/go-homedir"
11)
12
13const (
14	hostReStr = "(?i)^[ \t]*(host|hostname)[ \t]+(.+)$"
15)
16
17type SSHConfig map[string]string
18
19func newSSHConfigReader() *SSHConfigReader {
20	configFiles := []string{
21		"/etc/ssh_config",
22		"/etc/ssh/ssh_config",
23	}
24	if homedir, err := homedir.Dir(); err == nil {
25		userConfig := filepath.Join(homedir, ".ssh", "config")
26		configFiles = append([]string{userConfig}, configFiles...)
27	}
28	return &SSHConfigReader{
29		Files: configFiles,
30	}
31}
32
33type SSHConfigReader struct {
34	Files []string
35}
36
37func (r *SSHConfigReader) Read() SSHConfig {
38	config := make(SSHConfig)
39	hostRe := regexp.MustCompile(hostReStr)
40
41	for _, filename := range r.Files {
42		r.readFile(config, hostRe, filename)
43	}
44
45	return config
46}
47
48func (r *SSHConfigReader) readFile(c SSHConfig, re *regexp.Regexp, f string) error {
49	file, err := os.Open(f)
50	if err != nil {
51		return err
52	}
53	defer file.Close()
54
55	hosts := []string{"*"}
56	scanner := bufio.NewScanner(file)
57	for scanner.Scan() {
58		line := scanner.Text()
59		match := re.FindStringSubmatch(line)
60		if match == nil {
61			continue
62		}
63
64		names := strings.Fields(match[2])
65		if strings.EqualFold(match[1], "host") {
66			hosts = names
67		} else {
68			for _, host := range hosts {
69				for _, name := range names {
70					c[host] = expandTokens(name, host)
71				}
72			}
73		}
74	}
75
76	return scanner.Err()
77}
78
79func expandTokens(text, host string) string {
80	re := regexp.MustCompile(`%[%h]`)
81	return re.ReplaceAllStringFunc(text, func(match string) string {
82		switch match {
83		case "%h":
84			return host
85		case "%%":
86			return "%"
87		}
88		return ""
89	})
90}
91