2021-07-30 08:02:03 +02:00
|
|
|
package mod
|
|
|
|
|
|
|
|
import (
|
2021-10-23 00:37:28 +02:00
|
|
|
"context"
|
2021-07-30 08:02:03 +02:00
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
"sort"
|
2021-08-10 12:23:03 +02:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/go-git/go-git/v5/plumbing/transport/ssh"
|
2021-10-23 00:37:28 +02:00
|
|
|
"github.com/rs/zerolog/log"
|
2021-07-30 08:02:03 +02:00
|
|
|
|
|
|
|
"github.com/go-git/go-git/v5"
|
|
|
|
"github.com/go-git/go-git/v5/plumbing"
|
|
|
|
"github.com/hashicorp/go-version"
|
|
|
|
)
|
|
|
|
|
|
|
|
type repo struct {
|
2021-10-13 23:32:06 +02:00
|
|
|
contents *git.Repository
|
2021-10-23 00:37:28 +02:00
|
|
|
require *Require
|
2021-07-30 08:02:03 +02:00
|
|
|
}
|
|
|
|
|
2021-10-23 00:37:28 +02:00
|
|
|
func clone(ctx context.Context, require *Require, dir string, privateKeyFile, privateKeyPassword string) (*repo, error) {
|
2021-10-13 23:32:06 +02:00
|
|
|
if err := os.RemoveAll(dir); err != nil {
|
|
|
|
return nil, fmt.Errorf("error cleaning up tmp directory")
|
|
|
|
}
|
|
|
|
if err := os.MkdirAll(dir, 0755); err != nil {
|
|
|
|
return nil, fmt.Errorf("error creating tmp dir for cloning package")
|
|
|
|
}
|
|
|
|
|
2021-08-10 12:23:03 +02:00
|
|
|
o := git.CloneOptions{
|
|
|
|
URL: fmt.Sprintf("https://%s", require.cloneRepo),
|
|
|
|
}
|
|
|
|
|
|
|
|
if privateKeyFile != "" {
|
|
|
|
publicKeys, err := ssh.NewPublicKeysFromFile("git", privateKeyFile, privateKeyPassword)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
o.Auth = publicKeys
|
|
|
|
o.URL = fmt.Sprintf("git@%s", strings.Replace(require.cloneRepo, "/", ":", 1))
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := git.PlainClone(dir, false, &o)
|
2021-07-30 08:02:03 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
rr := &repo{
|
2021-10-13 23:32:06 +02:00
|
|
|
contents: r,
|
2021-10-23 00:37:28 +02:00
|
|
|
require: require,
|
2021-07-30 08:02:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if require.version == "" {
|
2021-10-23 00:37:28 +02:00
|
|
|
latestTag, err := rr.latestTag(ctx, require.versionConstraint)
|
2021-07-30 08:02:03 +02:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-08-12 08:37:17 +02:00
|
|
|
|
|
|
|
require.version = latestTag
|
2021-07-30 08:02:03 +02:00
|
|
|
}
|
|
|
|
|
2021-10-23 00:37:28 +02:00
|
|
|
if err := rr.checkout(ctx, require.version); err != nil {
|
2021-07-30 08:02:03 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return rr, nil
|
|
|
|
}
|
|
|
|
|
2021-10-23 00:37:28 +02:00
|
|
|
func (r *repo) checkout(ctx context.Context, version string) error {
|
|
|
|
lg := log.Ctx(ctx)
|
|
|
|
|
2021-07-30 08:02:03 +02:00
|
|
|
h, err := r.contents.ResolveRevision(plumbing.Revision(version))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-10-23 00:37:28 +02:00
|
|
|
lg.Debug().Str("repository", r.require.repo).Str("version", version).Str("commit", h.String()).Msg("checkout repo")
|
|
|
|
|
2021-07-30 08:02:03 +02:00
|
|
|
w, err := r.contents.Worktree()
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = w.Checkout(&git.CheckoutOptions{
|
|
|
|
Hash: *h,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-10-23 00:37:28 +02:00
|
|
|
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()
|
|
|
|
|
2021-10-22 02:50:18 +02:00
|
|
|
if versionConstraint == "" {
|
|
|
|
versionConstraint = ">= 0"
|
|
|
|
}
|
|
|
|
|
|
|
|
constraint, err := version.NewConstraint(versionConstraint)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-07-30 08:02:03 +02:00
|
|
|
iter, err := r.contents.Tags()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var tags []string
|
2021-10-22 02:50:18 +02:00
|
|
|
err = iter.ForEach(func(ref *plumbing.Reference) error {
|
|
|
|
tagV := ref.Name().Short()
|
|
|
|
|
|
|
|
if !strings.HasPrefix(tagV, "v") {
|
2021-10-23 00:37:28 +02:00
|
|
|
lg.Debug().Str("tag", tagV).Msg("tag version ignored, wrong format")
|
2021-10-22 02:50:18 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
v, err := version.NewVersion(tagV)
|
|
|
|
if err != nil {
|
2021-10-23 00:37:28 +02:00
|
|
|
lg.Debug().Str("tag", tagV).Err(err).Msg("tag version ignored, parsing error")
|
2021-10-22 02:50:18 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if constraint.Check(v) {
|
|
|
|
// Add tag if it matches the version constraint
|
|
|
|
tags = append(tags, ref.Name().Short())
|
2021-10-23 00:37:28 +02:00
|
|
|
lg.Debug().Str("tag", tagV).Msg("version added")
|
|
|
|
} else {
|
|
|
|
lg.Debug().Str("tag", tagV).Msg("tag version ignored, does not satisfy constraint")
|
2021-10-22 02:50:18 +02:00
|
|
|
}
|
|
|
|
|
2021-07-30 08:02:03 +02:00
|
|
|
return nil
|
2021-10-22 02:50:18 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
if err != nil {
|
2021-07-30 08:02:03 +02:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return tags, nil
|
|
|
|
}
|
|
|
|
|
2021-10-23 00:37:28 +02:00
|
|
|
func (r *repo) latestTag(ctx context.Context, versionConstraint string) (string, error) {
|
|
|
|
versionsRaw, err := r.listTagVersions(ctx, versionConstraint)
|
2021-07-30 08:02:03 +02:00
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
versions := make([]*version.Version, len(versionsRaw))
|
|
|
|
for i, raw := range versionsRaw {
|
|
|
|
v, _ := version.NewVersion(raw)
|
|
|
|
versions[i] = v
|
|
|
|
}
|
|
|
|
|
2021-08-12 08:37:17 +02:00
|
|
|
if len(versions) == 0 {
|
2021-10-22 02:50:18 +02:00
|
|
|
return "", fmt.Errorf("repo doesn't have any tags matching the required version")
|
2021-08-12 08:37:17 +02:00
|
|
|
}
|
|
|
|
|
2021-10-22 02:50:18 +02:00
|
|
|
sort.Sort(sort.Reverse(version.Collection(versions)))
|
2021-10-23 00:37:28 +02:00
|
|
|
version := versions[0].Original()
|
|
|
|
|
|
|
|
return version, nil
|
2021-07-30 08:02:03 +02:00
|
|
|
}
|