Просмотр исходного кода

fix: expand tilde in --env-file paths to user home directory

When using --env-file=~/.env, the tilde was not expanded to the user's
home directory. Instead, it was treated as a literal character and
resolved relative to the current working directory, resulting in errors
like "couldn't find env file: /current/dir/~/.env".

This adds an ExpandUser function that expands ~ to the home directory
before converting relative paths to absolute paths.

Fixes #13508

Signed-off-by: tensorworker <[email protected]>
tensorworker 1 неделя назад
Родитель
Сommit
9856802945
3 измененных файлов с 112 добавлено и 0 удалено
  1. 4 0
      cmd/compose/compose.go
  2. 24 0
      internal/paths/paths.go
  3. 84 0
      internal/paths/paths_test.go

+ 4 - 0
cmd/compose/compose.go

@@ -46,6 +46,7 @@ import (
 
 	"github.com/docker/compose/v5/cmd/display"
 	"github.com/docker/compose/v5/cmd/formatter"
+	"github.com/docker/compose/v5/internal/paths"
 	"github.com/docker/compose/v5/internal/tracing"
 	"github.com/docker/compose/v5/pkg/api"
 	"github.com/docker/compose/v5/pkg/compose"
@@ -550,12 +551,15 @@ func RootCommand(dockerCli command.Cli, backendOptions *BackendOptions) *cobra.C
 				fmt.Fprint(os.Stderr, aec.Apply("option '--workdir' is DEPRECATED at root level! Please use '--project-directory' instead.\n", aec.RedF))
 			}
 			for i, file := range opts.EnvFiles {
+				file = paths.ExpandUser(file)
 				if !filepath.IsAbs(file) {
 					file, err := filepath.Abs(file)
 					if err != nil {
 						return err
 					}
 					opts.EnvFiles[i] = file
+				} else {
+					opts.EnvFiles[i] = file
 				}
 			}
 

+ 24 - 0
internal/paths/paths.go

@@ -22,6 +22,30 @@ import (
 	"strings"
 )
 
+// ExpandUser expands a leading tilde (~) in a path to the user's home directory.
+// If the path doesn't start with ~, it is returned unchanged.
+// If the home directory cannot be determined, the original path is returned.
+func ExpandUser(path string) string {
+	if path == "" {
+		return path
+	}
+	if path[0] != '~' {
+		return path
+	}
+	if len(path) > 1 && path[1] != '/' && path[1] != filepath.Separator {
+		// ~otheruser/... syntax is not supported
+		return path
+	}
+	home, err := os.UserHomeDir()
+	if err != nil {
+		return path
+	}
+	if len(path) == 1 {
+		return home
+	}
+	return filepath.Join(home, path[2:])
+}
+
 func IsChild(dir string, file string) bool {
 	if dir == "" {
 		return false

+ 84 - 0
internal/paths/paths_test.go

@@ -0,0 +1,84 @@
+/*
+   Copyright 2020 Docker Compose CLI authors
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+*/
+
+package paths
+
+import (
+	"os"
+	"path/filepath"
+	"testing"
+
+	"gotest.tools/v3/assert"
+)
+
+func TestExpandUser(t *testing.T) {
+	home, err := os.UserHomeDir()
+	assert.NilError(t, err)
+
+	tests := []struct {
+		name     string
+		input    string
+		expected string
+	}{
+		{
+			name:     "empty string",
+			input:    "",
+			expected: "",
+		},
+		{
+			name:     "tilde only",
+			input:    "~",
+			expected: home,
+		},
+		{
+			name:     "tilde with slash",
+			input:    "~/.env",
+			expected: filepath.Join(home, ".env"),
+		},
+		{
+			name:     "tilde with subdir",
+			input:    "~/subdir/.env",
+			expected: filepath.Join(home, "subdir", ".env"),
+		},
+		{
+			name:     "absolute path unchanged",
+			input:    "/absolute/path/.env",
+			expected: "/absolute/path/.env",
+		},
+		{
+			name:     "relative path unchanged",
+			input:    "relative/path/.env",
+			expected: "relative/path/.env",
+		},
+		{
+			name:     "tilde in middle unchanged",
+			input:    "/path/~/file",
+			expected: "/path/~/file",
+		},
+		{
+			name:     "tilde other user unchanged",
+			input:    "~otheruser/.env",
+			expected: "~otheruser/.env",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			result := ExpandUser(tt.input)
+			assert.Equal(t, result, tt.expected)
+		})
+	}
+}