packages feed

dnf-repo-0.1: src/YumRepoFile.hs

{-# LANGUAGE OverloadedStrings #-}

module YumRepoFile (
  Mode(..),
  readRepo,
  RepoState,
  selectRepo,
  Modular(..),
  Testing(..),
  changeRepo,
  saveRepo,
  updateState,
  expiring,
  deleting
  )
where

import Data.List.Extra (isPrefixOf, isInfixOf, isSuffixOf, trim)
import SimpleCmd (error')

type RepoState = (String,Bool,FilePath)

data Mode = AddCopr String | AddKoji String
          | EnableRepo String | DisableRepo String
          | ExpireRepo String | DeleteRepo String | Default
  deriving Eq

data ChangeEnable = Disable String | Enable String | Expire String
                  | Delete FilePath
  deriving (Eq,Ord,Show)

changeRepo :: ChangeEnable -> [String]
changeRepo (Disable r) = ["--disablerepo", r]
changeRepo (Enable r) = ["--enablerepo", r]
changeRepo _ = []

saveRepo :: ChangeEnable -> [String]
saveRepo (Disable r) = ["--disable", r]
saveRepo (Enable r) = ["--enable", r]
saveRepo _ = []

expiring :: ChangeEnable -> Maybe String
expiring (Expire r) = Just r
expiring _ = Nothing

deleting :: ChangeEnable -> Maybe String
deleting (Delete r) = Just r
deleting _ = Nothing

updateState :: [ChangeEnable] -> RepoState -> RepoState
updateState [] rs = rs
updateState (ce:ces) re@(repo,enabled,file) =
  case ce of
    Disable r | r == repo && enabled -> (repo,False,file)
    Enable r | r == repo && not enabled -> (repo,True,file)
    _ -> updateState ces re

data Modular = EnableModular | DisableModular
  deriving Eq

data Testing = EnableTesting | DisableTesting
  deriving Eq

selectRepo :: Bool -> Mode -> Maybe Testing -> Maybe Modular
           -> RepoState -> Maybe ChangeEnable
selectRepo _debug mode mtesting mmodular (name,enabled,file) =
  case mode of
    AddCopr repo -> if repo `isSuffixOf` name && not enabled
                    then Just (Enable name)
                    else selectOther
    AddKoji repo -> if repo `isSuffixOf` name && not enabled
                    then Just (Enable name)
                    else selectOther
    EnableRepo pat -> if pat `isInfixOf` name && not enabled
                  then Just (Enable name)
                  else selectOther
    DisableRepo pat -> if pat `isInfixOf` name && enabled
                   then Just (Disable name)
                   else selectOther
    ExpireRepo pat -> if pat `isInfixOf` name
                  then Just (Expire name)
                  else Nothing
    DeleteRepo pat -> if pat `isInfixOf` name
                  then if enabled
                       then error' $ "disable repo before deleting: " ++ name
                       else Just (Delete file)
                  else Nothing
    _ -> selectOther
  where
    selectOther :: Maybe ChangeEnable
    selectOther
      | "modular" `isSuffixOf` name =
        case mmodular of
          Nothing -> Nothing
          Just include ->
            case include of
              EnableModular | not enabled ->
                               if "testing" `isInfixOf` name
                               then if mtesting == Just EnableTesting
                                    then Just (Enable name)
                                    else Nothing
                               else Just (Enable name)
              DisableModular | enabled -> Just (Disable name)
              _ -> Nothing
      | "testing" `isInfixOf` name =
          case mtesting of
            Nothing -> Nothing
            Just include ->
              case include of
                EnableTesting | not enabled -> Just (Enable name)
                DisableTesting | enabled -> Just (Disable name)
                _ -> Nothing
      | otherwise = Nothing

readRepo :: FilePath -> IO RepoState
readRepo file =
  parseRepo file . lines <$> readFile file

-- was called parseIni
parseRepo :: FilePath -> [String] -> RepoState
parseRepo file [] = error' $ "empty ini file: " ++ file
parseRepo file (l:ls) =
  case trim l of
    "" -> parseRepo file ls
    ('#':_) -> parseRepo file ls
    sec ->
      let section = secName sec
          enabled =
            case dropWhile (not . ("enabled=" `isPrefixOf`)) ls of
              [] -> error' $ "no enabled field for " ++ section
              (e:_) ->
                case trim e of
                  "enabled=1" -> True
                  "enabled=0" -> False
                  _ -> error' $ "unknown enabled state " ++ e ++ " for " ++ section
      in (section,enabled,file)
  where
    secName :: String -> String
    secName sec =
      if ' ' `elem` sec
      then error' $ "section contains space: " ++ sec
      else case sec of
        ('[' : rest) ->
          if last rest == ']'
          then init rest
          else error' $ "bad section " ++ sec ++ " in " ++ file
        _ -> error' $ "section not found in " ++ file