{-# LANGUAGE TupleSections, RecordWildCards, ScopedTypeVariables #-} -- | Run the @weeder@ program as a direct dependency. -- You are encouraged to use the binary in preference to the library. module Weeder(weeder) where import Hi import Cabal import Stack import Data.Version import Data.List.Extra import Data.Functor import Data.Tuple.Extra import Control.Monad.Extra import System.Console.CmdArgs.Verbosity import System.IO.Extra import qualified Data.HashMap.Strict as Map import System.Directory.Extra import System.FilePath import Paths_weeder import Check import Warning import CmdLine import Prelude -- | Given the weeder command line arguments, return the number of warnings that were produced. -- If the number is @0@ that corresponds to a successful run. weeder :: [String] -> IO Int weeder args = do cmd@Cmd{..} <- getCmd args whenLoud $ putStrLn $ "Weeder version " ++ showVersion version res <- mapM (weedPath cmd) cmdProjects return $ sum res weedPath :: Cmd -> FilePath -> IO Int weedPath Cmd{..} proj = do -- project may either be a directory name, or a stack.yaml file file <- do isDir <- doesDirectoryExist proj if isDir then findStack proj else return proj whenLoud $ putStrLn $ "Running on Stack file " ++ file when cmdBuild $ buildStack file Stack{..} <- parseStack cmdDistDir file cabals <- forM stackPackages $ \x -> do file <- selectCabalFile x (file,) <$> parseCabal file ignore <- do let x = takeDirectory file ".weeder.yaml" b <- doesFileExist x if not b then return [] else do whenLoud $ putStrLn $ "Reading ignored warnings from " ++ x readWarningsFile x let quiet = cmdJson || cmdYaml res <- forM cabals $ \(cabalFile, Cabal{..}) -> do (fileToKey, keyToHi) <- hiParseDirectory $ takeDirectory cabalFile stackDistDir let full = check (keyToHi Map.!) cabalName $ map (id &&& selectHiFiles stackDistDir fileToKey) cabalSections let warn = if cmdShowAll || cmdMatch then full else ignoreWarnings ignore full unless quiet $ putStrLn $ unlines $ showWarningsPretty cabalName warn return (length full - length warn, warn) let (ignored, warns) = sum *** concat $ unzip res when cmdJson $ putStrLn $ showWarningsJson warns when cmdYaml $ putStrLn $ showWarningsYaml warns if cmdMatch then if sort ignore == sort warns then do putStrLn "Warnings match" return 0 else do putStrLn "MISSING WARNINGS" putStrLn $ unlines $ showWarningsPretty "" $ ignore \\ warns putStrLn "EXTRA WARNINGS" putStrLn $ unlines $ showWarningsPretty "" $ warns \\ ignore return 1 else do when (ignored > 0 && not quiet) $ putStrLn $ "Ignored " ++ show ignored ++ " weeds (pass --show-all to see them)" return $ length warns