Skip to content

Instantly share code, notes, and snippets.

@mattn
Created September 1, 2015 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mattn/4bf77ec122e6cb618972 to your computer and use it in GitHub Desktop.
Save mattn/4bf77ec122e6cb618972 to your computer and use it in GitHub Desktop.
From aad1bc815162d4c55dbc8609b1dc650e1dc782a6 Mon Sep 17 00:00:00 2001
From: mathhun <achemer@gmail.com>
Date: Fri, 22 May 2015 07:41:18 +0900
Subject: [PATCH 1/6] Implement download cheats feature
---
cheat.go | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/cheat.go b/cheat.go
index 4284c86..b5592eb 100644
--- a/cheat.go
+++ b/cheat.go
@@ -8,6 +8,7 @@ import (
"github.com/atotto/clipboard"
"github.com/codegangsta/cli"
"github.com/mattn/go-colorable"
+ "io"
"io/ioutil"
"os"
"os/exec"
@@ -37,6 +38,8 @@ func main() {
config := &JSONData{}
config.ReadConfig()
+ cheatsDirectory := path.Join(os.Getenv("HOME"), "/.cheatsheets")
+
app.Commands = []cli.Command{
{
Name: "show",
@@ -94,6 +97,25 @@ func main() {
editCheat(rcfile, config.Editor)
},
},
+ {
+ Name: "download",
+ Usage: "Download cheats",
+ Flags: []cli.Flag{
+ cli.StringFlag{
+ Name: "dir, d",
+ Value: cheatsDirectory,
+ Usage: fmt.Sprintf("cheats directory (default: %s)", cheatsDirectory),
+ },
+ cli.BoolFlag{
+ Name: "verbose, v",
+ },
+ },
+ Action: func(c *cli.Context) {
+ url := "https://github.com/jahendrie/cheat"
+ exitCode := download(url, c.String("dir"), c.Bool("verbose"))
+ os.Exit(exitCode)
+ },
+ },
}
app.Run(os.Args)
@@ -159,3 +181,74 @@ func editCheat(cheatfile string, configEditor string) {
cmd.Stderr = os.Stderr
cmd.Run()
}
+
+func download(url string, cheatsDir string, verbose bool) int {
+ cloneDir, err := ioutil.TempDir(os.TempDir(), "cheat")
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return 1
+ }
+
+ defer func() {
+ if verbose {
+ fmt.Fprintf(os.Stderr, "Removing temporary directory: %s\n", cloneDir)
+ }
+ os.RemoveAll(cloneDir)
+ }()
+
+ if runGitClone(url, cloneDir, verbose) != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return 1
+ }
+
+ if copyCheatFiles(path.Join(cloneDir, "data"), cheatsDir) != nil {
+ fmt.Fprintln(os.Stderr, err)
+ return 1
+ }
+
+ return 0
+}
+
+func runGitClone(url, dir string, verbose bool) error {
+ cmd := exec.Command("git", "clone", url, dir)
+ if verbose {
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
+ }
+ return cmd.Run()
+}
+
+func copyCheatFiles(cloneDir, cheatsDir string) error {
+ files, err := ioutil.ReadDir(cloneDir)
+ if err != nil {
+ return err
+ }
+
+ for _, f := range files {
+ err := copyFile(path.Join(cloneDir, f.Name()), path.Join(cheatsDir, f.Name()))
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func copyFile(src, dst string) error {
+ s, err := os.Open(src)
+ if err != nil {
+ return err
+ }
+ defer s.Close()
+
+ d, err := os.Create(dst)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(d, s); err != nil {
+ d.Close()
+ return err
+ }
+
+ return d.Close()
+}
From bacf2e267e252b4ded5f332af0b300b55f5e9a37 Mon Sep 17 00:00:00 2001
From: mathhun <achemer@gmail.com>
Date: Fri, 22 May 2015 07:49:34 +0900
Subject: [PATCH 2/6] fix
---
cheat.go | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/cheat.go b/cheat.go
index b5592eb..f45f825 100644
--- a/cheat.go
+++ b/cheat.go
@@ -38,8 +38,6 @@ func main() {
config := &JSONData{}
config.ReadConfig()
- cheatsDirectory := path.Join(os.Getenv("HOME"), "/.cheatsheets")
-
app.Commands = []cli.Command{
{
Name: "show",
@@ -103,8 +101,8 @@ func main() {
Flags: []cli.Flag{
cli.StringFlag{
Name: "dir, d",
- Value: cheatsDirectory,
- Usage: fmt.Sprintf("cheats directory (default: %s)", cheatsDirectory),
+ Value: config.Cheatdirs[0],
+ Usage: fmt.Sprintf("cheats directory (default: %s)", config.Cheatdirs[0]),
},
cli.BoolFlag{
Name: "verbose, v",
From 17ed59818a787c6c0dd149ae37a48d166002ad8a Mon Sep 17 00:00:00 2001
From: mathhun <achemer@gmail.com>
Date: Fri, 22 May 2015 08:05:49 +0900
Subject: [PATCH 3/6] Use Chris' repo as a cheat source
---
cheat.go | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/cheat.go b/cheat.go
index f45f825..847ff62 100644
--- a/cheat.go
+++ b/cheat.go
@@ -96,7 +96,7 @@ func main() {
},
},
{
- Name: "download",
+ Name: "fetch",
Usage: "Download cheats",
Flags: []cli.Flag{
cli.StringFlag{
@@ -109,7 +109,7 @@ func main() {
},
},
Action: func(c *cli.Context) {
- url := "https://github.com/jahendrie/cheat"
+ url := "https://github.com/chrisallenlane/cheat"
exitCode := download(url, c.String("dir"), c.Bool("verbose"))
os.Exit(exitCode)
},
@@ -199,7 +199,7 @@ func download(url string, cheatsDir string, verbose bool) int {
return 1
}
- if copyCheatFiles(path.Join(cloneDir, "data"), cheatsDir) != nil {
+ if copyCheatFiles(path.Join(cloneDir, "cheat", "cheatsheets"), cheatsDir) != nil {
fmt.Fprintln(os.Stderr, err)
return 1
}
From 07a93f85ed2929e1c9d56103af82cb89def3f7ab Mon Sep 17 00:00:00 2001
From: mathhun <achemer@gmail.com>
Date: Fri, 22 May 2015 08:09:07 +0900
Subject: [PATCH 4/6] Rename
---
cheat.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/cheat.go b/cheat.go
index 847ff62..e630f5c 100644
--- a/cheat.go
+++ b/cheat.go
@@ -110,7 +110,7 @@ func main() {
},
Action: func(c *cli.Context) {
url := "https://github.com/chrisallenlane/cheat"
- exitCode := download(url, c.String("dir"), c.Bool("verbose"))
+ exitCode := fetchCheats(url, c.String("dir"), c.Bool("verbose"))
os.Exit(exitCode)
},
},
@@ -180,7 +180,7 @@ func editCheat(cheatfile string, configEditor string) {
cmd.Run()
}
-func download(url string, cheatsDir string, verbose bool) int {
+func fetchCheats(url string, cheatsDir string, verbose bool) int {
cloneDir, err := ioutil.TempDir(os.TempDir(), "cheat")
if err != nil {
fmt.Fprintln(os.Stderr, err)
From e1f9e9096f414eccd0394cbe6850cb5df352424a Mon Sep 17 00:00:00 2001
From: mathhun <achemer@gmail.com>
Date: Sat, 23 May 2015 10:41:36 +0900
Subject: [PATCH 5/6] Keep cloned repos and do git pull when exists
---
cheat.go | 119 +++++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 89 insertions(+), 30 deletions(-)
diff --git a/cheat.go b/cheat.go
index e630f5c..28ba51d 100644
--- a/cheat.go
+++ b/cheat.go
@@ -10,6 +10,7 @@ import (
"github.com/mattn/go-colorable"
"io"
"io/ioutil"
+ "net/url"
"os"
"os/exec"
"os/user"
@@ -97,21 +98,30 @@ func main() {
},
{
Name: "fetch",
- Usage: "Download cheats",
+ Usage: "Fetch cheats",
Flags: []cli.Flag{
cli.StringFlag{
Name: "dir, d",
Value: config.Cheatdirs[0],
- Usage: fmt.Sprintf("cheats directory (default: %s)", config.Cheatdirs[0]),
+ Usage: "cheats directory",
},
- cli.BoolFlag{
- Name: "verbose, v",
+ cli.StringFlag{
+ Name: "repo, r",
+ Value: "https://github.com/chrisallenlane/cheat/cheat/cheatsheets",
+ Usage: "repository to fetch cheats from",
+ },
+ cli.StringFlag{
+ Name: "local, l",
+ Usage: "local path to store repository",
},
},
Action: func(c *cli.Context) {
- url := "https://github.com/chrisallenlane/cheat"
- exitCode := fetchCheats(url, c.String("dir"), c.Bool("verbose"))
- os.Exit(exitCode)
+ if c.String("local") == "" && os.Getenv("GOPATH") == "" {
+ fmt.Fprintf(os.Stderr, "Local path to store repo is required.\n")
+ return
+ }
+
+ fetchCheats(c)
},
},
}
@@ -180,56 +190,105 @@ func editCheat(cheatfile string, configEditor string) {
cmd.Run()
}
-func fetchCheats(url string, cheatsDir string, verbose bool) int {
- cloneDir, err := ioutil.TempDir(os.TempDir(), "cheat")
+func fetchCheats(c *cli.Context) {
+ // parse repo url
+ repo, err := url.Parse(c.String("repo"))
if err != nil {
fmt.Fprintln(os.Stderr, err)
- return 1
+ return
}
- defer func() {
- if verbose {
- fmt.Fprintf(os.Stderr, "Removing temporary directory: %s\n", cloneDir)
- }
- os.RemoveAll(cloneDir)
- }()
+ repoPath := strings.Split(repo.Path, "/")
+ if len(repoPath) <= 3 {
+ fmt.Fprintln(os.Stderr, "Invalid Repo URL")
+ return
+ }
- if runGitClone(url, cloneDir, verbose) != nil {
- fmt.Fprintln(os.Stderr, err)
- return 1
+ cheatsPath := repoPath[3:]
+ repo.Path = fmt.Sprintf("/%s/%s", repoPath[1], repoPath[2])
+
+ // directory where the cloned repository is stored
+ var cloneDir string
+ if c.String("local") != "" {
+ cloneDir = c.String("local")
+ } else if os.Getenv("GOPATH") != "" {
+ cloneDir = path.Join(os.Getenv("GOPATH"), "src", repo.Host, repoPath[1], repoPath[2])
}
- if copyCheatFiles(path.Join(cloneDir, "cheat", "cheatsheets"), cheatsDir) != nil {
+ // update the repo
+ updated, err := updateLocalRepo(repo.String(), cloneDir)
+ if err != nil {
fmt.Fprintln(os.Stderr, err)
- return 1
+ return
}
- return 0
+ // copy cheats
+ if updated {
+ srcPath := cloneDir
+ for _, p := range cheatsPath {
+ srcPath = path.Join(srcPath, p)
+ }
+
+ count, err := copyCheatFiles(srcPath, c.String("dir"))
+ if err != nil {
+ fmt.Fprintln(os.Stderr, err)
+ }
+ fmt.Fprintf(os.Stderr, "%d cheats updated.\n", count)
+ } else {
+ fmt.Fprintf(os.Stderr, "No cheats updated.\n")
+ }
}
-func runGitClone(url, dir string, verbose bool) error {
- cmd := exec.Command("git", "clone", url, dir)
- if verbose {
+func updateLocalRepo(url, dir string) (bool, error) {
+ var cmd *exec.Cmd
+
+ _, err := os.Stat(dir)
+ if os.IsNotExist(err) {
+ cmd = exec.Command("git", "clone", url, dir)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
+ return true, cmd.Run()
+ } else {
+ cmd = exec.Command("git", "pull", url)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+
+ res := string(out)
+ fmt.Fprint(os.Stderr, res)
+
+ updated := true
+ if strings.Contains(res, "Already up-to-date.") {
+ updated = false
+ }
+
+ return updated, err
}
- return cmd.Run()
}
-func copyCheatFiles(cloneDir, cheatsDir string) error {
+func copyCheatFiles(cloneDir, cheatsDir string) (int, error) {
+ fmt.Fprintf(os.Stderr, "Copying from %s to %s\n", cloneDir, cheatsDir)
+ count := 0
+
files, err := ioutil.ReadDir(cloneDir)
if err != nil {
- return err
+ return count, err
+ }
+
+ err = os.MkdirAll(cheatsDir, 0755)
+ if err != nil {
+ return count, err
}
for _, f := range files {
+ count += 1
+
err := copyFile(path.Join(cloneDir, f.Name()), path.Join(cheatsDir, f.Name()))
if err != nil {
- return err
+ return count, err
}
}
- return nil
+ return count, nil
}
func copyFile(src, dst string) error {
From c1c580cff53a6e29f18cf2a56338a629f606b41d Mon Sep 17 00:00:00 2001
From: mathhun <achemer@gmail.com>
Date: Tue, 1 Sep 2015 06:12:19 +0900
Subject: [PATCH 6/6] Fix according to the suggested changes
---
cheat.go | 17 +++++++++++------
1 file changed, 11 insertions(+), 6 deletions(-)
diff --git a/cheat.go b/cheat.go
index 28ba51d..3d635f2 100644
--- a/cheat.go
+++ b/cheat.go
@@ -212,7 +212,7 @@ func fetchCheats(c *cli.Context) {
if c.String("local") != "" {
cloneDir = c.String("local")
} else if os.Getenv("GOPATH") != "" {
- cloneDir = path.Join(os.Getenv("GOPATH"), "src", repo.Host, repoPath[1], repoPath[2])
+ cloneDir = filepath.Join(os.Getenv("GOPATH"), "src", repo.Host, repoPath[1], repoPath[2])
}
// update the repo
@@ -226,7 +226,7 @@ func fetchCheats(c *cli.Context) {
if updated {
srcPath := cloneDir
for _, p := range cheatsPath {
- srcPath = path.Join(srcPath, p)
+ srcPath = filepath.Join(srcPath, p)
}
count, err := copyCheatFiles(srcPath, c.String("dir"))
@@ -251,7 +251,11 @@ func updateLocalRepo(url, dir string) (bool, error) {
} else {
cmd = exec.Command("git", "pull", url)
cmd.Dir = dir
+
out, err := cmd.CombinedOutput()
+ if err != nil {
+ return false, err
+ }
res := string(out)
fmt.Fprint(os.Stderr, res)
@@ -261,7 +265,7 @@ func updateLocalRepo(url, dir string) (bool, error) {
updated = false
}
- return updated, err
+ return updated, nil
}
}
@@ -282,7 +286,7 @@ func copyCheatFiles(cloneDir, cheatsDir string) (int, error) {
for _, f := range files {
count += 1
- err := copyFile(path.Join(cloneDir, f.Name()), path.Join(cheatsDir, f.Name()))
+ err := copyFile(filepath.Join(cloneDir, f.Name()), filepath.Join(cheatsDir, f.Name()))
if err != nil {
return count, err
}
@@ -302,10 +306,11 @@ func copyFile(src, dst string) error {
if err != nil {
return err
}
+ defer d.Close()
+
if _, err := io.Copy(d, s); err != nil {
- d.Close()
return err
}
- return d.Close()
+ return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment