generateHaddockIndex
    :: (MonadIO m, MonadCatch m, MonadThrow m, MonadLogger m, MonadBaseControl IO m)
    => Text
    -> EnvOverride
    -> WhichCompiler
    -> [PackageIdentifier]
    -> FilePath
    -> Path Abs Dir
    -> m ()
generateHaddockIndex descr envOverride wc packageIDs docRelDir destDir = do
    createTree destDir
    interfaceOpts <- liftIO $ fmap catMaybes (mapM toInterfaceOpt packageIDs)
    case maximumMay (map snd interfaceOpts) of
        Nothing -> return ()
        Just maxInterfaceModTime -> do
            eindexModTime <-
                liftIO $
                tryJust (guard . isDoesNotExistError) $
                getModificationTime (toFilePath (haddockIndexFile destDir))
            let needUpdate =
                    case eindexModTime of
                        Left _ -> True
                        Right indexModTime ->
                            indexModTime < maxInterfaceModTime
            when
                needUpdate $
                do $logInfo
                       ("Updating Haddock index for " <> descr <> " in\n" <>
                        T.pack (toFilePath (haddockIndexFile destDir)))
                   readProcessNull
                       (Just destDir)
                       envOverride
                       (haddockExeName wc)
                       (["--gen-contents", "--gen-index"] ++ concatMap fst interfaceOpts)
  where
    toInterfaceOpt pid@(PackageIdentifier name _) = do
        let interfaceRelFile =
                docRelDir FP.</> packageIdentifierString pid FP.</>
                packageNameString name FP.<.>
                "haddock"
            interfaceAbsFile = toFilePath destDir FP.</> interfaceRelFile
        einterfaceModTime <-
            tryJust (guard . isDoesNotExistError) $
            getModificationTime interfaceAbsFile
        return $
            case einterfaceModTime of
                Left _ -> Nothing
                Right interfaceModTime ->
                    Just
                        ( [ "-i"
                          , concat
                                [ docRelDir FP.</> packageIdentifierString pid
                                , ","
                                , interfaceRelFile]]
                        , interfaceModTime)

-- | Path of haddock index file.
generateHaddockIndex
    :: (MonadIO m, MonadCatch m, MonadThrow m, MonadLogger m, MonadBaseControl IO m)
    => Text
    -> EnvOverride
    -> WhichCompiler
    -> [PackageIdentifier]
    -> FilePath
    -> Path Abs Dir
    -> m ()
generateHaddockIndex descr envOverride wc packageIDs docRelDir destDir = do
    createTree destDir
    interfaceOpts <- liftIO $ fmap catMaybes (mapM toInterfaceOpt packageIDs)
    case maximumMay (map snd interfaceOpts) of
        Nothing -> return ()
        Just maxInterfaceModTime -> do
            eindexModTime <-
                liftIO $
                tryJust (guard . isDoesNotExistError) $
                getModificationTime (toFilePath (haddockIndexFile destDir))
            let needUpdate =
                    case eindexModTime of
                        Left _ -> True
                        Right indexModTime ->
                            indexModTime < maxInterfaceModTime
            when
                needUpdate $
                do $logInfo
                       ("Updating Haddock index for " <> descr <> " in\n" <>
                        T.pack (toFilePath (haddockIndexFile destDir)))
                   readProcessNull
                       (Just destDir)
                       envOverride
                       (haddockExeName wc)
                       (["--gen-contents", "--gen-index"] ++ concatMap fst interfaceOpts)
  where
    toInterfaceOpt pid@(PackageIdentifier name _) = do
        let interfaceRelFile =
                docRelDir FP.</> packageIdentifierString pid FP.</>
                packageNameString name FP.<.>
                "haddock"
            interfaceAbsFile = toFilePath destDir FP.</> interfaceRelFile
        einterfaceModTime <-
            tryJust (guard . isDoesNotExistError) $
            getModificationTime interfaceAbsFile
        return $
            case einterfaceModTime of
                Left _ -> Nothing
                Right interfaceModTime ->
                    Just
                        ( [ "-i"
                          , concat
                                [ docRelDir FP.</> packageIdentifierString pid
                                , ","
                                , interfaceRelFile]]
                        , interfaceModTime)

-- | Path of haddock index file.
generateHaddockIndex descr envOverride wc packageIDs docRelDir destDir = do
    createTree destDir
    interfaceOpts <- liftIO $ fmap catMaybes (mapM toInterfaceOpt packageIDs)
    case maximumMay (map snd interfaceOpts) of
        Nothing -> return ()
        Just maxInterfaceModTime -> do
            eindexModTime <-
                liftIO $
                tryJust (guard . isDoesNotExistError) $
                getModificationTime (toFilePath (haddockIndexFile destDir))
            let needUpdate =
                    case eindexModTime of
                        Left _ -> True
                        Right indexModTime ->
                            indexModTime < maxInterfaceModTime
            when
                needUpdate $
                do $logInfo
                       ("Updating Haddock index for " <> descr <> " in\n" <>
                        T.pack (toFilePath (haddockIndexFile destDir)))
                   readProcessNull
                       (Just destDir)
                       envOverride
                       (haddockExeName wc)
                       (["--gen-contents", "--gen-index"] ++ concatMap fst interfaceOpts)
  where
    toInterfaceOpt pid@(PackageIdentifier name _) = do
        let interfaceRelFile =
                docRelDir FP.</> packageIdentifierString pid FP.</>
                packageNameString name FP.<.>
                "haddock"
            interfaceAbsFile = toFilePath destDir FP.</> interfaceRelFile
        einterfaceModTime <-
            tryJust (guard . isDoesNotExistError) $
            getModificationTime interfaceAbsFile
        return $
            case einterfaceModTime of
                Left _ -> Nothing
                Right interfaceModTime ->
                    Just
                        ( [ "-i"
                          , concat
                                [ docRelDir FP.</> packageIdentifierString pid
                                , ","
                                , interfaceRelFile]]
                        , interfaceModTime)

-- | Path of haddock index file.