More docs, fixed naming inconsistencies, moved formatting to Hostname methods

pull/13/head
Chris Bednarski 9 years ago
parent ebc96283b0
commit 3639cfd93b

@ -40,19 +40,6 @@ func MaybeLoadHostFile(c *cli.Context) *Hostfile {
return hostsfile
}
// ShowEnabled turns a boolean into a string (On) or (Off)
func ShowEnabled(on bool) string {
if on {
return "(On)"
}
return "(Off)"
}
// ShowHostname turns a Hostname into a string for display
func ShowHostname(hostname Hostname) string {
return fmt.Sprintf("%s -> %s %s", hostname.Domain, hostname.Ip, ShowEnabled(hostname.Enabled))
}
// StrPadRight adds spaces to the right of a string until it reaches l length.
// If the input string is already that long, do nothing.
func StrPadRight(s string, l int) string {
@ -78,7 +65,7 @@ func Add(c *cli.Context) {
if c.Bool("n") {
fmt.Println(hostsfile.Format())
} else {
MaybePrintln(c, fmt.Sprintf("Added %s", ShowHostname(*hostname)))
MaybePrintln(c, fmt.Sprintf("Added %s", hostname.FormatHuman()))
hostsfile.Save()
}
} else {
@ -150,7 +137,7 @@ func Ls(c *cli.Context) {
if dlen > maxdomain {
maxdomain = dlen
}
ilen := len(hostname.Ip)
ilen := len(hostname.IP)
if ilen > maxip {
maxip = ilen
}

@ -11,11 +11,11 @@ import (
// passed a value not 4 or 6.
var ErrInvalidVersionArg = errors.New("Version argument must be 4 or 6")
// Hostlist is a collection of Hostnames. When in a Hostlist, hostnames must
// Hostlist is a collection of Hostnames. When in a Hostlist, Hostnames must
// follow some rules:
// - Hostlist may contain IPv4 AND IPv6 (collectively, "IP version") hostnames.
// - Hostlist may contain IPv4 AND IPv6 (collectively, "IP version") Hostnames.
// - Names are only allowed to overlap if IP version is different.
// - Adding a hostname for an existing name will replace the old one.
// - Adding a Hostname for an existing name will replace the old one.
// See docs for the Sort and Add for more details.
type Hostlist []*Hostname
@ -24,12 +24,12 @@ func NewHostlist() *Hostlist {
return &Hostlist{}
}
// Len returns the number of hostnames in the list, part of sort.Interface
// Len returns the number of Hostnames in the list, part of sort.Interface
func (h Hostlist) Len() int {
return len(h)
}
// Less determines the sort order of two hostnames, part of sort.Interface
// Less determines the sort order of two Hostnames, part of sort.Interface
func (h Hostlist) Less(i, j int) bool {
// Sort 127.0.0.1, 127.0.1.1 and "localhost" at the top
if h[i].Domain == "localhost" {
@ -40,18 +40,18 @@ func (h Hostlist) Less(i, j int) bool {
}
// Sort IPv4 before IPv6
if h[i].Ipv6 && !h[j].Ipv6 {
if h[i].IPv6 && !h[j].IPv6 {
return false
}
if !h[i].Ipv6 && h[j].Ipv6 {
if !h[i].IPv6 && h[j].IPv6 {
return true
}
// Compare the the IP addresses (byte array)
for c := range h[i].Ip {
if h[i].Ip[c] < h[j].Ip[c] {
for c := range h[i].IP {
if h[i].IP[c] < h[j].IP[c] {
return true
} else if h[i].Ip[c] > h[j].Ip[c] {
} else if h[i].IP[c] > h[j].IP[c] {
return false
}
}
@ -88,7 +88,7 @@ func (h Hostlist) Less(i, j int) bool {
return false
}
// Swap changes the position of two hostnames, part of sort.Interface
// Swap changes the position of two Hostnames, part of sort.Interface
func (h Hostlist) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}
@ -125,7 +125,7 @@ func (h *Hostlist) ContainsDomain(domain string) bool {
// ContainsIP returns true if a Hostname in this Hostlist matches IP
func (h *Hostlist) ContainsIP(IP net.IP) bool {
for _, hostname := range *h {
if hostname.EqualIp(IP) {
if hostname.EqualIP(IP) {
return true
}
}
@ -142,10 +142,10 @@ func (h *Hostlist) Add(host *Hostname) error {
for _, found := range *h {
if found.Equal(host) {
return fmt.Errorf("Duplicate hostname entry for %s -> %s",
host.Domain, host.Ip)
} else if found.Domain == host.Domain && found.Ipv6 == host.Ipv6 {
host.Domain, host.IP)
} else if found.Domain == host.Domain && found.IPv6 == host.IPv6 {
return fmt.Errorf("Conflicting hostname entries for %s -> %s and -> %s",
host.Domain, host.Ip, found.Ip)
host.Domain, host.IP, found.IP)
}
}
*h = append(*h, host)
@ -171,7 +171,7 @@ func (h *Hostlist) IndexOfDomainV(domain string, version int) int {
panic(ErrInvalidVersionArg)
}
for index, hostname := range *h {
if hostname.Domain == domain && hostname.Ipv6 == (version == 6) {
if hostname.Domain == domain && hostname.IPv6 == (version == 6) {
return index
}
}
@ -186,7 +186,7 @@ func (h *Hostlist) Remove(index int) {
}
}
// RemoveDomain removes both Ipv4 and Ipv6 Hostname entries matching domain.
// RemoveDomain removes both IPv4 and IPv6 Hostname entries matching domain.
func (h *Hostlist) RemoveDomain(domain string) {
h.Remove(h.IndexOfDomainV(domain, 4))
h.Remove(h.IndexOfDomainV(domain, 6))
@ -217,7 +217,7 @@ func (h *Hostlist) EnableV(domain string, version int) {
panic(ErrInvalidVersionArg)
}
for _, hostname := range *h {
if hostname.Domain == domain && hostname.Ipv6 == (version == 6) {
if hostname.Domain == domain && hostname.IPv6 == (version == 6) {
hostname.Enabled = true
}
}
@ -239,7 +239,7 @@ func (h *Hostlist) DisableV(domain string, version int) {
panic(ErrInvalidVersionArg)
}
for _, hostname := range *h {
if hostname.Domain == domain && hostname.Ipv6 == (version == 6) {
if hostname.Domain == domain && hostname.IPv6 == (version == 6) {
hostname.Enabled = false
}
}
@ -249,9 +249,9 @@ func (h *Hostlist) DisableV(domain string, version int) {
// into a string suitable for use as an /etc/hosts file.
// Sorting uses the following logic:
// 1. List is sorted by IP address
// 2. Commented items are left in place
// 2. Commented items are sorted displayed
// 3. 127.* appears at the top of the list (so boot resolvers don't break)
// 4. When present, localhost will always appear first in the domain list
// 4. When present, "localhost" will always appear first in the domain list
func (h *Hostlist) Format() string {
h.Sort()
out := ""

@ -7,56 +7,84 @@ import (
"strings"
)
var ipv4_pattern = regexp.MustCompile(`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`)
var ipv6_pattern = regexp.MustCompile(`^[a-z0-9:]+$`)
var ipv4Pattern = regexp.MustCompile(`^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$`)
var ipv6Pattern = regexp.MustCompile(`^[a-z0-9:]+$`)
func LooksLikeIpv4(ip string) bool {
return ipv4_pattern.MatchString(ip)
// LooksLikeIPv4 returns true if the IP looks like it's IPv4. This does not
// validate whether the string is a valid IP address.
func LooksLikeIPv4(ip string) bool {
return ipv4Pattern.MatchString(ip)
}
func LooksLikeIpv6(ip string) bool {
// LooksLikeIPv6 returns true if the IP looks like it's IPv6. This does not
// validate whether the string is a valid IP address.
func LooksLikeIPv6(ip string) bool {
if !strings.Contains(ip, ":") {
return false
}
return ipv6_pattern.MatchString(ip)
return ipv6Pattern.MatchString(ip)
}
// Hostname represents a hosts file entry, including a Domain, IP, whether the
// Hostname is enabled (uncommented in the hosts file), and whether the IP is
// in the IPv6 format. You should always create these with NewHostname(). Note:
// when using Hostnames in the context of a Hostlist, you should not change the
// Hostname fields except through the Hostlist's aggregate methods. Doing so
// can cause unexpected behavior. Instead, use Hostlist's Add, Remove, Enable,
// and Disable methods.
type Hostname struct {
Domain string
Ip net.IP
IP net.IP
Enabled bool
Ipv6 bool
IPv6 bool
}
// NewHostname creates a new Hostname struct and automatically sets the IPv6
// field based on the IP you pass in.
func NewHostname(domain, ip string, enabled bool) (hostname *Hostname) {
IP := net.ParseIP(ip)
hostname = &Hostname{domain, IP, enabled, LooksLikeIpv6(ip)}
hostname = &Hostname{domain, IP, enabled, LooksLikeIPv6(ip)}
return
}
// Equal compares two Hostnames. Note that only the Domain and IP fields are
// compared because Enabled is transient state, and IPv6 should be set
// automatically based on IP.
func (h *Hostname) Equal(n *Hostname) bool {
return h.Ip.Equal(n.Ip) && h.Domain == n.Domain
return h.Domain == n.Domain && h.IP.Equal(n.IP)
}
func (h *Hostname) EqualIp(ip net.IP) bool {
return h.Ip.Equal(ip)
// EqualIP compares an IP against this Hostname.
func (h *Hostname) EqualIP(ip net.IP) bool {
return h.IP.Equal(ip)
}
// IsValid does a spot-check on the domain and IP to make sure they aren't blank
func (h *Hostname) IsValid() bool {
return h.Domain != "" && h.Ip != nil
return h.Domain != "" && h.IP != nil
}
// Format outputs the Hostname as you'd see it in a hosts file, with a comment
// if it is disabled. E.g.
// # 127.0.0.1 blah.example.com
func (h *Hostname) Format() string {
r := fmt.Sprintf("%s %s", h.Ip.String(), h.Domain)
r := fmt.Sprintf("%s %s", h.IP.String(), h.Domain)
if !h.Enabled {
r = "# " + r
}
return r
}
func (a *Hostname) Equals(b Hostname) bool {
if a.Domain == b.Domain && a.Ip.Equal(b.Ip) {
return true
// FormatEnabled displays Hostname.Enabled as (On) or (Off)
func (h *Hostname) FormatEnabled() string {
if h.Enabled {
return "(On)"
}
return false
return "(Off)"
}
// Format outputs the Hostname in a more human-readable format:
// blah.example.com -> 127.0.0.1 (Off)
func (h *Hostname) FormatHuman() string {
return fmt.Sprintf("%s -> %s %s", h.Domain, h.IP, h.FormatEnabled())
}

Loading…
Cancel
Save