packages feed

arch-hs-0.0.0.0: src/OptionParse.hs

{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_HADDOCK hide #-}

module OptionParse
  ( readFlag,
    optFlagReader,
    optFlagParser,
    optSkippedReader,
    optExtraCabalReader,
    optVersionReader,
    optPackageNameReader,
    module Options.Applicative,
  )
where

import Data.List (groupBy, intercalate)
import Data.List.Split (splitOn)
import qualified Data.Map.Strict as Map
import Data.Void (Void)
import Distribution.ArchHs.Types
import Distribution.ArchHs.Utils
import Distribution.Parsec (simpleParsec)
import Distribution.Types.Flag (FlagAssignment, insertFlagAssignment, mkFlagAssignment, mkFlagName)
import Distribution.Types.PackageName (PackageName, mkPackageName)
import Distribution.Version (Version)
import Options.Applicative
import System.FilePath (takeExtension)
import qualified Text.Megaparsec as M
import qualified Text.Megaparsec.Char as M

readFlag :: [(String, String, Bool)] -> Map.Map PackageName FlagAssignment
readFlag [] = Map.empty
readFlag list =
  Map.fromList
    . fmap (\l -> (mkPackageName . (^. _1) . head $ l, foldr (\(_, f, v) acc -> insertFlagAssignment (mkFlagName f) v acc) (mkFlagAssignment []) l))
    . groupBy (\a b -> uncurry (==) (getTwo _1 a b))
    $ list

optFlagReader :: ReadM (Map.Map PackageName FlagAssignment)
optFlagReader =
  eitherReader
    ( \s -> case M.parse optFlagParser "" s of
        Right x -> Right x
        Left err -> Left $ M.errorBundlePretty err
    )

optFlagParser :: M.Parsec Void String (Map.Map PackageName FlagAssignment)
optFlagParser =
  readFlag
    <$> ( do
            pkg <- M.manyTill M.anySingle $ M.single ':'
            flg <- M.manyTill M.anySingle $ M.single ':'
            b <- bool
            return (pkg, flg, b)
        )
    `M.sepBy` ","
  where
    bool = do
      s <- M.string "true" <|> M.string "false"
      case s of
        "true" -> return True
        "false" -> return False
        _ -> fail $ "unknown bool: " <> s

optSkippedReader :: ReadM [String]
optSkippedReader = eitherReader $ Right . splitOn ","

optExtraCabalReader :: ReadM [FilePath]
optExtraCabalReader = eitherReader $ \x ->
  let splitted = splitOn "," x
      check = map (\e -> if takeExtension x == ".cabal" then (e, True) else (e, False)) splitted
      failed = map fst . filter (not . snd) $ check
      successful = map fst . filter snd $ check
   in if failed /= [] then Left ("Unexpected file name: " <> intercalate ", " failed) else Right successful

optVersionReader :: ReadM Version
optVersionReader =
  eitherReader
    ( \s -> case simpleParsec s of
        Just v -> Right v
        _ -> Left $ "Failed to parse version: " <> s
    )

optPackageNameReader :: ReadM PackageName
optPackageNameReader = eitherReader $ Right . mkPackageName