packages feed

autonix-deps-kf5-0.1.0.0: src/Autonix/KF5.hs

{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TemplateHaskell #-}

module Autonix.KF5 where

import Control.Lens
import Control.Monad.IO.Class
import Control.Monad.State
import qualified Data.ByteString.Char8 as B
import Data.Conduit
import Data.List (isPrefixOf)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.Monoid
import qualified Data.Set as S
import System.FilePath (takeBaseName, takeExtensions, takeFileName)

import Autonix.Analyze
import Autonix.CMake
import Autonix.Deps
import Autonix.Regex

printFilePaths :: MonadIO m => Analyzer m
printFilePaths _ = awaitForever $ \(path, _) -> liftIO $ putStrLn path

renameKF5Pkgs :: (MonadIO m, MonadState Deps m) => Analyzer m
renameKF5Pkgs pkg = awaitForever $ \(path, contents) ->
    when (takeFileName path == "metainfo.yaml") $ do
        let regex = makeRegex "cmakename:[[:space:]]*([[:alnum:]]*)"
            matches = match regex contents
        case matches of
            ((_ : cmakeName : _) : _) -> rename cmakeName pkg
            _ -> return ()

propagateKF5Deps :: (MonadIO m, MonadState Deps m) => Analyzer m
propagateKF5Deps newPkg = awaitForever $ \(path, contents) ->
    when (".cmake" `isPrefixOf` takeExtensions path) $ do
        let base = takeBaseName $ takeBaseName path
            regex = makeRegex
                    "find_dependency[[:space:]]*\\([[:space:]]*\
                    \([^[:space:],$\\)]+)"
        case splitAt (length base - 6) base of
            (oldPkg, "Config") -> do
                let new = concatMap (take 1 . drop 1) $ match regex contents
                rename (B.pack oldPkg) newPkg
                at newPkg %=
                    Just
                    . (propagatedBuildInputs %~ S.union (S.fromList new))
                    . fromMaybe mempty
            _ -> return ()

findKF5Components :: (MonadIO m, MonadState Deps m) => Analyzer m
findKF5Components pkg = awaitForever $ \(path, contents) ->
    when ("CMakeLists.txt" == takeFileName path) $ do
        let new = filter (not . cmakeReserved)
                  $ filter (not . B.null)
                  $ concatMap B.words
                  $ concatMap (take 1 . drop 1)
                  $ match regex contents
            regex = makeRegex
                    "find_package[[:space:]]*\\([[:space:]]*KF5\
                    \[[:space:]]*([#\\.${}_[:alnum:][:space:]]+)\\)"
        ix pkg . buildInputs %= S.union (S.fromList $ map ("KF5" <>) new)

cmakeReserved :: ByteString -> Bool
cmakeReserved bs = or $ map ($ bs)
                   [ B.elem '$'
                   , B.elem '{'
                   , B.elem '}'
                   , B.elem '#'
                   , B.elem '.'
                   , (==) "COMPONENTS"
                   , (==) "REQUIRED"
                   , (==) "CONFIG"
                   ]

kf5Analyzers :: (MonadIO m, MonadState Deps m) => [Analyzer m]
kf5Analyzers = [findKF5Components, renameKF5Pkgs, propagateKF5Deps]
               ++ cmakeAnalyzers

kf5PostAnalyze :: MonadState Deps m => m ()
kf5PostAnalyze = do
    moveNativeInputs
    movePropagatedInputs
    moveUserEnvPkgs

moveNativeInputs :: MonadState Deps m => m ()
moveNativeInputs = deps %= M.map makeNative
  where
    makeNative = execState $ forM_ native $ \dep -> do
        hasDep <- use (buildInputs.to (S.member dep))
        when hasDep $ do
            buildInputs %= S.delete dep
            nativeBuildInputs %= S.insert dep
        hasPropDep <- use (propagatedBuildInputs.to (S.member dep))
        when hasPropDep $ do
            propagatedBuildInputs %= S.delete dep
            propagatedNativeBuildInputs %= S.insert dep
    native = [ "BISON"
             , "extra-cmake-modules"
             , "FLEX"
             , "kdoctools"
             , "ki18n"
             , "LibXslt"
             , "Perl"
             , "PythonInterp"
             ]

movePropagatedInputs :: MonadState Deps m => m ()
movePropagatedInputs = deps %= M.map propagate
  where
    propagate = execState $ forM_ propagated $ \dep -> do
        hasDep <- use (buildInputs.to (S.member dep))
        when hasDep $ do
            buildInputs %= S.delete dep
            propagatedBuildInputs %= S.insert dep
        hasNativeDep <- use (nativeBuildInputs.to (S.member dep))
        when hasNativeDep $ do
            nativeBuildInputs %= S.delete dep
            propagatedNativeBuildInputs %= S.insert dep
    propagated = [ "extra-cmake-modules" ]

moveUserEnvPkgs :: MonadState Deps m => m ()
moveUserEnvPkgs = deps %= M.map propagate
  where
    propagate = execState $ forM_ userEnv $ \dep -> do
        hasDep <- use (buildInputs.to (S.member dep))
        hasNativeDep <- use (buildInputs.to (S.member dep))
        hasPropDep <- use (buildInputs.to (S.member dep))
        hasPropNativeDep <- use (buildInputs.to (S.member dep))
        when (hasDep || hasNativeDep || hasPropDep || hasPropNativeDep)
            $ propagatedUserEnvPkgs %= S.insert dep
    userEnv = [ "SharedMimeInfo" ]