You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2017/04/07 19:36:06 UTC
[05/23] incubator-mynewt-newt git commit: MYNEWT-655 newt - Detect
repo/newt ver incompat.
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/f264e676
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/tree/f264e676
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/diff/f264e676
Branch: refs/heads/master
Commit: f264e6767fbfd26ff24f31b55e63fd8b189daa9f
Parents: 1fb9697
Author: Christopher Collins <cc...@apache.org>
Authored: Tue Mar 7 12:11:12 2017 -0800
Committer: Christopher Collins <cc...@apache.org>
Committed: Tue Mar 7 12:22:06 2017 -0800
----------------------------------------------------------------------
newt/newtutil/newtutil.go | 71 ++++++++---
newt/project/project.go | 18 +++
newt/repo/compat.go | 284 +++++++++++++++++++++++++++++++++++++++++
newt/repo/repo.go | 114 +++++------------
newt/repo/version.go | 9 ++
5 files changed, 397 insertions(+), 99 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt/blob/f264e676/newt/newtutil/newtutil.go
----------------------------------------------------------------------
diff --git a/newt/newtutil/newtutil.go b/newt/newtutil/newtutil.go
index 48ef4a0..98307ec 100644
--- a/newt/newtutil/newtutil.go
+++ b/newt/newtutil/newtutil.go
@@ -34,6 +34,7 @@ import (
"mynewt.apache.org/newt/viper"
)
+var NewtVersion Version = Version{1, 0, 0}
var NewtVersionStr string = "Apache Newt (incubating) version: 1.0.0-dev"
var NewtBlinkyTag string = "develop"
var NewtNumJobs int
@@ -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/f264e676/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/f264e676/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/f264e676/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/f264e676/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