Skip to content

Commit

Permalink
#60: Composing with outdated cache
Browse files Browse the repository at this point in the history
  • Loading branch information
iignatevich committed Nov 27, 2024
1 parent 1b1300f commit 7106407
Showing 1 changed file with 171 additions and 56 deletions.
227 changes: 171 additions & 56 deletions compose/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"os"
"path/filepath"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/config"

"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/transport"
"github.com/go-git/go-git/v5/plumbing/transport/http"
Expand All @@ -23,6 +24,95 @@ func newGit(kw *keyringWrapper) Downloader {
return &gitDownloader{k: kw}
}

func (g *gitDownloader) fetchRemotes(r *git.Repository, url string, refSpec []config.RefSpec) error {
remotes, errR := r.Remotes()
if errR != nil {
return errR
}

launchr.Term().Printfln("Fetching remote %s", url)
for _, rem := range remotes {
options := git.FetchOptions{
//RefSpecs: []config.RefSpec{"refs/*:refs/*", "HEAD:refs/heads/HEAD"},
RefSpecs: refSpec,
Force: true,
}

auths := []authorizationMode{authorisationNone, authorisationKeyring, authorisationManual}
for _, authType := range auths {
if authType == authorisationNone {
err := rem.Fetch(&options)
if err != nil {
if errors.Is(err, transport.ErrAuthenticationRequired) {
continue
}

if !errors.Is(err, git.NoErrAlreadyUpToDate) {
return err
}

return nil
}
}

if authType == authorisationKeyring {
ci, err := g.k.getForURL(url)
if err != nil {
return err
}

options.Auth = &http.BasicAuth{
Username: ci.Username,
Password: ci.Password,
}

err = rem.Fetch(&options)
if err != nil {
if errors.Is(err, transport.ErrAuthorizationFailed) || errors.Is(err, transport.ErrAuthenticationRequired) {
if g.k.interactive {
launchr.Term().Println("invalid auth, trying manual authorisation")
continue
}
}

if !errors.Is(err, git.NoErrAlreadyUpToDate) {
return err
}

return nil
}
}

if authType == authorisationManual {
ci := keyring.CredentialsItem{}
ci.URL = url
ci, err := g.k.fillCredentials(ci)
if err != nil {
return err
}

options.Auth = &http.BasicAuth{
Username: ci.Username,
Password: ci.Password,
}

err = rem.Fetch(&options)
if err != nil {
if !errors.Is(err, git.NoErrAlreadyUpToDate) {
return err
}

return nil
}
}

break
}
}

return nil
}

func (g *gitDownloader) EnsureLatest(pkg *Package, downloadPath string) (bool, error) {
if _, err := os.Stat(downloadPath); os.IsNotExist(err) {
// Return False in case package doesn't exist.
Expand All @@ -31,87 +121,112 @@ func (g *gitDownloader) EnsureLatest(pkg *Package, downloadPath string) (bool, e

r, err := git.PlainOpen(downloadPath)
if err != nil {
launchr.Log().Debug("git init error", "err", err)
return false, nil
}

head, err := r.Head()
if err != nil {
launchr.Log().Debug("get head error", "err", err)
return false, err
}

k, err := g.k.getForURL(pkg.GetURL())
headName := head.Name().Short()
pkgRefName := pkg.GetRef()
remoteRefName := pkgRefName

if pkg.GetTarget() == TargetLatest && headName != "" {
pkgRefName = headName
remoteRefName = plumbing.HEAD.String()
}

isLatest := false
if headName == pkgRefName {
isLatest, err = g.ensureLatestBranch(r, pkg.GetURL(), pkgRefName, remoteRefName)
if err != nil {
launchr.Term().Warning().Printfln("Couldn't check local branch, marking package %s(%s) as outdated, see debug for detailed error.", pkg.GetName(), pkgRefName)
launchr.Log().Debug("ensure branch error", "err", err)
return isLatest, nil
}
} else {
isLatest, err = g.ensureLatestTag(r, pkg.GetURL(), pkgRefName)
if err != nil {
launchr.Term().Warning().Printfln("Couldn't check local tag, marking package %s(%s) as outdated, see debug for detailed error.", pkg.GetName(), pkgRefName)
launchr.Log().Debug("ensure tag error", "err", err)
return isLatest, nil
}
}

if !isLatest {
launchr.Term().Warning().Printfln("Package %s(%s) is outdated", pkg.GetName(), pkgRefName)
}

return isLatest, nil
}

func (g *gitDownloader) ensureLatestBranch(r *git.Repository, fetchURL, refName, remoteRefName string) (bool, error) {
refSpec := []config.RefSpec{config.RefSpec(fmt.Sprintf("refs/heads/%s:refs/heads/%s", refName, refName))}
err := g.fetchRemotes(r, fetchURL, refSpec)
if err != nil {
return false, err
}

remotes, err := r.Remotes()
br, err := r.Branch(refName)
if err != nil {
return false, err
}

// Fetch from the remote repository
for _, rem := range remotes {
err = rem.Fetch(&git.FetchOptions{
RefSpecs: []config.RefSpec{"refs/*:refs/*", "HEAD:refs/heads/HEAD"},
Auth: &http.BasicAuth{
Username: k.Username,
Password: k.Password,
},
})
if err != nil {
if !errors.Is(err, git.NoErrAlreadyUpToDate) {
return false, err
}
}
localRef, err := r.Reference(plumbing.ReferenceName(br.Merge.String()), true)
if err != nil {
return false, err
}

head, err := r.Head()
remote := filepath.Join("refs", "remotes", br.Remote, remoteRefName)
remoteRef, err := r.Reference(plumbing.ReferenceName(remote), false)
if err != nil {
return false, err
}

refName := head.Name().Short()
pkgRef := pkg.GetRef()
remoteRefName := pkgRef
return localRef.Hash() == remoteRef.Hash(), nil
}

if pkg.GetTarget() == TargetLatest && refName != "" {
pkgRef = refName
remoteRefName = plumbing.HEAD.String()
func (g *gitDownloader) ensureLatestTag(r *git.Repository, fetchURL, refName string) (bool, error) {
oldTag, err := r.Tag(refName)
if err != nil {
return false, err
}

latest := false
if refName == pkgRef {
br, err := r.Branch(pkgRef)
if err != nil {
return false, err
}
head, err := r.Head()
if err != nil {
return false, err
}

localRef, err := r.Reference(plumbing.ReferenceName(br.Merge.String()), true)
if err != nil {
return false, err
}
refSpec := []config.RefSpec{config.RefSpec(fmt.Sprintf("refs/tags/%s:refs/tags/%s", refName, refName))}
err = g.fetchRemotes(r, fetchURL, refSpec)
if err != nil {
return false, err
}

// Obtain remote branch reference
remote := filepath.Join("refs", "remotes", br.Remote, remoteRefName)
remoteRef, err := r.Reference(plumbing.ReferenceName(remote), false)
if err != nil {
return false, err
}
newTag, err := r.Tag(refName)
if err != nil {
return false, err
}

if localRef.Hash() == remoteRef.Hash() {
latest = true
} else {
launchr.Term().Info().Println("Local and remote branches are not synced.")
}
} else {
tag, err := r.Tag(pkgRef)
if err != nil {
return false, err
}
if oldTag.Hash().String() != newTag.Hash().String() {
return false, err
}
revision := plumbing.Revision(newTag.Name().String())
tagCommitHash, err := r.ResolveRevision(revision)
if err != nil {
return false, err
}

if tag.Hash() == head.Hash() {
latest = true
} else {
launchr.Term().Info().Println("HEAD and tag hashes do not match.")
}
commit, err := r.CommitObject(*tagCommitHash)
if err != nil {
return false, err
}

return latest, nil
return commit.ID() == head.Hash(), nil
}

// Download implements Downloader.Download interface
Expand Down

0 comments on commit 7106407

Please sign in to comment.