twpayne / chezmoi

Manage your dotfiles across multiple diverse machines, securely.
https://www.chezmoi.io/
MIT License
12.63k stars 475 forks source link

`.chezmoiexternal` - Download to the parent directory multiple times? #2475

Closed xfzv closed 1 year ago

xfzv commented 1 year ago

What exactly are you trying to do?

I'm trying to download four directories from two different archives to the same parent directory. The dirs structure should be as follows:

chrome
    ├── css
    ├── icons
    ├── image
    └── window

I have the following chrome/.chezmoiexternal.yaml file:

"":
  type: "archive"
  url: "https://github.com/black7375/Firefox-UI-Fix/archive/refs/heads/master.zip"
  refreshperiod: "168h"
  stripComponents: 1
  include: ["*/css/**", "*/icons/**"]

"":
  type: "archive"
  url: "https://github.com/datguypiko/Firefox-Mod-Blur/archive/refs/heads/master.zip"
  refreshperiod: "168h"
  stripComponents: 1
  include: ["*/image/**", "*/window/**"]

No issue with only one of the two, but it fails with both when running chezmoi apply:

.chezmoiexternal.yaml: yaml: unmarshal errors: line 26: mapping key "" already defined at line 5

What have you tried so far?

I actually found a workaround but it's ugly. I moved the .chezmoiexternal file to the chrome parent directory and used one entry per directory so that I can explicitly set the paths:

"chrome/css":
  type: "archive"
  url: "https://github.com/black7375/Firefox-UI-Fix/archive/refs/heads/master.zip"
  refreshperiod: "168h"
  stripComponents: 2
  include: ["*/css/**"]

"chrome/icons":
  type: "archive"
  url: "https://github.com/black7375/Firefox-UI-Fix/archive/refs/heads/master.zip"
  refreshperiod: "168h"
  stripComponents: 2
  include: ["*/icons/**"]

"chrome/image":
  type: "archive"
  url: "https://github.com/datguypiko/Firefox-Mod-Blur/archive/refs/heads/master.zip"
  refreshperiod: "168h"
  stripComponents: 2
  include: ["*/image/**"]

"chrome/window":
  type: "archive"
  url: "https://github.com/datguypiko/Firefox-Mod-Blur/archive/refs/heads/master.zip"
  refreshperiod: "168h"
  stripComponents: 2
  include: ["*/window/**"]

Is there a better way to handle this?

Where else have you checked for solutions?

Thanks in advance for any suggestion.

twpayne commented 1 year ago

.chezmoiexternal.yaml: yaml: unmarshal errors: line 26: mapping key "" already defined at line 5

This error is coming from the YAML parser: it is not allowed in YAML to have repeated map keys. Repeating "" as the key will therefore not work.

I actually found a workaround but it's ugly. I moved the .chezmoiexternal file to the chrome parent directory and used one entry per directory so that I can explicitly set the paths:

I'm surprised this works, but I'm glad it does.

As .chezmoiexternal.yaml is a template, you can use some template magic to reduce the repetition. Something like:

{{- range $_, $repo := list "black7375/Firefox-UI-Fix" "datguypiko/Firefox-Mod-Blur" }}
{{-   range $_, $dir := list "css" "icons" "image" "window" }}
"chrome/{{ $dir }}":
  type: "archive"
  url: "https://github.com/{{ $repo }}/archive/refs/heads/master.zip"
  refreshPeriod: "168h"
  stripComponents: 2
  include: ["*/{{ $dir }}/**"]
{{-   end }}
{{- end  }}
twpayne commented 1 year ago

Hang on, that won't work as it still has the duplicate keys problem.

bradenhilton commented 1 year ago

@twpayne I think the duplicate keys in your example are from {{- range $_, $repo := list "black7375/Firefox-UI-Fix" "datguypiko/Firefox-Mod-Blur" }}.

I'm unsure why moving to the parent directory is necessary, isn't it possible to simply do:

{{- $repo := "black7375/Firefox-UI-Fix" }}
{{- range $_, $dir := list "css" "icons" }}
"{{ $dir }}":
  type: "archive"
  url: "https://github.com/{{ $repo }}/archive/refs/heads/master.zip"
  refreshPeriod: "168h"
  stripComponents: 2
  include: ["*/{{ $dir }}/**"]
{{- end }}

{{- $repo = "datguypiko/Firefox-Mod-Blur" }}
{{- range $_, $dir := list "image" "window" }}
"{{ $dir }}":
  type: "archive"
  url: "https://github.com/{{ $repo }}/archive/refs/heads/master.zip"
  refreshPeriod: "168h"
  stripComponents: 2
  include: ["*/{{ $dir }}/**"]
{{- end }}
twpayne commented 1 year ago

Oops, you're right, thanks for the catch @bradenhilton :)

bradenhilton commented 1 year ago

I missed the $ on the repos, just added them.

bradenhilton commented 1 year ago

@twpayne Perhaps you had something like this in mind?

{{- $firefox_ui_fix := dict "repo" "black7375/Firefox-UI-Fix" "dirs" (list "css" "icons") }}
{{- $firefox_mod_blur := dict "repo" "datguypiko/Firefox-Mod-Blur" "dirs" (list "image" "window") }}
{{- range list $firefox_ui_fix $firefox_mod_blur }}
{{-   $repo := .repo }}
{{-   range $_, $dir := .dirs }}
"{{ $dir }}":
  type: "archive"
  url: "https://github.com/{{ $repo }}/archive/refs/heads/master.zip"
  refreshPeriod: "168h"
  stripComponents: 2
  include: ["*/{{ $dir }}/**"]
{{-   end }}
{{- end }}
xfzv commented 1 year ago

Thank you both! @bradenhilton can confirm either of your attempts works just fine. :+1: