diff --git a/internal/sync/tar.go b/internal/sync/tar.go index ae7d8517e..050f6ab95 100644 --- a/internal/sync/tar.go +++ b/internal/sync/tar.go @@ -47,6 +47,7 @@ type LowLevelClient interface { ContainersForService(ctx context.Context, projectName string, serviceName string) ([]moby.Container, error) Exec(ctx context.Context, containerID string, cmd []string, in io.Reader) error + Untar(ctx context.Context, id string, reader io.ReadCloser) error } type Tar struct { @@ -84,39 +85,24 @@ func (t *Tar) Sync(ctx context.Context, service types.ServiceConfig, paths []Pat if len(pathsToDelete) != 0 { deleteCmd = append([]string{"rm", "-rf"}, pathsToDelete...) } - copyCmd := []string{"tar", "-v", "-C", "/", "-x", "-f", "-"} - var eg multierror.Group - writers := make([]*io.PipeWriter, len(containers)) for i := range containers { containerID := containers[i].ID - r, w := io.Pipe() - writers[i] = w + tarReader := tarArchive(pathsToCopy) + eg.Go(func() error { if len(deleteCmd) != 0 { if err := t.client.Exec(ctx, containerID, deleteCmd, nil); err != nil { return fmt.Errorf("deleting paths in %s: %w", containerID, err) } } - if err := t.client.Exec(ctx, containerID, copyCmd, r); err != nil { + + if err := t.client.Untar(ctx, containerID, tarReader); err != nil { return fmt.Errorf("copying files to %s: %w", containerID, err) } return nil }) } - - multiWriter := newLossyMultiWriter(writers...) - tarReader := tarArchive(pathsToCopy) - defer func() { - _ = tarReader.Close() - multiWriter.Close() - }() - _, err = io.Copy(multiWriter, tarReader) - if err != nil { - return err - } - multiWriter.Close() - return eg.Wait().ErrorOrNil() } diff --git a/pkg/compose/watch.go b/pkg/compose/watch.go index 288bc2f85..436b6c5f0 100644 --- a/pkg/compose/watch.go +++ b/pkg/compose/watch.go @@ -419,6 +419,12 @@ func (t tarDockerClient) Exec(ctx context.Context, containerID string, cmd []str return nil } +func (t tarDockerClient) Untar(ctx context.Context, id string, archive io.ReadCloser) error { + return t.s.apiClient().CopyToContainer(ctx, id, "/", archive, moby.CopyToContainerOptions{ + CopyUIDGID: true, + }) +} + func (s *composeService) handleWatchBatch(ctx context.Context, project *types.Project, serviceName string, build api.BuildOptions, batch []fileEvent, syncer sync.Syncer) error { pathMappings := make([]sync.PathMapping, len(batch)) restartService := false