module Hpack (
hpack
, hpackResult
, Result(..)
, Status(..)
, version
, main
#ifdef TEST
, hpackWithVersion
, parseVerbosity
, extractVersion
, parseVersion
#endif
) where
import Prelude ()
import Prelude.Compat
import Control.Monad.Compat
import qualified Data.ByteString as B
import Data.List.Compat
import Data.Maybe
import qualified Data.Text as T
import Data.Text.Encoding (encodeUtf8)
import Data.Version (Version)
import qualified Data.Version as Version
import System.Environment
import System.Exit
import System.IO
import Text.ParserCombinators.ReadP
import Paths_hpack (version)
import Hpack.Config
import Hpack.Run
import Hpack.Util
programVersion :: Version -> String
programVersion v = "hpack version " ++ Version.showVersion v
header :: Version -> String
header v = unlines [
"-- This file has been generated from " ++ packageConfig ++ " by " ++ programVersion v ++ "."
, "--"
, "-- see: https://github.com/sol/hpack"
, ""
]
main :: IO ()
main = do
args <- getArgs
case args of
["--version"] -> putStrLn (programVersion version)
["--help"] -> printHelp
_ -> case parseVerbosity args of
(verbose, [dir]) -> hpack dir verbose
(verbose, []) -> hpack "" verbose
_ -> do
printHelp
exitFailure
printHelp :: IO ()
printHelp = do
hPutStrLn stderr $ unlines [
"Usage: hpack [ --silent ] [ dir ]"
, " hpack --version"
]
parseVerbosity :: [String] -> (Bool, [String])
parseVerbosity xs = (verbose, ys)
where
silentFlag = "--silent"
verbose = not (silentFlag `elem` xs)
ys = filter (/= silentFlag) xs
safeInit :: [a] -> [a]
safeInit [] = []
safeInit xs = init xs
extractVersion :: [String] -> Maybe Version
extractVersion = listToMaybe . mapMaybe (stripPrefix prefix >=> parseVersion . safeInit)
where
prefix = "-- This file has been generated from package.yaml by hpack version "
parseVersion :: String -> Maybe Version
parseVersion xs = case [v | (v, "") <- readP_to_S Version.parseVersion xs] of
[v] -> Just v
_ -> Nothing
hpack :: FilePath -> Bool -> IO ()
hpack = hpackWithVersion version
hpackResult :: FilePath -> IO Result
hpackResult = hpackWithVersionResult version
data Result = Result {
resultWarnings :: [String]
, resultCabalFile :: String
, resultStatus :: Status
}
data Status = Generated | AlreadyGeneratedByNewerHpack | OutputUnchanged
hpackWithVersion :: Version -> FilePath -> Bool -> IO ()
hpackWithVersion v dir verbose = do
r <- hpackWithVersionResult v dir
forM_ (resultWarnings r) $ \warning -> hPutStrLn stderr ("WARNING: " ++ warning)
when verbose $ putStrLn $
case resultStatus r of
Generated -> "generated " ++ resultCabalFile r
OutputUnchanged -> resultCabalFile r ++ " is up-to-date"
AlreadyGeneratedByNewerHpack -> resultCabalFile r ++ " was generated with a newer version of hpack, please upgrade and try again."
hpackWithVersionResult :: Version -> FilePath -> IO Result
hpackWithVersionResult v dir = do
(warnings, cabalFile, new) <- run dir
old <- fmap splitHeader <$> tryReadFile cabalFile
let oldVersion = fmap fst old >>= extractVersion
status <-
if (oldVersion <= Just v) then
if (fmap snd old == Just (lines new)) then
return OutputUnchanged
else do
B.writeFile cabalFile $ encodeUtf8 $ T.pack $ header v ++ new
return Generated
else
return AlreadyGeneratedByNewerHpack
return Result
{ resultWarnings = warnings
, resultCabalFile = cabalFile
, resultStatus = status
}
where
splitHeader :: String -> ([String], [String])
splitHeader = fmap (dropWhile null) . span ("--" `isPrefixOf`) . lines