|
@@ -29,11 +29,11 @@ import (
|
|
|
"path"
|
|
"path"
|
|
|
"path/filepath"
|
|
"path/filepath"
|
|
|
"strings"
|
|
"strings"
|
|
|
-
|
|
|
|
|
- "github.com/hashicorp/go-multierror"
|
|
|
|
|
|
|
+ "sync"
|
|
|
|
|
|
|
|
"github.com/docker/docker/api/types/container"
|
|
"github.com/docker/docker/api/types/container"
|
|
|
"github.com/moby/go-archive"
|
|
"github.com/moby/go-archive"
|
|
|
|
|
+ "golang.org/x/sync/errgroup"
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
type archiveEntry struct {
|
|
type archiveEntry struct {
|
|
@@ -84,7 +84,14 @@ func (t *Tar) Sync(ctx context.Context, service string, paths []*PathMapping) er
|
|
|
if len(pathsToDelete) != 0 {
|
|
if len(pathsToDelete) != 0 {
|
|
|
deleteCmd = append([]string{"rm", "-rf"}, pathsToDelete...)
|
|
deleteCmd = append([]string{"rm", "-rf"}, pathsToDelete...)
|
|
|
}
|
|
}
|
|
|
- var eg multierror.Group
|
|
|
|
|
|
|
+
|
|
|
|
|
+ var (
|
|
|
|
|
+ eg errgroup.Group
|
|
|
|
|
+ errMu sync.Mutex
|
|
|
|
|
+ errs = make([]error, 0, len(containers)*2) // max 2 errs per container
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ eg.SetLimit(16) // arbitrary limit, adjust to taste :D
|
|
|
for i := range containers {
|
|
for i := range containers {
|
|
|
containerID := containers[i].ID
|
|
containerID := containers[i].ID
|
|
|
tarReader := tarArchive(pathsToCopy)
|
|
tarReader := tarArchive(pathsToCopy)
|
|
@@ -92,17 +99,23 @@ func (t *Tar) Sync(ctx context.Context, service string, paths []*PathMapping) er
|
|
|
eg.Go(func() error {
|
|
eg.Go(func() error {
|
|
|
if len(deleteCmd) != 0 {
|
|
if len(deleteCmd) != 0 {
|
|
|
if err := t.client.Exec(ctx, containerID, deleteCmd, nil); err != nil {
|
|
if err := t.client.Exec(ctx, containerID, deleteCmd, nil); err != nil {
|
|
|
- return fmt.Errorf("deleting paths in %s: %w", containerID, err)
|
|
|
|
|
|
|
+ errMu.Lock()
|
|
|
|
|
+ errs = append(errs, fmt.Errorf("deleting paths in %s: %w", containerID, err))
|
|
|
|
|
+ errMu.Unlock()
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if err := t.client.Untar(ctx, containerID, tarReader); err != nil {
|
|
if err := t.client.Untar(ctx, containerID, tarReader); err != nil {
|
|
|
- return fmt.Errorf("copying files to %s: %w", containerID, err)
|
|
|
|
|
|
|
+ errMu.Lock()
|
|
|
|
|
+ errs = append(errs, fmt.Errorf("copying files to %s: %w", containerID, err))
|
|
|
|
|
+ errMu.Unlock()
|
|
|
}
|
|
}
|
|
|
- return nil
|
|
|
|
|
|
|
+ return nil // don't fail-fast; collect all errors
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
- return eg.Wait().ErrorOrNil()
|
|
|
|
|
|
|
+
|
|
|
|
|
+ _ = eg.Wait()
|
|
|
|
|
+ return errors.Join(errs...)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
type ArchiveBuilder struct {
|
|
type ArchiveBuilder struct {
|