mirror of
https://github.com/docker/compose.git
synced 2026-05-13 13:58:02 +00:00
Merge 736906faf5 into 659b269e52
This commit is contained in:
commit
e30fc4e8ce
3 changed files with 89 additions and 0 deletions
|
|
@ -298,6 +298,10 @@ func (o *ProjectOptions) ToModel(ctx context.Context, dockerCli command.Cli, ser
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkConfigPathsNotDirectories(options.ConfigPaths, remotes); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if o.Compatibility || utils.StringToBool(options.Environment[ComposeCompatibility]) {
|
||||
api.Separator = "_"
|
||||
}
|
||||
|
|
@ -305,6 +309,34 @@ func (o *ProjectOptions) ToModel(ctx context.Context, dockerCli command.Cli, ser
|
|||
return options.LoadModel(ctx)
|
||||
}
|
||||
|
||||
// checkConfigPathsNotDirectories returns an error if any local config path is a
|
||||
// directory rather than a file. Remote resource paths and stdin ("-") are skipped.
|
||||
//
|
||||
// This guards against COMPOSE_FILE being set to a directory (e.g. COMPOSE_FILE=""
|
||||
// which filepath.Abs resolves to the working directory).
|
||||
func checkConfigPathsNotDirectories(configPaths []string, remoteLoaders []loader.ResourceLoader) error {
|
||||
for _, configPath := range configPaths {
|
||||
if configPath == "-" {
|
||||
continue
|
||||
}
|
||||
isRemote := false
|
||||
for _, r := range remoteLoaders {
|
||||
if r.Accept(configPath) {
|
||||
isRemote = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isRemote {
|
||||
continue
|
||||
}
|
||||
if info, err := os.Stat(configPath); err == nil && info.IsDir() {
|
||||
return fmt.Errorf("path %q is a directory, not a Compose file; "+
|
||||
"check the COMPOSE_FILE environment variable or the -f flag", configPath)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ToProject loads a Compose project using the LoadProject API.
|
||||
// Accepts optional cli.ProjectOptionsFn to control loader behavior.
|
||||
func (o *ProjectOptions) ToProject(ctx context.Context, dockerCli command.Cli, backend api.Compose, services []string, po ...cli.ProjectOptionsFn) (*types.Project, tracing.Metrics, error) {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ package compose
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
|
@ -31,6 +32,36 @@ import (
|
|||
"github.com/docker/compose/v5/pkg/utils"
|
||||
)
|
||||
|
||||
// checkConfigPathsForDirectories returns an error if any config path in configPaths
|
||||
// is a local directory instead of a file. Remote paths (accepted by remoteLoaders)
|
||||
// and the special "-" (stdin) value are skipped.
|
||||
//
|
||||
// This provides a clear error when COMPOSE_FILE is set to a directory path (e.g.,
|
||||
// "COMPOSE_FILE=" resolves to the working directory via filepath.Abs("")).
|
||||
func checkConfigPathsForDirectories(configPaths []string, remoteLoaders []loader.ResourceLoader) error {
|
||||
for _, configPath := range configPaths {
|
||||
if configPath == "-" {
|
||||
continue
|
||||
}
|
||||
isRemote := false
|
||||
for _, r := range remoteLoaders {
|
||||
if r.Accept(configPath) {
|
||||
isRemote = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if isRemote {
|
||||
continue
|
||||
}
|
||||
info, err := os.Stat(configPath)
|
||||
if err == nil && info.IsDir() {
|
||||
return fmt.Errorf("path %q is a directory, not a Compose file; "+
|
||||
"check the COMPOSE_FILE environment variable or the -f flag", configPath)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadProject implements api.Compose.LoadProject
|
||||
// It loads and validates a Compose project from configuration files.
|
||||
func (s *composeService) LoadProject(ctx context.Context, options api.ProjectLoadOptions) (*types.Project, error) {
|
||||
|
|
@ -42,6 +73,10 @@ func (s *composeService) LoadProject(ctx context.Context, options api.ProjectLoa
|
|||
return nil, err
|
||||
}
|
||||
|
||||
if err := checkConfigPathsForDirectories(projectOptions.ConfigPaths, remoteLoaders); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Register all user-provided listeners (e.g., for metrics collection)
|
||||
for _, listener := range options.LoadListeners {
|
||||
if listener != nil {
|
||||
|
|
|
|||
|
|
@ -319,3 +319,25 @@ func TestLoadProject_MissingComposeFile(t *testing.T) {
|
|||
assert.Assert(t, err != nil)
|
||||
assert.Assert(t, project == nil)
|
||||
}
|
||||
|
||||
func TestLoadProject_DirectoryAsComposeFile(t *testing.T) {
|
||||
// Reproduce the misleading error described in https://github.com/docker/compose/issues/13649:
|
||||
// when COMPOSE_FILE is set to a directory (e.g. COMPOSE_FILE="" resolves to the working
|
||||
// directory via filepath.Abs("")), the error "read <dir>: is a directory" was shown.
|
||||
// The fix should return a clear error message instead.
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
service, err := NewComposeService(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
project, err := service.LoadProject(t.Context(), api.ProjectLoadOptions{
|
||||
ConfigPaths: []string{tmpDir},
|
||||
})
|
||||
|
||||
require.Error(t, err)
|
||||
assert.Nil(t, project)
|
||||
assert.Contains(t, err.Error(), "is a directory")
|
||||
assert.Contains(t, err.Error(), "Compose file")
|
||||
// Ensure the old opaque error message is NOT present
|
||||
assert.NotContains(t, err.Error(), "read "+tmpDir+": is a directory")
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue