diff --git a/ChangeLog.md b/ChangeLog.md index f7a0f1e0c6..810a21642e 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -16,6 +16,9 @@ Other enhancements: Bug fixes: +* Support most executable extensions on Windows + [#2225](https://github.com/commercialhaskell/stack/issues/2225) + ## 1.1.2 Release notes: diff --git a/src/System/Process/Read.hs b/src/System/Process/Read.hs index b94f57067b..ed591fa9f7 100644 --- a/src/System/Process/Read.hs +++ b/src/System/Process/Read.hs @@ -55,7 +55,7 @@ import Data.Foldable (forM_) import Data.IORef import Data.Map (Map) import qualified Data.Map as Map -import Data.Maybe (isJust, maybeToList) +import Data.Maybe (isJust, maybeToList, fromMaybe) import Data.Monoid import Data.Text (Text) import qualified Data.Text as T @@ -81,7 +81,7 @@ data EnvOverride = EnvOverride , eoStringList :: [(String, String)] -- ^ Environment variables as association list , eoPath :: [FilePath] -- ^ List of directories searched for executables (@PATH@) , eoExeCache :: IORef (Map FilePath (Either ReadProcessException (Path Abs File))) - , eoExeExtension :: String -- ^ @""@ or @".exe"@, depending on the platform + , eoExeExtensions :: [String] -- ^ @[""]@ on non-Windows systems, @["", ".exe", ".bat"]@ on Windows , eoPlatform :: Platform } @@ -112,9 +112,17 @@ mkEnvOverride platform tm' = do return EnvOverride { eoTextMap = tm , eoStringList = map (T.unpack *** T.unpack) $ Map.toList tm - , eoPath = maybe [] (FP.splitSearchPath . T.unpack) (Map.lookup "PATH" tm) + , eoPath = + (if isWindows then (".":) else id) + (maybe [] (FP.splitSearchPath . T.unpack) (Map.lookup "PATH" tm)) , eoExeCache = ref - , eoExeExtension = if isWindows then ".exe" else "" + , eoExeExtensions = + if isWindows + then let pathext = fromMaybe + ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC" + (Map.lookup "PATHEXT" tm) + in map T.unpack $ "" : T.splitOn ";" pathext + else [""] , eoPlatform = platform } where @@ -336,10 +344,7 @@ findExecutable :: (MonadIO m, MonadThrow n) -> String -- ^ Name of executable -> m (n (Path Abs File)) -- ^ Full path to that executable on success findExecutable eo name0 | any FP.isPathSeparator name0 = do - let names0 - | null (eoExeExtension eo) = [name0] - -- Support `stack exec foo/bar.exe` on Windows - | otherwise = [name0 ++ eoExeExtension eo, name0] + let names0 = map (name0 ++) (eoExeExtensions eo) testNames [] = return $ throwM $ ExecutableNotFoundAt name0 testNames (name:names) = do exists <- liftIO $ D.doesFileExist name @@ -357,10 +362,7 @@ findExecutable eo name = liftIO $ do let loop [] = return $ Left $ ExecutableNotFound name (eoPath eo) loop (dir:dirs) = do let fp0 = dir FP. name - fps0 - | null (eoExeExtension eo) = [fp0] - -- Support `stack exec foo.exe` on Windows - | otherwise = [fp0 ++ eoExeExtension eo, fp0] + fps0 = map (fp0 ++) (eoExeExtensions eo) testFPs [] = loop dirs testFPs (fp:fps) = do exists <- D.doesFileExist fp