From 094a3b56faca84a16c097e3dc5a4bca998386594 Mon Sep 17 00:00:00 2001 From: Doron Cohen Date: Mon, 9 Nov 2020 08:51:47 +0200 Subject: [PATCH 1/5] fix: add proper error when missing rules file --- cmd/clean.go | 5 +++++ internal/rules/config.go | 10 ++++++++++ 2 files changed, 15 insertions(+) diff --git a/cmd/clean.go b/cmd/clean.go index 99ac2cf..670d736 100644 --- a/cmd/clean.go +++ b/cmd/clean.go @@ -2,6 +2,7 @@ package cmd import ( "log" + "os" "github.com/spf13/cobra" @@ -23,6 +24,10 @@ var cleanCmd = &cobra.Command{ _, err := rules.LoadRulesConfig(rulesFilePath) if err != nil { + if _, rulesMissing := err.(*rules.MissingRulesFile); rulesMissing { + log.Println("Couldn't find rules file. Please run `antidot update`.") + os.Exit(2) + } log.Fatalln("Failed to read rules file: ", err) } diff --git a/internal/rules/config.go b/internal/rules/config.go index 227d269..75409a0 100644 --- a/internal/rules/config.go +++ b/internal/rules/config.go @@ -3,11 +3,18 @@ package rules import ( "io/ioutil" "log" + "os" "github.com/mitchellh/mapstructure" "gopkg.in/yaml.v2" ) +type MissingRulesFile struct{} + +func (e *MissingRulesFile) Error() string { + return "Rules file is missing" +} + type RulesConfig struct { Version int Rules []Rule @@ -19,6 +26,9 @@ func LoadRulesConfig(filepath string) (RulesConfig, error) { log.Printf("Loading rules config file %s", filepath) rulesBytes, err := ioutil.ReadFile(filepath) if err != nil { + if os.IsNotExist(err) { + return RulesConfig{}, &MissingRulesFile{} + } return RulesConfig{}, err } From cdf5c281d7f6f04e3ad096ab0a3c067e98b9c188 Mon Sep 17 00:00:00 2001 From: Doron Cohen Date: Mon, 9 Nov 2020 09:37:47 +0200 Subject: [PATCH 2/5] fix: ensure data home exists before rules update --- internal/utils/fetch.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/internal/utils/fetch.go b/internal/utils/fetch.go index c6b3a5e..24e9749 100644 --- a/internal/utils/fetch.go +++ b/internal/utils/fetch.go @@ -1,11 +1,14 @@ package utils import ( + "errors" + "fmt" "io" "io/ioutil" "log" "net/http" "os" + "path" ) func Download(src, dest string) error { @@ -27,6 +30,17 @@ func Download(src, dest string) error { return err } + dir := path.Dir(dest) + fileInfo, err := os.Stat(dir) + if os.IsNotExist(err) { + if err = os.MkdirAll(dir, os.FileMode(0o755)); err != nil { + return err + } + } else if !fileInfo.IsDir() { + text := fmt.Sprintf("Rules file destination directory is a file: %s", dir) + return errors.New(text) + } + err = MoveFile(tempFile.Name(), dest) if err != nil { return err From ed69d382a04cfd0e76417ecb7bd2a2b2168b2579 Mon Sep 17 00:00:00 2001 From: Doron Cohen Date: Mon, 9 Nov 2020 09:49:48 +0200 Subject: [PATCH 3/5] refactor: change to a nicer prompt (#23) --- cmd/clean.go | 6 +----- go.mod | 1 + go.sum | 20 ++++++++++++++++++++ internal/tui/prompt.go | 22 +++++++--------------- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/cmd/clean.go b/cmd/clean.go index 670d736..890a5ea 100644 --- a/cmd/clean.go +++ b/cmd/clean.go @@ -54,11 +54,7 @@ var cleanCmd = &cobra.Command{ foundRules = append(foundRules, rule) } - confirmed, err := tui.Confirm("Apply rules?") - if err != nil { - log.Fatalf("Failed to read input from stdin: %v", err) - } - + confirmed := tui.Confirm("Apply rules?") if !confirmed { log.Println("User cancelled. No action was preformed") return diff --git a/go.mod b/go.mod index 4770e0f..91ed293 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/doron-cohen/antidot go 1.14 require ( + github.com/AlecAivazis/survey/v2 v2.2.2 github.com/adrg/xdg v0.2.2 github.com/google/go-cmp v0.5.2 github.com/mitchellh/mapstructure v1.3.3 diff --git a/go.sum b/go.sum index ec24b8c..4bfbdf0 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,12 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/AlecAivazis/survey v1.8.8 h1:Y4yypp763E8cbqb5RBqZhGgkCFLRFnbRBHrxnpMMsgQ= +github.com/AlecAivazis/survey/v2 v2.2.2 h1:1I4qBrNsHQE+91tQCqVlfrKe9DEL65949d1oKZWVELY= +github.com/AlecAivazis/survey/v2 v2.2.2/go.mod h1:9FJRdMdDm8rnT+zHVbvQT2RTSTLq0Ttd6q3Vl2fahjk= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/adrg/xdg v0.2.2 h1:A7ZHKRz5KGOLJX/bg7IPzStryhvCzAE1wX+KWawPiAo= github.com/adrg/xdg v0.2.2/go.mod h1:7I2hH/IT30IsupOpKZ5ue7/qNi3CoKzD6tL3HwpaRMQ= @@ -94,6 +98,7 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ= github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= +github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= @@ -101,6 +106,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -108,12 +115,19 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/pty v1.1.4/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= @@ -168,6 +182,7 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -190,6 +205,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190530122614-20be4c3c3ed5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -238,16 +255,19 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190530182044-ad28b68e88f1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200107162124-548cf772de50 h1:YvQ10rzcqWXLlJZ3XCUoO25savxmscf4+SC+ZqiCHhA= golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/internal/tui/prompt.go b/internal/tui/prompt.go index 5e1bced..e08a0aa 100644 --- a/internal/tui/prompt.go +++ b/internal/tui/prompt.go @@ -1,20 +1,12 @@ package tui -import ( - "bufio" - "fmt" - "os" - "strings" -) +import "github.com/AlecAivazis/survey/v2" -func Confirm(text string) (bool, error) { - reader := bufio.NewReader(os.Stdin) - fmt.Printf("%s - enter 'yes' to proceed: ", text) - answer, err := reader.ReadString('\n') - if err != nil { - return false, err +func Confirm(text string) bool { + var answer bool + prompt := &survey.Confirm{ + Message: text, } - - sanitized := strings.TrimSpace(strings.ToLower(answer)) - return sanitized == "yes", nil + survey.AskOne(prompt, &answer) + return answer } From aa488a8c01386f28695d59ec86b5cff16eda46fc Mon Sep 17 00:00:00 2001 From: Doron Cohen Date: Mon, 9 Nov 2020 09:53:51 +0200 Subject: [PATCH 4/5] refactor: change to prompt per action (#22) --- cmd/clean.go | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/cmd/clean.go b/cmd/clean.go index 890a5ea..29b4b65 100644 --- a/cmd/clean.go +++ b/cmd/clean.go @@ -1,6 +1,7 @@ package cmd import ( + "fmt" "log" "os" @@ -43,7 +44,6 @@ var cleanCmd = &cobra.Command{ log.Printf("Found %d dotfiles in %s\n", len(dotfiles), userHomeDir) - foundRules := make([]*rules.Rule, 0) for _, dotfile := range dotfiles { rule := rules.MatchRule(&dotfile) if rule == nil { @@ -51,17 +51,12 @@ var cleanCmd = &cobra.Command{ } rule.Pprint() - foundRules = append(foundRules, rule) - } - - confirmed := tui.Confirm("Apply rules?") - if !confirmed { - log.Println("User cancelled. No action was preformed") - return - } + confirmed := tui.Confirm(fmt.Sprintf("Apply rule %s?", rule.Name)) + if !confirmed { + log.Println("Not applying rule") + continue + } - log.Println("Applying rules") - for _, rule := range foundRules { rule.Apply() } }, From 74792b4f305509772e4f87267305ee9be2ce39f4 Mon Sep 17 00:00:00 2001 From: Doron Cohen Date: Mon, 9 Nov 2020 21:15:39 +0200 Subject: [PATCH 5/5] feat: add verbose flag (#23) --- cmd/clean.go | 24 +++++++++--------------- cmd/init.go | 14 ++++---------- cmd/root.go | 2 ++ cmd/update.go | 11 ++++------- internal/rules/alias.go | 7 +++---- internal/rules/config.go | 6 +++--- internal/rules/delete.go | 3 +-- internal/rules/export.go | 7 +++---- internal/rules/migrate.go | 5 ++--- internal/rules/rule.go | 10 ++++------ internal/tui/log.go | 29 +++++++++++++++++++++++++++++ internal/utils/fetch.go | 7 +++---- 12 files changed, 67 insertions(+), 58 deletions(-) create mode 100644 internal/tui/log.go diff --git a/cmd/clean.go b/cmd/clean.go index 29b4b65..6afa451 100644 --- a/cmd/clean.go +++ b/cmd/clean.go @@ -2,7 +2,6 @@ package cmd import ( "fmt" - "log" "os" "github.com/spf13/cobra" @@ -21,28 +20,24 @@ var cleanCmd = &cobra.Command{ Use: "clean", Short: "Clean up dotfiles from your $HOME", Run: func(cmd *cobra.Command, args []string) { - log.Println("Cleaning up!") + tui.Debug("Cleaning up!") _, err := rules.LoadRulesConfig(rulesFilePath) if err != nil { if _, rulesMissing := err.(*rules.MissingRulesFile); rulesMissing { - log.Println("Couldn't find rules file. Please run `antidot update`.") + tui.Print("Couldn't find rules file. Please run `antidot update`.") os.Exit(2) } - log.Fatalln("Failed to read rules file: ", err) + tui.FatalIfError("Failed to read rules file", err) } userHomeDir, err := utils.GetHomeDir() - if err != nil { - log.Fatalln("Unable to detect user home dir: ", err) - } + tui.FatalIfError("Unable to detect user home dir", err) dotfiles, err := dotfile.Detect(userHomeDir) - if err != nil { - log.Fatalln("Failed to detect dotfiles in home dir: ", err) - } + tui.FatalIfError("Failed to detect dotfiles in home dir", err) - log.Printf("Found %d dotfiles in %s\n", len(dotfiles), userHomeDir) + tui.Debug("Found %d dotfiles in %s", len(dotfiles), userHomeDir) for _, dotfile := range dotfiles { rule := rules.MatchRule(&dotfile) @@ -52,12 +47,11 @@ var cleanCmd = &cobra.Command{ rule.Pprint() confirmed := tui.Confirm(fmt.Sprintf("Apply rule %s?", rule.Name)) - if !confirmed { - log.Println("Not applying rule") - continue + if confirmed { + rule.Apply() } - rule.Apply() + tui.Print("") // one line space } }, } diff --git a/cmd/init.go b/cmd/init.go index 444ebe0..a3a2adb 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -1,11 +1,9 @@ package cmd import ( - "fmt" - "log" - "github.com/spf13/cobra" + "github.com/doron-cohen/antidot/internal/tui" "github.com/doron-cohen/antidot/internal/utils" ) @@ -19,16 +17,12 @@ var initCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { // TODO: detect shell and generate appropriate script envFilePath, err := utils.GetEnvFile() - if err != nil { - log.Fatalf("Failed to get env file path: %v", err) - } + tui.FatalIfError("Failed to get env file path", err) aliasFilePath, err := utils.GetAliasFile() - if err != nil { - log.Fatalf("Failed to get alias file path: %v", err) - } + tui.FatalIfError("Failed to get alias file path", err) - fmt.Printf(`if [[ "$ANTIDOT_INIT" != "1" ]]; then + tui.Print(`if [[ "$ANTIDOT_INIT" != "1" ]]; then %s source %s source %s diff --git a/cmd/root.go b/cmd/root.go index 0494f51..b379dcc 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -6,6 +6,7 @@ import ( "github.com/spf13/cobra" + "github.com/doron-cohen/antidot/internal/tui" "github.com/doron-cohen/antidot/internal/utils" ) @@ -19,6 +20,7 @@ var rootCmd = &cobra.Command{ } func init() { + rootCmd.PersistentFlags().BoolVarP(&tui.Verbose, "verbose", "v", false, "Output verbosity") rootCmd.PersistentFlags().StringVarP(&rulesFilePath, "rules", "r", utils.GetRulesFilePath(), "Rules file path") } diff --git a/cmd/update.go b/cmd/update.go index 81f89fb..8180795 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -1,8 +1,7 @@ package cmd import ( - "log" - + "github.com/doron-cohen/antidot/internal/tui" "github.com/doron-cohen/antidot/internal/utils" "github.com/spf13/cobra" ) @@ -17,12 +16,10 @@ var updateCmd = &cobra.Command{ Use: "update", Short: "Update rules file", Run: func(cmd *cobra.Command, args []string) { - log.Printf("Updating rules...") + tui.Debug("Updating rules...") err := utils.Download(rulesSource, rulesFilePath) - if err != nil { - log.Fatalf("Failed to update rules: %v", err) - } + tui.FatalIfError("Failed to update rules", err) - log.Printf("Rules updated") + tui.Print("Rules updated successfully") }, } diff --git a/internal/rules/alias.go b/internal/rules/alias.go index 2606b7b..0de9818 100644 --- a/internal/rules/alias.go +++ b/internal/rules/alias.go @@ -3,7 +3,6 @@ package rules import ( "errors" "fmt" - "log" "os" "github.com/doron-cohen/antidot/internal/tui" @@ -35,7 +34,7 @@ func (a Alias) Apply() error { existingAlias, isAliasContained := aliasMap[a.Alias] if isAliasContained { - log.Printf("Alias %s already exists in alias file %s", a.Alias, aliasMap) + tui.Debug("Alias %s already exists in alias file %s", a.Alias, aliasMap) if existingAlias != a.Command { errMessage := fmt.Sprintf( "Current command for alias '%s' (%s) is different than the requested (%s)", @@ -49,7 +48,7 @@ func (a Alias) Apply() error { aliasMap[a.Alias] = a.Command } - log.Printf("Writing to %s", aliasFilePath) + tui.Debug("Writing to %s", aliasFilePath) if err = utils.WriteKeyValuesToFile(aliasMap, aliasFilePath); err != nil { return err } @@ -58,7 +57,7 @@ func (a Alias) Apply() error { } func (a Alias) Pprint() { - log.Printf( + tui.Print( " %s %s%s\"%s\"", tui.ApplyStyle(tui.Magenta, "ALIAS"), a.Alias, diff --git a/internal/rules/config.go b/internal/rules/config.go index 75409a0..4d4ceb5 100644 --- a/internal/rules/config.go +++ b/internal/rules/config.go @@ -2,9 +2,9 @@ package rules import ( "io/ioutil" - "log" "os" + "github.com/doron-cohen/antidot/internal/tui" "github.com/mitchellh/mapstructure" "gopkg.in/yaml.v2" ) @@ -23,7 +23,7 @@ type RulesConfig struct { var rulesConfig RulesConfig func LoadRulesConfig(filepath string) (RulesConfig, error) { - log.Printf("Loading rules config file %s", filepath) + tui.Debug("Loading rules config file %s", filepath) rulesBytes, err := ioutil.ReadFile(filepath) if err != nil { if os.IsNotExist(err) { @@ -55,6 +55,6 @@ func LoadRulesConfig(filepath string) (RulesConfig, error) { return RulesConfig{}, err } - log.Printf("Loaded %d rules", len(rulesConfig.Rules)) + tui.Debug("Loaded %d rules", len(rulesConfig.Rules)) return rulesConfig, nil } diff --git a/internal/rules/delete.go b/internal/rules/delete.go index 830130a..24a042a 100644 --- a/internal/rules/delete.go +++ b/internal/rules/delete.go @@ -1,7 +1,6 @@ package rules import ( - "log" "os" "github.com/doron-cohen/antidot/internal/tui" @@ -27,7 +26,7 @@ func (d Delete) Apply() error { } func (d Delete) Pprint() { - log.Printf(" %s %s", tui.ApplyStyle(tui.Red, "DELETE"), utils.ExpandEnv(d.Path)) + tui.Print(" %s %s", tui.ApplyStyle(tui.Red, "DELETE"), utils.ExpandEnv(d.Path)) } func init() { diff --git a/internal/rules/export.go b/internal/rules/export.go index f841978..bc6ab3c 100644 --- a/internal/rules/export.go +++ b/internal/rules/export.go @@ -3,7 +3,6 @@ package rules import ( "errors" "fmt" - "log" "os" "github.com/doron-cohen/antidot/internal/tui" @@ -34,7 +33,7 @@ func (e Export) Apply() error { existingValue, isKeyContained := envMap[e.Key] if isKeyContained { - log.Printf("Key %s already exists in env file %s", e.Key, envFile) + tui.Debug("Key %s already exists in env file %s", e.Key, envFile) if existingValue != e.Value { errMessage := fmt.Sprintf( "Current value for key '%s' (%s) is different than the requested (%s)", @@ -48,7 +47,7 @@ func (e Export) Apply() error { envMap[e.Key] = e.Value } - log.Printf("Writing to %s", envFile) + tui.Debug("Writing to %s", envFile) if err = utils.WriteKeyValuesToFile(envMap, envFile); err != nil { return err } @@ -57,7 +56,7 @@ func (e Export) Apply() error { } func (e Export) Pprint() { - log.Printf( + tui.Print( " %s %s%s\"%s\"", tui.ApplyStyle(tui.Blue, "EXPORT"), e.Key, diff --git a/internal/rules/migrate.go b/internal/rules/migrate.go index 53cd460..41c7706 100644 --- a/internal/rules/migrate.go +++ b/internal/rules/migrate.go @@ -3,7 +3,6 @@ package rules import ( "errors" "fmt" - "log" "os" "path/filepath" @@ -21,7 +20,7 @@ func (m Migrate) Apply() error { source := utils.ExpandEnv(m.Source) _, err := os.Stat(source) if os.IsNotExist(err) { - log.Printf("File %s doesn't exist. Skipping action", source) + tui.Print("File %s doesn't exist. Skipping action", source) return nil } else if err != nil { return err @@ -60,7 +59,7 @@ func (m Migrate) Pprint() { } // TODO: move the indentation logic elsewhere - log.Printf( + tui.Print( " %s %s %s %s%s", tui.ApplyStyle(tui.Green, "MOVE "), utils.ExpandEnv(m.Source), diff --git a/internal/rules/rule.go b/internal/rules/rule.go index 8bdb087..22a4701 100644 --- a/internal/rules/rule.go +++ b/internal/rules/rule.go @@ -1,8 +1,6 @@ package rules import ( - "log" - "github.com/google/go-cmp/cmp" "github.com/doron-cohen/antidot/internal/dotfile" @@ -18,13 +16,13 @@ type Rule struct { } func (r Rule) Pprint() { - log.Println(tui.ApplyStylef(tui.Cyan, "Rule %s:", r.Name)) + tui.Print(tui.ApplyStylef(tui.Cyan, "Rule %s:", r.Name)) for _, action := range r.Actions { action.Pprint() } if r.Ignore { - log.Println(tui.ApplyStyle(tui.Gray, " IGNORED")) + tui.Print(tui.ApplyStyle(tui.Gray, " IGNORED")) } } @@ -34,7 +32,7 @@ func (r Rule) Apply() { for _, action := range r.Actions { err := action.Apply() if err != nil { - log.Printf("Failed to run rule %s: %v", r.Name, err) + tui.Print("Failed to run rule %s: %v", r.Name, err) break } } @@ -44,7 +42,7 @@ func (r Rule) Apply() { func MatchRule(dotfile *dotfile.Dotfile) *Rule { for _, rule := range rulesConfig.Rules { if cmp.Equal(dotfile, rule.Dotfile) { - log.Printf("Matched rule %s with dotfile %s", rule.Name, dotfile.Name) + tui.Debug("Matched rule %s with dotfile %s", rule.Name, dotfile.Name) return &rule } } diff --git a/internal/tui/log.go b/internal/tui/log.go new file mode 100644 index 0000000..64405b0 --- /dev/null +++ b/internal/tui/log.go @@ -0,0 +1,29 @@ +package tui + +import ( + "fmt" + "os" +) + +var Verbose bool + +func Debug(format string, a ...interface{}) { + if Verbose { + format = fmt.Sprintf("DEBUG: %s\n", format) + fmt.Fprintf(os.Stderr, ApplyStylef(Gray, format, a...)) + } +} + +func Print(format string, a ...interface{}) { + fmt.Printf(format+"\n", a...) +} + +func FatalIfError(message string, err error) { + if err != nil { + if message != "" { + fmt.Fprintln(os.Stderr, message) + } + fmt.Fprintf(os.Stderr, ApplyStylef(Red, "Error: %v\n", err)) + os.Exit(255) + } +} diff --git a/internal/utils/fetch.go b/internal/utils/fetch.go index 24e9749..ef95c14 100644 --- a/internal/utils/fetch.go +++ b/internal/utils/fetch.go @@ -5,10 +5,11 @@ import ( "fmt" "io" "io/ioutil" - "log" "net/http" "os" "path" + + "github.com/doron-cohen/antidot/internal/tui" ) func Download(src, dest string) error { @@ -20,9 +21,7 @@ func Download(src, dest string) error { defer resp.Body.Close() tempFile, err := ioutil.TempFile("", "rules.*.yaml") - if err != nil { - log.Fatal(err) - } + tui.FatalIfError("Failed to create rules file", err) defer os.Remove(tempFile.Name()) _, err = io.Copy(tempFile, resp.Body)