spy 0.10 → 0.12
raw patch · 7 files changed
+164/−81 lines, 7 filesdep ~fsnotify
Dependency ranges changed: fsnotify
Files
- README.md +12/−9
- spy.cabal +25/−24
- src/Main.hs +9/−8
- src/Spy/Color.hs +66/−0
- src/Spy/Run.hs +3/−3
- src/Spy/Watcher.hs +41/−30
- tests/Tests.hs +8/−7
README.md view
@@ -89,7 +89,17 @@ The user manual should now be available via `man spy` and the `spy` executable should be on your `$PATH`. +Homebrew on Mac OS X?+--------------------- +You can use:++ brew tap juretta/spy+ brew install spy+ +To install the latest spy release.++ Source distribution ------------------- @@ -101,18 +111,11 @@ Done! -To install spy from git you need the Haskell platform installed and cabal-install available on your $PATH:+To install spy from git you need [the Haskell Tool Stack](https://docs.haskellstack.org) installed and `stack` available on your $PATH: $> git@bitbucket.org:ssaasen/spy.git $> cd spy- $> cabal install --only-dependencies- $> cabal configure- $> cabal build--This will create the spy binary in the ./dist/build/spy directory.--To copy the spy binary to the cabal bin directory (which should be available on your PATH) use:+ $> stack install - $> cabal copy
spy.cabal view
@@ -1,5 +1,5 @@ name: spy-version: 0.10+version: 0.12 license: BSD3 license-file: LICENSE author: Stefan Saasen@@ -20,33 +20,12 @@ flag small_base description: Choose the new, split-up base package. -test-suite spy-testsuite- type: exitcode-stdio-1.0- main-is: Tests.hs- hs-source-dirs: tests, src- build-depends: base < 5 && >= 3,- test-framework >= 0.3.3,- test-framework-quickcheck2 >= 0.2.9,- test-framework-hunit,- HUnit,- QuickCheck >= 2.4.0.1,- fsnotify >= 0.0.4,- cmdargs >= 0.10,- filepath >= 1.3,- filemanip >= 0.3.6.2,- process >= 1.1,- json >= 0.7,- directory >= 1.1,- system-filepath >= 0.4.7,- time >= 1.4,- unix- executable spy main-is: Main.hs- other-modules: Spy.Watcher, Spy.Run+ other-modules: Spy.Watcher, Spy.Run, Spy.Color build-depends: base < 5 && >= 3,- fsnotify >= 0.0.4,+ fsnotify >= 0.2.1, cmdargs >= 0.10, filepath >= 1.3, filemanip >= 0.3.6.2,@@ -65,4 +44,26 @@ hs-source-dirs: src++test-suite spy-testsuite+ type: exitcode-stdio-1.0+ main-is: Tests.hs+ other-modules: Spy.Watcher, Spy.Run, Spy.Color+ hs-source-dirs: tests, src+ build-depends: base < 5 && >= 3,+ test-framework >= 0.3.3,+ test-framework-quickcheck2 >= 0.2.9,+ test-framework-hunit,+ HUnit,+ QuickCheck >= 2.4.0.1,+ fsnotify >= 0.0.4,+ cmdargs >= 0.10,+ filepath >= 1.3,+ filemanip >= 0.3.6.2,+ process >= 1.1,+ json >= 0.7,+ directory >= 1.1,+ system-filepath >= 0.4.7,+ time >= 1.4,+ unix
src/Main.hs view
@@ -1,19 +1,19 @@-{-# LANGUAGE DeriveDataTypeable #-} module Main where -import System.Console.CmdArgs-import System.Directory (canonicalizePath)-import System.FilePath (addTrailingPathSeparator)-import Spy.Watcher+import Spy.Watcher+import System.Console.CmdArgs+import System.Directory (canonicalizePath)+import System.Environment (getArgs, withArgs)+import System.FilePath (addTrailingPathSeparator) version :: String-version = "spy v0.10, (C) Stefan Saasen"+version = "spy v0.12, (C) Stefan Saasen" watch :: Spy watch = Watch {hidden = False &= help "Set to true if hidden files/directories should be included" &= name "i" &= typ "BOOL" ,dir = "." &= argPos 0 &= typ "FILE/DIR"- ,format = Just plainFormat &= name "f" &= help "Specify the output format ('json', 'plain')"+ ,format = Just plainFormat &= name "f" &= help "Specify the output format ('json', 'plain', 'color')" ,glob = Nothing &= args &= typ "GLOB" } &= help "Watch a directory (or file) for file changes"@@ -38,7 +38,8 @@ main :: IO () main = do- config <- cmdArgsRun mode+ options <- getArgs+ config <- (if null options then withArgs ["--help"] else id) $ cmdArgsRun mode canonicalizedDir <- canonicalizePath $ dir config putStrLn "Press Ctrl-D to stop" spy (config { dir = addTrailingPathSeparator canonicalizedDir }) $
+ src/Spy/Color.hs view
@@ -0,0 +1,66 @@+module Spy.Color (+ green+ , red+ , yellow+ , Color(..)+ , Mode(..)+ , ansi+ , bold+) where++data Color = Black | Blue | Green | Cyan | Purple | Red | Brown |+ LightGray | DarkGray | LightBlue | LightGreen | LightCyan |+ LightRed | LightPurple | Yellow | White deriving (Show, Eq, Ord)++data Mode = Foreground | Background deriving (Show, Eq, Ord)++-- | Return the String wrapped with ANSI escape codes to turn the+-- foreground red+--+-- >>> red "test"+-- "\ESC[0;31mtest\ESC[0m"+green, red, yellow :: String -> String+green = ansi Foreground Green+red = ansi Foreground Red+yellow = ansi Foreground Yellow+++-- | Return the given String with ANSI escape codes for bold+-- >>> bold "test"+-- "\ESC[1mtest\ESC[0m"+bold :: String -> String+bold s = "\x1b[1m" ++ s ++ "\x1b[0m"++ansi :: Mode -> Color -> String -> String+ansi m c s = "\x1b["++ toCode m c ++ "m" ++ s ++ "\x1b[0m"++-- "\033[1;34mT\033[0m"+++toCode :: Mode -> Color -> String+toCode m Black = asAnsi m 0 0+toCode m Blue = asAnsi m 0 4+toCode m Green = asAnsi m 0 2+toCode m Cyan = asAnsi m 0 6+toCode m Purple = asAnsi m 0 5+toCode m Red = asAnsi m 0 1+toCode m Brown = asAnsi m 0 3+toCode m LightGray = asAnsi m 0 7+toCode m DarkGray = asAnsi m 1 0+toCode m LightBlue = asAnsi m 1 4+toCode m LightGreen = asAnsi m 1 2+toCode m LightCyan = asAnsi m 1 6+toCode m LightRed = asAnsi m 1 1+toCode m LightPurple = asAnsi m 1 5+toCode m Yellow = asAnsi m 1 3+toCode m White = asAnsi m 1 7++asAnsi :: Mode -> Int -> Int -> String+asAnsi Foreground = foreground+asAnsi Background = background++background, foreground :: Int -> Int -> String+foreground l r = show l ++ ";3" ++ show r++background l r = show l ++ ";4" ++ show r+
src/Spy/Run.hs view
@@ -5,11 +5,11 @@ ) where -import System.IO (isEOF)+import Control.Concurrent+import qualified Control.Exception as E import System.Exit+import System.IO (isEOF) import System.Posix.Signals-import Control.Concurrent-import qualified Control.Exception as E -- | Run indefinitely until the users aborts (via CTRL-D, CTRL-C or by sending a TERM -- signal)
src/Spy/Watcher.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE DeriveDataTypeable,RecordWildCards #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE RecordWildCards #-} module Spy.Watcher (@@ -11,35 +12,38 @@ ,containsHiddenPathElement ) where -import System.FSNotify (withManager, watchTree, Event(..))-import System.Console.CmdArgs-import System.Cmd-import System.Exit-import System.IO (stderr, hPrint)-import System.FilePath.GlobPattern-import System.FilePath (splitDirectories, takeFileName)-import Filesystem.Path.CurrentOS- (encodeString, decodeString, commonPrefix, stripPrefix)-import Data.Time.Clock(UTCTime)-import Data.Maybe (fromMaybe, maybeToList, fromJust)-import Text.JSON-import Spy.Run+import Data.Maybe (fromJust, fromMaybe, maybeToList)+import Data.Time.Clock (UTCTime)+import Filesystem.Path.CurrentOS (commonPrefix, decodeString,+ encodeString, stripPrefix)+import Spy.Color+import Spy.Run+import System.Console.CmdArgs+import System.Exit+import System.FilePath (splitDirectories, takeFileName)+import System.FilePath.GlobPattern+import System.FSNotify (Event (..), watchTree,+ withManager)+import System.IO (hPrint, stderr)+import System.Process (rawSystem)+import Text.JSON+import Text.Printf -- | The output format when Spy prints out changes to STDOUT-data Format = Json | Plain deriving (Show, Eq, Data, Typeable)+data Format = Json | Color | Plain deriving (Show, Eq, Data, Typeable) -- | Spy run modes. data Spy = Watch {- dir :: FilePath- ,glob :: Maybe GlobPattern- ,format :: Maybe Format- ,hidden :: Bool+ dir :: FilePath+ ,glob :: Maybe GlobPattern+ ,format :: Maybe Format+ ,hidden :: Bool } | Run {- dir :: FilePath- ,command :: String- ,glob :: Maybe GlobPattern- ,hidden :: Bool- ,notifyOnly :: Bool+ dir :: FilePath+ ,command :: String+ ,glob :: Maybe GlobPattern+ ,hidden :: Bool+ ,notifyOnly :: Bool } deriving (Data,Typeable,Show,Eq) -- | Return the Plain format.@@ -50,9 +54,9 @@ spy :: Spy -> IO b -> IO () spy config after = withManager $ \wm -> runIndefinitely- (watchTree wm (decodeString $ dir config)+ (watchTree wm (dir config) (not . skipEvent config . eventPath)- (handleEvent config)) + (handleEvent config)) (const after) -- | Handle the FS event based on the current Spy run configuration@@ -89,7 +93,14 @@ ("flag", showJSON $ eventType event), ("time", showJSON . show $ eventTime event)] outputHandler Plain = eventPath-+outputHandler Color = \event -> case event of+ (Added fp _) -> printf "%s %s" (added "+|") fp+ (Modified fp _) -> printf "%s %s" (updated "~|") fp+ (Removed fp _) -> printf "%s %s" (removed "-|") (ansi Foreground DarkGray fp)+ where+ added = ansi Foreground Black . ansi Background LightGreen+ updated = ansi Foreground Black . ansi Background Yellow+ removed = ansi Foreground Black . ansi Background LightRed -- | Skip events based on the configuration given skipEvent :: Spy -> FilePath -> Bool@@ -106,9 +117,9 @@ eventTime (Removed _ t) = t eventPath :: Event -> FilePath-eventPath (Added fp _) = encodeString fp-eventPath (Modified fp _) = encodeString fp-eventPath (Removed fp _) = encodeString fp+eventPath (Added fp _) = fp+eventPath (Modified fp _) = fp+eventPath (Removed fp _) = fp eventType :: Event -> FilePath eventType (Added _ _) = "Added"
tests/Tests.hs view
@@ -2,13 +2,14 @@ module Main (main) where -import qualified Test.HUnit as H-import Data.Maybe-import Spy.Watcher-import Test.QuickCheck hiding ((.&.))-import Test.Framework (Test, defaultMain, testGroup)-import Test.Framework.Providers.QuickCheck2 (testProperty)-import Test.Framework.Providers.HUnit+import Data.Maybe+import Spy.Watcher+import Test.Framework (Test, defaultMain,+ testGroup)+import Test.Framework.Providers.HUnit+import Test.Framework.Providers.QuickCheck2 (testProperty)+import qualified Test.HUnit as H+import Test.QuickCheck hiding ((.&.)) test_globMatchesFile = H.assertBool