{-# LANGUAGE TypeOperators , TemplateHaskell #-} module Config where import Control.Monad import Data.Label import Data.List.Split import Data.Version import Distribution.Package import Distribution.Text import System.Console.GetOpt import System.Environment import qualified Data.Map as M data Action = Run | ShowDeps | ShowHelp | ShowVersion deriving Show data Config = Config { _bump :: M.Map Int [PackageName] -- Map of which packages to bump at which position , _setVersion :: [(PackageName,Version)] , _transitive :: Bool , _ignore :: [PackageName] , _global :: Maybe String , _action :: Action } deriving Show $(mkLabels [''Config]) defaultConfig :: Config defaultConfig = Config { _bump = M.empty , _setVersion = [] , _transitive = True , _ignore = [] , _global = Nothing , _action = Run } versionPar :: String -> [(PackageName, Version)] versionPar = foldr addVer [] . splitOn "," where addVer fld ac = case splitOn "@" fld of [p,v] -> case simpleParse v of (Just ver) -> (PackageName p, ver) : ac Nothing -> ac _ -> ac options :: [OptDescr (Config -> Config)] options = [ Option ['m'] ["major"] (ReqArg (addBumps 1) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will get a major bump (bump at position 1)." , Option ['n'] ["minor"] (ReqArg (addBumps 2) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will get a minor bump (bump at position 2)." , Option ['0'] ["bump-0"] (ReqArg (addBumps 0) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will get a bump at position 0." , Option ['1'] ["bump-1"] (ReqArg (addBumps 1) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will get a bump at position 1." , Option ['2'] ["bump-2"] (ReqArg (addBumps 2) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will get a bump at position 2." , Option ['3'] ["bump-3"] (ReqArg (addBumps 3) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will get a bump at position 3." , Option [] ["set-versions"] (ReqArg (\v -> modify setVersion (++ versionPar v)) "PACKAGE@VERSION(,PACKAGE@VERSION)*") "Comma-separated list of packages and their versions." , Option ['t'] ["no-transitive"] (NoArg (set transitive False)) "Do not apply bumping transitively." , Option ['i'] ["ignore"] (ReqArg (\v -> modify ignore (++ map PackageName (splitOn "," v))) "PACKAGE(,PACKAGE)*") "Comma-separated list of packages which will be ignored when transitive bumping." , Option ['g'] ["global"] (ReqArg (\v -> set global (Just v)) "PATH") "Bump according to latest version number in the given package database." , Option ['d'] ["dry-run"] (NoArg (set action ShowDeps)) "Just output the dependencies that will be updated." , Option ['?'] ["help"] (NoArg (set action ShowHelp)) "Show usage help and exit." , Option ['v'] ["version"] (NoArg (set action ShowVersion)) "Show version info and exit." ] where addBumps :: Int -> String -> Config -> Config addBumps p pks = modify bump (M.insertWith (++) p (map PackageName $ splitOn "," pks)) getConfig :: IO Config getConfig = do args <- getArgs opts <- processArgs defaultConfig options header args uncurry checkConfig opts checkConfig :: Config -> [String] -> IO Config checkConfig opts rest = do when (not . null $ rest) (error "Trailing options. Did you forget a flag?") return opts processArgs :: a -> [OptDescr (a -> a)] -> String -> [String] -> IO (a, [String]) processArgs def opts hdr args = case getOpt Permute opts args of (oargs, nonopts, [] ) -> return (foldl (flip ($)) def oargs, nonopts) (_ , _ , errors) -> ioError $ userError $ (concat errors) ++ usageInfo hdr opts header :: String header = "Usage: bumper [OPTIONS...], with the following options:" printUsage :: [OptDescr a] -> IO () printUsage opts = putStrLn $ usageInfo header opts