diff --git a/hostess/hostlist.go b/hostess/hostlist.go index 93cfe24..5914fce 100644 --- a/hostess/hostlist.go +++ b/hostess/hostlist.go @@ -1,10 +1,13 @@ package hostess import ( + "bytes" "encoding/json" "errors" "fmt" "net" + "os" + "runtime" "sort" "strings" ) @@ -374,9 +377,9 @@ func (h *Hostlist) GetUniqueIPs() []net.IP { // 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 -func (h *Hostlist) Format() []byte { +func (h *Hostlist) FormatLinux() []byte { h.Sort() - out := []byte{} + out := bytes.Buffer{} // We want to output one line of hostnames per IP, so first we get that // list of IPs and iterate. @@ -400,19 +403,49 @@ func (h *Hostlist) Format() []byte { // Finally, if the bucket contains anything, concatenate it all // together and append it to the output. Also add a newline. if len(enabledIPs) > 0 { - concat := fmt.Sprintf("%s %s", IP.String(), strings.Join(enabledIPs, " ")) - out = append(out, []byte(concat)...) - out = append(out, []byte("\n")...) + out.WriteString(fmt.Sprintf("%s %s\n", IP.String(), strings.Join(enabledIPs, " "))) } if len(disabledIPs) > 0 { - concat := fmt.Sprintf("# %s %s", IP.String(), strings.Join(disabledIPs, " ")) - out = append(out, []byte(concat)...) - out = append(out, []byte("\n")...) + out.WriteString(fmt.Sprintf("# %s %s\n", IP.String(), strings.Join(disabledIPs, " "))) } } - return out + return out.Bytes() +} + +func (h Hostlist) FormatWindows() []byte { + h.Sort() + out := bytes.Buffer{} + + for _, hostname := range h { + out.WriteString(hostname.Format()) + out.WriteString("\n") + } + + return out.Bytes() +} + +func (h *Hostlist) Format() []byte { + format := os.Getenv(EnvHostessFmt) + if format == "" { + format = runtime.GOOS + } + + switch format { + case "windows": + return h.FormatWindows() + case "linux": + return h.FormatLinux() + default: + // Theoretically the Windows format might be more compatible but there + // are a lot of different operating systems, and they're almost all + // unix-based OSes, so we'll just assume the linux format is OK. For + // example, FreeBSD, MacOS, and Linux all use the same format and while + // I haven't checked OpenBSD or NetBSD, I am going to assume they are + // OK with this format. If not we can add a case above. + return h.FormatLinux() + } } // Dump exports all entries in the Hostlist as JSON diff --git a/hostess/hostlist_test.go b/hostess/hostlist_test.go index 48a050e..751f527 100644 --- a/hostess/hostlist_test.go +++ b/hostess/hostlist_test.go @@ -3,7 +3,9 @@ package hostess_test import ( "bytes" "fmt" + "io/ioutil" "net" + "path/filepath" "testing" "github.com/cbednarski/hostess/hostess" @@ -95,6 +97,52 @@ func TestContainsDomainIp(t *testing.T) { } } +func TestFormatLinux(t *testing.T) { + hostfile := hostess.NewHostfile() + hostfile.Path = filepath.Join("testdata", "hostfile3") + if err := hostfile.Read(); err != nil { + t.Fatal(err) + } + if errs := hostfile.Parse(); len(errs) != 0 { + t.Fatal(errs) + } + + + expected, err := ioutil.ReadFile(filepath.Join("testdata", "expected-linux")) + if err != nil { + t.Fatal(err) + } + + output := hostfile.Hosts.FormatLinux() + + if !bytes.Equal(output, expected) { + t.Errorf("---- Expected ----\n%s\n---- Found----\n%s\n", expected, output) + } +} + +func TestFormatWindows(t *testing.T) { + hostfile := hostess.NewHostfile() + hostfile.Path = filepath.Join("testdata", "hostfile3") + if err := hostfile.Read(); err != nil { + t.Fatal(err) + } + if errs := hostfile.Parse(); len(errs) != 0 { + t.Fatal(errs) + } + + expected, err := ioutil.ReadFile(filepath.Join("testdata", "expected-windows")) + if err != nil { + t.Fatal(err) + } + + output := hostfile.Hosts.FormatWindows() + + if !bytes.Equal(output, expected) { + t.Errorf("---- Expected ----\n%s\n---- Found----\n%s\n", expected, output) + } +} + + func TestFormat(t *testing.T) { hosts := hostess.NewHostlist() hosts.Add(hostess.MustHostname(domain, ip, false)) diff --git a/hostess/testdata/expected-linux b/hostess/testdata/expected-linux new file mode 100644 index 0000000..d81e74a --- /dev/null +++ b/hostess/testdata/expected-linux @@ -0,0 +1,8 @@ +127.0.0.1 localhost +127.0.1.1 robobrain +# 192.168.0.1 pie.dev.example.com +192.168.0.2 cookie.example.com +192.168.1.1 pie.example.com strawberry.pie.example.com +::1 localhost cake.example.com hostname.candy hostname.pie +fe:23b3:890e:342e::ef chocolate.pie.example.com strawberry.pie.example.com +# fe:23b3:890e:342e::ef chocolate.cake.example.com chocolate.cookie.example.com chocolate.ru.example.com chocolate.tr.example.com dev.strawberry.pie.example.com diff --git a/hostess/testdata/expected-windows b/hostess/testdata/expected-windows new file mode 100644 index 0000000..3c781a0 --- /dev/null +++ b/hostess/testdata/expected-windows @@ -0,0 +1,17 @@ +127.0.0.1 localhost +127.0.1.1 robobrain +# 192.168.0.1 pie.dev.example.com +192.168.0.2 cookie.example.com +192.168.1.1 pie.example.com +192.168.1.1 strawberry.pie.example.com +::1 localhost +::1 cake.example.com +::1 hostname.candy +::1 hostname.pie +# fe:23b3:890e:342e::ef chocolate.cake.example.com +# fe:23b3:890e:342e::ef chocolate.cookie.example.com +fe:23b3:890e:342e::ef chocolate.pie.example.com +# fe:23b3:890e:342e::ef chocolate.ru.example.com +# fe:23b3:890e:342e::ef chocolate.tr.example.com +# fe:23b3:890e:342e::ef dev.strawberry.pie.example.com +fe:23b3:890e:342e::ef strawberry.pie.example.com diff --git a/hostess/testdata/hostfile3 b/hostess/testdata/hostfile3 new file mode 100644 index 0000000..09cd958 --- /dev/null +++ b/hostess/testdata/hostfile3 @@ -0,0 +1,12 @@ +#192.168.0.1 pie.dev.example.com +192.168.0.2 cookie.example.com +::1 hostname.pie hostname.candy cake.example.com +fe:23b3:890e:342e::ef strawberry.pie.example.com +# fe:23b3:890e:342e::ef dev.strawberry.pie.example.com +127.0.1.1 robobrain +# fe:23b3:890e:342e::ef chocolate.cake.example.com chocolate.ru.example.com chocolate.tr.example.com chocolate.cookie.example.com +fe:23b3:890e:342e::ef chocolate.pie.example.com +::1 localhost +127.0.0.1 localhost +192.168.1.1 pie.example.com +192.168.1.1 strawberry.pie.example.com diff --git a/main_test.go b/main_test.go index ab9d046..a5d5045 100644 --- a/main_test.go +++ b/main_test.go @@ -4,6 +4,7 @@ import ( "io" "io/ioutil" "os" + "runtime" "strings" "testing" @@ -65,6 +66,20 @@ ff02::1 ip6-allnodes ff02::2 ip6-allrouters ` + if runtime.GOOS == "windows" { + expected = `127.0.0.1 localhost +127.0.0.1 myapp.local +127.0.1.1 ubuntu +192.168.0.30 raspberrypi +::1 ip6-localhost +::1 ip6-loopback +fe00:: ip6-localnet +ff00:: ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +` + } + if output != expected { t.Errorf("--- Expected ---\n%s\n--- Found ---\n%s\n", expected, output) } @@ -102,6 +117,22 @@ ff02::1 ip6-allnodes ff02::2 ip6-allrouters ` + if runtime.GOOS == "windows" { + expected = `127.0.0.1 localhost +127.0.0.1 my.new.website +127.0.1.1 ubuntu +10.20.0.23 myapp.local +192.168.0.30 raspberrypi +192.168.0.82 mediaserver +::1 ip6-localhost +::1 ip6-loopback +fe00:: ip6-localnet +ff00:: ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +` + } + if output != expected { t.Errorf("--- Expected ---\n%s\n--- Found ---\n%s\n", expected, output) } @@ -133,6 +164,18 @@ ff02::1 ip6-allnodes ff02::2 ip6-allrouters ` + if runtime.GOOS== "windows" { + expected = `127.0.0.1 localhost +127.0.1.1 ubuntu +::1 ip6-localhost +::1 ip6-loopback +fe00:: ip6-localnet +ff00:: ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +` + } + if output != expected { t.Errorf("--- Expected ---\n%s\n--- Found ---\n%s\n", expected, output) } @@ -166,6 +209,20 @@ ff02::1 ip6-allnodes ff02::2 ip6-allrouters ` + if runtime.GOOS == "windows" { + expected = `127.0.0.1 localhost +# 127.0.0.1 myapp.local +127.0.1.1 ubuntu +# 192.168.0.30 raspberrypi +::1 ip6-localhost +::1 ip6-loopback +fe00:: ip6-localnet +ff00:: ip6-mcastprefix +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +` + } + if output != expected { t.Errorf("--- Expected ---\n%s\n--- Found ---\n%s\n", expected, output) }