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
Alias a command to a subcommand #281
Comments
|
Yes, aware of major versions! (I'm a maintainer/project lead of a large OSS project myself!) In this particular case, consumers are using the script I've created to perform automation tasks, so I'd love to have a forwards-compatible minor release before I bump to a new major and break BC. (This is something I've done in my OSS projects, and it's tended to make the transition to a new major far easier, which has led to fewer support headaches for myself and the other maintainers.) Thanks for reviewing; curious to see if it's something you're willing or able to tackle! Glad to help test out if you decide to attempt it! (I'd try, but have almost zero Ruby experience!) |
Ok. First of all, my major version comment was a joke :) - I am aware of both your credentials and the need to be backwards compatible wherever possible. Also - thanks for the detailed ticket, however - I would like to suggest a simpler solution that will hopefully work for you. The concept is this:
Now, to explain the above with files: # src/bashly.yml
name: cli
commands:
- name: foo
help: New foo
commands:
- &foo-list
name: list
help: New foo list
flags:
- long: --alpha
help: Alpha flag
# Deprecated
- <<: *foo-list
name: foo-list
private: true
filename: deprecated/foo_list_command.sh
function: deprecated_foo_list # this feature does not exist yet
# src/deprecated/foo_list_command.sh
echo "DEPRECATED: Use 'foo list' instead" >&2
cli_foo_list_command "$@" and output:
|
Actually - the above suggestion will also allow you to create a separate help with this YAML: name: cli
commands:
- name: foo
help: New foo
commands:
- &foo-list
name: list
help: New foo list
flags:
- long: --alpha
help: Alpha flag
# Deprecated
- <<: *foo-list
name: foo-list
help: DEPRECATED - use 'foo list' instead
private: true
filename: deprecated/foo_list_command.sh
function: deprecated_foo_list # this feature does not exist yet and I am also toying with the idea of wrapping the entire concept in one new directive: - name: foo-list
deprecated: foo list If you want, I can push a version that supports this |
Love these approaches! The two potential issues I see with using the
The first is not a huge problem, and, honestly, both could be cases that documentation would solve. I use the Docker version, but can also do the Ruby version for testing purposes. |
Not necessarily, and even if so, this is the niche case of the niche case. Normally, there should be no reason for anyone to use the
I am not following. This function name is internal. It will be suffixed by |
I mean it requires that somebody writing a command in bashly understands how something like: name: cli
commands:
- name: config
commands:
- name: set-default translates to the functions |
I have just pushed a new branch, if you want to test this approach. I have not published an If using Ruby, make sure you have at least Ruby 2.7. ...and the beauty of it, is that the change cannot be any smaller |
Works brilliantly! A few notes for the docs:
These limitations work great for my purposes, and allow me to accomplish what I need to in terms of preparing a forwards compatible release. Thanks for the quick turnaround! |
Oh, this is slick! I discovered that I can have a script with front matter that omits the name: cli
commands:
- name: config
commands:
- name: set-default
import: src/config_set_default_command.sh
# Legacy commands
- name: config-set-default
import: src/config_set_default_command.sh
function: config_set_default_command
footer: $(red "DEPRECATED Use config set-default") The beauty of this is that I get to re-use the argument, flag, and filter configuration, and help text, but still draw attention to the deprecation. When I'm ready to cut the next major, I just remove all the items after |
Ran into my first issue. name: cli
commands:
- name: utility
commands:
- name: exec
import: src/utility_exec_command.sh
# Legacy commands
- name: exec
import: src/utility_exec_command.sh
function: utility_exec_command and where I have a When I run |
Excellent. Since the I would love your opinion on the docs and example, once I complete them. |
Can you paste a minimal version of what you have in |
Specifying And do not use I suggest you test with my initial minimal example, and review the generated script to understand what it does. |
You might be able to get away with this: # src/bashly.yml
name: cli
commands:
- name: foo
help: New foo
commands:
- &foo-list
name: list
help: New foo list
flags:
- long: --alpha
help: Alpha flag
# Deprecated
- <<: *foo-list
name: foo-list
help: DEPRECATED
private: true
filename: foo_list_command.sh
function: deprecated_foo_list Notes:
Although I still recommend my original concept - of allowing it to have its own file, and using this file to a) print deprecation and b) call the internal new function |
Wonderful - adding I'd also not understood the So yes,the combination of the new |
This is what I was hoping to hear. I will work on the docs and example. Thanks for raising an interesting issue. |
Added a laser-focused example for I avoided use of imports, YAML aliases and filenames in order to just clarify this one concept. |
Documentation examples look great, @DannyBen ! I'll likely write up a blog post about my use case once the feature is released and I've tested it with end users. Thanks again! |
Version 0.8.9 is released to both Rubygems and Docker Hub.
Thanks for raising this issue, I hope the solution works well for your use case. |
Description
I have a script I maintain that either predated nested commands, or where I missed the feature when creating it. As such, I used
namespace-
prefixes:Now that I know about nested commands, I'd like to refactor the script to use those. However, because this script is already shipped to end users, I cannot break backwards compatibility.
This is where things get interesting.
Let's say I had this:
If I then add the new command and nested command alongside this:
I then run into an interesting phenomenon: If I call
cli foo-list --help
, I do not get the "DEPRECATED use cli foo list" help message. If I reverse the order, so that the deprecated command comes last in the file, I do, but then I also get it forcli foo list --help
.(Helpfully, these both resolve to the same command script, so nothing changes in terms of actual implementation.)
I understand why this happens. Clearly, internally, bashly is normalizing the names to convert
-
to an underscore, and concatenates command + subcommand using an underscore, so the last definition "wins".What would be great is if we could alias a command or subcommand to another command or subcommand.
This would not work like the current aliasing which allows providing an alternate name, usually a shorter one, for a given command. Instead, it would mean that when an alias is invoked for any reason, it would act exactly like the other command: the help/usage text would come from that command, and it would call its associated command script. The "alias" would be a name and a target only.
Such an approach would mean that my previous commands would continue to work, but users could start adopting the new syntax.
Proposal
In these examples, I'm choosing the term "target" to indicate that the given target will be executed/merged for the given command, and that no command script should be directly associated.
Behavior:
bashly generate
to fail andbashly validate
to raise an error.Example 1: aliasing command to a subcommand
This example aliases the command "bar-list" to the nested command "foo list".
Results:
src/foo_list_command.sh
created.src/bar_list_command.sh
NOT created.cli bar-list --help
would output the same help ascli foo list --help
cli bar-list
would call whatever command script is associated withcli foo list
.In other words, when generating the production script, this could get generated:
Alternately, the generated
parse_requirements()
function could match "bar-list" and set the action to "foo list" and call the "cli_foo_list_parse_requirements" function.Example 2: aliasing command to a subcommand (normalized to same name)
This example aliases the command "foo-list" to the nested command "foo list"; doing so allows users to use "foo-list" and "foo list" interchangeably, and the usage text from "foo list" would be presented to users.
Results:
src/foo_list_command.sh
created.cli foo-list --help
would output the same help ascli foo list --help
cli foo-list
would call whatever command script is associated withcli foo list
.This one is interesting as the normalized names for the usage and command functions would be the same.
However, the point is that the non-aliased version is what would be used (not whichever comes last per current versions).
Example 3: aliasing a subcommand to a command
This example aliases the nested command "foo list" to the command "bar-list"
Results:
src/bar_list_command.sh
created.src/voo_list_command.sh
NOT created.cli foo list --help
would output the same help ascli bar-list --help
cli foo list
would call whatever command script is associated withcli bar-list
.In other words, when generating the production script, this would get generated:
Alternately, the generated
parse_requirements()
function could match "foo list" and set the action to "bar-list" and call the "cli_bar_list_parse_requirements" function.Example 4: aliasing a subcommand to a command (normalized to same name)
Results:
src/foo_list_command.sh
created.cli foo list --help
would output the same help ascli foo-list --help
cli foo list
would call whatever command script is associated withcli foo-list
.Example 5: aliasing a command to another command
Results:
src/foo_list_command.sh
created.src/bar_list_command.sh
NOT created.cli bar-list --help
would output the same help ascli foo-list --help
cli bar-list
would call whatever command script is associated withcli foo-list
.In other words, when generating the production script, this would get generated:
The text was updated successfully, but these errors were encountered: