Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions core/pkg/executor/action_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"errors"
"fmt"
"io"
"io/fs"
"net/url"
"path/filepath"

Expand All @@ -24,7 +25,6 @@ import (
"drassi.run/core/pkg/store/git"
"drassi.run/core/util/dig"
"drassi.run/core/util/otel"
"github.com/go-git/go-git/v5/plumbing/object"
"go.opentelemetry.io/otel/trace"
"go.uber.org/dig"
"gopkg.in/yaml.v3"
Expand Down Expand Up @@ -75,7 +75,12 @@ func (spec *ReferenceActionSpec) CreateExecutor(
token = ""
}

if rev, err := store.Fetch(ctx, spec.Repo, token); err != nil {
var fetchOpts []gitstore.FetchOption
if token != "" {
fetchOpts = append(fetchOpts, gitstore.WithToken(token))
}

if rev, err := store.Fetch(ctx, spec.Repo, fetchOpts...); err != nil {
return nil, err
} else {
s.Writef("Download action repository %q (SHA:%s)", gitstore.Location(spec.Repo), rev)
Expand All @@ -97,28 +102,28 @@ func (spec *ReferenceActionSpec) loadAction(ctx context.Context, s *scribe.Scrib
// 1. First, try reading "action.yml" or "action.yaml" file
for _, f := range []string{"action.yml", "action.yaml"} {
path := filepath.Join(spec.Repo.Path, f)
if r, err := store.File(ctx, spec.Repo, spec.rev, path); err == nil {
if r, err := store.Read(ctx, spec.Repo, spec.rev, gitstore.WithFile(path)); err == nil {
span.AddEvent("Loaded Action",
trace.WithAttributes(xotel.ActionPath(path)),
)
s.Debugf("Loading %q for action", path)
return spec.loadActionManifest(r)
} else if !errors.Is(err, object.ErrFileNotFound) {
} else if !errors.Is(err, fs.ErrNotExist) {
return nil, err
}
}

// 2. Second, try reading "Dockerfile" or "dockerfile"
for _, f := range []string{"Dockerfile", "dockerfile"} {
path := filepath.Join(spec.Repo.Path, f)
if r, err := store.File(ctx, spec.Repo, spec.rev, path); err == nil {
if r, err := store.Read(ctx, spec.Repo, spec.rev, gitstore.WithFile(path)); err == nil {
r.Close()
span.AddEvent("Loaded Action",
trace.WithAttributes(xotel.ActionPath(path)),
)
s.Debugf("Loading %q for action", path)
return spec.createDockerfileAction(path)
} else if !errors.Is(err, object.ErrFileNotFound) {
} else if !errors.Is(err, fs.ErrNotExist) {
return nil, err
}
}
Expand Down Expand Up @@ -154,8 +159,7 @@ func (spec *ReferenceActionSpec) createDockerfileAction(dockerfile string) (Acti
}

func (spec *ReferenceActionSpec) transferAction(ctx context.Context, store gitstore.Manager, sandbox sandboxer.Sandbox) error {
location := gitstore.FullName(spec.Repo) + "@" + spec.Repo.Ref
r, err := store.Read(ctx, spec.Repo, spec.rev, location)
r, err := store.Read(ctx, spec.Repo, spec.rev, gitstore.WithSubpath(spec.Repo.Path))
if err != nil {
return err
}
Expand Down
109 changes: 55 additions & 54 deletions core/pkg/store/git/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ import (
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/cache"
"github.com/go-git/go-git/v5/plumbing/object"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
"github.com/go-git/go-git/v5/storage"
"github.com/go-git/go-git/v5/storage/filesystem"
"github.com/hashicorp/golang-lru/v2/expirable"
Expand All @@ -39,9 +37,8 @@ import (
)

type Manager interface {
Fetch(ctx context.Context, repo *RepoReference, token string) (rev string, err error)
Read(ctx context.Context, repo *RepoReference, rev, dir string) (io.ReadCloser, error)
File(ctx context.Context, repo *RepoReference, rev, path string) (io.ReadCloser, error)
Fetch(ctx context.Context, repo *RepoReference, opts ...FetchOption) (rev string, err error)
Read(ctx context.Context, repo *RepoReference, rev string, opts ...ReadOption) (io.ReadCloser, error)
Close() error
}

Expand Down Expand Up @@ -87,7 +84,7 @@ func (m *manager) onEvict(_ string, repo *git.Repository) {
}
}

func (m *manager) Fetch(ctx context.Context, repo *RepoReference, token string) (string, error) {
func (m *manager) Fetch(ctx context.Context, repo *RepoReference, opts ...FetchOption) (string, error) {
key := Location(repo)
v, err, _ := m.sf.Do(key, func() (any, error) {
repoPath, err := m.ensureDir(repo)
Expand All @@ -103,7 +100,7 @@ func (m *manager) Fetch(ctx context.Context, repo *RepoReference, token string)
tmpBranch := rand.String(12)
defer gitRepo.DeleteBranch(tmpBranch)

err = m.fetch(ctx, gitRepo, repo, token, tmpBranch)
err = m.fetch(ctx, gitRepo, repo, tmpBranch, opts...)
if err != nil {
return "", err
}
Expand All @@ -120,7 +117,16 @@ func (m *manager) Fetch(ctx context.Context, repo *RepoReference, token string)
return v.(string), nil
}

func (m *manager) Read(ctx context.Context, repo *RepoReference, rev string, dir string) (io.ReadCloser, error) {
func (m *manager) Read(ctx context.Context, repo *RepoReference, rev string, opts ...ReadOption) (io.ReadCloser, error) {
ro := new(readOptions)
for _, opt := range opts {
opt(ro)
}

if ro.file != "" && ro.subpath != "" {
return nil, errors.New("cannot specify both file and subpath")
}

gitRepo, err := m.getRepo(repo)
if err != nil {
return nil, err
Expand All @@ -130,6 +136,39 @@ func (m *manager) Read(ctx context.Context, repo *RepoReference, rev string, dir
if err != nil {
return nil, err
}

if ro.file != "" {
return m.readFile(commit, ro.file)
}
return m.readArchive(ctx, commit, ro.subpath)
}

func (m *manager) readFile(commit *object.Commit, filePath string) (io.ReadCloser, error) {
tree, err := commit.Tree()
if err != nil {
return nil, err
}

cleanPath := strings.TrimPrefix(path.Clean(filePath), "/")
entry, err := tree.FindEntry(cleanPath)
if err != nil {
if notFoundErr(err) {
return nil, fs.ErrNotExist
}
return nil, err
}
if !entry.Mode.IsFile() {
return nil, fmt.Errorf("%q is not a (regular) file", filePath)
}

file, err := tree.TreeEntryFile(entry)
if err != nil {
return nil, err
}
return file.Reader()
}

func (m *manager) readArchive(ctx context.Context, commit *object.Commit, subpath string) (io.ReadCloser, error) {
files, err := commit.Files()
if err != nil {
return nil, err
Expand All @@ -149,7 +188,7 @@ func (m *manager) Read(ctx context.Context, repo *RepoReference, rev string, dir
defer close(ch)

tw := tar.NewWriter(writer)
handler := newTarHandler(tw, dir)
handler := newTarHandler(tw, subpath)

err := files.ForEach(handler)
err = cmp.Or(err, tw.Close())
Expand All @@ -158,41 +197,6 @@ func (m *manager) Read(ctx context.Context, repo *RepoReference, rev string, dir
return reader, nil
}

func (m *manager) File(ctx context.Context, repo *RepoReference, rev, filePath string) (io.ReadCloser, error) {
gitRepo, err := m.getRepo(repo)
if err != nil {
return nil, err
}

commit, err := gitRepo.CommitObject(plumbing.NewHash(rev))
if err != nil {
return nil, err
}

tree, err := commit.Tree()
if err != nil {
return nil, err
}

cleanPath := strings.TrimPrefix(path.Clean(filePath), "/")
entry, err := tree.FindEntry(cleanPath)
if err != nil {
if notFoundErr(err) {
return nil, fs.ErrNotExist
}
return nil, err
}
if !entry.Mode.IsFile() {
return nil, fmt.Errorf("%q is not a (regular) file", filePath)
}

if file, err := tree.TreeEntryFile(entry); err != nil {
return nil, err
} else {
return file.Reader()
}
}

func (m *manager) getRepo(repo *RepoReference) (*git.Repository, error) {
id := FullName(repo)
if gitRepo, ok := m.repos.Get(id); ok {
Expand All @@ -215,13 +219,10 @@ func (m *manager) getRepo(repo *RepoReference) (*git.Repository, error) {
return gitRepo, nil
}

func (m *manager) fetch(ctx context.Context, gitRepo *git.Repository, repo *RepoReference, token, branch string) error {
var auth transport.AuthMethod
if token != "" {
auth = &http.BasicAuth{
Username: "token",
Password: token,
}
func (m *manager) fetch(ctx context.Context, gitRepo *git.Repository, repo *RepoReference, branch string, opts ...FetchOption) error {
fo := new(fetchOptions)
for _, opt := range opts {
opt(fo)
}

remoteConfig := &config.RemoteConfig{
Expand All @@ -235,18 +236,18 @@ func (m *manager) fetch(ctx context.Context, gitRepo *git.Repository, repo *Repo

// TODO: using treeless clone when go-git implement it
// https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/
fetchOptions := &git.FetchOptions{
gfo := &git.FetchOptions{
RefSpecs: []config.RefSpec{
config.RefSpec(fmt.Sprintf("+%s:refs/heads/%s", repo.Ref, branch)),
},

Auth: auth,
Auth: fo.auth,
Tags: git.NoTags,
Force: true,
Prune: true,
}

return remote.FetchContext(ctx, fetchOptions)
return remote.FetchContext(ctx, gfo)
}

func (m *manager) ensureDir(repo *RepoReference) (string, error) {
Expand Down
Loading
Loading