Skip to content

Commit

Permalink
resolve symbolic links when loading develop.watch.path
Browse files Browse the repository at this point in the history
Signed-off-by: Joana Hrotko <joana.hrotko@docker.com>
  • Loading branch information
jhrotko committed Jul 10, 2024
1 parent 300b0ed commit 670ded9
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 1 deletion.
2 changes: 1 addition & 1 deletion paths/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func ResolveRelativePaths(project map[string]any, base string, remotes []RemoteR
"services.*.build.additional_contexts.*": r.absContextPath,
"services.*.env_file.*.path": r.absPath,
"services.*.extends.file": r.absExtendsPath,
"services.*.develop.watch.*.path": r.absPath,
"services.*.develop.watch.*.path": r.absSymbolicLink,
"services.*.volumes.*": r.absVolumeMount,
"configs.*.file": r.maybeUnixPath,
"secrets.*.file": r.maybeUnixPath,
Expand Down
14 changes: 14 additions & 0 deletions paths/unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package paths
import (
"path"
"path/filepath"

"github.com/compose-spec/compose-go/v2/utils"
)

func (r *relativePathsResolver) maybeUnixPath(a any) (any, error) {
Expand All @@ -38,3 +40,15 @@ func (r *relativePathsResolver) maybeUnixPath(a any) (any, error) {
}
return p, nil
}

func (r *relativePathsResolver) absSymbolicLink(value any) (any, error) {
abs, err := r.absPath(value)
if err != nil {
return nil, err
}
str, ok := abs.(string)
if !ok {
return abs, nil
}
return utils.ResolveSymbolicLink(str)
}
76 changes: 76 additions & 0 deletions utils/pathutils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package utils

import (
"os"
"path/filepath"
"strings"
)

// ResolveSymbolicLink converts the section of an absolute path if it is a
// symbolic link
//
// Parameters:
// - path: an absolute path
//
// Returns:
// - converted path if it has a symbolic link or the same path if there is
// no symbolic link
func ResolveSymbolicLink(path string) (string, error) {
sym, part, err := getSymbolinkLink(path)
if err != nil {
return "", err
}
if sym == "" && part == "" {
// no symbolic link detected
return path, nil
}
return strings.Replace(path, part, sym, 1), nil

}

// getSymbolinkLink parses all parts of the path and returns the
//
// Parameters:
// - path: an absolute path
//
// Returns:
// - string section of the path that is a symbolic link
// - string correspondent path section of the symbolic link
// - An error
func getSymbolinkLink(path string) (string, string, error) {
parts := strings.Split(path, string(os.PathSeparator))

// Reconstruct the path step by step, checking each component
var currentPath string
if filepath.IsAbs(path) {
currentPath = string(os.PathSeparator)
}

for _, part := range parts {
if part == "" {
continue
}
currentPath = filepath.Join(currentPath, part)

if isSymLink := isSymbolicLink(currentPath); isSymLink {
// return symbolic link, and correspondent part
target, err := filepath.EvalSymlinks(currentPath)
if err != nil {
return "", "", err
}
return target, currentPath, nil
}
}
return "", "", nil // no symbolic link
}

// isSymbolicLink validates if the path is a symbolic link
func isSymbolicLink(path string) bool {
info, err := os.Lstat(path)
if err != nil {
return false
}

// Check if the file mode indicates a symbolic link
return info.Mode()&os.ModeSymlink != 0
}

0 comments on commit 670ded9

Please sign in to comment.