aeson-diff-1.1.0.11: src/diff.hs
{-# LANGUAGE RecordWildCards #-}
module Main (main) where
import Control.Exception (bracket)
import Data.Aeson (Value, encode, decode)
import Data.Aeson.Diff (Config(Config), diff')
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy as BSL
import Options.Applicative (fullDesc, info, execParser, helper, metavar, progDesc, argument, help, value, long, option, short, switch)
import Options.Applicative.Types (Parser, readerAsk)
import System.IO (Handle, IOMode(ReadMode, WriteMode), hClose, openFile, stdin, stdout)
type File = Maybe FilePath
-- | Command-line options.
data DiffOptions = DiffOptions
{ optionTst :: Bool
, optionOut :: File
, optionFrom :: File
, optionTo :: File
}
data Configuration = Configuration
{ cfgTst :: Bool
, cfgOut :: Handle
, cfgFrom :: Handle
, cfgTo :: Handle
}
optionParser :: Parser DiffOptions
optionParser = DiffOptions
<$> switch
( long "test-before-remove"
<> short 'T'
<> help "Include a test before each remove."
)
<*> option fileP
( long "output"
<> short 'o'
<> metavar "OUTPUT"
<> help "Write patch to file OUTPUT."
<> value Nothing
)
<*> argument fileP
( metavar "FROM"
)
<*> argument fileP
( metavar "TO"
)
where
fileP = do
s <- readerAsk
return $ case s of
"-" -> Nothing
_ -> Just s
jsonFile :: Handle -> IO Value
jsonFile fp = do
s <- BS.hGetContents fp
case decode (BSL.fromStrict s) of
Nothing -> error "Could not parse as JSON"
Just v -> return v
run :: DiffOptions -> IO ()
run opt = bracket (load opt) close process
where
openr :: Maybe FilePath -> IO Handle
openr Nothing = return stdin
openr (Just p) = openFile p ReadMode
openw :: Maybe FilePath -> IO Handle
openw Nothing = return stdout
openw (Just p) = openFile p WriteMode
load :: DiffOptions -> IO Configuration
load DiffOptions{..} =
Configuration
<$> pure optionTst
<*> openw optionOut
<*> openr optionFrom
<*> openr optionTo
close :: Configuration -> IO ()
close Configuration{..} = do
hClose cfgOut
hClose cfgFrom
hClose cfgTo
process :: Configuration -> IO ()
process Configuration{..} = do
json_from <- jsonFile cfgFrom
json_to <- jsonFile cfgTo
let c = Config cfgTst
let p = diff' c json_from json_to
BS.hPutStrLn cfgOut $ BSL.toStrict (encode p)
main :: IO ()
main = execParser opts >>= run
where
opts = info (helper <*> optionParser)
( fullDesc
<> progDesc "Generate a patch between two JSON documents.")