Cabal commands do not work with whitespace in path
Describe the bug
Cabal commands do not work with provided paths when the paths contain white spaces. For example, if the path /home/USERNAME/Cabal Projects/app/Main.hs is provided instead of the path ./app/Main.hs or the path /home/USERNAME/cabal-projects/app/Main.hs, the command does not work. This is an issue for projects with parent directories containing white spaces.
To Reproduce Steps to reproduce the behavior:
- Create a new directory
Cabal Projectsin the home directory/home/USERNAME. - Run
cabal initin theCabal Projectsdirectory. - Run
cabal v2-repl ./app/Main.hs. The file should run correctly. - Attempt to run
cabal v2-repl /home/USERNAME/Cabal\ Projects/app/Main.hsorcabal v2-repl "/home/USERNAME/Cabal Projects/app/Main.hs". The command fails with the error message "cabal: Unrecognised target syntax for '/home/USERNAME/Cabal Project/app/Main.hs'." for Cabal3.6.2.0, and "Error: cabal: Failed extracting script block:{- cabal:start marker not found" for Cabal3.10.1.0. - Create a new directory
cabal-projectsin the home directory/home/USERNAME. - Run
cabal initin thecabal-projectsdirectory. - Run
cabal v2-repl ./app/Main.hs. The file should run correctly. - Run
cabal v2-repl /home/USERNAME/cabal-projects/app/Main.hs. The file should also run correctly.
Expected behavior The cabal command should run correctly in both the instance where the directory has no whitespace and the instance where the directory has whitespace in its name.
System information
- Linux, Fedora 37
- Tested with cabal versions
3.6.2.0and3.10.1.0 - Tested with ghc versions
9.2.5and9.4.4
Additional context
This problem causes issues with Haskell Language Server as HLS runs cabal commands from the root directory with the format cabal v2-repl "/home/USERNAME/Cabal Projects/app/Main.hs" in order to work, which causes issues when the intermediate directories have whitespaces.
I suspect 46987a928ddee7ca1310d1eeee2cbc46eecab615
https://github.com/haskell/cabal/blob/d53b4d46c51f5162e84765fd69d9c8806eea15b1/cabal-install/src/Distribution/Client/ScriptUtils.hs#L182-L186
Does this ring a bell, @bacchanalia?
@ffaf1 good bug hunting, thank you!
I'm curious though: https://github.com/haskell/cabal/commit/46987a928ddee7ca1310d1eeee2cbc46eecab615 concerns scripts but the bug report seem to point to a fresh cabal inited package. There may be something else at play? Or all cabal run go thorugh this part of code? How about cabal repl (which is also mentioned in the bug report)?
The fact that this was failing on 3.6.2.0 suggests that I was right in the comment that readTargetSelectors would fail to parse targets that contain spaces was correct :sweat_smile:.
I'm not sure I realized you could point to specific files as cabal targets, or I probably would have thought to fix this while working on the script stuff.
@ulysses4ever It does look like I replaced an existing bug with another related bug though, so that will have to be fixed along with the original bug. I think I might actually have some time this week to look into it.
While we're here, I assume we also want to support paths that contain ':' (which is also currently not supported)?
I would say “any path valid on the user’s system” would be perfect.
I think whitespace and ':' are the only chars currently prohibited.
While we're here, I assume we also want to support paths that contain ':' (which is also currently not supported)?
I'd say - heck, yes!!
Colon has special meaning in target syntax: it separates the parts of a target. See https://cabal.readthedocs.io/en/stable/cabal-commands.html#target-forms
Space is also special in that it separates multiple targets.
Now, we’re used to the shell UX when enclosing a string into quotes allows special symbols. But that’s never been promised for targets. Trying to implement it is, perhaps, a noble goal (especially if there are legit use cases e.g. arising from how HLS calls cabal), but I’m slightly worried that it may be not trivial in fully backwards compatible manner.
"Noble goal" here is more important than "backward compatibility", IMHO. Especially since "backward" way of dealing with colon-separated paths is nothing to be happy about.
Space only separates targets in that it's passed as multiple arguments. Inside a single argument it's just disallowed (except for scripts, currently), so allowing spaces I don't think will cause problems.
Allowing ':'s is trickier because it can lead to ambiguity. A compromise might be to require paths with ':'s to start with '.' or '/'.
compromise might be to require paths with ':'s to start with '.' or '/'.
I don't like when a tool is trying to be smart. But maybe it's just me.
Also, keep in mind that colon is simply forbidden as a part of a path on all Unix systems (I think). That was probably the original motivation for picking it in the target syntax.
This issue is still biting HLS users, as hie-bios passes the absolute path to a file to cabal repl, leading to issues such as https://github.com/haskell/haskell-language-server/issues/4225
A shorter reproducer:
$ mkdir new-project && cd new-project
$ cabal init --lib -n -m --source-dir="lib src"
$ cabal repl lib\ src/MyLib.hs
Failed extracting script block: `{- cabal:` start marker not found
Still reproducible with HEAD.
@bacchanalia Do you still plan working on this?
I finally have some time, so I'll take a look.