module Data.GI.GIR.Repository (readGiRepository) where
import Prelude hiding (readFile)
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
#endif
import Control.Monad (when)
import Data.Maybe
import qualified Data.List as List
import qualified Data.Text as T
import Data.Text (Text)
import Safe (maximumMay)
import qualified Text.XML as XML
import System.Directory
import System.Environment (lookupEnv)
import System.Environment.XDG.BaseDir (getSystemDataDirs)
import System.FilePath (searchPathSeparator, takeBaseName, (</>), (<.>))
girFilePath :: String -> String -> FilePath -> FilePath
girFilePath :: String -> String -> String -> String
girFilePath String
name String
version String
path = String
path String -> String -> String
</> String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
version String -> String -> String
<.> String
"gir"
girFile' :: Text -> Maybe Text -> FilePath -> IO (Maybe FilePath)
girFile' :: Text -> Maybe Text -> String -> IO (Maybe String)
girFile' Text
name (Just Text
version) String
path =
let filePath :: String
filePath = String -> String -> String -> String
girFilePath (Text -> String
T.unpack Text
name) (Text -> String
T.unpack Text
version) String
path
in String -> IO Bool
doesFileExist String
filePath IO Bool -> (Bool -> IO (Maybe String)) -> IO (Maybe String)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Bool
True -> Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe String -> IO (Maybe String))
-> Maybe String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ String -> Maybe String
forall a. a -> Maybe a
Just String
filePath
Bool
False -> Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
forall a. Maybe a
Nothing
girFile' Text
name Maybe Text
Nothing String
path =
String -> IO Bool
doesDirectoryExist String
path IO Bool -> (Bool -> IO (Maybe String)) -> IO (Maybe String)
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Bool
True -> do
[String]
repositories <- (String -> String) -> [String] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map String -> String
takeBaseName ([String] -> [String]) -> IO [String] -> IO [String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> String -> IO [String]
getDirectoryContents String
path
let version :: Maybe String
version = [String] -> Maybe String
forall a. Ord a => [a] -> Maybe a
maximumMay ([String] -> Maybe String)
-> ([Maybe String] -> [String]) -> [Maybe String] -> Maybe String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe String] -> [String]
forall a. [Maybe a] -> [a]
catMaybes ([Maybe String] -> Maybe String) -> [Maybe String] -> Maybe String
forall a b. (a -> b) -> a -> b
$
String -> String -> Maybe String
forall a. Eq a => [a] -> [a] -> Maybe [a]
List.stripPrefix (Text -> String
T.unpack Text
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"-") (String -> Maybe String) -> [String] -> [Maybe String]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> [String]
repositories
Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe String -> IO (Maybe String))
-> Maybe String -> IO (Maybe String)
forall a b. (a -> b) -> a -> b
$ case Maybe String
version of
Just String
v -> String -> Maybe String
forall a. a -> Maybe a
Just (String -> Maybe String) -> String -> Maybe String
forall a b. (a -> b) -> a -> b
$ String -> String -> String -> String
girFilePath (Text -> String
T.unpack Text
name) String
v String
path
Maybe String
Nothing -> Maybe String
forall a. Maybe a
Nothing
Bool
False -> Maybe String -> IO (Maybe String)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe String
forall a. Maybe a
Nothing
splitOn :: Eq a => a -> [a] -> [[a]]
splitOn :: a -> [a] -> [[a]]
splitOn a
x [a]
xs = [a] -> [a] -> [[a]]
go [a]
xs []
where go :: [a] -> [a] -> [[a]]
go [] [a]
acc = [[a] -> [a]
forall a. [a] -> [a]
reverse [a]
acc]
go (a
y : [a]
ys) [a]
acc = if a
x a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
y
then [a] -> [a]
forall a. [a] -> [a]
reverse [a]
acc [a] -> [[a]] -> [[a]]
forall a. a -> [a] -> [a]
: [a] -> [a] -> [[a]]
go [a]
ys []
else [a] -> [a] -> [[a]]
go [a]
ys (a
y a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
acc)
girDataDirs :: IO [FilePath]
girDataDirs :: IO [String]
girDataDirs = String -> IO [String]
getSystemDataDirs String
"gir-1.0"
buildSearchPath :: [FilePath] -> IO [FilePath]
buildSearchPath :: [String] -> IO [String]
buildSearchPath [String]
extraPaths = do
[String]
paths <- case [String]
extraPaths of
[] -> String -> IO (Maybe String)
lookupEnv String
"HASKELL_GI_GIR_SEARCH_PATH" IO (Maybe String) -> (Maybe String -> IO [String]) -> IO [String]
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Maybe String
Nothing -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return []
Just String
s -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return (Char -> String -> [String]
forall a. Eq a => a -> [a] -> [[a]]
splitOn Char
searchPathSeparator String
s)
[String]
ps -> [String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return [String]
ps
[String]
dataDirs <- IO [String]
girDataDirs
[String] -> IO [String]
forall (m :: * -> *) a. Monad m => a -> m a
return ([String]
paths [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ [String]
dataDirs)
girFile :: Text -> Maybe Text -> [FilePath] -> IO (Maybe FilePath)
girFile :: Text -> Maybe Text -> [String] -> IO (Maybe String)
girFile Text
name Maybe Text
version [String]
searchPath =
[Maybe String] -> Maybe String
forall a. [Maybe a] -> Maybe a
firstJust ([Maybe String] -> Maybe String)
-> IO [Maybe String] -> IO (Maybe String)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((String -> IO (Maybe String)) -> [String] -> IO [Maybe String]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM (Text -> Maybe Text -> String -> IO (Maybe String)
girFile' Text
name Maybe Text
version) [String]
searchPath)
where firstJust :: [Maybe a] -> Maybe a
firstJust = [a] -> Maybe a
forall a. [a] -> Maybe a
listToMaybe ([a] -> Maybe a) -> ([Maybe a] -> [a]) -> [Maybe a] -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe a] -> [a]
forall a. [Maybe a] -> [a]
catMaybes
readGiRepository :: Bool
-> Text
-> Maybe Text
-> [FilePath]
-> IO XML.Document
readGiRepository :: Bool -> Text -> Maybe Text -> [String] -> IO Document
readGiRepository Bool
verbose Text
name Maybe Text
version [String]
extraPaths = do
[String]
searchPath <- [String] -> IO [String]
buildSearchPath [String]
extraPaths
Text -> Maybe Text -> [String] -> IO (Maybe String)
girFile Text
name Maybe Text
version [String]
searchPath IO (Maybe String) -> (Maybe String -> IO Document) -> IO Document
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
Just String
path -> do
Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
verbose (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ String -> IO ()
putStrLn (String -> IO ()) -> String -> IO ()
forall a b. (a -> b) -> a -> b
$ String
"Loading GI repository: " String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
path
ParseSettings -> String -> IO Document
XML.readFile ParseSettings
forall a. Default a => a
XML.def String
path
Maybe String
Nothing -> String -> IO Document
forall a. HasCallStack => String -> a
error (String -> IO Document) -> String -> IO Document
forall a b. (a -> b) -> a -> b
$ String
"Did not find a GI repository for "
String -> String -> String
forall a. [a] -> [a] -> [a]
++ (Text -> String
T.unpack Text
name)
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String -> (String -> String) -> Maybe String -> String
forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"" (String
"-" String -> String -> String
forall a. [a] -> [a] -> [a]
++) (Text -> String
T.unpack (Text -> String) -> Maybe Text -> Maybe String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Maybe Text
version)
String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
" in " String -> String -> String
forall a. [a] -> [a] -> [a]
++ [String] -> String
forall a. Show a => a -> String
show [String]
searchPath String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
"."