Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Properly handling file paths with spaces in them in merge tool settings in .chezmoi.toml.tmpl #4169

Open
3 tasks done
macintacos opened this issue Dec 30, 2024 · 5 comments
Open
3 tasks done
Labels
support Support request

Comments

@macintacos
Copy link

macintacos commented Dec 30, 2024

What exactly are you trying to do?

I'm trying to implement "Use VSCode as the merge tool" as described in the docs here: https://www.chezmoi.io/user-guide/tools/merge/

It doesn't work quite right when you try to use something like chezmoi merge-all to resolve your configuration on files that have paths with spaces in them, like ~/Library/Application Support on macOS. Or at least, I'm not sure why it's not working properly. When it executes the function in the documentation, it appears to be trying to diff multiple files (like ~/Library/Application and Support/<file>) that just straight up don't exist, and I'm assuming it's because of that space in the path.

My .chezmoi.toml.tmpl currently looks like this:

{{- $email := promptStringOnce . "email" "Email Address" -}}

{{/*
  `workingContext` is the context you are working from. Basically - is this a "work"
  machine, or is it a "personal" machine? Etc.
*/}}
{{- $choices := list "work" "personal" -}}
{{- $workingContext := promptChoiceOnce . "workingContext" "What context is are you working in" $choices -}}

[data]
email = {{ $email | quote }}
workingContext = {{ $workingContext | quote }}

[diff]
command = "code"
args = [
  "--wait",
  "--diff",
  "{{ `{{ .Destination }}` }}",
  "{{ `{{ .Target }}` }}",
]

[merge]
command = "bash"
args = [
  "-c",
  "cp {{ `{{ .Target }}` }} {{ `{{ .Target }}` }}.base && code --wait --new-window --merge {{ `{{ .Destination }}` }} {{ `{{ .Target }}` }} {{ `{{ .Target }}` }}.base {{ `{{ .Source }}` }}",
]

The .chezmoi.toml file that gets generated after chezmoi init seems correct to my eyes:

[data]
email = "blah"
workingContext = "work"

[diff]
command = "code"
args = [
  "--wait",
  "--diff",
  "{{ .Destination }}",
  "{{ .Target }}",
]

[merge]
command = "bash"
args = [
  "-c",
  "cp {{ .Target }} {{ .Target }}.base && code --wait --new-window --merge {{ .Destination }} {{ .Target  }} {{ .Target }}.base {{ .Source }}",
]

I tried using the quote function (by adding | quote everywhere, like {{ .Target | quote }}), but it seems not to believe that it exists:

$ chezmoi merge-all
chezmoi: template: merge.args[1]:1: function "quote" not defined

How can I make sure that the paths that are passed to the cp / code command in the documentation are properly escaped so that spaces are interpreted as part of the path for the .Destination / .Source / .Target variables?

Where else have you checked for solutions?

Output of any commands you've tried with --verbose flag

$ chezmoi --verbose $COMMAND

Running `chezmoi --verbose merge-all didn't print anything to the console. Anything I should be doing here?

Output of chezmoi doctor

$ chezmoi doctor
RESULT    CHECK                       MESSAGE
ok        version                     v2.53.1, commit Homebrew, built at 2024-10-28T10:15:00Z, built by Homebrew
warning   latest-version              v2.57.0
ok        os-arch                     darwin/arm64
ok        uname                       Darwin M-QM24K02V5H 23.6.0 Darwin Kernel Version 23.6.0: Fri Nov 15 15:13:15 PST 2024; root:xnu-10063.141.1.702.7~1/RELEASE_ARM64_T6000 arm64 arm Darwin
ok        go-version                  go1.23.2 (gc)
ok        executable                  /opt/homebrew/bin/chezmoi
ok        upgrade-method              brew-upgrade
ok        config-file                 ~/.config/chezmoi/chezmoi.toml, last modified 2024-12-30T16:21:51-05:00
warning   source-dir                  ~/.local/share/chezmoi is a git working tree (dirty)
ok        suspicious-entries          no suspicious entries
warning   working-tree                ~/.local/share/chezmoi is a git working tree (dirty)
ok        dest-dir                    ~ is a directory
ok        umask                       022
ok        cd-command                  found /opt/homebrew/bin/fish
ok        cd-args                     /opt/homebrew/bin/fish
ok        diff-command                found /opt/homebrew/bin/code
ok        edit-command                found /opt/homebrew/bin/nvim
ok        edit-args                   /opt/homebrew/bin/nvim
ok        git-command                 found /opt/homebrew/bin/git, version 2.47.0
ok        merge-command               found /opt/homebrew/bin/bash
ok        shell-command               found /opt/homebrew/bin/fish
ok        shell-args                  /opt/homebrew/bin/fish
info      age-command                 age not found in $PATH
ok        gpg-command                 found /opt/homebrew/bin/gpg, version 2.4.6
info      pinentry-command            not set
ok        1password-command           found /opt/homebrew/bin/op, version 2.30.3
info      bitwarden-command           bw not found in $PATH
info      bitwarden-secrets-command   bws not found in $PATH
info      dashlane-command            dcli not found in $PATH
info      doppler-command             doppler not found in $PATH
info      gopass-command              gopass not found in $PATH
info      keepassxc-command           keepassxc-cli not found in $PATH
info      keepassxc-db                not set
info      keeper-command              keeper not found in $PATH
info      lastpass-command            lpass not found in $PATH
info      pass-command                pass not found in $PATH
info      passhole-command            ph not found in $PATH
info      rbw-command                 rbw not found in $PATH
info      vault-command               vault not found in $PATH
info      vlt-command                 vlt not found in $PATH
info      secret-command              not set

Additional context

For background on how I got here, I was just checking out the Ghostty terminal, and its config is in ~/Library/Application Support on macOS. I started managing the config file as part of chezmoi (via chezmoi add $HOME/Library/Application\ Support/com.mitchellh.ghostty/config), which works fine, however I edited some settings directly in the file instead of via chezmoi, so I decided to use chezmoi merge-all to merge them. It's my first time using that command, and I wanted to use VSCode to do that diff instead of vimdiff, which led me to the aforementioned documentation page. Any help would be greatly appreciated! Thanks!

@macintacos macintacos added the support Support request label Dec 30, 2024
@halostatue
Copy link
Collaborator

I tried using the quote function (by adding | quote everywhere, like {{ .Target | quote }}), but it seems not to believe that it exists:

$ chezmoi merge-all
chezmoi: template: merge.args[1]:1: function "quote" not defined

This feels like it should be a bug, but I can understand not wanting to make all template instantiations use the formatting functions (it's non-trivial to set up). However, I think that you can make this happen with:

[merge]
command = "bash"
args = [
  "-c",
  "cp {{ `"{{ .Target }}"` }} {{ `"{{ .Target }}"` }}.base && code --wait --new-window --merge {{ `"{{ .Destination }}"` }} {{ `"{{ .Target }}"` }} {{ `"{{ .Target }}"` }}.base {{ `"{{ .Source }}"` }}",
]

@macintacos
Copy link
Author

That did indeed work, thank you @halostatue! You have to change the outermost quotes to be single quotes (otherwise it gets interpreted as multiple strings). So this would be the correct thing to do:

[merge]
command = "bash"
args = [
  "-c",
  'cp {{ `"{{ .Target }}"` }} {{ `"{{ .Target }}"` }}.base && code --wait --new-window --merge {{ `"{{ .Destination }}"` }} {{ `"{{ .Target }}"` }} {{ `"{{ .Target }}"` }}.base {{ `"{{ .Source }}"` }}',
]

I'm going to leave this open though, since I think the documentation should be updated to make this adjustment clear.

@LeonardoMor
Copy link

LeonardoMor commented Dec 31, 2024

This is mentioned on the docs for Diff

image

To avoid dealing with so much quoting, you can also use the available functions. For example, I simply use print like this:

[merge]
    command = "nvim"
    args = [
        {{ print "{{.Destination}}" | quote }},
        {{ print "{{.Source}}" | quote }},
        {{ print "{{.Target}}" | quote }}
    ]

@macintacos
Copy link
Author

@LeonardoMor appreciate the callout in the docs, but I tried that and it didn't work. I'll try it again just to verify.

@LeonardoMor
Copy link

Using print should work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
support Support request
Projects
None yet
Development

No branches or pull requests

3 participants