dotbot icon indicating copy to clipboard operation
dotbot copied to clipboard

Templating support?

Open ashkitten opened this issue 7 years ago • 11 comments

I don't know how hard it would be, but would it be possible to allow for templating support in the case of files with only minute differences? That would be really useful for me.

ashkitten avatar Apr 03 '17 19:04 ashkitten

It's a neat idea!

The approach I currently use is that I have my common config in a dotfiles repo, and I have per-machine configs in branches in a dotfiles-local repo. And then I use includes to include the machine-specific config. At least for the software I use, most of them do support some kind of include mechanism, so this works out fine for me. And for software that does work like this, I think this is a cleaner solution.

But for software that doesn't support any kind of include mechanism, I can see that it could be frustrating. I wonder if it's possible to do templating in a simple and clean way... thoughts?

Also, this is another example of an idea that could be initially developed as a plugin and then could potentially be merged in as a first-party plugin.

anishathalye avatar Apr 03 '17 19:04 anishathalye

I've implemented a hosts option (dictionary) for the link plugin in my fork project. It allows to define the names of hosts this configuration should be applied on. The difference between dotbot is that I'm using multiple configuration files as described in the Design Concept, but maybe this can be ported for dotbot too.

arcticicestudio avatar Apr 04 '17 05:04 arcticicestudio

Snowsaw looks neat!

Hmm, so between (1) includes, (2) templating, and (3) host-based per-machine configs, which one is the cleanest solution?

Dotbot already supports (1) in a natural way. At least for the programs I use, that has been sufficient, but I recognize that it doesn't work for everything.

Dotbot doesn't implement (2). Dotbot can do (3), but it's kinda clunky (with a bash script).

Kinda related issues: #96, #81, #44

anishathalye avatar Apr 07 '17 21:04 anishathalye

Thanks, but it would not exist in this form without your awesome project it is based on 😉

I would vote for (1) which opens up a way to do some kind of dependencies and would like to suggest my host option as a single feature since it can not be directly be seen as a kind of template.

[...] with only minute differences.

@ashkitten Can you please explain this a bit more detailed?

arcticicestudio avatar Apr 17 '17 14:04 arcticicestudio

not @ashkitten but maybe having the same issue: I use dotbot on my macbook and on some cloud machine. Some ssh config options apply only for macbook, others for cloud. Ideally, I'd use the Include command in my .ssh/config. Unfortunately, this is only available since version 7.3 but an older version is installed in the cloud machine.

If dotbot knew templates I would transform the main config into a template and source the environment-depending parts from my dotfiles-local repository.

In summary, I like the dotfiles-local approach but see templates as a good solution for software that does not include Include.

jhereth avatar Jan 31 '19 09:01 jhereth

I had a similar issue, with .ssh/config, and here's how I did it with my dotfiles-local repository. The main config is in the master branch, and the macOS specific config is in the mac branch (see the added lines 1-4), where master is periodically merged into mac. Seems to work all right for me.

Templating support is something I'm open to considering, if we can come up with a nice design for it.

What I don't like about templating is having to introduce additional syntax, not being able to parse/syntax highlight config files properly anymore (e.g. a templated .ssh/config is no longer a valid sshconfig), and having to escape actual config file contents if they conflict with the templating.

anishathalye avatar Jan 31 '19 14:01 anishathalye

While this is pretty old, i thought i might add my opinion on this. Note that these are most definitely not the cleanest solutions but they do not modify the actual file so the original .ssh/config is still useable as is

  1. Add per platform and/or hostname files like .ssh/config_win32, .ssh/config_darwin
  2. Add additional templating file like .ssh/config.template and this could work with platform and/or hostname specific files and you can just put .ssh/config_common and then in the template specify what kind of combination of prefixing, suffixing, etc, you want

sandorex avatar Jan 27 '20 17:01 sandorex

I use a custom plugin to template files using jinja2.

It creates a separate directive to template a source file using given parameters. You can see it in action here. It can also do some basic (and clunky) platform detection.

Heres the code (Maybe it will be useful to someone):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import platform
import dotbot
from jinja2 import Environment, FileSystemLoader


class Template(dotbot.Plugin):
    _directive = 'template'

    def can_handle(self, directive):
        return directive == self._directive

    def handle(self, directive, data):
        if directive == self._directive:
            for temp in data:
                target, opts = list(temp.items())[0]
                self._log.info("Rendering template %s" % target)
                try:
                    target = os.path.expanduser(target)
                    params = self._parse_params(opts['params'])
                    self._render_template(opts['source_file'], params, target)
                except:
                    self._log.error("Could not render %s" % target)
                    return False
            return True
        else:
            raise ValueError('Cannot handle this directive %s' % directive)

    def _parse_params(self, params):
        params = self._add_homedir(params)
        params = self._parse_platform_specific(params)
        return params

    def _add_homedir(self, params):
        params['HOME_DIR'] = os.environ['HOME']
        return params

    def _parse_platform_specific(self, params):
        if '__UNAME__' in params:
            uname = platform.system()
            for k in params['__UNAME__'].keys():
                params[k] = params['__UNAME__'][k][uname]
            del params['__UNAME__']
        return params

    def _render_template(self, template_file, params, target):
        cwd = self._context.base_directory()
        template_dir = os.path.dirname(
            os.path.abspath(cwd + '/' + template_file))
        jinja_env = Environment(loader=FileSystemLoader(template_dir))
        template = jinja_env.get_template(os.path.basename(template_file))

        with open(target, 'w') as target_file:
            target_file.write(template.render(params))

ssbanerje avatar Sep 09 '21 03:09 ssbanerje

@ssbanerje if you're interested, you could separate that plugin into a separate repo, and we could add it to the list of plugins.

anishathalye avatar Sep 09 '21 16:09 anishathalye

Sure. I have added it to the wiki under template. Here is a link to the repo for folks who see this issue.

ssbanerje avatar Sep 09 '21 16:09 ssbanerje

Thank you!

anishathalye avatar Sep 09 '21 17:09 anishathalye