{-# LANGUAGE CPP, ScopedTypeVariables #-} {- Copyright (C) 2009 John MacFarlane 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 -} {- Utility functions for Gitit. -} module Network.Gitit.Util ( readFileUTF8 , inDir , withTempDir , orIfNull , splitCategories , trim , yesOrNo , parsePageType , encUrl , getPageTypeDefaultExtensions ) where import System.Directory import Control.Exception (bracket) import System.FilePath ((), (<.>)) import System.IO.Error (isAlreadyExistsError) import Control.Monad.Trans (liftIO) import Data.Char (toLower, isAscii) import Data.Text (Text) import qualified Data.Text as T import Network.Gitit.Types import qualified Control.Exception as E import qualified Text.Pandoc.UTF8 as UTF8 import Text.Pandoc (Extension(..), Extensions, getDefaultExtensions, enableExtension) import Network.URL (encString) -- | Read file as UTF-8 string. Encode filename as UTF-8. readFileUTF8 :: FilePath -> IO Text readFileUTF8 = fmap T.pack . UTF8.readFile -- | Perform a function a directory and return to working directory. inDir :: FilePath -> IO a -> IO a inDir d action = do w <- getCurrentDirectory setCurrentDirectory d result <- action setCurrentDirectory w return result -- | Perform a function in a temporary directory and clean up. withTempDir :: FilePath -> (FilePath -> IO a) -> IO a withTempDir baseName f = do oldDir <- getCurrentDirectory bracket (createTempDir 0 baseName) (\tmp -> setCurrentDirectory oldDir >> removeDirectoryRecursive tmp) f -- | Create a temporary directory with a unique name. createTempDir :: Integer -> FilePath -> IO FilePath createTempDir num baseName = do sysTempDir <- getTemporaryDirectory let dirName = sysTempDir baseName <.> show num liftIO $ E.catch (createDirectory dirName >> return dirName) $ \e -> if isAlreadyExistsError e then createTempDir (num + 1) baseName else ioError e -- | Returns a list, if it is not null, or a backup, if it is. orIfNull :: [a] -> [a] -> [a] orIfNull lst backup = if null lst then backup else lst -- | Split a string containing a list of categories. splitCategories :: String -> [String] splitCategories = words . map puncToSpace . trim where puncToSpace x | x `elem` ".,;:" = ' ' puncToSpace x = x -- | Trim leading and trailing spaces. trim :: String -> String trim = reverse . trimLeft . reverse . trimLeft where trimLeft = dropWhile (`elem` " \t") -- | Show Bool as "yes" or "no". yesOrNo :: Bool -> String yesOrNo True = "yes" yesOrNo False = "no" parsePageType :: String -> (PageType, Bool) parsePageType s = case map toLower s of "markdown" -> (Markdown,False) "markdown+lhs" -> (Markdown,True) "commonmark" -> (CommonMark,False) "docbook" -> (DocBook,False) "rst" -> (RST,False) "rst+lhs" -> (RST,True) "html" -> (HTML,False) "textile" -> (Textile,False) "latex" -> (LaTeX,False) "latex+lhs" -> (LaTeX,True) "org" -> (Org,False) "mediawiki" -> (MediaWiki,False) x -> error $ "Unknown page type: " ++ x getPageTypeDefaultExtensions :: PageType -> Bool -> Extensions getPageTypeDefaultExtensions pt lhs = if lhs then enableExtension Ext_literate_haskell defaults else defaults where defaults = getDefaultExtensions $ case pt of CommonMark -> "commonmark" DocBook -> "docbook" HTML -> "html" LaTeX -> "latex" Markdown -> "markdown" MediaWiki -> "mediawiki" Org -> "org" RST -> "rst" Textile -> "textile" encUrl :: String -> String encUrl = encString True isAscii