-
Notifications
You must be signed in to change notification settings - Fork 45
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
fix(windows): Find purs.exe on Windows, if available #69
Conversation
Since `purs` isn't executable on Windows, Turtle procs weren't finding it to execute. `purs.cmd` is executable on windows, but it must be run in a shell for the `~%dp0` macros to expand properly. But running in a shell seems to break on other platforms (I tested on OS X). `purs.exe` seems to work just fine if it is on the path. If it is not already on the path, we have to find it. In this solution, I'm just looking for the exe relative to where the `purs.cmd` file is and executing it.
app/Main.hs
Outdated
constCmd t = fmap (const t) | ||
appendExeText :: Turtle.FilePath -> Text | ||
appendExeText p = | ||
either id id (toText (p </> "node_modules" </> "purescript" </> "vendor" </> "purs.exe")) |
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'm not keen on depending on npm here like this. I would encourage users to put the executable on their PATH instead.
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.
Yeah... I can't argue with you there.
The problem that I was working around was that when a user installs purescript with npm, the purs.cmd
is what ends up on the path. That is executable, but when run as a proc, the path macros in the file don't expand properly. So purs.cmd
has to be run with shell instead.
I did this because I was trying to avoid having to shell out for that one case, but this is kind of a terrible hack 🤷♂️
So, I could take a crack at shelling out when we find the purs.cmd
but no exe on the path.
Or we could pop an error message when we detect this case that says "Windows users need to have the exe on their path". Maybe even include a link to the latest release or something.
Thoughts?
app/Main.hs
Outdated
purs <- which "purs" | ||
cmd <- which "purs.cmd" | ||
exe <- which "purs.exe" | ||
return $ fromMaybe "purs" $ msum [ constCmd "purs" purs |
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.
Let's exit here instead of returning purs
?
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.
Sure thing. Perhaps a message like "purs needs to be on your path"?
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.
Yes please!
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.
Maybe "The "purs" executable could not be found. Please make sure your PATH variable is set correctly"?
Windows users who install purescript through npm can't use psc-package because the `purs` script isn't executable on windows. To make this work, we need to find the `purs.cmd` that npm installs on the path and run it in a shell (rather than a process). This change favors `purs` and `purs.exe` (if available on the path) over using the cmd. This also adds a more helpful error message if we can't find a purs executable.
Updated: There's a nicer error message now. I'm also not fishing for the exe. Instead I use the I tested this on Windows and OS X. |
app/Main.hs
Outdated
Just c -> return c | ||
where | ||
constCmd :: Text -> Maybe Turtle.FilePath -> Maybe Text | ||
constCmd t = fmap (const t) |
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.
You can use <$
for this.
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.
Ahhh, cool. Thanks! Haskell is still just a hobby for me.
I will try that out.
pursCmd :: IO Text | ||
pursCmd = do | ||
purs <- which "purs" | ||
cmd <- which "purs.cmd" |
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.
Where is purs.cmd
from again?
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.
When you install an npm package globally using npm (or yarn, I suppose), a cmd file is created for each bin script the package has. The cmd file is executable and passes the bin script and any arguments to node.
So, for example, purescript has bin/purs.js. So npm creates purs.cmd
on the path. And purs.cmd
runs purs.js
; like this --> node "%~dp0\node_modules\purescript\bin\purs.js" %*
... well, there's a couple other steps, but that's basically it.
So windows users who use cmd.exe or powershell, instead of an msys terminal or git shell or something, need to be able find and execute the purs.cmd
script if they are getting purescript from npm.
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 I would rather leave purs.cmd
out here, and encourage Windows users to either a) use the binaries directly, or b) temporarily modify their path to include wherever NPM puts them. I think it would reduce some complexity here, and I really don't think we should build in support for NPM. What do you think?
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 don't think that's a good idea - you're basically saying "we don't support the most common way of installing purescript" on Windows if purs.cmd
is ignored.
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.
Honestly, I don't think psc-package should have support for building anyway now that Pulp has support for using psc-package. I'd rather delete the code than have custom code for each way PureScript might be installed.
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 suppose we do need it for the version check though.
I know it seems overly minimalist, or something, but it bothers me that there is a sensible default on all decent OSes (just put it on your PATH), but not on Windows, and we have to make special cases there, which then have to be documented.
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.
Oh if we're removing build
altogether that works too 👍
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 feel pretty alienated when project's tooling doesn't support windows native. In this case, the work around isn't that big of a deal, but I'm sure it will still drive people away.
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.
We could remove build
, but then we'd still have verify
which uses purs
.
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.
Yeah we need it to check the compiler version too, actually, so removing it isn't really a solution.
Of course there was an operator for that...
Not supporting puts.cmd also breaks init and verify
|
app/Main.hs
Outdated
run purs srcGlobs | ||
where | ||
run :: MonadIO io => Text -> [Text] -> io () | ||
run "purs.cmd" globs = |
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 this special case should be fused into the function which finds the executable.
i.e. one function which finds purs
and runs it with some arguments.
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.
So, a runPurs
command, looks up the executable and does the right thing with the globs to execute it?
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.
Yes, I think so.
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.
ok... Let me try it and if it's not what you had in mind, I'll be glad to change it.
Move logic for managing args and discovering executable name into a single function.
procs "purs" ("compile" : srcGlobs) empty | ||
runPurs srcGlobs | ||
where | ||
runPurs :: [Text] -> IO () |
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 made this change, @paf31. Not sure if that's what you had in mind.
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.
Thanks, this is closer, but what I meant was to move this function to the top level, and to combine it with pursCmd
. Could you please try that?
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’ll give it a shot
Nothing -- use existing stdin | ||
Nothing -- use existing stdout | ||
Nothing -- use existing stderr | ||
=<< run purs paths srcParts |
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.
This should use runPurs
too.
getPureScriptVersion :: IO Version | ||
getPureScriptVersion = do | ||
let pursProc = inproc "purs" [ "--version" ] empty | ||
purs <- pursCmd | ||
let pursProc = cmdProc purs |
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.
And this one.
I know very little about Haskell but would it be possible to just run the command in a shell on Windows and not on other platforms? The new |
Can we consider this fixed by #141? |
Closing since #141 should have fixed this problem and there has been no activity here. |
Since
purs
isn't executable on Windows, Turtle procs weren't findingit to execute.
purs.cmd
is executable on windows, but it must be run in a shell forthe
~%dp0
macros to expand properly. But running in a shell seems tobreak on other platforms (I tested on OS X).
purs.exe
seems to work just fine if it is on the path. If it is notalready on the path, we have to find it. In this solution, I'm just
looking for the exe relative to where the
purs.cmd
file is andexecuting it.
Fixes #34