pub 2.0.2 → 3.0.0
raw patch · 8 files changed
+164/−291 lines, 8 filesdep +optparse-genericdep −ConfigFiledep −cmdargsdep −containersdep ~basedep ~bytestringdep ~hedis
Dependencies added: optparse-generic
Dependencies removed: ConfigFile, cmdargs, containers, groom, hslogger, mtl, network, safe, system-filepath, time, transformers
Dependency ranges changed: base, bytestring, hedis, pipes, pipes-bytestring, text
Files
- Makefile +0/−21
- README.md +53/−0
- README.org +0/−21
- pub.cabal +16/−65
- pub/Main.hs +48/−26
- pub/Pub/Internal.hs +0/−66
- sub/Main.hs +47/−26
- sub/Sub/Internal.hs +0/−66
− Makefile
@@ -1,21 +0,0 @@-.PHONY: test--prog = ghc-path = /usr/bin/ghc-7.6.3--all: deps build install--tags:- hasktags --etags --output='TAGS' *--build:- cabal configure --with-$(prog)=$(path) && cabal build --with-$(prog)=$(path)--install:- cabal install -w $(path)--deps:- cabal install --only-dependencies -w $(path)--test: build- cabal test
+ README.md view
@@ -0,0 +1,53 @@+# Welcome!++++The `pub` utility publishes input from stdin to a redis channel and the `sub`+utility consumes from a redis channel, writing to stdout.++## Quickstart+Publishing to Redis from `stdin` is easy with the `pub` utility:+```shell+$ pub --help+Pipe stdin to a redis pub/sub channel++Usage: pub --channel TEXT [--host STRING] [--port INTEGER] [--db INTEGER]+ [--version]++Available options:+ -h,--help Show this help text+ --channel TEXT Redis channel to publish to+ --host STRING Redis host (default: localhost)+ --port INTEGER Redis post (default: 6379)+ --db INTEGER Redis db (default: 0)++$ journalctl -f nginx.service | pub --channel "nginx-loglines"+```++and subscribing to Redis channels and piping to `stdout` is also easy with the+`sub` utility:++```shell+$ sub --help+Subscribe to redis channels and pipe to stdout++Usage: sub [--channel TEXT]... [--host STRING] [--port INTEGER] [--db INTEGER]+ [--version]++Available options:+ -h,--help Show this help text+ --channel TEXT... Redis channel(s) to subscribe to+ --host STRING Redis host (default: localhost)+ --port INTEGER Redis post (default: 6379)+ --db INTEGER Redis db (default: 0)++$ sub --channel "nginx-loglines" --channel "haproxy-loglines" # This subscribes to both redis channels+```++## Building+You can build multiple ways:++- `stack build`+- `cabal build`+- `nix-build --not-out-link -A pub release.nix`+- `nix-shell -A pub.env release.nix`
− README.org
@@ -1,21 +0,0 @@-* Welcome!- [[https://hackage.haskell.org/package/pub][https://img.shields.io/hackage/v/pub.svg?style=flat]]- [[https://travis-ci.org/ixmatus/pub][https://travis-ci.org/ixmatus/pub.svg?branch=master]]-- =Pub= builds two utilities for piping to and from a redis pub/sub- channel and stdout/stdin.--** Install- =cabal install pub=--** Examples--*** Using pub- #+BEGIN_SRC- tail -F /some/log/file | grep "logfileProperty" | pub "logline"- #+END_SRC--*** Using sub- #+BEGIN_SRC- sub "logline" | grep "somethingspecific"- #+END_SRC
pub.cabal view
@@ -1,5 +1,5 @@ Name: pub-Version: 2.0.2+Version: 3.0.0 Author: Parnell Springmeyer <parnell@digitalmentat.com> Maintainer: Parnell Springmeyer <parnell@digitalmentat.com> License: BSD3@@ -29,83 +29,34 @@ Build-Type: Simple Data-Files:- Makefile LICENSE- README.org+ README.md Executable pub Default-Language: Haskell2010 HS-Source-Dirs: pub- GHC-Options: -threaded -Wall -fwarn-tabs -funbox-strict-fields- -fno-warn-orphans -fno-warn-unused-do-bind -rtsopts -with-rtsopts=-N+ GHC-Options: -threaded -Wall -rtsopts -with-rtsopts=-N Main-Is: Main.hs- Other-Modules: Pub.Internal- Build-Depends:- base >= 4 && < 5,- network >= 2.4.2.2 && < 2.5,- bytestring >= 0.10.0.2 && < 0.10.1,- cmdargs >= 0.10.7 && < 0.11,- hslogger >= 1.2.3 && < 1.3,- ConfigFile >= 1.1.1 && < 1.2,- text >= 1.1.0.1 && < 1.2,- safe >= 0.3 && < 0.4,- containers >= 0.5.0.0 && < 0.6,- hedis >= 0.6 && < 0.7,- pipes >= 4.1.1 && < 4.2,- pipes-bytestring >= 2 && < 3,- mtl >= 2.1 && < 2.3,- system-filepath >= 0.4.12 && < 0.5,- groom >= 0.1.2 && < 0.2,- time >= 1.4 && < 1.5,- transformers >= 0.4 && < 0.5+ base >= 4.9 && < 5+ , bytestring >= 0.10.8.1 && < 0.11+ , hedis >= 0.9.5 && < 1.0+ , optparse-generic >= 1.1.5 && < 2.0+ , pipes >= 4.1.9 && < 5.0+ , pipes-bytestring >= 2.1.4 && < 3.0+ , text >= 1.2.2.1 && < 2.0 Executable sub Default-Language: Haskell2010 HS-Source-Dirs: sub- GHC-Options: -threaded -Wall -fwarn-tabs -funbox-strict-fields- -fno-warn-orphans -fno-warn-unused-do-bind -rtsopts -with-rtsopts=-N+ GHC-Options: -threaded -Wall -rtsopts -with-rtsopts=-N Main-Is: Main.hs- Other-Modules: Sub.Internal- Build-Depends:- base >= 4 && < 5,- network >= 2.4.2.2 && < 2.5,- bytestring >= 0.10.0.2 && < 0.10.1,- cmdargs >= 0.10.7 && < 0.11,- hslogger >= 1.2.3 && < 1.3,- ConfigFile >= 1.1.1 && < 1.2,- text >= 1.1.0.1 && < 1.2,- safe >= 0.3 && < 0.4,- containers >= 0.5.0.0 && < 0.6,- hedis >= 0.6 && < 0.7,- mtl >= 2.1 && < 2.3,- system-filepath >= 0.4.12 && < 0.5,- groom >= 0.1.2 && < 0.2,- time >= 1.4 && < 1.5,- transformers >= 0.4 && < 0.5---- Test-Suite tests--- Type: exitcode-stdio-1.0--- Default-Language: Haskell2010--- Hs-Source-Dirs: test, src--- Ghc-Options: -Wall--- Main-Is: Test.hs--- Other-Modules: Pub.Internal---- Build-Depends:--- base >= 4.4 && < 5,--- groom >= 0.1.2 && < 0.2,--- cmdargs >= 0.10.7 && < 0.11,--- hslogger >= 1.2.3 && < 1.3,--- system-filepath >= 0.4.12 && < 0.5,--- bytestring >= 0.9.1 && < 0.11,--- QuickCheck >= 2.6 && < 2.8,--- HUnit >= 1.2.5.2 && < 1.3,--- tasty >= 0.8 && < 0.9,--- tasty-golden >= 2.2.1 && < 2.3,--- tasty-hunit >= 0.8.0.1 && < 0.9,--- tasty-quickcheck >= 0.8 && < 0.9+ base >= 4.9 && < 5+ , bytestring >= 0.10.8.1 && < 0.11+ , hedis >= 0.9.5 && < 1.0+ , optparse-generic >= 1.1.5 && < 2.0+ , text >= 1.2.2.1 && < 2.0 Source-Repository head Type: git
pub/Main.hs view
@@ -5,38 +5,60 @@ -- License : AllRightsReserved -- Maintainer : Parnell Springmeyer <parnell@digitalmentat.com> -- Stability : stable------ This is the entry point for the `pub` executable. Main sets up--- the cli options configuration and parses configuration file options. ---------------------------------------------------------------------------- -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeOperators #-} module Main where -import Data.Version (showVersion)-import Paths_pub (version)-import System.Console.CmdArgs+import Control.Monad+import Data.ByteString (ByteString)+import Data.Maybe+import Data.Version (showVersion)+import qualified Database.Redis as Redis+import Options.Generic+import qualified Paths_pub as Pub+import Pipes+import qualified Pipes.ByteString+import qualified System.IO -import Pub-import Pub.Internal+data Options w = Options+ { channel :: w ::: ByteString <?> "Redis channel to publish to"+ , host :: w ::: Maybe String <?> "Redis host (default: localhost)"+ , port :: w ::: Maybe Integer <?> "Redis post (default: 6379)"+ , db :: w ::: Maybe Integer <?> "Redis db (default: 0)"+ , version :: Bool+ } deriving (Generic) --- | Command line argument configuration.------ Help messages, switches, options, and the human-readable version--- number is configured here.-programArgs :: PArgs-programArgs = PArgs- { chan = def &= argPos 0 &= typ "CHANNEL"- , host = def &= name "h" &= typ "STRING" &= help "Redis host (default `localhost`)"- , port = def &= name "p" &= help "Redis port (default `6379`)"- , db = def &= name "d" &= help "Redis database (default `0`)"- } &=- verbosity &=- help "Pipe stdin to a pub/sub channel." &=- summary ("pub v" ++ showVersion version) &=- noAtExpand &=- details ["Given an input on stdin, pipe to a redis pub/sub channel."]+instance ParseRecord (Options Wrapped)+deriving instance Show (Options Unwrapped) main :: IO ()-main = cmdArgs programArgs >>= handleOpts >>= pipePublish+main = do+ Options{..} <- unwrapRecord "Pipe stdin to a redis pub/sub channel"+ let stderr = System.IO.stderr+ when version $+ System.IO.hPutStrLn stderr (showVersion Pub.version)+ conn <-+ Redis.connect+ Redis.defaultConnectInfo+ { Redis.connectHost = (fromMaybe "localhost" host)+ , Redis.connectPort = Redis.PortNumber (fromInteger $ fromMaybe 6379 port)+ , Redis.connectDatabase = fromMaybe 0 db+ }++ let publish =+ (\value ->+ -- TODO: should we use runRedis here!?!?+ lift (Redis.runRedis conn $ Redis.publish channel value) >>= \case+ Left reply -> lift (System.IO.hPutStrLn stderr $ show reply)+ Right _ -> pure ())++ runEffect (for Pipes.ByteString.stdin publish)
− pub/Pub/Internal.hs
@@ -1,66 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Pub.Internal--- Copyright : (C) 2014 Parnell Springmeyer--- License : AllRightsReserved--- Maintainer : Parnell Springmeyer <parnell@digitalmentat.com>--- Stability : stable------ Internal functions and types for the `Main` program. Mostly--- responsible for defining the `cmdargs` data type, parsing--- configuration, and setting the log level.-------------------------------------------------------------------------------{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Pub.Internal where--import Control.Applicative-import qualified Data.ByteString.Char8 as C8-import Database.Redis as R-import Network.Socket.Internal as NSI (PortNumber)-import System.Console.CmdArgs-import System.Log.Logger-import Text.Groom (groom)---- | Data type for program CLI options.-data PArgs = PArgs- { chan :: String- , host :: Maybe String- , port :: Maybe Integer- , db :: Maybe Integer- } deriving (Data, Typeable, Show, Eq)---- | Data type for settings once merged from CLI.-data Settings = Settings- { loglevel :: !Priority- , channel :: C8.ByteString- , redisHost :: Maybe HostName- , redisPort :: Maybe PortID- , redisDB :: Maybe Integer- } deriving (Show, Eq)---- | Given options, set the logging level, and create the settings--- record.-handleOpts :: PArgs -> IO Settings-handleOpts cliopts = do- whenNormal $ updateGlobalLogger "Console" (setLevel ERROR)- whenLoud $ updateGlobalLogger "Console" (setLevel DEBUG)-- let c = C8.pack $ chan cliopts- p = (fromInteger <$> (port cliopts)) :: Maybe NSI.PortNumber- conf = Settings { loglevel = INFO- , channel = c- , redisHost = host cliopts- , redisPort = R.PortNumber <$> p- , redisDB = db cliopts- }-- debugM "Console" "Configuration parsed"- debugM "Console" $ groom conf-- return conf
sub/Main.hs view
@@ -5,38 +5,59 @@ -- License : AllRightsReserved -- Maintainer : Parnell Springmeyer <parnell@digitalmentat.com> -- Stability : stable------ This is the entry point for the `sub` executable. Main sets up--- the cli options configuration and parses configuration file options. ---------------------------------------------------------------------------- -{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE StandaloneDeriving #-}+{-# LANGUAGE TypeOperators #-} module Main where -import Data.Version (showVersion)-import Paths_pub (version)-import System.Console.CmdArgs+import Control.Monad+import Data.ByteString (ByteString)+import qualified Data.ByteString.Char8 as C8+import Data.Maybe+import Data.Version (showVersion)+import qualified Database.Redis as Redis+import Options.Generic+import qualified Paths_pub as Pub+import qualified System.IO -import Sub-import Sub.Internal+data Options w = Options+ { channel :: w ::: [ByteString] <?> "Redis channel(s) to subscribe to"+ , host :: w ::: Maybe String <?> "Redis host (default: localhost)"+ , port :: w ::: Maybe Integer <?> "Redis post (default: 6379)"+ , db :: w ::: Maybe Integer <?> "Redis db (default: 0)"+ , version :: Bool+ } deriving (Generic) --- | Command line argument configuration.------ Help messages, switches, options, and the human-readable version--- number is configured here.-programArgs :: PArgs-programArgs = PArgs- { chan = def &= argPos 0 &= typ "CHANNEL"- , host = def &= name "h" &= typ "STRING" &= help "Redis host (default `localhost`)"- , port = def &= name "p" &= help "Redis port (default `6379`)"- , db = def &= name "d" &= help "Redis database (default `0`)"- } &=- verbosity &=- help "Pipe from a pub/sub channel to stdout." &=- summary ("sub v" ++ showVersion version) &=- noAtExpand &=- details ["Given a redis pub/sub channel, pipe to stdout."]+instance ParseRecord (Options Wrapped)+deriving instance Show (Options Unwrapped) main :: IO ()-main = cmdArgs programArgs >>= handleOpts >>= pipePublish+main = do+ Options{..} <- unwrapRecord "Subscribe to redis channels and pipe to stdout"+ let stderr = System.IO.stderr+ let stdout = System.IO.stdout+ when version $+ System.IO.hPutStrLn stderr (showVersion Pub.version)+ conn <-+ Redis.connect+ Redis.defaultConnectInfo+ { Redis.connectHost = (fromMaybe "localhost" host)+ , Redis.connectPort = Redis.PortNumber (fromInteger $ fromMaybe 6379 port)+ , Redis.connectDatabase = fromMaybe 0 db+ }++ Redis.runRedis conn $+ Redis.pubSub+ (Redis.subscribe channel)+ (\msg -> do+ C8.putStrLn $ Redis.msgMessage msg+ System.IO.hFlush stdout+ pure mempty)
− sub/Sub/Internal.hs
@@ -1,66 +0,0 @@--------------------------------------------------------------------------------- |--- Module : Sub.Internal--- Copyright : (C) 2014 Parnell Springmeyer--- License : AllRightsReserved--- Maintainer : Parnell Springmeyer <parnell@digitalmentat.com>--- Stability : stable------ Internal functions and types for the `Main` program. Mostly--- responsible for defining the `cmdargs` data type, parsing--- configuration, and setting the log level.-------------------------------------------------------------------------------{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveDataTypeable #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# OPTIONS_GHC -fno-warn-orphans #-}--module Sub.Internal where--import Control.Applicative-import qualified Data.ByteString.Char8 as C8-import Database.Redis as R-import Network.Socket.Internal as NSI (PortNumber)-import System.Console.CmdArgs-import System.Log.Logger-import Text.Groom (groom)---- | Data type for program CLI options.-data PArgs = PArgs- { chan :: String- , host :: Maybe String- , port :: Maybe Integer- , db :: Maybe Integer- } deriving (Data, Typeable, Show, Eq)---- | Data type for settings once merged from CLI.-data Settings = Settings- { loglevel :: !Priority- , channel :: C8.ByteString- , redisHost :: Maybe HostName- , redisPort :: Maybe PortID- , redisDB :: Maybe Integer- } deriving (Show, Eq)---- | Given options, set the logging level, and create the settings--- record.-handleOpts :: PArgs -> IO Settings-handleOpts cliopts = do- whenNormal $ updateGlobalLogger "Console" (setLevel ERROR)- whenLoud $ updateGlobalLogger "Console" (setLevel DEBUG)-- let c = C8.pack $ chan cliopts- p = (fromInteger <$> (port cliopts)) :: Maybe NSI.PortNumber- conf = Settings { loglevel = INFO- , channel = c- , redisHost = host cliopts- , redisPort = R.PortNumber <$> p- , redisDB = db cliopts- }-- debugM "Console" "Configuration parsed"- debugM "Console" $ groom conf-- return conf