func benchCheckVersion(c, v string, b *testing.B) { version, _ := semver.NewVersion(v) constraint, _ := semver.NewConstraint(c) for i := 0; i < b.N; i++ { constraint.Check(version) } }
func benchValidateVersion(c, v string, b *testing.B) { version, _ := semver.NewVersion(v) constraint, _ := semver.NewConstraint(c) for i := 0; i < b.N; i++ { constraint.Validate(version) } }
// Resolve resolves dependencies and returns a lock file with the resolution. func (r *Resolver) Resolve(reqs *chartutil.Requirements, repoNames map[string]string) (*chartutil.RequirementsLock, error) { d, err := HashReq(reqs) if err != nil { return nil, err } // Now we clone the dependencies, locking as we go. locked := make([]*chartutil.Dependency, len(reqs.Dependencies)) missing := []string{} for i, d := range reqs.Dependencies { constraint, err := semver.NewConstraint(d.Version) if err != nil { return nil, fmt.Errorf("dependency %q has an invalid version/constraint format: %s", d.Name, err) } repoIndex, err := repo.LoadIndexFile(r.helmhome.CacheIndex(repoNames[d.Name])) if err != nil { return nil, fmt.Errorf("no cached repo found. (try 'helm repo update'). %s", err) } vs, ok := repoIndex.Entries[d.Name] if !ok { return nil, fmt.Errorf("%s chart not found in repo %s", d.Name, d.Repository) } locked[i] = &chartutil.Dependency{ Name: d.Name, Repository: d.Repository, } found := false // The version are already sorted and hence the first one to satisfy the constraint is used for _, ver := range vs { v, err := semver.NewVersion(ver.Version) if err != nil || len(ver.URLs) == 0 { // Not a legit entry. continue } if constraint.Check(v) { found = true locked[i].Version = v.Original() break } } if !found { missing = append(missing, d.Name) } } if len(missing) > 0 { return nil, fmt.Errorf("Can't get a valid version for repositories %s. Try changing the version constraint in requirements.yaml", strings.Join(missing, ", ")) } return &chartutil.RequirementsLock{ Generated: time.Now(), Digest: d, Dependencies: locked, }, nil }
func wizardLookInto(d *cfg.Dependency) bool { _, err := semver.NewConstraint(d.Reference) // The existing version is already a valid semver constraint so we skip suggestions. if err == nil { return false } return true }
// VersionOK returns true if the given version meets the constraints. // // It returns false if the version string or constraint is unparsable or if the // version does not meet the constraint. func (d *Dependency) VersionOK(version string) bool { c, err := semver.NewConstraint(d.Version) if err != nil { return false } v, err := semver.NewVersion(version) if err != nil { return false } return c.Check(v) }
func validateChartVersion(cf *chart.Metadata) error { if cf.Version == "" { return errors.New("version is required") } version, err := semver.NewVersion(cf.Version) if err != nil { return fmt.Errorf("version '%s' is not a valid SemVer", cf.Version) } c, err := semver.NewConstraint("> 0") valid, msg := c.Validate(version) if !valid && len(msg) > 0 { return fmt.Errorf("version %v", msg[0]) } return nil }
func validateChartVersion(cf *chart.Metadata) (lintError support.LintError) { if cf.Version == "" { lintError = fmt.Errorf("Chart.yaml: 'version' value is required") return } version, err := semver.NewVersion(cf.Version) if err != nil { lintError = fmt.Errorf("Chart.yaml: version '%s' is not a valid SemVer", cf.Version) return } c, err := semver.NewConstraint("> 0") valid, msg := c.Validate(version) if !valid && len(msg) > 0 { lintError = fmt.Errorf("Chart.yaml: 'version' %v", msg[0]) } return }
func determineDependency(v, dep *cfg.Dependency, dest string) *cfg.Dependency { repo, err := v.GetRepo(dest) if err != nil { singleWarn("Unable to access repo for %s\n", v.Name) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } vIsRef := repo.IsReference(v.Reference) depIsRef := repo.IsReference(dep.Reference) // Both are references and they are different ones. if vIsRef && depIsRef { singleWarn("Conflict: %s ref is %s, but also asked for %s\n", v.Name, v.Reference, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } else if vIsRef { // The current one is a reference and the suggestion is a SemVer constraint. con, err := semver.NewConstraint(dep.Reference) if err != nil { singleWarn("Version issue for %s: '%s' is neither a reference or semantic version constraint\n", dep.Name, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } ver, err := semver.NewVersion(v.Reference) if err != nil { // The existing version is not a semantic version. singleWarn("Conflict: %s version is %s, but also asked for %s\n", v.Name, v.Reference, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } if con.Check(ver) { singleInfo("Keeping %s %s because it fits constraint '%s'", v.Name, v.Reference, dep.Reference) return v } singleWarn("Conflict: %s version is %s but does not meet constraint '%s'\n", v.Name, v.Reference, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } else if depIsRef { con, err := semver.NewConstraint(v.Reference) if err != nil { singleWarn("Version issue for %s: '%s' is neither a reference or semantic version constraint\n", v.Name, v.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } ver, err := semver.NewVersion(dep.Reference) if err != nil { singleWarn("Conflict: %s version is %s, but also asked for %s\n", v.Name, v.Reference, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } if con.Check(ver) { v.Reference = dep.Reference singleInfo("Using %s %s because it fits constraint '%s'", v.Name, v.Reference, v.Reference) return v } singleWarn("Conflict: %s semantic version constraint is %s but '%s' does not meet the constraint\n", v.Name, v.Reference, v.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } // Neither is a vcs reference and both could be semantic version // constraints that are different. _, err = semver.NewConstraint(dep.Reference) if err != nil { // dd.Reference is not a reference or a valid constraint. singleWarn("Version %s %s is not a reference or valid semantic version constraint\n", dep.Name, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v } _, err = semver.NewConstraint(v.Reference) if err != nil { // existing.Reference is not a reference or a valid constraint. // We really should never end up here. singleWarn("Version %s %s is not a reference or valid semantic version constraint\n", v.Name, v.Reference) v.Reference = dep.Reference v.Pin = "" singleInfo("Using %s %s because it is a valid version", v.Name, v.Reference) return v } // Both versions are constraints. Try to merge them. // If either comparison has an || skip merging. That's complicated. ddor := strings.Index(dep.Reference, "||") eor := strings.Index(v.Reference, "||") if ddor == -1 && eor == -1 { // Add the comparisons together. newRef := v.Reference + ", " + dep.Reference v.Reference = newRef v.Pin = "" singleInfo("Combining %s semantic version constraints %s and %s", v.Name, v.Reference, dep.Reference) return v } singleWarn("Conflict: %s version is %s, but also asked for %s\n", v.Name, v.Reference, dep.Reference) singleInfo("Keeping %s %s", v.Name, v.Reference) return v }
// mergeDeps merges any dependency array into deps. func mergeDeps(orig map[string]*yaml.Dependency, add []*yaml.Dependency, vend string) []string { mod := []string{} for _, dd := range add { // Add it unless it's already there. if existing, ok := orig[dd.Name]; !ok { orig[dd.Name] = dd Debug("Adding %s to the scan list", dd.Name) mod = append(mod, dd.Name) } else if existing.Reference == "" && dd.Reference != "" { // If a nested dep has finer dependency references than outside, // set the reference. existing.Reference = dd.Reference mod = append(mod, dd.Name) } else if dd.Reference != "" && existing.Reference != "" && dd.Reference != existing.Reference { // Check if one is a version and the other is a constraint. If the // version is in the constraint use that. dest := path.Join(vend, dd.Name) repo, err := existing.GetRepo(dest) if err != nil { Warn("Unable to access repo for %s\n", existing.Name) Info("Keeping %s %s", existing.Name, existing.Reference) continue } eIsRef := repo.IsReference(existing.Reference) ddIsRef := repo.IsReference(dd.Reference) // Both are references and different ones. if eIsRef && ddIsRef { Warn("Conflict: %s ref is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) } else if eIsRef { // Test ddIsRef is a constraint and if eIsRef is a semver // within that con, err := semver.NewConstraint(dd.Reference) if err != nil { Warn("Version issue for %s: '%s' is neither a reference or semantic version constraint\n", dd.Name, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) continue } ver, err := semver.NewVersion(existing.Reference) if err != nil { // The existing version is not a semantic version. Warn("Conflict: %s version is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) continue } if con.Check(ver) { Info("Keeping %s %s because it fits constraint '%s'", existing.Name, existing.Reference, dd.Reference) } else { Warn("Conflict: %s version is %s but does not meet constraint '%s'\n", existing.Name, existing.Reference, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) } } else if ddIsRef { // Test eIsRef is a constraint and if ddIsRef is a semver // within that con, err := semver.NewConstraint(existing.Reference) if err != nil { Warn("Version issue for %s: '%s' is neither a reference or semantic version constraint\n", existing.Name, existing.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) continue } ver, err := semver.NewVersion(dd.Reference) if err != nil { // The dd version is not a semantic version. Warn("Conflict: %s version is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) continue } if con.Check(ver) { // Use the specific version if noted instead of the existing // constraint. existing.Reference = dd.Reference mod = append(mod, dd.Name) Info("Using %s %s because it fits constraint '%s'", existing.Name, dd.Reference, existing.Reference) } else { Warn("Conflict: %s semantic version constraint is %s but '%s' does not meet the constraint\n", existing.Name, existing.Reference, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) } } else { // Neither is a vcs reference and both could be semantic version // constraints that are different. _, err := semver.NewConstraint(dd.Reference) if err != nil { // dd.Reference is not a reference or a valid constraint. Warn("Version %s %s is not a reference or valid semantic version constraint\n", dd.Name, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) continue } _, err = semver.NewConstraint(existing.Reference) if err != nil { // existing.Reference is not a reference or a valid constraint. // We really should never end up here. Warn("Version %s %s is not a reference or valid semantic version constraint\n", existing.Name, existing.Reference) existing.Reference = dd.Reference mod = append(mod, dd.Name) Info("Using %s %s because it is a valid version", existing.Name, existing.Reference) continue } // Both versions are constraints. Try to merge them. // If either comparison has an || skip merging. That's complicated. ddor := strings.Index(dd.Reference, "||") eor := strings.Index(existing.Reference, "||") if ddor == -1 && eor == -1 { // Add the comparisons together. newRef := existing.Reference + ", " + dd.Reference existing.Reference = newRef mod = append(mod, dd.Name) Info("Combining %s semantic version constraints %s and %s", existing.Name, existing.Reference, dd.Reference) } else { Warn("Conflict: %s version is %s, but also asked for %s\n", existing.Name, existing.Reference, dd.Reference) Info("Keeping %s %s", existing.Name, existing.Reference) } } } } return mod }
func benchNewConstraint(c string, b *testing.B) { for i := 0; i < b.N; i++ { semver.NewConstraint(c) } }
// VcsVersion set the VCS version for a checkout. func VcsVersion(dep *yaml.Dependency, vend string) error { // If there is no refernece configured there is nothing to set. if dep.Reference == "" { return nil } cwd := path.Join(vend, dep.Name) // When the directory is not empty and has no VCS directory it's // a vendored files situation. empty, err := isDirectoryEmpty(cwd) if err != nil { return err } _, err = v.DetectVcsFromFS(cwd) if empty == false && err == v.ErrCannotDetectVCS { Warn("%s appears to be a vendored package. Unable to set new version. Consider the '--update-vendored' flag.\n", dep.Name) } else { repo, err := dep.GetRepo(cwd) if err != nil { return err } ver := dep.Reference // Referenes in Git can begin with a ^ which is similar to semver. // If there is a ^ prefix we assume it's a semver constraint rather than // part of the git/VCS commit id. if repo.IsReference(ver) && !strings.HasPrefix(ver, "^") { Info("Setting version for %s to %s.\n", dep.Name, ver) } else { // Create the constraing first to make sure it's valid before // working on the repo. constraint, err := semver.NewConstraint(ver) // Make sure the constriant is valid. At this point it's not a valid // reference so if it's not a valid constrint we can exit early. if err != nil { Warn("The reference '%s' is not valid\n", ver) return err } // Get the tags and branches (in that order) refs, err := getAllVcsRefs(repo) if err != nil { return err } // Convert and filter the list to semver.Version instances semvers := getSemVers(refs) // Sort semver list sort.Sort(sort.Reverse(semver.Collection(semvers))) found := false for _, v := range semvers { if constraint.Check(v) { found = true // If the constrint passes get the original reference ver = v.Original() break } } if found { Info("Detected semantic version. Setting version for %s to %s.\n", dep.Name, ver) } else { Warn("Unable to find semantic version for constraint %s %s\n", dep.Name, ver) } } if err := repo.UpdateVersion(ver); err != nil { Error("Failed to set version to %s: %s\n", dep.Reference, err) return err } } return nil }
// VcsVersion set the VCS version for a checkout. func VcsVersion(dep *cfg.Dependency) error { // If the dependency has already been pinned we can skip it. This is a // faster path so we don't need to resolve it again. if dep.Pin != "" { msg.Debug("Dependency %s has already been pinned. Setting version skipped.", dep.Name) return nil } key, err := cp.Key(dep.Remote()) if err != nil { msg.Die("Cache key generation error: %s", err) } location := cp.Location() cwd := filepath.Join(location, "src", key) // If there is no reference configured there is nothing to set. if dep.Reference == "" { // Before exiting update the pinned version repo, err := dep.GetRepo(cwd) if err != nil { return err } dep.Pin, err = repo.Version() if err != nil { return err } return nil } // When the directory is not empty and has no VCS directory it's // a vendored files situation. empty, err := gpath.IsDirectoryEmpty(cwd) if err != nil { return err } _, err = v.DetectVcsFromFS(cwd) if empty == false && err == v.ErrCannotDetectVCS { return fmt.Errorf("Cache directory missing VCS information for %s", dep.Name) } repo, err := dep.GetRepo(cwd) if err != nil { return err } ver := dep.Reference // References in Git can begin with a ^ which is similar to semver. // If there is a ^ prefix we assume it's a semver constraint rather than // part of the git/VCS commit id. if repo.IsReference(ver) && !strings.HasPrefix(ver, "^") { msg.Info("--> Setting version for %s to %s.\n", dep.Name, ver) } else { // Create the constraint first to make sure it's valid before // working on the repo. constraint, err := semver.NewConstraint(ver) // Make sure the constriant is valid. At this point it's not a valid // reference so if it's not a valid constrint we can exit early. if err != nil { msg.Warn("The reference '%s' is not valid\n", ver) return err } // Get the tags and branches (in that order) refs, err := getAllVcsRefs(repo) if err != nil { return err } // Convert and filter the list to semver.Version instances semvers := getSemVers(refs) // Sort semver list sort.Sort(sort.Reverse(semver.Collection(semvers))) found := false for _, v := range semvers { if constraint.Check(v) { found = true // If the constrint passes get the original reference ver = v.Original() break } } if found { msg.Info("--> Detected semantic version. Setting version for %s to %s.", dep.Name, ver) } else { msg.Warn("--> Unable to find semantic version for constraint %s %s", dep.Name, ver) } } if err := repo.UpdateVersion(ver); err != nil { return err } dep.Pin, err = repo.Version() if err != nil { return err } return nil }