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

Provide a run command #1088

Closed
sol opened this issue Oct 30, 2012 · 42 comments
Closed

Provide a run command #1088

sol opened this issue Oct 30, 2012 · 42 comments
Assignees

Comments

@sol
Copy link
Member

sol commented Oct 30, 2012

I propose to add a run command to cabal-install, that can be used to build and run executables.

Details

If I have a cabal file with an executable section for foo, then running

$ cabal run foo

should build foo, if necessary, and run it. It should have the same effect as:

$ cabal build && ./dist/build/foo/foo

If I provide additional arguments to cabal run they are just passed though, e.g.

$ cabal run foo arg1 arg2

should have the same effect as:

$ cabal build && ./dist/build/foo/foo arg1 arg2
@sol
Copy link
Member Author

sol commented Oct 30, 2012

Please let me know if this would be accepted. Normally I'd just start hacking, but after the #2 disaster I'd rather not spend any time on that only to get it bikeshedded to death.

@23Skidoo
Copy link
Member

I think it's a good idea. @dcoutts?

@tibbe
Copy link
Member

tibbe commented Oct 30, 2012

I've argued for this feature in the past.

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

I suggest that cabal run takes a --component flag that is mandatory if there are more than one executable, if there's only one, we default to that one. This means that we might want to support an -- argument to separate cabal flags from executable flags, if the executable also has a --component flag.

@23Skidoo
Copy link
Member

@tibbe Why is that better than the original proposal (cabal run [COMPONENT] [ARGS]) ?

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

@23Skidoo That would work as long as the component name is mandatory? How would you otherwise tell it apart from an argument? Perhaps it's better to just have cabal run COMPONENT ARGS... (i.e. make the component mandatory.

@sol
Copy link
Member Author

sol commented Oct 31, 2012

Yes, I would prefer to make the component mandatory.

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

I'm fine with that.

@23Skidoo
Copy link
Member

How would you otherwise tell it apart from an argument?

If there are extra arguments provided, always treat the first one as the component name. If -- will be used to separate Cabal flags from the executable flags, cabal run -- -arg1 -arg2 will also work.

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

If there are extra arguments provided, always treat the first one as the component name.

Would the -- be required even if there's only one executable defined? I fell that in practice -- will always be required as lots of executables (e.g. the executable that's created by Snap web apps) take arguments.

@23Skidoo
Copy link
Member

Would the -- be required even if there's only one executable defined?

I am not even sure we want run to accept any arguments besides the component name and args to forward. In that case, -- won't be needed and we can make run context-sensitive (so that run -arg1 -arg2 works if there is only one executable).

@sol
Copy link
Member Author

sol commented Oct 31, 2012

@23Skidoo Would that mean, that cabal run <name> would not work, if there is only one executable defined?

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

I didn't follow your last comment. Are you saying that we will only forward flag (i.e. -foo) type arguments and the can thereby tell what's the component name because it doesn't start with a -?

@23Skidoo
Copy link
Member

Sorry, I should have explained it better. If the run command won't take any arguments besides the component name and args to forward, that is run :: [String] -> IO (), we can make it context-sensitive depending on whether there are multiple executables defined.

If there is only one executable:

$ cabal run
Runs ./dist/build/exe
$ cabal run arg1 arg2
Runs ./dist/build/exe arg1 arg2

If there is more than one executable:

$ cabal run
Error: no executable name specified
$ cabal run arg1 arg2
Error: no executable 'arg1'
$ cabal run foo
Runs ./dist/build/foo
$ cabal run foo arg1 arg2
Runs ./dist/build/foo arg1 arg2

@23Skidoo
Copy link
Member

On the other hand, if run will take some arguments of its own (e.g. --builddir) - that is, if run will have type RunFlags -> [String] -> IO (), then we will need to somehow distinguish between the two types of arguments. For example, with --.

@sol
Copy link
Member Author

sol commented Oct 31, 2012

Personally I think that if there is an executable foo, then cabal run foo should always work. I really prefer consistency (and simplicity) over saving some key strokes here.

That also spares us from --, it would then just be cabal run [cabal-flags] <name> [args]. You then only need the -- if you have a command that is named like a flag, e.g. --version:

cabal run -- --version

If we want to make it more convenient for the user, we could put our effort into the bash completion script, and let it complete command names.

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

If the run command won't take any arguments besides the component name and args to forward, ..., we can make it context-sensitive depending on whether there are multiple executables defined.

But if the name of the executable is the same as the value of an argument, it becomes ambiguous. We can solve that by disallowing the executable name part if there's only one executable defined, but then the user needs to look up the number of executable to know if she can use the longer cabal run <executable> form. I think simplicity and consistency is more important than brevity here (although one of the goals of cabal run is brevity, so perhaps I'm arguing against myself here).

I think we shouldn't exclude the possibility of then run command itself will take arguments (e.g. --env_var).

@23Skidoo
Copy link
Member

But if the name of the executable is the same as the value of an argument, it becomes ambiguous.

Since this case is likely to be rare, we can require the user to be more explicit here. For example, in the single executable case:

$ cabal run
Runs ./dist/build/foo
$ cabal run foo
Runs ./dist/build/foo
$ cabal run arg1
Runs ./dist/build/foo arg1
$ cabal run foo foo
Runs ./dist/build/foo foo

And if there are multiple executables, specifying the component name will be required.

I think we shouldn't exclude the possibility of then run command itself will take arguments (e.g. --env_var).

Yes, --env-var can be useful on Windows.

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

@23Skidoo Can you formalize the rules for parsing cabal run invocations int his style, including possible flag arguments to build? We could then easier judge of those rules can be easily grasped by a user.

@sol
Copy link
Member Author

sol commented Oct 31, 2012

If we agree that the form cabal run [cabal-flags] <name> [args] should always work, regardless of the number of executables defined in a cabal file. Could we then break this up into two separate stories? E.g.:

  1. Provide a run command
  2. Make run command more permissive, if there is only one executable

@tibbe
Copy link
Member

tibbe commented Oct 31, 2012

@sol Right. (1) is easy to define (as the executable name is mandatory). (2) is what we need to define, with the side condition that nothing in (2) can invalidate anything in (1).

@23Skidoo
Copy link
Member

Can you formalize the rules [...] including possible flag arguments to build

I need to look more closely into how Cabal's option parsing works for that.

@23Skidoo
Copy link
Member

23Skidoo commented Nov 1, 2012

Right now -- is required to separate arguments to run from the executable's arguments (cabal complains about unrecognised options). This can be changed by modifying commandParseArgs in Distribution.Simple.Command, but the executable's arguments whose names clash with run flags will still have to be escaped with --.

No matter how this is implemented, run will accept a RunFlags record and a [String] list with extra arguments. Now, this is the algorithm I had in mind:

runAction runFlags extraArgs = 
    [...]
    if numExes == 1 then
       case extraArgs of
            []                    -> run exeName []
            (x:xs) | x == exeName -> run exeName xs                         
                   | otherwise    -> run exeName extraArgs
    else
       run (head extraArgs) (tail extraArgs)
    [...]

@dcoutts
Copy link
Contributor

dcoutts commented Nov 1, 2012

I've thought about this too. I see two reasonable alternatives:

  1. is to rearrange the dist tree to make it much more convenient to run programs inplace. That also might include wrapper scripts to set the env vars so that programs can find their datafiles locally etc.
  2. is a run command that would do the appropriate thing.

In relation to the issue of making the exe name mandatory or not, I don't have a strong opinion. I should note that it'd be good if we can make the ui here similar to what we're planning for cabal build which is cabal build [targets] where an individual target can be a component name, module name or file name, or in the case of ambiguity, qualified by component name or even component type (for when a lib and exe have the same name).

@tibbe
Copy link
Member

tibbe commented Nov 1, 2012

As a side note: cabal run should imply cabal build, just like e.g. cabal test does.

@tibbe
Copy link
Member

tibbe commented Nov 1, 2012

@23Skidoo How will the change to commandParseArgs affect other commands? We don't then to stop reporting invalid flag names. Could we have a commandParseSomeArgs that is used for commands that pass remaining args on to some other binary?

If we don't change commandParseArgs, are we willing to live with e.g. running a Snap app using:

cabal run -- -p 8080

instead of

cabal run -p 8080

? I think so.

@23Skidoo
Copy link
Member

23Skidoo commented Nov 1, 2012

How will the change to commandParseArgs affect other commands?

I think that it can be implemented similarly to hiddenCommand, so other commands won't be affected.

@tibbe
Copy link
Member

tibbe commented Nov 1, 2012

Before I forget, we also need cabal run to set the data-dir correctly when running the executable.

@tibbe
Copy link
Member

tibbe commented Nov 1, 2012

Is anyone against settling on the conceptually simple (i.e. no changes to commandParseArgs) versions:

cabal run -- -p 8080

? I think the need to not change how command parsing works somehow shows that this version will also be more intuitive for users.

@23Skidoo
Copy link
Member

23Skidoo commented Nov 1, 2012

I like the ability to omit --, but I also agree that making -- obligatory is probably more intuitive.

@tibbe
Copy link
Member

tibbe commented Nov 2, 2012

We could go with a mandatory -- at first and eventually let users skip it without breaking any old commands/scripts users might have saved.

@sol
Copy link
Member Author

sol commented Nov 2, 2012

I didn't really follow the discussion. So just to be sure, would that only affect situations where the user omits the component name? Say would

cabal run <myapp> -p 8080

still work?

@23Skidoo
Copy link
Member

23Skidoo commented Nov 2, 2012

@sol No, it will complain about the unrecognised option -p. cabal run foo 8080 will work, though.

@23Skidoo
Copy link
Member

23Skidoo commented Nov 4, 2012

I hacked together an initial implementation of run (see the branch cabal-run in my repo). Please give it a try!

23Skidoo added a commit to 23Skidoo/cabal that referenced this issue Nov 5, 2012
@23Skidoo
Copy link
Member

Do we want to make -- optional? If not, is there something else to do here?

@sol
Copy link
Member Author

sol commented Nov 10, 2012

Personally, I think it would be nice.

@ghost ghost assigned 23Skidoo Nov 10, 2012
@tibbe
Copy link
Member

tibbe commented Nov 10, 2012

I'm not sure whether we want to make -- optional. I guess it's standard unix practice to only force its use when something is ambiguous? I don't feel strongly about it so go ahead and implement it if you want to. Otherwise I'm find with closing this bug.

@sol
Copy link
Member Author

sol commented Nov 10, 2012

Hm, not sure. If you explicitly mention the component as in

cabal run <myapp> -p 8080

I think it's odd if you have to type -- for no obvious reason. I'd be fine with deferring it for now. But leaving it like that?

@23Skidoo
Copy link
Member

Well, you'll still have to type -- if you want cabal run foo --help to run foo --help (though I think it can be made to work with a modified GetOpt.hs).

@sol
Copy link
Member Author

sol commented Nov 10, 2012

You don't, if you define the syntax to be:

cabal run [cabal-flags] <name> [args]

@23Skidoo
Copy link
Member

@sol You can't make this syntax work without modifying Distribution.GetOpt.

@23Skidoo
Copy link
Member

Closing this ticket since cabal run is now in mainline. Opened #1119 as a reminder about the -- issue.

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

No branches or pull requests

4 participants