add the ability to specify repository ref
This commit is contained in:
		| @@ -33,6 +33,7 @@ import ( | ||||
| 	"github.com/go-git/go-billy/v5" | ||||
| 	"github.com/go-git/go-billy/v5/osfs" | ||||
| 	"github.com/go-git/go-git/v5" | ||||
| 	gitConfig "github.com/go-git/go-git/v5/config" | ||||
| 	"github.com/go-git/go-git/v5/plumbing" | ||||
| 	"github.com/leonelquinteros/gotext" | ||||
| 	"github.com/pelletier/go-toml/v2" | ||||
| @@ -88,6 +89,14 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			err = r.FetchContext(ctx, &git.FetchOptions{ | ||||
| 				Progress: os.Stderr, | ||||
| 				Force:    true, | ||||
| 			}) | ||||
| 			if err != nil && !errors.Is(err, git.NoErrAlreadyUpToDate) { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			w, err := r.Worktree() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| @@ -98,34 +107,41 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			err = w.PullContext(ctx, &git.PullOptions{Progress: os.Stderr}) | ||||
| 			if errors.Is(err, git.NoErrAlreadyUpToDate) { | ||||
| 			revHash, err := resolveHash(r, repo.Ref) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("error resolving hash: %w", err) | ||||
| 			} | ||||
|  | ||||
| 			if old.Hash() == *revHash { | ||||
| 				slog.Info(gotext.Get("Repository up to date"), "name", repo.Name) | ||||
| 			} else if err != nil { | ||||
| 			} | ||||
|  | ||||
| 			err = w.Checkout(&git.CheckoutOptions{ | ||||
| 				Hash:  plumbing.NewHash(revHash.String()), | ||||
| 				Force: true, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			repoFS = w.Filesystem | ||||
|  | ||||
| 			// Make sure the DB is created even if the repo is up to date | ||||
| 			if !errors.Is(err, git.NoErrAlreadyUpToDate) || rs.db.IsEmpty(ctx) { | ||||
| 				new, err := r.Head() | ||||
| 			new, err := r.Head() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			// If the DB was not present at startup, that means it's | ||||
| 			// empty. In this case, we need to update the DB fully | ||||
| 			// rather than just incrementally. | ||||
| 			if rs.db.IsEmpty(ctx) { | ||||
| 				err = rs.processRepoFull(ctx, repo, repoDir) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
|  | ||||
| 				// If the DB was not present at startup, that means it's | ||||
| 				// empty. In this case, we need to update the DB fully | ||||
| 				// rather than just incrementally. | ||||
| 				if rs.db.IsEmpty(ctx) { | ||||
| 					err = rs.processRepoFull(ctx, repo, repoDir) | ||||
| 					if err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 				} else { | ||||
| 					err = rs.processRepoChanges(ctx, repo, r, w, old, new) | ||||
| 					if err != nil { | ||||
| 						return err | ||||
| 					} | ||||
| 			} else { | ||||
| 				err = rs.processRepoChanges(ctx, repo, r, w, old, new) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 			} | ||||
| 		} else { | ||||
| @@ -139,9 +155,40 @@ func (rs *Repos) Pull(ctx context.Context, repos []types.Repo) error { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			_, err = git.PlainCloneContext(ctx, repoDir, false, &git.CloneOptions{ | ||||
| 				URL:      repoURL.String(), | ||||
| 			r, err := git.PlainInit(repoDir, false) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			_, err = r.CreateRemote(&gitConfig.RemoteConfig{ | ||||
| 				Name: git.DefaultRemoteName, | ||||
| 				URLs: []string{repoURL.String()}, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			err = r.FetchContext(ctx, &git.FetchOptions{ | ||||
| 				Progress: os.Stderr, | ||||
| 				Force:    true, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			w, err := r.Worktree() | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			revHash, err := resolveHash(r, repo.Ref) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("error resolving hash: %w", err) | ||||
| 			} | ||||
|  | ||||
| 			err = w.Checkout(&git.CheckoutOptions{ | ||||
| 				Hash:  plumbing.NewHash(revHash.String()), | ||||
| 				Force: true, | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| @@ -268,7 +315,8 @@ func (rs *Repos) processRepoChangesRunner(repoDir, scriptDir string) (*interp.Ru | ||||
| 		interp.StatHandler(handlers.RestrictedStat(repoDir)), | ||||
| 		interp.OpenHandler(handlers.RestrictedOpen(repoDir)), | ||||
| 		interp.StdIO(handlers.NopRWC{}, handlers.NopRWC{}, handlers.NopRWC{}), | ||||
| 		interp.Dir(scriptDir), | ||||
| 		// Use temp dir instead script dir because runner may be for deleted file | ||||
| 		interp.Dir(os.TempDir()), | ||||
| 	) | ||||
| } | ||||
|  | ||||
| @@ -285,7 +333,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git | ||||
|  | ||||
| 	patch, err := oldCommit.Patch(newCommit) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 		return fmt.Errorf("error to create patch: %w", err) | ||||
| 	} | ||||
|  | ||||
| 	var actions []action | ||||
| @@ -319,6 +367,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git | ||||
| 				}, | ||||
| 			) | ||||
| 		default: | ||||
| 			slog.Debug("unexpected, but I'll try to do") | ||||
| 			actions = append(actions, action{ | ||||
| 				Type: actionUpdate, | ||||
| 				File: to.Path(), | ||||
| @@ -332,7 +381,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git | ||||
| 	for _, action := range actions { | ||||
| 		runner, err := rs.processRepoChangesRunner(repoDir, filepath.Dir(filepath.Join(repoDir, action.File))) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 			return fmt.Errorf("error creating process repo changes runner: %w", err) | ||||
| 		} | ||||
|  | ||||
| 		switch action.Type { | ||||
| @@ -340,15 +389,19 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git | ||||
| 			if filepath.Base(action.File) != "alr.sh" { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			scriptFl, err := oldCommit.File(action.File) | ||||
| 			if err != nil { | ||||
| 				return nil | ||||
| 				return fmt.Errorf("error getting file: %w", err) | ||||
| 			} | ||||
|  | ||||
| 			r, err := scriptFl.Reader() | ||||
| 			if err != nil { | ||||
| 				return nil | ||||
| 				return fmt.Errorf("error creating reader: %w", err) | ||||
| 			} | ||||
|  | ||||
| 			runner, err := rs.processRepoChangesRunner(repoDir, filepath.Dir(filepath.Join(repoDir, action.File))) | ||||
| 			if err != nil { | ||||
| 				return fmt.Errorf("error creating process repo changes runner: %w", err) | ||||
| 			} | ||||
|  | ||||
| 			var pkg db.Package | ||||
| @@ -378,7 +431,7 @@ func (rs *Repos) processRepoChanges(ctx context.Context, repo types.Repo, r *git | ||||
|  | ||||
| 			err = rs.updatePkg(ctx, repo, runner, r) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 				return fmt.Errorf("error updatePkg: %w", err) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
| @@ -18,12 +18,18 @@ package repos | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/go-git/go-git/v5" | ||||
| 	"github.com/go-git/go-git/v5/plumbing" | ||||
| 	"github.com/go-git/go-git/v5/plumbing/format/diff" | ||||
| 	"github.com/go-git/go-git/v5/plumbing/transport" | ||||
| 	"github.com/go-git/go-git/v5/plumbing/transport/client" | ||||
|  | ||||
| 	"mvdan.cc/sh/v3/interp" | ||||
| 	"mvdan.cc/sh/v3/syntax" | ||||
|  | ||||
| @@ -137,3 +143,59 @@ func resolveOverrides(runner *interp.Runner, pkg *db.Package) { | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func getHeadReference(r *git.Repository) (plumbing.ReferenceName, error) { | ||||
| 	remote, err := r.Remote(git.DefaultRemoteName) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	endpoint, err := transport.NewEndpoint(remote.Config().URLs[0]) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	gitClient, err := client.NewClient(endpoint) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	session, err := gitClient.NewUploadPackSession(endpoint, nil) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	info, err := session.AdvertisedReferences() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	refs, err := info.AllReferences() | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return refs["HEAD"].Target(), nil | ||||
| } | ||||
|  | ||||
| func resolveHash(r *git.Repository, ref string) (*plumbing.Hash, error) { | ||||
| 	var err error | ||||
|  | ||||
| 	if ref == "" { | ||||
| 		reference, err := getHeadReference(r) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to get head reference %w", err) | ||||
| 		} | ||||
| 		ref = reference.Short() | ||||
| 	} | ||||
|  | ||||
| 	hsh, err := r.ResolveRevision(git.DefaultRemoteName + "/" + plumbing.Revision(ref)) | ||||
| 	if err != nil { | ||||
| 		hsh, err = r.ResolveRevision(plumbing.Revision(ref)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return hsh, nil | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user