Skip to content
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

Clear STAN-0001 suggestion #6302

Merged
merged 2 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 23 additions & 18 deletions doc/maintainers/stack_errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,13 @@
In connection with considering Stack's support of the
[Haskell Error Index](https://errors.haskell.org/) initiative, this page seeks
to take stock of the errors that Stack itself can raise, by reference to the
`master` branch of the Stack repository. Last updated: 2023-10-17.

* `GHC.GHC.Utils.GhcPkg.Main.Compat`

~~~haskell
[S-6512] = CannotParse String String String
[S-3384] | CannotOpenDBForModification FilePath IOException
[S-1430] | SingleFileDBUnsupported FilePath
[S-5996] | ParsePackageInfoExceptions String
[S-3189] | CannotFindPackage PackageArg (Maybe FilePath)

~~~
`master` branch of the Stack repository. Last updated: 2023-10-18.

* `Stack.main`: catches exceptions from action `commandLineHandler`.

- `ExitCode`
- `throwIO`

* `Stack.StackException`

~~~haskell
[S-2186] = InvalidReExecVersion String String
~~~

* `Stack.main`: catches exceptions from action `run`:

- `ExitCode` (`exitWith`)
Expand All @@ -45,6 +28,16 @@ to take stock of the errors that Stack itself can raise, by reference to the
[S-2816] = InconsistentDependenciesBug
~~~

- `GHC.GHC.Utils.GhcPkg.Main.Compat`

~~~haskell
[S-6512] = CannotParse String String String
[S-3384] | CannotOpenDBForModification FilePath IOException
[S-1430] | SingleFileDBUnsupported FilePath
[S-5996] | ParsePackageInfoExceptions String
[S-3189] | CannotFindPackage PackageArg (Maybe FilePath)
~~~

- `Options.Applicative.Builder.Extra.OptionsApplicativeExtraException`

~~~haskell
Expand Down Expand Up @@ -72,6 +65,12 @@ to take stock of the errors that Stack itself can raise, by reference to the
[S-5743] | DuplicatePackagesBug
~~~

- `Stack.CLI.CliPrettyException`

~~~haskell
[S-4639] = NoArgumentsBug
~~~

- `Stack.Clean.CleanException`

~~~haskell
Expand Down Expand Up @@ -322,6 +321,12 @@ to take stock of the errors that Stack itself can raise, by reference to the
[S-4230] | ExistingMSYS2NotDeleted (Path Abs Dir) IOException
~~~

- `Stack.StackException`

~~~haskell
[S-2186] = InvalidReExecVersion String String
~~~

- `Stack.Storage.User.StorageUserException`

~~~haskell
Expand Down
12 changes: 8 additions & 4 deletions src/Data/Attoparsec/Interpreter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ import Data.Char ( isSpace )
import Conduit ( decodeUtf8C, withSourceFile )
import Data.Conduit.Attoparsec ( ParseError (..), Position (..), sinkParserEither )
import Data.List ( intercalate )
import Data.List.NonEmpty ( singleton )
import Data.Text ( pack )
import RIO.NonEmpty ( nonEmpty )
import Stack.Constants ( stackProgName )
import Stack.Prelude
import System.FilePath ( takeExtension )
Expand Down Expand Up @@ -108,7 +110,7 @@ interpreterArgsParser isLiterate progName = P.option "" sheBangLine *> interpret

-- | Extract Stack arguments from a correctly placed and correctly formatted
-- comment when it is being used as an interpreter
getInterpreterArgs :: String -> IO [String]
getInterpreterArgs :: String -> IO (NonEmpty String)
getInterpreterArgs file = do
eArgStr <- withSourceFile file parseFile
case eArgStr of
Expand All @@ -134,14 +136,16 @@ getInterpreterArgs file = do
mapM_ stackWarn (lines err)
stackWarn "Missing or unusable Stack options specification"
stackWarn "Using runghc without any additional Stack options"
pure ["runghc"]
pure $ singleton "runghc"

parseArgStr str =
case P.parseOnly (argsParser Escaping) (pack str) of
Left err -> handleFailure ("Error parsing command specified in the "
++ "Stack options comment: " ++ err)
Right [] -> handleFailure "Empty argument list in Stack options comment"
Right args -> pure args
Right args -> maybe
(handleFailure "Empty argument list in Stack options comment")
pure
(nonEmpty args)

decodeError e =
case e of
Expand Down
13 changes: 11 additions & 2 deletions src/Options/Applicative/Complicated.hs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,17 @@ complicatedOptions ::
-> AddCommand
-- ^ commands (use 'addCommand')
-> IO (GlobalOptsMonoid, RIO Runner ())
complicatedOptions numericVersion stringVersion numericHpackVersion h pd
footerStr commonParser mOnFailure commandParser = do
complicatedOptions
numericVersion
stringVersion
numericHpackVersion
h
pd
footerStr
commonParser
mOnFailure
commandParser
= do
args <- getArgs
(a, (b, c)) <- let parserPrefs = prefs $ noBacktrack <> showHelpOnEmpty
in case execParserPure parserPrefs parser args of
Expand Down
3 changes: 1 addition & 2 deletions src/Stack/Build/ConstructPlan.hs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ import Stack.Types.SourceMap
import Stack.Types.Version
( latestApplicableVersion, versionRangeText, withinRange )
import System.Environment ( lookupEnv )
import Data.List.NonEmpty (nonEmpty)

data PackageInfo
= PIOnlyInstalled InstallLocation Installed
Expand Down Expand Up @@ -621,7 +620,7 @@ addDep name packageInfo = do
Nothing -> do
-- This could happen for GHC boot libraries missing from
-- Hackage.
cs <- asks (nonEmpty . callStack)
cs <- asks (NE.nonEmpty . callStack)
cs' <- maybe
(throwIO CallStackEmptyBug)
(pure . NE.tail)
Expand Down
64 changes: 43 additions & 21 deletions src/Stack/CLI.hs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module Stack.CLI
import Data.Attoparsec.Interpreter ( getInterpreterArgs )
import Data.Char ( toLower )
import qualified Data.List as L
import Data.List.NonEmpty ( prependList )
import Options.Applicative
( Parser, ParserFailure, ParserHelp, ParserResult (..), flag, switch
, handleParseResult, help, helpError, idm, long, metavar
Expand All @@ -16,6 +17,8 @@ import Options.Applicative.Builder.Extra
( boolFlags, extraHelpOption, textOption )
import Options.Applicative.Complicated
( addCommand, addSubCommands, complicatedOptions )
import qualified RIO.NonEmpty as NE
import RIO.NonEmpty ( (<|) )
import qualified RIO.Process ( exec )
import RIO.Process ( withProcessContextNoLogging )
import Stack.Build ( buildCmd )
Expand Down Expand Up @@ -82,6 +85,18 @@ import qualified System.Directory as D
import System.Environment ( getProgName, withArgs )
import System.FilePath ( pathSeparator, takeDirectory )

-- | Type representing \'pretty\' exceptions thrown by functions in the
-- "Stack.CLI" module.
data CliPrettyException
= NoArgumentsBug
deriving (Show, Typeable)

instance Pretty CliPrettyException where
pretty NoArgumentsBug = bugPrettyReport "[S-4639]" $
flow "commandLineHandler: no command line arguments on event of failure."

instance Exception CliPrettyException

-- | Stack's command line handler.
commandLineHandler ::
FilePath
Expand Down Expand Up @@ -112,10 +127,16 @@ commandLineHandler currentDir progName isInterpreter =
else mempty
failureCallback f args =
case L.stripPrefix "Invalid argument" (fst (renderFailure f "")) of
Just _ -> if isInterpreter
then parseResultHandler args f
else secondaryCommandHandler args f
>>= interpreterHandler currentDir args
Just _ -> maybe
(prettyThrowIO NoArgumentsBug)
( \args' -> if isInterpreter
then
parseResultHandler (NE.toList args') f
else
secondaryCommandHandler args' f
>>= interpreterHandler currentDir args'
)
(NE.nonEmpty args)
Nothing -> parseResultHandler args f

parseResultHandler args f =
Expand Down Expand Up @@ -613,12 +634,12 @@ commandLineHandler currentDir progName isInterpreter =
-- (i.e. `stack something` looks for `stack-something` before
-- failing with "Invalid argument `something'")
secondaryCommandHandler ::
[String]
NonEmpty String
-> ParserFailure ParserHelp
-> IO (ParserFailure ParserHelp)
secondaryCommandHandler args f =
-- don't even try when the argument looks like a path or flag
if elem pathSeparator cmd || "-" `L.isPrefixOf` L.head args
if elem pathSeparator cmd || "-" `L.isPrefixOf` NE.head args
then pure f
else do
mExternalExec <- D.findExecutable cmd
Expand All @@ -627,20 +648,20 @@ secondaryCommandHandler args f =
-- TODO show the command in verbose mode
-- hPutStrLn stderr $ unwords $
-- ["Running", "[" ++ ex, unwords (tail args) ++ "]"]
_ <- RIO.Process.exec ex (L.tail args)
_ <- RIO.Process.exec ex (NE.tail args)
pure f
Nothing -> pure $ fmap (vcatErrorHelp (noSuchCmd cmd)) f
where
-- FIXME this is broken when any options are specified before the command
-- e.g. stack --verbosity silent cmd
cmd = stackProgName ++ "-" ++ L.head args
cmd = stackProgName <> "-" <> NE.head args
noSuchCmd name = errorHelp $ stringChunk
("Auxiliary command not found in path '" ++ name ++ "'.")

interpreterHandler ::
Monoid t
=> FilePath
-> [String]
-> NonEmpty String
-> ParserFailure ParserHelp
-> IO (GlobalOptsMonoid, (RIO Runner (), t))
interpreterHandler currentDir args f = do
Expand All @@ -653,17 +674,18 @@ interpreterHandler currentDir args f = do
(file:fileArgs') -> runInterpreterCommand file stackArgs fileArgs'
[] -> parseResultHandler (errorCombine (noSuchFile firstArg))
where
firstArg = L.head args
firstArg = NE.head args

spanM _ [] = pure ([], [])
spanM p xs@(x:xs') = do
spanM p xs@(x :| rest) = do
r <- p x
if r
then do
(ys, zs) <- spanM p xs'
pure (x:ys, zs)
else
pure ([], xs)
then case rest of
[] -> pure ([x], [])
(x': rest') -> do
(ys, zs) <- spanM p (x' :| rest')
pure (x : ys, zs)
else
pure ([], NE.toList xs)

-- if the first argument contains a path separator then it might be a file,
-- or a Stack option referencing a file. In that case we only show the
Expand All @@ -685,14 +707,14 @@ interpreterHandler currentDir args f = do
let parseCmdLine = commandLineHandler currentDir progName True
-- Implicit file arguments are put before other arguments that
-- occur after "--". See #3658
cmdArgs = stackArgs ++ case break (== "--") iargs of
(beforeSep, []) -> beforeSep ++ ["--"] ++ [path] ++ fileArgs
cmdArgs = prependList stackArgs $ case NE.break (== "--") iargs of
(beforeSep, []) -> prependList beforeSep $ "--" <| path :| fileArgs
(beforeSep, optSep : afterSep) ->
beforeSep ++ [optSep] ++ [path] ++ fileArgs ++ afterSep
prependList beforeSep $ optSep <| path :| fileArgs <> afterSep
-- TODO show the command in verbose mode
-- hPutStrLn stderr $ unwords $
-- ["Running", "[" ++ progName, unwords cmdArgs ++ "]"]
(a,b) <- withArgs cmdArgs parseCmdLine
(a,b) <- withArgs (NE.toList cmdArgs) parseCmdLine
pure (a,(b,mempty))

-- Vertically combine only the error component of the first argument with the
Expand Down