{-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE TupleSections #-} module Main ( main ) where import Control.Applicative import Control.Monad import Data.Foldable (asum) import System.FilePath import System.Directory import System.IO.Error import qualified Data.Text as T import qualified Data.Text.IO as T import Data.Maybe import Options.Applicative import Documentation.Haddocset import Documentation.Haddocset.Index import Documentation.Haddocset.Plist createCommand :: Options -> IO () createCommand o = do unless (optQuiet o) $ putStrLn "[1/5] Create Directory." createDirectory (optTarget o) -- for fail when directory already exists. createDirectoryIfMissing True (optDocumentsDir o) createDirectoryIfMissing False (optHaddockDir o) unless (optQuiet o) $ putStrLn "[2/5] Writing plist." T.writeFile (optTarget o "Contents/Info.plist") $ showPlist (createPlist $ optCommand o) unless (optQuiet o) $ putStrLn "[3/5] Migrate Database." withSearchIndex (optTarget o "Contents/Resources/docSet.dsidx") $ \idx -> do globalDirs <- globalPackageDirectories (optHcPkg o) unless (optQuiet o) $ do putStr " Global package directory: " putStr (head globalDirs) if length globalDirs > 1 then putStr " and " >> putStr (show . pred $ length globalDirs) >> putStrLn "directories." else putStrLn "" globals <- concat <$> mapM (\d -> map (d ) <$> packageConfs d) globalDirs let locals = toAddFiles $ optCommand o iFiles <- filter diExposed . catMaybes <$> mapM readDocInfoFile (globals ++ locals) unless (optQuiet o) $ putStr " Global package count: " >> print (length globals) unless (optQuiet o) $ putStrLn "[4/5] Copy and populate Documents." forM_ iFiles $ \iFile -> addSinglePackage (optQuiet o) Fail (optDocumentsDir o) (optHaddockDir o) idx iFile unless (optQuiet o) $ putStrLn "[5/5] Create index." haddockIndex (optHaddockDir o) (optDocumentsDir o) addCommand :: Options -> ResolutionStrategy -> IO () addCommand o resolution = withSearchIndex (optTarget o "Contents/Resources/docSet.dsidx") $ \idx -> do forM_ (toAddFiles $ optCommand o) $ \i -> go idx i `catchIOError` handler haddockIndex (optHaddockDir o) (optDocumentsDir o) where go idx p = readDocInfoFile p >>= \mbIFile -> case mbIFile of Nothing -> return () Just iFile -> addSinglePackage (optQuiet o) resolution (optDocumentsDir o) (optHaddockDir o) idx iFile handler ioe | isDoesNotExistError ioe = print ioe | otherwise = ioError ioe listCommand :: Options -> IO () listCommand o = mapM_ (putStrLn . dropExtension . takeFileName) =<< getDirectoryContents (optHaddockDir o) data Options = Options { optHcPkg :: String , optTarget :: FilePath , optQuiet :: Bool , optCommand :: Command } deriving Show optHaddockDir, optDocumentsDir :: Options -> FilePath optHaddockDir opt = optTarget opt "Contents/Resources/Haddock/" optDocumentsDir opt = optTarget opt "Contents/Resources/Documents/" data Command = Create { createPlist :: Plist, toAddFiles :: [FilePath] } | List | Add { toAddFiles :: [FilePath] , resolution :: ResolutionStrategy } deriving Show main :: IO () main = do opts <- execParser optRule case opts of Options{optCommand = Create{}} -> createCommand opts Options{optCommand = List} -> listCommand opts Options{optCommand = Add{resolution}} -> addCommand opts resolution where optRule = info (helper <*> options) fullDesc options = Options <$> (strOption (long "hc-pkg" <> metavar "CMD" <> help "hc-pkg command (default: ghc-pkg)") <|> pure "ghc-pkg") <*> fmap docsetDir (strOption (long "target" <> short 't' <> metavar "DOCSET" <> help "output directory (default: haskell.docset)") <|> pure "haskell") <*> switch (long "quiet" <> short 'q' <> help "suppress output.") <*> subparser (command "create" (info createOpts $ progDesc "create new docset.") <> command "list" (info (pure List) $ progDesc "list package of docset.") <> command "add" (info addOpts $ progDesc "add package to docset.")) createOpts = Create <$> ( Plist <$> (textOption (long "CFBundleIdentifier") <|> pure "haskell") <*> (textOption (long "CFBundleName") <|> pure "Haskell") <*> (textOption (long "DocSetPlatformFamily") <|> pure "haskell")) <*> many (argument str (metavar "CONFS" <> help "path to installed package configuration.")) addOpts = Add <$> some (argument str (metavar "CONFS" <> help "path to installed package configuration.")) <*> asum [ flag' Overwrite (long "force" <> short 'f' <> help "overwrite exist package.") , flag' Skip (long "skip" <> short 's' <> help "skip existing packages") , pure Fail ] textOption = fmap T.pack . strOption