Skip to content

How to use the original $PATH environment variable inside a stack execution #5055

@jneira

Description

@jneira

Hi! I recently discovered that stack is modifying the $PATH variable when you ran any command. More precisely it prepends to it {local-install-root}/bin and {snapshot-install-root}/bin.

It is interfering with an actual use case in haskell-ide-engine. We are using a script to perform the installation of the tool and one of the commands installs the appropiate version of cabal in local-bin-dir (that hopefully is in $PATH).

The issue is once you have installed it the first time, stack put it in {snapshot-install-root}/bin and all subsequent calls to the script using stack use that cached version of cabal and no the original executable in user $PATH (wherever it is).

That behaviour causes:

  • If you delete the cabal executable in $PATH after installing it with the script, another invocation doesn't copy again the cabal executable, cause the version cached by stack is found (using Directory.findExecutable).
  • All executions of the script that eventually execute cabal use that cached version and no the original one, so f.e. if you upgrade manually your cabal in $PATH to 3.0.0.0 the script will continue using the cached version, (currently 2.4.1.0)

The unique workaround i've got is to manually remove those paths from $PATH and run all cabal executions and Directory.findExecutable without them:

withoutStackCachedBinaries action = do
  mbPath <- liftIO (lookupEnv "PATH")

  case (mbPath, isRunFromStack) of

    (Just paths, True) -> do
      snapshotDir <- trimmedStdout <$> execStackShake ["path", "--snapshot-install-root"]
      localInstallDir <- trimmedStdout <$> execStackShake ["path", "--local-install-root"]

      let cacheBinPaths = [snapshotDir </> "bin", localInstallDir </> "bin"]
      let origPaths = removePathsContaining cacheBinPaths paths

      liftIO (setEnv "PATH" origPaths)
      a <- action
      liftIO (setEnv "PATH" paths)
      return a

    otherwise -> action

  where ....

Clearly it is an ugly and brittle hack so do you know another better way to accomplish it?
In case there is no one, could be added some way to optionally bypass the stack modifications of the $PATH variable?

(NOTE: i am aware that the modification of the $PATH variable is absolutely required to not break stack builds, optionally bypassing it only would make sense inside stack run script.hs or maybe stack exec whatever. A possible improvement could be save the original path to another environment variable with a specific name)

Stack version

$ stack --version
Version 2.1.3, Git revision 0fa51b9925decd937e4a993ad90cb686f88fa282 (7739 commits) x86_64 hpack-0.31.2

Method of installation

  • Official binary, downloaded from stackage.org or fpcomplete's package repository

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions