import Prelude import Control.Applicative (many) import Control.Monad (unless) import Control.Monad.IO.Class (liftIO) import Control.Monad.State (execStateT, put) import Data.Foldable (for_, traverse_) import Data.Text (Text, pack, unpack) import Data.Traversable (for) import System.Exit (ExitCode(ExitFailure, ExitSuccess), exitWith) import qualified Data.Set as Set import qualified Options.Applicative as Opt import Data.Prune.Dependency (getDependencyByModule) import Data.Prune.ImportParser (getCompilableUsedDependencies) import Data.Prune.Package (parseStackYaml) import qualified Data.Prune.Types as T data Opts = Opts { optsStackYamlFile :: FilePath , optsPackages :: [Text] } parseArgs :: IO Opts parseArgs = Opt.execParser (Opt.info (Opt.helper <*> parser) $ Opt.progDesc "Prune a Stack project's dependencies") where parser = Opts <$> Opt.strOption ( Opt.long "stack-yaml-file" <> Opt.metavar "STACK_YAML_FILE" <> Opt.help "Location of stack.yaml" <> Opt.value "stack.yaml" <> Opt.showDefault ) <*> many ( pack <$> Opt.strOption ( Opt.long "package" <> Opt.metavar "PACKAGE" <> Opt.help "Package name(s)" ) ) main :: IO () main = do Opts {..} <- parseArgs packages <- parseStackYaml optsStackYamlFile optsPackages dependencyByModule <- liftIO $ getDependencyByModule optsStackYamlFile packages code <- flip execStateT ExitSuccess $ for_ packages $ \T.Package {..} -> do baseUsedDependencies <- fmap mconcat . for packageCompilables $ \compilable@T.Compilable {..} -> do usedDependencies <- liftIO $ getCompilableUsedDependencies dependencyByModule compilable let (baseUsedDependencies, otherUsedDependencies) = Set.partition (flip Set.member packageBaseDependencies) usedDependencies otherUnusedDependencies = Set.difference compilableDependencies otherUsedDependencies unless (Set.null otherUnusedDependencies) $ do liftIO . putStrLn . unpack $ "Some unused dependencies for " <> pack (show compilableType) <> " " <> T.unCompilableName compilableName <> " in package " <> packageName traverse_ (liftIO . putStrLn . unpack . (" " <>) . T.unDependencyName) $ Set.toList otherUnusedDependencies put $ ExitFailure 1 pure baseUsedDependencies let baseUnusedDependencies = Set.difference packageBaseDependencies baseUsedDependencies unless (Set.null baseUnusedDependencies) $ do liftIO . putStrLn . unpack $ "Some unused base dependencies for package " <> packageName liftIO . traverse_ (putStrLn . unpack . (" " <>) . T.unDependencyName) $ Set.toList baseUnusedDependencies put $ ExitFailure 1 exitWith code