瀏覽代碼

chore(desktop): revised feature detection for file shares

Unfortunately, the feature flag mechanism for experimental features
isn't adequate. To avoid some edge cases where Compose might try to
use Synchronized file shares with Desktop when the feature isn't
available, we need to query a new endpoint.

Before we move any of this out of experimental, we need to improve
the integration here with Desktop & Compose so that we get all the
necessary feature/experiment state up-front to reduce the quantity
of IPC calls needed up-front.

For now, there's some intentional redundancy to avoid making this
extra call if we can avoid it. The actual endpoint is very cheap/
fast, but every IPC call is a potential point of of failure, so
it's worth it.

Signed-off-by: Milas Bowman <[email protected]>
Milas Bowman 1 年之前
父節點
當前提交
3371227794
共有 4 個文件被更改,包括 51 次插入2 次删除
  1. 31 0
      internal/desktop/client.go
  2. 1 1
      pkg/compose/create.go
  3. 18 0
      pkg/compose/desktop.go
  4. 1 1
      pkg/compose/down.go

+ 31 - 0
internal/desktop/client.go

@@ -123,6 +123,37 @@ func (c *Client) FeatureFlags(ctx context.Context) (FeatureFlagResponse, error)
 	return ret, nil
 }
 
+type GetFileSharesConfigResponse struct {
+	Active  bool `json:"active"`
+	Compose struct {
+		ManageBindMounts bool `json:"manageBindMounts"`
+	}
+}
+
+func (c *Client) GetFileSharesConfig(ctx context.Context) (*GetFileSharesConfigResponse, error) {
+	req, err := http.NewRequestWithContext(ctx, http.MethodGet, backendURL("/mutagen/file-shares/config"), http.NoBody)
+	if err != nil {
+		return nil, err
+	}
+	resp, err := c.client.Do(req)
+	if err != nil {
+		return nil, err
+	}
+	defer func() {
+		_ = resp.Body.Close()
+	}()
+
+	if resp.StatusCode != http.StatusOK {
+		return nil, newHTTPStatusCodeError(resp)
+	}
+
+	var ret GetFileSharesConfigResponse
+	if err := json.NewDecoder(resp.Body).Decode(&ret); err != nil {
+		return nil, err
+	}
+	return &ret, nil
+}
+
 type CreateFileShareRequest struct {
 	HostPath string            `json:"hostPath"`
 	Labels   map[string]string `json:"labels,omitempty"`

+ 1 - 1
pkg/compose/create.go

@@ -152,7 +152,7 @@ func (s *composeService) ensureProjectVolumes(ctx context.Context, project *type
 	}
 
 	err := func() error {
-		if s.experiments.AutoFileShares() && s.isDesktopIntegrationActive() {
+		if s.manageDesktopFileSharesEnabled(ctx) {
 			// collect all the bind mount paths and try to set up file shares in
 			// Docker Desktop for them
 			var paths []string

+ 18 - 0
pkg/compose/desktop.go

@@ -17,8 +17,11 @@
 package compose
 
 import (
+	"context"
+
 	"github.com/docker/compose/v2/internal/desktop"
 	"github.com/docker/compose/v2/internal/experimental"
+	"github.com/sirupsen/logrus"
 )
 
 func (s *composeService) SetDesktopClient(cli *desktop.Client) {
@@ -28,3 +31,18 @@ func (s *composeService) SetDesktopClient(cli *desktop.Client) {
 func (s *composeService) SetExperiments(experiments *experimental.State) {
 	s.experiments = experiments
 }
+
+func (s *composeService) manageDesktopFileSharesEnabled(ctx context.Context) bool {
+	// there's some slightly redundancy here to avoid fetching the config if
+	// we can already tell the feature state - in practice, we
+	if !s.isDesktopIntegrationActive() || !s.experiments.AutoFileShares() {
+		return false
+	}
+
+	fileSharesConfig, err := s.desktopCli.GetFileSharesConfig(ctx)
+	if err != nil {
+		logrus.Debugf("Failed to retrieve file shares config: %v", err)
+		return false
+	}
+	return fileSharesConfig.Active && fileSharesConfig.Compose.ManageBindMounts
+}

+ 1 - 1
pkg/compose/down.go

@@ -145,7 +145,7 @@ func (s *composeService) ensureVolumesDown(ctx context.Context, project *types.P
 		})
 	}
 
-	if s.experiments.AutoFileShares() && s.isDesktopIntegrationActive() {
+	if s.manageDesktopFileSharesEnabled(ctx) {
 		ops = append(ops, func() error {
 			desktop.RemoveFileSharesForProject(ctx, s.desktopCli, project.Name)
 			return nil