Repository: gohugoio/hugo (language: go)

Issue:
Mounting data directory to subdirectory does not allow access by subkey
### What version of Hugo are you using (`hugo version`)?

<pre>
$ hugo version
hugo v0.110.0-e32a493b7826d02763c3b79623952e625402b168 linux/amd64 BuildDate=2023-01-17T12:16:09Z VendorInfo=gohugoio
</pre>

### Does this issue reproduce with the latest release?

Yes

### Description

I have an external directory containing JSON data files, which I mount in my site with the following configuration:

```
[[module.imports]]
source = "../external-data"
target = "data/my_section"
```

For this example, suppose that the `external-data` directory contains a `my_data.json` file with the contents `{ "my_key": "my value" }`.

Because the target is the `my_section` subdirectory, I expect to be able to access the data in my templates using `.Site.Data.my_section...`. With the example data given previously, this would be `.Site.Data.my_section.my_data.my_key`. However, this does not work; I have to use `.Site.Data.my_data.my_key`. If I want to have the data under `my_section`, I have to create an `external-data/my_section` subdirectory instead of having it as part of the mount.


Discussion / hints:
Related (both closed by stalebot):
- <https://github.com/gohugoio/hugo/issues/8556>
- <https://github.com/gohugoio/hugo/issues/7616>
As noted in one of the related issues, this...

```text
[[module.mounts]]
source = 'data'
target = 'data'

[[module.mounts]]
source = "../external-data"
target = "data/my_section"
```

...mounts `../external-data/bar.toml` to `data/bar.b`
Thanks @jmooring . This seems like a clear duplicate of #7616 . I'm not sure if #8556 is the same issue though. I get the impression that that one had more to do with trying to mount a single file rather than an individual directory.
Because https://github.com/gohugoio/hugo/issues/7616 is closed, let's leave this issue open.
I just ran into this again in my own work - being able to mount data to the correct subfolder (and thus dot-path) would be hugely helpful for me. I have some monorepos where multiple projects share the same docs site, and this becomes a very funky workaround problem, unfortunately.

Fix patch:
diff --git a/hugolib/hugo_sites.go b/hugolib/hugo_sites.go
index 9c121f7ac11..d63e56300fe 100644
--- a/hugolib/hugo_sites.go
+++ b/hugolib/hugo_sites.go
@@ -555,13 +555,14 @@ func (h *HugoSites) loadData(fis []hugofs.FileMetaInfo) (err error) {
 
 	h.data = make(map[string]any)
 	for _, fi := range fis {
+		basePath := fi.Meta().Path
 		fileSystem := spec.NewFilesystemFromFileMetaInfo(fi)
 		files, err := fileSystem.Files()
 		if err != nil {
 			return err
 		}
 		for _, r := range files {
-			if err := h.handleDataFile(r); err != nil {
+			if err := h.handleDataFile(basePath, r); err != nil {
 				return err
 			}
 		}
@@ -570,7 +571,7 @@ func (h *HugoSites) loadData(fis []hugofs.FileMetaInfo) (err error) {
 	return
 }
 
-func (h *HugoSites) handleDataFile(r source.File) error {
+func (h *HugoSites) handleDataFile(basePath string, r source.File) error {
 	var current map[string]any
 
 	f, err := r.FileInfo().Meta().Open()
@@ -581,7 +582,8 @@ func (h *HugoSites) handleDataFile(r source.File) error {
 
 	// Crawl in data tree to insert data
 	current = h.data
-	keyParts := strings.Split(r.Dir(), helpers.FilePathSeparator)
+	dataPath := filepath.Join(basePath, r.Dir())
+	keyParts := strings.Split(dataPath, helpers.FilePathSeparator)
 
 	for _, key := range keyParts {
 		if key != "" {


Test patch:
diff --git a/hugolib/hugo_modules_test.go b/hugolib/hugo_modules_test.go
index 3353f508e5f..88a0c3ec630 100644
--- a/hugolib/hugo_modules_test.go
+++ b/hugolib/hugo_modules_test.go
@@ -1178,3 +1178,32 @@ target = "content/resources-b"
 	b.AssertFileContent("public/resources-a/subdir/about/index.html", "Single")
 	b.AssertFileContent("public/resources-b/subdir/about/index.html", "Single")
 }
+
+func TestMountData(t *testing.T) {
+	files := `
+-- hugo.toml --
+baseURL = 'https://example.org/'
+disableKinds = ["taxonomy", "term", "RSS", "sitemap", "robotsTXT", "page", "section"]
+
+[[module.mounts]]
+source = "data"
+target = "data"
+
+[[module.mounts]]
+source = "extra-data"
+target = "data/extra"
+-- extra-data/test.yaml --
+message: Hugo Rocks
+-- layouts/index.html --
+{{ site.Data.extra.test.message }}
+`
+
+	b := NewIntegrationTestBuilder(
+		IntegrationTestConfig{
+			T:           t,
+			TxtarString: files,
+		},
+	).Build()
+
+	b.AssertFileContent("public/index.html", "Hugo Rocks")
+}