mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-26 10:35:04 +03:00
Improve waspc node version checking and error messages (#1210)
* increase minimum version of process dependency * improve node version error messages
This commit is contained in:
parent
3f2bb72a0e
commit
ce587a9fad
@ -8,6 +8,7 @@ import Data.Char (isSpace)
|
||||
import Data.List (intercalate)
|
||||
import Main.Utf8 (withUtf8)
|
||||
import System.Environment (getArgs)
|
||||
import System.Exit (exitFailure)
|
||||
import Wasp.Cli.Command (runCommand)
|
||||
import Wasp.Cli.Command.BashCompletion (bashCompletion, generateBashCompletionScript, printBashCompletionInstruction)
|
||||
import Wasp.Cli.Command.Build (build)
|
||||
@ -30,7 +31,10 @@ import qualified Wasp.Cli.Command.Telemetry as Telemetry
|
||||
import Wasp.Cli.Command.Test (test)
|
||||
import Wasp.Cli.Command.Uninstall (uninstall)
|
||||
import Wasp.Cli.Command.WaspLS (runWaspLS)
|
||||
import Wasp.Cli.Message (cliSendMessage)
|
||||
import Wasp.Cli.Terminal (title)
|
||||
import qualified Wasp.Generator.Node.Version as NodeVersion
|
||||
import qualified Wasp.Message as Message
|
||||
import Wasp.Util (indent)
|
||||
import qualified Wasp.Util.Terminal as Term
|
||||
import Wasp.Version (waspVersion)
|
||||
@ -62,6 +66,16 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
|
||||
|
||||
telemetryThread <- Async.async $ runCommand $ Telemetry.considerSendingData commandCall
|
||||
|
||||
-- Before calling any command, check that the node requirement is met. Node is
|
||||
-- not needed for every command, but checking for every command was decided
|
||||
-- to be more robust than trying to only check for commands that require it.
|
||||
-- See https://github.com/wasp-lang/wasp/issues/1134#issuecomment-1554065668
|
||||
NodeVersion.getAndCheckNodeVersion >>= \case
|
||||
Left errorMsg -> do
|
||||
cliSendMessage $ Message.Failure "Node requirement not met" errorMsg
|
||||
exitFailure
|
||||
Right _ -> pure ()
|
||||
|
||||
case commandCall of
|
||||
Command.Call.New newArgs -> runCommand $ createNewProject newArgs
|
||||
Command.Call.Start -> runCommand start
|
||||
@ -95,11 +109,11 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
|
||||
handleInternalErrors :: E.ErrorCall -> IO ()
|
||||
handleInternalErrors e = putStrLn $ "\nInternal Wasp error (bug in compiler):\n" ++ indent 2 (show e)
|
||||
|
||||
{- ORMOLU_DISABLE -}
|
||||
printUsage :: IO ()
|
||||
printUsage =
|
||||
putStrLn $
|
||||
unlines
|
||||
{- ORMOLU_DISABLE -}
|
||||
[ title "USAGE",
|
||||
" wasp <command> [command-args]",
|
||||
"",
|
||||
@ -165,11 +179,11 @@ dbCli args = case args of
|
||||
["studio"] -> runDbCommand Command.Db.Studio.studio
|
||||
_ -> printDbUsage
|
||||
|
||||
{- ORMOLU_DISABLE -}
|
||||
printDbUsage :: IO ()
|
||||
printDbUsage =
|
||||
putStrLn $
|
||||
unlines
|
||||
{- ORMOLU_DISABLE -}
|
||||
[ title "USAGE",
|
||||
" wasp db <command> [command-args]",
|
||||
"",
|
||||
|
@ -23,7 +23,6 @@ import qualified System.Process as P
|
||||
import UnliftIO.Exception (bracket)
|
||||
import qualified Wasp.Generator.Job as J
|
||||
import qualified Wasp.Generator.Node.Version as NodeVersion
|
||||
import qualified Wasp.SemanticVersion as SV
|
||||
|
||||
-- TODO:
|
||||
-- Switch from Data.Conduit.Process to Data.Conduit.Process.Typed.
|
||||
@ -97,15 +96,12 @@ runNodeCommandAsJob = runNodeCommandAsJobWithExtraEnv []
|
||||
|
||||
runNodeCommandAsJobWithExtraEnv :: [(String, String)] -> Path' Abs (Dir a) -> String -> [String] -> J.JobType -> J.Job
|
||||
runNodeCommandAsJobWithExtraEnv extraEnvVars fromDir command args jobType chan =
|
||||
NodeVersion.getNodeVersion >>= \case
|
||||
NodeVersion.getAndCheckNodeVersion >>= \case
|
||||
Left errorMsg -> exitWithError (ExitFailure 1) (T.pack errorMsg)
|
||||
Right nodeVersion ->
|
||||
if SV.isVersionInRange nodeVersion NodeVersion.nodeVersionRange
|
||||
then do
|
||||
envVars <- getAllEnvVars
|
||||
let nodeCommandProcess = (P.proc command args) {P.env = Just envVars, P.cwd = Just $ SP.fromAbsDir fromDir}
|
||||
runProcessAsJob nodeCommandProcess jobType chan
|
||||
else exitWithError (ExitFailure 1) (T.pack $ NodeVersion.makeNodeVersionMismatchMessage nodeVersion)
|
||||
Right _ -> do
|
||||
envVars <- getAllEnvVars
|
||||
let nodeCommandProcess = (P.proc command args) {P.env = Just envVars, P.cwd = Just $ SP.fromAbsDir fromDir}
|
||||
runProcessAsJob nodeCommandProcess jobType chan
|
||||
where
|
||||
-- Haskell will use the first value for variable name it finds. Since env
|
||||
-- vars in 'extraEnvVars' should override the the inherited env vars, we
|
||||
|
@ -1,5 +1,6 @@
|
||||
module Wasp.Generator.Node.Version
|
||||
( getNodeVersion,
|
||||
( getAndCheckNodeVersion,
|
||||
getNodeVersion,
|
||||
nodeVersionRange,
|
||||
latestMajorNodeVersion,
|
||||
waspNodeRequirementMessage,
|
||||
@ -13,25 +14,56 @@ import qualified System.Process as P
|
||||
import Text.Read (readMaybe)
|
||||
import qualified Text.Regex.TDFA as R
|
||||
import qualified Wasp.SemanticVersion as SV
|
||||
import Wasp.Util (indent)
|
||||
|
||||
-- | Gets the installed node version, if any is installed, and checks that it
|
||||
-- meets Wasp's version requirement.
|
||||
--
|
||||
-- Returns a string representing the error
|
||||
-- condition if node's version could not be found or if the version does not
|
||||
-- meet the requirements.
|
||||
getAndCheckNodeVersion :: IO (Either String SV.Version)
|
||||
getAndCheckNodeVersion =
|
||||
getNodeVersion >>= \case
|
||||
Left errorMsg -> return $ Left errorMsg
|
||||
Right nodeVersion ->
|
||||
if SV.isVersionInRange nodeVersion nodeVersionRange
|
||||
then return $ Right nodeVersion
|
||||
else return $ Left $ makeNodeVersionMismatchMessage nodeVersion
|
||||
|
||||
-- | Gets the installed node version, if any is installed, and returns it.
|
||||
--
|
||||
-- Returns a string representing the error condition if node's version could
|
||||
-- not be found.
|
||||
getNodeVersion :: IO (Either String SV.Version)
|
||||
getNodeVersion = do
|
||||
(exitCode, stdout, stderr) <-
|
||||
P.readProcessWithExitCode "node" ["--version"] ""
|
||||
-- Node result is one of:
|
||||
-- 1. @Left processError@, when an error occurs trying to run the process
|
||||
-- 2. @Right (ExitCode, stdout, stderr)@, when the node process runs and terminates
|
||||
nodeResult <-
|
||||
(Right <$> P.readProcessWithExitCode "node" ["--version"] "")
|
||||
`catchIOError` ( \e ->
|
||||
if isDoesNotExistError e
|
||||
then return (ExitFailure 1, "", "Command 'node' not found.")
|
||||
else ioError e
|
||||
then return $ Left nodeNotFoundMessage
|
||||
else return $ Left $ makeNodeUnknownErrorMessage e
|
||||
)
|
||||
return $ case exitCode of
|
||||
ExitFailure _ ->
|
||||
return $ case nodeResult of
|
||||
Left procErr ->
|
||||
Left
|
||||
( "Running 'node --version' failed: "
|
||||
++ stderr
|
||||
++ " "
|
||||
++ waspNodeRequirementMessage
|
||||
( unlines
|
||||
[ procErr,
|
||||
waspNodeRequirementMessage
|
||||
]
|
||||
)
|
||||
ExitSuccess -> case parseNodeVersion stdout of
|
||||
Right (ExitFailure code, _, stderr) ->
|
||||
Left
|
||||
( unlines
|
||||
[ "Running `node --version` failed (exit code " ++ show code ++ "):",
|
||||
indent 2 stderr,
|
||||
waspNodeRequirementMessage
|
||||
]
|
||||
)
|
||||
Right (ExitSuccess, stdout, _) -> case parseNodeVersion stdout of
|
||||
Nothing ->
|
||||
Left
|
||||
( "Wasp failed to parse node version."
|
||||
@ -49,11 +81,21 @@ parseNodeVersion nodeVersionStr =
|
||||
return $ SV.Version mjr mnr ptc
|
||||
_ -> Nothing
|
||||
|
||||
nodeNotFoundMessage :: String
|
||||
nodeNotFoundMessage = "`node` command not found!"
|
||||
|
||||
makeNodeUnknownErrorMessage :: IOError -> String
|
||||
makeNodeUnknownErrorMessage err =
|
||||
unlines
|
||||
[ "An unknown error occured while trying to run `node --version`:",
|
||||
indent 2 $ show err
|
||||
]
|
||||
|
||||
waspNodeRequirementMessage :: String
|
||||
waspNodeRequirementMessage =
|
||||
unwords
|
||||
[ "Wasp requires node " ++ show nodeVersionRange ++ ".",
|
||||
"Check Wasp docs for more details: https://wasp-lang.dev/docs/quick-start#requirements."
|
||||
[ "Wasp requires Node " ++ show nodeVersionRange ++ " to be installed and in PATH.",
|
||||
"Check Wasp documentation for more details: https://wasp-lang.dev/docs/quick-start#requirements."
|
||||
]
|
||||
|
||||
nodeVersionRange :: SV.Range
|
||||
@ -72,8 +114,10 @@ latestMajorNodeVersion = latestNodeLTSVersion
|
||||
|
||||
makeNodeVersionMismatchMessage :: SV.Version -> String
|
||||
makeNodeVersionMismatchMessage nodeVersion =
|
||||
unwords
|
||||
[ "Your node version does not match Wasp's requirements.",
|
||||
"You are running node " ++ show nodeVersion ++ ".",
|
||||
unlines
|
||||
[ unwords
|
||||
[ "Your Node version does not meet Wasp's requirements!",
|
||||
"You are running Node " ++ show nodeVersion ++ "."
|
||||
],
|
||||
waspNodeRequirementMessage
|
||||
]
|
||||
|
@ -107,7 +107,7 @@ library
|
||||
, exceptions ^>= 0.10.4
|
||||
, split ^>= 0.2.3
|
||||
, conduit-extra ^>= 1.3.5
|
||||
, process ^>= 1.6.13
|
||||
, process ^>= 1.6.17
|
||||
, cryptohash-sha256 ^>= 0.11.102
|
||||
, mustache ^>= 2.3.2
|
||||
, parsec ^>= 3.1.14
|
||||
|
Loading…
Reference in New Issue
Block a user