Skip to content

Commit

Permalink
feat: treat pairs domain/ip always as uniq. Fixes #71
Browse files Browse the repository at this point in the history
  • Loading branch information
guumaster committed Jul 13, 2021
1 parent 2c4ea86 commit 9477b29
Show file tree
Hide file tree
Showing 13 changed files with 92 additions and 57 deletions.
49 changes: 49 additions & 0 deletions cmd/hostctl/actions/add_domains_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,53 @@ func Test_AddDomains(t *testing.T) {
+----------+--------+-----------+----------------+
`, r.Hostfile())
})

t.Run("Add domains uniq", func(t *testing.T) {
r := NewRunner(t, cmd, "add_uniq")
defer r.Clean()

r.Run("hostctl add domains awesome same.domain.loc --ip 3.3.3.3").
Run("hostctl add domains awesome same.domain.loc --ip 3.3.3.3").
Containsf(`
[ℹ] Using hosts file: %s
[✔] Domains 'same.domain.loc' added.
+---------+--------+---------+-----------------+
| PROFILE | STATUS | IP | DOMAIN |
+---------+--------+---------+-----------------+
| awesome | on | 3.3.3.3 | same.domain.loc |
+---------+--------+---------+-----------------+
`, r.Hostfile())
})

t.Run("Add domains uniq per profile", func(t *testing.T) {
r := NewRunner(t, cmd, "multi_profile")
defer r.Clean()

r.Run("hostctl add domains another same.domain.loc --ip 3.3.3.3").
Run("hostctl add domains another same.domain.loc --ip 3.3.3.3").
Run("hostctl add domains awesome same.domain.loc --ip 3.3.3.3").
Run("hostctl add domains awesome same.domain.loc --ip 3.3.3.3").
Run("hostctl list another").
Containsf(`
[ℹ] Using hosts file: %s
+---------+--------+---------+-----------------+
| PROFILE | STATUS | IP | DOMAIN |
+---------+--------+---------+-----------------+
| another | on | 3.3.3.3 | same.domain.loc |
+---------+--------+---------+-----------------+
`, r.Hostfile()).
Run("hostctl list awesome").
Containsf(`
[ℹ] Using hosts file: %s
+---------+--------+---------+-----------------+
| PROFILE | STATUS | IP | DOMAIN |
+---------+--------+---------+-----------------+
| awesome | on | 3.3.3.3 | same.domain.loc |
+---------+--------+---------+-----------------+
`, r.Hostfile())
})
}
7 changes: 3 additions & 4 deletions cmd/hostctl/actions/add_replace.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ func makeAddReplace(actionFn addRemoveFn) func(cmd *cobra.Command, profiles []st
return func(cmd *cobra.Command, profiles []string) error {
src, _ := cmd.Flags().GetString("host-file")
from, _ := cmd.Flags().GetString("from")
uniq, _ := cmd.Flags().GetBool("uniq")
in := cmd.InOrStdin()

p, err := getProfileFromInput(in, from, uniq)
p, err := getProfileFromInput(in, from)
if err != nil {
return err
}
Expand All @@ -83,7 +82,7 @@ func makeAddReplace(actionFn addRemoveFn) func(cmd *cobra.Command, profiles []st
}
}

func getProfileFromInput(in io.Reader, from string, uniq bool) (*types.Profile, error) {
func getProfileFromInput(in io.Reader, from string) (*types.Profile, error) {
var (
r io.Reader
err error
Expand All @@ -104,5 +103,5 @@ func getProfileFromInput(in io.Reader, from string, uniq bool) (*types.Profile,
return nil, err
}

return parser.ParseProfile(r, uniq)
return parser.ParseProfile(r)
}
23 changes: 19 additions & 4 deletions cmd/hostctl/actions/add_replace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,26 @@ func Test_Add(t *testing.T) {
r := NewRunner(t, cmd, "add")
defer r.Clean()

tmp := r.TempHostfile("source")
defer os.Remove(tmp.Name())

t.Run("Add from file", func(t *testing.T) {
r.Runf("hostctl add awesome --uniq --from %s", tmp.Name()).
tmp := r.TempHostfile("source")
defer os.Remove(tmp.Name())
r.Runf("hostctl add awesome --from %s", tmp.Name()).
Contains(`
+---------+--------+-----------+------------+
| PROFILE | STATUS | IP | DOMAIN |
+---------+--------+-----------+------------+
| awesome | on | 127.0.0.1 | localhost |
| awesome | on | 127.0.0.1 | first.loc |
| awesome | on | 127.0.0.1 | second.loc |
+---------+--------+-----------+------------+
`)
})

t.Run("Add from file uniq", func(t *testing.T) {
tmp := r.TempHostfile("source")
defer os.Remove(tmp.Name())
r.Runf("hostctl add awesome --from %s", tmp.Name()).
Runf("hostctl add awesome --from %s", tmp.Name()).
Contains(`
+---------+--------+-----------+------------+
| PROFILE | STATUS | IP | DOMAIN |
Expand Down
2 changes: 1 addition & 1 deletion cmd/hostctl/actions/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestReadFromURL(t *testing.T) {
r, err := readerFromURL(server.URL)
assert.NoError(t, err)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)

hosts := p.GetAllHostNames()
Expand Down
2 changes: 0 additions & 2 deletions cmd/hostctl/actions/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ func registerCommands(rootCmd *cobra.Command) {
addCmd.Flags().StringP("from", "f", "", "file to read")
addCmd.PersistentFlags().
DurationP("wait", "w", -1, "Enables a profile for a specific amount of time. (example: 5m, 1h)")
addCmd.PersistentFlags().BoolP("uniq", "u", false, "only keep uniq domains per IP")

// remove
removeCmd.Flags().Bool("all", false, "Remove all profiles")
Expand All @@ -113,7 +112,6 @@ func registerCommands(rootCmd *cobra.Command) {
// replace
replaceCmd := newReplaceCmd()
replaceCmd.Flags().StringP("from", "f", "", "file to read")
replaceCmd.Flags().BoolP("uniq", "u", false, "only keep uniq domains per IP")

// toggle
toggleCmd := newToggleCmd()
Expand Down
6 changes: 3 additions & 3 deletions pkg/file/add_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestFile_AddProfile(t *testing.T) {
assert.NoError(t, err)
r := strings.NewReader(`127.0.0.1 added.loc`)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)
p.Name = "awesome"
p.Status = types.Enabled
Expand All @@ -41,7 +41,7 @@ func TestFile_AddProfile(t *testing.T) {
assert.NoError(t, err)
r := strings.NewReader(`127.0.0.1 added.loc`)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)
p.Name = "profile1"

Expand All @@ -63,7 +63,7 @@ func TestFile_AddProfile(t *testing.T) {
assert.NoError(t, err)
r := strings.NewReader(`127.0.0.1 added.loc`)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)
p.Name = "default"

Expand Down
2 changes: 1 addition & 1 deletion pkg/file/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func (f *File) AddRoutes(name string, routes []*types.Route) error {
}

// RemoveHostnames removes route information from a given types.
// also removes the profile if gets empty.
// also removes the profile if it gets empty.
func (f *File) RemoveHostnames(name string, routes []string) (bool, error) {
p, err := f.GetProfile(name)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/file/file_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ func TestManagerRoutes(t *testing.T) {
assert.NoError(t, err)

r := strings.NewReader(`3.3.3.4 some.profile.loc`)
p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)

h, _ := mem.OpenFile("/tmp/etc/hosts", os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0644)
Expand Down
6 changes: 3 additions & 3 deletions pkg/file/replace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func TestFile_ReplaceProfile(t *testing.T) {

r := strings.NewReader(`4.4.4.4 replaced.loc`)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)
p.Name = "profile1"
p.Status = types.Enabled
Expand All @@ -42,7 +42,7 @@ func TestFile_ReplaceProfile(t *testing.T) {

r := strings.NewReader(`4.4.4.4 replaced.loc`)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)
p.Name = "awesome"
p.Status = types.Enabled
Expand All @@ -63,7 +63,7 @@ func TestFile_ReplaceProfile(t *testing.T) {

r := strings.NewReader(`4.4.4.4 replaced.loc`)

p, err := parser.ParseProfile(r, true)
p, err := parser.ParseProfile(r)
assert.NoError(t, err)
p.Name = types.Default
p.Status = types.Enabled
Expand Down
8 changes: 2 additions & 6 deletions pkg/parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ func parseRouteLine(str string) (*types.Route, bool) {
}

// ParseProfile creates a new profile reading lines from a reader
func ParseProfile(r io.Reader, uniq bool) (*types.Profile, error) {
func ParseProfile(r io.Reader) (*types.Profile, error) {
p := &types.Profile{}
s := bufio.NewScanner(r)

Expand All @@ -186,11 +186,7 @@ func ParseProfile(r io.Reader, uniq bool) (*types.Profile, error) {
}
}

if uniq {
p.AddRoutesUniq(routes)
} else {
p.AddRoutes(routes)
}
p.AddRoutes(routes)

return p, nil
}
6 changes: 3 additions & 3 deletions pkg/parser/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func TestNewProfile(t *testing.T) {
3.3.3.4 some.profile.loc
3.3.3.4 first.loc
`)
p, err := ParseProfile(r, true)
p, err := ParseProfile(r)
assert.NoError(t, err)
hosts, err := p.GetHostNames("3.3.3.4")
assert.NoError(t, err)
Expand All @@ -77,11 +77,11 @@ func TestNewProfile(t *testing.T) {
3.3.3.4 first.loc
3.3.3.4 first.loc
`)
p, err := ParseProfile(r, false)
p, err := ParseProfile(r)
assert.NoError(t, err)
hosts, err := p.GetHostNames("3.3.3.4")
assert.NoError(t, err)
assert.Equal(t, []string{"some.profile.loc", "first.loc", "first.loc"}, hosts)
assert.Equal(t, []string{"some.profile.loc", "first.loc"}, hosts)
})
}

Expand Down
34 changes: 6 additions & 28 deletions pkg/types/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ func (p *Profile) AddRoute(route *Route) {
p.AddRoutes([]*Route{route})
}

// AddRouteUniq adds a single route to the profile and removes duplicates
func (p *Profile) AddRouteUniq(route *Route) {
p.AddRoutesUniq([]*Route{route})
}

// AddRoutes adds a list of routes to the profile
// AddRoutes adds non duplicated routes to a profile
func (p *Profile) AddRoutes(routes []*Route) {
if p.Routes == nil {
p.Routes = map[string]*Route{}
Expand All @@ -57,31 +52,14 @@ func (p *Profile) AddRoutes(routes []*Route) {
p.appendIP(ip)
p.Routes[ip] = &Route{
IP: net.ParseIP(ip),
HostNames: r.HostNames,
HostNames: uniqueStrings(r.HostNames),
}
} else {
p.Routes[ip].HostNames = append(p.Routes[ip].HostNames, r.HostNames...)
p.Routes[ip].HostNames = uniqueStrings(append(p.Routes[ip].HostNames, r.HostNames...))
}
}
}

// AddRoutesUniq adds non duplicated routes to a profile
func (p *Profile) AddRoutesUniq(routes []*Route) {
p.AddRoutes(routes)

done := map[string]bool{}

for _, r := range routes {
ip := r.IP.String()
if _, ok := done[ip]; ok {
continue
}

p.Routes[ip].HostNames = uniqueStrings(p.Routes[ip].HostNames)
done[ip] = true
}
}

// RemoveHostnames removes multiple hostnames of a profile
func (p *Profile) RemoveHostnames(hostnames []string) {
for _, h := range hostnames {
Expand Down Expand Up @@ -111,7 +89,7 @@ func (p *Profile) GetHostNames(ip string) ([]string, error) {

// GetAllHostNames returns all hostnames of the profile.
func (p *Profile) GetAllHostNames() []string {
list := []string{}
var list []string

if p.IPList == nil {
return list
Expand Down Expand Up @@ -153,7 +131,7 @@ func (p *Profile) Render(w io.StringWriter) error {
return err
}

// Write to input writer after knowing the profile is well formed
// Write to input writer after knowing the profile is well-formed
_, err = w.WriteString(tmp.String())

return err
Expand All @@ -176,7 +154,7 @@ func uniqueStrings(xs []string) []string {
}

func remove(s []string, n string) []string {
list := []string{}
var list []string

for _, x := range s {
if x != n {
Expand Down
2 changes: 1 addition & 1 deletion pkg/types/profile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func TestProfile(t *testing.T) {
p := Profile{}

p.AddRoute(NewRoute("1.1.1.1", "another.loc", "added.loc"))
p.AddRouteUniq(NewRoute("1.1.1.1", "added.loc", "third.loc"))
p.AddRoute(NewRoute("1.1.1.1", "added.loc", "third.loc"))

names, err := p.GetHostNames("1.1.1.1")
assert.NoError(t, err)
Expand Down

0 comments on commit 9477b29

Please sign in to comment.