cabal-audit 0.1.0.0 → 0.2.0.0
raw patch · 5 files changed
+116/−1 lines, 5 files
Files
- cabal-audit.cabal +5/−1
- src/Audit.hs +41/−0
- src/Audit/Latest.hs +30/−0
- src/Audit/Options.hs +19/−0
- src/Audit/Panic.hs +21/−0
cabal-audit.cabal view
@@ -1,5 +1,5 @@ name: cabal-audit-version: 0.1.0.0+version: 0.2.0.0 synopsis: Check how up-to-date your .cabal dependencies are. description: Check how up-to-date your .cabal dependencies are. homepage: https://github.com/joelteon/cabal-audit.git@@ -14,6 +14,10 @@ executable cabal-audit hs-source-dirs: src main-is: Main.hs+ other-modules: Audit+ Audit.Latest+ Audit.Options+ Audit.Panic build-depends: base ==4.6.*, Cabal == 1.16.*, directory == 1.2.*,
+ src/Audit.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE TupleSections #-}++module Audit (+ audit+) where++import Audit.Latest+import Audit.Panic+import Control.Monad+import Data.Maybe+import Data.Version+import Distribution.Package+import Distribution.PackageDescription+import Distribution.PackageDescription.Parse+import Distribution.Text+import Distribution.Verbosity+import Distribution.Version+import Text.Printf++audit :: FilePath -> IO ()+audit f = do+ pkgDesc <- readPackageDescription deafening f+ mapM_ (auditChunk id) (fmap ("library",) $ maybeToList $ condLibrary pkgDesc)+ mapM_ (auditChunk (printf "executable %s")) (condExecutables pkgDesc)+ mapM_ (auditChunk (printf "test suite %s")) (condTestSuites pkgDesc)+ mapM_ (auditChunk (printf "benchmark %s")) (condBenchmarks pkgDesc)++auditChunk :: (String -> String) -> (String, CondTree ConfVar [Dependency] a) -> IO ()+auditChunk f (e,m) = do+ putStrLn (f $ bold e)+ allOk <- mapM auditDep $ condTreeConstraints m+ when (and allOk) $ putStrLn $ success "ok!"++auditDep :: Dependency -> IO Bool+auditDep (Dependency (PackageName n) v)+ | n == "base" = return True+ | otherwise = do+ latest <- getLatestVersionOf n+ unless (withinRange latest v) $+ printf "%s\n latest: %s\n requested: %s\n" (warning n) (showVersion latest) (display v)+ return (withinRange latest v)
+ src/Audit/Latest.hs view
@@ -0,0 +1,30 @@+module Audit.Latest (+ getLatestVersionOf+) where++import Audit.Panic+import Distribution.Package+import Distribution.PackageDescription+import Distribution.PackageDescription.Parse+import Distribution.ParseUtils+import Distribution.Version+import Network.HTTP+import Text.Printf++getLatestVersionOf :: String -> IO Version+getLatestVersionOf pkg = do+ resp <- simpleHTTP (getRequest url)+ case resp of+ Left err -> panic $ "Connection error when connecting to hackage: " ++ show err+ Right s -> do+ let desc = parsePackageDescription $ rspBody s+ case desc of+ ParseFailed pe -> giveUp pe+ ParseOk ws d -> do+ mapM_ (worry . showPWarning (pkg ++ ".cabal")) ws+ return . pkgVersion . package $ packageDescription d+ where url = printf "http://new-hackage.haskell.org/package/%s/src/%s.cabal" pkg pkg+ giveUp pe = case ln of+ Nothing -> panic $ printf "Error when parsing %s.cabal: %s" pkg s+ Just num -> panic $ printf "Error when parsing %s.cabal: line %d: %s" pkg num s+ where (ln, s) = locatedErrorMsg pe
+ src/Audit/Options.hs view
@@ -0,0 +1,19 @@+module Audit.Options (+ Opts(..),+ fullOpts,+ module Options.Applicative.Extra+) where++import Options.Applicative+import Options.Applicative.Extra++data Opts = Opts { cabalFile :: Maybe FilePath } deriving Show++opts :: Parser Opts+opts = Opts <$> optional (argument str ( metavar "FILE"+ <> help ".cabal file to parse" ))++fullOpts :: ParserInfo Opts+fullOpts = info (helper <*> opts)+ ( fullDesc+ <> progDesc "Audit your .cabal file" )
+ src/Audit/Panic.hs view
@@ -0,0 +1,21 @@+module Audit.Panic where++import System.IO+import System.Exit+import Text.Printf++panic :: String -> IO a+panic s = do hPutStrLn stderr s+ exitFailure++worry :: String -> IO ()+worry = hPutStrLn stderr++bold :: String -> String+bold s = printf "\27[1m%s\27[0m" s++warning :: String -> String+warning s = printf "\27[33m%s\27[0m" s++success :: String -> String+success s = printf "\27[32m%s\27[0m" s