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

cabal exec may silently run previous version of project executable. #57

Open
kindaro opened this issue Jan 29, 2021 · 11 comments
Open

cabal exec may silently run previous version of project executable. #57

kindaro opened this issue Jan 29, 2021 · 11 comments
Labels

Comments

@kindaro
Copy link

kindaro commented Jan 29, 2021

So, there are two ways to run an executable X in a project:

  • cabal run X
  • cabal exec X

There are a few differences:

  1. run checks for changes in the source, resolves dependency versions and so on, while exec does nothing of that.
  2. Consequently, run emits strings to standard output or standard error, so the output is not suitable for piping into other programs.

In a real case, I have a program X that generates a script in another language. This script is then being fed to the interpreter Y of that language. So, I have to use exec, and the command line looks as cabal exec X | Y. So far so good, but then I ship an update and the previous version is being used instead, because re-build is not forced, and no one even notices this because there are no warnings.

A simple solution would be to emit a warning (or even an error) when the project is not freshly re-built when running cabal exec. A more advanced solution may be to intelligently study the executable to run, see if it is located in the project, and in that case check if it needs to be re-built and inform the operator.

@tomjaguarpaw
Copy link
Owner

Hadrian, the GHC build tool, also suffered from this. I asked (probably on #haskell) why cabal exec does not rebuild and I was told that it is intended to be used by build tools, not by end users. (Unfortunately I can't find links to either of these things.)

Do you think cabal run should have a flag that silences it, assuming the build completes successfully?

@kindaro
Copy link
Author

kindaro commented Jan 29, 2021

Thanks Tom. I think this is a dismissal and not an answer, and unfortunately I find it to be exemplary of the general attitude of the developers of Cabal.

I think Cabal should have a coherent user experience model from which such decisions may be derived, and also that there should be an open and persistent channel of communication that allows such a model to be iteratively improved on based on actual reports of user experience issues. In the case here, cabal is a tool primarily for humans to use, and it being also optimized for machines to use is incoherent.

It is already not feasible to remember the variety of flags one may give to Cabal — before more flags are added, a way to discover them should be provided that is commensurate with the human cognitive ability. It is one thing to have flags for different compiler optimizations — you know where to look for when you need them and they make no difference up to performance. Adding corner cases to patch corner cases is another thing — a bad thing that we should not ask for.

Also, I think possibilities for things to go wrong should be eliminated and not merely provided a way to work around of. It puzzles me to no end that, with all the ethos of «making invalid states irrepresentable», we close our eyes to the myriad of invalid states that are very much representable when it comes to human interaction with the prime Haskell build tool. This is not a singular case — there is a whole class of bugs waiting to be eliminated by construction.

It would be strategically unwise to push for a small fix, because it being accepted would uphold the limbo of things being bad but not bad enough to bother fixing the problem at the root.

@kindaro
Copy link
Author

kindaro commented Jan 29, 2021

Actually I do not buy the argument to optimization for machines to use. Why would a machine want to run a random version of an executable? It does not even exist as far as Cabal can see. I checked in another version control branch — end of story. Interference between different versions of a repository is forbidden in the version control paradigm. Human or machine — what difference does it make in this case?

@fgaz
Copy link

fgaz commented Mar 1, 2021

Actually I do not buy the argument to optimization for machines to use. Why would a machine want to run a random version of an executable?

Well, there is a reason. From the --help:

During development it is often useful to run build tasks and perform one-off
program executions to experiment with the behavior of build tools. It is
convenient to run these tools in the same way cabal itself would. The cabal exec command provides a way to do so.

Compiler tools will be configured to see the same subset of the store that
builds would see. The PATH is modified to make all executables in the
dependency tree available (provided they have been built already). Commands
are also rewritten in the way cabal itself would. For example, cabal exec ghc will consult the configuration to choose an appropriate version of ghc
and to include any ghc-specific flags requested.

So maybe you want to debug some build failure, or run ghc directly on your project's files, or run some tool that does not know about cabal. Especially in the first case, having cabal also do stuff, could interfere with your command, or possibly could prevent it from running altogether.

By the way, since you do not need the build environment but only the executable, another option is cabal build myexe && $(cabal list-bin myexe) [...]. I think it's clearer from the name that list-bin does not do any rebuilding

@kindaro
Copy link
Author

kindaro commented Mar 1, 2021

Thanks Francesco.

I do not think it follows from your argument that running a random version of an executable is a desirable feature. It does follow from your argument that it may be desirable to inspect the world through its eyes. The missing link is the assumption that Cabal itself needs to see a random version of an executable. I doubt that it does. Actually what I suggest is that it should not see any executables belonging to a project until it made sure all build artifacts are up to date. Being able to see these executables is an instance of being able to see an invalid state, so the general argument against invalid states applies.

So maybe you want to debug some build failure, or run ghc directly on your project's files, or run some tool that does not know about cabal.

  • Why would I want to run a random version of an executable belonging to the project in any of these cases?
    • Is the support of these rare cases worth having an invalid state every time the working tree is not pristine?

So, perhaps a special command like cabal shell should be provided that allows one to see the world through the eyes of Cabal. But care should be taken to make sure it cannot run a random version of an executable. I am not advocating that we should remove good and useful things — only that we should make them safe.

@fgaz
Copy link

fgaz commented Mar 1, 2021

I see where you're coming from. My point is that running executables, especially ones that are not build tools is more of an incidental feature of exec. It was inherited from v1-exec, before list-bin was a thing. Not exposing outdated executables is a cool idea. I wonder if anyone relies on the exe always being there, outdated or not.

So, perhaps a special command like cabal shell should be provided that allows one to see the world through the eyes of Cabal

That's cabal exec $SHELL :D (edit: this is a hack, please don't do this unless you know the consequences)

Also, relevant cabal issue: haskell/cabal#7106

@kindaro
Copy link
Author

kindaro commented Mar 1, 2021

I do not find this as hilarious as you do.

That's cabal exec $SHELL :D

To me that's an example of user experience that is not thought through.

Incidentally this works. But is it officially supported? What exactly does it do behind the scenes? What are the guarantees? For example, is running ghci on project files from inside this shell guaranteed to work? Does any significant share of user base know of and use this feature?

This could be an awesome feature, but instead it is delegated to a special case of a special case.

  • We are told that cabal exec is for machines, or for obscure debugging purposes. For all I know, I should not even touch that thing.
  • Running shell in such places feels more like a shell exploit than a legitimate feature. I mean, there are many places out there where I can get a shell, but we all understand that doing this without invitation may void the warranty.

In the case of Cabal, given my history of unsuccessful attempts at communication with the core developers, it is not reasonable for me to expect that, should I have any issues with the shell thus spawned, anyone on the team would take me seriously — I expect the issue to be immediately dismissed.

A cool and safe top level feature should be provided instead of this hack.

@fgaz
Copy link

fgaz commented Mar 1, 2021

That was a half-joke. cabal exec $SHELL is indeed a hack abusing the exec functionality and does have some differences from direct exec commands. One I can think of is that program names will not be rewritten (eg. ghc -> ghc-x.y.z) in the shell. write-ghc-environment-files=always would be a more appropriate way of getting the most useful part of a "cabal shell" functionality.

But this is off topic anyway.

@kindaro
Copy link
Author

kindaro commented Mar 1, 2021

So what did we establish?

  1. It seems we agree that cabal exec is unsafe in the sense of running a random version of an executable belonging to the project.
    • Do we consequently agree that list-bin is unsafe as well?
  2. It turns out that cabal exec is also unsafe in the sense that some executables not belonging to the project are not supported, particularly shells. (What others?)
  3. Tentatively it seems that we might like the feature cabal shell instead that does what it says on the box, and then cabal exec can be removed.

Please correct whatever does not faithfully represent your view.

@fgaz
Copy link

fgaz commented Jun 3, 2021

Oops, I forgot about this

It seems we agree that cabal exec is unsafe in the sense of running a random version of an executable belonging to the project.

Yes, and the same goes for list-bin

I think the proper solution to the original issue would be to have an better verbosity control for run. I now see that I didn't mention this before: does -v0 suffice?
Having an option in list-bin to rebuild or to not list outdated executables could also be an option

It turns out that cabal exec is also unsafe in the sense that some executables not belonging to the project are not supported, particularly shells. (What others?)

It's not that running shells is unsupported: it works the same with them as with other stuff. It's just that one has to be aware of what that command is doing before building a workflow around that

Tentatively it seems that we might like the feature cabal shell instead that does what it says on the box, and then cabal exec can be removed.

I feel like exec will always be needed by some. If you feel like cabal shell could be a nice addition, please open a ticket in the cabal tracker and we'll see if there's interest for that

@kindaro
Copy link
Author

kindaro commented Jun 3, 2021

cabal run -v0 works alright, problem solved, thanks!

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

No branches or pull requests

3 participants