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:05 UTC

[1/5] incubator-mynewt-newt git commit: MYNEWT-655 newt - Detect repo/newt ver incompat.

Repository: incubator-mynewt-newt
Updated Branches:
  refs/heads/1_0_0_dev 7161f92af -> 38aa51055


MYNEWT-655 newt - Detect repo/newt ver incompat.

This is done with a separate map "repo.newt_compatibility" in the repo's
repository.yml file.

Example:

repo.newt_compatibility:
    1.0.0:
        1.1.0: error
        1.0.0: good
        0.9.99: warn
        0.9.9: error

This says that this version 1.0.0 of this repo is compatible with newt
versions [1.0.0, 1.1.0). Newt versions in the range [0.9.99, 1.0.0)
elicit a warning message. All other newt versions generate an error.


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

Branch: refs/heads/1_0_0_dev
Commit: 734b55ede5d8b996e5b57153870ea079620cd39f
Parents: 7161f92
Author: Christopher Collins <cc...@apache.org>
Authored: Tue Mar 7 12:11:12 2017 -0800
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Mar 7 15:59:59 2017 -0800

----------------------------------------------------------------------
 newt/newtutil/newtutil.go |  75 ++++++++---
 newt/project/project.go   |  18 +++
 newt/repo/compat.go       | 284 +++++++++++++++++++++++++++++++++++++++++
 newt/repo/repo.go         | 114 +++++------------
 newt/repo/version.go      |   9 ++
 5 files changed, 399 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/734b55ed/newt/newtutil/newtutil.go
----------------------------------------------------------------------
diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go
index 0c7db18..0f2e32c 100644
--- a/newt/newtutil/newtutil.go
+++ b/newt/newtutil/newtutil.go
@@ -34,8 +34,9 @@ import (
 	"mynewt.apache.org/newt/viper"
 )
 
-var NewtVersionStr string = "Apache Newt (incubating) version: 1.0.0-rc1"
-var NewtBlinkyTag string = "1_0_0_dev"
+var NewtVersion Version = Version{1, 0, 0}
+var NewtVersionStr string = "Apache Newt (incubating) version: 1.0.0"
+var NewtBlinkyTag string = "mynewt_1_0_0"
 var NewtNumJobs int
 var NewtForce bool
 
@@ -45,27 +46,59 @@ const REPOS_FILENAME string = "repos.yml"
 const CORE_REPO_NAME string = "apache-mynewt-core"
 const ARDUINO_ZERO_REPO_NAME string = "mynewt_arduino_zero"
 
-type RepoCommitEntry struct {
-	Version     string
-	Hash        string
-	Description string
+type Version struct {
+	Major    int64
+	Minor    int64
+	Revision int64
 }
 
-// A warning is displayed if newt requires a newer version of a repo.
-var RepoMinCommits = map[string]*RepoCommitEntry{
-	// Newt no longer cd's to a source directory when it compiles its contents.
-	// Consequently, package include flags need to be relative to the project
-	// directory, not the package source directory.
-	CORE_REPO_NAME: &RepoCommitEntry{
-		Version:     "develop",
-		Hash:        "cd99344df197d5b9e372b93142184a39ec078f69",
-		Description: "Include paths now relative to project base.",
-	},
-	ARDUINO_ZERO_REPO_NAME: &RepoCommitEntry{
-		Version:     "develop",
-		Hash:        "a6348961fef56dbfe09a1b9418d3add3ad22eaf2",
-		Description: "Include paths now relative to project base.",
-	},
+func ParseVersion(s string) (Version, error) {
+	v := Version{}
+	parseErr := util.FmtNewtError("Invalid version string: %s", s)
+
+	parts := strings.Split(s, ".")
+	if len(parts) != 3 {
+		return v, parseErr
+	}
+
+	var err error
+
+	v.Major, err = strconv.ParseInt(parts[0], 10, 64)
+	if err != nil {
+		return v, parseErr
+	}
+
+	v.Minor, err = strconv.ParseInt(parts[1], 10, 64)
+	if err != nil {
+		return v, parseErr
+	}
+
+	v.Revision, err = strconv.ParseInt(parts[2], 10, 64)
+	if err != nil {
+		return v, parseErr
+	}
+
+	return v, nil
+}
+
+func (v *Version) String() string {
+	return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Revision)
+}
+
+func VerCmp(v1 Version, v2 Version) int64 {
+	if r := v1.Major - v2.Major; r != 0 {
+		return r
+	}
+
+	if r := v1.Minor - v2.Minor; r != 0 {
+		return r
+	}
+
+	if r := v1.Revision - v2.Revision; r != 0 {
+		return r
+	}
+
+	return 0
 }
 
 // Contains general newt settings read from $HOME/.newt

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/734b55ed/newt/project/project.go
----------------------------------------------------------------------
diff --git a/newt/project/project.go b/newt/project/project.go
index cc68c30..bf4b00e 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -416,6 +416,24 @@ func (proj *Project) loadRepo(rname string, v *viper.Viper) error {
 
 	proj.localRepo.AddDependency(rd)
 
+	// Read the repo's descriptor file so that we have its newt version
+	// compatibility map.
+	_, _, err = r.ReadDesc()
+	if err != nil {
+		return util.FmtNewtError("Failed to read repo descriptor; %s",
+			err.Error())
+	}
+
+	rvers := proj.projState.GetInstalledVersion(rname)
+	code, msg := r.CheckNewtCompatibility(rvers, newtutil.NewtVersion)
+	switch code {
+	case repo.NEWT_COMPAT_GOOD:
+	case repo.NEWT_COMPAT_WARN:
+		util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: %s.\n", msg)
+	case repo.NEWT_COMPAT_ERROR:
+		return util.NewNewtError(msg)
+	}
+
 	log.Debugf("Loaded repository %s (type: %s, user: %s, repo: %s)", rname,
 		repoVars["type"], repoVars["user"], repoVars["repo"])
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/734b55ed/newt/repo/compat.go
----------------------------------------------------------------------
diff --git a/newt/repo/compat.go b/newt/repo/compat.go
new file mode 100644
index 0000000..cd9fc82
--- /dev/null
+++ b/newt/repo/compat.go
@@ -0,0 +1,284 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package repo
+
+import (
+	"fmt"
+	"math"
+	"sort"
+
+	"github.com/spf13/cast"
+
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/util"
+	"mynewt.apache.org/newt/viper"
+)
+
+type NewtCompatCode int
+
+const (
+	NEWT_COMPAT_GOOD NewtCompatCode = iota
+	NEWT_COMPAT_WARN
+	NEWT_COMPAT_ERROR
+)
+
+var NewtCompatCodeNames = map[NewtCompatCode]string{
+	NEWT_COMPAT_GOOD:  "good",
+	NEWT_COMPAT_WARN:  "warn",
+	NEWT_COMPAT_ERROR: "error",
+}
+
+type NewtCompatEntry struct {
+	code       NewtCompatCode
+	minNewtVer newtutil.Version
+}
+
+type NewtCompatTable struct {
+	// Sorted in ascending order by newt version number.
+	entries []NewtCompatEntry
+}
+
+type NewtCompatMap struct {
+	verTableMap map[newtutil.Version]NewtCompatTable
+}
+
+func newNewtCompatMap() *NewtCompatMap {
+	return &NewtCompatMap{
+		verTableMap: map[newtutil.Version]NewtCompatTable{},
+	}
+}
+
+func newtCompatCodeToString(code NewtCompatCode) string {
+	return NewtCompatCodeNames[code]
+}
+
+func newtCompatCodeFromString(codeStr string) (NewtCompatCode, error) {
+	for c, s := range NewtCompatCodeNames {
+		if codeStr == s {
+			return c, nil
+		}
+	}
+
+	return NewtCompatCode(0),
+		util.FmtNewtError("Invalid newt compatibility code: %s", codeStr)
+}
+
+func parseNcEntry(verStr string, codeStr string) (NewtCompatEntry, error) {
+	entry := NewtCompatEntry{}
+	var err error
+
+	entry.minNewtVer, err = newtutil.ParseVersion(verStr)
+	if err != nil {
+		return entry, err
+	}
+
+	entry.code, err = newtCompatCodeFromString(codeStr)
+	if err != nil {
+		return entry, err
+	}
+
+	return entry, nil
+}
+
+func parseNcTable(strMap map[string]string) (NewtCompatTable, error) {
+	tbl := NewtCompatTable{}
+
+	for c, v := range strMap {
+		entry, err := parseNcEntry(c, v)
+		if err != nil {
+			return tbl, err
+		}
+
+		tbl.entries = append(tbl.entries, entry)
+	}
+
+	sortEntries(tbl.entries)
+
+	return tbl, nil
+}
+
+func readNcMap(v *viper.Viper) (*NewtCompatMap, error) {
+	mp := newNewtCompatMap()
+	ncMap := v.GetStringMap("repo.newt_compatibility")
+
+	for k, v := range ncMap {
+		repoVer, err := newtutil.ParseVersion(k)
+		if err != nil {
+			return nil, util.FmtNewtError("Newt compatibility table contains " +
+				"invalid repo version \"%s\"")
+		}
+
+		if _, ok := mp.verTableMap[repoVer]; ok {
+			return nil, util.FmtNewtError("Newt compatibility table contains "+
+				"duplicate version specifier: %s", repoVer.String())
+		}
+
+		strMap := cast.ToStringMapString(v)
+		tbl, err := parseNcTable(strMap)
+		if err != nil {
+			return nil, err
+		}
+
+		mp.verTableMap[repoVer] = tbl
+	}
+
+	return mp, nil
+}
+
+func (tbl *NewtCompatTable) matchIdx(newtVer newtutil.Version) int {
+	// Iterate the table backwards.  The first entry whose version is less than
+	// or equal to the specified version is the match.
+	for i := 0; i < len(tbl.entries); i++ {
+		idx := len(tbl.entries) - i - 1
+		entry := &tbl.entries[idx]
+		cmp := newtutil.VerCmp(entry.minNewtVer, newtVer)
+		if cmp <= 0 {
+			return idx
+		}
+	}
+
+	return -1
+}
+
+func (tbl *NewtCompatTable) newIdxRange(i int, j int) []int {
+	if i >= len(tbl.entries) {
+		return []int{j, i}
+	}
+
+	if j >= len(tbl.entries) {
+		return []int{i, j}
+	}
+
+	e1 := tbl.entries[i]
+	e2 := tbl.entries[j]
+
+	if newtutil.VerCmp(e1.minNewtVer, e2.minNewtVer) < 0 {
+		return []int{i, j}
+	} else {
+		return []int{j, i}
+	}
+}
+
+func (tbl *NewtCompatTable) idxRangesWithCode(c NewtCompatCode) [][]int {
+	ranges := [][]int{}
+
+	curi := -1
+	for i, e := range tbl.entries {
+		if curi == -1 {
+			if e.code == c {
+				curi = i
+			}
+		} else {
+			if e.code != c {
+				ranges = append(ranges, tbl.newIdxRange(curi, i))
+				curi = -1
+			}
+		}
+	}
+
+	if curi != -1 {
+		ranges = append(ranges, tbl.newIdxRange(curi, len(tbl.entries)))
+	}
+	return ranges
+}
+
+func (tbl *NewtCompatTable) minMaxTgtVers(goodRange []int) (
+	newtutil.Version, newtutil.Version, newtutil.Version) {
+
+	minVer := tbl.entries[goodRange[0]].minNewtVer
+
+	var maxVer newtutil.Version
+	if goodRange[1] < len(tbl.entries) {
+		maxVer = tbl.entries[goodRange[1]].minNewtVer
+	} else {
+		maxVer = newtutil.Version{math.MaxInt64, math.MaxInt64, math.MaxInt64}
+	}
+
+	targetVer := tbl.entries[goodRange[1]-1].minNewtVer
+
+	return minVer, maxVer, targetVer
+}
+
+// @return NewtCompatCode       The severity of the newt incompatibility
+//         string               The warning or error message to display in case
+//                                  of incompatibility.
+func (tbl *NewtCompatTable) CheckNewtVer(
+	newtVer newtutil.Version) (NewtCompatCode, string) {
+
+	var code NewtCompatCode
+	idx := tbl.matchIdx(newtVer)
+	if idx == -1 {
+		// This version of newt is older than every entry in the table.
+		code = NEWT_COMPAT_ERROR
+	} else {
+		code = tbl.entries[idx].code
+		if code == NEWT_COMPAT_GOOD {
+			return NEWT_COMPAT_GOOD, ""
+		}
+	}
+
+	goodRanges := tbl.idxRangesWithCode(NEWT_COMPAT_GOOD)
+	for i := 0; i < len(goodRanges); i++ {
+		minVer, maxVer, tgtVer := tbl.minMaxTgtVers(goodRanges[i])
+
+		if newtutil.VerCmp(newtVer, minVer) < 0 {
+			return code, fmt.Sprintf("Please upgrade your newt tool to "+
+				"version %s", tgtVer.String())
+		}
+
+		if newtutil.VerCmp(newtVer, maxVer) >= 0 {
+			return code, "Please upgrade your repos with \"newt upgrade\""
+		}
+	}
+
+	return code, ""
+}
+
+type entrySorter struct {
+	entries []NewtCompatEntry
+}
+
+func (s entrySorter) Len() int {
+	return len(s.entries)
+}
+func (s entrySorter) Swap(i, j int) {
+	s.entries[i], s.entries[j] = s.entries[j], s.entries[i]
+}
+func (s entrySorter) Less(i, j int) bool {
+	e1 := s.entries[i]
+	e2 := s.entries[j]
+
+	cmp := newtutil.VerCmp(e1.minNewtVer, e2.minNewtVer)
+	if cmp < 0 {
+		return true
+	} else if cmp > 0 {
+		return false
+	}
+
+	return false
+}
+
+func sortEntries(entries []NewtCompatEntry) {
+	sorter := entrySorter{
+		entries: entries,
+	}
+
+	sort.Sort(sorter)
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/734b55ed/newt/repo/repo.go
----------------------------------------------------------------------
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index a2331f7..a534ea3 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -52,10 +52,7 @@ type Repo struct {
 	ignDirs    []string
 	updated    bool
 	local      bool
-
-	// The minimim git commit the repo must have to interoperate with this
-	// version of newt.
-	minCommit *newtutil.RepoCommitEntry
+	ncMap      *NewtCompatMap
 }
 
 type RepoDesc struct {
@@ -475,8 +472,8 @@ func (r *Repo) DownloadDesc() error {
 	}
 
 	dl.SetBranch("master")
-	if err := dl.FetchFile("repository.yml",
-		cpath+"/"+"repository.yml"); err != nil {
+	if err := dl.FetchFile(REPO_FILE_NAME,
+		cpath+"/"+REPO_FILE_NAME); err != nil {
 		util.StatusMessage(util.VERBOSITY_VERBOSE, " failed\n")
 		return err
 	}
@@ -553,60 +550,13 @@ func (r *Repo) ReadDesc() (*RepoDesc, []*Repo, error) {
 		return nil, nil, err
 	}
 
-	return rdesc, repos, nil
-}
-
-// Checks if the specified repo is compatible with this version of newt.  This
-// function only verifies that the repo is new enough; it doesn't check that
-// newt is new enough.
-func (r *Repo) HasMinCommit() (bool, error) {
-	if r.minCommit == nil {
-		return true, nil
-	}
-
-	// Change back to the initial directory when this function returns.
-	cwd, err := os.Getwd()
-	if err != nil {
-		return false, util.ChildNewtError(err)
-	}
-	defer os.Chdir(cwd)
-
-	if err := os.Chdir(r.localPath); err != nil {
-		return false, util.ChildNewtError(err)
-	}
-
-	cmd := []string{
-		"git",
-		"merge-base",
-		r.minCommit.Hash,
-		"HEAD",
-	}
-	mergeBase, err := util.ShellCommand(cmd, nil)
-	if err != nil {
-		if strings.Contains(err.Error(), "Not a valid commit name") {
-			return false, nil
-		} else {
-			return false, util.ChildNewtError(err)
-		}
-	}
-	if len(mergeBase) == 0 {
-		// No output means the commit does not exist in the current branch.
-		return false, nil
-	}
-
-	cmd = []string{
-		"git",
-		"rev-parse",
-		"--verify",
-		r.minCommit.Hash,
-	}
-	revParse, err := util.ShellCommand(cmd, nil)
+	// Read the newt version compatibility map.
+	r.ncMap, err = readNcMap(v)
 	if err != nil {
-		return false, util.ChildNewtError(err)
+		return nil, nil, err
 	}
 
-	// The commit exists in HEAD if the two commands produced identical output.
-	return string(mergeBase) == string(revParse), nil
+	return rdesc, repos, nil
 }
 
 func (r *Repo) Init(repoName string, rversreq string, d downloader.Downloader) error {
@@ -626,38 +576,41 @@ func (r *Repo) Init(repoName string, rversreq string, d downloader.Downloader) e
 		r.localPath = filepath.ToSlash(filepath.Clean(path))
 	} else {
 		r.localPath = filepath.ToSlash(filepath.Clean(path + "/" + REPOS_DIR + "/" + r.name))
-		r.minCommit = newtutil.RepoMinCommits[repoName]
+	}
 
-		upToDate, err := r.HasMinCommit()
-		if err != nil {
-			// If there is an error checking the repo's commit log, just abort
-			// the check.  An error could have many possible causes: repo not
-			// installed, network issue, etc.  In none of these cases does it
-			// makes sense to warn about an out of date repo.  If the issue is
-			// a real one, it will be handled when it prevents forward
-			// progress.
-			return nil
-		}
+	return nil
+}
 
-		if !upToDate {
-			util.ErrorMessage(util.VERBOSITY_QUIET,
-				"Warning: repo \"%s\" is out of date for this version of "+
-					"newt.  Please upgrade the repo to meet these "+
-					"requirements:\n"+
-					"    * Version: %s\n"+
-					"    * Commit: %s\n"+
-					"    * Change: %s\n",
-				r.name, r.minCommit.Version, r.minCommit.Hash,
-				r.minCommit.Description)
-		}
+func (r *Repo) CheckNewtCompatibility(rvers *Version, nvers newtutil.Version) (
+	NewtCompatCode, string) {
+
+	// If this repo doesn't have a newt compatibility map, just assume there is
+	// no incompatibility.
+	if len(r.ncMap.verTableMap) == 0 {
+		return NEWT_COMPAT_GOOD, ""
 	}
 
-	return nil
+	rnuver := rvers.ToNuVersion()
+	tbl, ok := r.ncMap.verTableMap[rnuver]
+	if !ok {
+		// Unknown repo version.
+		return NEWT_COMPAT_WARN, "Repo version missing from compatibility map"
+	}
+
+	code, text := tbl.CheckNewtVer(nvers)
+	if code == NEWT_COMPAT_GOOD {
+		return code, text
+	}
+
+	return code, fmt.Sprintf("This version of newt (%s) is incompatible with "+
+		"your version of the %s repo (%s); %s",
+		nvers.String(), r.name, rnuver.String(), text)
 }
 
 func NewRepo(repoName string, rversreq string, d downloader.Downloader) (*Repo, error) {
 	r := &Repo{
 		local: false,
+		ncMap: newNewtCompatMap(),
 	}
 
 	if err := r.Init(repoName, rversreq, d); err != nil {
@@ -670,6 +623,7 @@ func NewRepo(repoName string, rversreq string, d downloader.Downloader) (*Repo,
 func NewLocalRepo(repoName string) (*Repo, error) {
 	r := &Repo{
 		local: true,
+		ncMap: newNewtCompatMap(),
 	}
 
 	if err := r.Init(repoName, "", nil); err != nil {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/734b55ed/newt/repo/version.go
----------------------------------------------------------------------
diff --git a/newt/repo/version.go b/newt/repo/version.go
index ce81ef2..bbf5b56 100644
--- a/newt/repo/version.go
+++ b/newt/repo/version.go
@@ -26,6 +26,7 @@ import (
 	"strings"
 
 	"mynewt.apache.org/newt/newt/interfaces"
+	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/util"
 )
 
@@ -137,6 +138,14 @@ func (vers *Version) String() string {
 	return fmt.Sprintf(VERSION_FORMAT, vers.Major(), vers.Minor(), vers.Revision(), vers.Stability())
 }
 
+func (vers *Version) ToNuVersion() newtutil.Version {
+	return newtutil.Version{
+		Major:    vers.major,
+		Minor:    vers.minor,
+		Revision: vers.revision,
+	}
+}
+
 func LoadVersion(versStr string) (*Version, error) {
 	var err error
 


[2/5] incubator-mynewt-newt git commit: MYNEWT-655 newt - Detect proj/newt ver incompat.

Posted by ma...@apache.org.
MYNEWT-655 newt - Detect proj/newt ver incompat.

Projects can specify newt version restrictions as follows (project.yml):

project.newt_compatibility:
    1.1.0: error
    1.0.0: good
    0.9.99: warn
    0.9.9: error


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

Branch: refs/heads/1_0_0_dev
Commit: 8ac563e826ce01d7417a197ca4f7ca2b28b1496c
Parents: 734b55e
Author: Christopher Collins <cc...@apache.org>
Authored: Tue Mar 7 13:16:04 2017 -0800
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Mar 7 16:00:14 2017 -0800

----------------------------------------------------------------------
 newt/compat/compat.go   | 275 +++++++++++++++++++++++++++++++++++++++++
 newt/project/project.go |  48 ++++++--
 newt/repo/compat.go     | 284 -------------------------------------------
 newt/repo/repo.go       |  20 +--
 4 files changed, 325 insertions(+), 302 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/8ac563e8/newt/compat/compat.go
----------------------------------------------------------------------
diff --git a/newt/compat/compat.go b/newt/compat/compat.go
new file mode 100644
index 0000000..2e4355f
--- /dev/null
+++ b/newt/compat/compat.go
@@ -0,0 +1,275 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package compat
+
+import (
+	"fmt"
+	"math"
+	"sort"
+
+	"github.com/spf13/cast"
+
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/util"
+	"mynewt.apache.org/newt/viper"
+)
+
+type NewtCompatCode int
+
+const (
+	NEWT_COMPAT_GOOD NewtCompatCode = iota
+	NEWT_COMPAT_WARN
+	NEWT_COMPAT_ERROR
+)
+
+var NewtCompatCodeNames = map[NewtCompatCode]string{
+	NEWT_COMPAT_GOOD:  "good",
+	NEWT_COMPAT_WARN:  "warn",
+	NEWT_COMPAT_ERROR: "error",
+}
+
+type NewtCompatEntry struct {
+	code       NewtCompatCode
+	minNewtVer newtutil.Version
+}
+
+// Sorted in ascending order by newt version number.
+type NewtCompatTable []NewtCompatEntry
+
+type NewtCompatMap map[newtutil.Version]NewtCompatTable
+
+func newtCompatCodeToString(code NewtCompatCode) string {
+	return NewtCompatCodeNames[code]
+}
+
+func newtCompatCodeFromString(codeStr string) (NewtCompatCode, error) {
+	for c, s := range NewtCompatCodeNames {
+		if codeStr == s {
+			return c, nil
+		}
+	}
+
+	return NewtCompatCode(0),
+		util.FmtNewtError("Invalid newt compatibility code: %s", codeStr)
+}
+
+func parseNcEntry(verStr string, codeStr string) (NewtCompatEntry, error) {
+	entry := NewtCompatEntry{}
+	var err error
+
+	entry.minNewtVer, err = newtutil.ParseVersion(verStr)
+	if err != nil {
+		return entry, err
+	}
+
+	entry.code, err = newtCompatCodeFromString(codeStr)
+	if err != nil {
+		return entry, err
+	}
+
+	return entry, nil
+}
+
+func ParseNcTable(strMap map[string]string) (NewtCompatTable, error) {
+	tbl := NewtCompatTable{}
+
+	for v, c := range strMap {
+		entry, err := parseNcEntry(v, c)
+		if err != nil {
+			return tbl, err
+		}
+
+		tbl = append(tbl, entry)
+	}
+
+	sortEntries(tbl)
+
+	return tbl, nil
+}
+
+func ReadNcMap(v *viper.Viper) (NewtCompatMap, error) {
+	mp := NewtCompatMap{}
+	ncMap := v.GetStringMap("repo.newt_compatibility")
+
+	for k, v := range ncMap {
+		repoVer, err := newtutil.ParseVersion(k)
+		if err != nil {
+			return nil, util.FmtNewtError("Newt compatibility table contains " +
+				"invalid repo version \"%s\"")
+		}
+
+		if _, ok := mp[repoVer]; ok {
+			return nil, util.FmtNewtError("Newt compatibility table contains "+
+				"duplicate version specifier: %s", repoVer.String())
+		}
+
+		strMap := cast.ToStringMapString(v)
+		tbl, err := ParseNcTable(strMap)
+		if err != nil {
+			return nil, err
+		}
+
+		mp[repoVer] = tbl
+	}
+
+	return mp, nil
+}
+
+func (tbl NewtCompatTable) matchIdx(newtVer newtutil.Version) int {
+	// Iterate the table backwards.  The first entry whose version is less than
+	// or equal to the specified version is the match.
+	for i := 0; i < len(tbl); i++ {
+		idx := len(tbl) - i - 1
+		entry := &tbl[idx]
+		cmp := newtutil.VerCmp(entry.minNewtVer, newtVer)
+		if cmp <= 0 {
+			return idx
+		}
+	}
+
+	return -1
+}
+
+func (tbl NewtCompatTable) newIdxRange(i int, j int) []int {
+	if i >= len(tbl) {
+		return []int{j, i}
+	}
+
+	if j >= len(tbl) {
+		return []int{i, j}
+	}
+
+	e1 := tbl[i]
+	e2 := tbl[j]
+
+	if newtutil.VerCmp(e1.minNewtVer, e2.minNewtVer) < 0 {
+		return []int{i, j}
+	} else {
+		return []int{j, i}
+	}
+}
+
+func (tbl NewtCompatTable) idxRangesWithCode(c NewtCompatCode) [][]int {
+	ranges := [][]int{}
+
+	curi := -1
+	for i, e := range tbl {
+		if curi == -1 {
+			if e.code == c {
+				curi = i
+			}
+		} else {
+			if e.code != c {
+				ranges = append(ranges, tbl.newIdxRange(curi, i))
+				curi = -1
+			}
+		}
+	}
+
+	if curi != -1 {
+		ranges = append(ranges, tbl.newIdxRange(curi, len(tbl)))
+	}
+	return ranges
+}
+
+func (tbl NewtCompatTable) minMaxTgtVers(goodRange []int) (
+	newtutil.Version, newtutil.Version, newtutil.Version) {
+
+	minVer := tbl[goodRange[0]].minNewtVer
+
+	var maxVer newtutil.Version
+	if goodRange[1] < len(tbl) {
+		maxVer = tbl[goodRange[1]].minNewtVer
+	} else {
+		maxVer = newtutil.Version{math.MaxInt64, math.MaxInt64, math.MaxInt64}
+	}
+
+	targetVer := tbl[goodRange[1]-1].minNewtVer
+
+	return minVer, maxVer, targetVer
+}
+
+// @return NewtCompatCode       The severity of the newt incompatibility
+//         string               The warning or error message to display in case
+//                                  of incompatibility.
+func (tbl NewtCompatTable) CheckNewtVer(
+	newtVer newtutil.Version) (NewtCompatCode, string) {
+
+	var code NewtCompatCode
+	idx := tbl.matchIdx(newtVer)
+	if idx == -1 {
+		// This version of newt is older than every entry in the table.
+		code = NEWT_COMPAT_ERROR
+	} else {
+		code = tbl[idx].code
+		if code == NEWT_COMPAT_GOOD {
+			return NEWT_COMPAT_GOOD, ""
+		}
+	}
+
+	goodRanges := tbl.idxRangesWithCode(NEWT_COMPAT_GOOD)
+	for i := 0; i < len(goodRanges); i++ {
+		minVer, maxVer, tgtVer := tbl.minMaxTgtVers(goodRanges[i])
+
+		if newtutil.VerCmp(newtVer, minVer) < 0 {
+			return code, fmt.Sprintf("Please upgrade your newt tool to "+
+				"version %s", tgtVer.String())
+		}
+
+		if newtutil.VerCmp(newtVer, maxVer) >= 0 {
+			return code, fmt.Sprintf("Please upgrade your project "+
+				"or downgrade newt to %s", tgtVer.String())
+		}
+	}
+
+	return code, ""
+}
+
+type entrySorter struct {
+	entries []NewtCompatEntry
+}
+
+func (s entrySorter) Len() int {
+	return len(s.entries)
+}
+func (s entrySorter) Swap(i, j int) {
+	s.entries[i], s.entries[j] = s.entries[j], s.entries[i]
+}
+func (s entrySorter) Less(i, j int) bool {
+	e1 := s.entries[i]
+	e2 := s.entries[j]
+
+	cmp := newtutil.VerCmp(e1.minNewtVer, e2.minNewtVer)
+	if cmp < 0 {
+		return true
+	} else if cmp > 0 {
+		return false
+	}
+
+	return false
+}
+
+func sortEntries(entries []NewtCompatEntry) {
+	sorter := entrySorter{
+		entries: entries,
+	}
+
+	sort.Sort(sorter)
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/8ac563e8/newt/project/project.go
----------------------------------------------------------------------
diff --git a/newt/project/project.go b/newt/project/project.go
index bf4b00e..6778c8b 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -29,6 +29,7 @@ import (
 
 	log "github.com/Sirupsen/logrus"
 
+	"mynewt.apache.org/newt/newt/compat"
 	"mynewt.apache.org/newt/newt/downloader"
 	"mynewt.apache.org/newt/newt/interfaces"
 	"mynewt.apache.org/newt/newt/newtutil"
@@ -100,6 +101,7 @@ func TryGetProject() (*Project, error) {
 	}
 	return globalProject, nil
 }
+
 func GetProject() *Project {
 	if _, err := TryGetProject(); err != nil {
 		panic(err.Error())
@@ -418,19 +420,15 @@ func (proj *Project) loadRepo(rname string, v *viper.Viper) error {
 
 	// Read the repo's descriptor file so that we have its newt version
 	// compatibility map.
-	_, _, err = r.ReadDesc()
-	if err != nil {
-		return util.FmtNewtError("Failed to read repo descriptor; %s",
-			err.Error())
-	}
+	r.ReadDesc()
 
 	rvers := proj.projState.GetInstalledVersion(rname)
 	code, msg := r.CheckNewtCompatibility(rvers, newtutil.NewtVersion)
 	switch code {
-	case repo.NEWT_COMPAT_GOOD:
-	case repo.NEWT_COMPAT_WARN:
+	case compat.NEWT_COMPAT_GOOD:
+	case compat.NEWT_COMPAT_WARN:
 		util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: %s.\n", msg)
-	case repo.NEWT_COMPAT_ERROR:
+	case compat.NEWT_COMPAT_ERROR:
 		return util.NewNewtError(msg)
 	}
 
@@ -441,6 +439,36 @@ func (proj *Project) loadRepo(rname string, v *viper.Viper) error {
 	return nil
 }
 
+func (proj *Project) checkNewtVer() error {
+	compatSms := proj.v.GetStringMapString("project.newt_compatibility")
+	// If this project doesn't have a newt compatibility map, just assume there
+	// is no incompatibility.
+	if compatSms == nil {
+		return nil
+	}
+
+	tbl, err := compat.ParseNcTable(compatSms)
+	if err != nil {
+		return util.FmtNewtError("Error reading project.yml: %s", err.Error())
+	}
+
+	code, msg := tbl.CheckNewtVer(newtutil.NewtVersion)
+	msg = fmt.Sprintf("This version of newt (%s) is incompatible with "+
+		"your project; %s", newtutil.NewtVersion.String(), msg)
+
+	switch code {
+	case compat.NEWT_COMPAT_GOOD:
+		return nil
+	case compat.NEWT_COMPAT_WARN:
+		util.StatusMessage(util.VERBOSITY_QUIET, "WARNING: %s.\n", msg)
+		return nil
+	case compat.NEWT_COMPAT_ERROR:
+		return util.NewNewtError(msg)
+	default:
+		return nil
+	}
+}
+
 func (proj *Project) loadConfig() error {
 	v, err := util.ReadConfig(proj.BasePath,
 		strings.TrimSuffix(PROJECT_FILE_NAME, ".yml"))
@@ -496,6 +524,10 @@ func (proj *Project) loadConfig() error {
 		r.AddIgnoreDir(dirName)
 	}
 
+	if err := proj.checkNewtVer(); err != nil {
+		return err
+	}
+
 	return nil
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/8ac563e8/newt/repo/compat.go
----------------------------------------------------------------------
diff --git a/newt/repo/compat.go b/newt/repo/compat.go
deleted file mode 100644
index cd9fc82..0000000
--- a/newt/repo/compat.go
+++ /dev/null
@@ -1,284 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package repo
-
-import (
-	"fmt"
-	"math"
-	"sort"
-
-	"github.com/spf13/cast"
-
-	"mynewt.apache.org/newt/newt/newtutil"
-	"mynewt.apache.org/newt/util"
-	"mynewt.apache.org/newt/viper"
-)
-
-type NewtCompatCode int
-
-const (
-	NEWT_COMPAT_GOOD NewtCompatCode = iota
-	NEWT_COMPAT_WARN
-	NEWT_COMPAT_ERROR
-)
-
-var NewtCompatCodeNames = map[NewtCompatCode]string{
-	NEWT_COMPAT_GOOD:  "good",
-	NEWT_COMPAT_WARN:  "warn",
-	NEWT_COMPAT_ERROR: "error",
-}
-
-type NewtCompatEntry struct {
-	code       NewtCompatCode
-	minNewtVer newtutil.Version
-}
-
-type NewtCompatTable struct {
-	// Sorted in ascending order by newt version number.
-	entries []NewtCompatEntry
-}
-
-type NewtCompatMap struct {
-	verTableMap map[newtutil.Version]NewtCompatTable
-}
-
-func newNewtCompatMap() *NewtCompatMap {
-	return &NewtCompatMap{
-		verTableMap: map[newtutil.Version]NewtCompatTable{},
-	}
-}
-
-func newtCompatCodeToString(code NewtCompatCode) string {
-	return NewtCompatCodeNames[code]
-}
-
-func newtCompatCodeFromString(codeStr string) (NewtCompatCode, error) {
-	for c, s := range NewtCompatCodeNames {
-		if codeStr == s {
-			return c, nil
-		}
-	}
-
-	return NewtCompatCode(0),
-		util.FmtNewtError("Invalid newt compatibility code: %s", codeStr)
-}
-
-func parseNcEntry(verStr string, codeStr string) (NewtCompatEntry, error) {
-	entry := NewtCompatEntry{}
-	var err error
-
-	entry.minNewtVer, err = newtutil.ParseVersion(verStr)
-	if err != nil {
-		return entry, err
-	}
-
-	entry.code, err = newtCompatCodeFromString(codeStr)
-	if err != nil {
-		return entry, err
-	}
-
-	return entry, nil
-}
-
-func parseNcTable(strMap map[string]string) (NewtCompatTable, error) {
-	tbl := NewtCompatTable{}
-
-	for c, v := range strMap {
-		entry, err := parseNcEntry(c, v)
-		if err != nil {
-			return tbl, err
-		}
-
-		tbl.entries = append(tbl.entries, entry)
-	}
-
-	sortEntries(tbl.entries)
-
-	return tbl, nil
-}
-
-func readNcMap(v *viper.Viper) (*NewtCompatMap, error) {
-	mp := newNewtCompatMap()
-	ncMap := v.GetStringMap("repo.newt_compatibility")
-
-	for k, v := range ncMap {
-		repoVer, err := newtutil.ParseVersion(k)
-		if err != nil {
-			return nil, util.FmtNewtError("Newt compatibility table contains " +
-				"invalid repo version \"%s\"")
-		}
-
-		if _, ok := mp.verTableMap[repoVer]; ok {
-			return nil, util.FmtNewtError("Newt compatibility table contains "+
-				"duplicate version specifier: %s", repoVer.String())
-		}
-
-		strMap := cast.ToStringMapString(v)
-		tbl, err := parseNcTable(strMap)
-		if err != nil {
-			return nil, err
-		}
-
-		mp.verTableMap[repoVer] = tbl
-	}
-
-	return mp, nil
-}
-
-func (tbl *NewtCompatTable) matchIdx(newtVer newtutil.Version) int {
-	// Iterate the table backwards.  The first entry whose version is less than
-	// or equal to the specified version is the match.
-	for i := 0; i < len(tbl.entries); i++ {
-		idx := len(tbl.entries) - i - 1
-		entry := &tbl.entries[idx]
-		cmp := newtutil.VerCmp(entry.minNewtVer, newtVer)
-		if cmp <= 0 {
-			return idx
-		}
-	}
-
-	return -1
-}
-
-func (tbl *NewtCompatTable) newIdxRange(i int, j int) []int {
-	if i >= len(tbl.entries) {
-		return []int{j, i}
-	}
-
-	if j >= len(tbl.entries) {
-		return []int{i, j}
-	}
-
-	e1 := tbl.entries[i]
-	e2 := tbl.entries[j]
-
-	if newtutil.VerCmp(e1.minNewtVer, e2.minNewtVer) < 0 {
-		return []int{i, j}
-	} else {
-		return []int{j, i}
-	}
-}
-
-func (tbl *NewtCompatTable) idxRangesWithCode(c NewtCompatCode) [][]int {
-	ranges := [][]int{}
-
-	curi := -1
-	for i, e := range tbl.entries {
-		if curi == -1 {
-			if e.code == c {
-				curi = i
-			}
-		} else {
-			if e.code != c {
-				ranges = append(ranges, tbl.newIdxRange(curi, i))
-				curi = -1
-			}
-		}
-	}
-
-	if curi != -1 {
-		ranges = append(ranges, tbl.newIdxRange(curi, len(tbl.entries)))
-	}
-	return ranges
-}
-
-func (tbl *NewtCompatTable) minMaxTgtVers(goodRange []int) (
-	newtutil.Version, newtutil.Version, newtutil.Version) {
-
-	minVer := tbl.entries[goodRange[0]].minNewtVer
-
-	var maxVer newtutil.Version
-	if goodRange[1] < len(tbl.entries) {
-		maxVer = tbl.entries[goodRange[1]].minNewtVer
-	} else {
-		maxVer = newtutil.Version{math.MaxInt64, math.MaxInt64, math.MaxInt64}
-	}
-
-	targetVer := tbl.entries[goodRange[1]-1].minNewtVer
-
-	return minVer, maxVer, targetVer
-}
-
-// @return NewtCompatCode       The severity of the newt incompatibility
-//         string               The warning or error message to display in case
-//                                  of incompatibility.
-func (tbl *NewtCompatTable) CheckNewtVer(
-	newtVer newtutil.Version) (NewtCompatCode, string) {
-
-	var code NewtCompatCode
-	idx := tbl.matchIdx(newtVer)
-	if idx == -1 {
-		// This version of newt is older than every entry in the table.
-		code = NEWT_COMPAT_ERROR
-	} else {
-		code = tbl.entries[idx].code
-		if code == NEWT_COMPAT_GOOD {
-			return NEWT_COMPAT_GOOD, ""
-		}
-	}
-
-	goodRanges := tbl.idxRangesWithCode(NEWT_COMPAT_GOOD)
-	for i := 0; i < len(goodRanges); i++ {
-		minVer, maxVer, tgtVer := tbl.minMaxTgtVers(goodRanges[i])
-
-		if newtutil.VerCmp(newtVer, minVer) < 0 {
-			return code, fmt.Sprintf("Please upgrade your newt tool to "+
-				"version %s", tgtVer.String())
-		}
-
-		if newtutil.VerCmp(newtVer, maxVer) >= 0 {
-			return code, "Please upgrade your repos with \"newt upgrade\""
-		}
-	}
-
-	return code, ""
-}
-
-type entrySorter struct {
-	entries []NewtCompatEntry
-}
-
-func (s entrySorter) Len() int {
-	return len(s.entries)
-}
-func (s entrySorter) Swap(i, j int) {
-	s.entries[i], s.entries[j] = s.entries[j], s.entries[i]
-}
-func (s entrySorter) Less(i, j int) bool {
-	e1 := s.entries[i]
-	e2 := s.entries[j]
-
-	cmp := newtutil.VerCmp(e1.minNewtVer, e2.minNewtVer)
-	if cmp < 0 {
-		return true
-	} else if cmp > 0 {
-		return false
-	}
-
-	return false
-}
-
-func sortEntries(entries []NewtCompatEntry) {
-	sorter := entrySorter{
-		entries: entries,
-	}
-
-	sort.Sort(sorter)
-}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/8ac563e8/newt/repo/repo.go
----------------------------------------------------------------------
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index a534ea3..a2b98c9 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -29,6 +29,7 @@ import (
 	log "github.com/Sirupsen/logrus"
 	"github.com/spf13/cast"
 
+	"mynewt.apache.org/newt/newt/compat"
 	"mynewt.apache.org/newt/newt/downloader"
 	"mynewt.apache.org/newt/newt/interfaces"
 	"mynewt.apache.org/newt/newt/newtutil"
@@ -52,7 +53,7 @@ type Repo struct {
 	ignDirs    []string
 	updated    bool
 	local      bool
-	ncMap      *NewtCompatMap
+	ncMap      compat.NewtCompatMap
 }
 
 type RepoDesc struct {
@@ -551,7 +552,7 @@ func (r *Repo) ReadDesc() (*RepoDesc, []*Repo, error) {
 	}
 
 	// Read the newt version compatibility map.
-	r.ncMap, err = readNcMap(v)
+	r.ncMap, err = compat.ReadNcMap(v)
 	if err != nil {
 		return nil, nil, err
 	}
@@ -582,23 +583,24 @@ func (r *Repo) Init(repoName string, rversreq string, d downloader.Downloader) e
 }
 
 func (r *Repo) CheckNewtCompatibility(rvers *Version, nvers newtutil.Version) (
-	NewtCompatCode, string) {
+	compat.NewtCompatCode, string) {
 
 	// If this repo doesn't have a newt compatibility map, just assume there is
 	// no incompatibility.
-	if len(r.ncMap.verTableMap) == 0 {
-		return NEWT_COMPAT_GOOD, ""
+	if len(r.ncMap) == 0 {
+		return compat.NEWT_COMPAT_GOOD, ""
 	}
 
 	rnuver := rvers.ToNuVersion()
-	tbl, ok := r.ncMap.verTableMap[rnuver]
+	tbl, ok := r.ncMap[rnuver]
 	if !ok {
 		// Unknown repo version.
-		return NEWT_COMPAT_WARN, "Repo version missing from compatibility map"
+		return compat.NEWT_COMPAT_WARN,
+			"Repo version missing from compatibility map"
 	}
 
 	code, text := tbl.CheckNewtVer(nvers)
-	if code == NEWT_COMPAT_GOOD {
+	if code == compat.NEWT_COMPAT_GOOD {
 		return code, text
 	}
 
@@ -610,7 +612,6 @@ func (r *Repo) CheckNewtCompatibility(rvers *Version, nvers newtutil.Version) (
 func NewRepo(repoName string, rversreq string, d downloader.Downloader) (*Repo, error) {
 	r := &Repo{
 		local: false,
-		ncMap: newNewtCompatMap(),
 	}
 
 	if err := r.Init(repoName, rversreq, d); err != nil {
@@ -623,7 +624,6 @@ func NewRepo(repoName string, rversreq string, d downloader.Downloader) (*Repo,
 func NewLocalRepo(repoName string) (*Repo, error) {
 	r := &Repo{
 		local: true,
-		ncMap: newNewtCompatMap(),
 	}
 
 	if err := r.Init(repoName, "", nil); err != nil {


[5/5] incubator-mynewt-newt git commit: Updates to sync/upgrade/install inner working

Posted by ma...@apache.org.
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/38aa5105
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/38aa5105
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/38aa5105

Branch: refs/heads/1_0_0_dev
Commit: 38aa51055961ad6e075a0ee6be8b8e16e041e486
Parents: a7c0235
Author: Fabio Utzig <ut...@utzig.org>
Authored: Tue Mar 7 11:33:01 2017 -0300
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Mar 7 16:04:50 2017 -0800

----------------------------------------------------------------------
 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/38aa5105/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/38aa5105/newt/repo/repo.go
----------------------------------------------------------------------
diff --git a/newt/repo/repo.go b/newt/repo/repo.go
index 316b274..e058466 100644
--- a/newt/repo/repo.go
+++ b/newt/repo/repo.go
@@ -376,11 +376,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
 }
@@ -389,7 +389,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
 }
@@ -429,33 +429,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)
@@ -464,6 +446,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
 	}
@@ -494,10 +490,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)
@@ -509,14 +508,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
 				}
@@ -564,6 +563,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
 	}
 
@@ -576,8 +576,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()
@@ -590,7 +590,7 @@ func (r *Repo) DownloadDesc() error {
 	dl.SetBranch("master")
 	if err := dl.FetchFile(REPO_FILE_NAME,
 		cpath+"/"+REPO_FILE_NAME); err != nil {
-		util.StatusMessage(util.VERBOSITY_VERBOSE, " failed\n")
+		util.StatusMessage(util.VERBOSITY_VERBOSE, "Download failed\n")
 		return err
 	}
 
@@ -602,7 +602,7 @@ func (r *Repo) DownloadDesc() error {
 		}
 	}
 
-	util.StatusMessage(util.VERBOSITY_VERBOSE, " success!\n")
+	util.StatusMessage(util.VERBOSITY_VERBOSE, "Download successful!\n")
 
 	return nil
 }


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

Posted by ma...@apache.org.
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)


[3/5] incubator-mynewt-newt git commit: MYNEWT-655 newt - Detect newt version incompat.

Posted by ma...@apache.org.
MYNEWT-655 newt - Detect newt version incompat.

Correctly handle case where project imposes no newt version
restrictions.


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

Branch: refs/heads/1_0_0_dev
Commit: 934b3cc1ab0e533958e5cdf0bc133798e7f2dd6d
Parents: 8ac563e
Author: Christopher Collins <cc...@apache.org>
Authored: Tue Mar 7 14:03:48 2017 -0800
Committer: Marko Kiiskila <ma...@runtime.io>
Committed: Tue Mar 7 16:00:23 2017 -0800

----------------------------------------------------------------------
 newt/project/project.go | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/934b3cc1/newt/project/project.go
----------------------------------------------------------------------
diff --git a/newt/project/project.go b/newt/project/project.go
index 6778c8b..42015bb 100644
--- a/newt/project/project.go
+++ b/newt/project/project.go
@@ -443,7 +443,7 @@ func (proj *Project) checkNewtVer() error {
 	compatSms := proj.v.GetStringMapString("project.newt_compatibility")
 	// If this project doesn't have a newt compatibility map, just assume there
 	// is no incompatibility.
-	if compatSms == nil {
+	if len(compatSms) == 0 {
 		return nil
 	}