import System.Environment (getArgs)
import System.Directory (getAppUserDataDirectory)
import Control.Applicative ((<$>))
import Data.Maybe (catMaybes)
import Data.Char (isSpace)
import Data.List (isPrefixOf, foldl')
import System.Exit (exitWith)
import System.Cmd (rawSystem)
import Network.HTTP (simpleHTTP, getRequest, getResponseBody)
configFile :: IO FilePath
configFile = do
dir <- getAppUserDataDirectory "cabal"
return $ dir ++ "/config"
nirvanaFile :: IO FilePath
nirvanaFile = do
dir <- getAppUserDataDirectory "cabal-nirvana"
return $ dir ++ "/default"
data Package = Package
{ name :: String
, version :: String
}
readPackages :: FilePath -> IO [Package]
readPackages fp =
readFile fp >>= (catMaybes <$>) . mapM parse . lines
where
parse s
| all isSpace s = return Nothing
| "--" `isPrefixOf` s = return Nothing
parse s =
case words s of
[a, b] -> return $ Just $ Package a b
_ -> error $ "Invalid nirvana line: " ++ show s
readConfigFile :: IO [String]
readConfigFile = do
ls <- lines <$> (configFile >>= readFile)
-- force evaluation
if length ls > 0
then return ls
else return []
writeConfigFile :: [String] -> IO ()
writeConfigFile ss = configFile >>= flip writeFile (unlines ss)
main :: IO ()
main = do
args <- getArgs
case args of
("fetch":rest) -> do
url <-
case rest of
[] -> return "http://www.snoyman.com/cabal-nirvana/yesod"
[x] -> return x
_ -> error $ "Usage: cabal-nirvana fetch [URL]"
str <- simpleHTTP (getRequest url) >>= getResponseBody
nirvanaFile >>= flip writeFile str
("start":rest) -> do
fp <-
case rest of
[] -> nirvanaFile
[x] -> return x
_ -> error $ "Usage: cabal-nirvana start [package file]"
packages <- readPackages fp
config <- readConfigFile
writeConfigFile $ addNirvana packages $ removeNirvana config
["stop"] -> do
config <- readConfigFile
writeConfigFile $ removeNirvana config
("test":rest) -> do
fp <-
case rest of
[] -> nirvanaFile
[x] -> return x
_ -> error $ "Usage: cabal-nirvana test [package file]"
packages <- readPackages fp
let ws = map (\(Package n v) -> concat [n, "-", v]) packages
putStrLn $ "cabal-dev install " ++ unwords ws
ec <- rawSystem "cabal-dev" $ "install" : ws
exitWith ec
_ -> do
putStrLn "Available commands:"
putStrLn " cabal-nirvana fetch [URL]"
putStrLn " cabal-nirvana start [package file]"
putStrLn " cabal-nirvana stop"
putStrLn " cabal-nirvana test [package file]"
beginLine, endLine :: String
beginLine = "-- cabal-nirvana begin"
endLine = "-- cabal-nirvana end"
removeNirvana :: [String] -> [String]
removeNirvana [] = []
removeNirvana (x:xs)
| x == beginLine = removeNirvana $ drop 1 $ dropWhile (/= endLine) xs
| otherwise = x : removeNirvana xs
addNirvana :: [Package] -> [String] -> [String]
addNirvana ps =
(++ ss)
where
ss = beginLine : foldr (:) [endLine] (map toS ps)
toS (Package n v) = concat
[ "constraint: "
, n
, " == "
, v
]