mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-27 19:14:52 +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 Data.List (intercalate)
|
||||||
import Main.Utf8 (withUtf8)
|
import Main.Utf8 (withUtf8)
|
||||||
import System.Environment (getArgs)
|
import System.Environment (getArgs)
|
||||||
|
import System.Exit (exitFailure)
|
||||||
import Wasp.Cli.Command (runCommand)
|
import Wasp.Cli.Command (runCommand)
|
||||||
import Wasp.Cli.Command.BashCompletion (bashCompletion, generateBashCompletionScript, printBashCompletionInstruction)
|
import Wasp.Cli.Command.BashCompletion (bashCompletion, generateBashCompletionScript, printBashCompletionInstruction)
|
||||||
import Wasp.Cli.Command.Build (build)
|
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.Test (test)
|
||||||
import Wasp.Cli.Command.Uninstall (uninstall)
|
import Wasp.Cli.Command.Uninstall (uninstall)
|
||||||
import Wasp.Cli.Command.WaspLS (runWaspLS)
|
import Wasp.Cli.Command.WaspLS (runWaspLS)
|
||||||
|
import Wasp.Cli.Message (cliSendMessage)
|
||||||
import Wasp.Cli.Terminal (title)
|
import Wasp.Cli.Terminal (title)
|
||||||
|
import qualified Wasp.Generator.Node.Version as NodeVersion
|
||||||
|
import qualified Wasp.Message as Message
|
||||||
import Wasp.Util (indent)
|
import Wasp.Util (indent)
|
||||||
import qualified Wasp.Util.Terminal as Term
|
import qualified Wasp.Util.Terminal as Term
|
||||||
import Wasp.Version (waspVersion)
|
import Wasp.Version (waspVersion)
|
||||||
@ -62,6 +66,16 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
|
|||||||
|
|
||||||
telemetryThread <- Async.async $ runCommand $ Telemetry.considerSendingData commandCall
|
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
|
case commandCall of
|
||||||
Command.Call.New newArgs -> runCommand $ createNewProject newArgs
|
Command.Call.New newArgs -> runCommand $ createNewProject newArgs
|
||||||
Command.Call.Start -> runCommand start
|
Command.Call.Start -> runCommand start
|
||||||
@ -95,11 +109,11 @@ main = withUtf8 . (`E.catch` handleInternalErrors) $ do
|
|||||||
handleInternalErrors :: E.ErrorCall -> IO ()
|
handleInternalErrors :: E.ErrorCall -> IO ()
|
||||||
handleInternalErrors e = putStrLn $ "\nInternal Wasp error (bug in compiler):\n" ++ indent 2 (show e)
|
handleInternalErrors e = putStrLn $ "\nInternal Wasp error (bug in compiler):\n" ++ indent 2 (show e)
|
||||||
|
|
||||||
|
{- ORMOLU_DISABLE -}
|
||||||
printUsage :: IO ()
|
printUsage :: IO ()
|
||||||
printUsage =
|
printUsage =
|
||||||
putStrLn $
|
putStrLn $
|
||||||
unlines
|
unlines
|
||||||
{- ORMOLU_DISABLE -}
|
|
||||||
[ title "USAGE",
|
[ title "USAGE",
|
||||||
" wasp <command> [command-args]",
|
" wasp <command> [command-args]",
|
||||||
"",
|
"",
|
||||||
@ -165,11 +179,11 @@ dbCli args = case args of
|
|||||||
["studio"] -> runDbCommand Command.Db.Studio.studio
|
["studio"] -> runDbCommand Command.Db.Studio.studio
|
||||||
_ -> printDbUsage
|
_ -> printDbUsage
|
||||||
|
|
||||||
|
{- ORMOLU_DISABLE -}
|
||||||
printDbUsage :: IO ()
|
printDbUsage :: IO ()
|
||||||
printDbUsage =
|
printDbUsage =
|
||||||
putStrLn $
|
putStrLn $
|
||||||
unlines
|
unlines
|
||||||
{- ORMOLU_DISABLE -}
|
|
||||||
[ title "USAGE",
|
[ title "USAGE",
|
||||||
" wasp db <command> [command-args]",
|
" wasp db <command> [command-args]",
|
||||||
"",
|
"",
|
||||||
|
@ -23,7 +23,6 @@ import qualified System.Process as P
|
|||||||
import UnliftIO.Exception (bracket)
|
import UnliftIO.Exception (bracket)
|
||||||
import qualified Wasp.Generator.Job as J
|
import qualified Wasp.Generator.Job as J
|
||||||
import qualified Wasp.Generator.Node.Version as NodeVersion
|
import qualified Wasp.Generator.Node.Version as NodeVersion
|
||||||
import qualified Wasp.SemanticVersion as SV
|
|
||||||
|
|
||||||
-- TODO:
|
-- TODO:
|
||||||
-- Switch from Data.Conduit.Process to Data.Conduit.Process.Typed.
|
-- 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 :: [(String, String)] -> Path' Abs (Dir a) -> String -> [String] -> J.JobType -> J.Job
|
||||||
runNodeCommandAsJobWithExtraEnv extraEnvVars fromDir command args jobType chan =
|
runNodeCommandAsJobWithExtraEnv extraEnvVars fromDir command args jobType chan =
|
||||||
NodeVersion.getNodeVersion >>= \case
|
NodeVersion.getAndCheckNodeVersion >>= \case
|
||||||
Left errorMsg -> exitWithError (ExitFailure 1) (T.pack errorMsg)
|
Left errorMsg -> exitWithError (ExitFailure 1) (T.pack errorMsg)
|
||||||
Right nodeVersion ->
|
Right _ -> do
|
||||||
if SV.isVersionInRange nodeVersion NodeVersion.nodeVersionRange
|
|
||||||
then do
|
|
||||||
envVars <- getAllEnvVars
|
envVars <- getAllEnvVars
|
||||||
let nodeCommandProcess = (P.proc command args) {P.env = Just envVars, P.cwd = Just $ SP.fromAbsDir fromDir}
|
let nodeCommandProcess = (P.proc command args) {P.env = Just envVars, P.cwd = Just $ SP.fromAbsDir fromDir}
|
||||||
runProcessAsJob nodeCommandProcess jobType chan
|
runProcessAsJob nodeCommandProcess jobType chan
|
||||||
else exitWithError (ExitFailure 1) (T.pack $ NodeVersion.makeNodeVersionMismatchMessage nodeVersion)
|
|
||||||
where
|
where
|
||||||
-- Haskell will use the first value for variable name it finds. Since env
|
-- Haskell will use the first value for variable name it finds. Since env
|
||||||
-- vars in 'extraEnvVars' should override the the inherited env vars, we
|
-- vars in 'extraEnvVars' should override the the inherited env vars, we
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
module Wasp.Generator.Node.Version
|
module Wasp.Generator.Node.Version
|
||||||
( getNodeVersion,
|
( getAndCheckNodeVersion,
|
||||||
|
getNodeVersion,
|
||||||
nodeVersionRange,
|
nodeVersionRange,
|
||||||
latestMajorNodeVersion,
|
latestMajorNodeVersion,
|
||||||
waspNodeRequirementMessage,
|
waspNodeRequirementMessage,
|
||||||
@ -13,25 +14,56 @@ import qualified System.Process as P
|
|||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
import qualified Text.Regex.TDFA as R
|
import qualified Text.Regex.TDFA as R
|
||||||
import qualified Wasp.SemanticVersion as SV
|
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 :: IO (Either String SV.Version)
|
||||||
getNodeVersion = do
|
getNodeVersion = do
|
||||||
(exitCode, stdout, stderr) <-
|
-- Node result is one of:
|
||||||
P.readProcessWithExitCode "node" ["--version"] ""
|
-- 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 ->
|
`catchIOError` ( \e ->
|
||||||
if isDoesNotExistError e
|
if isDoesNotExistError e
|
||||||
then return (ExitFailure 1, "", "Command 'node' not found.")
|
then return $ Left nodeNotFoundMessage
|
||||||
else ioError e
|
else return $ Left $ makeNodeUnknownErrorMessage e
|
||||||
)
|
)
|
||||||
return $ case exitCode of
|
return $ case nodeResult of
|
||||||
ExitFailure _ ->
|
Left procErr ->
|
||||||
Left
|
Left
|
||||||
( "Running 'node --version' failed: "
|
( unlines
|
||||||
++ stderr
|
[ procErr,
|
||||||
++ " "
|
waspNodeRequirementMessage
|
||||||
++ 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 ->
|
Nothing ->
|
||||||
Left
|
Left
|
||||||
( "Wasp failed to parse node version."
|
( "Wasp failed to parse node version."
|
||||||
@ -49,11 +81,21 @@ parseNodeVersion nodeVersionStr =
|
|||||||
return $ SV.Version mjr mnr ptc
|
return $ SV.Version mjr mnr ptc
|
||||||
_ -> Nothing
|
_ -> 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 :: String
|
||||||
waspNodeRequirementMessage =
|
waspNodeRequirementMessage =
|
||||||
unwords
|
unwords
|
||||||
[ "Wasp requires node " ++ show nodeVersionRange ++ ".",
|
[ "Wasp requires Node " ++ show nodeVersionRange ++ " to be installed and in PATH.",
|
||||||
"Check Wasp docs for more details: https://wasp-lang.dev/docs/quick-start#requirements."
|
"Check Wasp documentation for more details: https://wasp-lang.dev/docs/quick-start#requirements."
|
||||||
]
|
]
|
||||||
|
|
||||||
nodeVersionRange :: SV.Range
|
nodeVersionRange :: SV.Range
|
||||||
@ -72,8 +114,10 @@ latestMajorNodeVersion = latestNodeLTSVersion
|
|||||||
|
|
||||||
makeNodeVersionMismatchMessage :: SV.Version -> String
|
makeNodeVersionMismatchMessage :: SV.Version -> String
|
||||||
makeNodeVersionMismatchMessage nodeVersion =
|
makeNodeVersionMismatchMessage nodeVersion =
|
||||||
unwords
|
unlines
|
||||||
[ "Your node version does not match Wasp's requirements.",
|
[ unwords
|
||||||
"You are running node " ++ show nodeVersion ++ ".",
|
[ "Your Node version does not meet Wasp's requirements!",
|
||||||
|
"You are running Node " ++ show nodeVersion ++ "."
|
||||||
|
],
|
||||||
waspNodeRequirementMessage
|
waspNodeRequirementMessage
|
||||||
]
|
]
|
||||||
|
@ -107,7 +107,7 @@ library
|
|||||||
, exceptions ^>= 0.10.4
|
, exceptions ^>= 0.10.4
|
||||||
, split ^>= 0.2.3
|
, split ^>= 0.2.3
|
||||||
, conduit-extra ^>= 1.3.5
|
, conduit-extra ^>= 1.3.5
|
||||||
, process ^>= 1.6.13
|
, process ^>= 1.6.17
|
||||||
, cryptohash-sha256 ^>= 0.11.102
|
, cryptohash-sha256 ^>= 0.11.102
|
||||||
, mustache ^>= 2.3.2
|
, mustache ^>= 2.3.2
|
||||||
, parsec ^>= 3.1.14
|
, parsec ^>= 3.1.14
|
||||||
|
Loading…
Reference in New Issue
Block a user