hackport-0.6.6: cabal/cabal-testsuite/src/Test/Cabal/Plan.hs
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
-- | Utilities for understanding @plan.json@.
module Test.Cabal.Plan (
Plan,
planDistDir,
) where
import Distribution.Parsec (simpleParsec)
import Distribution.Pretty (prettyShow)
import Distribution.Types.ComponentName
import Distribution.Package
import qualified Data.Text as Text
import Data.Aeson
import Data.Aeson.Types
import Control.Monad
-- TODO: index this
data Plan = Plan { planInstallPlan :: [InstallItem] }
data InstallItem
= APreExisting
| AConfiguredGlobal
| AConfiguredInplace ConfiguredInplace
-- local or inplace package
data ConfiguredInplace = ConfiguredInplace
{ configuredInplaceDistDir :: FilePath
, configuredInplacePackageName :: PackageName
, configuredInplaceComponentName :: Maybe ComponentName }
instance FromJSON Plan where
parseJSON (Object v) = fmap Plan (v .: "install-plan")
parseJSON invalid = typeMismatch "Plan" invalid
instance FromJSON InstallItem where
parseJSON obj@(Object v) = do
t <- v .: "type"
case t :: String of
"pre-existing" -> return APreExisting
"configured" -> do
s <- v .: "style"
case s :: String of
"global" -> return AConfiguredGlobal
"inplace" -> AConfiguredInplace `fmap` parseJSON obj
"local" -> AConfiguredInplace `fmap` parseJSON obj
_ -> fail $ "unrecognized value of 'style' field: " ++ s
_ -> fail "unrecognized value of 'type' field"
parseJSON invalid = typeMismatch "InstallItem" invalid
instance FromJSON ConfiguredInplace where
parseJSON (Object v) = do
dist_dir <- v .: "dist-dir"
pkg_name <- v .: "pkg-name"
component_name <- v .:? "component-name"
return (ConfiguredInplace dist_dir pkg_name component_name)
parseJSON invalid = typeMismatch "ConfiguredInplace" invalid
instance FromJSON PackageName where
parseJSON (String t) = return (mkPackageName (Text.unpack t))
parseJSON invalid = typeMismatch "PackageName" invalid
instance FromJSON ComponentName where
parseJSON (String t) =
case simpleParsec s of
Nothing -> fail ("could not parse component-name: " ++ s)
Just r -> return r
where s = Text.unpack t
parseJSON invalid = typeMismatch "ComponentName" invalid
planDistDir :: Plan -> PackageName -> ComponentName -> FilePath
planDistDir plan pkg_name cname =
case concatMap p (planInstallPlan plan) of
[x] -> x
[] -> error $ "planDistDir: component " ++ prettyShow cname
++ " of package " ++ prettyShow pkg_name ++ " either does not"
++ " exist in the install plan or does not have a dist-dir"
_ -> error $ "planDistDir: found multiple copies of component " ++ prettyShow cname
++ " of package " ++ prettyShow pkg_name ++ " in install plan"
where
p APreExisting = []
p AConfiguredGlobal = []
p (AConfiguredInplace conf) = do
guard (configuredInplacePackageName conf == pkg_name)
guard $ case configuredInplaceComponentName conf of
Nothing -> True
Just cname' -> cname == cname'
return (configuredInplaceDistDir conf)