phatsort-0.5.0.1: app/seqcp.hs
------------------------------------------------------------------------------
-- |
-- Module : Main
-- Description : seqcp CLI
-- Copyright : Copyright (c) 2019-2022 Travis Cardwell
-- License : MIT
------------------------------------------------------------------------------
{-# LANGUAGE RecordWildCards #-}
module Main (main) where
-- https://hackage.haskell.org/package/base
import Control.Applicative (some)
import Data.Bifunctor (first)
import Data.List.NonEmpty (nonEmpty)
import System.Exit (ExitCode(ExitFailure), exitWith)
import System.IO (hPutStrLn, stderr)
-- https://hackage.haskell.org/package/optparse-applicative
import qualified Options.Applicative as OA
-- (phatsort)
import PhatSort (version)
import PhatSort.Cmd.SeqCp
( Options
( Options, optCase, optFirst, optSync, optOrder, optReverse, optScript
, optVerbose, optSources, optDestination
)
, runIO
)
import PhatSort.SortOptions (SortCase, SortFirst, SortOrder)
-- (phatsort:executable)
import qualified LibOA
import Options
( caseOption, exitCodeHelp, firstOption, firstTypeHelp, noSyncOption
, orderHelp, orderOption, reverseOption, scriptOption, verboseOption
)
------------------------------------------------------------------------------
data Options'
= Options'
{ optCase :: !SortCase
, optFirst :: !SortFirst
, optSync :: !Bool
, optOrder :: !SortOrder
, optReverse :: !Bool
, optScript :: !Bool
, optVerbose :: !Bool
, optArgs :: ![FilePath]
}
deriving Show
------------------------------------------------------------------------------
options :: OA.Parser Options'
options = Options'
<$> caseOption
<*> firstOption
<*> noSyncOption
<*> orderOption
<*> reverseOption
<*> scriptOption
<*> verboseOption
<*> arguments
------------------------------------------------------------------------------
arguments :: OA.Parser [FilePath]
arguments = some . OA.strArgument $ mconcat
[ OA.metavar "SOURCE ... DESTINATION"
, OA.help "source directories/files and destination directory"
]
------------------------------------------------------------------------------
parseOptions :: IO Options
parseOptions = processOptions =<< OA.execParser info
where
info :: OA.ParserInfo Options'
info
= OA.info (LibOA.helper <*> LibOA.versioner version <*> options)
$ mconcat
[ OA.fullDesc
, OA.progDesc "sequentially copy files and directories"
, OA.failureCode 2
, OA.footerDoc . Just $ LibOA.vspace
[ firstTypeHelp
, orderHelp
, exitCodeHelp
]
]
processOptions :: Options' -> IO Options
processOptions Options'{..} = case first nonEmpty <$> unsnoc optArgs of
Just (Just optSources, optDestination) -> pure Options{..}
Just (Nothing, _destination) -> usageExit "Missing: DESTINATION"
Nothing -> usageExit "Missing: SOURCE ... DESTINATION"
unsnoc :: [FilePath] -> Maybe ([FilePath], FilePath)
unsnoc (x:xs)
| null xs = Just ([], x)
| otherwise = first (x :) <$> unsnoc xs
unsnoc [] = Nothing
usageExit :: String -> IO a
usageExit msg = OA.handleParseResult . OA.Failure $
OA.parserFailure OA.defaultPrefs info (OA.ErrorMsg msg) []
------------------------------------------------------------------------------
errorExit :: String -> IO a
errorExit message = do
hPutStrLn stderr $ "error: " ++ message
exitWith $ ExitFailure 1
------------------------------------------------------------------------------
main :: IO ()
main = either errorExit pure =<< runIO =<< parseOptions