dnf-repo-0.7: src/YumRepoFile.hs
{-# LANGUAGE CPP #-}
module YumRepoFile (
readRepos,
RepoState(..),
printRepo,
applyOverrides,
readOverrides
)
where
import Control.Applicative ((<|>))
import Control.Monad (foldM)
import Data.List.Extra (breakOn, isInfixOf, isPrefixOf, splitOn, trim, trimEnd,
#if !MIN_VERSION_base(4,20,0)
foldl',
#endif
unsnoc)
import Data.Maybe (fromMaybe)
import SimpleCmd (error', warning, (+-+))
import System.FilePath.Glob (compile, match)
data RepoState =
RepoState
{ repoName :: String
, repoState :: (Bool, -- enabled
FilePath, -- repofile
Maybe String -- baseurl
)
}
deriving (Eq, Ord)
readRepos :: FilePath -> IO [RepoState]
readRepos file =
parseRepos file . lines <$> readFile file
-- parse ini
parseRepos :: FilePath -> [String] -> [RepoState]
parseRepos file ls =
case nextSection file ls of
Nothing -> []
Just (section,rest) ->
let (mbaseurl,rest1) =
case dropWhile (not . ("baseurl" `isInfixOf`)) rest of
[] -> (Nothing,rest)
(e:more') ->
case breakOn "=" e of
(_,'=':url) -> (Just (trim url), more')
_ -> error' $ "failed to parse" +-+ show e +-+ "for" +-+ section
(enabled,more) =
case dropWhile (not . ("enabled" `isPrefixOf`)) rest1 of
[] -> error' $ "no enabled field for" +-+ section
(e:more') ->
case splitOn "=" e of
[_,v] ->
case trim v of
"1" -> (True,more')
"0" -> (False,more')
_ -> error' $ "strange enabled state" +-+ e +-+ "for" +-+ section
_ -> error' $ "unknown enabled state" +-+ e +-+ "for" +-+ section
in RepoState section (enabled,file,mbaseurl) : parseRepos file more
nextSection :: FilePath -> [String] -> Maybe (String,[String])
nextSection _ [] = Nothing
nextSection file (l:ls') =
case trimEnd l of
('[' : rest) ->
case unsnoc rest of
Just (rest',']') -> Just (rest', ls')
_ -> error' $ "bad section" +-+ l +-+ "in" +-+ file
_ -> nextSection file ls'
printRepo :: RepoState -> IO ()
printRepo (RepoState n s) =
print (n,s)
-- An override section may set only enabled and/or baseurl (or neither).
data RepoOverride = RepoOverride String (Maybe Bool) (Maybe String)
readOverrides :: FilePath -> IO [RepoOverride]
readOverrides file = do
ls <- lines <$> readFile file
parseOverrides file ls
parseOverrides :: FilePath -> [String] -> IO [RepoOverride]
parseOverrides file ls =
case nextSection file ls of
Nothing -> return []
Just (section, rest) -> do
let (body, more) = break isHeader rest
ov <- sectionOverride file (trim section) body
(ov :) <$> parseOverrides file more
where
isHeader l =
case trimEnd l of
'[':_ -> True
_ -> False
sectionOverride :: FilePath -> String -> [String] -> IO RepoOverride
sectionOverride file section body = do
(menable, murl) <- foldM add (Nothing, Nothing) body
return $ RepoOverride section menable murl
where
add (menable, murl) line =
case splitKv line of
Just ("enabled", v) ->
case v of
"1" -> return (Just True, murl)
"0" -> return (Just False, murl)
_ -> do
warning $ "strange enabled state" +-+ v +-+ "for" +-+ section +-+
"in" +-+ file
return (menable, murl)
Just ("baseurl", v) -> return (menable, Just v)
_ -> return (menable, murl)
splitKv line =
case breakOn "=" line of
(k, '=':v) -> Just (trim k, trim v)
_ -> Nothing
applyOverrides :: [RepoOverride] -> [RepoState] -> [RepoState]
applyOverrides ovs states = foldl' applyOne states ovs
where
applyOne ss (RepoOverride pat men murl) =
let compiled = compile pat
in map (apply compiled men murl) ss
apply compiled men murl rs@(RepoState name (en, file, url))
| match compiled name =
RepoState name (fromMaybe en men, file, murl <|> url)
| otherwise = rs