From da79719d284a09092990ae09e3e77b2ee37d07a1 Mon Sep 17 00:00:00 2001 From: Alice BRENON <alice.brenon@ens-lyon.fr> Date: Thu, 11 Feb 2021 18:15:54 +0100 Subject: [PATCH] Add a command-line interface to allow processing stdin or a given file and create files corresponding to both parts of the XML (raw text / empty tree structure) --- InvisiXML.cabal | 4 ++++ app/CLI.hs | 45 +++++++++++++++++++++++++++++++++++++++++++++ app/Main.hs | 31 ++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 app/CLI.hs diff --git a/InvisiXML.cabal b/InvisiXML.cabal index 1a58dfd..857afc0 100644 --- a/InvisiXML.cabal +++ b/InvisiXML.cabal @@ -36,9 +36,13 @@ library executable invisiXML main-is: Main.hs + other-modules: CLI + , Paths_InvisiXML build-depends: base >=4.12 && <4.15 + , filepath , InvisiXML , mtl + , optparse-applicative , text hs-source-dirs: app default-language: Haskell2010 diff --git a/app/CLI.hs b/app/CLI.hs new file mode 100644 index 0000000..e549eaf --- /dev/null +++ b/app/CLI.hs @@ -0,0 +1,45 @@ +module CLI ( + Command(..) + , Input(..) + , getCommand + ) where + +import Data.Version (showVersion) +import Control.Applicative ((<*>), optional) +import Options.Applicative ( + Parser, ReadM, argument, execParser, fullDesc, header + , help, helper, info, long, metavar, option, short, str, switch, value + ) +import qualified Paths_InvisiXML as InvisiXML (version) + +data Input = StdIn | FileInput FilePath + +data Command = Command { + input :: Input + , outputPrefix :: Maybe FilePath + , pristine :: Bool + } + +inputArg :: ReadM Input +inputArg = fileOrStdIn <$> str + where + fileOrStdIn "-" = StdIn + fileOrStdIn f = FileInput f + +command :: Parser Command +command = Command + <$> argument inputArg (metavar "INPUT_FILE" <> value StdIn + <> help "XML file to process" + ) + <*> option (optional str) (short 'o' <> long "outputPrefix" <> value Nothing + <> help "prefix for the output files" + ) + <*> switch (short 'p' <> long "pristine" + <> help "keep input exactly as is, not unindenting or normalizing it in any way" + ) + +getCommand :: IO Command +getCommand = execParser $ + info + (helper <*> command) + (fullDesc <> header ("InvisiXML v" ++ showVersion InvisiXML.version)) diff --git a/app/Main.hs b/app/Main.hs index 214d1a3..5f4032e 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,14 +1,31 @@ +{-# LANGUAGE NamedFieldPuns #-} module Main where - +import CLI (Command(..), Input(..), getCommand) import Control.Monad.Except (runExceptT) -import qualified Data.Text.IO as Text (putStr) +import Data.Maybe (fromMaybe) +import Data.Text (Text) +import qualified Data.Text.IO as Text (getContents, readFile, writeFile) import Text.InvisiXML (InvisiXML(..), parse) import Text.XML.Light.Serializer (encode) +import System.FilePath ((<.>), dropExtension) -main :: IO () -main = getContents >>= runExceptT . parse >>= either (fail . show) display +endPoints :: Command -> (IO Text, FilePath) +endPoints (Command {input = StdIn, outputPrefix}) = + (Text.getContents, fromMaybe noOutputPrefix outputPrefix) + where + noOutputPrefix = error "output prefix (-o) is necessary when running on stdin" +endPoints (Command {input = FileInput f, outputPrefix}) = + (Text.readFile f, fromMaybe (dropExtension f) outputPrefix) + +run :: Command -> IO () +run command = + source >>= runExceptT . parse >>= either (fail . show) create where - display result = do - Text.putStr $ text result - putStr . encode $ structure result + (source, prefix) = endPoints command + create (InvisiXML {text, structure}) = do + Text.writeFile (prefix <.> "txt") text + writeFile (prefix <.> "ixml") $ encode structure + +main :: IO () +main = getCommand >>= run -- GitLab