{-# LANGUAGE CPP #-} {-# LANGUAGE RecordWildCards #-} module Hpack ( hpack , hpackResult , Result(..) , Status(..) , Verbose(..) , Force(..) , version , main , mainWith , RunOptions(..) , defaultRunOptions #ifdef TEST , header , hpackWithVersionResult #endif ) where import Control.Monad import Data.Version (Version) import qualified Data.Version as Version import System.Environment import System.Exit import System.IO (stderr) import Data.Aeson (Value) import Paths_hpack (version) import Hpack.Options import Hpack.Config import Hpack.Run import Hpack.Util import Hpack.Utf8 as Utf8 import Hpack.CabalFile import Hpack.Yaml programVersion :: Version -> String programVersion v = "hpack version " ++ Version.showVersion v header :: FilePath -> Version -> Hash -> String header p v hash = unlines [ "-- This file has been generated from " ++ p ++ " by " ++ programVersion v ++ "." , "--" , "-- see: https://github.com/sol/hpack" , "--" , "-- hash: " ++ hash , "" ] main :: IO () main = mainWith packageConfig decodeYaml mainWith :: FilePath -> (FilePath -> IO (Either String Value)) -> IO () mainWith configFile decode = do result <- getArgs >>= parseOptions configFile case result of PrintVersion -> putStrLn (programVersion version) PrintNumericVersion -> putStrLn (Version.showVersion version) Help -> printHelp Run options -> case options of Options _verbose _force True dir file -> hpackStdOut (RunOptions dir file decode) Options verbose force False dir file -> hpack (RunOptions dir file decode) verbose force ParseError -> do printHelp exitFailure printHelp :: IO () printHelp = do Utf8.hPutStrLn stderr $ unlines [ "Usage: hpack [ --silent ] [ --force | -f ] [ PATH ] [ - ]" , " hpack --version" , " hpack --help" ] hpack :: RunOptions -> Verbose -> Force -> IO () hpack = hpackWithVersion version hpackResult :: RunOptions -> Force -> IO Result hpackResult = hpackWithVersionResult version data Result = Result { resultWarnings :: [String] , resultCabalFile :: String , resultStatus :: Status } deriving (Eq, Show) data Status = Generated | ExistingCabalFileWasModifiedManually | AlreadyGeneratedByNewerHpack | OutputUnchanged deriving (Eq, Show) hpackWithVersion :: Version -> RunOptions -> Verbose -> Force -> IO () hpackWithVersion v options verbose force = do r <- hpackWithVersionResult v options force printWarnings (resultWarnings r) when (verbose == 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." ExistingCabalFileWasModifiedManually -> resultCabalFile r ++ " was modified manually, please use --force to overwrite." printWarnings :: [String] -> IO () printWarnings warnings = do forM_ warnings $ \warning -> Utf8.hPutStrLn stderr ("WARNING: " ++ warning) mkStatus :: [String] -> Version -> CabalFile -> Status mkStatus new v (CabalFile mOldVersion mHash old) = case (mOldVersion, mHash) of (Nothing, _) -> ExistingCabalFileWasModifiedManually (Just oldVersion, _) | oldVersion < makeVersion [0, 20, 0] -> Generated (_, Nothing) -> ExistingCabalFileWasModifiedManually (Just oldVersion, Just hash) | v < oldVersion -> AlreadyGeneratedByNewerHpack | sha256 (unlines old) /= hash -> ExistingCabalFileWasModifiedManually | old == new -> OutputUnchanged | otherwise -> Generated hpackWithVersionResult :: Version -> RunOptions -> Force -> IO Result hpackWithVersionResult v options@RunOptions{..} force = do (warnings, cabalFile, new) <- run options oldCabalFile <- readCabalFile cabalFile let status = case force of Force -> Generated NoForce -> maybe Generated (mkStatus (lines new) v) oldCabalFile case status of Generated -> do let hash = sha256 new Utf8.writeFile cabalFile (header runOptionsConfigFile v hash ++ new) _ -> return () return Result { resultWarnings = warnings , resultCabalFile = cabalFile , resultStatus = status } hpackStdOut :: RunOptions -> IO () hpackStdOut options = do (warnings, _cabalFile, new) <- run options Utf8.putStr new printWarnings warnings