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

Generalize chain? #11

Closed
baskerville opened this issue May 5, 2020 · 18 comments · Fixed by #20
Closed

Generalize chain? #11

baskerville opened this issue May 5, 2020 · 18 comments · Fixed by #20

Comments

@baskerville
Copy link
Contributor

The current behavior is to abort a chain of actions on the first failure.

Would it be possible to introduce the following variants of chain:

  • and_then: only executes if the last executed action succeeded.
  • or_else: only executes if the last executed action failed.
@shermp
Copy link
Collaborator

shermp commented May 5, 2020

Intriguing idea. I wrote the original chain code, with the goal of being as simple and non-invasive to the current code base (at the time) as possible.

Currently, it's basically just a dumb list of function pointers, I'd have to have a bit of a think as to how it could be implemented (and parsed!)

@shermp
Copy link
Collaborator

shermp commented May 5, 2020

Because I can't help myself, I'm prototyping this to see how it could work.

@baskerville
Copy link
Contributor Author

I think you'd need an extra attribute in nm_menu_action_t to express whether you're dealing with and_then or or_else, (chain is probably a synonym for and_then). And then you just need to keep track, within the aforementioned loop, of the return status of the last executed action.

@shermp
Copy link
Collaborator

shermp commented May 5, 2020

I'm actually thinking of using the terms on_success/on_failure instead. Seems to be a more explicit terminology for the desired effect. Thoughts?

@baskerville
Copy link
Contributor Author

baskerville commented May 5, 2020

I'm actually thinking of using the terms on_success/on_failure instead.

I'm fine with it.

@shermp
Copy link
Collaborator

shermp commented May 5, 2020

Got a prototype semi-working. It's going to need a bit more time in the oven before I push it.

EDIT: Hopefully, morning brain might be a bit more with it than midnight brain...

@pgaskin
Copy link
Owner

pgaskin commented May 5, 2020

I don't know what @shermp has in mind yet, but I'd probably implement this myself by adding an on_success and on_failure bool fields nm_action_t which is only on_success by default. Then, I'd make variants of chain with chain_failure and chain_always. This has the advantage of pushing the complexity to the config parsing rather than the menu itself, while still having the best backwards-compatibility. I'm open to other ideas, though.

Another idea I'm considering is to add another option to nm_action_result_t which specifies whether to continue or abort, but I probably won't go with this. It seems simple at a first glance, but it ties a lot of unnecessary things together, which will make things harder to debug and maintain in the future.

shermp added a commit that referenced this issue May 6, 2020
This allows for conditional menu action execution, as discussed in #11
@shermp
Copy link
Collaborator

shermp commented May 6, 2020

Ok, I've pushed a prototype to shermp/conditional_actions. It's not extensively tested, but I haven't managed to break it FWIW. More testing can occur if @geek1011 thinks my approach is ok.

Here's the quick doc I wrote for the feature:

on_success:<action>:<arg>
on_failure:<action>:<arg>
     Adds a conditional action that is triggered when the preceeding chain or menu_item fails or succeeds.
     At most, one of each is allowed, and only one will be executed. If the on_success/on_failure succeeds,
     the next action in the chain will be triggered as normal.

The approach I took was a "jump ahead" approach. The jump distances are set during config parsing, and during the loop in menu.cc, the pointer is advanced as necessary to skip unwanted actions.

The approach means that one or both options may be set in the config, and the order of the two doesn't matter.

@pgaskin
Copy link
Owner

pgaskin commented May 6, 2020

Thanks! I'll have a closer look at this tomorrow or the day after.

One thought: That point about the order is interesting. The advantage of your approach is the clarity, but it comes at the cost of flexibility with action chaining. If anyone else has opinions on this tradeoff, I'd like to hear them.

@shermp
Copy link
Collaborator

shermp commented May 6, 2020

I hadn't really thought of conditional chains. My first impression of that idea is "it could get messy".

Note, with my approach, each action can have a condition attached to it if you like. Makes it very clear what condition belongs with which action.

eg:

menu_item ....
on_success ...
on_failure ...
chain ...
on_failure ...
chain ...
chain ...
on_failure ...
on_success ...

@pgaskin
Copy link
Owner

pgaskin commented May 6, 2020

OTOH, I was thinking more along the lines of shell script && and ||, so you'd have chain for always chaining, chain_success for if the previous action (whether in a chain or not) succeeded, and chain_failure for failure. Then, the menu would loop over each item and set a bool for if it failed or succeeded. It would skip over items which don't match the current set of bools.

So, you could do something like:

menu_item : ... : cmd_output : /bin/whatever
chain_failure : cmd_output : /bin/whatever_fallback
chain_failure : cmd_output : /bin/whatever_fallback2
chain_success : dbg_msg : Something worked
chain_failure: dbg_msg : Nothing worked
chain : dbg_msg : All finished
chain : do_something_else

@pgaskin pgaskin mentioned this issue May 7, 2020
@pgaskin
Copy link
Owner

pgaskin commented May 7, 2020

Does anybody else have an opinion on this?

@pgaskin pgaskin added this to the v0.1.0 milestone May 7, 2020
@baskerville
Copy link
Contributor Author

The behavior of && and || is probably what I had in mind.

@shermp
Copy link
Collaborator

shermp commented May 9, 2020

As this is @baskerville 's request, I'm happy with whatever you guys are happy with. Whether that's my approach, or a different one is fine by me.

@pgaskin
Copy link
Owner

pgaskin commented May 11, 2020

Ok, I'll probably go with my approach then. Thanks for working on this, though, @shermp.

pgaskin added a commit that referenced this issue May 11, 2020
@pgaskin
Copy link
Owner

pgaskin commented May 11, 2020

@baskerville, can you test this: https://github.com/geek1011/NickelMenu/suites/672525752/artifacts/6077878?

Here's what I tested this with myself:

menu_item:main:Test:cmd_output:500:mkdir /tmp/geek1011 && echo mkdir
chain:dbg_msg:Success
chain_failure:cmd_output:500:rm -rf /tmp/geek1011 && echo rm
chain_always:dbg_toast:Done

@baskerville
Copy link
Contributor Author

It seems to work fine, thanks.

@pgaskin
Copy link
Owner

pgaskin commented May 11, 2020

No problem. @shermp or @NiLuJe, can you try and break it, and maybe also come up with an example?

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

Successfully merging a pull request may close this issue.

3 participants