diff --git a/addressbook.cabal b/addressbook.cabal index 719827f..cad62e9 100644 --- a/addressbook.cabal +++ b/addressbook.cabal @@ -20,6 +20,7 @@ library exposed-modules: MyLib , Data.Email.Header , Data.Email + , Control.Addressbook.Streaming -- other-modules: -- other-extensions: default-extensions: OverloadedStrings @@ -42,6 +43,7 @@ executable addressbook -- other-modules: -- other-extensions: build-depends: base ^>=4.13.0.0, addressbook + , optparse-applicative hs-source-dirs: app default-language: Haskell2010 diff --git a/app/Main.hs b/app/Main.hs index 60d904e..b55c6ee 100644 --- a/app/Main.hs +++ b/app/Main.hs @@ -1,8 +1,22 @@ +{-# LANGUAGE LambdaCase #-} module Main where -import qualified MyLib (someFunc) +import Options.Applicative + +import qualified Control.Addressbook.Streaming as Streaming + +data CmdLine + = Stream + deriving Show + +cmdline :: Parser CmdLine +cmdline = subparser (command "stream" (info (pure Stream) (progDesc "Record a stream of filenames"))) + +handler :: CmdLine -> IO () +handler = \case + Stream -> Streaming.run main :: IO () -main = do - putStrLn "Hello, Haskell!" - MyLib.someFunc +main = execParser opts >>= handler + where + opts = info (cmdline <**> helper) (fullDesc <> progDesc "Email addressbook") diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..2892ba0 --- /dev/null +++ b/build.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# while :; do +find addressbook.cabal {src,test,app} -type f | entr -d -r -c -s 'cabal build --ghc-options=-Wall' +# done + diff --git a/default.nix b/default.nix index c4377c6..53b64d1 100644 --- a/default.nix +++ b/default.nix @@ -1,6 +1,7 @@ { mkDerivation, attoparsec, base, bytestring, bytestring-trie , conduit, conduit-extra, hedgehog, hedgehog-corpus, HUnit, lens -, mtl, stdenv, tasty, tasty-hedgehog, tasty-hunit, text, vector +, mtl, optparse-applicative, stdenv, tasty, tasty-hedgehog +, tasty-hunit, text, vector }: mkDerivation { pname = "addressbook"; @@ -12,7 +13,7 @@ mkDerivation { attoparsec base bytestring bytestring-trie conduit conduit-extra lens mtl text vector ]; - executableHaskellDepends = [ base ]; + executableHaskellDepends = [ base optparse-applicative ]; testHaskellDepends = [ base bytestring conduit conduit-extra hedgehog hedgehog-corpus HUnit tasty tasty-hedgehog tasty-hunit text vector diff --git a/src/Control/Addressbook/Streaming.hs b/src/Control/Addressbook/Streaming.hs new file mode 100644 index 0000000..e8b6246 --- /dev/null +++ b/src/Control/Addressbook/Streaming.hs @@ -0,0 +1,25 @@ +module Control.Addressbook.Streaming where + +import qualified Data.Text as T + +import Conduit +import qualified Data.Conduit.Binary as CB +import qualified Data.Conduit.Combinators as C +import qualified Data.Conduit.List as CL +import qualified Data.Conduit.Text as CT + +import Data.Email +import Data.Email.Header + (Header) + +import System.IO + (stdin) + +combine :: (MonadResource m, MonadThrow m, MonadIO m) => ConduitM FilePath Header m () +combine = await >>= \case + Nothing -> pure () + Just path -> (CB.sourceFile path .| parseEmail) >> combine + +run :: IO () +run = do + runResourceT $ runConduit (CB.sourceHandle stdin .| CT.decode CT.utf8 .| CT.lines .| C.map T.unpack .| combine .| C.mapM_ (liftIO . print))