Updates to sync/upgrade/install inner working

- sync now creates a new branch when checking out a tag commit
- sync flow now:
  1) stash changes
  2) fetch branchs/tags from origin
  3) merges in changes on master and develop
  4) checks out old branch or new branch (creating if necessary)
  5) stash pops if the previous stash was succesful
- upgrade/install now try first to cleanup and existing repo and if it
  fails do the old style remove+clone.


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/0418ceab
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/0418ceab
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/0418ceab

Branch: refs/heads/master
Commit: 0418ceab007a703ca86652adb7455958d5eac24b
Parents: 0196ba5
Author: Fabio Utzig <[email protected]>
Authored: Tue Mar 7 11:33:01 2017 -0300
Committer: Fabio Utzig <[email protected]>
Committed: Tue Mar 7 11:33:01 2017 -0300

----------------------------------------------------------------------
 newt/downloader/downloader.go | 116 +++++++++++++++++++++++++++++++------
 newt/repo/repo.go             |  78 ++++++++++++-------------
 2 files changed, 138 insertions(+), 56 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0418ceab/newt/downloader/downloader.go
----------------------------------------------------------------------
diff --git a/newt/downloader/downloader.go b/newt/downloader/downloader.go
index e57ecfa..c8e13c6 100644
--- a/newt/downloader/downloader.go
+++ b/newt/downloader/downloader.go
@@ -41,7 +41,7 @@ type Downloader interface {
        SetBranch(branch string)
        DownloadRepo(branch string) (string, error)
        CurrentBranch(path string) (string, error)
-       UpdateRepo(path string) error
+       UpdateRepo(path string, branchName string) error
        CleanupRepo(path string, branchName string) error
        LocalDiff(path string) ([]byte, error)
 }
@@ -100,22 +100,86 @@ func executeGitCommand(dir string, cmd []string) ([]byte, 
error) {
        return output, nil
 }
 
+func isTag(repoDir string, branchName string) bool {
+       cmd := []string{"tag", "--list"}
+       output, _ := executeGitCommand(repoDir, cmd)
+       return strings.Contains(string(output), branchName)
+}
+
+func branchExists(repoDir string, branchName string) bool {
+       cmd := []string{"show-ref", "--verify", "--quiet", "refs/heads/" + 
branchName}
+       _, err := executeGitCommand(repoDir, cmd)
+       return err == nil
+}
+
+// checkout does checkout a branch, or create a new branch from a tag name
+// if the commit supplied is a tag. sha1 based commits have no special
+// handling and result in dettached from HEAD state.
 func checkout(repoDir string, commit string) error {
-       cmd := []string{
-               "checkout",
-               commit,
+       var cmd []string
+       if isTag(repoDir, commit) && !branchExists(repoDir, commit) {
+               util.StatusMessage(util.VERBOSITY_VERBOSE, "Will create new 
branch %s"+
+                       " from tag %s\n", commit, "tags/"+commit)
+               cmd = []string{
+                       "checkout",
+                       "tags/" + commit,
+                       "-b",
+                       commit,
+               }
+       } else {
+               util.StatusMessage(util.VERBOSITY_VERBOSE, "Will checkout 
branch %s\n",
+                       commit)
+               cmd = []string{
+                       "checkout",
+                       commit,
+               }
        }
        _, err := executeGitCommand(repoDir, cmd)
        return err
 }
 
-func pull(repoDir string) error {
-       _, err := executeGitCommand(repoDir, []string{"pull"})
+// mergeBranches applies upstream changes to the local copy and must be
+// preceeded by a "fetch" to achieve any meaningful result.
+func mergeBranches(repoDir string) {
+       branches := []string{"master", "develop"}
+       for _, branch := range branches {
+               err := checkout(repoDir, branch)
+               if err != nil {
+                       continue
+               }
+               _, err = executeGitCommand(repoDir, []string{"merge", "origin/" 
+ branch})
+               if err != nil {
+                       util.StatusMessage(util.VERBOSITY_VERBOSE, "Merging 
changes from origin/%s: %s\n",
+                               branch, err)
+               } else {
+                       util.StatusMessage(util.VERBOSITY_VERBOSE, "Merging 
changes from origin/%s\n",
+                               branch)
+               }
+               // XXX: ignore error, probably resulting from a branch not 
available at
+               //      origin anymore.
+       }
+}
+
+func fetch(repoDir string) error {
+       util.StatusMessage(util.VERBOSITY_VERBOSE, "Fetching new remote 
branches/tags\n")
+       _, err := executeGitCommand(repoDir, []string{"fetch", "--tags"})
        return err
 }
 
-func stash(repoDir string) error {
-       _, err := executeGitCommand(repoDir, []string{"stash"})
+// stash saves current changes locally and returns if a new stash was
+// created (if there where no changes, there's no need to stash)
+func stash(repoDir string) (bool, error) {
+       util.StatusMessage(util.VERBOSITY_VERBOSE, "Stashing local changes\n")
+       output, err := executeGitCommand(repoDir, []string{"stash"})
+       if err != nil {
+               return false, err
+       }
+       return strings.Contains(string(output), "Saved"), nil
+}
+
+func stashPop(repoDir string) error {
+       util.StatusMessage(util.VERBOSITY_VERBOSE, "Un-stashing local 
changes\n")
+       _, err := executeGitCommand(repoDir, []string{"stash", "pop"})
        return err
 }
 
@@ -198,27 +262,45 @@ func (gd *GithubDownloader) CurrentBranch(path string) 
(string, error) {
        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)
+func (gd *GithubDownloader) UpdateRepo(path string, branchName string) error {
+       err := fetch(path)
        if err != nil {
                return err
        }
 
-       err = clean(path)
+       stashed, err := stash(path)
        if err != nil {
                return err
        }
 
+       mergeBranches(path)
+
        err = checkout(path, branchName)
        if err != nil {
                return err
        }
 
-       return pull(path)
+       if stashed {
+               return stashPop(path)
+       }
+
+       return nil
+}
+
+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
+       }
+
+       // TODO: needs handling of non-tracked files
+
+       return gd.UpdateRepo(path, branchName)
 }
 
 func (gd *GithubDownloader) LocalDiff(path string) ([]byte, error) {
@@ -303,7 +385,7 @@ func (ld *LocalDownloader) CurrentBranch(path string) 
(string, error) {
 }
 
 // NOTE: intentionally always error...
-func (ld *LocalDownloader) UpdateRepo(path string) error {
+func (ld *LocalDownloader) UpdateRepo(path string, branchName string) error {
        return util.NewNewtError(fmt.Sprintf("Can't pull from a local repo\n"))
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/0418ceab/newt/repo/repo.go
----------------------------------------------------------------------
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index a4a916f..139c499 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -378,11 +378,11 @@ func (r *Repo) checkExists() bool {
        return util.NodeExist(r.Path())
 }
 
-func (r *Repo) updateRepo() error {
+func (r *Repo) updateRepo(branchName string) error {
        dl := r.downloader
-       err := dl.UpdateRepo(r.Path())
+       err := dl.UpdateRepo(r.Path(), branchName)
        if err != nil {
-               return util.NewNewtError(fmt.Sprintf("\tError updating\n"))
+               return util.NewNewtError(fmt.Sprintf("Error updating\n"))
        }
        return nil
 }
@@ -391,7 +391,7 @@ 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 util.NewNewtError(fmt.Sprintf("Error cleaning and 
updating\n"))
        }
        return nil
 }
@@ -431,33 +431,15 @@ func (r *Repo) currentBranch() (string, error) {
                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()) {
-               if force {
-                       if err := os.RemoveAll(r.Path()); err != nil {
-                               return util.NewNewtError(err.Error()), true
-                       }
-               }
-               return nil, true
-       }
-       return nil, false
+       return filepath.Base(branch), nil
 }
 
 func (r *Repo) Install(force bool) (*Version, error) {
-       if err, exists := r.checkForceInstall(force); err != nil || exists {
-               if err == nil {
-                       if !force {
-                               return nil, util.NewNewtError(fmt.Sprintf(
-                                       "Repository %s already exists, provide 
the -f option "+
-                                               "to overwrite", r.Name()))
-                       }
-               } else {
-                       return nil, err
-               }
+       exists := util.NodeExist(r.Path())
+       if exists && !force {
+               return nil, util.NewNewtError(fmt.Sprintf(
+                       "Repository %s already exists, provide the -f option "+
+                               "to overwrite", r.Name()))
        }
 
        branchName, vers, found := r.rdesc.Match(r)
@@ -466,6 +448,20 @@ func (r *Repo) Install(force bool) (*Version, error) {
                        r.rdesc.String()))
        }
 
+       // if the repo is already cloned, try to cleanup and checkout the 
requested branch
+       if exists {
+               err := r.cleanupRepo(branchName)
+               if err == nil {
+                       return vers, nil
+               }
+
+               // cleanup failed, so remove current copy and let download 
clone again...
+               if err := os.RemoveAll(r.Path()); err != nil {
+                       return nil, util.NewNewtError(err.Error())
+               }
+       }
+
+       // repo was not already cloned or cleanup failed...
        if err := r.downloadRepo(branchName); err != nil {
                return nil, err
        }
@@ -496,10 +492,13 @@ func (r *Repo) Sync(vers *Version, force bool) (bool, 
bool, error) {
                // 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()
+
+               // currBranch == HEAD means we're dettached from HEAD, so
+               // ignore and move to "new" tag
                if err != nil {
                        return exists, false, err
-               } else if currBranch != branchName {
-                       msg := "Unexpected local branch for %s: \"%s\" != 
\"%s\""
+               } else if currBranch != "HEAD" && currBranch != branchName {
+                       msg := "Unexpected local branch for %s: \"%s\" != 
\"%s\"\n"
                        if force {
                                util.StatusMessage(util.VERBOSITY_VERBOSE,
                                        msg, r.rdesc.name, currBranch, 
branchName)
@@ -511,14 +510,14 @@ func (r *Repo) Sync(vers *Version, force bool) (bool, 
bool, error) {
                }
 
                // 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 currBranch == "HEAD" || currBranch == branchName {
+                       util.StatusMessage(util.VERBOSITY_VERBOSE, "Updating 
repository...\n")
+                       err = r.updateRepo(branchName)
                        if err == nil {
-                               util.StatusMessage(util.VERBOSITY_VERBOSE, " 
success!\n")
+                               util.StatusMessage(util.VERBOSITY_VERBOSE, 
"Update successful!\n")
                                return exists, true, err
                        } else {
-                               util.StatusMessage(util.VERBOSITY_VERBOSE, " 
failed!\n")
+                               util.StatusMessage(util.VERBOSITY_VERBOSE, 
"Update failed!\n")
                                if !force {
                                        return exists, false, err
                                }
@@ -566,6 +565,7 @@ func (r *Repo) UpdateDesc() ([]*Repo, bool, error) {
 
        _, repos, err := r.ReadDesc()
        if err != nil {
+               fmt.Printf("ReadDesc: %v\n", err)
                return nil, false, err
        }
 
@@ -578,8 +578,8 @@ func (r *Repo) UpdateDesc() ([]*Repo, bool, error) {
 func (r *Repo) DownloadDesc() error {
        dl := r.downloader
 
-       util.StatusMessage(util.VERBOSITY_VERBOSE, "\tDownloading "+
-               "repository description... ")
+       util.StatusMessage(util.VERBOSITY_VERBOSE, "Downloading "+
+               "repository description\n")
 
        // Configuration path
        cpath := r.repoFilePath()
@@ -592,7 +592,7 @@ func (r *Repo) DownloadDesc() error {
        dl.SetBranch("master")
        if err := dl.FetchFile("repository.yml",
                cpath+"/"+"repository.yml"); err != nil {
-               util.StatusMessage(util.VERBOSITY_VERBOSE, " failed\n")
+               util.StatusMessage(util.VERBOSITY_VERBOSE, "Download failed\n")
                return err
        }
 
@@ -604,7 +604,7 @@ func (r *Repo) DownloadDesc() error {
                }
        }
 
-       util.StatusMessage(util.VERBOSITY_VERBOSE, " success!\n")
+       util.StatusMessage(util.VERBOSITY_VERBOSE, "Download successful!\n")
 
        return nil
 }

Reply via email to