mynewt-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] utzig commented on a change in pull request #140: newt - Repo dependencies
Date Wed, 07 Mar 2018 13:51:04 GMT
utzig commented on a change in pull request #140: newt - Repo dependencies
URL: https://github.com/apache/mynewt-newt/pull/140#discussion_r172846489
 
 

 ##########
 File path: newt/project/project.go
 ##########
 @@ -198,177 +209,350 @@ 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) {
+// Selects repositories from the global state that satisfy the specified
+// predicate.
+func (proj *Project) SelectRepos(pred func(r *repo.Repo) bool) []*repo.Repo {
+	all := proj.repos.Sorted()
+	var filtered []*repo.Repo
 
-	rdesc, err := r.GetRepoDesc()
-	if err != nil {
-		return false, err
+	for _, r := range all {
+		if pred(r) {
+			filtered = append(filtered, r)
+		}
 	}
 
-	branch, newVers, _ := rdesc.Match(r)
-	if newVers == nil {
-		util.StatusMessage(util.VERBOSITY_DEFAULT,
-			"No matching version to upgrade to "+
-				"found for %s.  Please check your 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 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 {
-			str := ""
-			if newVers.Stability() != repo.VERSION_STABILITY_NONE {
-				str += "(" + branch + ")"
-			}
+	return filtered
+}
 
-			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 {
-				return false, util.NewNewtError(fmt.Sprintf(
-					"Couldn't read upgrade response: %s\n", err.Error()))
-			}
+// Indicates whether a repo should be installed.  A repo should be installed if
+// it is not currently installed.
+func (proj *Project) shouldInstallRepo(repoName string) bool {
+	return proj.projState.GetInstalledVersion(repoName) == nil
+}
 
-			// Anything but no means yes.
-			answer := strings.ToUpper(strings.Trim(string(line), " "))
-			if answer == "N" || answer == "NO" {
-				fmt.Printf("User says don't upgrade, skipping upgrade of %s\n",
-					r.Name())
-				return true, nil
-			}
-		}
-	} else {
-		util.StatusMessage(util.VERBOSITY_VERBOSE,
-			"Repository %s doesn't need to be upgraded, latest "+
-				"version installed.\n", r.Name())
-		return true, nil
+// Indicates whether a repo should be upgraded to the specified version.  A
+// repo should be upgraded if it is not currently installed, or if a version
+// other than the desired one is installed.
+func (proj *Project) shouldUpgradeRepo(repoName string,
+	destVer newtutil.RepoVersion) bool {
+
+	r := proj.repos[repoName]
+	if r == nil {
+		return false
 	}
 
-	return false, nil
+	stateVer := proj.projState.GetInstalledVersion(repoName)
+	if stateVer == nil {
+		return true
+	}
+
+	return !r.VersionsEqual(*stateVer, destVer)
 }
 
-func (proj *Project) checkVersionRequirements(
-	r *repo.Repo, upgrade bool, force bool) (bool, error) {
+// Removes repos that shouldn't be installed from the specified list.  A repo
+// should not be installed if it is already installed (any version).
+//
+// @param repos                 The list of repos to filter.
+//
+// @return []*Repo              The filtered list of repos.
+func (proj *Project) filterInstallList(repos []*repo.Repo) []*repo.Repo {
+	keep := []*repo.Repo{}
 
-	rdesc, err := r.GetRepoDesc()
-	if err != nil {
-		return false, err
+	for _, r := range repos {
+		curVer := proj.projState.GetInstalledVersion(r.Name())
+		if curVer == nil {
+			keep = append(keep, r)
+		} else {
+			util.StatusMessage(util.VERBOSITY_DEFAULT,
+				"Skipping \"%s\": already installed (%s)\n",
+				r.Name(), curVer.String())
+		}
 	}
 
-	rname := r.Name()
+	return keep
+}
+
+// Removes repos that shouldn't be upgraded from the specified list.  A repo
+// should not be upgraded if the desired version is already installed.
+//
+// @param repos                 The list of repos to filter.
+// @param vm                    Specifies the desired version of each repo.
+//
+// @return []*Repo              The filtered list of repos.
+func (proj *Project) filterUpgradeList(
+	repos []*repo.Repo, vm deprepo.VersionMap) []*repo.Repo {
 
-	vers := proj.projState.GetInstalledVersion(rname)
-	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",
-				vers, rname, r.VersionRequirementsString())
-			return true, nil
+	keep := []*repo.Repo{}
+
+	for _, r := range repos {
+		destVer := vm[r.Name()]
+		if proj.shouldUpgradeRepo(r.Name(), destVer) {
+			keep = append(keep, r)
 		} else {
-			if !upgrade {
-				util.StatusMessage(util.VERBOSITY_VERBOSE,
-					"%s correct version already installed\n", r.Name())
-				return true, nil
-			} else {
-				skip, err := proj.upgradeCheck(r, vers, force)
-				return skip, err
+			curVer := proj.projState.GetInstalledVersion(r.Name())
+			util.StatusMessage(util.VERBOSITY_DEFAULT,
+				"Skipping \"%s\": already upgraded (%s)\n",
+				r.Name(), curVer.String())
+		}
+	}
+
+	return keep
+}
+
+// Determines if the `project.yml` file specifies a nonexistent repo version.
+// Only the repos in the specified slice are considered.
+//
+// @param repos                 The list of repos to consider during the check.
+// @param m                     A matrix containing all versions of the
+//                                  specified repos.
+//
+// @return error                Error if any repo requirement is invalid.
+func (proj *Project) detectIllegalRepoReqs(
+	repos []*repo.Repo, m deprepo.Matrix) error {
+
+	var lines []string
+	for _, r := range repos {
+		reqs, ok := proj.rootRepoReqs[r.Name()]
+		if ok {
+			row := m.FindRow(r.Name())
+			if row == nil {
+				return util.FmtNewtError(
+					"internal error; repo \"%s\" missing from matrix", r.Name())
+			}
+
+			r := proj.repos[r.Name()]
+			nreqs, err := r.NormalizeVerReqs(reqs)
+			if err != nil {
+				return err
+			}
+
+			anySatisfied := false
+			for _, ver := range row.Vers {
+				if ver.SatisfiesAll(nreqs) {
+					anySatisfied = true
+					break
+				}
+			}
+			if !anySatisfied {
+				line := fmt.Sprintf("    %s,%s", r.Name(),
+					newtutil.RepoVerReqsString(nreqs))
+				lines = append(lines, line)
 			}
 		}
+	}
+
+	if len(lines) > 0 {
+		sort.Strings(lines)
+		return util.NewNewtError(
+			"project.yml file specifies nonexistent repo versions:\n" +
+				strings.Join(lines, "\n"))
+	}
+
+	return nil
+}
+
+// Installs or upgrades a single repo to the specified version.
+func (proj *Project) installRepo(r *repo.Repo, ver newtutil.RepoVersion,
+	upgrade bool, force bool) error {
+
+	// Install the acceptable version.
+	if upgrade {
+		if err := r.Upgrade(ver, force); err != nil {
+			return err
+		}
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"%s successfully upgraded to version %s\n",
+			r.Name(), ver.String())
 	} else {
-		// Fallthrough and perform the installation.
-		// Check to make sure that this repository contains a version
-		// that can satisfy.
-		_, _, ok := rdesc.Match(r)
-		if !ok {
-			util.StatusMessage(util.VERBOSITY_QUIET,
-				"WARNING: No matching repository version found for "+
-					"repository %s specified in project.\n", r.Name())
-			return true, nil
+		if err := r.Install(ver); err != nil {
+			return err
 		}
+
+		util.StatusMessage(util.VERBOSITY_DEFAULT,
+			"%s successfully installed version %s\n",
+			r.Name(), ver.String())
 	}
 
-	return false, nil
+	// Update the project state with the new repository version
+	// information.
+	proj.projState.Replace(r.Name(), ver)
+
+	return nil
 }
 
-func (proj *Project) checkDeps(r *repo.Repo) error {
-	repos, updated, err := r.UpdateDesc()
-	if err != nil {
-		return err
-	}
+func (proj *Project) installMessageOneRepo(
+	repoName string, op installOp, force bool, curVer *newtutil.RepoVersion,
+	destVer newtutil.RepoVersion) (string, error) {
 
-	if !updated {
-		return nil
+	// If the repo isn't installed yet, this is an install, not an upgrade.
+	if op == INSTALL_OP_UPGRADE && curVer == nil {
+		op = INSTALL_OP_INSTALL
 	}
 
-	for _, newRepo := range repos {
-		curRepo, ok := proj.repos[newRepo.Name()]
-		if !ok {
-			proj.repos[newRepo.Name()] = newRepo
-			return proj.updateRepos(proj.SortedRepos())
+	var verb string
+	switch op {
+	case INSTALL_OP_INSTALL:
+		if !force {
+			verb = "install"
 		} else {
-			// Add any dependencies we might have found here.
-			for _, dep := range newRepo.Deps() {
-				newRepo.DownloadDesc()
-				newRepo.ReadDesc()
-				curRepo.AddDependency(dep)
-			}
+			verb = "reinstall"
 		}
+
+	case INSTALL_OP_UPGRADE:
+		verb = "upgrade"
+
+	case INSTALL_OP_SYNC:
+		verb = "sync"
+
+	default:
+		return "", util.FmtNewtError(
+			"internal error: invalid install op: %v", op)
 	}
 
-	return nil
+	msg := fmt.Sprintf("    %s %s ", verb, repoName)
+	if curVer != nil {
+		msg += fmt.Sprintf("(%s --> %s)", curVer.String(), destVer.String())
+	} else {
+		msg += fmt.Sprintf("(%s)", destVer.String())
+	}
+
+	return msg, nil
 }
 
-// Selects repositories from the global state that satisfy the specified
-// predicate.
-func (proj *Project) SelectRepos(pred func(r *repo.Repo) bool) []*repo.Repo {
-	all := proj.SortedRepos()
-	var filtered []*repo.Repo
+// Describes an imminent repo operation to the user.  In addition, prompts the
+// user for confirmation if the `-a` (ask) option was specified.
+func (proj *Project) installPrompt(repoList []*repo.Repo,
+	vm deprepo.VersionMap, op installOp, force bool, ask bool) (bool, error) {
 
-	for _, r := range all {
-		if pred(r) {
-			filtered = append(filtered, r)
+	if len(repoList) == 0 {
+		return true, nil
+	}
+
+	util.StatusMessage(util.VERBOSITY_DEFAULT,
+		"Making the following changes to the project:\n")
+
+	for _, r := range repoList {
+		curVer := proj.projState.GetInstalledVersion(r.Name())
+		destVer := vm[r.Name()]
+
+		msg, err := proj.installMessageOneRepo(
+			r.Name(), op, force, curVer, destVer)
+		if err != nil {
+			return false, err
 		}
+
+		util.StatusMessage(util.VERBOSITY_DEFAULT, "%s\n", msg)
 	}
+	util.StatusMessage(util.VERBOSITY_DEFAULT, "\n")
 
-	return filtered
-}
+	if !ask {
+		return true, nil
+	}
 
-func (proj *Project) updateRepos(repos []*repo.Repo) error {
-	for _, r := range repos {
-		if r.IsLocal() {
-			continue
+	for {
+		fmt.Printf("Proceed? [Y/n] ")
+		line, more, err := bufio.NewReader(os.Stdin).ReadLine()
+		if more || err != nil {
+			return false, util.ChildNewtError(err)
 		}
 
-		err := proj.checkDeps(r)
-		if err != nil {
-			return err
+		trimmed := strings.ToLower(strings.TrimSpace(string(line)))
+		if len(trimmed) == 0 || strings.HasPrefix(trimmed, "y") {
+			// User wants to proceed.
+			return true, nil
+		}
+
+		if strings.HasPrefix(trimmed, "n") {
+			// User wants to cancel.
+			return false, nil
 		}
+
+		// Invalid response.
+		fmt.Printf("Invalid response.  Please enter 'y' or 'n'.\n")
 
 Review comment:
   A small nit! `Please enter 'y' or 'n'` since you already have a prompt with `[Y/n]`, and
both `<ENTER>`, `YES`, `Yes` would work this extra message feels unnecessary (and not
precise).

----------------------------------------------------------------
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

Mime
View raw message