Glob process (pattern match) resource files in a folder with resources.Match?


#1

I have svg icon files in assets/icon/ folder with stroke values set as {{ .Site.Params.icons.color1 }} so I can .ExecuteAsTemplate and control their color using configuration.

I can use template logic to process individual files like this:

{{- $test := resources.Get "icons/test1.svg" | resources.ExecuteAsTemplate "icons/test1.svg" . }}
{{ $test.RelPermalink }}

But I want to use a glob or pattern to output the folder using file names, and so I can just drop more in as/when I make them.

I had thought that this is what resources.Match was for, but I can’t seem to figure out how to get it to work. For example:

{{- $test := resources.Get "icons/*" | resources.ExecuteAsTemplate "icons/*" . }}
{{ $test.RelPermalink }}

I’ve tried .Get and .GetMatch too, but the error is basically same:

<resources>: can't evaluate field Match in type interface {}

I understand that this means Hugo is not recognising the path as a pattern, and is probably trying to match it as a string.

I also tried ranging, but not sure I got this right or even how to declare/assign $variables to each item so I can then add the .ExecuteAsTemplate transform to it.

Can someone help please?

Thank you in advance.


#2

Hi,

I think the confusion is with Hugo Pipes (resources.Get "sass/main.scss") vs Page Resources (.Resources.GetMatch "**.jpg").

I don’t think Pipes has .GetMatch.


#3

Oh really, they’re different? That’s unexpected and confusing. I just assumed it was a path reference - but that may also explain why I’ve battled a bit with Hugo’s templating.

Thanks for the heads @pointyfar - I’ll try play around with that.


#4

Hi @pointyfar or anyone else

So I can glob with Page Resources.

What I now have is two test svgs (test1.svg, and test2.svg) in a central content/images/icon/ folder (no longer in the assets/ folder), where content/images/ is a headless (frontmatter: headless: true) leaf bundle (index.md).

With the following (inside my head.html partial), I can trigger getting the test resources and outputting them to public/images/icons/ folder:

{{ with .Site.GetPage "section" "images" }}
  {{ with .Resources.ByType "text" }}
    {{ range .Resources.Match "icons/*" | resources.ExecuteAsTemplate "icons/*" . }}
    {{ end }}
  {{ end }}
{{ end }}

HOWEVER, the Go templating inside the test .svg files ( {{ .Site.Params.icons.color1 }} set in my theme’s config.yaml ) are not being processed by Hugo.

So I am starting to think that:

  1. the .ExecuteAsTemplate pipe doesn’t work with Page Resources (.Resources),
  2. just like globbing doesn’t work with the Asset Folder resource piping (resources).

Does that accord with anyone else’s understanding?

Any workaround anyone can think of?

Preferably using the Asset folder (as I feel these are best described as non-page content and more “naturally” belong there), but I’ll take a solution using the “image page” hack too?

Thanks.


#5

That’s how I understand it as well.

You could try use readDir to get the files inside the assets/icons and then resources.ExecuteAsTemplate :

{{ $iconsrc := readDir "assets/icons" }}
{{ $icons := slice }}
{{ range $iconsrc }}
  {{ $icon :=  resources.Get (printf "icons/%s" .Name ) | resources.ExecuteAsTemplate  (printf "icons/%s" .Name) $ }}
  {{ $icons = $icons | append $icon  }}
{{ end }}

{{ range $icons }}
{{.Permalink}}
<br>
{{ end }}

#6

@pointyfar you’re awesome, thanks. I’m out and about now, but I’ll give this ago when I’m back home again.

By the way, your advice about “resources” being different from “.Resources” was a really helpful revelation. It’s clarified Hugo templating a lot for me - thank you!


#7

@pointyfar

I had to set the target path to the theme’s asset dir, but that worked so you win the secret Hugo Hero badge!

I really liked the approach - which I think was:

  1. Define the target (readDir)
  2. Create an empty array (slice)
  3. Loop over the the target (range):
    3.1 read the found items filenames (printf), process them, and output using those filenames, and
    3.2 throw the items into the empty array (append).
  4. Finally, go through the now full array and reference the .Permalinks.

That process seems a really powerful tool to have in the tool belt - knowledge of Go’s print / format package is clearly useful.

Bearing in mind I am not a coder, I’ve done some research but am curious about:

  1. The .Name input is from Hugo’s data structure, right? So in theory we could input .Content too (if it was a page) or some other value?

  2. In the appending self, why does = work but not := we’re used to seeing? What is it doing? Is the difference between “assign to” and “is” respectively?

Thanks again!


#8

readDir returns an array of os.FileInfo, with .Name being one of the keys. .Content does not seem to be available though, but once you have the .Name and assuming you know the path, you can resources.Get using the full path + name (as we do in the code above). We could also use readFile if you just wanted the contents, but then we lose the ExecuteAsTemplate feature.

The simplified answer is that = is used to overwrite the value initially declared using :=

Happy to help!


#9

Thanks again @pointyfar - you’ve been very kind!