Repository: avenga/couper
Pull request #463 (2022-03-31 15:58:52)

Fix absolute path replacement
Fixup for #437 

Filepath attribute values which are already absolute do not have to be processed by load related path operations.

---
<details>
    <summary>Reviewer checklist</summary>
    <ul>
        <li>Read PR description: a summary about the changes is required</li>
        <li>Changelog updated</li>
        <li>Documentation: docs/{Reference, Cli, ...}, Docker and cli help/usage</li>
        <li>Pulled branch, manually tested</li>
        <li>Verified requirements are met</li>
        <li>Reviewed the code</li>
        <li>Reviewed the related tests</li>
    </ul>
</details>



Patch:
diff --git a/config/configload/load.go b/config/configload/load.go
index 66054fff..be1d41bb 100644
--- a/config/configload/load.go
+++ b/config/configload/load.go
@@ -134,8 +134,10 @@ func LoadFiles(filePath, dirPath string) (*config.Couper, error) {
 
 		parsedBodies = append([]*hclsyntax.Body{parsed.Body.(*hclsyntax.Body)}, parsedBodies...)
 	}
+
 	if filePath != "" {
-		filePath, err := filepath.Abs(filePath)
+		var err error
+		filePath, err = filepath.Abs(filePath)
 		if err != nil {
 			return nil, err
 		}
@@ -172,22 +174,22 @@ func LoadFiles(filePath, dirPath string) (*config.Couper, error) {
 		return nil, diags
 	}
 
-	settings := mergeAttributes("settings", parsedBodies)
+	settingsBlock := mergeAttributes(settings, parsedBodies)
 
-	definitions, err := mergeDefinitions(parsedBodies)
+	definitionsBlock, err := mergeDefinitions(parsedBodies)
 	if err != nil {
 		return nil, err
 	}
 
-	servers, err := mergeServers(parsedBodies)
+	serverBlocks, err := mergeServers(parsedBodies)
 	if err != nil {
 		return nil, err
 	}
 
-	configBlocks := servers
-	configBlocks = append(configBlocks, definitions)
+	configBlocks := serverBlocks
+	configBlocks = append(configBlocks, definitionsBlock)
 	configBlocks = append(configBlocks, defaults)
-	configBlocks = append(configBlocks, settings)
+	configBlocks = append(configBlocks, settingsBlock)
 
 	configBody := &hclsyntax.Body{
 		Blocks: configBlocks,
diff --git a/config/configload/merge.go b/config/configload/merge.go
index 924f04f3..a455db0b 100644
--- a/config/configload/merge.go
+++ b/config/configload/merge.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 	"path"
 	"path/filepath"
+	"strings"
 
 	"github.com/hashicorp/hcl/v2"
 	"github.com/hashicorp/hcl/v2/hclsyntax"
@@ -22,10 +23,12 @@ func errorUniqueLabels(block *hclsyntax.Block) error {
 	}
 }
 
+// absPath replaces the given attribute path expression with an absolute path
+// related to its filename if not already an absolute one.
 func absPath(attr *hclsyntax.Attribute) hclsyntax.Expression {
 	value, diags := attr.Expr.Value(envContext)
-	if diags.HasErrors() {
-		return attr.Expr // Return unchanged in error cases.
+	if diags.HasErrors() || strings.Index(value.AsString(), "/") == 0 {
+		return attr.Expr // Return unchanged in error cases and for absolute path values.
 	}
 
 	return &hclsyntax.LiteralValueExpr{


Test patch:
diff --git a/config/configload/merge_test.go b/config/configload/merge_test.go
new file mode 100644
index 00000000..8047f2f2
--- /dev/null
+++ b/config/configload/merge_test.go
@@ -0,0 +1,47 @@
+package configload
+
+import (
+	"github.com/hashicorp/hcl/v2"
+	"github.com/hashicorp/hcl/v2/hclsyntax"
+	"github.com/zclconf/go-cty/cty"
+	"testing"
+)
+
+func Test_absPath(t *testing.T) {
+	tests := []struct {
+		name string
+		attr *hclsyntax.Attribute
+		want cty.Value
+	}{
+		{"absolute path",
+			&hclsyntax.Attribute{Expr: &hclsyntax.LiteralValueExpr{Val: cty.StringVal("/www")}, SrcRange: hcl.Range{Filename: "/dir1/case1.hcl"}},
+			cty.StringVal("/www"),
+		},
+		{"relative path",
+			&hclsyntax.Attribute{Expr: &hclsyntax.LiteralValueExpr{Val: cty.StringVal("./www")}, SrcRange: hcl.Range{Filename: "/dir2/case2.hcl"}},
+			cty.StringVal("/dir2/www"),
+		},
+		{"relative parent dir path",
+			&hclsyntax.Attribute{Expr: &hclsyntax.LiteralValueExpr{Val: cty.StringVal("./../subDir1/www")}, SrcRange: hcl.Range{Filename: "/dir3/case3.hcl"}},
+			cty.StringVal("/subDir1/www"),
+		},
+		{"relative parent dir path 2",
+			&hclsyntax.Attribute{Expr: &hclsyntax.LiteralValueExpr{Val: cty.StringVal("./../../../../../subDir2/www")}, SrcRange: hcl.Range{Filename: "/dir4/case4.hcl"}},
+			cty.StringVal("/subDir2/www"),
+		},
+		{"relative path w/o dot",
+			&hclsyntax.Attribute{Expr: &hclsyntax.LiteralValueExpr{Val: cty.StringVal("www")}, SrcRange: hcl.Range{Filename: "/dir5/case5.hcl"}},
+			cty.StringVal("/dir5/www"),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := absPath(tt.attr)
+			gotExpr := got.(*hclsyntax.LiteralValueExpr)
+			gotValue, _ := gotExpr.Value(envContext)
+			if gotValue.Equals(tt.want).False() {
+				t.Errorf("absPath() = %q, want %q", gotValue.AsString(), tt.want.AsString())
+			}
+		})
+	}
+}