Cleanup for public release

- Test Include string representation

- Add docs and examples
This commit is contained in:
Kevin Burke
2017-05-25 08:00:10 -07:00
parent 3fad3c64da
commit 7897293c53
5 changed files with 69 additions and 24 deletions

View File

@@ -297,20 +297,21 @@ func special(b byte) bool {
return bytes.IndexByte(specialBytes, b) >= 0
}
// NewPattern creates a new Pattern for matching hosts.
// NewPattern creates a new Pattern for matching hosts. NewPattern("*") creates
// a Pattern that matches all hosts.
//
// From the manpage, a pattern consists of zero or more non-whitespace
// characters, `*' (a wildcard that matches zero or more characters), or `?' (a
// wildcard that matches exactly one character). For example, to specify a set
// of declarations for any host in the ".co.uk" set of domains, the following
// pattern could be used:
//
// Host *.co.uk
//
// The following pattern would match any host in the 192.168.0.[0-9] network range:
//
// Host 192.168.0.?
func NewPattern(s string) (*Pattern, error) {
// From the manpage:
// A pattern consists of zero or more non-whitespace characters,
// `*' (a wildcard that matches zero or more characters),
// or `?' (a wildcard that matches exactly one character).
// For example, to specify a set of declarations for any host in the
// ".co.uk" set of domains, the following pattern could be used:
//
// Host *.co.uk
//
// The following pattern would match any host in the 192.168.0.[0-9] network range:
//
// Host 192.168.0.?
if s == "" {
return nil, errors.New("ssh_config: empty pattern")
}
@@ -344,6 +345,7 @@ func NewPattern(s string) (*Pattern, error) {
return &Pattern{str: s, regex: r, not: negated}, nil
}
// Host describes a Host directive and the keywords that follow it.
type Host struct {
// A list of host patterns that should match this host.
Patterns []*Pattern
@@ -492,6 +494,7 @@ type Include struct {
leadingSpace uint16
position Position
depth uint8
hasEquals bool
}
const maxRecurseDepth = 5
@@ -519,7 +522,7 @@ func removeDups(arr []string) []string {
// Configuration files are parsed greedily (e.g. as soon as this function runs).
// Any error encountered while parsing nested configuration files will be
// returned.
func NewInclude(directives []string, comment string, system bool, depth uint8) (*Include, error) {
func NewInclude(directives []string, hasEquals bool, pos Position, comment string, system bool, depth uint8) (*Include, error) {
if depth > maxRecurseDepth {
return nil, ErrDepthExceeded
}
@@ -527,7 +530,10 @@ func NewInclude(directives []string, comment string, system bool, depth uint8) (
Comment: comment,
directives: directives,
files: make(map[string]*Config),
position: pos,
leadingSpace: uint16(pos.Col) - 1,
depth: depth,
hasEquals: hasEquals,
}
// no need for inc.mu.Lock() since nothing else can access this inc
matches := make([]string, 0)
@@ -582,8 +588,18 @@ func (inc *Include) Get(alias, key string) string {
return ""
}
func (i *Include) String() string {
return "TODO"
// String prints out a string representation of this Include directive. Note
// included Config files are not printed as part of this representation.
func (inc *Include) String() string {
equals := " "
if inc.hasEquals {
equals = " = "
}
line := fmt.Sprintf("%sInclude%s%s", strings.Repeat(" ", int(inc.leadingSpace)), equals, strings.Join(inc.directives, " "))
if inc.Comment != "" {
line += " #" + inc.Comment
}
return line
}
var matchAll *Pattern

View File

@@ -3,6 +3,7 @@ package ssh_config
import (
"bytes"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
@@ -253,6 +254,24 @@ func TestIncludeRecursive(t *testing.T) {
}
}
func TestIncludeString(t *testing.T) {
if testing.Short() {
t.Skip("skipping fs write in short mode")
}
data, err := ioutil.ReadFile("testdata/include")
if err != nil {
log.Fatal(err)
}
c, err := Decode(bytes.NewReader(data))
if err != nil {
t.Fatal(err)
}
s := c.String()
if s != string(data) {
t.Errorf("mismatch: got %q\nwant %q", s, string(data))
}
}
var matchTests = []struct {
in []string
alias string

View File

@@ -11,3 +11,13 @@ func ExampleHost_Matches() {
// true
// false
}
func ExamplePattern() {
pat, _ := NewPattern("*")
host := &Host{Patterns: []*Pattern{pat}}
fmt.Println(host.Matches("test.stage.example.com"))
fmt.Println(host.Matches("othersubdomain.any.any"))
// Output:
// true
// true
}

View File

@@ -131,7 +131,7 @@ func (p *sshParser) parseKV() sshParserStateFn {
}
lastHost := p.config.Hosts[len(p.config.Hosts)-1]
if strings.ToLower(key.val) == "include" {
inc, err := NewInclude(strings.Split(val.val, " "), comment, p.system, p.depth+1)
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