dotbot icon indicating copy to clipboard operation
dotbot copied to clipboard

Support named, conditional tasks

Open davesteinberg opened this issue 3 years ago • 7 comments

Just like on a link action, the value is executed in the shell. If it has a non-zero exit code (indicating failure), the whole task is skipped.

This allows tasks to group actions that only apply in certain conditions (e.g. on certain OSes or in certain configurations), and allows all actions (not just link) to be conditional.

Resolves #225.

davesteinberg avatar Jul 13 '20 02:07 davesteinberg

I haven't tackled trying to figure out the testing infrastructure yet, so I haven't written any tests. Here's the install.conf.yaml file I used to manually verify that the new functionality works and that I didn't break link in the refactoring:

- link:
    ~/profile.no:
      path: profile
      if: "false"
    ~/profile.yes:
      path: profile
      if: "true"

- if: "true"
  shell:
    - [touch $HOME/yes, I should do this]

- if: "false"
  shell:
    - [touch $HOME/no, I should not do this]

davesteinberg avatar Jul 13 '20 03:07 davesteinberg

This PR now supports named tasks, too, as described in https://github.com/anishathalye/dotbot/issues/225#issuecomment-657609807

Here's the install.conf.yaml file I used to manually verify it:

- defaults:
    link:
      create: true
      relink: true
    shell:
      stdin: true
      stdout: true
      stderr: true

- task: Prepare
  actions:
    clean: ["~"]

- link:
    ~/profile.no:
      path: profile
      if: "false"
    ~/profile.yes:
      path: profile
      if: "true"

- task: Go
  if: "true"
  actions:
    shell:
      - [touch $HOME/yes, I should do this]
    link:
      ~/profile.go.yes: profile

- task: No go
  if: "false"
  actions:
    shell:
      - [touch $HOME/no, I should not do this]
    link:
      ~/profile.go.no: profile

- task: No actions

- task: Empty actions
  actions: []

davesteinberg avatar Jul 20 '20 00:07 davesteinberg

Thanks for taking the time to submit a PR. I left some general comments related to the discussion in #225 back in https://github.com/anishathalye/dotbot/issues/225#issuecomment-669606842.

This is an interesting proposal. While not technically backwards compatible in the strictest sense (there could have been a plugin called "if" or "task"), I don't think it will break anything in practice (nobody is using those plugin names). It does change the execution model for tasks. As it's implemented now, tasks are a set of actions, and Dotbot executes all of them independently (in an arbitrary order).

I wonder what is the use of named tasks, beyond documentation? Would it be equivalent if they were # yaml comments?

Compositionality is a tricky issue... I'm going to spend a bit of time thinking about many of the open issues for Dotbot, thinking a bit about how people are using Dotbot in practice (going to try to do a user study), think about what we'd change if we could break backwards compatibility, and so on. I'll try to see if there's a clean solution to this problem of compositionality (e.g. it's a little annoying if we have a different if: inside link: vs the if: at the level of the task, and I think this sort of problem might come up again in other contexts), thinking about both the case where we stick to a YAML-based config file and also the case where we switch to a different syntax, either something custom or an embedded DSL in a full-fledged programming language.

I'll leave this issue open right now, so I can think about it for a bit. Happy to hear feedback from you on this as well. (Once I make a bit more progress on a user study and going through issues, I might try to come up with a more general way to discuss and get feedback on potential larger-scale changes / a Dotbot 2.0).

anishathalye avatar Aug 06 '20 00:08 anishathalye

Thanks for considering my proposal and for the feedback here and on the issue.

To answer your question here: I think the main use of named tasks is for log output. It lets dotbot print out the name of the task when it begins running or when it is skipped, giving context that helps the user to understand what happened.

I agree with all of your comments on #225. It's not strictly backwards compatible, but the risk of someone using task or if as a plugin name is very low. It is a bit verbose (especially if you only ever use one action per task), but you can skip all the extra syntax if you don't want to use named/conditional actions, and just continue to do what you do today.

Regarding the limitation that actions in a task are unique and unordered, I think that's okay, since it feels like imposing order or repeating actions within a task are super edge-case. At worst, you could always split one task into more than one if you had such a need, even if it meant repeating a test.

In the end, I still see my proposal as small change that gives you a whole lot more power, and that feels worth it to me. But of course that's based only on my usage. And I can see why you might prefer to shoot for something better in a larger-scale change.

Thanks again!

davesteinberg avatar Aug 31 '20 18:08 davesteinberg

@anishathalye any chance you will merge this, both the named part and conditional part would be very useful.

Today I'm trying to figure out how to run a command, but only if a directory doesn't already exist. I don't think there's any way to do this, but this PR would solve it.

Futurile avatar Feb 06 '22 17:02 Futurile

For the moment, as a workaround, you could incorporate the check into the command. ! test -d some_dir_name && echo "some_dir_name either doesn't exist or is not a directory".

anishathalye avatar Feb 07 '22 15:02 anishathalye

@anishathalye Sorry for digging out older things here but....

I'd really like to have this! My max06/dotfiles are constantly growing. I use them heavily in any kind of containerized environment, in an automated manner. These containers serve specific purposes, like eg. containing an openstack client. Adding if-conditions to every task is not exactly a good way to keep the configuration clean. The automation prevents me from going with the profiles-route described in the wiki - dotbot itself needs to figure out what to use and what to skip. Writing an own script around dotbot to accomodate for this defeats the purpose. Ideally I'd love to have some kind of "include"-functionality, so I can reference each part in the main config with its filename and one single if condition. I'm also fine with grouping tasks like it's done here, as long as this reduces the conditions to one per block.

Any chance?

Edit: I need to edit myself...

- shell:
    - description: Include ansible configuration
      command: >
        [ -x "$(command -v ansible)" ] && ./install -c ansible.conf.yaml || true
      stdout: true

seems to do exactly what I had in mind!

(Not the nicest solution but better than nothing.)

max06 avatar Jun 05 '22 11:06 max06