diff --git a/.gitignore b/.gitignore index 755d380..4832950 100644 --- a/.gitignore +++ b/.gitignore @@ -20,3 +20,4 @@ # Go workspace file go.work bin/ +dotfiles diff --git a/Makefile b/Makefile index fd70577..8ae9ab3 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -APP_NAME := dotfiles-cli +APP_NAME := dotfiles GOBASE := $(shell pwd) GOBIN := $(GOBASE)/bin diff --git a/README.md b/README.md index 1de9e25..ce17ab6 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -# dotfiles-cli +# dotfiles CLI This is my personal [dotfiles](/~https://github.com/pablobfonseca/dotfiles.git) installer ## Getting started ```shell -$ dotfiles-cli -dotfiles-cli is a CLI tool to install dotfiles from a git repository. +$ dotfiles +dotfiles is a CLI tool to install dotfiles from a git repository. Usage: - dotfiles-cli [command] + dotfiles [command] Available Commands: completion Generate the autocompletion script for the specified shell @@ -18,8 +18,8 @@ Available Commands: update Update the dotfiles Flags: - -h, --help help for dotfiles-cli + -h, --help help for dotfiles -t, --toggle Help message for toggle -Use "dotfiles-cli [command] --help" for more information about a command. +Use "dotfiles [command] --help" for more information about a command. ``` diff --git a/cmd/install.go b/cmd/install.go index 8341bb6..de3962b 100644 --- a/cmd/install.go +++ b/cmd/install.go @@ -7,7 +7,7 @@ import ( "github.com/spf13/cobra" "github.com/vbauerster/mpb/v7" - dotfiles "github.com/pablobfonseca/dotfiles-cli/src/installers" + dotfiles "github.com/pablobfonseca/dotfiles/src/installers" ) var installCmd = &cobra.Command{ @@ -29,10 +29,10 @@ var installCmd = &cobra.Command{ installAll(p) } if nvim { - dotfiles.InstallNvim(p) + dotfiles.InstallNvim(p, verbose) } if emacs { - dotfiles.InstallEmacs(p) + dotfiles.InstallEmacs(p, verbose) } if zsh { dotfiles.InstallZsh(p) @@ -43,11 +43,11 @@ var installCmd = &cobra.Command{ } func installAll(p *mpb.Progress) { - dotfiles.CloneRepo(p) - dotfiles.InstallHomebrew(p) - dotfiles.InstallNvim(p) + dotfiles.CloneRepo(p, verbose) + dotfiles.InstallHomebrew(p, verbose) + dotfiles.InstallNvim(p, verbose) dotfiles.InstallZsh(p) - dotfiles.InstallEmacs(p) + dotfiles.InstallEmacs(p, verbose) } func init() { diff --git a/cmd/root.go b/cmd/root.go index 8bb5550..4d8b334 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -5,15 +5,20 @@ package cmd import ( "os" + "path" + tea "github.com/charmbracelet/bubbletea" + "github.com/pablobfonseca/dotfiles/src/utils" + "github.com/pablobfonseca/dotfiles/src/utils/prompts" "github.com/spf13/cobra" + "github.com/spf13/viper" ) // rootCmd represents the base command when called without any subcommands var rootCmd = &cobra.Command{ - Use: "dotfiles-cli", + Use: "dotfiles", Short: "Install dotfiles from a git repository", - Long: `dotfiles-cli is a CLI tool to install dotfiles from a git repository.`, + Long: `dotfiles is a CLI tool to install dotfiles from a git repository.`, } // Execute adds all child commands to the root command and sets flags appropriately. @@ -25,15 +30,40 @@ func Execute() { } } +var cfgFile = "" +var verbose bool + func init() { - // Here you will define your flags and configuration settings. - // Cobra supports persistent flags, which, if defined here, - // will be global for your application. - // cfgFile := "" + cobra.OnInitialize(initConfig) + rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.dotfiles/config.toml)") + rootCmd.PersistentFlags().BoolVarP(&verbose, "verbose", "v", false, "verbose output") + rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") +} - // rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/config/dotfiles-cli/config.yaml)") +func initConfig() { + if cfgFile != "" { + viper.SetConfigFile(cfgFile) + } else { + home, err := os.UserHomeDir() + if err != nil { + utils.ErrorMessage("Something went wrong", err) + } - // Cobra also supports local flags, which will only run - // when this action is called directly. - rootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") + viper.AddConfigPath(path.Join(home, ".dotfiles/")) + viper.SetConfigType("toml") + viper.SetConfigName("config") + } + + if err := viper.ReadInConfig(); err != nil { + if _, ok := err.(viper.ConfigFileNotFoundError); ok { + p := tea.NewProgram(prompts.ConfigPrompt()) + + if _, err := p.Run(); err != nil { + utils.ErrorMessage("[Config prompt error]: Something went wrong", err) + } + + } else { + utils.ErrorMessage("Something went wrong", err) + } + } } diff --git a/cmd/uninstall.go b/cmd/uninstall.go index cb6f1d0..d0c67d7 100644 --- a/cmd/uninstall.go +++ b/cmd/uninstall.go @@ -7,15 +7,14 @@ import ( "github.com/spf13/cobra" "github.com/vbauerster/mpb/v7" - dotfiles "github.com/pablobfonseca/dotfiles-cli/src/installers" + dotfiles "github.com/pablobfonseca/dotfiles/src/installers" ) var uninstallCmd = &cobra.Command{ Use: "uninstall", Short: "Uninstall the dotfiles", Long: `Uninstall the dotfiles. You can uninstall all the dotfiles or just some of them. - Example: dotfiles uninstall --all - dotfiles uninstall --nvim + Example: dotfiles uninstall --nvim dotfiles uninstall --emacs `, Run: func(cmd *cobra.Command, args []string) { @@ -29,10 +28,10 @@ var uninstallCmd = &cobra.Command{ uninstallAll(p) } if nvim { - dotfiles.UninstallNvim(p) + dotfiles.UninstallNvim(uninstallApp, p, verbose) } if emacs { - dotfiles.UninstallEmacs(p) + dotfiles.UninstallEmacs(uninstallApp, p, verbose) } p.Wait() @@ -40,15 +39,19 @@ var uninstallCmd = &cobra.Command{ } func uninstallAll(p *mpb.Progress) { - dotfiles.DeleteRepo(p) - dotfiles.UninstallNvim(p) - dotfiles.UninstallEmacs(p) + dotfiles.DeleteRepo(p, verbose) + dotfiles.UninstallNvim(uninstallApp, p, verbose) + dotfiles.UninstallEmacs(uninstallApp, p, verbose) } +var uninstallApp bool + func init() { rootCmd.AddCommand(uninstallCmd) - uninstallCmd.Flags().BoolP("all", "a", false, "Uninstall all the dotfiles") + uninstallCmd.Flags().BoolVarP(&uninstallApp, "prune", "p", false, "Also uninstall the app") + + uninstallCmd.Flags().BoolP("all", "a", false, "Uninstall all dotfiles") uninstallCmd.Flags().BoolP("nvim", "n", false, "Uninstall nvim files") uninstallCmd.Flags().BoolP("emacs", "e", false, "Uninstall emacs files") } diff --git a/cmd/update.go b/cmd/update.go index c0bc534..083ec18 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -1,7 +1,7 @@ package cmd import ( - updaters "github.com/pablobfonseca/dotfiles-cli/src/updaters" + updaters "github.com/pablobfonseca/dotfiles/src/updaters" "github.com/spf13/cobra" "github.com/vbauerster/mpb/v7" ) @@ -21,11 +21,11 @@ var updateCmd = &cobra.Command{ brew, _ := cmd.Flags().GetBool("brew") if nvim { - updaters.UpdateNvim(p) + updaters.UpdateNvim(p, verbose) } if brew { - updaters.UpdateBrew(p) + updaters.UpdateBrew(p, verbose) } p.Wait() diff --git a/go.mod b/go.mod index 4bd8c55..c9d96dd 100644 --- a/go.mod +++ b/go.mod @@ -1,19 +1,52 @@ -module github.com/pablobfonseca/dotfiles-cli +module github.com/pablobfonseca/dotfiles go 1.21.5 require ( + github.com/charmbracelet/bubbles v0.17.1 + github.com/charmbracelet/bubbletea v0.25.0 + github.com/charmbracelet/lipgloss v0.9.1 + github.com/enescakir/emoji v1.0.0 github.com/spf13/cobra v1.7.0 + github.com/spf13/viper v1.18.1 github.com/vbauerster/mpb/v7 v7.5.3 ) require ( github.com/VividCortex/ewma v1.2.0 // indirect github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d // indirect - github.com/enescakir/emoji v1.0.0 // indirect + github.com/atotto/clipboard v0.1.4 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/magiconair/properties v1.8.7 // indirect + github.com/mattn/go-isatty v0.0.18 // indirect + github.com/mattn/go-localereader v0.0.1 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b // indirect + github.com/muesli/cancelreader v0.2.2 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/pelletier/go-toml/v2 v2.1.0 // indirect github.com/rivo/uniseg v0.2.0 // indirect + github.com/sagikazarmark/locafero v0.4.0 // indirect + github.com/sagikazarmark/slog-shim v0.1.0 // indirect + github.com/sourcegraph/conc v0.3.0 // indirect + github.com/spf13/afero v1.11.0 // indirect + github.com/spf13/cast v1.6.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 // indirect + github.com/subosito/gotenv v1.6.0 // indirect + go.uber.org/atomic v1.9.0 // indirect + go.uber.org/multierr v1.9.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/sync v0.5.0 // indirect + golang.org/x/sys v0.15.0 // indirect + golang.org/x/term v0.6.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 18e1133..cfcbbeb 100644 --- a/go.sum +++ b/go.sum @@ -2,23 +2,122 @@ github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1o github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= +github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= +github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/charmbracelet/bubbles v0.17.1 h1:0SIyjOnkrsfDo88YvPgAWvZMwXe26TP6drRvmkjyUu4= +github.com/charmbracelet/bubbles v0.17.1/go.mod h1:9HxZWlkCqz2PRwsCbYl7a3KXvGzFaDHpYbSYMJ+nE3o= +github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM= +github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg= +github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg= +github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= +github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/enescakir/emoji v1.0.0 h1:W+HsNql8swfCQFtioDGDHCHri8nudlK1n5p2rHCJoog= github.com/enescakir/emoji v1.0.0/go.mod h1:Bt1EKuLnKDTYpLALApstIkAjdDrS/8IAgTkKp+WKFD0= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= +github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= +github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= +github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= +github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b h1:1XF24mVaiu7u+CFywTdcDo2ie1pzzhwjt6RHqzpMU34= +github.com/muesli/ansi v0.0.0-20211018074035-2e021307bc4b/go.mod h1:fQuZ0gauxyBcmsdE3ZT4NasjaRdxmbCS0jRHsrWu3Ho= +github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= +github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= +github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ= +github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4= +github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE= +github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ= +github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= +github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= +github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= +github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/viper v1.18.1 h1:rmuU42rScKWlhhJDyXZRKJQHXFX02chSVW1IvkPGiVM= +github.com/spf13/viper v1.18.1/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= +github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/vbauerster/mpb/v7 v7.5.3 h1:BkGfmb6nMrrBQDFECR/Q7RkKCw7ylMetCb4079CGs4w= github.com/vbauerster/mpb/v7 v7.5.3/go.mod h1:i+h4QY6lmLvBNK2ah1fSreiw3ajskRlBp9AhY/PnuOE= -golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2 h1:wM1k/lXfpc5HdkJJyW9GELpd8ERGdnh8sMGL6Gzq3Ho= +go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= +go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= +go.uber.org/multierr v1.9.0 h1:7fIwc/ZtS0q++VgcfqFDxSBZVv/Xo49/SYnDFupUwlI= +go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTVQ= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE= +golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20220909162455-aba9fc2a8ff2/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.6.0 h1:clScbb1cHjoCkyRbWwBEUZ5H/tIFu5TAXIqaZD0Gcjw= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= +gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= +gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/main.go b/main.go index 40f1e36..51ec72b 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,7 @@ Copyright © 2023 Pablo Fonseca */ package main -import "github.com/pablobfonseca/dotfiles-cli/cmd" +import "github.com/pablobfonseca/dotfiles/cmd" func main() { cmd.Execute() diff --git a/src/config/config.go b/src/config/config.go new file mode 100644 index 0000000..2622fc0 --- /dev/null +++ b/src/config/config.go @@ -0,0 +1,19 @@ +package config + +import "github.com/spf13/viper" + +func RepositoryUrl() string { + return "/~https://github.com/" + viper.GetString("dotfiles.repository") +} + +func DotfilesConfigDir() string { + return viper.GetString("dotfiles.default_dir") +} + +func NvimConfigDir() string { + return viper.GetString("dotfiles.nvim.config_dir") +} + +func EmacsConfigDir() string { + return viper.GetString("dotfiles.emacs.config_dir") +} diff --git a/src/installers/emacs.go b/src/installers/emacs.go index 67f57b8..2b51bfc 100644 --- a/src/installers/emacs.go +++ b/src/installers/emacs.go @@ -4,54 +4,57 @@ import ( "os" "path" - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/config" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) -var emacsConfigPath = path.Join(os.Getenv("HOME"), ".emacs.d") - -func InstallEmacs(p *mpb.Progress) { +func InstallEmacs(p *mpb.Progress, verbose bool) { if emacsInstalled() { utils.SkipMessage("Emacs is already installed") } else { installEmacsBar := utils.NewBar("Installing emacs", 1, p) - if err := utils.ExecuteCommand("brew", "install", "--cask", "emacs"); err != nil { + if err := utils.ExecuteCommand(verbose, "brew", "install", "--cask", "emacs"); err != nil { utils.ErrorMessage("Error installing emacs symlink", err) } installEmacsBar.Increment() } - utils.CloneRepoIfNotExists() + utils.CloneRepoIfNotExists(verbose) symlinkBar := utils.NewBar("Symlinking files", 1, p) - src := path.Join(utils.DotfilesPath, "emacs.d") - dest := path.Join(emacsConfigPath) + src := path.Join(config.DotfilesConfigDir(), "emacs.d") + dest := path.Join(config.EmacsConfigDir()) if err := os.Symlink(src, dest); err != nil { utils.ErrorMessage("Error creating symlink", err) } symlinkBar.Increment() } -func UninstallEmacs(p *mpb.Progress) { +func UninstallEmacs(uninstallApp bool, p *mpb.Progress, verbose bool) { if !emacsInstalled() { utils.SkipMessage("Emacs is not installed") return } - uninstallBar := utils.NewBar("Uninstalling emacs", 2, p) + uninstallBar := utils.NewBar("Uninstalling emacs", 1, p) + + if uninstallApp { + if err := utils.ExecuteCommand(verbose, "brew", "uninstall", "emacs"); err != nil { + utils.ErrorMessage("Error uninstalling emacs", err) + } + uninstallBar.Increment() - if err := utils.ExecuteCommand("brew", "uninstall", "emacs"); err != nil { - utils.ErrorMessage("Error uninstalling emacs", err) } - uninstallBar.Increment() - if err := utils.ExecuteCommand("rm", "-rf", emacsConfigPath); err != nil { + removeFilesBar := utils.NewBar("Removing emacs files", 1, p) + if err := utils.ExecuteCommand(verbose, "rm", "-rf", config.EmacsConfigDir()); err != nil { utils.ErrorMessage("Error removing emacs files", err) } - uninstallBar.Increment() + removeFilesBar.Increment() } func emacsInstalled() bool { diff --git a/src/installers/homebrew.go b/src/installers/homebrew.go index a1231dd..cf31474 100644 --- a/src/installers/homebrew.go +++ b/src/installers/homebrew.go @@ -3,14 +3,14 @@ package dotfiles import ( "fmt" - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) -func InstallHomebrew(p *mpb.Progress) { +func InstallHomebrew(p *mpb.Progress, verbose bool) { bar := utils.NewBar("Installing homebrew", 1, p) - if err := utils.ExecuteCommand("/bin/bash", "-c", "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"); err != nil { + if err := utils.ExecuteCommand(verbose, "/bin/bash", "-c", "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"); err != nil { fmt.Println("Error installing homebrew:", err) return } diff --git a/src/installers/nvim.go b/src/installers/nvim.go index 3b977e3..a795d8b 100644 --- a/src/installers/nvim.go +++ b/src/installers/nvim.go @@ -4,42 +4,41 @@ import ( "os" "path" - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/config" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) -var nvimConfigPath = path.Join(os.Getenv("HOME"), ".config", "nvim") var nvChadRepo = "/~https://github.com/NvChad/NvChad" -func InstallNvim(p *mpb.Progress) { +func InstallNvim(p *mpb.Progress, verbose bool) { if nvimInstalled() { utils.SkipMessage("nvim already installed") - return + } else { + installNvimBar := utils.NewBar("Installing nvim", 1, p) + if err := utils.ExecuteCommand(verbose, "brew", "install", "neovim"); err != nil { + utils.ErrorMessage("Error installing nvim", err) + } + installNvimBar.Increment() } - utils.CloneRepoIfNotExists() - - installNvimBar := utils.NewBar("Installing nvim", 1, p) - if err := utils.ExecuteCommand("brew", "install", "neovim"); err != nil { - utils.ErrorMessage("Error installing nvim", err) - } - installNvimBar.Increment() + utils.CloneRepoIfNotExists(verbose) - if utils.DirExists(nvimConfigPath) { + if utils.DirExists(config.NvimConfigDir()) { utils.SkipMessage("nvim files already exists") return } installNvChadBar := utils.NewBar("Installing NvChad", 1, p) - if err := utils.ExecuteCommand("git", "clone", "--depth", "1", nvChadRepo, nvimConfigPath); err != nil { + if err := utils.ExecuteCommand(verbose, "git", "clone", "--depth", "1", nvChadRepo, config.NvimConfigDir()); err != nil { utils.ErrorMessage("Error cloning the repository", err) } installNvChadBar.Increment() symlinkBar := utils.NewBar("Symlinking files", 1, p) - src := path.Join(utils.DotfilesPath, "nvim", "custom") - dest := path.Join(nvimConfigPath, "lua", "custom") + src := path.Join(config.DotfilesConfigDir(), "nvim", "custom") + dest := path.Join(config.NvimConfigDir(), "lua", "custom") if err := os.Symlink(src, dest); err != nil { utils.ErrorMessage("Error creating symlink", err) } @@ -47,23 +46,26 @@ func InstallNvim(p *mpb.Progress) { } -func UninstallNvim(p *mpb.Progress) { +func UninstallNvim(uninstallApp bool, p *mpb.Progress, verbose bool) { if !nvimInstalled() { utils.SkipMessage("nvim is not installed") return } - uninstallBar := utils.NewBar("Uninstalling nvim", 2, p) + if uninstallApp { + uninstallBar := utils.NewBar("Uninstalling nvim", 1, p) - if err := utils.ExecuteCommand("brew", "uninstall", "neovim"); err != nil { - utils.ErrorMessage("Error uninstalling nvim", err) + if err := utils.ExecuteCommand(verbose, "brew", "uninstall", "neovim"); err != nil { + utils.ErrorMessage("Error uninstalling nvim", err) + } + uninstallBar.Increment() } - uninstallBar.Increment() - if err := utils.ExecuteCommand("rm", "-rf", nvimConfigPath); err != nil { + removeFilesBar := utils.NewBar("Removing nvim files", 1, p) + if err := utils.ExecuteCommand(verbose, "rm", "-rf", config.NvimConfigDir()); err != nil { utils.ErrorMessage("Error removing nvim files", err) } - uninstallBar.Increment() + removeFilesBar.Increment() } func nvimInstalled() bool { diff --git a/src/installers/repo.go b/src/installers/repo.go index 3e1be17..7abdab4 100644 --- a/src/installers/repo.go +++ b/src/installers/repo.go @@ -1,26 +1,24 @@ package dotfiles import ( - "os" - "path" - - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/config" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) -func CloneRepo(p *mpb.Progress) { +func CloneRepo(p *mpb.Progress, verbose bool) { bar := utils.NewBar("Cloning dotfiles repo", 1, p) - if err := utils.ExecuteCommand("git", "clone", utils.DotfilesRepo, path.Join(os.Getenv("HOME"), ".dotfiles")); err != nil { + if err := utils.ExecuteCommand(verbose, "git", "clone", config.RepositoryUrl(), config.DotfilesConfigDir()); err != nil { utils.ErrorMessage("Error cloning the repository", err) } bar.Increment() } -func DeleteRepo(p *mpb.Progress) { +func DeleteRepo(p *mpb.Progress, verbose bool) { bar := utils.NewBar("Deleting dotfiles repo", 1, p) - if err := utils.ExecuteCommand("rm", "-rf", path.Join(os.Getenv("HOME"), ".dotfiles")); err != nil { + if err := utils.ExecuteCommand(verbose, "rm", "-rf", config.DotfilesConfigDir()); err != nil { utils.ErrorMessage("Error deleting the repository", err) } bar.Increment() diff --git a/src/installers/zsh.go b/src/installers/zsh.go index 0a47c6e..abe6b5c 100644 --- a/src/installers/zsh.go +++ b/src/installers/zsh.go @@ -4,7 +4,8 @@ import ( "os" "path" - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/config" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) @@ -14,7 +15,7 @@ func InstallZsh(p *mpb.Progress) { bar := utils.NewBar("Symlinking zsh files", 1, p) for _, file := range []string{"zshrc", "zshenv"} { - src := path.Join(utils.DotfilesPath, "zsh", file) + src := path.Join(config.DotfilesConfigDir(), "zsh", file) dest := path.Join(os.Getenv("HOME"), "."+file) utils.InfoMessage("Syncing " + src + " to " + dest) diff --git a/src/updaters/brew.go b/src/updaters/brew.go index da1d958..2c7410e 100644 --- a/src/updaters/brew.go +++ b/src/updaters/brew.go @@ -3,14 +3,14 @@ package dotfiles import ( "log" - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) -func UpdateBrew(p *mpb.Progress) { +func UpdateBrew(p *mpb.Progress, verbose bool) { bar := utils.NewBar("Updating brew packages", 1, p) - if err := utils.ExecuteCommand("brew", "update"); err != nil { + if err := utils.ExecuteCommand(verbose, "brew", "update"); err != nil { log.Fatal("Error updating homebrew:", err) return } diff --git a/src/updaters/nvim.go b/src/updaters/nvim.go index d8a149c..25a73ff 100644 --- a/src/updaters/nvim.go +++ b/src/updaters/nvim.go @@ -3,14 +3,14 @@ package dotfiles import ( "log" - "github.com/pablobfonseca/dotfiles-cli/src/utils" + "github.com/pablobfonseca/dotfiles/src/utils" "github.com/vbauerster/mpb/v7" ) -func UpdateNvim(p *mpb.Progress) { +func UpdateNvim(p *mpb.Progress, verbose bool) { updateBar := utils.NewBar("Updating nvim packages", 1, p) - if err := utils.ExecuteCommand("nvim", "+NvChadUpdate", "+qall"); err != nil { + if err := utils.ExecuteCommand(verbose, "nvim", "+NvChadUpdate", "+qall"); err != nil { log.Fatal("Error updating nvim:", err) } updateBar.Increment() diff --git a/src/utils/log.go b/src/utils/log.go deleted file mode 100644 index ec89556..0000000 --- a/src/utils/log.go +++ /dev/null @@ -1,20 +0,0 @@ -package utils - -import ( - "fmt" - "log" - - "github.com/enescakir/emoji" -) - -func ErrorMessage(message string, err error) { - log.Fatalf("%v %s: %v", emoji.CrossMark, message, err) -} - -func SkipMessage(message string) { - fmt.Printf("%v %s, skipping...\n", emoji.CheckMark, message) -} - -func InfoMessage(message string) { - fmt.Printf("%v %s\n", emoji.Information, message) -} diff --git a/src/utils/messages.go b/src/utils/messages.go new file mode 100644 index 0000000..95411f5 --- /dev/null +++ b/src/utils/messages.go @@ -0,0 +1,40 @@ +package utils + +import ( + "fmt" + "log" + "strings" + + "github.com/enescakir/emoji" +) + +// ErrorMessage prints an error message and exits the program +func ErrorMessage(message string, err error) { + log.Fatalf("%v %s: %v", emoji.CrossMark, message, err) +} + +// SuccessMessage prints a success message +func SuccessMessage(message string) { + fmt.Printf("%v %s\n", emoji.CheckMark, message) +} + +// SkipMessage prints a skipping message +func SkipMessage(message string) { + fmt.Printf("%v %s, skipping...\n", emoji.CheckMark, message) +} + +// InfoMessage prints an information message +func InfoMessage(message string, args ...interface{}) { + var stringArgs []string + + for _, arg := range args { + stringArgs = append(stringArgs, fmt.Sprintf("%v", arg)) + } + + fullMessage := message + if len(args) > 0 { + fullMessage += ": " + strings.Join(stringArgs, ", ") + } + + fmt.Printf("%v %s\n", emoji.Information, fullMessage) +} diff --git a/src/utils/prompts/config.go b/src/utils/prompts/config.go new file mode 100644 index 0000000..3b61e80 --- /dev/null +++ b/src/utils/prompts/config.go @@ -0,0 +1,189 @@ +package prompts + +import ( + "fmt" + "os" + "strings" + + "github.com/charmbracelet/bubbles/textinput" + tea "github.com/charmbracelet/bubbletea" + "github.com/charmbracelet/lipgloss" + "github.com/pablobfonseca/dotfiles/src/utils" + "github.com/spf13/viper" +) + +var ( + focusedStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#00FFFF")) + blurredStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("#008B8B")) + noStyle = lipgloss.NewStyle() + helpStyle = blurredStyle.Copy() + + focusedButton = focusedStyle.Copy().Render("[ Submit ]") + blurredButton = fmt.Sprintf("[ %s ]", blurredStyle.Render("Submit")) +) + +type configData struct { + repositoryUrl string + dotfilesConfigDir string + nvimConfigDir string + emacsConfigDir string +} + +type model struct { + focusIndex int + inputs []Input + textInputs []textinput.Model + config configData + err error +} + +func ConfigPrompt() model { + inputs := []Input{ + NewInput("\uf408", "repository (e.g, username/dotfiles)", "pablobfonseca/dotfiles"), + NewInput("\uebdf", "dotfiles directory (e.g, ~/.dotfiles)", "~/.dotfiles"), + NewInput("\ue7c5", "config directory (e.g, ~/.config/nvim)", "~/.config/nvim"), + NewInput("\ue632", "emacs config directory (e.g, ~/.emacs.d)", "~/.emacs.d"), + } + + textInputs := make([]textinput.Model, len(inputs)) + for i, in := range inputs { + t := textinput.New() + t.Prompt = in.icon + " " + t.Placeholder = in.placeholder + t.Cursor.Style = focusedStyle + + if i == 0 { + t.Focus() + t.PromptStyle = focusedStyle + t.TextStyle = focusedStyle + } + + textInputs[i] = t + } + + return model{ + inputs: inputs, + textInputs: textInputs, + } +} + +func (m model) Init() tea.Cmd { + return textinput.Blink +} + +func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { + switch msg := msg.(type) { + case tea.KeyMsg: + switch msg.String() { + case "ctrl+c", "esc": + os.Exit(0) + + case "tab", "shift+tab", "enter", "up", "down": + s := msg.String() + + // Did the user press enter while the submit button was focused? + // If so, exit. + if s == "enter" && m.focusIndex == len(m.inputs) { + err := m.persistConfig() + if err != nil { + utils.ErrorMessage("Error creating config file", err) + } + return m, tea.Quit + } + + // Cycle indexes + if s == "up" || s == "shift+tab" { + m.focusIndex-- + } else { + m.focusIndex++ + } + + if m.focusIndex > len(m.inputs) { + m.focusIndex = 0 + } else if m.focusIndex < 0 { + m.focusIndex = len(m.inputs) + } + + cmds := make([]tea.Cmd, len(m.inputs)) + for i := 0; i <= len(m.inputs)-1; i++ { + if i == m.focusIndex { + // Set focused state + cmds[i] = m.textInputs[i].Focus() + m.textInputs[i].PromptStyle = focusedStyle + m.textInputs[i].TextStyle = focusedStyle + continue + } + // Remove focused state + m.textInputs[i].Blur() + m.textInputs[i].PromptStyle = noStyle + m.textInputs[i].TextStyle = noStyle + } + + return m, tea.Batch(cmds...) + } + } + + // Handle character input and blinking + cmd := m.updateInputs(msg) + + return m, cmd +} + +func (m *model) updateInputs(msg tea.Msg) tea.Cmd { + cmds := make([]tea.Cmd, len(m.textInputs)) + + for i := range m.textInputs { + m.textInputs[i], cmds[i] = m.textInputs[i].Update(msg) + m.inputs[i].value = m.textInputs[i].Value() + } + + return tea.Batch(cmds...) +} + +func (m model) View() string { + var b strings.Builder + + for i := range m.inputs { + b.WriteString(m.textInputs[i].View()) + if i < len(m.inputs)-1 { + b.WriteRune('\n') + } + } + + button := &blurredButton + if m.focusIndex == len(m.inputs) { + button = &focusedButton + } + + fmt.Fprintf(&b, "\n\n%s\n\n", *button) + + return b.String() +} + +func (m *model) persistConfig() error { + m.config.repositoryUrl = m.inputs[0].Value() + m.config.dotfilesConfigDir = expandPath(m.inputs[1].Value()) + m.config.nvimConfigDir = expandPath(m.inputs[2].Value()) + m.config.emacsConfigDir = expandPath(m.inputs[3].Value()) + + viper.Set("dotfiles.repository", m.config.repositoryUrl) + viper.Set("dotfiles.default_dir", m.config.dotfilesConfigDir) + viper.Set("dotfiles.nvim.config_dir", m.config.nvimConfigDir) + viper.Set("dotfiles.emacs.config_dir", m.config.emacsConfigDir) + + err := viper.SafeWriteConfig() + if err == nil { + utils.SuccessMessage("Successfully created your config") + } + + return err +} + +func expandPath(path string) string { + if !strings.HasPrefix(path, "~") { + return path + } + + home, _ := os.UserHomeDir() + return strings.Replace(path, "~", home, 1) +} diff --git a/src/utils/prompts/input.go b/src/utils/prompts/input.go new file mode 100644 index 0000000..eb1dd87 --- /dev/null +++ b/src/utils/prompts/input.go @@ -0,0 +1,24 @@ +package prompts + +type Input struct { + icon string + placeholder string + value string + defaultValue string +} + +func (i Input) Value() string { + if i.value == "" { + return i.defaultValue + } + return i.value +} + +func NewInput(icon, placeholder, defaultValue string) Input { + return Input{ + icon: icon, + placeholder: placeholder, + value: "", + defaultValue: defaultValue, + } +} diff --git a/src/utils/repo.go b/src/utils/repo.go index 1e62cb7..1494611 100644 --- a/src/utils/repo.go +++ b/src/utils/repo.go @@ -1,12 +1,17 @@ package utils -func CloneRepoIfNotExists() { - if DirExists(DotfilesPath) { +import ( + "github.com/pablobfonseca/dotfiles/src/config" +) + +func CloneRepoIfNotExists(verbose bool) { + if DirExists(config.DotfilesConfigDir()) { SkipMessage("Dotfiles directory already exists") return } + InfoMessage("Dotfiles directory does not exists, cloning...") - if err := ExecuteCommand("git", "clone", DotfilesRepo, DotfilesPath); err != nil { + if err := ExecuteCommand(verbose, "git", "clone", config.RepositoryUrl(), config.DotfilesConfigDir()); err != nil { ErrorMessage("Error cloning the repository", err) } } diff --git a/src/utils/utils.go b/src/utils/utils.go index c4095bc..dee231a 100644 --- a/src/utils/utils.go +++ b/src/utils/utils.go @@ -5,12 +5,8 @@ import ( "fmt" "os" "os/exec" - "path" ) -var DotfilesRepo = "/~https://github.com/pablobfonseca/dotfiles.git" -var DotfilesPath = path.Join(os.Getenv("HOME"), ".dotfiles") - func CommandExists(command string) bool { _, err := exec.LookPath(command) return err == nil @@ -25,7 +21,7 @@ func DirExists(path string) bool { return info.IsDir() } -func ExecuteCommand(command string, args ...string) error { +func ExecuteCommand(verbose bool, command string, args ...string) error { var stdoutBuf, stderrBuf bytes.Buffer cmd := exec.Command(command, args...) cmd.Stdout = &stdoutBuf @@ -33,7 +29,13 @@ func ExecuteCommand(command string, args ...string) error { err := cmd.Run() if err != nil { - fmt.Println("Error executing command:", err) + fmt.Printf("Error executing command: %s %v | %v\n", command, args, err) + if verbose { + fmt.Println("Command output:", stderrBuf.String()) + } + } + + if verbose { fmt.Println("Command output:", stdoutBuf.String()) }