mod: added support for version constraint when fetching a remote version

Signed-off-by: Sam Alba <samalba@users.noreply.github.com>
This commit is contained in:
Sam Alba 2021-10-21 17:50:18 -07:00
parent 428aca1c03
commit cee8c91e50
7 changed files with 74 additions and 49 deletions

View File

@ -98,7 +98,8 @@ func read(fMod, fSum io.Reader) (*file, error) {
return nil, fmt.Errorf("repos in mod and sum line don't match: %s and %s", modSplit[0], sumSplit[0]) return nil, fmt.Errorf("repos in mod and sum line don't match: %s and %s", modSplit[0], sumSplit[0])
} }
require, err := newRequire(modSplit[0]) // FIXME: if we want to add support for version constraints in the mod file, it would be here
require, err := newRequire(modSplit[0], "")
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -204,7 +205,7 @@ func (f *file) updateToLatest(req *Require) (*Require, error) {
} }
// checkout the latest tag // checkout the latest tag
latestTag, err := gitRepo.latestTag() latestTag, err := gitRepo.latestTag(req.versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -6,14 +6,8 @@ import (
"github.com/gofrs/flock" "github.com/gofrs/flock"
) )
func InstallStdlib(workspace string) error { func Install(workspace, repoName, versionConstraint string) (*Require, error) {
_, err := Install(workspace, "alpha.dagger.io@v0.1") require, err := newRequire(repoName, versionConstraint)
return err
}
func Install(workspace, repoName string) (*Require, error) {
require, err := newRequire(repoName)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -51,7 +45,7 @@ func InstallAll(workspace string, repoNames []string) ([]*Require, error) {
for _, repoName := range repoNames { for _, repoName := range repoNames {
var require *Require var require *Require
if require, err = Install(workspace, repoName); err != nil { if require, err = Install(workspace, repoName, ""); err != nil {
continue continue
} }
@ -61,8 +55,8 @@ func InstallAll(workspace string, repoNames []string) ([]*Require, error) {
return installedRequires, err return installedRequires, err
} }
func Update(workspace, repoName string) (*Require, error) { func Update(workspace, repoName, versionConstraint string) (*Require, error) {
require, err := newRequire(repoName) require, err := newRequire(repoName, versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -100,7 +94,7 @@ func UpdateAll(workspace string, repoNames []string) ([]*Require, error) {
for _, repoName := range repoNames { for _, repoName := range repoNames {
var require *Require var require *Require
if require, err = Update(workspace, repoName); err != nil { if require, err = Update(workspace, repoName, ""); err != nil {
continue continue
} }

View File

@ -49,7 +49,7 @@ func clone(require *Require, dir string, privateKeyFile, privateKeyPassword stri
} }
if require.version == "" { if require.version == "" {
latestTag, err := rr.latestTag() latestTag, err := rr.latestTag(require.versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -85,25 +85,53 @@ func (r *repo) checkout(version string) error {
return nil return nil
} }
func (r *repo) listTags() ([]string, error) { func (r *repo) listTagVersions(versionConstraint string) ([]string, error) {
if versionConstraint == "" {
versionConstraint = ">= 0"
}
constraint, err := version.NewConstraint(versionConstraint)
if err != nil {
return nil, err
}
iter, err := r.contents.Tags() iter, err := r.contents.Tags()
if err != nil { if err != nil {
return nil, err return nil, err
} }
var tags []string var tags []string
if err := iter.ForEach(func(ref *plumbing.Reference) error { err = iter.ForEach(func(ref *plumbing.Reference) error {
tags = append(tags, ref.Name().Short()) tagV := ref.Name().Short()
if !strings.HasPrefix(tagV, "v") {
// ignore wrong formatted tags
return nil return nil
}); err != nil { }
v, err := version.NewVersion(tagV)
if err != nil {
// ignore invalid tag
return nil
}
if constraint.Check(v) {
// Add tag if it matches the version constraint
tags = append(tags, ref.Name().Short())
}
return nil
})
if err != nil {
return nil, err return nil, err
} }
return tags, nil return tags, nil
} }
func (r *repo) latestTag() (string, error) { func (r *repo) latestTag(versionConstraint string) (string, error) {
versionsRaw, err := r.listTags() versionsRaw, err := r.listTagVersions(versionConstraint)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -115,10 +143,9 @@ func (r *repo) latestTag() (string, error) {
} }
if len(versions) == 0 { if len(versions) == 0 {
return "", fmt.Errorf("repo doesn't have any tags") return "", fmt.Errorf("repo doesn't have any tags matching the required version")
} }
sort.Sort(version.Collection(versions)) sort.Sort(sort.Reverse(version.Collection(versions)))
return versions[0].Original(), nil
return versions[len(versions)-1].Original(), nil
} }

View File

@ -74,7 +74,7 @@ func TestListTags(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
tags, err := r.listTags() tags, err := r.listTagVersions("")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

View File

@ -16,15 +16,16 @@ type Require struct {
clonePath string clonePath string
version string version string
versionConstraint string
checksum string checksum string
} }
func newRequire(repoName string) (*Require, error) { func newRequire(repoName, versionConstraint string) (*Require, error) {
switch { switch {
case strings.HasPrefix(repoName, "github.com"): case strings.HasPrefix(repoName, "github.com"):
return parseGithubRepoName(repoName) return parseGithubRepoName(repoName, versionConstraint)
case strings.HasPrefix(repoName, "alpha.dagger.io"): case strings.HasPrefix(repoName, "alpha.dagger.io"):
return parseDaggerRepoName(repoName) return parseDaggerRepoName(repoName, versionConstraint)
default: default:
return nil, fmt.Errorf("repo name does not match suported providers") return nil, fmt.Errorf("repo name does not match suported providers")
} }
@ -32,7 +33,7 @@ func newRequire(repoName string) (*Require, error) {
var githubRepoNameRegex = regexp.MustCompile(`(github.com/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)([a-zA-Z0-9/_.-]*)@?([0-9a-zA-Z.-]*)`) var githubRepoNameRegex = regexp.MustCompile(`(github.com/[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+)([a-zA-Z0-9/_.-]*)@?([0-9a-zA-Z.-]*)`)
func parseGithubRepoName(repoName string) (*Require, error) { func parseGithubRepoName(repoName, versionConstraint string) (*Require, error) {
repoMatches := githubRepoNameRegex.FindStringSubmatch(repoName) repoMatches := githubRepoNameRegex.FindStringSubmatch(repoName)
if len(repoMatches) < 4 { if len(repoMatches) < 4 {
@ -43,6 +44,7 @@ func parseGithubRepoName(repoName string) (*Require, error) {
repo: repoMatches[1], repo: repoMatches[1],
path: repoMatches[2], path: repoMatches[2],
version: repoMatches[3], version: repoMatches[3],
versionConstraint: versionConstraint,
cloneRepo: repoMatches[1], cloneRepo: repoMatches[1],
clonePath: repoMatches[2], clonePath: repoMatches[2],
@ -51,7 +53,7 @@ func parseGithubRepoName(repoName string) (*Require, error) {
var daggerRepoNameRegex = regexp.MustCompile(`alpha.dagger.io([a-zA-Z0-9/_.-]*)@?([0-9a-zA-Z.-]*)`) var daggerRepoNameRegex = regexp.MustCompile(`alpha.dagger.io([a-zA-Z0-9/_.-]*)@?([0-9a-zA-Z.-]*)`)
func parseDaggerRepoName(repoName string) (*Require, error) { func parseDaggerRepoName(repoName, versionConstraint string) (*Require, error) {
repoMatches := daggerRepoNameRegex.FindStringSubmatch(repoName) repoMatches := daggerRepoNameRegex.FindStringSubmatch(repoName)
if len(repoMatches) < 3 { if len(repoMatches) < 3 {
@ -62,6 +64,7 @@ func parseDaggerRepoName(repoName string) (*Require, error) {
repo: "alpha.dagger.io", repo: "alpha.dagger.io",
path: repoMatches[1], path: repoMatches[1],
version: repoMatches[2], version: repoMatches[2],
versionConstraint: versionConstraint,
cloneRepo: "github.com/dagger/universe", cloneRepo: "github.com/dagger/universe",
clonePath: path.Join("/stdlib", repoMatches[1]), clonePath: path.Join("/stdlib", repoMatches[1]),

View File

@ -98,7 +98,7 @@ func TestParseArgument(t *testing.T) {
for _, c := range cases { for _, c := range cases {
t.Run(c.name, func(t *testing.T) { t.Run(c.name, func(t *testing.T) {
got, err := newRequire(c.in) got, err := newRequire(c.in, "")
if err != nil && c.hasError { if err != nil && c.hasError {
return return
} }

View File

@ -12,6 +12,7 @@ import (
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
"go.dagger.io/dagger/keychain" "go.dagger.io/dagger/keychain"
"go.dagger.io/dagger/mod"
"go.dagger.io/dagger/stdlib" "go.dagger.io/dagger/stdlib"
"gopkg.in/yaml.v3" "gopkg.in/yaml.v3"
) )
@ -30,6 +31,7 @@ const (
planDir = "plan" planDir = "plan"
manifestFile = "values.yaml" manifestFile = "values.yaml"
computedFile = "computed.json" computedFile = "computed.json"
universeVersionConstraint = ">= 0.1, < 0.2"
) )
type Project struct { type Project struct {
@ -396,9 +398,7 @@ func vendorUniverse(ctx context.Context, p string) error {
} }
log.Ctx(ctx).Debug().Str("mod", p).Msg("vendoring universe") log.Ctx(ctx).Debug().Str("mod", p).Msg("vendoring universe")
// FIXME(samalba): disabled install remote stdlib temporarily if _, err := mod.Install(p, "alpha.dagger.io", universeVersionConstraint); err != nil {
// if err := mod.InstallStdlib(p); err != nil {
if err := stdlib.Vendor(ctx, p); err != nil {
return err return err
} }