    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 Text
    pkgName = do
      (exitcode, stdout, _) <-
          String -> [String] -> String -> IO (ExitCode, String, String)
    readProcessWithExitCode String
    "pkg-config" [String
    "--modversion", Text -> String
    T.unpack Text
    pkgName] String
    ""
      case exitcode of
        ExitCode
    ExitSuccess -> case String -> [String]
    lines String
    stdout of
                         [String
    v] -> Maybe (Text, Text) -> IO (Maybe (Text, Text))
    forall a. a -> IO a
    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))
                         [String]
    _ -> Maybe (Text, Text) -> IO (Maybe (Text, Text))
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (Text, Text)
    forall a. Maybe a
    Nothing
        ExitFailure Int
    _ -> Maybe (Text, Text) -> IO (Maybe (Text, Text))
    forall a. a -> IO a
    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 Text
    name Text
    version [Text]
    packages Bool
    verbose 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 (Text
    "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
    <>
                                  Text
    " 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
                           Maybe Text
    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 -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    version,
                                                   Text
    lowerName]
                           Just Text
    n -> [Text
    n Text -> Text -> Text
    forall a. Semigroup a => a -> a -> a
    <> Text
    "-" 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)
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [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 a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Maybe (Text, Text) -> IO (Maybe (Text, Text))
    forall a. a -> IO a
    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