hdevtools
hdevtools copied to clipboard
Stack compatibility
I'm really excited about stack because it makes building Haskell projects super easy. Right now the only thing blocking me from using it for everything is that the current crop of vim plugins all rely on either ghc-mod (which doesn't appear to be compatible with stack at all) or hdevtools.
Generally, the way to execute a command in the stack context is stack exec
. Trying to do stack exec hdevtools check src/Main.hs
in a project of mine gives the following error:
Cabal error: Use of GHC's environment variable GHC_PACKAGE_PATH is incompatible with Cabal. Use the flag --package-db to specify a package database (it can be used multiple times).
Stack can output the path to the current package database with stack path
. I'd like to try testing to see if we can pass that into hdevtools and it would be able to run in a stack environment, but I'm not sure where in the code it's calling out to cabal or GHC. If anyone could give me some pointers there, that'd help out a lot with integrating with the new tool :smile:
Interesting - I'd have to do a fair amount of digging to see where that error is coming from.
In my experimentation with ghc-mod and stack, I got a similar error:
$ stack exec ghc-mod check src/Main.hs
cabal: Use of GHC's environment variable GHC_PACKAGE_PATH is incompatible with
Cabal. Use the flag --package-db to specify a package database (it can be used
multiple times).
ghc-mod: readCreateProcess: cabal "configure" "--with-ghc=ghc" "--package-db=clear" "--package-db=global" "--package-db=user" (exit 1): failed
readCreateProcess is not in ghc-mod repository according to ag, or hoogle, so I'm not sure how helpful that is
I have a feeling it's in System.Process and that ghc-mod is issuing a cabal shell command.
Yup! You're right there.
The hdevtools code for executing the GHC stuff is here:
runCommand :: IORef State -> ClientSend -> Command -> GHC.Ghc ()
runCommand _ clientSend (CmdCheck file) = do
let noPhase = Nothing
target <- GHC.guessTarget file noPhase
GHC.setTargets [target]
let handler err = GHC.printException err >> return GHC.Failed
flag <- GHC.handleSourceError handler (GHC.load GHC.LoadAllTargets)
liftIO $ case flag of
GHC.Succeeded -> clientSend (ClientExit ExitSuccess)
GHC.Failed -> clientSend (ClientExit (ExitFailure 1))
(plus other cases)
Looking at the GHC module docs, there's a DynFlags
config object, which has a field:
extraPkgConfs :: [PkgConfRef] -> [PkgConfRef]
-- |The -package-db flags given on the command line, in the order they appeared.
where PkgConfRef
can be constructed as PkgConfFile FilePath
.
Looking at DynFlags, it seems like it should be possible to do:
dynFlags { extraPkgConfs = (:) (PkgConfFile pathToPkgDb) }
In fact, I bet that could be done just by making the modification here!
let updatedDynFlags = initialDynFlags
{ GHC.log_action = logAction state clientSend
, GHC.ghcLink = GHC.NoLink
, GHC.hscTarget = GHC.HscInterpreted
}
let updatedDynFlags' = if hasDbPath ghcOpts then updateDynFlags { extraPkgConfgs = -- etc...
I'll give this a shot tonight to see if it works.
Yes please! And thanks :)
Great news! It works :D
https://github.com/parsonsmatt/hdevtools/commit/0a25c74082d4c8841ac3d89d7d8f5a75f0673796
So I built hdevtools with stack, hard coded the output of stack path --local-pkg-db
into the file, and rebuilt it with stack. Once it was built, I installed it onto my path, and it doesn't have any issues working in the directory. Naturally it only works in that directory, but... well, it works.
So I can think of two ways to get stack and hdevtools playing a bit nicer together:
-
Expose a
--package-db
command line argument that would take precedence. Then hdevtools could use the stack db with:hdevtools --package-db "`stack path --local-pkg-db`" check src/Main.hs
which isn't clean, but it would work, be pretty easy to implement.
-
Check for the presence of a stack.yaml file, and if so, get the local package database information from stack somehow. This would work similarly to the way hdevtools looks for the cabal sandbox file and gets the db info from there.
I've asked the stack mailing list what the easiest way for hdevtools to get the info.
How would you like to proceed with implementing the feature?
+1
@parsonsmatt - can you submit a pull request to https://github.com/schell/hdevtools? If not I'll do it by hand :)
@ranjitjhala is actually a bit further along with the changes: https://github.com/ranjitjhala/hdevtools/tree/stack
I exposed a -g --package-db=
flag in my branch. With the right combination of package-dbs being passed in, that's probably sufficient to get stack and hdevtools playing nicely for right now. I can take another look and submit a PR if I can verify that it works, for exposing that feature.
There have been a few other packages modified to be compatible with Stack. The most useful one as a comparison for implementing it in other packages is probably the commit to get yesod-devel working with stack. I'd also like to work on getting that integrated but likely won't have time until Thursday.
Any updates?
Hi all, sorry was a bit checked out -- I believe this is done and merged into the @schell repo? and in hdevtools 1.1.1.9?
Yes, over merged your changes into my fork and pushed to hackage. Try it out and tell me if it works for you.
Any progress on this? I'm getting this error on hdevtools version 0.1.2.2 (the latest on hackage).