policeman-0.0.0.0: src/Policeman/Run.hs
module Policeman.Run
( runPoliceman
) where
import Control.Monad.Except (throwError)
import Control.Monad.Trans.Except (withExceptT)
import System.Directory (getCurrentDirectory)
import Policeman.Cabal (CabalError (..), extractExposedModules, extractPackageName,
extractPackageVersion, findCabalDescription, parseCabalFile)
import Policeman.Cli (CliArgs (..))
import Policeman.Core.Hie (hieFilesToHashMap)
import Policeman.Core.Package (Module, PackageName (..), PackageStructure (..))
import Policeman.Core.Version (Version, versionFromText)
import Policeman.Diff (comparePackageStructures, prettyPrintDiff)
import Policeman.Download.Common (DownloadError)
import Policeman.Download.Hackage (downloadFromHackage, getLatestHackageCabalFileContent)
import Policeman.Evaluate (eval)
import Policeman.Hie (createHieFiles)
import qualified Data.Set as Set
data PolicemanError
= DError DownloadError
| CError CabalError
deriving stock (Show)
-- | Runs the tool based on the CLI input.
runPoliceman :: CliArgs -> IO ()
runPoliceman CliArgs{..} = whenLeftM_ (runExceptT findNextVersion) print
where
findNextVersion :: ExceptT PolicemanError IO ()
findNextVersion = do
curPackagePath <- liftIO getCurrentDirectory
(packageName, curModules) <- getPackageInfo curPackagePath
let runDiff :: Version -> ExceptT PolicemanError IO ()
runDiff prevVer = diffWith prevVer packageName curModules
-- TODO: check for invalid version separately
case cliArgsPrev >>= versionFromText of
Nothing -> getLatestHackageVersion packageName >>= runDiff
Just prev -> runDiff prev
getLatestHackageVersion :: PackageName -> ExceptT PolicemanError IO Version
getLatestHackageVersion packageName = do
cabalContent <- withExceptT DError $ getLatestHackageCabalFileContent packageName
packageDesc <- withExceptT CError $ parseCabalFile cabalContent
whenNothing (extractPackageVersion packageDesc) $
throwError $ CError CabalParseError
diffWith
:: Version
-> PackageName
-> [Module]
-> ExceptT PolicemanError IO ()
diffWith prevVersion packageName curModules = do
prevPackagePath <- withExceptT DError $ downloadFromHackage packageName prevVersion
(_, prevModules) <- getPackageInfo prevPackagePath
prevHieFiles <- liftIO $ createHieFiles prevPackagePath
curHieFiles <- liftIO $ createHieFiles "."
let prevPackageStructure = PackageStructure
{ psModules = Set.fromList prevModules
, psModulesMap = hieFilesToHashMap prevHieFiles
}
let curPackageStructure = PackageStructure
{ psModules = Set.fromList curModules
, psModulesMap = hieFilesToHashMap curHieFiles
}
let diff = comparePackageStructures prevPackageStructure curPackageStructure
let evaluation = eval prevVersion diff
liftIO $ prettyPrintDiff prevVersion evaluation diff
getPackageInfo :: FilePath -> ExceptT PolicemanError IO (PackageName, [Module])
getPackageInfo path = withExceptT CError $ do
packageDesc <- findCabalDescription path
let name = extractPackageName packageDesc
let modules = extractExposedModules packageDesc
pure (name, modules)