-
Notifications
You must be signed in to change notification settings - Fork 723
cabal-install: do not pass the executable name to cabal external commands #11232
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
base: master
Are you sure you want to change the base?
Conversation
47ea2c6 to
50e1bfa
Compare
geekosaur
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's an issue here which hasn't been brought up yet, which is one of the reasons the program name is passed as the first parameter.
See the caveat on getProgName. On Windows in particular, there is no way to retrieve argv[0], so anything relying on it will have issues.
This also plays into a potential future change where invocation via cabal would be marked. (Likely by something like how login on Unix marks login shells: leading '-'.) The reason we would want this is the potential for future versions of the external command mechanism to receive bits of project or cabal state via the environment. (We already pass $CABAL / %CABAL%, but tooling should already use that to ensure they are running the right cabal.) External commands would need some "key" indicating that the additional information is available. We don't do this yet because we're waiting for feedback from users of the external command mechanism about what information they would need from cabal.
All of which means I'm not sure we can get away with not passing the name. At minimum, we might need to replace it with a --run-from-cabal parameter or other mechanism to indicate that additional information is available, and potentially parameterized by the actual run name to work around getProgName issues on non-POSIX (which would put us right back where we are now).
|
There are two possible workarounds listed, the other one (just using multiple executables) even aligns very nicely with how Haskell projects are usually structured and doesn't incur a lot of overhead. Does that one not work on windows either? On the topic of getting more information: if you're setting an environment variable anyway, then why is it not possible to just check for the presence of that variable? |
|
If two tools share most of their implementation, multiple driver programs are possible but may lead to complex library entry points. This is why Unix likes to use (sym)links in that case, but that doesn't fly on Windows and probably other OSes that aren't Unix-like (there's ongoing work to port ghc and build tools to Haiku, for example). |
|
You haven't updated the external command tests (PackageTests/ExternalCommandExitCode/cabal.test.hs, PackageTests/ExternalCommand/cabal.test.hs, PackageTests/ExternalCommandHelp/cabal.test.hs). |
I didn't see it failing locally, must've slipped through the one million lines of output
That's why I said in Haskell, it is super common to make the executable just a shim that invokes the library. In my opinion we don't have too look too closely what other people are doing there because they have other backgrounds. The default case is that it's very simple to add new executables to Haskell projects and even if that's not a case, for that hypothetical project (I know of none that has this problem) it's not a hurdle that big that should force other users to take the hurdles that they have to take now. (Or making anything impossible)
Yes, I propose not setting that variable and instead use a longer, more rarely used one like $CABAL_EXTERNAL_COMMAND_CONTEXT which at the same time would be good to avoid executables that currently long for $CABAL to break. |
We still need to set it, because if a user runs a different |
I doubt it's ever wise to use |
|
That may tie your program to a specific version. In the opposite direction, this is why I think we'll be exporting more information in the future. Also, future versions of cabal will have more stable interfaces for this, whose design will come from this and other users (e.g. HLS); we already have a ticket and some early design work for a proposed |
|
Do I understand this incorrectly though: I think this is orthogonal to the issue at hand - the additional argument wouldn't carry any information about the status of cabal, it would be the environment variable. |
|
If the additional parameter were to stay, it would be the same as the |
|
Some care is needed with the environment, though; it's already pretty sizable on some systems, and there is a limit on |
Which is something under mine control as a developer, so it's good. While with |
I feel like you're severily misunderstanding the docs here. Here's what it looks like: |
50e1bfa to
2fbabfe
Compare
It still leaves out cabal-specific changes to it to indicate that it has been run from cabal and extra information may be available (#11232 (review)); it only provides the executable name that was run. |
Yes. This is a completely orthogonal issue though to whether cabal copies the command name in argv[1] or not. This PR isn't about making the perfect cabal external commands system, it's about changing that one specific aspect. |
2fbabfe to
cdd2f7a
Compare
|
Thank you for submitting the patch @MangoIV! I agree with your arguments and I wasn't able to discern serious counter-arguments from the discussion above. So I'm in support of the change. Why is it a draft? |
There's two missing checkboxes that I haven't gone through yet (I want to adjust missing docs) |
|
You still also have a typo in your changelog entry and two tests that still need to be fixed (I saw only one fixed in the last push). |
|
yeah that's also why it's still draft, sorry. I will of course go through this. :) |
|
No worries, I was just making sure it's not an oversight. |
|
As per request of @mpickering I have announced this change on discourse in order for users to be able to chime in if they expect breakage. |
cdd2f7a to
9280ae0
Compare
|
I would like to note that |
041ad3a to
017a12e
Compare
Previously the executable name of the external command was passed to external commands as the first argument. This behaviour was adapated from cargo which does this because of reasons that are internal to rust that do not affect GHC Haskell, and are even orthogonal to patterns that see common use in Haskell. Additionally, it complicates the 'simple' case which is what we should optimize for when building such a feature. The previous use case (one executable that serves multiple external subcommands) is still possible by the following means: - using a wrapper around the executable - using a symlink and check argv[0] in the executable Additionally, the variable `$CABAL` that was set by `cabal-install` was renamed to `CABAL_EXTERNAL_CABAL_PATH`. This has two reasons: 1. it makes migration easier for users of the external command feature that were previously expecting the name of the executable to appear in `argv[1]` 2. it does not unnecessarily pollute the environment variable namespace as it turns out some other tools have been and are already using this name, historically Resolves haskell#10275
✅ Branch has been successfully rebased |
fb6aa24 to
d8ac2bf
Compare
|
given the extensive discussion, it doesn't look like we're reaching consensus in time before 3.16.1.0 release. @geekosaur can I ask you to state your proposal for a deprecation strategy? With as much details as possible, since I wasn't quite able to follow before and it seems I'm not the only one. @Mikolaj I think the answer about the change in the variable name is reasonable: as I understand it, this change allows tools to handle both old cabals (before th change in the argument passing) and new ones (after the change). |
|
That's the idea, yes. Unfortunately, I've realized there's a kink that makes my plan unworkable: since ghc 9.14 is intended to be an LTS release, we'll want cabal 3.16 to be an LTS release as well — but that means we'll be stuck with using For the record, my plan had been:
(This could have been implemented as changing it for #1 in this PR, then a second PR that wouldn't be backported on Unless someone thinks changing it in a minor LTS release after 6 months or something is viable, that means I have to concede and hope it doesn't trip anyone up. I still don't like it much, but we're running pretty short on alternatives. |
|
Maybe I am misunderstanding but I think this can’t work. If an old binary is looking for $CABAL, it mustn’t be set because otherwise the binary would assume old behaviour. Since the new behaviour is a no op for old binaries that only serve a single executable name, not setting $CABAL it is strictly better than setting both. |
|
The inherent problem is that cabal-install cannot detect (without horrible, horrible hacks, yes it could work but i wouldn’t even consider it an option) which behaviour the callee expects - that is the source of problems for a good migration path. |
|
The problem you're flatly ignoring is the possibility that someone is currently relying on the current behavior. |
Im not sure what gives you the impression I’m ignoring it. If i did this wouldn’t even be a breaking change. The only situation where this could be problematic is if someone would actually be detecting the exe name via argv[1] (and not just use it as a marker that it was called from cabal-install) in which case
|
|
I'm not, and have never been, debating that part: apps already have to deal with that if they're run standalone instead of via cabal. Just the environment variable change. |
|
Also I suspect they'll need to deal with it for a couple years even after this goes in, because we have no control over Linux distributions that package cabal, nor over the many users who insist on only using things packaged by their distro. |
Mind that the really important bits are that the first two rows work across the board, the rest are just corner cases, which are broken but
|
|
@sol as one of the early adopters of the external-commands interface, do you have an opinion about this change and a deprecation strategy? |
|
@ulysses4ever thanks for looping me in. My main issue here is that this PR does not state a clear motivation for this change. So I am left guessing. @MangoIV is it so that you can run e.g. It dazzles me why I would put so much discussion into a proposed breaking change without stating a convincing user benefit. |
|
This doesn't benefit users at all; it benefits authors of external tools intended to work with cabal's external command interface, who won't need to deal with a weird requirement of the original version that was taken from |
If this change means that I as a tool author have to replace lookupEnv "CABAL" >>= \ case
Nothing -> run "cabal" args
Just cabal -> run cabal (drop 1 args)with lookupEnv "CABAL_EXTERNAL_CABAL_PATH" >>= \ case
Just cabal -> run cabal args
Nothing -> lookupEnv "CABAL" >>= \ case
Just cabal -> run cabal (drop 1 args)
Nothing -> run "cabal" argsthen I don't see how I as a tool author benefit from this change. If there is anything else to it, then again, I think this PR lacks proper motivation. |
|
The problem with |
|
(In fact, I thought that would have been clear from the discussion earlier in this PR, because that's central to why I'm worried about backward compatibility issues.) |
|
@sol the motivation is to remove the currently complicated "simple" case. As you have already showcased, a tool must currently look up the variable and then drop the first argument. With this change, this is not required anymore. Any tool that provides only one subcommand per executable will work without further changes, as is the case with e.g. More information can be found in the commit message, in the discourse announcement or the original issue. |
Mikolaj
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it makes sense to provide rationale in the issue ticket that a PR ticket implements and indeed the issue ticket mentioned in the description, and the ticket it links to, do provide it IMHO. Thank you again for the PR, the discussion and for the table detailing the compatibility situation. It's now clear to me why this PR changes the variable name and why no more backward compatibility measures are attempted.
|
@MangoIV: please kindly set the merge label. This still gives us two days to propose amendments to this PR. @sol: would you have any advice on how to make this PR better? @geekosaur: from you PR approval I take it you are fine (if not completely happy) to merge this PR as is? Even for release 3.16.1.0? |
|
I'm kinda treating 3.16.1.0 as what 3.16.0.0 should have been. (I still think that should have been treated as a prerelease.) I'm still worried about removing |
|
I don’t wanna be too snarky but I wonder where the caution was when the original behaviour was approved with no possibility of migration to a different behaviour without creating a breaking change like this. I don’t want anyone to „give in“. If the maintainers think this is not workable and they want to keep the behaviour because major tools cannot create breaking changes like this, then so be it. It is hard for me to navigate this situation. It feels like the narrative is a bit like „let him do the change and let him see how it’ll blow up in their face“, and I am not here for that. I want to make an improvement to the actual user experience. If this change does not satisfy this expectation, or the costs are considered too high, I can very well accept a rejection of the change. Mind though since there is no and will not be a proper way for deprecation and migration, that the longer this behaviour stays as is, the bigger the problems with a future change will be. |
|
What exactly would you have recommended as an alternative? There aren't many useful possibilities, and use of environment variables can't reasonably be tracked. |
|
Also, "I don’t wanna be too snarky but I wonder where the caution was when the original behavior was approved" is exactly snarky, and honestly not thinking. A new feature was added, a mistake was made in its design, "caution" here would have meant "time travel to the future to see the outcome". |
yes, this was inadequate. My point is that when a feature is added that will be cemented with no migration path forever, an attempt to fix it is easily rejected because the cost is high, but the cost is not caused by the fix but by the addition of the feature. |
There are unresolved comments by @ulysses4ever above, so Mergify will not pick it up. On a meta level this PR highlights why people are reluctant to contribute to Cabal: the procedure is vague, protracted and hindered by obscure Mergify bureaucracy. It's clear that @MangoIV struggles to navigate it, and anyone else will too. Could the Cabal team possibly reflect on this at their next meeting and extend (To be clear: I'm not suggesting that the Cabal team has to apply more or less scrutiny when reviewing PRs, I'd just prefer their desired level of scrutiny to be written down somewhere) |
|
Fwiw I was going to apply the suggested fixes by @ulysses4ever tomorrow, sorry for not acting on them sooner. |
Previously the executable name of the external command was passed to external commands as the first argument.
This behaviour was adapated from cargo which does this because of reasons that are internal to rust that do not affect GHC Haskell, and are even orthogonal to patterns that see common use in Haskell.
Additionally, it complicates the 'simple' case which is what we should optimize for when building such a feature.
The previous use case (one executable that serves multiple external subcommands) is still possible by the following means:
Survey of tools that can be affected by this change: #11232 (comment)
Include the following checklist in your PR:
significance: significantin the changelog file.