{-# LANGUAGE CPP #-}
module Freckle.App.Env
( module Env
, Off (..)
, On (..)
, flag
, Timeout (..)
, kept
, eitherReader
, time
, keyValues
, timeout
) where
import Freckle.App.Prelude
import Control.Error.Util (note)
import Data.Char (isDigit)
import qualified Data.Text as T
import Data.Time (defaultTimeLocale, parseTimeM)
import Env hiding (flag)
import qualified Env
import Env.Internal.Free (hoistAlt)
import Env.Internal.Parser (Parser (..), VarF (..))
import qualified Prelude as Unsafe (read)
newtype Off a = Off a
newtype On a = On a
flag :: Off a -> On a -> String -> Mod Flag a -> Parser Error a
flag :: forall a. Off a -> On a -> String -> Mod Flag a -> Parser Error a
flag (Off a
f) (On a
t) String
n Mod Flag a
m = forall a e. a -> a -> String -> Mod Flag a -> Parser e a
Env.flag a
f a
t String
n Mod Flag a
m
kept :: Parser e a -> Parser e a
kept :: forall e a. Parser e a -> Parser e a
kept = forall e a. Alt (VarF e) a -> Parser e a
Parser forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) (g :: * -> *) b.
Functor g =>
(forall a. f a -> g a) -> Alt f b -> Alt g b
hoistAlt forall {e} {a}. VarF e a -> VarF e a
go forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall e a. Parser e a -> Alt (VarF e) a
unParser
where
go :: VarF e a -> VarF e a
go VarF e a
v =
#if MIN_VERSION_envparse(0,5,0)
VarF e a
v { varfSensitive :: Bool
varfSensitive = Bool
False }
#else
v { varfKeep = True }
#endif
eitherReader :: (String -> Either String a) -> Reader Error a
eitherReader :: forall a. (String -> Either String a) -> Reader Error a
eitherReader String -> Either String a
f String
s = forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first (forall e. AsUnread e => String -> e
unread forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
suffix) forall a b. (a -> b) -> a -> b
$ String -> Either String a
f String
s
where
suffix :: String -> String
suffix String
x = String
x forall a. Semigroup a => a -> a -> a
<> String
": " forall a. Semigroup a => a -> a -> a
<> forall a. Show a => a -> String
show String
s
time :: String -> Reader Error UTCTime
time :: String -> Reader Error UTCTime
time String
fmt =
forall a. (String -> Either String a) -> Reader Error a
eitherReader forall a b. (a -> b) -> a -> b
$
forall a b. a -> Maybe b -> Either a b
note (String
"unable to parse time as " forall a. Semigroup a => a -> a -> a
<> String
fmt)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) t.
(MonadFail m, ParseTime t) =>
Bool -> TimeLocale -> String -> String -> m t
parseTimeM Bool
True TimeLocale
defaultTimeLocale String
fmt
keyValues :: Reader Error [(Text, Text)]
keyValues :: Reader Error [(Text, Text)]
keyValues = forall a. (String -> Either String a) -> Reader Error a
eitherReader forall a b. (a -> b) -> a -> b
$ forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse Text -> Either String (Text, Text)
keyValue forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Text -> [Text]
T.splitOn Text
"," forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
pack
where
keyValue :: Text -> Either String (Text, Text)
keyValue :: Text -> Either String (Text, Text)
keyValue Text
t = case forall (p :: * -> * -> *) b c a.
Bifunctor p =>
(b -> c) -> p a b -> p a c
second (Int -> Text -> Text
T.drop Int
1) forall a b. (a -> b) -> a -> b
$ Text -> Text -> (Text, Text)
T.breakOn Text
":" Text
t of
(Text
k, Text
v) | Text -> Bool
T.null Text
v -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"Key " forall a. Semigroup a => a -> a -> a
<> Text -> String
unpack Text
k forall a. Semigroup a => a -> a -> a
<> String
" has no value"
(Text
k, Text
v) | Text -> Bool
T.null Text
k -> forall a b. a -> Either a b
Left forall a b. (a -> b) -> a -> b
$ String
"Value " forall a. Semigroup a => a -> a -> a
<> Text -> String
unpack Text
v forall a. Semigroup a => a -> a -> a
<> String
" has no key"
(Text
k, Text
v) -> forall a b. b -> Either a b
Right (Text
k, Text
v)
data Timeout
= TimeoutSeconds Int
| TimeoutMilliseconds Int
deriving stock (Int -> Timeout -> String -> String
[Timeout] -> String -> String
Timeout -> String
forall a.
(Int -> a -> String -> String)
-> (a -> String) -> ([a] -> String -> String) -> Show a
showList :: [Timeout] -> String -> String
$cshowList :: [Timeout] -> String -> String
show :: Timeout -> String
$cshow :: Timeout -> String
showsPrec :: Int -> Timeout -> String -> String
$cshowsPrec :: Int -> Timeout -> String -> String
Show, Timeout -> Timeout -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Timeout -> Timeout -> Bool
$c/= :: Timeout -> Timeout -> Bool
== :: Timeout -> Timeout -> Bool
$c== :: Timeout -> Timeout -> Bool
Eq)
timeout :: Reader Error Timeout
timeout :: Reader Error Timeout
timeout = forall a. (String -> Either String a) -> Reader Error a
eitherReader forall a b. (a -> b) -> a -> b
$ forall {a} {a}.
(Eq a, IsString a, IsString a) =>
(String, a) -> Either a Timeout
parseTimeout forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isDigit
where
parseTimeout :: (String, a) -> Either a Timeout
parseTimeout = \case
(String
"", a
_) -> forall a b. a -> Either a b
Left a
"must be {digits}(s|ms)"
(String
digits, a
"") -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ Int -> Timeout
TimeoutSeconds forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> a
Unsafe.read String
digits
(String
digits, a
"s") -> forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ Int -> Timeout
TimeoutSeconds forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> a
Unsafe.read String
digits
(String
digits, a
"ms") ->
forall a b. b -> Either a b
Right forall a b. (a -> b) -> a -> b
$ Int -> Timeout
TimeoutMilliseconds forall a b. (a -> b) -> a -> b
$ forall a. Read a => String -> a
Unsafe.read String
digits
(String, a)
_ -> forall a b. a -> Either a b
Left a
"must be {digits}(s|ms)"