{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
module Stack.Hoogle
( hoogleCmd
) where
import qualified Data.ByteString.Lazy.Char8 as BL8
import Data.Char ( isSpace )
import Data.Either.Extra ( eitherToMaybe )
import qualified Data.Text as T
import Distribution.PackageDescription ( packageDescription, package )
import Distribution.Types.PackageName ( mkPackageName )
import Distribution.Version ( mkVersion )
import Lens.Micro ( (?~) )
import Path ( parseAbsFile )
import Path.IO ( createDirIfMissing, doesFileExist )
import qualified RIO.Map as Map
import RIO.Process ( findExecutable, proc, readProcess_, runProcess_)
import qualified Stack.Build ( build )
import Stack.Build.Target ( NeedTargets (NeedTargets) )
import Stack.Constants ( stackProgName' )
import Stack.Prelude
import Stack.Runners
( ShouldReexec (..), withConfig, withDefaultEnvConfig
, withEnvConfig
)
import Stack.Types.BuildOpts
( BuildOptsCLI (..), buildOptsMonoidHaddockL
, defaultBuildOptsCLI
)
import Stack.Types.Config
( Config (..), HasConfig (..) )
import Stack.Types.EnvConfig
( EnvConfig, HasSourceMap (..), hoogleDatabasePath
, hoogleRoot
)
import Stack.Types.EnvSettings ( EnvSettings (..) )
import Stack.Types.GlobalOpts
( GlobalOpts (..), globalOptsBuildOptsMonoidL )
import Stack.Types.Runner ( Runner, globalOptsL )
import Stack.Types.SourceMap ( DepPackage (..), SourceMap (..) )
data HoogleException
= HoogleOnPathNotFoundBug
deriving (Int -> HoogleException -> ShowS
[HoogleException] -> ShowS
HoogleException -> String
(Int -> HoogleException -> ShowS)
-> (HoogleException -> String)
-> ([HoogleException] -> ShowS)
-> Show HoogleException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> HoogleException -> ShowS
showsPrec :: Int -> HoogleException -> ShowS
$cshow :: HoogleException -> String
show :: HoogleException -> String
$cshowList :: [HoogleException] -> ShowS
showList :: [HoogleException] -> ShowS
Show, Typeable)
instance Exception HoogleException where
displayException :: HoogleException -> String
displayException HoogleException
HoogleOnPathNotFoundBug = String -> ShowS
bugReport String
"[S-9669]"
String
"Cannot find Hoogle executable on PATH, after installing."
data HooglePrettyException
= HoogleNotFound StyleDoc
| HoogleDatabaseNotFound
deriving (Int -> HooglePrettyException -> ShowS
[HooglePrettyException] -> ShowS
HooglePrettyException -> String
(Int -> HooglePrettyException -> ShowS)
-> (HooglePrettyException -> String)
-> ([HooglePrettyException] -> ShowS)
-> Show HooglePrettyException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> HooglePrettyException -> ShowS
showsPrec :: Int -> HooglePrettyException -> ShowS
$cshow :: HooglePrettyException -> String
show :: HooglePrettyException -> String
$cshowList :: [HooglePrettyException] -> ShowS
showList :: [HooglePrettyException] -> ShowS
Show, Typeable)
instance Pretty HooglePrettyException where
pretty :: HooglePrettyException -> StyleDoc
pretty (HoogleNotFound StyleDoc
e) =
StyleDoc
"[S-1329]"
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
e
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> [StyleDoc] -> StyleDoc
fillSep
[ String -> StyleDoc
flow String
"Not installing Hoogle due to"
, Style -> StyleDoc -> StyleDoc
style Style
Shell StyleDoc
"--no-setup" StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
"."
]
pretty HooglePrettyException
HoogleDatabaseNotFound =
StyleDoc
"[S-3025]"
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
line
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> [StyleDoc] -> StyleDoc
fillSep
[ String -> StyleDoc
flow String
"No Hoogle database. Not building one due to"
, Style -> StyleDoc -> StyleDoc
style Style
Shell StyleDoc
"--no-setup" StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
"."
]
instance Exception HooglePrettyException
data Muted = Muted | NotMuted
hoogleCmd :: ([String], Bool, Bool, Bool) -> RIO Runner ()
hoogleCmd :: ([String], Bool, Bool, Bool) -> RIO Runner ()
hoogleCmd ([String]
args, Bool
setup, Bool
rebuild, Bool
startServer) =
(Runner -> Runner) -> RIO Runner () -> RIO Runner ()
forall a. (Runner -> Runner) -> RIO Runner a -> RIO Runner a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (ASetter Runner Runner GlobalOpts GlobalOpts
-> (GlobalOpts -> GlobalOpts) -> Runner -> Runner
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter Runner Runner GlobalOpts GlobalOpts
forall env. HasRunner env => Lens' env GlobalOpts
Lens' Runner GlobalOpts
globalOptsL GlobalOpts -> GlobalOpts
modifyGO) (RIO Runner () -> RIO Runner ()) -> RIO Runner () -> RIO Runner ()
forall a b. (a -> b) -> a -> b
$
ShouldReexec -> RIO Config () -> RIO Runner ()
forall a. ShouldReexec -> RIO Config a -> RIO Runner a
withConfig ShouldReexec
YesReexec (RIO Config () -> RIO Runner ()) -> RIO Config () -> RIO Runner ()
forall a b. (a -> b) -> a -> b
$
RIO EnvConfig () -> RIO Config ()
forall a. RIO EnvConfig a -> RIO Config a
withDefaultEnvConfig (RIO EnvConfig () -> RIO Config ())
-> RIO EnvConfig () -> RIO Config ()
forall a b. (a -> b) -> a -> b
$ do
Path Abs File
hooglePath <- RIO EnvConfig (Path Abs File)
ensureHoogleInPath
Path Abs File -> RIO EnvConfig ()
generateDbIfNeeded Path Abs File
hooglePath
Path Abs File -> [String] -> RIO EnvConfig ()
runHoogle Path Abs File
hooglePath [String]
args'
where
modifyGO :: GlobalOpts -> GlobalOpts
modifyGO :: GlobalOpts -> GlobalOpts
modifyGO = (BuildOptsMonoid -> Identity BuildOptsMonoid)
-> GlobalOpts -> Identity GlobalOpts
Lens' GlobalOpts BuildOptsMonoid
globalOptsBuildOptsMonoidL ((BuildOptsMonoid -> Identity BuildOptsMonoid)
-> GlobalOpts -> Identity GlobalOpts)
-> ((Maybe Bool -> Identity (Maybe Bool))
-> BuildOptsMonoid -> Identity BuildOptsMonoid)
-> (Maybe Bool -> Identity (Maybe Bool))
-> GlobalOpts
-> Identity GlobalOpts
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe Bool -> Identity (Maybe Bool))
-> BuildOptsMonoid -> Identity BuildOptsMonoid
Lens' BuildOptsMonoid (Maybe Bool)
buildOptsMonoidHaddockL ((Maybe Bool -> Identity (Maybe Bool))
-> GlobalOpts -> Identity GlobalOpts)
-> Bool -> GlobalOpts -> GlobalOpts
forall s t a b. ASetter s t a (Maybe b) -> b -> s -> t
?~ Bool
True
args' :: [String]
args' :: [String]
args' = if Bool
startServer
then [String
"server", String
"--local", String
"--port", String
"8080"] [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
args
else [String]
args
generateDbIfNeeded :: Path Abs File -> RIO EnvConfig ()
generateDbIfNeeded :: Path Abs File -> RIO EnvConfig ()
generateDbIfNeeded Path Abs File
hooglePath = do
Bool
databaseExists <- RIO EnvConfig Bool
checkDatabaseExists
if Bool
databaseExists Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
rebuild
then () -> RIO EnvConfig ()
forall a. a -> RIO EnvConfig a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
else
if Bool
setup Bool -> Bool -> Bool
|| Bool
rebuild
then do
StyleDoc -> RIO EnvConfig ()
forall env (m :: * -> *).
(HasCallStack, HasTerm env, MonadReader env m, MonadIO m) =>
StyleDoc -> m ()
prettyWarn (StyleDoc -> RIO EnvConfig ()) -> StyleDoc -> RIO EnvConfig ()
forall a b. (a -> b) -> a -> b
$
if Bool
rebuild
then String -> StyleDoc
flow String
"Rebuilding database ..."
else
[StyleDoc] -> StyleDoc
fillSep
[ String -> StyleDoc
flow String
"No Hoogle database yet. Automatically building \
\Haddock documentation and Hoogle database (use"
, Style -> StyleDoc -> StyleDoc
style Style
Shell StyleDoc
"--no-setup"
, String -> StyleDoc
flow String
"to disable) ..."
]
RIO EnvConfig ()
buildHaddocks
String -> RIO EnvConfig ()
forall env (m :: * -> *).
(HasCallStack, HasTerm env, MonadReader env m, MonadIO m) =>
String -> m ()
prettyInfoS String
"Built Haddock documentation."
Path Abs File -> RIO EnvConfig ()
generateDb Path Abs File
hooglePath
String -> RIO EnvConfig ()
forall env (m :: * -> *).
(HasCallStack, HasTerm env, MonadReader env m, MonadIO m) =>
String -> m ()
prettyInfoS String
"Generated Hoogle database."
else HooglePrettyException -> RIO EnvConfig ()
forall e (m :: * -> *) a.
(Exception e, MonadIO m, Pretty e) =>
e -> m a
prettyThrowIO HooglePrettyException
HoogleDatabaseNotFound
generateDb :: Path Abs File -> RIO EnvConfig ()
generateDb :: Path Abs File -> RIO EnvConfig ()
generateDb Path Abs File
hooglePath = do
Path Abs Dir
dir <- RIO EnvConfig (Path Abs Dir)
forall env. HasEnvConfig env => RIO env (Path Abs Dir)
hoogleRoot
Bool -> Path Abs Dir -> RIO EnvConfig ()
forall (m :: * -> *) b. MonadIO m => Bool -> Path b Dir -> m ()
createDirIfMissing Bool
True Path Abs Dir
dir
Path Abs File -> [String] -> RIO EnvConfig ()
runHoogle Path Abs File
hooglePath [String
"generate", String
"--local"]
buildHaddocks :: RIO EnvConfig ()
buildHaddocks :: RIO EnvConfig ()
buildHaddocks = do
Config
config <- Getting Config EnvConfig Config -> RIO EnvConfig Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config EnvConfig Config
forall env. HasConfig env => Lens' env Config
Lens' EnvConfig Config
configL
Config -> RIO Config () -> RIO EnvConfig ()
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO Config
config (RIO Config () -> RIO EnvConfig ())
-> RIO Config () -> RIO EnvConfig ()
forall a b. (a -> b) -> a -> b
$
RIO Config () -> (ExitCode -> RIO Config ()) -> RIO Config ()
forall (m :: * -> *) e a.
(MonadUnliftIO m, Exception e) =>
m a -> (e -> m a) -> m a
catch (RIO EnvConfig () -> RIO Config ()
forall a. RIO EnvConfig a -> RIO Config a
withDefaultEnvConfig (RIO EnvConfig () -> RIO Config ())
-> RIO EnvConfig () -> RIO Config ()
forall a b. (a -> b) -> a -> b
$ Maybe (Set (Path Abs File) -> IO ()) -> RIO EnvConfig ()
forall env.
HasEnvConfig env =>
Maybe (Set (Path Abs File) -> IO ()) -> RIO env ()
Stack.Build.build Maybe (Set (Path Abs File) -> IO ())
forall a. Maybe a
Nothing)
(\(ExitCode
_ :: ExitCode) -> () -> RIO Config ()
forall a. a -> RIO Config a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
hooglePackageName :: PackageName
hooglePackageName = String -> PackageName
mkPackageName String
"hoogle"
hoogleMinVersion :: Version
hoogleMinVersion = [Int] -> Version
mkVersion [Int
5, Int
0]
hoogleMinIdent :: PackageIdentifier
hoogleMinIdent =
PackageName -> Version -> PackageIdentifier
PackageIdentifier PackageName
hooglePackageName Version
hoogleMinVersion
installHoogle :: RIO EnvConfig (Path Abs File)
installHoogle :: RIO EnvConfig (Path Abs File)
installHoogle = Muted
-> RIO EnvConfig (Path Abs File) -> RIO EnvConfig (Path Abs File)
forall x. Muted -> RIO EnvConfig x -> RIO EnvConfig x
requiringHoogle Muted
Muted (RIO EnvConfig (Path Abs File) -> RIO EnvConfig (Path Abs File))
-> RIO EnvConfig (Path Abs File) -> RIO EnvConfig (Path Abs File)
forall a b. (a -> b) -> a -> b
$ do
Maybe (Set (Path Abs File) -> IO ()) -> RIO EnvConfig ()
forall env.
HasEnvConfig env =>
Maybe (Set (Path Abs File) -> IO ()) -> RIO env ()
Stack.Build.build Maybe (Set (Path Abs File) -> IO ())
forall a. Maybe a
Nothing
Either ProcessException String
mhooglePath' <- String -> RIO EnvConfig (Either ProcessException String)
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasProcessContext env) =>
String -> m (Either ProcessException String)
findExecutable String
"hoogle"
case Either ProcessException String
mhooglePath' of
Right String
hooglePath -> String -> RIO EnvConfig (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile String
hooglePath
Left ProcessException
_ -> HoogleException -> RIO EnvConfig (Path Abs File)
forall (m :: * -> *) e a. (MonadIO m, Exception e) => e -> m a
throwIO HoogleException
HoogleOnPathNotFoundBug
requiringHoogle :: Muted -> RIO EnvConfig x -> RIO EnvConfig x
requiringHoogle :: forall x. Muted -> RIO EnvConfig x -> RIO EnvConfig x
requiringHoogle Muted
muted RIO EnvConfig x
f = do
Text
hoogleTarget <- do
Map PackageName DepPackage
sourceMap <- Getting
(Map PackageName DepPackage) EnvConfig (Map PackageName DepPackage)
-> RIO EnvConfig (Map PackageName DepPackage)
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view (Getting
(Map PackageName DepPackage) EnvConfig (Map PackageName DepPackage)
-> RIO EnvConfig (Map PackageName DepPackage))
-> Getting
(Map PackageName DepPackage) EnvConfig (Map PackageName DepPackage)
-> RIO EnvConfig (Map PackageName DepPackage)
forall a b. (a -> b) -> a -> b
$ (SourceMap -> Const (Map PackageName DepPackage) SourceMap)
-> EnvConfig -> Const (Map PackageName DepPackage) EnvConfig
forall env. HasSourceMap env => Lens' env SourceMap
Lens' EnvConfig SourceMap
sourceMapL ((SourceMap -> Const (Map PackageName DepPackage) SourceMap)
-> EnvConfig -> Const (Map PackageName DepPackage) EnvConfig)
-> ((Map PackageName DepPackage
-> Const (Map PackageName DepPackage) (Map PackageName DepPackage))
-> SourceMap -> Const (Map PackageName DepPackage) SourceMap)
-> Getting
(Map PackageName DepPackage) EnvConfig (Map PackageName DepPackage)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (SourceMap -> Map PackageName DepPackage)
-> SimpleGetter SourceMap (Map PackageName DepPackage)
forall s a. (s -> a) -> SimpleGetter s a
to SourceMap -> Map PackageName DepPackage
smDeps
case PackageName -> Map PackageName DepPackage -> Maybe DepPackage
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup PackageName
hooglePackageName Map PackageName DepPackage
sourceMap of
Just DepPackage
hoogleDep ->
case DepPackage -> PackageLocation
dpLocation DepPackage
hoogleDep of
PLImmutable PackageLocationImmutable
pli ->
String -> Text
T.pack (String -> Text)
-> (PackageIdentifier -> String) -> PackageIdentifier -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageIdentifier -> String
packageIdentifierString (PackageIdentifier -> Text)
-> RIO EnvConfig PackageIdentifier -> RIO EnvConfig Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
Muted -> PackageIdentifier -> RIO EnvConfig PackageIdentifier
forall env.
HasLogFunc env =>
Muted -> PackageIdentifier -> RIO env PackageIdentifier
restrictMinHoogleVersion Muted
muted (PackageLocationImmutable -> PackageIdentifier
packageLocationIdent PackageLocationImmutable
pli)
plm :: PackageLocation
plm@(PLMutable ResolvedPath Dir
_) ->
String -> Text
T.pack (String -> Text)
-> (GenericPackageDescription -> String)
-> GenericPackageDescription
-> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageIdentifier -> String
packageIdentifierString (PackageIdentifier -> String)
-> (GenericPackageDescription -> PackageIdentifier)
-> GenericPackageDescription
-> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageDescription -> PackageIdentifier
package (PackageDescription -> PackageIdentifier)
-> (GenericPackageDescription -> PackageDescription)
-> GenericPackageDescription
-> PackageIdentifier
forall b c a. (b -> c) -> (a -> b) -> a -> c
. GenericPackageDescription -> PackageDescription
packageDescription
(GenericPackageDescription -> Text)
-> RIO EnvConfig GenericPackageDescription -> RIO EnvConfig Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Text
-> PackageLocation -> RIO EnvConfig GenericPackageDescription
forall env.
(HasPantryConfig env, HasLogFunc env, HasProcessContext env) =>
Maybe Text -> PackageLocation -> RIO env GenericPackageDescription
loadCabalFile (Text -> Maybe Text
forall a. a -> Maybe a
Just Text
stackProgName') PackageLocation
plm
Maybe DepPackage
Nothing -> do
String -> RIO EnvConfig ()
forall env (m :: * -> *).
(HasCallStack, HasTerm env, MonadReader env m, MonadIO m) =>
String -> m ()
prettyWarnS
String
"No hoogle version was found, trying to install the latest version"
Maybe PackageIdentifierRevision
mpir <- RequireHackageIndex
-> PackageName
-> UsePreferredVersions
-> RIO EnvConfig (Maybe PackageIdentifierRevision)
forall env.
(HasPantryConfig env, HasLogFunc env) =>
RequireHackageIndex
-> PackageName
-> UsePreferredVersions
-> RIO env (Maybe PackageIdentifierRevision)
getLatestHackageVersion RequireHackageIndex
YesRequireHackageIndex PackageName
hooglePackageName UsePreferredVersions
UsePreferredVersions
let hoogleIdent :: PackageIdentifier
hoogleIdent = case Maybe PackageIdentifierRevision
mpir of
Maybe PackageIdentifierRevision
Nothing -> PackageIdentifier
hoogleMinIdent
Just (PackageIdentifierRevision PackageName
_ Version
ver CabalFileInfo
_) ->
PackageName -> Version -> PackageIdentifier
PackageIdentifier PackageName
hooglePackageName Version
ver
String -> Text
T.pack (String -> Text)
-> (PackageIdentifier -> String) -> PackageIdentifier -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. PackageIdentifier -> String
packageIdentifierString (PackageIdentifier -> Text)
-> RIO EnvConfig PackageIdentifier -> RIO EnvConfig Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>
Muted -> PackageIdentifier -> RIO EnvConfig PackageIdentifier
forall env.
HasLogFunc env =>
Muted -> PackageIdentifier -> RIO env PackageIdentifier
restrictMinHoogleVersion Muted
muted PackageIdentifier
hoogleIdent
Config
config <- Getting Config EnvConfig Config -> RIO EnvConfig Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config EnvConfig Config
forall env. HasConfig env => Lens' env Config
Lens' EnvConfig Config
configL
let boptsCLI :: BuildOptsCLI
boptsCLI = BuildOptsCLI
defaultBuildOptsCLI
{ boptsCLITargets :: [Text]
boptsCLITargets = [Text
hoogleTarget]
}
Config -> RIO Config x -> RIO EnvConfig x
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO Config
config (RIO Config x -> RIO EnvConfig x)
-> RIO Config x -> RIO EnvConfig x
forall a b. (a -> b) -> a -> b
$ NeedTargets -> BuildOptsCLI -> RIO EnvConfig x -> RIO Config x
forall a.
NeedTargets -> BuildOptsCLI -> RIO EnvConfig a -> RIO Config a
withEnvConfig NeedTargets
NeedTargets BuildOptsCLI
boptsCLI RIO EnvConfig x
f
restrictMinHoogleVersion ::
HasLogFunc env
=> Muted
-> PackageIdentifier
-> RIO env PackageIdentifier
restrictMinHoogleVersion :: forall env.
HasLogFunc env =>
Muted -> PackageIdentifier -> RIO env PackageIdentifier
restrictMinHoogleVersion Muted
muted PackageIdentifier
ident =
if PackageIdentifier
ident PackageIdentifier -> PackageIdentifier -> Bool
forall a. Ord a => a -> a -> Bool
< PackageIdentifier
hoogleMinIdent
then do
LogLevel -> Muted -> Utf8Builder -> RIO env ()
forall env.
HasLogFunc env =>
LogLevel -> Muted -> Utf8Builder -> RIO env ()
muteableLog LogLevel
LevelWarn Muted
muted (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
Utf8Builder
"Minimum " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
String -> Utf8Builder
forall a. IsString a => String -> a
fromString (PackageIdentifier -> String
packageIdentifierString PackageIdentifier
hoogleMinIdent) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
Utf8Builder
" is not in your index. Installing the minimum version."
PackageIdentifier -> RIO env PackageIdentifier
forall a. a -> RIO env a
forall (f :: * -> *) a. Applicative f => a -> f a
pure PackageIdentifier
hoogleMinIdent
else do
LogLevel -> Muted -> Utf8Builder -> RIO env ()
forall env.
HasLogFunc env =>
LogLevel -> Muted -> Utf8Builder -> RIO env ()
muteableLog LogLevel
LevelInfo Muted
muted (Utf8Builder -> RIO env ()) -> Utf8Builder -> RIO env ()
forall a b. (a -> b) -> a -> b
$
Utf8Builder
"Minimum version is " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
String -> Utf8Builder
forall a. IsString a => String -> a
fromString (PackageIdentifier -> String
packageIdentifierString PackageIdentifier
hoogleMinIdent) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
Utf8Builder
". Found acceptable " Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
String -> Utf8Builder
forall a. IsString a => String -> a
fromString (PackageIdentifier -> String
packageIdentifierString PackageIdentifier
ident) Utf8Builder -> Utf8Builder -> Utf8Builder
forall a. Semigroup a => a -> a -> a
<>
Utf8Builder
" in your index, requiring its installation."
PackageIdentifier -> RIO env PackageIdentifier
forall a. a -> RIO env a
forall (f :: * -> *) a. Applicative f => a -> f a
pure PackageIdentifier
ident
muteableLog ::
HasLogFunc env
=> LogLevel
-> Muted
-> Utf8Builder
-> RIO env ()
muteableLog :: forall env.
HasLogFunc env =>
LogLevel -> Muted -> Utf8Builder -> RIO env ()
muteableLog LogLevel
logLevel Muted
muted Utf8Builder
msg =
case Muted
muted of
Muted
Muted -> () -> RIO env ()
forall a. a -> RIO env a
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
Muted
NotMuted -> Text -> LogLevel -> Utf8Builder -> RIO env ()
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasLogFunc env, HasCallStack) =>
Text -> LogLevel -> Utf8Builder -> m ()
logGeneric Text
"" LogLevel
logLevel Utf8Builder
msg
runHoogle :: Path Abs File -> [String] -> RIO EnvConfig ()
runHoogle :: Path Abs File -> [String] -> RIO EnvConfig ()
runHoogle Path Abs File
hooglePath [String]
hoogleArgs = do
Config
config <- Getting Config EnvConfig Config -> RIO EnvConfig Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config EnvConfig Config
forall env. HasConfig env => Lens' env Config
Lens' EnvConfig Config
configL
ProcessContext
menv <- IO ProcessContext -> RIO EnvConfig ProcessContext
forall a. IO a -> RIO EnvConfig a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ProcessContext -> RIO EnvConfig ProcessContext)
-> IO ProcessContext -> RIO EnvConfig ProcessContext
forall a b. (a -> b) -> a -> b
$ Config -> EnvSettings -> IO ProcessContext
configProcessContextSettings Config
config EnvSettings
envSettings
Path Abs File
dbpath <- RIO EnvConfig (Path Abs File)
forall env. HasEnvConfig env => RIO env (Path Abs File)
hoogleDatabasePath
let databaseArg :: [String]
databaseArg = [String
"--database=" String -> ShowS
forall a. [a] -> [a] -> [a]
++ Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
dbpath]
ProcessContext -> RIO EnvConfig () -> RIO EnvConfig ()
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv (RIO EnvConfig () -> RIO EnvConfig ())
-> RIO EnvConfig () -> RIO EnvConfig ()
forall a b. (a -> b) -> a -> b
$ String
-> [String]
-> (ProcessConfig () () () -> RIO EnvConfig ())
-> RIO EnvConfig ()
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc
(Path Abs File -> String
forall b t. Path b t -> String
toFilePath Path Abs File
hooglePath)
([String]
hoogleArgs [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
databaseArg)
ProcessConfig () () () -> RIO EnvConfig ()
forall (m :: * -> *) stdin stdout stderr.
MonadIO m =>
ProcessConfig stdin stdout stderr -> m ()
runProcess_
checkDatabaseExists :: RIO EnvConfig Bool
checkDatabaseExists = do
Path Abs File
path <- RIO EnvConfig (Path Abs File)
forall env. HasEnvConfig env => RIO env (Path Abs File)
hoogleDatabasePath
IO Bool -> RIO EnvConfig Bool
forall a. IO a -> RIO EnvConfig a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (Path Abs File -> IO Bool
forall (m :: * -> *) b. MonadIO m => Path b File -> m Bool
doesFileExist Path Abs File
path)
ensureHoogleInPath :: RIO EnvConfig (Path Abs File)
ensureHoogleInPath :: RIO EnvConfig (Path Abs File)
ensureHoogleInPath = do
Config
config <- Getting Config EnvConfig Config -> RIO EnvConfig Config
forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view Getting Config EnvConfig Config
forall env. HasConfig env => Lens' env Config
Lens' EnvConfig Config
configL
ProcessContext
menv <- IO ProcessContext -> RIO EnvConfig ProcessContext
forall a. IO a -> RIO EnvConfig a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ProcessContext -> RIO EnvConfig ProcessContext)
-> IO ProcessContext -> RIO EnvConfig ProcessContext
forall a b. (a -> b) -> a -> b
$ Config -> EnvSettings -> IO ProcessContext
configProcessContextSettings Config
config EnvSettings
envSettings
Maybe String
mHooglePath' <- Either ProcessException String -> Maybe String
forall a b. Either a b -> Maybe b
eitherToMaybe (Either ProcessException String -> Maybe String)
-> RIO EnvConfig (Either ProcessException String)
-> RIO EnvConfig (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ProcessContext
-> RIO ProcessContext (Either ProcessException String)
-> RIO EnvConfig (Either ProcessException String)
forall (m :: * -> *) env a. MonadIO m => env -> RIO env a -> m a
runRIO ProcessContext
menv (String -> RIO ProcessContext (Either ProcessException String)
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasProcessContext env) =>
String -> m (Either ProcessException String)
findExecutable String
"hoogle")
let mHooglePath'' :: RIO EnvConfig (Maybe String)
mHooglePath'' =
Either ProcessException String -> Maybe String
forall a b. Either a b -> Maybe b
eitherToMaybe (Either ProcessException String -> Maybe String)
-> RIO EnvConfig (Either ProcessException String)
-> RIO EnvConfig (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Muted
-> RIO EnvConfig (Either ProcessException String)
-> RIO EnvConfig (Either ProcessException String)
forall x. Muted -> RIO EnvConfig x -> RIO EnvConfig x
requiringHoogle Muted
NotMuted (String -> RIO EnvConfig (Either ProcessException String)
forall (m :: * -> *) env.
(MonadIO m, MonadReader env m, HasProcessContext env) =>
String -> m (Either ProcessException String)
findExecutable String
"hoogle")
Maybe String
mHooglePath <- RIO EnvConfig (Maybe String)
-> (String -> RIO EnvConfig (Maybe String))
-> Maybe String
-> RIO EnvConfig (Maybe String)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe RIO EnvConfig (Maybe String)
mHooglePath'' (Maybe String -> RIO EnvConfig (Maybe String)
forall a. a -> RIO EnvConfig a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Maybe String -> RIO EnvConfig (Maybe String))
-> (String -> Maybe String)
-> String
-> RIO EnvConfig (Maybe String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Maybe String
forall a. a -> Maybe a
Just) Maybe String
mHooglePath'
Either StyleDoc String
eres <- case Maybe String
mHooglePath of
Maybe String
Nothing -> Either StyleDoc String -> RIO EnvConfig (Either StyleDoc String)
forall a. a -> RIO EnvConfig a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either StyleDoc String -> RIO EnvConfig (Either StyleDoc String))
-> Either StyleDoc String -> RIO EnvConfig (Either StyleDoc String)
forall a b. (a -> b) -> a -> b
$ StyleDoc -> Either StyleDoc String
forall a b. a -> Either a b
Left (String -> StyleDoc
flow String
"Hoogle isn't installed.")
Just String
hooglePath -> do
Either SomeException ByteString
result <- ProcessContext
-> RIO EnvConfig (Either SomeException ByteString)
-> RIO EnvConfig (Either SomeException ByteString)
forall env a.
HasProcessContext env =>
ProcessContext -> RIO env a -> RIO env a
withProcessContext ProcessContext
menv
(RIO EnvConfig (Either SomeException ByteString)
-> RIO EnvConfig (Either SomeException ByteString))
-> RIO EnvConfig (Either SomeException ByteString)
-> RIO EnvConfig (Either SomeException ByteString)
forall a b. (a -> b) -> a -> b
$ String
-> [String]
-> (ProcessConfig () () ()
-> RIO EnvConfig (Either SomeException ByteString))
-> RIO EnvConfig (Either SomeException ByteString)
forall env (m :: * -> *) a.
(HasProcessContext env, HasLogFunc env, MonadReader env m,
MonadIO m, HasCallStack) =>
String -> [String] -> (ProcessConfig () () () -> m a) -> m a
proc String
hooglePath [String
"--numeric-version"]
((ProcessConfig () () ()
-> RIO EnvConfig (Either SomeException ByteString))
-> RIO EnvConfig (Either SomeException ByteString))
-> (ProcessConfig () () ()
-> RIO EnvConfig (Either SomeException ByteString))
-> RIO EnvConfig (Either SomeException ByteString)
forall a b. (a -> b) -> a -> b
$ RIO EnvConfig ByteString
-> RIO EnvConfig (Either SomeException ByteString)
forall (m :: * -> *) a.
MonadUnliftIO m =>
m a -> m (Either SomeException a)
tryAny (RIO EnvConfig ByteString
-> RIO EnvConfig (Either SomeException ByteString))
-> (ProcessConfig () () () -> RIO EnvConfig ByteString)
-> ProcessConfig () () ()
-> RIO EnvConfig (Either SomeException ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ByteString, ByteString) -> ByteString)
-> RIO EnvConfig (ByteString, ByteString)
-> RIO EnvConfig ByteString
forall a b. (a -> b) -> RIO EnvConfig a -> RIO EnvConfig b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteString, ByteString) -> ByteString
forall a b. (a, b) -> a
fst (RIO EnvConfig (ByteString, ByteString)
-> RIO EnvConfig ByteString)
-> (ProcessConfig () () ()
-> RIO EnvConfig (ByteString, ByteString))
-> ProcessConfig () () ()
-> RIO EnvConfig ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ProcessConfig () () () -> RIO EnvConfig (ByteString, ByteString)
forall (m :: * -> *) stdin stdoutIgnored stderrIgnored.
MonadIO m =>
ProcessConfig stdin stdoutIgnored stderrIgnored
-> m (ByteString, ByteString)
readProcess_
let unexpectedResult :: StyleDoc -> Either StyleDoc b
unexpectedResult StyleDoc
got = StyleDoc -> Either StyleDoc b
forall a b. a -> Either a b
Left (StyleDoc -> Either StyleDoc b) -> StyleDoc -> Either StyleDoc b
forall a b. (a -> b) -> a -> b
$
[StyleDoc] -> StyleDoc
fillSep
[ Style -> StyleDoc -> StyleDoc
style Style
Shell (String -> StyleDoc
forall a. IsString a => String -> a
fromString String
hooglePath)
, Style -> StyleDoc -> StyleDoc
style Style
Shell StyleDoc
"--numeric-version"
, String -> StyleDoc
flow String
"did not respond with expected value. Got:"
]
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
blankLine
StyleDoc -> StyleDoc -> StyleDoc
forall a. Semigroup a => a -> a -> a
<> StyleDoc
got
Either StyleDoc String -> RIO EnvConfig (Either StyleDoc String)
forall a. a -> RIO EnvConfig a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Either StyleDoc String -> RIO EnvConfig (Either StyleDoc String))
-> Either StyleDoc String -> RIO EnvConfig (Either StyleDoc String)
forall a b. (a -> b) -> a -> b
$ case Either SomeException ByteString
result of
Left SomeException
err -> StyleDoc -> Either StyleDoc String
forall {b}. StyleDoc -> Either StyleDoc b
unexpectedResult (StyleDoc -> Either StyleDoc String)
-> StyleDoc -> Either StyleDoc String
forall a b. (a -> b) -> a -> b
$ String -> StyleDoc
string (SomeException -> String
forall e. Exception e => e -> String
displayException SomeException
err)
Right ByteString
bs ->
case String -> Maybe Version
parseVersion ((Char -> Bool) -> ShowS
forall a. (a -> Bool) -> [a] -> [a]
takeWhile (Bool -> Bool
not (Bool -> Bool) -> (Char -> Bool) -> Char -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Bool
isSpace) (ByteString -> String
BL8.unpack ByteString
bs)) of
Maybe Version
Nothing -> StyleDoc -> Either StyleDoc String
forall {b}. StyleDoc -> Either StyleDoc b
unexpectedResult (StyleDoc -> Either StyleDoc String)
-> StyleDoc -> Either StyleDoc String
forall a b. (a -> b) -> a -> b
$ String -> StyleDoc
forall a. IsString a => String -> a
fromString (ByteString -> String
BL8.unpack ByteString
bs)
Just Version
ver
| Version
ver Version -> Version -> Bool
forall a. Ord a => a -> a -> Bool
>= Version
hoogleMinVersion -> String -> Either StyleDoc String
forall a b. b -> Either a b
Right String
hooglePath
| Bool
otherwise -> StyleDoc -> Either StyleDoc String
forall a b. a -> Either a b
Left (StyleDoc -> Either StyleDoc String)
-> StyleDoc -> Either StyleDoc String
forall a b. (a -> b) -> a -> b
$
[StyleDoc] -> StyleDoc
fillSep
[ String -> StyleDoc
flow String
"Installed Hoogle is too old, "
, Style -> StyleDoc -> StyleDoc
style Style
Shell (String -> StyleDoc
forall a. IsString a => String -> a
fromString String
hooglePath)
, String -> StyleDoc
flow String
"is version"
, String -> StyleDoc
forall a. IsString a => String -> a
fromString (Version -> String
versionString Version
ver)
, String -> StyleDoc
flow String
"but >= 5.0 is required."
]
case Either StyleDoc String
eres of
Right String
hooglePath -> String -> RIO EnvConfig (Path Abs File)
forall (m :: * -> *). MonadThrow m => String -> m (Path Abs File)
parseAbsFile String
hooglePath
Left StyleDoc
err
| Bool
setup -> do
[StyleDoc] -> RIO EnvConfig ()
forall env (m :: * -> *).
(HasCallStack, HasTerm env, MonadReader env m, MonadIO m) =>
[StyleDoc] -> m ()
prettyWarnL
[ StyleDoc
err
, String -> StyleDoc
flow String
"Automatically installing (use"
, Style -> StyleDoc -> StyleDoc
style Style
Shell StyleDoc
"--no-setup"
, String -> StyleDoc
flow String
"to disable) ..."
]
RIO EnvConfig (Path Abs File)
installHoogle
| Bool
otherwise -> HooglePrettyException -> RIO EnvConfig (Path Abs File)
forall e (m :: * -> *) a.
(Exception e, MonadIO m, Pretty e) =>
e -> m a
prettyThrowIO (HooglePrettyException -> RIO EnvConfig (Path Abs File))
-> HooglePrettyException -> RIO EnvConfig (Path Abs File)
forall a b. (a -> b) -> a -> b
$ StyleDoc -> HooglePrettyException
HoogleNotFound StyleDoc
err
envSettings :: EnvSettings
envSettings =
EnvSettings
{ esIncludeLocals :: Bool
esIncludeLocals = Bool
True
, esIncludeGhcPackagePath :: Bool
esIncludeGhcPackagePath = Bool
True
, esStackExe :: Bool
esStackExe = Bool
True
, esLocaleUtf8 :: Bool
esLocaleUtf8 = Bool
False
, esKeepGhcRts :: Bool
esKeepGhcRts = Bool
False
}