diff --git a/go.mod b/go.mod index d27f64245..a6c406785 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,7 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/zap v1.21.0 golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 + golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 gopkg.in/go-playground/validator.v9 v9.31.0 gopkg.in/yaml.v2 v2.4.0 diff --git a/go.sum b/go.sum index b7e0d1dca..63d612470 100644 --- a/go.sum +++ b/go.sum @@ -717,6 +717,7 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220513210516-0976fa681c29 h1:w8s32wxx3sY+OjLlv9qltkLU5yvJzxjjgiHWLjdIcw4= golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= diff --git a/server/events/working_dir.go b/server/events/working_dir.go index d9b98dd14..515f41af6 100644 --- a/server/events/working_dir.go +++ b/server/events/working_dir.go @@ -14,20 +14,25 @@ package events import ( + "context" "fmt" "os" "os/exec" "path/filepath" "strconv" "strings" + "sync" "github.com/pkg/errors" "github.com/runatlantis/atlantis/server/events/models" "github.com/runatlantis/atlantis/server/logging" + "golang.org/x/sync/semaphore" ) const workingDirPrefix = "repos" +var cloneLocks sync.Map + //go:generate pegomock generate -m --use-experimental-model-gen --package mocks -o mocks/mock_working_dir.go WorkingDir //go:generate pegomock generate -m --use-experimental-model-gen --package events WorkingDir @@ -199,6 +204,18 @@ func (w *FileWorkspace) forceClone(log logging.SimpleLogging, headRepo models.Repo, p models.PullRequest) error { + value, _ := cloneLocks.LoadOrStore(cloneDir, semaphore.NewWeighted(1)) + sem := value.(*semaphore.Weighted) + + defer sem.Release(1) + if acquired := sem.TryAcquire(1); !acquired { + err := sem.Acquire(context.TODO(), 1) + if err != nil { + return errors.Wrap(err, "waiting for repository to be cloned") + } + return nil + } + err := os.RemoveAll(cloneDir) if err != nil { return errors.Wrapf(err, "deleting dir %q before cloning", cloneDir)