1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-04-13 11:50:34 +02:00

fix: snapcraft temporary directory + concurrency (#4963)

this bug comes and goes every couple of versions it seems.

this will change the snapcraft implementation to run the first item
without concurrency, so all needed shared directories can be created
without issues, and then grows the limit of the wait group so the other
ones can run in parallel.

I haven't tested this yet, but I think it'll work.

- [x] test
- [x] godoc

refs https://github.com/goreleaser/goreleaser/issues/1715 refs
https://bugs.launchpad.net/snapcraft/+bug/1889741
This commit is contained in:
Carlos Alexandro Becker 2024-06-29 19:00:52 -03:00 committed by GitHub
parent 55249e73da
commit f0b4db184e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 72 additions and 5 deletions

View File

@ -43,8 +43,6 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft
mkdir -p $HOME/.cache/snapcraft/download
mkdir -p $HOME/.cache/snapcraft/stage-packages
- uses: crazy-max/ghaction-upx@v3
with:
install-only: true

View File

@ -84,8 +84,6 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -yq --no-install-suggests --no-install-recommends install snapcraft
mkdir -p $HOME/.cache/snapcraft/download
mkdir -p $HOME/.cache/snapcraft/stage-packages
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v4
with:
go-version: stable

View File

@ -180,7 +180,7 @@ func doRun(ctx *context.Context, snap config.Snapcraft) error {
return ErrNoSnapcraft
}
g := semerrgroup.New(ctx.Parallelism)
g := semerrgroup.NewBlockingFirst(semerrgroup.New(ctx.Parallelism))
for platform, binaries := range ctx.Artifacts.Filter(
artifact.And(
artifact.ByGoos("linux"),

View File

@ -16,6 +16,40 @@ type Group interface {
Wait() error
}
type blockingFirstGroup struct {
g Group
firstMu sync.Mutex
firstDone bool
}
func (g *blockingFirstGroup) Go(fn func() error) {
g.firstMu.Lock()
if g.firstDone {
g.g.Go(fn)
g.firstMu.Unlock()
return
}
if err := fn(); err != nil {
g.g.Go(func() error { return err })
}
g.firstDone = true
g.firstMu.Unlock()
}
func (g *blockingFirstGroup) Wait() error {
return g.g.Wait()
}
// NewBlockingFirst creates a new group that runs the first item,
// waiting for its return, and only then starts scheduling/running the
// other tasks.
func NewBlockingFirst(g Group) Group {
return &blockingFirstGroup{
g: g,
}
}
// New returns a new Group of a given size.
func New(size int) Group {
var g errgroup.Group

View File

@ -11,6 +11,43 @@ import (
"github.com/stretchr/testify/require"
)
func TestBlockingFirst(t *testing.T) {
g := NewBlockingFirst(New(5))
var lock sync.Mutex
var counter int
for i := 0; i < 10; i++ {
g.Go(func() error {
time.Sleep(10 * time.Millisecond)
lock.Lock()
defer lock.Unlock()
counter++
return nil
})
}
require.NoError(t, g.Wait())
require.Equal(t, 10, counter)
}
func TestBlockingFirstError(t *testing.T) {
g := NewBlockingFirst(New(5))
var lock sync.Mutex
var counter int
for i := 0; i < 10; i++ {
g.Go(func() error {
time.Sleep(10 * time.Millisecond)
lock.Lock()
defer lock.Unlock()
if counter == 0 {
return fmt.Errorf("my error")
}
counter++
return nil
})
}
require.EqualError(t, g.Wait(), "my error")
require.Equal(t, 0, counter)
}
func TestSemaphore(t *testing.T) {
for _, i := range []int{1, 4} {
t.Run(fmt.Sprintf("limit-%d", i), func(t *testing.T) {