mod: lock the version of universe for updates of package

Signed-off-by: Sam Alba <samalba@users.noreply.github.com>
This commit is contained in:
Sam Alba 2021-10-22 15:37:28 -07:00
parent 779dda1aca
commit 5e6d1261f7
5 changed files with 84 additions and 41 deletions

View File

@ -2,6 +2,7 @@ package mod
import ( import (
"bytes" "bytes"
"context"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -15,11 +16,13 @@ import (
"github.com/spf13/viper" "github.com/spf13/viper"
) )
const modFilePath = "./cue.mod/dagger.mod" const (
const sumFilePath = "./cue.mod/dagger.sum" modFilePath = "./cue.mod/dagger.mod"
const lockFilePath = "./cue.mod/dagger.lock" sumFilePath = "./cue.mod/dagger.sum"
const destBasePath = "./cue.mod/pkg" lockFilePath = "./cue.mod/dagger.lock"
const tmpBasePath = "./cue.mod/tmp" destBasePath = "./cue.mod/pkg"
tmpBasePath = "./cue.mod/tmp"
)
// file is the parsed, interpreted form of dagger.mod file. // file is the parsed, interpreted form of dagger.mod file.
type file struct { type file struct {
@ -127,20 +130,19 @@ func nonEmptyLines(b []byte) []string {
} }
trimmed = spaceRgx.ReplaceAllString(trimmed, " ") trimmed = spaceRgx.ReplaceAllString(trimmed, " ")
lines = append(lines, trimmed) lines = append(lines, trimmed)
} }
return lines return lines
} }
func (f *file) install(req *Require) error { func (f *file) install(ctx context.Context, req *Require) error {
// cleaning up possible leftovers // cleaning up possible leftovers
tmpPath := path.Join(f.workspacePath, tmpBasePath, req.fullPath()) tmpPath := path.Join(f.workspacePath, tmpBasePath, req.fullPath())
defer os.RemoveAll(tmpPath) defer os.RemoveAll(tmpPath)
// clone to a tmp directory // clone to a tmp directory
r, err := clone(req, tmpPath, viper.GetString("private-key-file"), viper.GetString("private-key-password")) r, err := clone(ctx, req, tmpPath, viper.GetString("private-key-file"), viper.GetString("private-key-password"))
if err != nil { if err != nil {
return fmt.Errorf("error downloading package %s: %w", req, err) return fmt.Errorf("error downloading package %s: %w", req, err)
} }
@ -169,7 +171,7 @@ func (f *file) install(req *Require) error {
// checkout the cloned repo to that tag, change the version in the existing requirement and // checkout the cloned repo to that tag, change the version in the existing requirement and
// replace the code in the /pkg folder // replace the code in the /pkg folder
existing.version = req.version existing.version = req.version
if err = r.checkout(req.version); err != nil { if err = r.checkout(ctx, req.version); err != nil {
return err return err
} }
@ -187,7 +189,7 @@ func (f *file) install(req *Require) error {
return nil return nil
} }
func (f *file) updateToLatest(req *Require) (*Require, error) { func (f *file) updateToLatest(ctx context.Context, req *Require) (*Require, error) {
// check if it doesn't exist // check if it doesn't exist
existing := f.searchInstalledRequire(req) existing := f.searchInstalledRequire(req)
if existing == nil { if existing == nil {
@ -199,13 +201,13 @@ func (f *file) updateToLatest(req *Require) (*Require, error) {
defer os.RemoveAll(tmpPath) defer os.RemoveAll(tmpPath)
// clone to a tmp directory // clone to a tmp directory
gitRepo, err := clone(existing, tmpPath, viper.GetString("private-key-file"), viper.GetString("private-key-password")) gitRepo, err := clone(ctx, existing, tmpPath, viper.GetString("private-key-file"), viper.GetString("private-key-password"))
if err != nil { if err != nil {
return nil, fmt.Errorf("error downloading package %s: %w", existing, err) return nil, fmt.Errorf("error downloading package %s: %w", existing, err)
} }
// checkout the latest tag // checkout the latest tag
latestTag, err := gitRepo.latestTag(req.versionConstraint) latestTag, err := gitRepo.latestTag(ctx, req.versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -220,7 +222,7 @@ func (f *file) updateToLatest(req *Require) (*Require, error) {
} }
existing.version = latestTag existing.version = latestTag
if err = gitRepo.checkout(existing.version); err != nil { if err = gitRepo.checkout(ctx, existing.version); err != nil {
return nil, err return nil, err
} }

View File

@ -3,15 +3,29 @@ package mod
import ( import (
"context" "context"
"path" "path"
"strings"
"github.com/gofrs/flock" "github.com/gofrs/flock"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
) )
const (
UniverseVersionConstraint = ">= 0.1.0, < 0.2"
)
func isUniverse(repoName string) bool {
return strings.HasPrefix(strings.ToLower(repoName), "alpha.dagger.io")
}
func Install(ctx context.Context, workspace, repoName, versionConstraint string) (*Require, error) { func Install(ctx context.Context, workspace, repoName, versionConstraint string) (*Require, error) {
lg := log.Ctx(ctx) lg := log.Ctx(ctx)
lg.Info().Str("name", repoName).Msg("installing module") if isUniverse(repoName) {
// override versionConstraint to lock the version of universe we vendor
versionConstraint = UniverseVersionConstraint
}
lg.Debug().Str("name", repoName).Msg("installing module")
require, err := newRequire(repoName, versionConstraint) require, err := newRequire(repoName, versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
@ -27,7 +41,7 @@ func Install(ctx context.Context, workspace, repoName, versionConstraint string)
return nil, err return nil, err
} }
err = modfile.install(require) err = modfile.install(ctx, require)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -63,7 +77,12 @@ func InstallAll(ctx context.Context, workspace string, repoNames []string) ([]*R
func Update(ctx context.Context, workspace, repoName, versionConstraint string) (*Require, error) { func Update(ctx context.Context, workspace, repoName, versionConstraint string) (*Require, error) {
lg := log.Ctx(ctx) lg := log.Ctx(ctx)
lg.Info().Str("name", repoName).Msg("updating module") if isUniverse(repoName) {
// override versionConstraint to lock the version of universe we vendor
versionConstraint = UniverseVersionConstraint
}
lg.Debug().Str("name", repoName).Msg("updating module")
require, err := newRequire(repoName, versionConstraint) require, err := newRequire(repoName, versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
@ -79,7 +98,7 @@ func Update(ctx context.Context, workspace, repoName, versionConstraint string)
return nil, err return nil, err
} }
updatedRequire, err := modfile.updateToLatest(require) updatedRequire, err := modfile.updateToLatest(ctx, require)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -1,12 +1,14 @@
package mod package mod
import ( import (
"context"
"fmt" "fmt"
"os" "os"
"sort" "sort"
"strings" "strings"
"github.com/go-git/go-git/v5/plumbing/transport/ssh" "github.com/go-git/go-git/v5/plumbing/transport/ssh"
"github.com/rs/zerolog/log"
"github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing" "github.com/go-git/go-git/v5/plumbing"
@ -15,9 +17,10 @@ import (
type repo struct { type repo struct {
contents *git.Repository contents *git.Repository
require *Require
} }
func clone(require *Require, dir string, privateKeyFile, privateKeyPassword string) (*repo, error) { func clone(ctx context.Context, require *Require, dir string, privateKeyFile, privateKeyPassword string) (*repo, error) {
if err := os.RemoveAll(dir); err != nil { if err := os.RemoveAll(dir); err != nil {
return nil, fmt.Errorf("error cleaning up tmp directory") return nil, fmt.Errorf("error cleaning up tmp directory")
} }
@ -46,10 +49,11 @@ func clone(require *Require, dir string, privateKeyFile, privateKeyPassword stri
rr := &repo{ rr := &repo{
contents: r, contents: r,
require: require,
} }
if require.version == "" { if require.version == "" {
latestTag, err := rr.latestTag(require.versionConstraint) latestTag, err := rr.latestTag(ctx, require.versionConstraint)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -57,19 +61,23 @@ func clone(require *Require, dir string, privateKeyFile, privateKeyPassword stri
require.version = latestTag require.version = latestTag
} }
if err := rr.checkout(require.version); err != nil { if err := rr.checkout(ctx, require.version); err != nil {
return nil, err return nil, err
} }
return rr, nil return rr, nil
} }
func (r *repo) checkout(version string) error { func (r *repo) checkout(ctx context.Context, version string) error {
lg := log.Ctx(ctx)
h, err := r.contents.ResolveRevision(plumbing.Revision(version)) h, err := r.contents.ResolveRevision(plumbing.Revision(version))
if err != nil { if err != nil {
return err return err
} }
lg.Debug().Str("repository", r.require.repo).Str("version", version).Str("commit", h.String()).Msg("checkout repo")
w, err := r.contents.Worktree() w, err := r.contents.Worktree()
if err != nil { if err != nil {
return err return err
@ -85,7 +93,12 @@ func (r *repo) checkout(version string) error {
return nil return nil
} }
func (r *repo) listTagVersions(versionConstraint string) ([]string, error) { func (r *repo) listTagVersions(ctx context.Context, versionConstraint string) ([]string, error) {
lg := log.Ctx(ctx).With().
Str("repository", r.require.repo).
Str("versionConstraint", versionConstraint).
Logger()
if versionConstraint == "" { if versionConstraint == "" {
versionConstraint = ">= 0" versionConstraint = ">= 0"
} }
@ -105,19 +118,22 @@ func (r *repo) listTagVersions(versionConstraint string) ([]string, error) {
tagV := ref.Name().Short() tagV := ref.Name().Short()
if !strings.HasPrefix(tagV, "v") { if !strings.HasPrefix(tagV, "v") {
// ignore wrong formatted tags lg.Debug().Str("tag", tagV).Msg("tag version ignored, wrong format")
return nil return nil
} }
v, err := version.NewVersion(tagV) v, err := version.NewVersion(tagV)
if err != nil { if err != nil {
// ignore invalid tag lg.Debug().Str("tag", tagV).Err(err).Msg("tag version ignored, parsing error")
return nil return nil
} }
if constraint.Check(v) { if constraint.Check(v) {
// Add tag if it matches the version constraint // Add tag if it matches the version constraint
tags = append(tags, ref.Name().Short()) tags = append(tags, ref.Name().Short())
lg.Debug().Str("tag", tagV).Msg("version added")
} else {
lg.Debug().Str("tag", tagV).Msg("tag version ignored, does not satisfy constraint")
} }
return nil return nil
@ -130,8 +146,8 @@ func (r *repo) listTagVersions(versionConstraint string) ([]string, error) {
return tags, nil return tags, nil
} }
func (r *repo) latestTag(versionConstraint string) (string, error) { func (r *repo) latestTag(ctx context.Context, versionConstraint string) (string, error) {
versionsRaw, err := r.listTagVersions(versionConstraint) versionsRaw, err := r.listTagVersions(ctx, versionConstraint)
if err != nil { if err != nil {
return "", err return "", err
} }
@ -147,5 +163,7 @@ func (r *repo) latestTag(versionConstraint string) (string, error) {
} }
sort.Sort(sort.Reverse(version.Collection(versions))) sort.Sort(sort.Reverse(version.Collection(versions)))
return versions[0].Original(), nil version := versions[0].Original()
return version, nil
} }

View File

@ -1,6 +1,7 @@
package mod package mod
import ( import (
"context"
"io/ioutil" "io/ioutil"
"os" "os"
"testing" "testing"
@ -50,7 +51,7 @@ func TestClone(t *testing.T) {
defer os.Remove(tmpDir) defer os.Remove(tmpDir)
_, err = clone(&c.require, tmpDir, c.privateKeyFile, c.privateKeyPassword) _, err = clone(context.TODO(), &c.require, tmpDir, c.privateKeyFile, c.privateKeyPassword)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -65,7 +66,9 @@ func TestListTags(t *testing.T) {
} }
defer os.Remove(tmpDir) defer os.Remove(tmpDir)
r, err := clone(&Require{ ctx := context.TODO()
r, err := clone(ctx, &Require{
cloneRepo: "github.com/dagger/universe", cloneRepo: "github.com/dagger/universe",
clonePath: "stdlib", clonePath: "stdlib",
version: "", version: "",
@ -74,7 +77,7 @@ func TestListTags(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
tags, err := r.listTagVersions("") tags, err := r.listTagVersions(ctx, "")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -91,7 +94,9 @@ func TestVersionConstraint(t *testing.T) {
} }
defer os.Remove(tmpDir) defer os.Remove(tmpDir)
r, err := clone(&Require{ ctx := context.TODO()
r, err := clone(ctx, &Require{
cloneRepo: "github.com/dagger/universe", cloneRepo: "github.com/dagger/universe",
clonePath: "stdlib", clonePath: "stdlib",
version: "", version: "",
@ -100,7 +105,7 @@ func TestVersionConstraint(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
tagVersion, err := r.latestTag("<= 0.1.0") tagVersion, err := r.latestTag(ctx, "<= 0.1.0")
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }
@ -111,7 +116,7 @@ func TestVersionConstraint(t *testing.T) {
} }
// Make sure an invalid constraint (version out of range) returns an error // Make sure an invalid constraint (version out of range) returns an error
_, err = r.latestTag("> 99999") _, err = r.latestTag(ctx, "> 99999")
if err == nil { if err == nil {
t.Error("selected wrong version based on constraint") t.Error("selected wrong version based on constraint")
} }

View File

@ -25,13 +25,12 @@ var (
) )
const ( const (
daggerDir = ".dagger" daggerDir = ".dagger"
envDir = "env" envDir = "env"
stateDir = "state" stateDir = "state"
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 {
@ -398,7 +397,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")
if _, err := mod.Install(ctx, p, "alpha.dagger.io", universeVersionConstraint); err != nil { if _, err := mod.Install(ctx, p, "alpha.dagger.io", ""); err != nil {
return err return err
} }