    {-# LANGUAGE CPP #-}
    {-
    Copyright (C) 2009 John MacFarlane <jgm@berkeley.edu>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    -}

    {- Functions for loading plugins.
    -}

    module Network.Gitit.Plugins ( loadPlugin, loadPlugins )
    where
    import Network.Gitit.Types
    import System.FilePath (takeBaseName)
    import Control.Monad (unless)
    import System.Log.Logger (logM, Priority(..))
    #ifdef _PLUGINS
    import Data.List (isInfixOf, isPrefixOf)
    import GHC
    import GHC.Paths
    import Unsafe.Coerce

    loadPlugin :: FilePath -> IO Plugin
    loadPlugin :: FilePath -> IO Plugin
    loadPlugin FilePath
    pluginName = do
      FilePath -> Priority -> FilePath -> IO ()
    logM FilePath
    "gitit" Priority
    WARNING (FilePath
    "Loading plugin '" FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    pluginName FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    "'...")
      Maybe FilePath -> Ghc Plugin -> IO Plugin
    forall a. Maybe FilePath -> Ghc a -> IO a
    runGhc (FilePath -> Maybe FilePath
    forall a. a -> Maybe a
    Just FilePath
    libdir) (Ghc Plugin -> IO Plugin) -> Ghc Plugin -> IO Plugin
    forall a b. (a -> b) -> a -> b
    $ do
        dflags <- Ghc DynFlags
    forall (m :: * -> *). GhcMonad m => m DynFlags
    getSessionDynFlags
        setSessionDynFlags dflags
        -- initDynFlags
        unless ("Network.Gitit.Plugin." `isPrefixOf` pluginName)
          $ do
    #if __GLASGOW_HASKELL__ >= 904
              addTarget =<< guessTarget pluginName Nothing Nothing
    #else
              addTarget =<< guessTarget pluginName Nothing
    #endif
              r <- load LoadAllTargets
              case r of
                SuccessFlag
    Failed -> FilePath -> Ghc ()
    forall a. HasCallStack => FilePath -> a
    error (FilePath -> Ghc ()) -> FilePath -> Ghc ()
    forall a b. (a -> b) -> a -> b
    $ FilePath
    "Error loading plugin: " FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath
    pluginName
                SuccessFlag
    Succeeded -> () -> Ghc ()
    forall a. a -> Ghc a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
        let modName =
              if FilePath
    "Network.Gitit.Plugin" FilePath -> FilePath -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isPrefixOf` FilePath
    pluginName
                 then FilePath
    pluginName
                 else if FilePath
    "Network/Gitit/Plugin/" FilePath -> FilePath -> Bool
    forall a. Eq a => [a] -> [a] -> Bool
    `isInfixOf` FilePath
    pluginName
                         then FilePath
    "Network.Gitit.Plugin." FilePath -> FilePath -> FilePath
    forall a. [a] -> [a] -> [a]
    ++ FilePath -> FilePath
    takeBaseName FilePath
    pluginName
                         else FilePath -> FilePath
    takeBaseName FilePath
    pluginName
        pr <- parseImportDecl "import Prelude"
        i <- parseImportDecl "import Network.Gitit.Interface"
        m <- parseImportDecl ("import " ++ modName)
        setContext [IIDecl m, IIDecl  i, IIDecl pr]
        value <- compileExpr (modName ++ ".plugin :: Plugin")
        let value' = (HValue -> Plugin
    forall a b. a -> b
    unsafeCoerce HValue
    value) :: Plugin
        return value'

    #else

    loadPlugin :: FilePath -> IO Plugin
    loadPlugin pluginName = do
      error $ "Cannot load plugin '" ++ pluginName ++
              "'. gitit was not compiled with plugin support."
      return undefined

    #endif

    loadPlugins :: [FilePath] -> IO [Plugin]
    loadPlugins :: [FilePath] -> IO [Plugin]
    loadPlugins [FilePath]
    pluginNames = do
      plugins' <- (FilePath -> IO Plugin) -> [FilePath] -> IO [Plugin]
    forall (t :: * -> *) (m :: * -> *) a b.
    (Traversable t, Monad m) =>
    (a -> m b) -> t a -> m (t b)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM FilePath -> IO Plugin
    loadPlugin [FilePath]
    pluginNames
      unless (null pluginNames) $ logM "gitit" WARNING "Finished loading plugins."
      return plugins'