-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Web application deployment manager, focusing on Haskell web frameworks -- -- Handles deployment of web apps, providing a reverse proxy to achieve -- zero downtime deployments. For more information, please see the README -- on Github: https://github.com/snoyberg/keter#readme -- -- Release history: -- -- @package keter @version 1.3.3 module Keter.LabelMap -- | A data structure for storing a hierarchical set of domain labels from -- TLD down, supporting wildcards. -- -- Data structure is mutually recursive with LabelEntry, and each -- level of the tree supports a static assignment for a hostname such as: -- --
--   example.com
--   
-- -- Or a wildcard assignment for a hostname such as: -- --
--   *.example.com
--   
-- -- Or a wildcard assignment with a set of teptions, for example: -- --
--   *.example.com
--   admin.example.com
--   
-- -- And lastly, empty labels are supported so that, of course, an -- assignment for example.com does not necessarily have any subdomains -- available. As an example suppose we have the following assigned -- domains: -- --
--           example.com
--       foo.example.com
--     *.bar.example.com
--     *.qux.example.com
--   baz.qux.example.com
--   
-- -- This will resolve to the following value, with some loose pseudocode -- notation. -- --
--   Static (map)
--     'com' -> Unassigned Static (map)
--       'example' -> Assigned a (map)
--          'foo'  -> Assigned a EmptyLabelMap
--          'bar'  -> Unassigned (Wildcard (Assigned a EmptyLabelMap)
--          'qux'  -> Unassigned (WildcardExcept (Assigned a (map)))
--            'baz' -> Assigned a EmptyLabelMap
--   
-- -- Note that the hostname bar.example.com is unassigned, only the -- wildcard was set. data LabelMap a insert :: ByteString -> a -> LabelMap a -> LabelMap a delete :: ByteString -> LabelMap a -> LabelMap a lookup :: ByteString -> LabelMap a -> Maybe a labelAssigned :: ByteString -> LabelMap a -> Bool empty :: LabelMap a instance Show (LabelMap a) instance Show (LabelEntry a) module Data.Conduit.Process.Unix -- | Represents the child process which handles process cleanup. -- -- Since 0.2.1 data ProcessTracker -- | Fork off the child cleanup process. -- -- This will ideally only be run once for your entire application. -- -- Since 0.2.1 initProcessTracker :: IO ProcessTracker -- | Abstract type containing information on a process which will be -- restarted. data MonitoredProcess -- | Run the given command, restarting if the process dies. monitorProcess :: (ByteString -> IO ()) -> ProcessTracker -> Maybe ByteString -> ByteString -> ByteString -> [ByteString] -> [(ByteString, ByteString)] -> (ByteString -> IO ()) -> (ExitCode -> IO Bool) -> IO MonitoredProcess -- | Terminate the process and prevent it from being restarted. terminateMonitoredProcess :: MonitoredProcess -> IO () instance Typeable ProcessTrackerException instance Show ProcessTrackerException instance Exception ProcessTrackerException module Data.Conduit.LogFile -- | Represents a folder used for totating log files. -- -- Since 0.2.1 data RotatingLog -- | Create a new RotatingLog. -- -- Since 0.2.1 openRotatingLog :: FilePath -> Word -> IO RotatingLog addChunk :: RotatingLog -> ByteString -> IO () close :: RotatingLog -> IO () defaultMaxTotal :: Word -- | A RotatingLog which performs no logging. -- -- Since 0.2.1 dummy :: RotatingLog -- | Handles allocation of temporary directories and unpacking of bundles -- into them. Sets owner and group of all created files and directories -- as necessary. module Codec.Archive.TempTarball data TempFolder setup :: FilePath -> IO TempFolder unpackTempTar :: Maybe (UserID, GroupID) -> TempFolder -> FilePath -> Text -> (FilePath -> IO a) -> IO a -- | Utilities for dealing with YAML config files which contain relative -- file paths. module Data.Yaml.FilePath -- | Parse a config file, using the ParseYamlFile typeclass. decodeFileRelative :: ParseYamlFile a => FilePath -> IO (Either ParseException a) -- | A replacement for the .: operator which will both parse a -- file path and apply the relative file logic. lookupBase :: ParseYamlFile a => BaseDir -> Object -> Text -> Parser a -- | A replacement for the .:? operator which will both parse a -- file path and apply the relative file logic. lookupBaseMaybe :: ParseYamlFile a => BaseDir -> Object -> Text -> Parser (Maybe a) -- | The directory from which we're reading the config file. data BaseDir -- | A replacement for the standard FromJSON typeclass which can -- handle relative filepaths. class ParseYamlFile a parseYamlFile :: ParseYamlFile a => BaseDir -> Value -> Parser a data NonEmptyVector a NonEmptyVector :: !a -> !(Vector a) -> NonEmptyVector a instance ParseYamlFile a => ParseYamlFile (NonEmptyVector a) instance ParseYamlFile a => ParseYamlFile (Vector a) instance (ParseYamlFile a, Ord a) => ParseYamlFile (Set a) instance ParseYamlFile FilePath module Network.HTTP.ReverseProxy.Rewrite data ReverseProxyConfig ReverseProxyConfig :: Text -> Int -> Text -> Bool -> Maybe Int -> Set RewriteRule -> Set RewriteRule -> ReverseProxyConfig reversedHost :: ReverseProxyConfig -> Text reversedPort :: ReverseProxyConfig -> Int reversingHost :: ReverseProxyConfig -> Text reverseUseSSL :: ReverseProxyConfig -> Bool reverseTimeout :: ReverseProxyConfig -> Maybe Int rewriteResponseRules :: ReverseProxyConfig -> Set RewriteRule rewriteRequestRules :: ReverseProxyConfig -> Set RewriteRule data RewriteRule RewriteRule :: Text -> Text -> Text -> RewriteRule ruleHeader :: RewriteRule -> Text ruleRegex :: RewriteRule -> Text ruleReplacement :: RewriteRule -> Text data RPEntry RPEntry :: ReverseProxyConfig -> Manager -> RPEntry config :: RPEntry -> ReverseProxyConfig httpManager :: RPEntry -> Manager simpleReverseProxy :: Manager -> ReverseProxyConfig -> Application instance Eq RewriteRule instance Ord RewriteRule instance Show RewriteRule instance Eq ReverseProxyConfig instance Ord ReverseProxyConfig instance Show ReverseProxyConfig instance ToJSON RewriteRule instance FromJSON RewriteRule instance Default ReverseProxyConfig instance ToJSON ReverseProxyConfig instance FromJSON ReverseProxyConfig instance Show RPEntry module Keter.Types.Common -- | Name of the application. Should just be the basename of the -- application file. type Appname = Text data Plugin Plugin :: (Appname -> Object -> IO [(Text, Text)]) -> Plugin pluginGetEnv :: Plugin -> Appname -> Object -> IO [(Text, Text)] type Plugins = [Plugin] -- | Used for versioning data types. class ToCurrent a where type family Previous a toCurrent :: ToCurrent a => Previous a -> a -- | A port for an individual app to listen on. type Port = Int -- | A virtual host we want to serve content from. type Host = Text type HostBS = ByteString getAppname :: FilePath -> Text data LogMessage ProcessCreated :: FilePath -> LogMessage InvalidBundle :: FilePath -> SomeException -> LogMessage ProcessDidNotStart :: FilePath -> LogMessage ExceptionThrown :: Text -> SomeException -> LogMessage RemovingPort :: Int -> LogMessage UnpackingBundle :: FilePath -> LogMessage TerminatingApp :: Text -> LogMessage FinishedReloading :: Text -> LogMessage TerminatingOldProcess :: AppId -> LogMessage RemovingOldFolder :: FilePath -> LogMessage ReceivedInotifyEvent :: Text -> LogMessage ProcessWaiting :: FilePath -> LogMessage OtherMessage :: Text -> LogMessage ErrorStartingBundle :: Text -> SomeException -> LogMessage SanityChecksPassed :: LogMessage ReservingHosts :: AppId -> (Set Host) -> LogMessage ForgetingReservations :: AppId -> (Set Host) -> LogMessage ActivatingApp :: AppId -> (Set Host) -> LogMessage DeactivatingApp :: AppId -> (Set Host) -> LogMessage ReactivatingApp :: AppId -> (Set Host) -> (Set Host) -> LogMessage WatchedFile :: Text -> FilePath -> LogMessage data KeterException CannotParsePostgres :: FilePath -> KeterException ExitCodeFailure :: FilePath -> ExitCode -> KeterException NoPortsAvailable :: KeterException InvalidConfigFile :: ParseException -> KeterException InvalidKeterConfigFile :: !FilePath -> !ParseException -> KeterException CannotReserveHosts :: !AppId -> !(Map Host AppId) -> KeterException FileNotExecutable :: !FilePath -> KeterException ExecutableNotFound :: !FilePath -> KeterException logEx :: Q Exp data AppId AIBuiltin :: AppId AINamed :: !Appname -> AppId data FilePath :: * -- | A space efficient, packed, unboxed Unicode text type. data Text :: * -- | A space-efficient representation of a Word8 vector, supporting -- many efficient operations. -- -- A ByteString contains 8-bit bytes, or by using the operations -- from Data.ByteString.Char8 it can be interpreted as containing -- 8-bit characters. data ByteString :: * -- | A set of values a. data Set a :: * -> * -- | A Map from keys k to values a. data Map k a :: * -> * -> * -- | Any type that you wish to throw or catch as an exception must be an -- instance of the Exception class. The simplest case is a new -- exception type directly below the root: -- --
--   data MyException = ThisException | ThatException
--       deriving (Show, Typeable)
--   
--   instance Exception MyException
--   
-- -- The default method definitions in the Exception class do what -- we need in this case. You can now throw and catch -- ThisException and ThatException as exceptions: -- --
--   *Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException))
--   Caught ThisException
--   
-- -- In more complicated examples, you may wish to define a whole hierarchy -- of exceptions: -- --
--   ---------------------------------------------------------------------
--   -- Make the root exception type for all the exceptions in a compiler
--   
--   data SomeCompilerException = forall e . Exception e => SomeCompilerException e
--       deriving Typeable
--   
--   instance Show SomeCompilerException where
--       show (SomeCompilerException e) = show e
--   
--   instance Exception SomeCompilerException
--   
--   compilerExceptionToException :: Exception e => e -> SomeException
--   compilerExceptionToException = toException . SomeCompilerException
--   
--   compilerExceptionFromException :: Exception e => SomeException -> Maybe e
--   compilerExceptionFromException x = do
--       SomeCompilerException a <- fromException x
--       cast a
--   
--   ---------------------------------------------------------------------
--   -- Make a subhierarchy for exceptions in the frontend of the compiler
--   
--   data SomeFrontendException = forall e . Exception e => SomeFrontendException e
--       deriving Typeable
--   
--   instance Show SomeFrontendException where
--       show (SomeFrontendException e) = show e
--   
--   instance Exception SomeFrontendException where
--       toException = compilerExceptionToException
--       fromException = compilerExceptionFromException
--   
--   frontendExceptionToException :: Exception e => e -> SomeException
--   frontendExceptionToException = toException . SomeFrontendException
--   
--   frontendExceptionFromException :: Exception e => SomeException -> Maybe e
--   frontendExceptionFromException x = do
--       SomeFrontendException a <- fromException x
--       cast a
--   
--   ---------------------------------------------------------------------
--   -- Make an exception type for a particular frontend compiler exception
--   
--   data MismatchedParentheses = MismatchedParentheses
--       deriving (Typeable, Show)
--   
--   instance Exception MismatchedParentheses where
--       toException   = frontendExceptionToException
--       fromException = frontendExceptionFromException
--   
-- -- We can now catch a MismatchedParentheses exception as -- MismatchedParentheses, SomeFrontendException or -- SomeCompilerException, but not other types, e.g. -- IOException: -- --
--   *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
--   Caught MismatchedParentheses
--   *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
--   Caught MismatchedParentheses
--   *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
--   Caught MismatchedParentheses
--   *Main> throw MismatchedParentheses catch e -> putStrLn ("Caught " ++ show (e :: IOException))
--   *** Exception: MismatchedParentheses
--   
class (Typeable e, Show e) => Exception e -- | The SomeException type is the root of the exception type -- hierarchy. When an exception of type e is thrown, behind the -- scenes it is encapsulated in a SomeException. data SomeException :: * instance Typeable KeterException instance Eq AppId instance Ord AppId instance Show KeterException instance Show AppId instance Exception KeterException instance Show LogMessage instance ToCurrent a => ToCurrent (Maybe a) -- | Legacy types from Keter version 0.4. Retained to keep backwards -- compatibility in config file format. module Keter.Types.V04 data AppConfig AppConfig :: FilePath -> [Text] -> Text -> Bool -> Set Text -> Object -> AppConfig configExec :: AppConfig -> FilePath configArgs :: AppConfig -> [Text] configHost :: AppConfig -> Text configSsl :: AppConfig -> Bool configExtraHosts :: AppConfig -> Set Text configRaw :: AppConfig -> Object data BundleConfig BundleConfig :: Maybe AppConfig -> Set StaticHost -> Set Redirect -> BundleConfig bconfigApp :: BundleConfig -> Maybe AppConfig bconfigStaticHosts :: BundleConfig -> Set StaticHost bconfigRedirects :: BundleConfig -> Set Redirect data StaticHost StaticHost :: Text -> FilePath -> StaticHost shHost :: StaticHost -> Text shRoot :: StaticHost -> FilePath data Redirect Redirect :: Text -> Text -> Redirect redFrom :: Redirect -> Text redTo :: Redirect -> Text data KeterConfig KeterConfig :: FilePath -> PortSettings -> HostPreference -> Port -> Maybe TLSConfig -> Maybe Text -> Set ReverseProxyConfig -> Bool -> KeterConfig kconfigDir :: KeterConfig -> FilePath kconfigPortMan :: KeterConfig -> PortSettings kconfigHost :: KeterConfig -> HostPreference kconfigPort :: KeterConfig -> Port kconfigSsl :: KeterConfig -> Maybe TLSConfig kconfigSetuid :: KeterConfig -> Maybe Text kconfigReverseProxy :: KeterConfig -> Set ReverseProxyConfig kconfigIpFromHeader :: KeterConfig -> Bool data TLSConfig TLSConfig :: !Settings -> !TLSSettings -> TLSConfig -- | Controls execution of the nginx thread. Follows the settings type -- pattern. See: http://www.yesodweb.com/book/settings-types. data PortSettings PortSettings :: [Port] -> PortSettings -- | Which ports to assign to apps. Defaults to unassigned ranges from IANA portRange :: PortSettings -> [Port] instance Eq StaticHost instance Ord StaticHost instance Eq Redirect instance Ord Redirect instance FromJSON PortSettings instance Default PortSettings instance ParseYamlFile TLSConfig instance ParseYamlFile KeterConfig instance Default KeterConfig instance FromJSON Redirect instance ParseYamlFile StaticHost instance ParseYamlFile BundleConfig instance ParseYamlFile AppConfig module Keter.Types.V10 data BundleConfig BundleConfig :: !(Vector (Stanza ())) -> !Object -> BundleConfig bconfigStanzas :: BundleConfig -> !(Vector (Stanza ())) -- | settings used for plugins bconfigPlugins :: BundleConfig -> !Object data ListeningPort LPSecure :: !HostPreference -> !Port -> !FilePath -> !FilePath -> ListeningPort LPInsecure :: !HostPreference -> !Port -> ListeningPort data KeterConfig KeterConfig :: FilePath -> PortSettings -> !(NonEmptyVector ListeningPort) -> Maybe Text -> !(Vector (Stanza ())) -> Bool -> KeterConfig kconfigDir :: KeterConfig -> FilePath kconfigPortPool :: KeterConfig -> PortSettings kconfigListeners :: KeterConfig -> !(NonEmptyVector ListeningPort) kconfigSetuid :: KeterConfig -> Maybe Text kconfigBuiltinStanzas :: KeterConfig -> !(Vector (Stanza ())) kconfigIpFromHeader :: KeterConfig -> Bool data Stanza port StanzaStaticFiles :: !StaticFilesConfig -> Stanza port StanzaRedirect :: !RedirectConfig -> Stanza port StanzaWebApp :: !(WebAppConfig port) -> Stanza port StanzaReverseProxy :: !ReverseProxyConfig -> Stanza port StanzaBackground :: !BackgroundConfig -> Stanza port -- | An action to be performed for a requested hostname. -- -- This datatype is very similar to Stanza, but is necessarily separate -- since: -- --
    --
  1. Webapps will be assigned ports.
  2. --
  3. Not all stanzas have an associated proxy action.
  4. --
data ProxyAction PAPort :: Port -> ProxyAction PAStatic :: StaticFilesConfig -> ProxyAction PARedirect :: RedirectConfig -> ProxyAction PAReverseProxy :: ReverseProxyConfig -> ProxyAction addStanzaType :: ToJSON a => Value -> a -> Value data StaticFilesConfig StaticFilesConfig :: !FilePath -> !(Set Host) -> !Bool -> StaticFilesConfig sfconfigRoot :: StaticFilesConfig -> !FilePath sfconfigHosts :: StaticFilesConfig -> !(Set Host) sfconfigListings :: StaticFilesConfig -> !Bool data RedirectConfig RedirectConfig :: !(Set Host) -> !Int -> !(Vector RedirectAction) -> RedirectConfig redirconfigHosts :: RedirectConfig -> !(Set Host) redirconfigStatus :: RedirectConfig -> !Int redirconfigActions :: RedirectConfig -> !(Vector RedirectAction) data RedirectAction RedirectAction :: !SourcePath -> !RedirectDest -> RedirectAction data SourcePath SPAny :: SourcePath SPSpecific :: !Text -> SourcePath data RedirectDest RDUrl :: !Text -> RedirectDest RDPrefix :: !IsSecure -> !Host -> !(Maybe Port) -> RedirectDest type IsSecure = Bool data WebAppConfig port WebAppConfig :: !FilePath -> !(Vector Text) -> !(Map Text Text) -> !Text -> !(Set Text) -> !Bool -> !port -> WebAppConfig port waconfigExec :: WebAppConfig port -> !FilePath waconfigArgs :: WebAppConfig port -> !(Vector Text) waconfigEnvironment :: WebAppConfig port -> !(Map Text Text) -- | primary host, used for approot waconfigApprootHost :: WebAppConfig port -> !Text -- | all hosts, not including the approot host waconfigHosts :: WebAppConfig port -> !(Set Text) waconfigSsl :: WebAppConfig port -> !Bool waconfigPort :: WebAppConfig port -> !port data AppInput AIBundle :: !FilePath -> !EpochTime -> AppInput AIData :: !BundleConfig -> AppInput data BackgroundConfig BackgroundConfig :: !FilePath -> !(Vector Text) -> !(Map Text Text) -> !RestartCount -> !Word -> BackgroundConfig bgconfigExec :: BackgroundConfig -> !FilePath bgconfigArgs :: BackgroundConfig -> !(Vector Text) bgconfigEnvironment :: BackgroundConfig -> !(Map Text Text) bgconfigRestartCount :: BackgroundConfig -> !RestartCount bgconfigRestartDelaySeconds :: BackgroundConfig -> !Word data RestartCount UnlimitedRestarts :: RestartCount LimitedRestarts :: !Word -> RestartCount instance Show StaticFilesConfig instance Show SourcePath instance Show RedirectDest instance Show RedirectAction instance Show RedirectConfig instance Show ProxyAction instance Show port => Show (WebAppConfig port) instance Show RestartCount instance Show BackgroundConfig instance Show port => Show (Stanza port) instance ToJSON BackgroundConfig instance ParseYamlFile BackgroundConfig instance FromJSON RestartCount instance ToJSON (WebAppConfig ()) instance ParseYamlFile (WebAppConfig ()) instance ToCurrent (WebAppConfig ()) instance ToJSON RedirectDest instance FromJSON RedirectDest instance ToJSON RedirectAction instance FromJSON RedirectAction instance ToJSON RedirectConfig instance ParseYamlFile RedirectConfig instance ToCurrent RedirectConfig instance ToJSON StaticFilesConfig instance ParseYamlFile StaticFilesConfig instance ToCurrent StaticFilesConfig instance ToJSON (Stanza ()) instance ParseYamlFile (Stanza ()) instance ParseYamlFile KeterConfig instance Default KeterConfig instance ToCurrent KeterConfig instance ParseYamlFile ListeningPort instance ToJSON BundleConfig instance ParseYamlFile BundleConfig instance ToCurrent BundleConfig module Keter.Types module Keter.HostManager data HostManager type Reservations = Set Host -- | Reserve the given hosts so that no other application may use them. -- Does not yet enable any action. The semantics are: -- --
    --
  1. If a requested host is currently actively used or by an app of the -- same name, it is considered reserved.
  2. --
  3. If a requested host is currently reserved by an app of the same -- name, it is considered an error in calling this API. Only one app -- reservation can happen at a time.
  4. --
  5. If any requested host is currently used or reserved by an app with -- a different name, then those values are returned as -- Left.
  6. --
  7. Otherwise, the hosts which were reserved are returned as -- Right. This does not include previously active -- hosts.
  8. --
reserveHosts :: (LogMessage -> IO ()) -> HostManager -> AppId -> Set Host -> IO Reservations -- | Forget previously made reservations. forgetReservations :: (LogMessage -> IO ()) -> HostManager -> AppId -> Reservations -> IO () -- | Activate a new app. Note that you must first reserve the -- hostnames you'll be using. activateApp :: (LogMessage -> IO ()) -> HostManager -> AppId -> Map Host ProxyAction -> IO () deactivateApp :: (LogMessage -> IO ()) -> HostManager -> AppId -> Set Host -> IO () reactivateApp :: (LogMessage -> IO ()) -> HostManager -> AppId -> Map Host ProxyAction -> Set Host -> IO () lookupAction :: HostManager -> HostBS -> IO (Maybe ProxyAction) start :: IO HostManager -- | Manages a pool of available ports and allocates them. module Keter.PortPool data PortPool -- | Gets an unassigned port number. getPort :: (LogMessage -> IO ()) -> PortPool -> IO (Either SomeException Port) -- | Return a port to the recycled collection of the pool. Note that -- recycling puts the new ports at the end of the queue (FIFO), so that -- if an application holds onto the port longer than expected, there -- should be no issues. releasePort :: PortPool -> Port -> IO () start :: PortSettings -> IO PortPool module Keter.App data App data AppStartConfig AppStartConfig :: !TempFolder -> !(Maybe (Text, (UserID, GroupID))) -> !ProcessTracker -> !HostManager -> !PortPool -> !Plugins -> !(LogMessage -> IO ()) -> !KeterConfig -> AppStartConfig ascTempFolder :: AppStartConfig -> !TempFolder ascSetuid :: AppStartConfig -> !(Maybe (Text, (UserID, GroupID))) ascProcessTracker :: AppStartConfig -> !ProcessTracker ascHostManager :: AppStartConfig -> !HostManager ascPortPool :: AppStartConfig -> !PortPool ascPlugins :: AppStartConfig -> !Plugins ascLog :: AppStartConfig -> !(LogMessage -> IO ()) ascKeterConfig :: AppStartConfig -> !KeterConfig start :: AppStartConfig -> AppId -> AppInput -> IO App reload :: App -> AppInput -> IO () -- | Get the modification time of the bundle file this app was launched -- from, if relevant. getTimestamp :: App -> STM (Maybe EpochTime) terminate :: App -> IO () -- | Used for management of applications. module Keter.AppManager data AppManager data Action Reload :: AppInput -> Action Terminate :: Action perform :: AppManager -> AppId -> Action -> IO () -- | Reset which apps are running. -- -- reloadAppList :: AppManager -> Map Appname (FilePath, EpochTime) -> IO () addApp :: AppManager -> FilePath -> IO () terminateApp :: AppManager -> Appname -> IO () initialize :: (LogMessage -> IO ()) -> AppStartConfig -> IO AppManager -- | A light-weight, minimalistic reverse HTTP proxy. module Keter.Proxy reverseProxy :: Bool -> Manager -> HostLookup -> ListeningPort -> IO () -- | Mapping from virtual hostname to port number. type HostLookup = ByteString -> IO (Maybe ProxyAction) data TLSConfig TLSConfig :: !Settings -> !TLSSettings -> TLSConfig module Keter.Main keter :: FilePath -> [FilePath -> IO Plugin] -> IO () module Keter.Plugin.Postgres data Settings -- | How to create the given user/database. Default: uses the psql -- command line tool and sudo -u postgres. setupDBInfo :: Settings -> DBInfo -> IO () -- | Load a set of existing connections from a config file. If the file -- does not exist, it will be created. Any newly created databases will -- automatically be saved to this file. load :: Settings -> FilePath -> IO Plugin instance Show DBInfo instance FromJSON DBInfo instance ToJSON DBInfo instance Default Settings