From 08851dce616615c966ece450631d3d0a822430cc Mon Sep 17 00:00:00 2001 From: Carlos Alexandro Becker Date: Tue, 19 Mar 2024 23:53:08 -0300 Subject: [PATCH] fix(aur): allow to have multiple AUR configs pointing to the same repo (#4712) - using the sha256 of the git url as repo name so we avoid race conditions - actually made the git client have a global lock so it doesn't step over itself closes #4679 Signed-off-by: Carlos Alexandro Becker --- internal/client/git.go | 48 ++++++-------------- internal/pipe/aur/aur.go | 3 +- internal/pipe/aur/aur_test.go | 82 +++++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 35 deletions(-) diff --git a/internal/client/git.go b/internal/client/git.go index 9f0ebc944cf..2a500d0154e 100644 --- a/internal/client/git.go +++ b/internal/client/git.go @@ -19,14 +19,11 @@ import ( "golang.org/x/crypto/ssh" ) +var gil sync.Mutex + // DefaulGitSSHCommand used for git over SSH. const DefaulGitSSHCommand = `ssh -i "{{ .KeyPath }}" -o StrictHostKeyChecking=accept-new -F /dev/null` -var cloneLock = cloneGlobalLock{ - l: sync.Mutex{}, - repos: map[string]bool{}, -} - type gitClient struct { branch string } @@ -46,6 +43,9 @@ func (g *gitClient) CreateFiles( message string, files []RepoFile, ) (err error) { + gil.Lock() + defer gil.Unlock() + url, err := tmpl.New(ctx).Apply(repo.GitURL) if err != nil { return fmt.Errorf("git: failed to template git url: %w", err) @@ -79,7 +79,8 @@ func (g *gitClient) CreateFiles( cwd := filepath.Join(parent, name) env := []string{fmt.Sprintf("GIT_SSH_COMMAND=%s", sshcmd)} - if err := cloneLock.clone(url, func() error { + if _, err := os.Stat(cwd); errors.Is(err, os.ErrNotExist) { + log.Infof("cloning %s %s", name, cwd) if err := os.MkdirAll(parent, 0o755); err != nil { return fmt.Errorf("git: failed to create parent: %w", err) } @@ -98,21 +99,17 @@ func (g *gitClient) CreateFiles( }); err != nil { return fmt.Errorf("git: failed to setup local repository: %w", err) } - if g.branch == "" { - return nil - } - if err := runGitCmds(ctx, cwd, env, [][]string{ - {"checkout", g.branch}, - }); err != nil { + if g.branch != "" { if err := runGitCmds(ctx, cwd, env, [][]string{ - {"checkout", "-b", g.branch}, + {"checkout", g.branch}, }); err != nil { - return fmt.Errorf("git: could not checkout branch %s: %w", g.branch, err) + if err := runGitCmds(ctx, cwd, env, [][]string{ + {"checkout", "-b", g.branch}, + }); err != nil { + return fmt.Errorf("git: could not checkout branch %s: %w", g.branch, err) + } } } - return nil - }); err != nil { - return err } for _, file := range files { @@ -216,20 +213,3 @@ func runGitCmds(ctx *context.Context, cwd string, env []string, cmds [][]string) func nameFromURL(url string) string { return strings.TrimSuffix(url[strings.LastIndex(url, "/")+1:], ".git") } - -type cloneGlobalLock struct { - l sync.Mutex - repos map[string]bool -} - -func (c *cloneGlobalLock) clone(url string, fn func() error) error { - c.l.Lock() - defer c.l.Unlock() - - if c.repos[url] { - return nil - } - - c.repos[url] = true - return fn() -} diff --git a/internal/pipe/aur/aur.go b/internal/pipe/aur/aur.go index 0b3082e9c04..ae13837c2d0 100644 --- a/internal/pipe/aur/aur.go +++ b/internal/pipe/aur/aur.go @@ -3,6 +3,7 @@ package aur import ( "bufio" "bytes" + "crypto/sha256" "errors" "fmt" "os" @@ -385,7 +386,7 @@ func doPublish(ctx *context.Context, pkgs []*artifact.Artifact) error { URL: cfg.GitURL, SSHCommand: cfg.GitSSHCommand, }, - Name: cfg.Name, + Name: fmt.Sprintf("%x", sha256.Sum256([]byte(cfg.GitURL))), }) files := make([]client.RepoFile, 0, len(pkgs)) diff --git a/internal/pipe/aur/aur_test.go b/internal/pipe/aur/aur_test.go index 7d3fa5143cc..b492a950a90 100644 --- a/internal/pipe/aur/aur_test.go +++ b/internal/pipe/aur/aur_test.go @@ -482,6 +482,88 @@ func TestRunPipe(t *testing.T) { requireEqualRepoFiles(t, folder, ".", "foo", url) } +func TestRunPipeMultipleConfigurations(t *testing.T) { + url := testlib.GitMakeBareRepository(t) + key := testlib.MakeNewSSHKey(t, "") + + folder := t.TempDir() + ctx := testctx.NewWithCfg( + config.Project{ + Dist: folder, + ProjectName: "foo", + AURs: []config.AUR{ + { + Name: "foo", + IDs: []string{"foo"}, + PrivateKey: key, + License: "MIT", + GitURL: url, + Description: "The foo aur", + Directory: "foo", + }, + { + Name: "bar", + IDs: []string{"bar"}, + PrivateKey: key, + License: "MIT", + GitURL: url, + Description: "The bar aur", + Directory: "bar", + }, + }, + }, + testctx.WithCurrentTag("v1.0.1-foo"), + testctx.WithSemver(1, 0, 1, "foo"), + testctx.WithVersion("1.0.1-foo"), + ) + + path := filepath.Join(folder, "bin.tar.gz") + ctx.Artifacts.Add(&artifact.Artifact{ + Name: "bar_bin.tar.gz", + Path: path, + Goos: "linux", + Goarch: "amd64", + Goamd64: "v1", + Type: artifact.UploadableArchive, + Extra: map[string]interface{}{ + artifact.ExtraID: "bar", + artifact.ExtraFormat: "tar.gz", + artifact.ExtraBinaries: []string{"bar"}, + }, + }) + ctx.Artifacts.Add(&artifact.Artifact{ + Name: "bin.tar.gz", + Path: path, + Goos: "linux", + Goarch: "amd64", + Goamd64: "v1", + Type: artifact.UploadableArchive, + Extra: map[string]interface{}{ + artifact.ExtraID: "foo", + artifact.ExtraFormat: "tar.gz", + artifact.ExtraBinaries: []string{"name"}, + }, + }) + + f, err := os.Create(path) + require.NoError(t, err) + require.NoError(t, f.Close()) + client := client.NewMock() + + require.NoError(t, Pipe{}.Default(ctx)) + require.NoError(t, runAll(ctx, client)) + require.NoError(t, Pipe{}.Publish(ctx)) + + dir := t.TempDir() + _, err = git.Run(testctx.New(), "-C", dir, "clone", url, "repo") + require.NoError(t, err) + + require.FileExists(t, filepath.Join(dir, "repo", "foo", ".SRCINFO")) + require.FileExists(t, filepath.Join(dir, "repo", "foo", "PKGBUILD")) + require.FileExists(t, filepath.Join(dir, "repo", "bar", ".SRCINFO")) + require.FileExists(t, filepath.Join(dir, "repo", "bar", "PKGBUILD")) +} + func TestRunPipeNoBuilds(t *testing.T) { ctx := testctx.NewWithCfg(config.Project{ ProjectName: "foo",