You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2017/03/08 00:06:08 UTC

[4/5] incubator-mynewt-newt git commit: MYNEWT-495: updates to sync command

MYNEWT-495: updates to sync command

- When repo is already cloned, try to update from remote
- If -f is passed, create a modifications diff, and try harder
  to update current local (stash, clean, checkout, pull)


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/commit/a7c02356
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/a7c02356
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/a7c02356

Branch: refs/heads/1_0_0_dev
Commit: a7c0235607ab10427aab02f7631e1a451cf889cc
Parents: 934b3cc
Author: Fabio Utzig <ut...@utzig.org>
Authored: Fri Mar 3 09:49:52 2017 -0300
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Mar 7 16:00:35 2017 -0800

----------------------------------------------------------------------
 newt/cli/project_cmds.go                        |  23 ++-
 newt/downloader/downloader.go                   | 110 ++++++++++---
 newt/repo/repo.go                               | 157 +++++++++++++++++--
 newt/vendor/mynewt.apache.org/newt/util/util.go |   1 -
 4 files changed, 247 insertions(+), 44 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/a7c02356/newt/cli/project_cmds.go
----------------------------------------------------------------------
diff --git a/newt/cli/project_cmds.go b/newt/cli/project_cmds.go
index a8d93b2..89a6eae 100644
--- a/newt/cli/project_cmds.go
+++ b/newt/cli/project_cmds.go
@@ -20,6 +20,7 @@
 package cli
 
 import (
+	"fmt"
 	"os"
 	"sort"
 	"strings"
@@ -156,26 +157,32 @@ func syncRunCmd(cmd *cobra.Command, args []string) {
 		NewtUsage(nil, err)
 	}
 
+	var failedRepos []string
 	for _, repo := range repos {
 		var exists bool
+		var updated bool
 		if repo.IsLocal() {
 			continue
 		}
 		vers := ps.GetInstalledVersion(repo.Name())
 		if vers == nil {
 			util.StatusMessage(util.VERBOSITY_DEFAULT,
-				"No installed version of %s found, skipping\n",
+				"No installed version of %s found, skipping\n\n",
 				repo.Name())
 		}
-		if err, exists = repo.Sync(vers, newtutil.NewtForce); err != nil {
-			NewtUsage(nil, err)
+		exists, updated, err = repo.Sync(vers, newtutil.NewtForce)
+		if exists && !updated {
+			failedRepos = append(failedRepos, repo.Name())
 		}
-
-		if exists && !newtutil.NewtForce {
-			util.StatusMessage(util.VERBOSITY_DEFAULT,
-				"Skipping resync of %s because directory exists.  To "+
-					"force resync, add the -f (force) option.\n", repo.Name())
+	}
+	if len(failedRepos) > 0 {
+		var forceMsg string
+		if !newtutil.NewtForce {
+			forceMsg = " To force resync, add the -f (force) option."
 		}
+		err = util.NewNewtError(fmt.Sprintf("Failed for repos: %v."+
+			forceMsg, failedRepos))
+		NewtUsage(nil, err)
 	}
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/a7c02356/newt/downloader/downloader.go
----------------------------------------------------------------------
diff --git a/newt/downloader/downloader.go b/newt/downloader/downloader.go
index 0ab201e..e57ecfa 100644
--- a/newt/downloader/downloader.go
+++ b/newt/downloader/downloader.go
@@ -27,6 +27,7 @@ import (
 	"os"
 	"os/exec"
 	"path/filepath"
+	"strings"
 
 	log "github.com/Sirupsen/logrus"
 
@@ -39,6 +40,10 @@ type Downloader interface {
 	Branch() string
 	SetBranch(branch string)
 	DownloadRepo(branch string) (string, error)
+	CurrentBranch(path string) (string, error)
+	UpdateRepo(path string) error
+	CleanupRepo(path string, branchName string) error
+	LocalDiff(path string) ([]byte, error)
 }
 
 type GenericDownloader struct {
@@ -66,42 +71,57 @@ type LocalDownloader struct {
 	Path string
 }
 
-func checkout(repoDir string, commit string) error {
-	// Retrieve the current directory so that we can get back to where we
-	// started after the download completes.
-	pwd, err := os.Getwd()
+func executeGitCommand(dir string, cmd []string) ([]byte, error) {
+	wd, err := os.Getwd()
 	if err != nil {
-		return util.NewNewtError(err.Error())
+		return nil, util.NewNewtError(err.Error())
 	}
 
 	gitPath, err := exec.LookPath("git")
 	if err != nil {
-		return util.NewNewtError(fmt.Sprintf("Can't find git binary: %s\n",
+		return nil, util.NewNewtError(fmt.Sprintf("Can't find git binary: %s\n",
 			err.Error()))
 	}
 	gitPath = filepath.ToSlash(gitPath)
 
-	if err := os.Chdir(repoDir); err != nil {
-		return util.NewNewtError(err.Error())
+	if err := os.Chdir(dir); err != nil {
+		return nil, util.NewNewtError(err.Error())
 	}
 
-	// Checkout the specified commit.
+	defer os.Chdir(wd)
+
+	gitCmd := []string{gitPath}
+	gitCmd = append(gitCmd, cmd...)
+	output, err := util.ShellCommand(gitCmd, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	return output, nil
+}
+
+func checkout(repoDir string, commit string) error {
 	cmd := []string{
-		gitPath,
 		"checkout",
 		commit,
 	}
+	_, err := executeGitCommand(repoDir, cmd)
+	return err
+}
 
-	if o, err := util.ShellCommand(cmd, nil); err != nil {
-		return util.NewNewtError(string(o))
-	}
+func pull(repoDir string) error {
+	_, err := executeGitCommand(repoDir, []string{"pull"})
+	return err
+}
 
-	// Go back to original directory.
-	if err := os.Chdir(pwd); err != nil {
-		return util.NewNewtError(err.Error())
-	}
+func stash(repoDir string) error {
+	_, err := executeGitCommand(repoDir, []string{"stash"})
+	return err
+}
 
-	return nil
+func clean(repoDir string) error {
+	_, err := executeGitCommand(repoDir, []string{"clean", "-f"})
+	return err
 }
 
 func (gd *GenericDownloader) Branch() string {
@@ -172,6 +192,39 @@ func (gd *GithubDownloader) FetchFile(name string, dest string) error {
 	return nil
 }
 
+func (gd *GithubDownloader) CurrentBranch(path string) (string, error) {
+	cmd := []string{"rev-parse", "--abbrev-ref", "HEAD"}
+	branch, err := executeGitCommand(path, cmd)
+	return strings.Trim(string(branch), "\r\n"), err
+}
+
+func (gd *GithubDownloader) UpdateRepo(path string) error {
+	return pull(path)
+}
+
+func (gd *GithubDownloader) CleanupRepo(path string, branchName string) error {
+	err := stash(path)
+	if err != nil {
+		return err
+	}
+
+	err = clean(path)
+	if err != nil {
+		return err
+	}
+
+	err = checkout(path, branchName)
+	if err != nil {
+		return err
+	}
+
+	return pull(path)
+}
+
+func (gd *GithubDownloader) LocalDiff(path string) ([]byte, error) {
+	return executeGitCommand(path, []string{"diff"})
+}
+
 func (gd *GithubDownloader) DownloadRepo(commit string) (string, error) {
 	// Get a temporary directory, and copy the repository into that directory.
 	tmpdir, err := ioutil.TempDir("", "newt-repo")
@@ -243,6 +296,27 @@ func (ld *LocalDownloader) FetchFile(name string, dest string) error {
 	return nil
 }
 
+func (ld *LocalDownloader) CurrentBranch(path string) (string, error) {
+	cmd := []string{"rev-parse", "--abbrev-ref", "HEAD"}
+	branch, err := executeGitCommand(path, cmd)
+	return strings.Trim(string(branch), "\r\n"), err
+}
+
+// NOTE: intentionally always error...
+func (ld *LocalDownloader) UpdateRepo(path string) error {
+	return util.NewNewtError(fmt.Sprintf("Can't pull from a local repo\n"))
+}
+
+func (ld *LocalDownloader) CleanupRepo(path string, branchName string) error {
+	os.RemoveAll(path)
+	_, err := ld.DownloadRepo(branchName)
+	return err
+}
+
+func (ld *LocalDownloader) LocalDiff(path string) ([]byte, error) {
+	return executeGitCommand(path, []string{"diff"})
+}
+
 func (ld *LocalDownloader) DownloadRepo(commit string) (string, error) {
 	// Get a temporary directory, and copy the repository into that directory.
 	tmpdir, err := ioutil.TempDir("", "newt-repo")

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/a7c02356/newt/repo/repo.go
----------------------------------------------------------------------
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index a2b98c9..316b274 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -25,6 +25,7 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"time"
 
 	log "github.com/Sirupsen/logrus"
 	"github.com/spf13/cast"
@@ -345,6 +346,11 @@ func (r *Repo) repoFilePath() string {
 		".configs/" + r.name + "/"
 }
 
+func (r *Repo) patchesFilePath() string {
+	return interfaces.GetProject().Path() + "/" + REPOS_DIR +
+		"/.patches/"
+}
+
 func (r *Repo) downloadRepo(branchName string) error {
 	dl := r.downloader
 
@@ -366,6 +372,66 @@ func (r *Repo) downloadRepo(branchName string) error {
 	return nil
 }
 
+func (r *Repo) checkExists() bool {
+	return util.NodeExist(r.Path())
+}
+
+func (r *Repo) updateRepo() error {
+	dl := r.downloader
+	err := dl.UpdateRepo(r.Path())
+	if err != nil {
+		return util.NewNewtError(fmt.Sprintf("\tError updating\n"))
+	}
+	return nil
+}
+
+func (r *Repo) cleanupRepo(branchName string) error {
+	dl := r.downloader
+	err := dl.CleanupRepo(r.Path(), branchName)
+	if err != nil {
+		return util.NewNewtError(fmt.Sprintf("\tError cleaning and updating\n"))
+	}
+	return nil
+}
+
+func (r *Repo) saveLocalDiff() (string, error) {
+	dl := r.downloader
+	diff, err := dl.LocalDiff(r.Path())
+	if err != nil {
+		return "", util.NewNewtError(fmt.Sprintf(
+			"Error creating diff for \"%s\" : %s", r.Name(), err.Error()))
+	}
+
+	// NOTE: date was not a typo: https://golang.org/pkg/time/#Time.Format
+	timenow := time.Now().Format("20060102_150405")
+	filename := r.patchesFilePath() + r.Name() + "_" + timenow + ".diff"
+
+	f, err := os.Create(filename)
+	if err != nil {
+		return "", util.NewNewtError(fmt.Sprintf(
+			"Error creating repo diff file \"%s\"", filename))
+	}
+	defer f.Close()
+
+	_, err = f.Write(diff)
+	if err != nil {
+		return "", util.NewNewtError(fmt.Sprintf(
+			"Error writing repo diff file \"%s\"", filename))
+	}
+
+	return filename, nil
+}
+
+func (r *Repo) currentBranch() (string, error) {
+	dl := r.downloader
+	branch, err := dl.CurrentBranch(r.Path())
+	if err != nil {
+		return "", util.NewNewtError(fmt.Sprintf("Error finding current branch for \"%s\" : %s",
+			r.Name(), err.Error()))
+	}
+	return branch, nil
+}
+
 func (r *Repo) checkForceInstall(force bool) (error, bool) {
 	// Copy the git repo into /repos/, error'ing out if the repo already exists
 	if util.NodeExist(r.Path()) {
@@ -405,33 +471,82 @@ func (r *Repo) Install(force bool) (*Version, error) {
 	return vers, nil
 }
 
-func (r *Repo) Sync(vers *Version, force bool) (error, bool) {
+func (r *Repo) Sync(vers *Version, force bool) (bool, bool, error) {
 	var exists bool
 	var err error
+	var currBranch string
 
-	if err, exists = r.checkForceInstall(force); err != nil {
-		return err, exists
-	}
-	if exists && !force {
-		return nil, exists
-	}
+	exists = r.checkExists()
 
 	// Update the repo description
 	if _, updated, err := r.UpdateDesc(); updated != true || err != nil {
-		return util.NewNewtError("Cannot update repository description."), exists
+		return exists, false, util.NewNewtError("Cannot update repository description.")
 	}
 
-	branchName, vers, found := r.rdesc.MatchVersion(vers)
+	branchName, _, found := r.rdesc.MatchVersion(vers)
 	if found == false {
-		return util.NewNewtError(fmt.Sprintf("Branch description for %s not found",
-			r.Name())), exists
+		return exists, false, util.NewNewtError(fmt.Sprintf(
+			"Branch description for %s not found", r.Name()))
 	}
 
-	if err := r.downloadRepo(branchName); err != nil {
-		return err, exists
+	if exists {
+		// Here assuming that if the branch was changed by the user,
+		// the user must know what he's doing...
+		// but, if -f is passed let's just save the work and re-clone
+		currBranch, err = r.currentBranch()
+		if err != nil {
+			return exists, false, err
+		} else if currBranch != branchName {
+			msg := "Unexpected local branch for %s: \"%s\" != \"%s\""
+			if force {
+				util.StatusMessage(util.VERBOSITY_VERBOSE,
+					msg, r.rdesc.name, currBranch, branchName)
+			} else {
+				err = util.NewNewtError(
+					fmt.Sprintf(msg, r.rdesc.name, currBranch, branchName))
+				return exists, false, err
+			}
+		}
+
+		// Don't try updating if on an invalid branch...
+		if currBranch == branchName {
+			util.StatusMessage(util.VERBOSITY_VERBOSE, "\tTrying to update repository... ")
+			err = r.updateRepo()
+			if err == nil {
+				util.StatusMessage(util.VERBOSITY_VERBOSE, " success!\n")
+				return exists, true, err
+			} else {
+				util.StatusMessage(util.VERBOSITY_VERBOSE, " failed!\n")
+				if !force {
+					return exists, false, err
+				}
+			}
+		}
+
+		filename, err := r.saveLocalDiff()
+		if err != nil {
+			return exists, false, err
+		}
+		wd, _ := os.Getwd()
+		filename, _ = filepath.Rel(wd, filename)
+
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "Saved local diff: "+
+			"\"%s\"\n", filename)
+
+		err = r.cleanupRepo(branchName)
+		if err != nil {
+			return exists, false, err
+		}
+
+	} else {
+		// fresh or updating was unsuccessfull and force was given...
+		err = r.downloadRepo(branchName)
+		if err != nil {
+			return exists, false, err
+		}
 	}
 
-	return nil, exists
+	return exists, true, nil
 }
 
 func (r *Repo) UpdateDesc() ([]*Repo, bool, error) {
@@ -441,7 +556,7 @@ func (r *Repo) UpdateDesc() ([]*Repo, bool, error) {
 		return nil, false, nil
 	}
 
-	util.StatusMessage(util.VERBOSITY_DEFAULT, "%s\n", r.Name())
+	util.StatusMessage(util.VERBOSITY_VERBOSE, "[%s]:\n", r.Name())
 
 	if err = r.DownloadDesc(); err != nil {
 		return nil, false, err
@@ -461,8 +576,8 @@ func (r *Repo) UpdateDesc() ([]*Repo, bool, error) {
 func (r *Repo) DownloadDesc() error {
 	dl := r.downloader
 
-	util.StatusMessage(util.VERBOSITY_VERBOSE, "Downloading "+
-		"repository description for %s...\n", r.Name())
+	util.StatusMessage(util.VERBOSITY_VERBOSE, "\tDownloading "+
+		"repository description... ")
 
 	// Configuration path
 	cpath := r.repoFilePath()
@@ -479,6 +594,14 @@ func (r *Repo) DownloadDesc() error {
 		return err
 	}
 
+	// also create a directory to save diffs for sync
+	cpath = r.patchesFilePath()
+	if util.NodeNotExist(cpath) {
+		if err := os.MkdirAll(cpath, REPO_DEFAULT_PERMS); err != nil {
+			return util.NewNewtError(err.Error())
+		}
+	}
+
 	util.StatusMessage(util.VERBOSITY_VERBOSE, " success!\n")
 
 	return nil

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/a7c02356/newt/vendor/mynewt.apache.org/newt/util/util.go
----------------------------------------------------------------------
diff --git a/newt/vendor/mynewt.apache.org/newt/util/util.go b/newt/vendor/mynewt.apache.org/newt/util/util.go
index fa3e60f..083ee9c 100644
--- a/newt/vendor/mynewt.apache.org/newt/util/util.go
+++ b/newt/vendor/mynewt.apache.org/newt/util/util.go
@@ -300,7 +300,6 @@ func ShellCommandLimitDbgOutput(
 	}
 
 	o, err := cmd.CombinedOutput()
-
 	if maxDbgOutputChrs < 0 || len(o) <= maxDbgOutputChrs {
 		dbgStr := string(o)
 		log.Debugf("o=%s", dbgStr)