content: {-# 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
  