module Data.GI.CodeGen.PkgConfig
    ( pkgConfigGetVersion
    , tryPkgConfig
    ) where

import Control.Monad (when)
#if !MIN_VERSION_base(4,11,0)
import Data.Monoid (First(..), (<>))
#else
import Data.Monoid (First(..))
#endif
import qualified Data.Map.Strict as M
import qualified Data.Text as T
import Data.Text (Text)
import System.Exit (ExitCode(..))
import System.Process (readProcessWithExitCode)

-- | Try asking pkg-config for the version of a given module, and
-- return the package name together with its version.
tryPkgConfig :: Text -> IO (Maybe (Text, Text))
tryPkgConfig :: Text -> IO (Maybe (Text, Text))
tryPkgConfig pkgName :: Text
pkgName = do
  (exitcode :: ExitCode
exitcode, stdout :: String
stdout, _) <-
      String -> [String] -> String -> IO (ExitCode, String, String)
readProcessWithExitCode "pkg-config" ["--modversion", Text -> String
T.unpack Text
pkgName] ""
  case ExitCode
exitcode of
    ExitSuccess -> case String -> [String]
lines String
stdout of
                     [v :: String
v] -> Maybe (Text, Text) -> IO (Maybe (Text, Text))
forall (m :: * -> *) a. Monad m => a -> m a
return ((Text, Text) -> Maybe (Text, Text)
forall a. a -> Maybe a
Just (Text
pkgName, String -> Text
T.pack String
v))
                     _ -> Maybe (Text, Text) -> IO (Maybe (Text, Text))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Text, Text)
forall a. Maybe a
Nothing
    ExitFailure _ -> Maybe (Text, Text) -> IO (Maybe (Text, Text))
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe (Text, Text)
forall a. Maybe a
Nothing

-- | Get the pkg-config name and associated installed version of a given
-- gobject-introspection namespace. Since the mapping is not
-- one-to-one some guessing is involved, although in most cases the
-- required information is listed in the GIR file.
pkgConfigGetVersion :: Text     -- name
                    -> Text     -- version
                    -> [Text]   -- known package names
                    -> Bool     -- verbose
                    -> M.Map Text Text -- suggested overrides
                    -> IO (Maybe (Text, Text))
pkgConfigGetVersion :: Text
-> Text
-> [Text]
-> Bool
-> Map Text Text
-> IO (Maybe (Text, Text))
pkgConfigGetVersion name :: Text
name version :: Text
version packages :: [Text]
packages verbose :: Bool
verbose overridenNames :: Map Text Text
overridenNames = do
  let lowerName :: Text
lowerName = Text -> Text
T.toLower Text
name
  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
$ Text -> String
T.unpack ("Querying pkg-config for " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
name Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<>
                              " version " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
version)
  let alternatives :: [Text]
alternatives = case Text -> Map Text Text -> Maybe Text
forall k a. Ord k => k -> Map k a -> Maybe a
M.lookup Text
lowerName Map Text Text
overridenNames of
                       Nothing -> [Text]
packages [Text] -> [Text] -> [Text]
forall a. [a] -> [a] -> [a]
++ [Text
lowerName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
version,
                                               Text
lowerName]
                       Just n :: Text
n -> [Text
n Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> "-" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
version, Text
n]
      firstJust :: [Maybe a] -> Maybe a
firstJust = First a -> Maybe a
forall a. First a -> Maybe a
getFirst (First a -> Maybe a)
-> ([Maybe a] -> First a) -> [Maybe a] -> Maybe a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [First a] -> First a
forall a. Monoid a => [a] -> a
mconcat ([First a] -> First a)
-> ([Maybe a] -> [First a]) -> [Maybe a] -> First a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Maybe a -> First a) -> [Maybe a] -> [First a]
forall a b. (a -> b) -> [a] -> [b]
map Maybe a -> First a
forall a. Maybe a -> First a
First
  (Text -> IO (Maybe (Text, Text)))
-> [Text] -> IO [Maybe (Text, Text)]
forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM Text -> IO (Maybe (Text, Text))
tryPkgConfig [Text]
alternatives IO [Maybe (Text, Text)]
-> ([Maybe (Text, Text)] -> IO (Maybe (Text, Text)))
-> IO (Maybe (Text, Text))
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Maybe (Text, Text) -> IO (Maybe (Text, Text))
forall (m :: * -> *) a. Monad m => a -> m a
return (Maybe (Text, Text) -> IO (Maybe (Text, Text)))
-> ([Maybe (Text, Text)] -> Maybe (Text, Text))
-> [Maybe (Text, Text)]
-> IO (Maybe (Text, Text))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Maybe (Text, Text)] -> Maybe (Text, Text)
forall a. [Maybe a] -> Maybe a
firstJust