dhall-csv-1.0.0: csv-to-dhall/Main.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Main where
import Control.Applicative (optional, (<|>))
import Control.Exception (SomeException)
import Data.Version (showVersion)
import Dhall.CsvToDhall
import Dhall.Pretty (CharacterSet (..))
import Data.Text (Text)
import Options.Applicative (Parser, ParserInfo)
import qualified Control.Exception
import qualified Data.Text.IO as Text.IO
import qualified Dhall.Csv.Util
import qualified Dhall.Core
import qualified Dhall.Util
import qualified GHC.IO.Encoding
import qualified Options.Applicative as Options
import qualified Paths_dhall_csv as Meta
import qualified System.IO as IO
import qualified System.Exit
parserInfo :: ParserInfo Options
parserInfo = Options.info
( Options.helper <*> parseOptions)
( Options.fullDesc
<> Options.progDesc "Convert a CSV expression to a Dhall expression, given the expected Dhall type"
)
data Options
= Default
{ schema :: Maybe Text
, conversion :: Conversion
, file :: Maybe FilePath
, output :: Maybe FilePath
, ascii :: Bool
, plain :: Bool
, noHeader :: Bool
}
| Type
{ file :: Maybe FilePath
, output :: Maybe FilePath
, ascii :: Bool
, plain :: Bool
, noHeader :: Bool
}
| Version
deriving Show
parseOptions :: Parser Options
parseOptions =
typeCommand
<|> ( Default
<$> optional parseSchema
<*> parseConversion
<*> optional parseFile
<*> optional parseOutput
<*> parseASCII
<*> parsePlain
<*> parseNoHeader
)
<|> parseVersion
where
typeCommand =
Options.hsubparser
(Options.command "type" info <> Options.metavar "type")
where
info =
Options.info parser (Options.progDesc "Output the inferred Dhall type from a CSV value (not implemented)")
parser =
Type
<$> optional parseFile
<*> optional parseOutput
<*> parseASCII
<*> parsePlain
<*> parseNoHeader
parseSchema =
Options.strArgument
( Options.metavar "SCHEMA"
<> Options.help "Dhall type (schema). You can omit the schema to let the executable infer the schema from the CSV value (not implemented)"
)
parseVersion =
Options.flag'
Version
( Options.long "version"
<> Options.short 'V'
<> Options.help "Display version"
)
parseFile =
Options.strOption
( Options.long "file"
<> Options.help "Read CSV from a file instead of standard input"
<> Options.metavar "FILE"
<> Options.action "file"
)
parseOutput =
Options.strOption
( Options.long "output"
<> Options.help "Write Dhall expression to a file instead of standard output"
<> Options.metavar "FILE"
<> Options.action "file"
)
parseASCII =
Options.switch
( Options.long "ascii"
<> Options.help "Format code using only ASCII syntax"
)
parsePlain =
Options.switch
( Options.long "plain"
<> Options.help "Disable syntax highlighting"
)
parseNoHeader =
Options.switch
( Options.long "no-header"
<> Options.help "Convert CSV with no header"
)
main :: IO ()
main = do
GHC.IO.Encoding.setLocaleEncoding GHC.IO.Encoding.utf8
options <- Options.execParser parserInfo
let toCharacterSet ascii = case ascii of
True -> ASCII
False -> Unicode
let toCsv hasHeader file = do
text <- case file of
Nothing -> Text.IO.getContents
Just path -> Text.IO.readFile path
case Dhall.Csv.Util.decodeCsvDefault hasHeader text of
Left err -> fail err
Right csv -> pure csv
let toSchema schema = do
finalSchema <- case schema of
Just text -> resolveSchemaExpr text
Nothing -> fail "Please specify a schema. Type inference has not been implemented"
typeCheckSchemaExpr id finalSchema
case options of
Version ->
putStrLn (showVersion Meta.version)
Default{..} -> do
handle $ do
let characterSet = toCharacterSet ascii
csv <- toCsv (not noHeader) file
finalSchema <- toSchema schema
expression <- Dhall.Core.throws $ dhallFromCsv conversion finalSchema csv
Dhall.Util.renderExpression characterSet plain output expression
Type{} -> do
putStrLn "type command has not been implemented yet"
handle :: IO a -> IO a
handle = Control.Exception.handle handler
where
handler :: SomeException -> IO a
handler e = do
IO.hPutStrLn IO.stderr ""
IO.hPrint IO.stderr e
System.Exit.exitFailure