twpayne / chezmoi

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

Add more config management functions #2215

Closed mcexit closed 2 years ago

mcexit commented 2 years ago

Is your feature request related to a problem? Please describe.

Functions are primarily limited to the Sprig library, which does not handle a lot of common config management functions.

Describe the solution you'd like

I'd like to see more functions available to address config management. The main functions here would to:

Additionally any merge functionality that may not be covered by Sprig functions. This helps streamline a common use case of overriding default config file values.

fromToml, toToml, fromIni, and toIni are all pretty self-explanatory. Here are some examples of where those are already implemented in Go.

  1. https://gohugo.io/functions/transform.unmarshal/
  2. https://docs.gomplate.ca/functions/data/
  3. https://github.com/go-ini/ini

replaceRE is the name of a function in Hugo^1 that allows for proper pipelining^2 and a limit parameter.

partials are like templates^3, except that you can do pipelining on the results, with an optional return function^4 in the partial template.

comment is very similar to the indent Sprig functions, and takes inspiration from an Ansible filter^5. This would take either a single or multiline string and adds the specified comment character(s) at the beginning of each newline. A common use case for this is a disclaimer for users that may try editing a file directly outside of the sourceDir:


.local/share/chezmoi/.chezmoitemplates/disclaimer

This file is managed by chezmoi. Do not edit!
To change it, modify {{ joinPath .chezmoi.sourceDir .chezmoi.sourceFile }}

.local/share/chezmoi/private_dot_config/example/exampleconfig.conf.tmpl

partial "examplepartial" | comment "#"

Describe alternatives you've considered

I've already to the larger extent implemented these in each file template, but it requires a lot of duplication.

twpayne commented 2 years ago

Thank you for the extremely complete and well-researched feature request!

2218 and #2237 add some of the functions.

For toIni and fromIni, these might take a bit more time as the .ini format does not seem to be well defined, and the Go library's API is rather ... large.

For partial and exit, these would require extensive re-writing of chezmoi's use of templates. Is it possible for you to use .chezmoitemplates and the template function instead?

mcexit commented 2 years ago

Thank you! I was able to clean up my templates significantly.

For toIni and fromIni, these might take a bit more time as the .ini format does not seem to be well defined, and the Go library's API is rather ... large.

Understandable. I was able to find the following, but it may not be an easy fix. Unfortunately I'm not the expert when it comes to Go, just more of a beginner with a descent understanding of templates from working with Hugo:

https://github.com/go-ini/ini

For partial and exit, these would require extensive re-writing of chezmoi's use of templates. Is it possible for you to use .chezmoitemplates and the template function instead?

The only issue I'm encountering is you can't pipeline or assign templates from what I can tell, so I'm not sure how to resolve at the moment. The comment function helped a little, but ultimately I'd like to pipeline the output of a template into that function. There are other things that it could be used for though. Regardless, thanks for taking notice and your diligence.

twpayne commented 2 years ago

The only issue I'm encountering is you can't pipeline or assign templates from what I can tell, so I'm not sure how to resolve at the moment. The comment function helped a little, but ultimately I'd like to pipeline the output of a template into that function.

Ah, good point. Yes, I don't think there's a way to capture the output of template for a pipeline.

As a drive-by comment, it might be possible to use the template data for your specific disclaimer case. If your disclaimer template in .chezmoitemplates/disclaimer contains:

{{ .prefix }}This file is managed by chezmoi. Do not edit!
{{ .prefix }}To change it, modify {{ joinPath .chezmoi.sourceDir .chezmoi.sourceFile }}

and you then invoke it with:

{{ template "disclaimer" (dict "prefix" "# " "chezmoi" .chezmoi) }}

you might get the effect you want with less code for now, at least until partial/return is implemented in chezmoi. I admit that I haven't actually tested the approach I proposed though.

mcexit commented 2 years ago

Thanks, that is very similar to what I ended up doing but I ended up incorporating the comment function with it. It is workable... and if you do get around to adding partial/return functionality, then great.

{{ partial "disclaimer" .chezmoi | comment "# " }} would be cleaner, but no complaints here!

twpayne commented 2 years ago

OK, I've added fromToml, toToml, fromIni, replaceRE (as replaceAllRegex), and comment.

For toIni, I don't think it's possible to add a sensible function for two reasons:

  1. The ini file format is not well defined and has hundreds of subtle variations. There is no canonical format and parameterizing toIni would make the function very hard to use.
  2. The gopkg.in/ini.v1 package has a frankly awful API and does not make it easy to write such a function.

Instead, for generating .ini files, I recommend using a template that generates the correct format variation that you need for the data you have.

For partial and return, this would require completely re-writing chezmoi's use of text/template, which I don't think is worth it, especially as similar (but not quite as elegant) functionality is already available through the use of .chezmoitemplates. I would accept a PR that implements this, however.

So, closing this as completed. Feel free to continue discussions, however.

mcexit commented 2 years ago

Thank you kindly for working on this. I will contribute more via a PR if I am able to do so at some point.

The ini file format is not well defined and has hundreds of subtle variations. There is no canonical format and parameterizing toIni would make the function very hard to use.

While I agree that there is no standard INI format like you'd see with YAML, there is a consistent format used by a majority of programs that I commonly interact with.

The gopkg.in/ini.v1 package has a frankly awful API and does not make it easy to write such a function.

That is unfortunate to hear, but I just linked with one of the first presentable Go packages I found. There may be others better suited for the task but I really don't know the best way to evaluate what would be an ideal module to create a function from, especially one that may allow an optional parameter to handle variations.

Again, thank you for your efforts as they make the process of utilizing chezmoi more friendly than implementing a bunch of custom templates. I'll explore implementing the additional functionality of writing to an INI file within the .chezmoitemplates directory. I am hopeful that there may be an opportunity to allow mixed-case keys within chezmoi config at some point although for that I would make another request for discussion or see if there is an existing request already.

twpayne commented 2 years ago

I am hopeful that there may be an opportunity to allow mixed-case keys within chezmoi config at some point although for that I would make another request for discussion or see if there is an existing request already.

Handling mixed-case keys is a long standing bug/feature in the viper library that chezmoi uses for parsing its config file. See #463.

twpayne commented 2 years ago

2279 tracks the feature request for partial and return so it doesn't get forgotten.