You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by GitBox <gi...@apache.org> on 2017/10/26 18:49:35 UTC

[GitHub] ccollins476ad closed pull request #103: Newt - Generic git repositories

ccollins476ad closed pull request #103: Newt - Generic git repositories
URL: https://github.com/apache/mynewt-newt/pull/103
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/newt/cli/project_cmds.go b/newt/cli/project_cmds.go
index 5cac6af..7716556 100644
--- a/newt/cli/project_cmds.go
+++ b/newt/cli/project_cmds.go
@@ -20,7 +20,6 @@
 package cli
 
 import (
-	"fmt"
 	"os"
 	"sort"
 	"strings"
@@ -77,7 +76,7 @@ func installRunCmd(cmd *cobra.Command, args []string) {
 	interfaces.SetProject(proj)
 
 	if err := proj.Install(false, newtutil.NewtForce); err != nil {
-		NewtUsage(cmd, err)
+		NewtUsage(nil, err)
 	}
 }
 
@@ -86,7 +85,7 @@ func upgradeRunCmd(cmd *cobra.Command, args []string) {
 	interfaces.SetProject(proj)
 
 	if err := proj.Upgrade(newtutil.NewtForce); err != nil {
-		NewtUsage(cmd, err)
+		NewtUsage(nil, err)
 	}
 }
 
@@ -157,31 +156,31 @@ func syncRunCmd(cmd *cobra.Command, args []string) {
 		NewtUsage(nil, err)
 	}
 
-	var failedRepos []string
+	var anyFails bool
 	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\n",
+				"No installed version of %s found, skipping\n",
 				repo.Name())
-		}
-		exists, updated, err = repo.Sync(vers, newtutil.NewtForce)
-		if exists && !updated {
-			failedRepos = append(failedRepos, repo.Name())
+		} else {
+			if _, err := repo.Sync(vers, newtutil.NewtForce); err != nil {
+				util.StatusMessage(util.VERBOSITY_QUIET,
+					"Failed to sync repo \"%s\": %s\n",
+					repo.Name(), err.Error())
+				anyFails = true
+			}
 		}
 	}
-	if len(failedRepos) > 0 {
+	if anyFails {
 		var forceMsg string
 		if !newtutil.NewtForce {
-			forceMsg = " To force resync, add the -f (force) option."
+			forceMsg = ".  To force resync, add the -f (force) option."
 		}
-		err = util.NewNewtError(fmt.Sprintf("Failed for repos: %v."+
-			forceMsg, failedRepos))
+		err := util.FmtNewtError("Failed to sync%s", forceMsg)
 		NewtUsage(nil, err)
 	}
 }
diff --git a/newt/downloader/downloader.go b/newt/downloader/downloader.go
index e490a8d..471dfb8 100644
--- a/newt/downloader/downloader.go
+++ b/newt/downloader/downloader.go
@@ -21,9 +21,7 @@ package downloader
 
 import (
 	"fmt"
-	"io"
 	"io/ioutil"
-	"net/http"
 	"os"
 	"os/exec"
 	"path/filepath"
@@ -36,7 +34,7 @@ import (
 )
 
 type Downloader interface {
-	FetchFile(name string, dest string) error
+	FetchFile(path string, filename string, dstDir string) error
 	Branch() string
 	SetBranch(branch string)
 	DownloadRepo(branch string) (string, error)
@@ -44,10 +42,14 @@ type Downloader interface {
 	UpdateRepo(path string, branchName string) error
 	CleanupRepo(path string, branchName string) error
 	LocalDiff(path string) ([]byte, error)
+	AreChanges(path string) (bool, error)
 }
 
 type GenericDownloader struct {
 	branch string
+
+	// Whether 'origin' has been fetched during this run.
+	fetched bool
 }
 
 type GithubDownloader struct {
@@ -67,6 +69,11 @@ type GithubDownloader struct {
 	PasswordEnv string
 }
 
+type GitDownloader struct {
+	GenericDownloader
+	Url string
+}
+
 type LocalDownloader struct {
 	GenericDownloader
 
@@ -156,25 +163,23 @@ func checkout(repoDir string, commit string) error {
 
 // 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}, true)
-		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 mergeBranch(repoDir string, branch string) error {
+	if err := checkout(repoDir, branch); err != nil {
+		return err
+	}
+
+	fullName := "origin/" + branch
+	if _, err := executeGitCommand(
+		repoDir, []string{"merge", fullName}, true); err != nil {
+
+		util.StatusMessage(util.VERBOSITY_VERBOSE,
+			"Merging changes from %s: %s\n", fullName, err)
+		return err
 	}
+
+	util.StatusMessage(util.VERBOSITY_VERBOSE,
+		"Merging changes from %s\n", fullName)
+	return nil
 }
 
 // stash saves current changes locally and returns if a new stash was
@@ -199,6 +204,50 @@ func clean(repoDir string) error {
 	return err
 }
 
+func diff(repoDir string) ([]byte, error) {
+	return executeGitCommand(repoDir, []string{"diff"}, true)
+}
+
+func areChanges(repoDir string) (bool, error) {
+	cmd := []string{
+		"diff",
+		"--name-only",
+	}
+
+	o, err := executeGitCommand(repoDir, cmd, true)
+	if err != nil {
+		return false, err
+	}
+
+	return len(o) > 0, nil
+}
+
+func showFile(
+	path string, branch string, filename string, dstDir string) error {
+
+	if err := os.MkdirAll(dstDir, os.ModePerm); err != nil {
+		return util.ChildNewtError(err)
+	}
+
+	cmd := []string{
+		"show",
+		fmt.Sprintf("origin/%s:%s", branch, filename),
+	}
+
+	dstPath := fmt.Sprintf("%s/%s", dstDir, filename)
+	log.Debugf("Fetching file %s to %s", filename, dstPath)
+	data, err := executeGitCommand(path, cmd, true)
+	if err != nil {
+		return err
+	}
+
+	if err := ioutil.WriteFile(dstPath, data, os.ModePerm); err != nil {
+		return util.ChildNewtError(err)
+	}
+
+	return nil
+}
+
 func (gd *GenericDownloader) Branch() string {
 	return gd.branch
 }
@@ -207,16 +256,29 @@ func (gd *GenericDownloader) SetBranch(branch string) {
 	gd.branch = branch
 }
 
-func (gd *GenericDownloader) TempDir() (string, error) {
-	dir, err := ioutil.TempDir("", "newt-tmp")
-	return dir, err
+// Fetches the downloader's origin remote if it hasn't been fetched yet during
+// this run.
+func (gd *GenericDownloader) cachedFetch(fn func() error) error {
+	if gd.fetched {
+		return nil
+	}
+
+	if err := fn(); err != nil {
+		return err
+	}
+
+	gd.fetched = true
+	return nil
 }
 
 func (gd *GithubDownloader) fetch(repoDir string) error {
-	util.StatusMessage(util.VERBOSITY_VERBOSE,
-		"Fetching new remote branches/tags\n")
-	_, err := gd.authenticatedCommand(repoDir, []string{"fetch", "--tags"})
-	return err
+	return gd.cachedFetch(func() error {
+		util.StatusMessage(util.VERBOSITY_VERBOSE,
+			"Fetching new remote branches/tags\n")
+
+		_, err := gd.authenticatedCommand(repoDir, []string{"fetch", "--tags"})
+		return err
+	})
 }
 
 func (gd *GithubDownloader) password() string {
@@ -240,57 +302,16 @@ func (gd *GithubDownloader) authenticatedCommand(path string,
 	return executeGitCommand(path, args, true)
 }
 
-func (gd *GithubDownloader) FetchFile(name string, dest string) error {
-	var url string
-	if gd.Server != "" {
-		// Use the github API
-		url = fmt.Sprintf("https://%s/api/v3/repos/%s/%s/%s?ref=%s",
-			gd.Server, gd.User, gd.Repo, name, gd.Branch())
-	} else {
-		// The public github API is ratelimited. Avoid rate limit issues with
-		// the raw endpoint.
-		url = fmt.Sprintf("https://raw.githubusercontent.com/%s/%s/%s/%s",
-			gd.User, gd.Repo, gd.Branch(), name)
-	}
+func (gd *GithubDownloader) FetchFile(
+	path string, filename string, dstDir string) error {
 
-	req, err := http.NewRequest("GET", url, nil)
-	req.Header.Add("Accept", "application/vnd.github.v3.raw")
-
-	pw := gd.password()
-	if pw != "" {
-		// XXX: Add command line option to include password in log.
-		log.Debugf("Using basic auth; login=%s", gd.Login)
-		req.SetBasicAuth(gd.Login, pw)
-	}
-
-	log.Debugf("Fetching file %s (url: %s) to %s", name, url, dest)
-	client := &http.Client{}
-	rsp, err := client.Do(req)
-	if err != nil {
-		return util.NewNewtError(err.Error())
-	}
-	defer rsp.Body.Close()
-
-	if rsp.StatusCode != http.StatusOK {
-		errMsg := fmt.Sprintf("Failed to download '%s'; status=%s",
-			url, rsp.Status)
-		switch rsp.StatusCode {
-		case http.StatusNotFound:
-			errMsg += "; URL incorrect or repository private?"
-		case http.StatusUnauthorized:
-			errMsg += "; credentials incorrect?"
-		}
-
-		return util.NewNewtError(errMsg)
+	if err := gd.fetch(path); err != nil {
+		return err
 	}
 
-	handle, err := os.Create(dest)
-	if err != nil {
-		return util.NewNewtError(err.Error())
+	if err := showFile(path, gd.Branch(), filename, dstDir); err != nil {
+		return err
 	}
-	defer handle.Close()
-
-	_, err = io.Copy(handle, rsp.Body)
 
 	return nil
 }
@@ -312,7 +333,9 @@ func (gd *GithubDownloader) UpdateRepo(path string, branchName string) error {
 		return err
 	}
 
-	mergeBranches(path)
+	// Ignore error, probably resulting from a branch not available at origin
+	// anymore.
+	mergeBranch(path, branchName)
 
 	err = checkout(path, branchName)
 	if err != nil {
@@ -343,7 +366,11 @@ func (gd *GithubDownloader) CleanupRepo(path string, branchName string) error {
 }
 
 func (gd *GithubDownloader) LocalDiff(path string) ([]byte, error) {
-	return executeGitCommand(path, []string{"diff"}, true)
+	return diff(path)
+}
+
+func (gd *GithubDownloader) AreChanges(path string) (bool, error) {
+	return areChanges(path)
 }
 
 func (gd *GithubDownloader) remoteUrls() (string, string) {
@@ -462,11 +489,145 @@ func NewGithubDownloader() *GithubDownloader {
 	return &GithubDownloader{}
 }
 
-func (ld *LocalDownloader) FetchFile(name string, dest string) error {
-	srcPath := ld.Path + "/" + name
+func (gd *GitDownloader) fetch(repoDir string) error {
+	return gd.cachedFetch(func() error {
+		util.StatusMessage(util.VERBOSITY_VERBOSE,
+			"Fetching new remote branches/tags\n")
+		_, err := executeGitCommand(repoDir, []string{"fetch", "--tags"}, true)
+		return err
+	})
+}
+
+func (gd *GitDownloader) FetchFile(
+	path string, filename string, dstDir string) error {
+
+	if err := gd.fetch(path); err != nil {
+		return err
+	}
 
-	log.Debugf("Fetching file %s to %s", srcPath, dest)
-	if err := util.CopyFile(srcPath, dest); err != nil {
+	if err := showFile(path, gd.Branch(), filename, dstDir); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func (gd *GitDownloader) CurrentBranch(path string) (string, error) {
+	cmd := []string{"rev-parse", "--abbrev-ref", "HEAD"}
+	branch, err := executeGitCommand(path, cmd, true)
+	return strings.Trim(string(branch), "\r\n"), err
+}
+
+func (gd *GitDownloader) UpdateRepo(path string, branchName string) error {
+	err := gd.fetch(path)
+	if err != nil {
+		return err
+	}
+
+	stashed, err := stash(path)
+	if err != nil {
+		return err
+	}
+
+	// Ignore error, probably resulting from a branch not available at origin
+	// anymore.
+	mergeBranch(path, branchName)
+
+	err = checkout(path, branchName)
+	if err != nil {
+		return err
+	}
+
+	if stashed {
+		return stashPop(path)
+	}
+
+	return nil
+}
+
+func (gd *GitDownloader) 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 *GitDownloader) LocalDiff(path string) ([]byte, error) {
+	return diff(path)
+}
+
+func (gd *GitDownloader) AreChanges(path string) (bool, error) {
+	return areChanges(path)
+}
+
+func (gd *GitDownloader) DownloadRepo(commit string) (string, error) {
+	// Currently only the master branch is supported.
+	branch := "master"
+
+	// Get a temporary directory, and copy the repository into that directory.
+	tmpdir, err := ioutil.TempDir("", "newt-repo")
+	if err != nil {
+		return "", err
+	}
+
+	util.StatusMessage(util.VERBOSITY_VERBOSE, "Downloading "+
+		"repository %s (branch: %s; commit: %s)\n", gd.Url, branch, commit)
+
+	gp, err := gitPath()
+	if err != nil {
+		return "", err
+	}
+
+	// Clone the repository.
+	cmd := []string{
+		gp,
+		"clone",
+		"-b",
+		branch,
+		gd.Url,
+		tmpdir,
+	}
+
+	if util.Verbosity >= util.VERBOSITY_VERBOSE {
+		err = util.ShellInteractiveCommand(cmd, nil)
+	} else {
+		_, err = util.ShellCommand(cmd, nil)
+	}
+	if err != nil {
+		os.RemoveAll(tmpdir)
+		return "", err
+	}
+
+	// Checkout the specified commit.
+	if err := checkout(tmpdir, commit); err != nil {
+		os.RemoveAll(tmpdir)
+		return "", err
+	}
+
+	return tmpdir, nil
+}
+
+func NewGitDownloader() *GitDownloader {
+	return &GitDownloader{}
+}
+
+func (ld *LocalDownloader) FetchFile(
+	path string, filename string, dstDir string) error {
+
+	srcPath := ld.Path + "/" + filename
+	dstPath := dstDir + "/" + filename
+
+	log.Debugf("Fetching file %s to %s", srcPath, dstPath)
+	if err := util.CopyFile(srcPath, dstPath); err != nil {
 		return err
 	}
 
@@ -491,7 +652,11 @@ func (ld *LocalDownloader) CleanupRepo(path string, branchName string) error {
 }
 
 func (ld *LocalDownloader) LocalDiff(path string) ([]byte, error) {
-	return executeGitCommand(path, []string{"diff"}, true)
+	return diff(path)
+}
+
+func (ld *LocalDownloader) AreChanges(path string) (bool, error) {
+	return areChanges(path)
 }
 
 func (ld *LocalDownloader) DownloadRepo(commit string) (string, error) {
@@ -555,6 +720,11 @@ func LoadDownloader(repoName string, repoVars map[string]string) (
 		}
 		return gd, nil
 
+	case "git":
+		gd := NewGitDownloader()
+		gd.Url = repoVars["url"]
+		return gd, nil
+
 	case "local":
 		ld := NewLocalDownloader()
 		ld.Path = repoVars["path"]
diff --git a/newt/project/project.go b/newt/project/project.go
index 4d524a8..6cc858b 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -25,6 +25,7 @@ import (
 	"os"
 	"path"
 	"path/filepath"
+	"sort"
 	"strings"
 
 	log "github.com/Sirupsen/logrus"
@@ -151,6 +152,21 @@ func (proj *Project) Repos() map[string]*repo.Repo {
 	return proj.repos
 }
 
+func (proj *Project) SortedRepos() []*repo.Repo {
+	names := make([]string, 0, len(proj.repos))
+	for n, _ := range proj.repos {
+		names = append(names, n)
+	}
+	sort.Strings(names)
+
+	repos := make([]*repo.Repo, len(names))
+	for i, n := range names {
+		repos[i] = proj.repos[n]
+	}
+
+	return repos
+}
+
 func (proj *Project) FindRepo(rname string) *repo.Repo {
 	if rname == repo.REPO_NAME_LOCAL {
 		return proj.LocalRepo()
@@ -177,8 +193,11 @@ func (proj *Project) Warnings() []string {
 	return proj.warnings
 }
 
+// @return bool                 True if upgrade should be skipped;
+//                              False if upgrade should occur.
 func (proj *Project) upgradeCheck(r *repo.Repo, vers *repo.Version,
 	force bool) (bool, error) {
+
 	rdesc, err := r.GetRepoDesc()
 	if err != nil {
 		return false, err
@@ -190,14 +209,14 @@ func (proj *Project) upgradeCheck(r *repo.Repo, vers *repo.Version,
 			"No matching version to upgrade to "+
 				"found for %s.  Please check your project requirements.",
 			r.Name())
-		return false, util.NewNewtError(fmt.Sprintf("Cannot find a "+
-			"version of repository %s that matches project requirements.",
-			r.Name()))
+		return false,
+			util.FmtNewtError("Cannot find a version of repository %s that "+
+				"matches project requirements.", r.Name())
 	}
 
-	// If the change between the old repository and the new repository would cause
-	// and upgrade.  Then prompt for an upgrade response, unless the force option
-	// is present.
+	// If the change between the old repository and the new repository would
+	// cause an upgrade.  Then prompt for an upgrade response, unless the force
+	// option is present.
 	if vers.CompareVersions(newVers, vers) != 0 ||
 		vers.Stability() != newVers.Stability() {
 		if !force {
@@ -206,7 +225,8 @@ func (proj *Project) upgradeCheck(r *repo.Repo, vers *repo.Version,
 				str += "(" + branch + ")"
 			}
 
-			fmt.Printf("Would you like to upgrade repository %s from %s to %s %s? [Yn] ",
+			fmt.Printf("Would you like to upgrade repository %s from %s "+
+				"to %s %s? [Yn] ",
 				r.Name(), vers.String(), newVers.String(), str)
 			line, more, err := bufio.NewReader(os.Stdin).ReadLine()
 			if more || err != nil {
@@ -232,7 +252,9 @@ func (proj *Project) upgradeCheck(r *repo.Repo, vers *repo.Version,
 	return false, nil
 }
 
-func (proj *Project) checkVersionRequirements(r *repo.Repo, upgrade bool, force bool) (bool, error) {
+func (proj *Project) checkVersionRequirements(
+	r *repo.Repo, upgrade bool, force bool) (bool, error) {
+
 	rdesc, err := r.GetRepoDesc()
 	if err != nil {
 		return false, err
@@ -244,15 +266,17 @@ func (proj *Project) checkVersionRequirements(r *repo.Repo, upgrade bool, force
 	if vers != nil {
 		ok := rdesc.SatisfiesVersion(vers, r.VersionRequirements())
 		if !ok && !upgrade {
-			util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: Installed "+
-				"version %s of repository %s does not match desired "+
-				"version %s in project file.  You can fix this by either upgrading"+
-				" your repository, or modifying the project.yml file.\n",
+			util.StatusMessage(util.VERBOSITY_QUIET,
+				"WARNING: Installed version %s of repository %s does not "+
+					"match desired version %s in project file.  You can fix "+
+					"this by either upgrading your repository, or modifying "+
+					"the project.yml file.\n",
 				vers, rname, r.VersionRequirementsString())
-			return true, err
+			return true, nil
 		} else {
 			if !upgrade {
-				util.StatusMessage(util.VERBOSITY_VERBOSE, "%s correct version already installed\n", r.Name())
+				util.StatusMessage(util.VERBOSITY_VERBOSE,
+					"%s correct version already installed\n", r.Name())
 				return true, nil
 			} else {
 				skip, err := proj.upgradeCheck(r, vers, force)
@@ -265,9 +289,10 @@ func (proj *Project) checkVersionRequirements(r *repo.Repo, upgrade bool, force
 		// that can satisfy.
 		_, _, ok := rdesc.Match(r)
 		if !ok {
-			fmt.Printf("WARNING: No matching repository version found for repository "+
-				"%s specified in project.\n", r.Name())
-			return true, err
+			util.StatusMessage(util.VERBOSITY_QUIET,
+				"WARNING: No matching repository version found for "+
+					"repository %s specified in project.\n", r.Name())
+			return true, nil
 		}
 	}
 
@@ -318,27 +343,43 @@ func (proj *Project) UpdateRepos() error {
 }
 
 func (proj *Project) Install(upgrade bool, force bool) error {
-	repoList := proj.Repos()
+	repoList := proj.SortedRepos()
 
-	for rname, _ := range repoList {
-		// Ignore the local repo on install
-		if rname == repo.REPO_NAME_LOCAL {
-			continue
+	var verb string
+	if upgrade {
+		verb = "upgraded"
+	} else {
+		verb = "installed"
+	}
+
+	// For a forced install, delete all existing repos.
+	if !upgrade && force {
+		for _, r := range repoList {
+			// Don't delete the local project directory!
+			if !r.IsLocal() {
+				util.StatusMessage(util.VERBOSITY_DEFAULT,
+					"Removing old copy of \"%s\" (%s)\n", r.Name(), r.Path())
+				os.RemoveAll(r.Path())
+				proj.projState.Delete(r.Name())
+			}
 		}
+	}
 
-		// First thing we do is update repository description.  This
-		// will get us available branches and versions in the repository.
-		if err := proj.UpdateRepos(); err != nil {
-			return err
-		}
+	// Fetch "origin" for all repos and copy the current version of
+	// `repository.yml`.
+	if err := proj.UpdateRepos(); err != nil {
+		return err
 	}
 
-	// Get repository list, and print every repo and it's dependencies.
-	if err := repo.CheckDeps(upgrade, proj.Repos()); err != nil {
+	// Now that all repos have been successfully fetched, we can finish the
+	// install procedure locally.
+
+	// Get repository list and print every repo and its dependencies.
+	if err := repo.CheckDeps(proj.Repos()); err != nil {
 		return err
 	}
 
-	for rname, r := range proj.Repos() {
+	for _, r := range repoList {
 		if r.IsLocal() {
 			continue
 		}
@@ -349,25 +390,35 @@ func (proj *Project) Install(upgrade bool, force bool) error {
 			return err
 		}
 		if skip {
-			continue
-		}
+			util.StatusMessage(util.VERBOSITY_DEFAULT,
+				"Skipping \"%s\": already %s\n", r.Name(), verb)
+		} else {
+			var rvers *repo.Version
 
-		// Do the hard work of actually copying and installing the repository.
-		rvers, err := r.Install(upgrade || force)
-		if err != nil {
-			return err
-		}
+			if upgrade {
+				rvers, err = r.Upgrade(force)
+				if err != nil {
+					return err
+				}
 
-		if upgrade {
-			util.StatusMessage(util.VERBOSITY_VERBOSE, "%s successfully upgraded to version %s\n",
-				r.Name(), rvers.String())
-		} else {
-			util.StatusMessage(util.VERBOSITY_VERBOSE, "%s successfully installed version %s\n",
-				r.Name(), rvers.String())
-		}
+				util.StatusMessage(util.VERBOSITY_DEFAULT,
+					"%s successfully upgraded to version %s\n",
+					r.Name(), rvers.String())
+			} else {
+				rvers, err = r.Install(force)
+				if err != nil {
+					return err
+				}
+
+				util.StatusMessage(util.VERBOSITY_DEFAULT,
+					"%s successfully installed version %s\n",
+					r.Name(), rvers)
+			}
 
-		// Update the project state with the new repository version information.
-		proj.projState.Replace(rname, rvers)
+			// Update the project state with the new repository version
+			// information.
+			proj.projState.Replace(r.Name(), rvers)
+		}
 	}
 
 	// Save the project state, including any updates or changes to the project
diff --git a/newt/project/projectstate.go b/newt/project/projectstate.go
index 0e0cc3b..aa6795c 100644
--- a/newt/project/projectstate.go
+++ b/newt/project/projectstate.go
@@ -45,6 +45,10 @@ func (ps *ProjectState) Replace(rname string, rvers *repo.Version) {
 	ps.installedRepos[rname] = rvers
 }
 
+func (ps *ProjectState) Delete(rname string) {
+	delete(ps.installedRepos, rname)
+}
+
 func (ps *ProjectState) StateFile() string {
 	return interfaces.GetProject().Path() + "/" + PROJECT_STATE_FILE
 }
@@ -74,8 +78,8 @@ func (ps *ProjectState) Init() error {
 
 	path := ps.StateFile()
 
-	// Read project state file.  If doesn't exist, it will be empty until somebody
-	// installs a repo
+	// Read project state file.  If doesn't exist, it will be empty until
+	// somebody installs a repo
 	if util.NodeNotExist(path) {
 		return nil
 	}
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index a39cd5f..3e31b15 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -199,7 +199,7 @@ func pickVersion(repo *Repo, versions []*Version) ([]*Version, error) {
 	}
 }
 
-func CheckDeps(upgrade bool, checkRepos map[string]*Repo) error {
+func CheckDeps(checkRepos map[string]*Repo) error {
 	// For each dependency, get it's version
 	depArray := map[string][]*Version{}
 
@@ -436,8 +436,8 @@ func (r *Repo) downloadRepo(branchName string) error {
 	// Download the git repo, returns the git repo, checked out to that branch
 	tmpdir, err := dl.DownloadRepo(branchName)
 	if err != nil {
-		return util.NewNewtError(fmt.Sprintf("Error download repository %s, : %s",
-			r.Name(), err.Error()))
+		return util.FmtNewtError("Error download repository %s, : %s",
+			r.Name(), err.Error())
 	}
 
 	// Copy the Git repo into the the desired local path of the repo
@@ -459,7 +459,7 @@ func (r *Repo) updateRepo(branchName string) error {
 	dl := r.downloader
 	err := dl.UpdateRepo(r.Path(), branchName)
 	if err != nil {
-		return util.NewNewtError(fmt.Sprintf("Error updating\n"))
+		return util.NewNewtError("Error updating\n")
 	}
 	return nil
 }
@@ -468,7 +468,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("Error cleaning and updating\n"))
+		return util.NewNewtError("Error cleaning and updating\n")
 	}
 	return nil
 }
@@ -477,8 +477,8 @@ 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()))
+		return "", util.FmtNewtError("Error creating diff for \"%s\" : %s",
+			r.Name(), err.Error())
 	}
 
 	// NOTE: date was not a typo: https://golang.org/pkg/time/#Time.Format
@@ -487,15 +487,15 @@ func (r *Repo) saveLocalDiff() (string, error) {
 
 	f, err := os.Create(filename)
 	if err != nil {
-		return "", util.NewNewtError(fmt.Sprintf(
-			"Error creating repo diff file \"%s\"", filename))
+		return "",
+			util.FmtNewtError("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 "",
+			util.FmtNewtError("Error writing repo diff file \"%s\"", filename)
 	}
 
 	return filename, nil
@@ -505,126 +505,121 @@ 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 "",
+			util.FmtNewtError("Error finding current branch for \"%s\" : %s",
+				r.Name(), err.Error())
 	}
 	return filepath.Base(branch), nil
 }
 
 func (r *Repo) Install(force bool) (*Version, error) {
-	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)
+	if !found {
+		return nil, util.FmtNewtError("No repository "+
+			"matching description %s found", r.rdesc.String())
+	}
+
+	if err := r.updateRepo(branchName); err != nil {
+		return nil, err
 	}
 
+	return vers, nil
+}
+
+func (r *Repo) Upgrade(force bool) (*Version, error) {
 	branchName, vers, found := r.rdesc.Match(r)
 	if !found {
-		return nil, util.NewNewtError(fmt.Sprintf("No repository "+
-			"matching description %s found", r.rdesc.String()))
+		return nil, util.FmtNewtError("No repository "+
+			"matching description %s found", 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
-		}
+	changes, err := r.downloader.AreChanges(r.Path())
+	if err != nil {
+		return nil, err
+	}
 
-		// 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())
-		}
+	if changes && !force {
+		return nil, util.FmtNewtError(
+			"Repository \"%s\" contains local changes.  Provide the "+
+				"-f option to attempt a merge.", r.Name())
 	}
 
-	// repo was not already cloned or cleanup failed...
-	if err := r.downloadRepo(branchName); err != nil {
+	if err := r.downloader.UpdateRepo(r.Path(), branchName); err != nil {
 		return nil, err
 	}
 
 	return vers, nil
 }
 
-func (r *Repo) Sync(vers *Version, force bool) (bool, bool, error) {
-	var exists bool
+func (r *Repo) Sync(vers *Version, force bool) (bool, error) {
 	var err error
 	var currBranch string
 
-	exists = r.checkExists()
-
 	// Update the repo description
 	if _, updated, err := r.UpdateDesc(); updated != true || err != nil {
-		return exists, false, util.NewNewtError("Cannot update repository description.")
+		return false, util.NewNewtError("Cannot update repository description.")
 	}
 
 	branchName, _, found := r.rdesc.MatchVersion(vers)
 	if found == false {
-		return exists, false, util.NewNewtError(fmt.Sprintf(
+		return false, util.NewNewtError(fmt.Sprintf(
 			"Branch description for %s not found", r.Name()))
 	}
 
-	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()
+	// 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()
 
-		// 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 != "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)
-			} else {
-				err = util.NewNewtError(
-					fmt.Sprintf(msg, r.rdesc.name, currBranch, branchName))
-				return exists, false, err
-			}
+	// currBranch == HEAD means we're dettached from HEAD, so
+	// ignore and move to "new" tag
+	if err != nil {
+		return false, err
+	} else if currBranch != "HEAD" && currBranch != branchName {
+		msg := "Unexpected local branch for %s: \"%s\" != \"%s\""
+		if force {
+			util.StatusMessage(util.VERBOSITY_DEFAULT,
+				msg+"\n", r.rdesc.name, currBranch, branchName)
+		} else {
+			err = util.FmtNewtError(
+				msg, r.rdesc.name, currBranch, branchName)
+			return false, err
 		}
+	}
 
-		// Don't try updating if on an invalid branch...
-		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, "Update successful!\n")
-				return exists, true, err
-			} else {
-				util.StatusMessage(util.VERBOSITY_VERBOSE, "Update failed!\n")
-				if !force {
-					return exists, false, err
-				}
+	// Don't try updating if on an invalid branch...
+	if currBranch == "HEAD" || currBranch == branchName {
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"Updating repository \"%s\"... ", r.Name())
+		err = r.updateRepo(branchName)
+		if err == nil {
+			util.StatusMessage(util.VERBOSITY_DEFAULT, "success\n")
+			return true, err
+		} else {
+			util.StatusMessage(util.VERBOSITY_QUIET, "failed: %s\n",
+				err.Error())
+			if !force {
+				return 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)
+	filename, err := r.saveLocalDiff()
+	if err != nil {
+		return false, err
+	}
+	wd, _ := os.Getwd()
+	filename, _ = filepath.Rel(wd, filename)
 
-		err = r.cleanupRepo(branchName)
-		if err != nil {
-			return exists, false, err
-		}
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "Saved local diff: "+
+		"\"%s\"\n", filename)
 
-	} else {
-		// fresh or updating was unsuccessfull and force was given...
-		err = r.downloadRepo(branchName)
-		if err != nil {
-			return exists, false, err
-		}
+	err = r.cleanupRepo(branchName)
+	if err != nil {
+		return false, err
 	}
 
-	return exists, true, nil
+	return true, nil
 }
 
 func (r *Repo) UpdateDesc() ([]*Repo, bool, error) {
@@ -655,9 +650,13 @@ func (r *Repo) downloadRepositoryYml() error {
 	dl := r.downloader
 	dl.SetBranch("master")
 
+	// Clone the repo if it doesn't exist.
+	if util.NodeNotExist(r.localPath) {
+		r.downloadRepo("master")
+	}
+
 	cpath := r.repoFilePath()
-	if err := dl.FetchFile(REPO_FILE_NAME,
-		cpath+"/"+REPO_FILE_NAME); err != nil {
+	if err := dl.FetchFile(r.localPath, REPO_FILE_NAME, cpath); err != nil {
 		util.StatusMessage(util.VERBOSITY_VERBOSE, "Download failed\n")
 
 		return err


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services