I have a suggestion for a new command: shards run [target] [args]. This would be the same as executing shards build [target] and then running the compiled file with the arguments specified, just shortened to one command. This can be useful for quickly testing out new changes, without needing to run two commands. In fact, crystal already has a run command, so maybe use that instead of outputting the file?
shards run would be great. Rust has something similar and it helps a lot when you only have to use one command instead of multiple for quick changes.
There may be many targets configured to build. Which one should a run command execute? Do binaries depend on each other? So, shall we build all targets, then run a single one?
Build is a minimalistic tool, and meant to stay this way; I don't want to add any more configuration. I'm not sure we can achieve anything proper for most scenarios without adding configuration.
If there's more than one target, you must specify shards run target. No dependencies between targets. That's a simple zero-config way to do this.
So shards run [target] where target can be omitted if only one is configured (no ambiguity) and prints a helpful error message otherwise. That sounds acceptable. Not really my workflow, but I understand it can be.
If someone wants to take a stab at this, with a integration tests, updated man pages, please do.
@ysbaddaden this is really helpful and benefits some web projects that happen to need to run scripts on remote servers with limited access and permission.
Well, I'd deploy pre-built binaries, not the source code, avoiding to install crystal/shards on production servers.
Has there been any progress on this? I'd also like to see this command implemented (it makes it much more sane to run Rust projects, from my experience).
I don't think so. But it should be rather easy to implement. If you're willing to take a stab at this, go ahead :+1:
Is this being worked on? If not, I'd like to take a stab at it.
Initial implementation here: https://github.com/denolfe/shards/commits/run-command. Any feedback is welcome.
I wrapped the build command because there needed to be some additional logic for checking for a number of targets then handling appropriately. It didn't make sense to me to shove that into cli.cr. Tests to be added, pending feedback on implementation.
Great! Please open a draft pull request so we can talk about this implementation.
PR opened in #298.
One thing that was not discussed at length: Should we allow some sort of default target name that will attempt to be run when shards run is executed without a target name? The discussions above indicate that shards run should actually error out if more than 1 target is specified in shard.yml (this functionality is in the PR). Is this still desired?
Yes. No default, unless there is only 1 target.
I'm not sure whether the default behaviour is a good idea. shards build defaults to building all. shards run defaults to running one, but only if there is one defined seems off.
Maybe it should just print a list of available targets?
I'm fine with it erroring out or printing the list of targets if there are multiple targets, though my preferred behavior would be to run the first target that is listed in shards.yml. I think that would just be a much less annoying behavior. Refusing to run any targets, when we have an ordered list of targets, is just being annoying and pedantic. We could simply include a note in the shards.yml documentation that the first target listed is the one that runs by default.
So to re-iterate, I'd like to base the default off the ordering of targets in shards.yml unless user specifies a particular target to run
Also to illustrate the need for this, right now my workaround is doing crystal run src/* which is just bad for a number of reasons.
Always running the first target if no name specified sounds good. That's consistent behaviour.
The onky consistent behavior is always asking a target, even when only one is present. But that would be annoying because we can easily infer the target when there is only one. An ordered list of targets has no meaning (its just a bunch of targets).
Let's go with erroring and see how it goes.
When specifying targets, I usually put the main one up front. When I want to execute a target, it's most often this one because it's the most important.
The thing with consistency is: When a Share has only one target, shards run works just fine. Assuming another target is added for some kind of auxiliary app, shards run breaks. But this change is unavoidable (unless you drop the second target). When always running the first target, shards run keeps working even with a second target. You only need to append it after the previous one, but that's totally in control of the author.
An alternative would be to add property to specify the main target. But that adds additional complexity when target order is sufficient.
As I said: the only consistent behavior is to always require the target. Shards isn't a build tool after all, it only provides a basic build command and now a run command with no configuration, except for entry points.
I would say that shards is in fact a build tool. We have a shards build command, and lots of shards have complex makefiles that get triggered by our hooks system.
I also don't think we need to be conservative here. It's not like we are releasing a breaking change to an existing shards run syntax. There is no shards run syntax. I say default to first target, but always print "running first target (target name)", and allow overriding this with shards run --target [target].
Oh and to be silly, we could of course run _all_ targets 馃槣
I lean more and more on always specifying the target to run: consistent, no configuration, no documentation, no repeated boring message (that boils down to: you should always specify the target), no surprises (you know what will happen).
Targets can be ordered for whatever reasons. Personal preference, alphabetical, to follow a specific build order, where the main target is the last one. Always building the first target is just a habit from make, it ain't that terrible because make has build dependencies (each target depends on others).
Shards isn't a build tool, and will never support such features. They're out of scope, and Shards already can't even do what's in scope properly (resolve and install libraries).
If typing shards run complicated_target_name_i_can_never_get_right is boring (I agree), I encourage you to create a Makefile, so you can just type make instead.
I would concede and say OK let's default to the only target when there is only one, and otherwise error unless a target is specified via args. That seems to be the compromise both sides of this are willing to make.
That said, I really don't get what the fear is here. What is the bad side effect we are afraid of causing? Someone has 3 targets, and the "main" one isn't listed first? Not exactly a tragedy.
Running the first target is a perfect example of convention over configuration, and will give users an easier time in general. It might be a convention from Make, but it's a widely recognized convention, and a logical one (i.e. the important thing goes first). If I was doing a code review, and someone listed an ancillary target first, I would probably provide feedback that they should list the primary target first to better follow the principle of least surprise.
As far as shards not being a build tool, I really don't see how that is true or why that is something to be afraid of. Shards is perfectly analogous to cargo in the Rust community, and no one is going to argue that cargo isn't a build tool. If I run it, and makefile stuff can start happening in the background, then it's a build tool. That doesn't mean we need to scope-creep tons of new features in, but we should at least be honest with ourselves and try to match the most basic convenience features of similar tools in similar ecosystems. For me, all we are missing really is shards run. Other than that, it's basically perfect as far as I'm concerned.
build and run commands have IMO visibly different semantics - having 1 target seems clear and it's obvious what happens when you run shards build, OTOH running shards run without an argument is pretty confusing - what actually does it do? does it run just one command, if so - which one - ah, the only one - but is it consistent between the projects? nope. shards run would be very much project dependent, unlike for instance rake or npm which by default will run only test task (if found).
@Sija npm does that because in the nodejs world, node . will typically actually work, whereas there isn't a good equivalent with crystal. Yes we have crystal run but it (unlike node / npm) ignores shards.yml. In the node case, it will actually look at package.json to figure out what file to run. You could say that behavior is very broken, and a better behavior would be that npm will run the entry file by default.
I'll be honest, I think of a shard as either an app or a library. If it's an app, it makes sense to run it, and I shouldn't have to know intimate things about the app to know how to run it. I should be able to just shards run and magic happens. Why kill that magic for this weird feeling of consistency, when the people complaining have implied they wouldn't even really use shards run and would rather roll their own Makefile?
Right now every single shard I author that is an app has a run.sh file. That's so messy and bad. Shards should be handling this for me.
#!/bin/bash
shards build || exit 1
./bin/my_app
And then I have to worry about making that bash script portable, which when windows support drops will be impossible, and which is already a pain with MacOS leaning towards zsh and everyone else sticking with bash.
shards run provides a 100% portable way to run a shard for someone who knows nothing about the shard other than the fact that they want to run it.
Most helpful comment
So
shards run [target]wheretargetcan be omitted if only one is configured (no ambiguity) and prints a helpful error message otherwise. That sounds acceptable. Not really my workflow, but I understand it can be.If someone wants to take a stab at this, with a integration tests, updated man pages, please do.