Files
go-ssh-config/config.go
2017-04-18 10:57:51 -07:00

145 lines
2.8 KiB
Go

package ssh_config
import (
"bytes"
"errors"
"fmt"
"io"
"os"
"runtime"
"strings"
)
type UserSettings struct {
systemConfig *Config
userConfig *Config
username string
}
func parseFile(filename string) (*Config, error) {
f, err := os.Open(filename)
if err != nil {
return nil, err
}
defer f.Close()
return Decode(f)
}
// Decode reads r into a Config, or returns an error if r could not be parsed as
// an SSH config file.
func Decode(r io.Reader) (c *Config, err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
panic(r)
}
err = errors.New(r.(string))
}
}()
c = parseSSH(lexSSH(r))
return c, err
}
// Config represents an SSH config file.
type Config struct {
position Position
Hosts []*Host
}
func (c *Config) String() string {
var buf bytes.Buffer
for i := range c.Hosts {
buf.WriteString(c.Hosts[i].String())
}
return buf.String()
}
type Host struct {
// A list of host patterns that should match this host.
Patterns []string
// A Node is either a key/value pair or a comment line.
Nodes []Node
// EOLComment is the comment (if any) terminating the Host line.
EOLComment string
leadingSpace uint16 // TODO: handle spaces vs tabs here.
// The file starts with an implicit "Host *" declaration.
implicit bool
}
func (h *Host) String() string {
var buf bytes.Buffer
if h.implicit == false {
buf.WriteString(strings.Repeat(" ", int(h.leadingSpace)))
buf.WriteString("Host ")
buf.WriteString(strings.Join(h.Patterns, " "))
if h.EOLComment != "" {
buf.WriteString(" #")
buf.WriteString(h.EOLComment)
}
buf.WriteByte('\n')
}
for i := range h.Nodes {
//fmt.Printf("%q\n", h.Nodes[i].String())
buf.WriteString(h.Nodes[i].String())
buf.WriteByte('\n')
}
return buf.String()
}
type Node interface {
Pos() Position
String() string
}
type KV struct {
Key string
Value string
Comment string
leadingSpace uint16 // Space before the key. TODO handle spaces vs tabs.
position Position
}
func (k *KV) Pos() Position {
return k.position
}
func (k *KV) String() string {
if k == nil {
return ""
}
line := fmt.Sprintf("%s%s %s", strings.Repeat(" ", int(k.leadingSpace)), k.Key, k.Value)
if k.Comment != "" {
line += " #" + k.Comment
}
return line
}
type Empty struct {
Comment string
leadingSpace uint16 // TODO handle spaces vs tabs.
position Position
}
func (e *Empty) Pos() Position {
return e.position
}
func (e *Empty) String() string {
if e == nil {
return ""
}
if e.Comment == "" {
return ""
}
return fmt.Sprintf("%s#%s", strings.Repeat(" ", int(e.leadingSpace)), e.Comment)
}
func newConfig() *Config {
return &Config{
Hosts: []*Host{
&Host{implicit: true, Patterns: []string{"*"}, Nodes: make([]Node, 0)},
},
}
}