From ebd9ec62873d7f286586ea0af9113d74b8a1d2f2 Mon Sep 17 00:00:00 2001 From: Chris Lane Date: Wed, 4 Mar 2020 19:31:13 -0500 Subject: [PATCH] wip(installer): stub experimental "installer" Stubs out an experimental "installer" that will help new users to quickly configure `cheat`. --- cmd/cheat/main.go | 61 +++++++++++++++++++++++++++++++++ cmd/cheat/str_config.go | 4 +-- configs/conf.yml | 4 +-- internal/installer/clone.go | 24 +++++++++++++ internal/installer/installer.go | 1 + internal/installer/prompt.go | 37 ++++++++++++++++++++ 6 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 internal/installer/clone.go create mode 100644 internal/installer/installer.go create mode 100644 internal/installer/prompt.go diff --git a/cmd/cheat/main.go b/cmd/cheat/main.go index f32fdbf..9af24de 100755 --- a/cmd/cheat/main.go +++ b/cmd/cheat/main.go @@ -5,13 +5,16 @@ package main import ( "fmt" "os" + "path" "runtime" "strings" "github.com/docopt/docopt-go" + "github.com/mitchellh/go-homedir" "github.com/cheat/cheat/internal/cheatpath" "github.com/cheat/cheat/internal/config" + "github.com/cheat/cheat/internal/installer" ) const version = "3.6.0" @@ -50,6 +53,64 @@ func main() { confpath, err := config.Path(confpaths) if err != nil { + // prompt the user to create a config file + yes, err := installer.Prompt( + "A config file was not found. Would you like to create one now? [Y/n]", + true, + ) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err) + os.Exit(1) + } + + // exit early on a negative answer + if !yes { + os.Exit(0) + } + + // prompt the user to create a config file + yes, err = installer.Prompt( + "Would you like to download the community cheatsheets? [Y/n]", + true, + ) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err) + os.Exit(1) + } + + // clone the community cheatsheets if so instructed + if yes { + + // get the user's home directory + home, err := homedir.Dir() + if err != nil { + fmt.Fprintf( + os.Stderr, + "failed to create config: failed to get user home directory: %v\n", + err, + ) + os.Exit(1) + } + + // clone the community cheatsheets + community := path.Join(home, ".config/cheat/cheatsheets/community") + if err := installer.Clone(community); err != nil { + fmt.Fprintf(os.Stderr, "failed to create config: %v\n", err) + os.Exit(1) + } + + // create a directory for personal cheatsheets too + personal := path.Join(home, ".config/cheat/cheatsheets/personal") + if err := os.MkdirAll(personal, os.ModePerm); err != nil { + fmt.Fprintf( + os.Stderr, + "failed to create config: failed to create directory: %s: %v\n", + personal, + err) + os.Exit(1) + } + } + // the config file does not exist, so we'll try to create one if err = config.Init(confpaths[0], configs()); err != nil { fmt.Fprintf( diff --git a/cmd/cheat/str_config.go b/cmd/cheat/str_config.go index 03582e0..0cfaf5b 100644 --- a/cmd/cheat/str_config.go +++ b/cmd/cheat/str_config.go @@ -52,14 +52,14 @@ cheatpaths: # Once downloaded, ensure that 'path' below points to the location at which # you downloaded the community cheatsheets. - name: community - path: ~/cheat/cheatsheets/community + path: ~/.config/cheat/cheatsheets/community tags: [ community ] readonly: true # If you have personalized cheatsheets, list them last. They will take # precedence over the more global cheatsheets. - name: personal - path: ~/cheat/cheatsheets/personal + path: ~/.config/cheat/cheatsheets/personal tags: [ personal ] readonly: false diff --git a/configs/conf.yml b/configs/conf.yml index 26f2a1e..c4ee6ff 100644 --- a/configs/conf.yml +++ b/configs/conf.yml @@ -43,14 +43,14 @@ cheatpaths: # Once downloaded, ensure that 'path' below points to the location at which # you downloaded the community cheatsheets. - name: community - path: ~/cheat/cheatsheets/community + path: ~/.config/cheat/cheatsheets/community tags: [ community ] readonly: true # If you have personalized cheatsheets, list them last. They will take # precedence over the more global cheatsheets. - name: personal - path: ~/cheat/cheatsheets/personal + path: ~/.config/cheat/cheatsheets/personal tags: [ personal ] readonly: false diff --git a/internal/installer/clone.go b/internal/installer/clone.go new file mode 100644 index 0000000..ee005a2 --- /dev/null +++ b/internal/installer/clone.go @@ -0,0 +1,24 @@ +package installer + +import ( + "fmt" + "os" + "os/exec" +) + +const cloneURL = "https://github.com/cheat/cheatsheets.git" + +// Clone clones the community cheatsheets +func Clone(path string) error { + + // perform the clone in a shell + cmd := exec.Command("git", "clone", cloneURL, path) + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + return fmt.Errorf("failed to clone cheatsheets: %v", err) + } + + return nil +} diff --git a/internal/installer/installer.go b/internal/installer/installer.go new file mode 100644 index 0000000..24e14ce --- /dev/null +++ b/internal/installer/installer.go @@ -0,0 +1 @@ +package installer diff --git a/internal/installer/prompt.go b/internal/installer/prompt.go new file mode 100644 index 0000000..646ee5d --- /dev/null +++ b/internal/installer/prompt.go @@ -0,0 +1,37 @@ +package installer + +import ( + "bufio" + "fmt" + "os" + "strings" +) + +// Prompt prompts the user for a answer +func Prompt(prompt string, def bool) (bool, error) { + + // initialize a line reader + reader := bufio.NewReader(os.Stdin) + + // display the prompt + fmt.Print(fmt.Sprintf("%s: ", prompt)) + + // read the answer + ans, err := reader.ReadString('\n') + if err != nil { + return false, fmt.Errorf("failed to parse input: %v", err) + } + + // normalize the answer + ans = strings.ToLower(strings.TrimRight(ans, "\n")) + + // return the appropriate response + switch ans { + case "y": + return true, nil + case "": + return def, nil + default: + return false, nil + } +}