asif-3.2.0: app/App/Commands/Ls.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module App.Commands.Ls
( commandLs
) where
import App.Commands.Options.Type (LsOptions (LsOptions))
import Arbor.File.Format.Asif.IO
import Arbor.File.Format.Asif.Segment hiding (meta)
import Control.Lens
import Control.Monad
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Resource (MonadResource, runResourceT)
import Data.Generics.Product.Any
import Data.Maybe
import Data.Monoid ((<>))
import Data.Thyme.Clock.POSIX (POSIXTime)
import Data.Thyme.Time.Core
import Options.Applicative
import qualified Data.Attoparsec.ByteString as AP
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Text as T
import qualified System.IO as IO
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
parseLsOptions :: Parser LsOptions
parseLsOptions = LsOptions
<$> strOption
( long "source"
<> metavar "FILE"
<> value "-"
<> help "Input file"
)
<*> strOption
( long "target"
<> metavar "FILE"
<> value "-"
<> help "Output file"
)
commandLs :: Parser (IO ())
commandLs = runResourceT . runDump <$> parseLsOptions
runDump :: MonadResource m => LsOptions -> m ()
runDump opt = do
(_, hIn) <- openFileOrStd (opt ^. the @"source") IO.ReadMode
(_, hOut) <- openFileOrStd (opt ^. the @"target") IO.WriteMode
contents <- liftIO $ LBS.hGetContents hIn
case extractSegments magic contents of
Left errorMessage -> do
liftIO $ IO.hPutStrLn IO.stderr $ "Error occured: " <> errorMessage
return ()
Right segments -> do
let filenames = fromMaybe "" . (^. the @"meta" . the @"filename") <$> segments
let namedSegments = zip filenames segments
forM_ (zip [0..] namedSegments) $ \(i :: Int, (filename, segment)) -> do
let meta = segment ^. the @"meta"
liftIO $ IO.hPutStrLn hOut $ mempty
<> (show i & trimPadLeft 4)
<> " " <> (meta ^. the @"createTime" <&> showPosixSeconds & fromMaybe "" & trimPadLeft 19)
<> " " <> (meta ^. the @"format" <&> show & fromMaybe "" & trimPadRight 20)
<> " " <> (segment ^. the @"payload" & showLbsLength & trimPadLeft 12)
<> " " <> T.unpack filename
where magic = AP.string "seg:" *> (BS.pack <$> many AP.anyWord8) AP.<?> "\"seg:????\""
showLbsLength :: LBS.ByteString -> String
showLbsLength = show . LBS.length
showPosixSeconds :: POSIXTime -> String
showPosixSeconds t = take 19 (show (posixSecondsToUTCTime t))
trimPadLeft :: Int -> String -> String
trimPadLeft n s
| len < n = replicate (n - len) ' ' <> s
| len == n = s
| otherwise = '<':reverse (take (n - 1) (reverse s))
where len = length s
trimPadRight :: Int -> String -> String
trimPadRight n s
| len < n = s <> replicate (n - len) ' '
| len == n = s
| otherwise = take (n - 1) s <> ">"
where len = length s