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 repl: Change in PATH environment variable not reflected #2015

Open
arj opened this issue Jul 25, 2014 · 26 comments · May be fixed by #10817
Open

cabal repl: Change in PATH environment variable not reflected #2015

arj opened this issue Jul 25, 2014 · 26 comments · May be fixed by #10817
Labels
Cabal: cmd/repl cabal-install: cmd/repl can-workaround There is a (maybe partial) workaround for the issue or missing feature type: bug

Comments

@arj
Copy link

arj commented Jul 25, 2014

Description

A change in the PATH environment variable is not visible in cabal repl.

Versions

Confirmed in versions:

  • Linux,
    cabal-install version 1.20.0.3,
    using version 1.20.0.1 of the Cabal library,
    ghc 7.6.3,
  • OS X 10.9,
    cabal-install version 1.18.0.5,
    ghc 7.8.3

Steps to reproduce

$ echo $PATH
/home/jakobro/.opam/4.01.0/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
$ export PATH=$PATH:/tmp
$ cabal repl
Prelude> :m Control.Monad System.Environment
Prelude Control.Monad System.Environment> liftM (lookup "PATH") getEnvironment 
Just "/home/jakobro/.opam/4.01.0/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"

The environment when accessed from cabal repl-based ghci does not reflect the change in the PATH variable.

It does work with newly created environment variables, though.

GHCI

In pure GHCI everything works fine:

$ echo $PATH
/home/jakobro/.opam/4.01.0/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/tmp
$ ghci
GHCi, version 7.6.3: http://www.haskell.org/ghc/  :? for help
Loading package ghc-prim ... linking ... done.
Loading package integer-gmp ... linking ... done.
Loading package base ... linking ... done.
Prelude> :m System.Environment Control.Monad
Prelude System.Environment Control.Monad> liftM (lookup "PATH") getEnvironment 
Just "/home/jakobro/.opam/4.01.0/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/home/jakobro/.cabal/bin:/home/jakobro/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/tmp"
@23Skidoo
Copy link
Member

Does this work in ghci for you?

@arj
Copy link
Author

arj commented Jul 25, 2014

Yes, it works within ghci. (see changes in first post)

@23Skidoo 23Skidoo added the repl label Aug 2, 2014
@ttuegel ttuegel added this to the cabal-install-1.24 milestone Apr 24, 2015
@23Skidoo 23Skidoo modified the milestones: cabal-install 1.24, cabal-install 1.26 Feb 21, 2016
@expipiplus1
Copy link

A simple workaround is to run cabal configure again.

@ezyang
Copy link
Contributor

ezyang commented Aug 16, 2016

I can repro by calling repl directly on Setup script, so it must be a Cabal library bug.

@ndmitchell
Copy link

This seems a more general issue that seemingly running cabal configure captures the $PATH and reuses it for subsequent steps. That's causing lots of surprise, e.g. https://gitlab.com/tim-m89/clr-haskell/issues/21

@nh2
Copy link
Member

nh2 commented May 18, 2017

I just lost an hour trying to figure out why the getEnv "PATH" in my ghci is different than from the shell.

@AlexeyRaga
Copy link

AlexeyRaga commented Apr 17, 2020

Looks like I am hitting the same issue with cabal 3.0.0.0.
I tried cabal configure workaround but it doesn't work.

Any other workarounds?

@phadej
Copy link
Collaborator

phadej commented Apr 17, 2020

rm -rf dist-newstyle
...

@jneira jneira added can-workaround There is a (maybe partial) workaround for the issue or missing feature and removed old-milestone: cabal-install 2.0 labels Jul 10, 2022
@jneira
Copy link
Member

jneira commented Jul 10, 2022

... or cabal clean 😉
This continue being reproduced with v2 build (well no one has fixed it, but just in case)

This seems a more general issue that seemingly running cabal configure captures the $PATH and reuses it for subsequent steps.

I am not able to reproduce with cabal run or exec, only with cabal repl, so it may be a bug related with

@Profpatsch
Copy link

Wow. Wow.

@LightAndLight
Copy link

I ran into this issue today. I'm curious why this behaviour is even possible. Like, it's probably the consequence of a well-meaning feature. Anyone know?

@stephenjudkins
Copy link

This was a pretty surprising bug that led me down a debugging rabbit hole. I'd love to see this fixed some day.

@ulysses4ever
Copy link
Collaborator

I just tried the reproducer in OP, and it works fine with cabal-head. @stephenjudkins which version are you using? Could you try with cabal-head?

@phadej
Copy link
Collaborator

phadej commented Jan 8, 2025

This does happen with cabal-install-3.14.1.1 still.

Try in a package

% cabal repl
>>> import System.Environment
>>> lookupEnv "PATH"
>>> :q

% export PATH=/foo:$PATH
% cabal repl
>>> import System.Environment
>>> lookupEnv "PATH"
>>> :q

The issue AFAIK is that cabal remembers PATH, and doesn't check it every time to reconfigure. You may also notice that install-dir or a like is prepended to PATH visible in cabal repl, it's /cabal/bin on my system:

*Network.URI> :m System.Environment
Prelude System.Environment> lookupEnv "PATH"
Just "/cabal/bin:/home/phadej/.nix-profile/bin:....:/snap/bin:/snap/bin"
Prelude System.Environment> 
Leaving GHCi.
[polinukli] /codetmp/network-uri-2.6.4.2 % echo $PATH
/foo:/home/phadej/.nix-profile/bin:...:/snap/bin:/snap/bin

There are duplicate issues, e.g. #6497

@ulysses4ever
Copy link
Collaborator

Thank you, I can reproduce it with your example. Do you know where in dist-newstyle the PATH value is stored? I can't find it with grep. The first suspect, plan.json, has something called path (inside pkg-src), but it doesn't resemble my $PATH in any way. It's probably the path to the source directory, which is unrelated to $PATH.

❯ jq . < dist-newstyle/cache/plan.json
{
  "cabal-version": "3.15.0.0",
  "cabal-lib-version": "3.15.0.0",
  "compiler-id": "ghc-9.6.6",
  "os": "linux",
  "arch": "x86_64",
  "install-plan": [
    {
      "type": "pre-existing",
      "id": "base-4.18.2.1",
      "pkg-name": "base",
      "pkg-version": "4.18.2.1",
      "depends": [
        "ghc-bignum-1.3",
        "ghc-prim-0.10.0",
        "rts-1.0.2"
      ]
    },
    {
      "type": "pre-existing",
      "id": "ghc-bignum-1.3",
      "pkg-name": "ghc-bignum",
      "pkg-version": "1.3",
      "depends": [
        "ghc-prim-0.10.0"
      ]
    },- .
    {
      "type": "pre-existing",
      "id": "ghc-prim-0.10.0",
      "pkg-name": "ghc-prim",
      "pkg-version": "0.10.0",
      "depends": [
        "rts-1.0.2"
      ]
    },
    {
      "type": "configured",
      "id": "mypkg-0.1.0.0-inplace",
      "pkg-name": "mypkg",
      "pkg-version": "0.1.0.0",
      "flags": {},
      "style": "local",
      "pkg-src": {
        "type": "local",
        "path": "/home/artem/tmp/cabal-issue-2015-repl-ignores-path-updates/mypkg/."
      },
      "dist-dir": "/home/artem/tmp/cabal-issue-2015-repl-ignores-path-updates/mypkg/dist-newstyle/build/x86_64-linux/ghc-9.6.6/mypkg-0.1.0.0",
      "build-info": "/home/artem/tmp/cabal-issue-2015-repl-ignores-path-updates/mypkg/dist-newstyle/build/x86_64-linux/ghc-9.6.6/mypkg-0.1.0.0/build-info.json",
      "depends": [
        "base-4.18.2.1"
      ],
      "exe-depends": [],
      "component-name": "lib"
    },
    {
      "type": "pre-existing",
      "id": "rts-1.0.2",
      "pkg-name": "rts",
      "pkg-version": "1.0.2",
      "depends": []
    }
  ]
}

@phadej
Copy link
Collaborator

phadej commented Jan 8, 2025

Do you know where in dist-newstyle the PATH value is stored

I don't. I'm quite sure it's a Cabal (i.e. not cabal-install) issue, i.e. something ./Setup configure does cache.

@ulysses4ever
Copy link
Collaborator

ulysses4ever commented Jan 8, 2025

Yes, it does seem to be the library, as also was pointed above (long time ago though), e.g. by Edward here: #2015 (comment) What I don’t understand is where Cabal stashes the value of PATH between creating dist-newstyle and a call to repl. It has to be some file on disk, right?

@ulysses4ever
Copy link
Collaborator

All right, the place where it stores the old value seems to be dist-newstyle/cache/config, a binary file (that's why I had trouble grepping it). And the place responsible for setting the PATH to the old value seems to be:

, programOverrideEnv = [("PATH", Just newPath)] ++ progOverrideEnv progdb

@mpickering
Copy link
Collaborator

@ulysses4ever I think that if you modify dryRunLocalPkg to also track if PATH has changed, then it will fix this bug. At the moment it only seems to track if any source files have changed. I'm not sure that's exactly the right fix but it seems along those lines.

@mpickering
Copy link
Collaborator

Perhaps the way to do this is to store the current path in ElaboratedConfiguredPackage.

@phadej
Copy link
Collaborator

phadej commented Jan 9, 2025

if PATH is changed, technically you should wipe the whole ProgramDb (i.e. configured programs) etc, in particular the used (implicit) ghc may change. I don't think there is an easy fix.

@ulysses4ever
Copy link
Collaborator

Thanks, Matt!

Oleg, is reconfiguring the whole ProgramDB a problem? What would be the downsides? Presumably, PATH doesn't change all the time, so this proposed check will hardly add much slowdown in practice and be noticed. Is this hard for some technical reason?

Besides, if we we only reconfigure ghc, we don't make things worse, do we? We don't reconfigure eagerly enough today anyway. It's just we improve on this particular case that happens to be a real stumbling block for people.

@phadej
Copy link
Collaborator

phadej commented Jan 9, 2025

@ulysses4ever I'm trying to say that changing PATH may well as well require doing everything from the beginning, essentially wiping all work done. Changed ghc means you need to create new install plan etc.

I'm not sure cabal-install rebuild logic is expressive enough to express that.

We don't know before we try to implement this, but if the rebuild logic will be sketchy, I think it will be worse than just not reacting to PATH changes. Not reacting is a clear specification: if you need to see new PATH, force reconfiguration (by wiping dist-newstyle).

@phadej
Copy link
Collaborator

phadej commented Jan 9, 2025

And to add, cabal doesn't react to many other similar changes. e.g adding a program to existing PATH, that doesn't cause reconfiguration, but in case of known programs it could. It's just simpler to not try to track too much stuff.

How often people do really change PATH? IMHO it can be leaved as a known behavior. It's surprising at first, but IMHO it makes sense.

Maybe what Cabal needs is a way to add stuff to PATH, not override it. But that's a new feature. (EDIT: I'm not sure why PATH is cached, there has to be a good reason to that - but it's possible that there isn't).

@mpickering
Copy link
Collaborator

cabal-install tracks the path when it decides whether to rebuild the build plan, so I think the change I suggested would be sufficient.

mpickering added a commit that referenced this issue Mar 6, 2025
When a user's PATH environment variable changes between Cabal commands,
the environment in the REPL becomes incorrect. This occurs because
during initial package configuration, the current PATH is captured via
`programSearchPathAsPATHVar` and then stored in the `programOverrideEnv`
field of a ConfiguredProgram. These `ConfiguredProgram`s are subsequently
serialized into the setup-config file, effectively baking in the PATH
environment from the time of configuration.

The issue manifests when `PATH` is updated after initial configuration.
Although the solver re-runs when detecting `PATH` changes, the
`dryRunLocalPkg` function examines `ElaboratedConfiguredPackage` and
incorrectly determines that nothing has changed that would require
reconfiguration. This decision is incorrect because `setup-config` now
contains a stale reference to the original `PATH` value, which no longer
matches the current environment.

To fix this problem, we need to store the `ConfiguredProgram`s directly in
`ElaboratedConfiguredPackage`. This approach will ensure that when `PATH`
changes, the `ConfiguredProgram`s will also change, properly triggering
reconfiguration. While this solution will cause more recompilations when
`PATH` changes, it guarantees that the correct environment is always used
during builds and REPL sessions.

An alternative approach would be to stop baking the `PATH` variable into
the environment of programs, but this would require more substantial
changes to how Cabal manages environment variables.

Fixes #2015
@mpickering mpickering linked a pull request Mar 6, 2025 that will close this issue
6 tasks
mpickering added a commit that referenced this issue Mar 6, 2025
When a user's PATH environment variable changes between Cabal commands,
the environment in the REPL becomes incorrect. This occurs because
during initial package configuration, the current PATH is captured via
`programSearchPathAsPATHVar` and then stored in the `programOverrideEnv`
field of a ConfiguredProgram. These `ConfiguredProgram`s are subsequently
serialized into the setup-config file, effectively baking in the PATH
environment from the time of configuration.

The issue manifests when `PATH` is updated after initial configuration.
Although the solver re-runs when detecting `PATH` changes, the
`dryRunLocalPkg` function examines `ElaboratedConfiguredPackage` and
incorrectly determines that nothing has changed that would require
reconfiguration. This decision is incorrect because `setup-config` now
contains a stale reference to the original `PATH` value, which no longer
matches the current environment.

To fix this problem, we need to store the `ConfiguredProgram`s directly in
`ElaboratedConfiguredPackage`. This approach will ensure that when `PATH`
changes, the `ConfiguredProgram`s will also change, properly triggering
reconfiguration. While this solution will cause more recompilations when
`PATH` changes, it guarantees that the correct environment is always used
during builds and REPL sessions.

An alternative approach would be to stop baking the `PATH` variable into
the environment of programs, but this would require more substantial
changes to how Cabal manages environment variables.

Fixes #2015
@mpickering
Copy link
Collaborator

Good news everyone. 10 years later I have put a fix in #10817

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Cabal: cmd/repl cabal-install: cmd/repl can-workaround There is a (maybe partial) workaround for the issue or missing feature type: bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.