Can mounts from config files be merged?

TL;DR: hugo config mounts –config hugo.yaml,extra-mounts.yaml … shows that only the mounts from the extra config file are used, despite the _merge:deep in hugo.yaml. Does merging happen only with theme config?

== Context ==

While waiting for the nifty feature described in mounts: Add name mapping config option #10129, we’ve been using explicit mount lists that map README.md to _index.md, something like this:

module:
  mounts:
    ...
    # DO NOT EDIT - semconv autogenerated mounts below - DO NOT EDIT
    - source: tmp/semconv/docs/app/README.md
      target: content/docs/specs/semconv/app/_index.md
    - source: tmp/semconv/docs/azure/README.md
      target: content/docs/specs/semconv/azure/_index.md
    - source: tmp/semconv/docs/browser/README.md
      target: content/docs/specs/semconv/browser/_index.md
    ...

The problem is that the semconv changes quite a bit and the mount list along with it; so we’re ending up with merge conflicts to deal with way more often than I’d like.

So I thought that I could move the README to index list to a separate file that would be generated a build time, rather than kept under version control.

== Problem ==

The problem is that the deep merge setting doesn’t appear to be working me, or at least not the way I expect. My setup is something like this

  • hugo.yaml containing base module: mounts: … and _merge: deep, see below
  • extra-mounts.yaml containing the README mount list
# hugo.yaml
...
module:
  _merge: deep # <== DEEP MERGE
  mounts:
    ## en
    - source: content/en
      target: content
...

I then run hugo –config hugo.yaml,extra-mounts.yaml … but the mounts don’t appear to be merged.

Running hugo config mounts with the above config args shows only the mounts from extra-mounts.yaml. Am I misunderstanding how merging is working. Maybe the merging only happens relative to theme configs?

Thanks!

I guess (1) two config files in the site and (2) module mounts are different.

I don’t know if (1) works, should work and if how that could be configured.

but you could create a module and import it

hugo.yaml in your project

baseURL: https://example.org/
...
module:
  mounts:
    - source: content/en
      target: content
  imports:
    - path: c:/_my/module

hugo.yaml in your readme module

module:
  mounts:
    - source: README_ONE.md
      target: content/readme/index.md
C:\_MY\MODULE
    go.mod
    hugo.yaml
    README_ONE.md

guess your module can start at tmp/semconv/docs/ just make sure the files are not outside the imported module

I haven’t read the entire thread here, but the gist of it is:

  • Mounts from project + themes/modules are combined into one big one.
  • Mount configs within one project (which I guess is the core of the question here) is a slice, so once it’s set, it will not be merged/overwritten by another mount config. So you cannot currently combine mounts from multiple config files.

As to why we cannot do this has been discsussed before; but there’s no way to merge slices without additional information.

1 Like

So that one is answered by @bep. thx and points me to the stuff below

UPDATE

the two file approach works if you have one file containing all the module settings (see below for content and generation) and then

# ATTENTION: --config expects a string, so enclose the files in double quotes
#     (at least on Windows/Powershell)
hugo --config "hugo.yaml,extra.yaml"

you could split the config up in a config dir:

  • leave everything but the extra part in /hugo.toml.
  • add all mount options to /config/_default/modules.html
    mounts:
    - source: content/en
      target: content
    - source: c:/_my/extra/README_ONE.md
      target: content/readme/index.md
    

if this is practicable for you cause you will have to add your non README stuff with a script

as you already need a build step and combine these files before build

/config
    /_default
        /module
            _base.yaml <- static stuff
            _extra.yaml <- generated stuff

scenarious using a

  • default environment with only standard as module.yaml
  • special environment that – with a build script generates env/special/modules.yaml

just to mention: the module option allows for semver versioning :smiling_face_with_sunglasses:

Thanks for the clarifications @bep.

Thanks for exploring solutions @irkode. I tried the module approach, but the mounts still aren’t merged. When I run hugo config --format yaml, I get:

module:
  hugoversion: {}
  imports:
  - path: semconv # <== Notice, no mounts, just a path
  - path: docsy
  mounts: # <== Listed below are only the mounts from the main project
  - source: content/en
    target: content
  ...

My main hugo.yaml is:

module:
  _merge: deep
  imports:
    - path: semconv
  mounts:
    ## en
    - source: content/en
      target: content
   # ...

And I put the module under themes:

$ ls -R themes/semconv 
go.mod          hugo.yaml

If I declare semconv as a theme, I get the same result. It is recognized, but no mounts are merged.

I guess that the mounts are considered “local” to the module / theme.

examples to play with at the end of the post

if you cannot get it to work, please share yours real setup and layout incl the module
will save both of us some time

From your description I get would check these:

  • your site has to be a go module, too git mod init

  • using module import usually means importing from outside your repo.
    I never tried to import a module that is already physically located in site/themes
    but if this works, I think it will fail the next step with your setup

  • your ls of the module shows no files !!
    in general a module is not allowed to access files from outside on your project
    that’s why I placed the readme physically in the module.

with your original setup your original setup would look like:

module:
  imports:
    - path: /tmp/semconv # <- notice this is an external module some where outside your repo
  mounts:
    - source: content/en
      target: content

to setup the extra module do (I assume the /tmp/semconv/docs folders cointain much more files) so I keep the single file mounts

  • cd /tmp/semconv/docs
    hugo mod init extra
    
  • /tmp/semconv/docs/hugo.yaml
    module:
      mounts:
        - source: app/README.md
          target: content/docs/specs/semconv/app/_index.md
        - source: azure/README.md
          target: content/docs/specs/semconv/azure/_index.md
    
    

Take these for a spin

I pushed two branches for you to play with

git clone --single-branch -b topic-56187-mount-module https://github.com/irkode/hugo-forum.git using-module
git clone --single-branch -b topic-56187-mount-config https://github.com/irkode/hugo-forum.git using-config

They require a folder c:/_my_module/ in your filesystem with this content:

  • the file imported : README_ONE.md
  • the module version additionally
    • go mod init
    • my hugo.yaml as shown
logfiles
PS C:\_repos\github\clone> git clone --single-branch -b topic-56187-mount-module https://github.com/irkode/hugo-forum.git using-module
Cloning into 'using-module'...
remote: Enumerating objects: 75, done.
remote: Counting objects: 100% (51/51), done.
remote: Compressing objects: 100% (34/34), done.
remote: Total 75 (delta 12), reused 46 (delta 11), pack-reused 24 (from 1)
Receiving objects: 100% (75/75), 36.33 KiB | 1.30 MiB/s, done.
Resolving deltas: 100% (15/15), done.
PS C:\_repos\github\clone> git clone --single-branch -b topic-56187-mount-config https://github.com/irkode/hugo-forum.git using-config
Cloning into 'using-config'...
remote: Enumerating objects: 80, done.
remote: Counting objects: 100% (56/56), done.
remote: Compressing objects: 100% (36/36), done.
remote: Total 80 (delta 15), reused 51 (delta 14), pack-reused 24 (from 1)
Receiving objects: 100% (80/80), 37.44 KiB | 1.21 MiB/s, done.
Resolving deltas: 100% (18/18), done.
PS C:\_repos\github\clone> cd .\using-module\
PS C:\_repos\github\clone\using-module> hugo config mounts
{
   "path": "project",
   "version": "",
   "time": "0001-01-01T00:00:00Z",
   "owner": "",
   "dir": "C:\\_repos\\github\\clone\\using-module",
   "mounts": [
      {
         "source": "content\\en",
         "target": "content"
      },
      {
         "source": "data",
         "target": "data"
      },
      {
         "source": "layouts",
         "target": "layouts"
      },
      {
         "source": "i18n",
         "target": "i18n"
      },
      {
         "source": "archetypes",
         "target": "archetypes"
      },
      {
         "source": "assets",
         "target": "assets"
      },
      {
         "source": "static",
         "target": "static"
      }
   ]
}
{
   "path": "c:/_my/module",
   "version": "",
   "time": "0001-01-01T00:00:00Z",
   "owner": "project",
   "dir": "c:\\_my\\module\\",
   "mounts": [
      {
         "source": "README_ONE.md",
         "target": "content\\readme\\index.md"
      }
   ]
}
PS C:\_repos\github\clone\using-module> cd ..\using-config\
PS C:\_repos\github\clone\using-config> hugo config mounts --config "hugo.yaml,module.yaml"
{
   "path": "project",
   "version": "",
   "time": "0001-01-01T00:00:00Z",
   "owner": "",
   "dir": "C:\\_repos\\github\\clone\\using-config",
   "mounts": [
      {
         "source": "content\\en",
         "target": "content"
      },
      {
         "source": "c:\\_my\\module\\README_ONE.md",
         "target": "content\\readme\\index.md"
      },
      {
         "source": "data",
         "target": "data"
      },
      {
         "source": "layouts",
         "target": "layouts"
      },
      {
         "source": "i18n",
         "target": "i18n"
      },
      {
         "source": "archetypes",
         "target": "archetypes"
      },
      {
         "source": "assets",
         "target": "assets"
      },
      {
         "source": "static",
         "target": "static"
      }
   ]
}

That’s it! Thanks for all the details and logfiles. I’ll give that a try.