Implemented add and fix with some error handling (no saving yet)

pull/13/head
Chris Bednarski 9 years ago
parent fba8a3d5a6
commit 1e90d1336c

@ -1,9 +1,9 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"github.com/cbednarski/hostess" "github.com/cbednarski/hostess"
"github.com/codegangsta/cli"
"os" "os"
) )
@ -20,6 +20,8 @@ const help = `Hostess: an idempotent tool for managing /etc/hosts
Commands will exit 0 or 1 in a sensible way so you can use the exit code for Commands will exit 0 or 1 in a sensible way so you can use the exit code for
bash and make scripting. Add -h to any command to learn more about it. bash and make scripting. Add -h to any command to learn more about it.
To preview a hostess-managed hostsfile run ` + "`" + `hostess fix -n` + "`" + `
WARNING: This program is BETA and not all commands are implemented. WARNING: This program is BETA and not all commands are implemented.
Commands: Commands:
@ -37,7 +39,7 @@ Commands:
Options: Options:
-f Force write to the hostfile even if there are errors or conflicts -f Force write to the hostsfile even if there are errors or conflicts
-n No-op. Show changes but don't write them. -n No-op. Show changes but don't write them.
-q Supress error messages -q Supress error messages
-s Supress success messages (implies -q) -s Supress success messages (implies -q)
@ -50,56 +52,77 @@ Report bugs at https://github.com/cbednarski/hostess
` `
func main() { func main() {
hostfile := hostess.NewHostfile(hostess.GetHostsPath()) app := cli.NewApp()
hostfile.Load() app.Name = "hostess"
hostfile.Parse() app.Usage = help
app.Version = "0.1.0"
flags := make(map[string]*bool)
flags["force"] = flag.Bool("f", false, "Forcibly apply changes, even if there are errors or conflicts") var err error = nil
flags["noop"] = flag.Bool("n", false, "No-op. Show changes but don't write them.")
flags["quiet"] = flag.Bool("q", false, "Suppress error and conflict messages.")
flags["silent"] = flag.Bool("s", false, "Suppress all output. Check exit codes for success / failure.")
flags["help"] = flag.Bool("h", false, "Help")
flag.Parse()
// Guard against zero arguments app.Flags = []cli.Flag{
var args []string cli.BoolFlag{
if len(flag.Args()) > 0 { Name: "f",
args = flag.Args()[1:] Usage: "Force",
},
cli.BoolFlag{
Name: "n",
Usage: "Noop",
},
cli.BoolFlag{
Name: "q",
Usage: "Quiet",
},
cli.BoolFlag{
Name: "s",
Usage: "Silent",
},
} }
var err error = nil app.Commands = []cli.Command{
{
switch flag.Arg(0) { Name: "add",
case "add": // Usage: "add a task to the list",
err = hostess.Add(args, flags) Action: hostess.Add,
case "del": Flags: app.Flags,
err = hostess.Del(args, flags) },
case "has": {
err = hostess.Has(args, flags) Name: "fix",
case "off": // Usage: "add a task to the list",
err = hostess.Fix(args, flags) Action: hostess.Fix,
case "on": Flags: app.Flags,
err = hostess.Fix(args, flags) },
case "ls":
err = hostess.Fix(args, flags)
case "fix":
err = hostess.Fix(args, flags)
case "dump":
err = hostess.Fix(args, flags)
case "apply":
err = hostess.Fix(args, flags)
default:
fmt.Print(help)
} }
// switch flag.Arg(0) {
// case "add":
// err = hostess.Add(args, flags)
// case "del":
// err = hostess.Del(args, flags)
// case "has":
// err = hostess.Has(args, flags)
// case "off":
// err = hostess.Off(args, flags)
// case "on":
// err = hostess.On(args, flags)
// case "ls":
// err = hostess.Ls(args, flags)
// case "fix":
// err = hostess.Fix(args, flags)
// case "dump":
// err = hostess.Dump(args, flags)
// case "apply":
// err = hostess.Apply(args, flags)
// default:
// fmt.Print(help)
// }
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(1) os.Exit(1)
} }
app.Run(os.Args)
os.Exit(0) os.Exit(0)
} }

@ -1,44 +1,112 @@
package hostess package hostess
import ( import (
"errors" // "errors"
"fmt"
"github.com/codegangsta/cli"
"os"
) )
func Add(args []string, flags map[string]*bool) error { func MaybeErrorln(c *cli.Context, message string) {
if len(args) > 2 { if !c.Bool("q") {
return errors.New("Unexpected arguments") fmt.Printf("%s: %s\n", c.Command.Name, message)
} }
return nil
} }
func Del(args []string, flags map[string]*bool) error { func MaybeError(c *cli.Context, message string) {
return nil if !c.Bool("q") {
fmt.Printf("%s: %s\n", c.Command.Name, message)
}
os.Exit(1)
}
func MaybePrintln(c *cli.Context, message string) {
if !c.Bool("s") {
fmt.Println(message)
}
}
func MaybeLoadHostFile(c *cli.Context) *Hostfile {
hostsfile, errs := LoadHostFile()
if len(errs) > 0 && !c.Bool("f") {
for _, err := range errs {
MaybeErrorln(c, err.Error())
}
MaybeError(c, "Errors while parsing hostsfile")
}
return hostsfile
}
func SprintEnabled(on bool) string {
if on {
return "(On)"
} else {
return "(Off)"
}
} }
func Has(args []string, flags map[string]*bool) error { func Add(c *cli.Context) {
if len(c.Args()) != 2 {
MaybeError(c, "expected <hostname> <ip>")
}
hostsfile := MaybeLoadHostFile(c)
hostname := Hostname{c.Args()[0], c.Args()[1], true}
err := hostsfile.Add(hostname)
if err == nil {
if c.Bool("n") {
fmt.Println(hostsfile.Format())
} else {
MaybePrintln(c, fmt.Sprintf("Added %s -> %s %s", hostname.Domain, hostname.Ip, SprintEnabled(hostname.Enabled)))
hostsfile.Save()
}
} else {
MaybeError(c, err.Error())
}
}
func Del(c *cli.Context) error {
return nil return nil
} }
func Off(args []string, flags map[string]*bool) error { func Has(c *cli.Context) error {
return nil return nil
} }
func On(args []string, flags map[string]*bool) error { func Off(c *cli.Context) error {
return nil return nil
} }
func Ls(args []string, flags map[string]*bool) error { func On(c *cli.Context) error {
return nil return nil
} }
func Fix(args []string, flags map[string]*bool) error { func Ls(c *cli.Context) error {
return nil return nil
} }
func Dump(args []string, flags map[string]*bool) error { const fix_help = `Programmatically rewrite your hostsfile.
Domains pointing to the same IP will be consolidated, sorted, and extra
whitespace and comments will be removed.
hostess fix Rewrite the hostsfile
hostess fix -n Show the new hostsfile. Don't write it
`
func Fix(c *cli.Context) {
hostfile := MaybeLoadHostFile(c)
if c.Bool("n") {
fmt.Println(hostfile.Format())
} else {
hostfile.Save()
}
}
func Dump(c *cli.Context) error {
return nil return nil
} }
func Apply(args []string, flags map[string]*bool) error { func Apply(c *cli.Context) error {
return nil return nil
} }

@ -150,6 +150,13 @@ func NewHostfile(path string) *Hostfile {
return &Hostfile{path, make(map[string]*Hostname), ""} return &Hostfile{path, make(map[string]*Hostname), ""}
} }
func LoadHostFile() (*Hostfile, []error) {
hostfile := NewHostfile(GetHostsPath())
hostfile.Load()
errs := hostfile.Parse()
return hostfile, errs
}
func (h *Hostfile) Load() string { func (h *Hostfile) Load() string {
data, err := ioutil.ReadFile(h.Path) data, err := ioutil.ReadFile(h.Path)
if err != nil { if err != nil {
@ -160,12 +167,17 @@ func (h *Hostfile) Load() string {
return h.data return h.data
} }
func (h *Hostfile) Parse() { func (h *Hostfile) Parse() []error {
var errs []error
for _, v := range strings.Split(h.data, "\n") { for _, v := range strings.Split(h.data, "\n") {
for _, hostname := range parseLine(v) { for _, hostname := range parseLine(v) {
h.Add(hostname) err := h.Add(hostname)
if err != nil {
errs = append(errs, err)
}
} }
} }
return errs
} }
func getSortedMapKeys(m map[string][]string) []string { func getSortedMapKeys(m map[string][]string) []string {

Loading…
Cancel
Save