summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/ponzu/add.go133
1 files changed, 117 insertions, 16 deletions
diff --git a/cmd/ponzu/add.go b/cmd/ponzu/add.go
index 0573a99..dd8af6c 100644
--- a/cmd/ponzu/add.go
+++ b/cmd/ponzu/add.go
@@ -2,14 +2,15 @@ package main
import (
"errors"
- "log"
+ "fmt"
+ "io"
"os"
"os/exec"
"path/filepath"
"strings"
)
-// Use `go get` to download addon and add to $GOPATH/src, useful
+// use `go get` to download addon and add to $GOPATH/src, useful
// for IDE auto-import and code completion, then copy entire directory
// tree to project's ./addons folder
func getAddon(args []string) error {
@@ -25,35 +26,32 @@ func getAddon(args []string) error {
err := get.Start()
if err != nil {
- addError(err)
+ return addError(err)
}
err = get.Wait()
if err != nil {
- addError(err)
+ return addError(err)
}
- // Copy to ./addons folder
+ // copy to ./addons folder
// GOPATH can be a list delimited by ":" on Linux or ";" on Windows
// `go get` uses the first, this should parse out the first whatever the OS
gopath := resolveGOPATH()
pwd, err := os.Getwd()
if err != nil {
- addError(err)
+ return addError(err)
}
src := filepath.Join(gopath, "src", addonPath)
- dest := filepath.Join(pwd, "addons", addonPath)
- log.Println(dest)
- err = os.Mkdir(dest, os.ModeDir|os.ModePerm)
- if err != nil {
- addError(err)
- }
- err = copyAll(src, dest)
+ // Need to strip the addon name for copyAll?
+ last := filepath.Base(addonPath)
+ dest := filepath.Join(pwd, "addons", strings.Replace(addonPath, last, "", 1))
+
+ err = replicateAll(src, dest)
if err != nil {
- log.Println(err)
- //addError(err)
+ return addError(err)
}
return nil
}
@@ -70,7 +68,110 @@ func resolveGOPATH() string {
return gopath
}
-// error return
+// this is distinct from copyAll() in that files are copied, not moved,
+// since we also need them to remain in $GOPATH/src
+// thanks to @markc of stack overflow for the copyFile and copyFileContents functions
+func replicateAll(src, dst string) error {
+ err := filepath.Walk(src, func(path string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ sep := string(filepath.Separator)
+
+ // base == the ponzu project dir + string(filepath.Separator)
+ parts := strings.Split(src, sep)
+ base := strings.Join(parts[:len(parts)-1], sep)
+ base += sep
+
+ target := filepath.Join(dst, path[len(base):])
+
+ // if its a directory, make dir in dst
+ if info.IsDir() {
+ err := os.MkdirAll(target, os.ModeDir|os.ModePerm)
+ if err != nil {
+ return err
+ }
+ } else {
+ // if its a file, copy file to dir of dst
+ err = copyFile(path, target)
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+ })
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// copyFile copies a file from src to dst. if src and dst files exist, and are
+// the same, then return success. Otherise, attempt to create a hard link
+// between the two files. If that fail, copy the file contents from src to dst.
+// thanks to Stack Overflow
+func copyFile(src, dst string) (err error) {
+ sfi, err := os.Stat(src)
+ if err != nil {
+ return
+ }
+ if !sfi.Mode().IsRegular() {
+ // cannot copy non-regular files (e.g., directories,
+ // symlinks, devices, etc.)
+ return fmt.Errorf("CopyFile: non-regular source file %s (%q)", sfi.Name(), sfi.Mode().String())
+ }
+ dfi, err := os.Stat(dst)
+ if err != nil {
+ if !os.IsNotExist(err) {
+ return
+ }
+ } else {
+ if !(dfi.Mode().IsRegular()) {
+ return fmt.Errorf("CopyFile: non-regular destination file %s (%q)", dfi.Name(), dfi.Mode().String())
+ }
+ if os.SameFile(sfi, dfi) {
+ return
+ }
+ }
+ if err = os.Link(src, dst); err == nil {
+ return
+ }
+ err = copyFileContents(src, dst)
+ return
+}
+
+// copyFileContents copies the contents of the file named src to the file named
+// by dst. The file will be created if it does not already exist. If the
+// destination file exists, all it's contents will be replaced by the contents
+// of the source file.
+// Thanks for Stack Overflow
+func copyFileContents(src, dst string) (err error) {
+ in, err := os.Open(src)
+ if err != nil {
+ return
+ }
+ defer in.Close()
+ out, err := os.Create(dst)
+ if err != nil {
+ return
+ }
+ defer func() {
+ cerr := out.Close()
+ if err == nil {
+ err = cerr
+ }
+ }()
+ if _, err = io.Copy(out, in); err != nil {
+ return
+ }
+ err = out.Sync()
+ return
+}
+
+// generic error return
func addError(err error) error {
return errors.New("Ponzu add failed. " + "\n" + err.Error())
}