module Hpack.Convert where
import Prelude ()
import Prelude.Compat
import Data.Maybe
import qualified Data.Version as Version
import qualified Distribution.Compiler as Compiler
import qualified Distribution.InstalledPackageInfo as Cabal
import qualified Distribution.Package as Cabal
import qualified Distribution.PackageDescription as Cabal
import qualified Distribution.PackageDescription.Parse as Cabal
import qualified Distribution.Text as Cabal
import qualified Distribution.Version as Cabal
import Hpack.Config hiding (package)
import Text.PrettyPrint (fsep, (<+>))
fromPackageDescription :: Cabal.GenericPackageDescription -> Package
fromPackageDescription Cabal.GenericPackageDescription{..} =
let Cabal.PackageDescription{..} = packageDescription
in
Package { packageName = Cabal.unPackageName (Cabal.pkgName package)
, packageVersion = Version.showVersion (Cabal.pkgVersion package)
, packageSynopsis = nullNothing synopsis
, packageDescription = nullNothing description
, packageHomepage = nullNothing homepage
, packageBugReports = nullNothing bugReports
, packageCategory = nullNothing category
, packageStability = nullNothing stability
, packageAuthor = maybeToList (nullNothing author)
, packageMaintainer = maybeToList (nullNothing maintainer)
, packageCopyright = maybeToList (nullNothing copyright)
, packageLicense = Just (show (Cabal.disp license))
, packageLicenseFile = listToMaybe licenseFiles
, packageTestedWith =
show .
fsep . map (\(f, vr) -> Cabal.disp f <+> Cabal.disp vr ) <$>
nullNothing testedWith
, packageFlags =
map (\Cabal.MkFlag{..} ->
let Cabal.FlagName fn = flagName
in Flag { flagName = fn
, flagDescription =
nullNothing flagDescription
, flagManual = flagManual
, flagDefault = flagDefault
})
genPackageFlags
, packageExtraSourceFiles = extraSrcFiles
, packageDataFiles = dataFiles
, packageSourceRepository = fromSourceRepos sourceRepos
, packageLibrary = fromCondLibrary condLibrary
, packageExecutables = fromCondExecutables condExecutables
, packageTests = fromCondTestSuites condTestSuites
, packageBenchmarks = fromCondBenchmarks condBenchmarks
}
fromPackageDescriptionString :: String -> Either ConvertError Package
fromPackageDescriptionString pkgStr =
case Cabal.parsePackageDescription pkgStr of
Cabal.ParseFailed e -> Left (ConvertCabalParseError e)
Cabal.ParseOk _ gpkg -> Right (fromPackageDescription gpkg)
data ConvertError = ConvertCabalParseError Cabal.PError
deriving(Show, Eq)
fromSourceRepos :: [Cabal.SourceRepo] -> Maybe SourceRepository
fromSourceRepos [] = Nothing
fromSourceRepos (_repo@Cabal.SourceRepo{..}:_more) =
Just SourceRepository { sourceRepositoryUrl = fromMaybe "" repoLocation
, sourceRepositorySubdir = repoSubdir
}
fromDependency :: Cabal.Dependency -> Dependency
fromDependency (Cabal.Dependency pn vr) | vr == Cabal.anyVersion =
Dependency (show (Cabal.disp pn)) Nothing
fromDependency (Cabal.Dependency pn vr) =
Dependency (show (Cabal.disp pn <+> Cabal.disp vr)) Nothing
fromCondLibrary :: Maybe (Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Library) -> Maybe (Section Library)
fromCondLibrary mcondLibrary = do
condLibrary@(Cabal.CondNode Cabal.Library{libBuildInfo} _ components) <- mcondLibrary
l <- libFromCondLibrary condLibrary
return (sectionWithBuildInfo l libBuildInfo)
{ sectionConditionals = map fromCondComponentHasBuildInfo components
}
fromCondExecutables :: [(String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Executable)] -> [Section Executable]
fromCondExecutables = map fromCondExecutableTup
fromCondTestSuites :: [(String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.TestSuite)] -> [Section Executable]
fromCondTestSuites = mapMaybe fromCondTestSuiteTup
fromCondBenchmarks :: [(String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Benchmark)] -> [Section Executable]
fromCondBenchmarks = mapMaybe fromCondBenchmarkTup
fromCondExecutableTup :: (String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Executable) -> Section Executable
fromCondExecutableTup etup@(_, Cabal.CondNode Cabal.Executable{buildInfo} _ components) =
let e = exeFromCondExecutableTup etup
in (sectionWithBuildInfo e buildInfo)
{ sectionConditionals = map fromCondComponentHasBuildInfo components
}
fromCondTestSuiteTup :: (String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.TestSuite) -> Maybe (Section Executable)
fromCondTestSuiteTup ttup@(_, Cabal.CondNode Cabal.TestSuite{testBuildInfo} _ components) = do
te <- testExeFromCondExecutableTup ttup
return (sectionWithBuildInfo te testBuildInfo)
{ sectionConditionals = map fromCondComponentHasBuildInfo components
}
fromCondBenchmarkTup :: (String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Benchmark) -> Maybe (Section Executable)
fromCondBenchmarkTup btup@(_, Cabal.CondNode Cabal.Benchmark{benchmarkBuildInfo} _ components) = do
be <- benchExeFromCondExecutableTup btup
return (sectionWithBuildInfo be benchmarkBuildInfo)
{ sectionConditionals = map fromCondComponentHasBuildInfo components
}
class HasBuildInfo a where
getBuildInfo :: a -> Cabal.BuildInfo
instance HasBuildInfo Cabal.Library where
getBuildInfo Cabal.Library{libBuildInfo} = libBuildInfo
instance HasBuildInfo Cabal.Executable where
getBuildInfo Cabal.Executable{buildInfo} = buildInfo
instance HasBuildInfo Cabal.TestSuite where
getBuildInfo Cabal.TestSuite{testBuildInfo} = testBuildInfo
instance HasBuildInfo Cabal.Benchmark where
getBuildInfo Cabal.Benchmark{benchmarkBuildInfo} = benchmarkBuildInfo
fromCondHasBuildInfo :: HasBuildInfo a => Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] a -> Section ()
fromCondHasBuildInfo (Cabal.CondNode hbi _ components) =
let bi = getBuildInfo hbi
in (sectionWithBuildInfo () bi)
{ sectionConditionals = map fromCondComponentHasBuildInfo components
}
fromCondComponentHasBuildInfo :: (HasBuildInfo a)
=> ( Cabal.Condition Cabal.ConfVar
, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] a
, Maybe (Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] a)
)
-> Conditional
fromCondComponentHasBuildInfo (cond, ifTree, elseTree) =
Conditional { conditionalCondition = fromCondition cond
, conditionalThen = fromCondHasBuildInfo ifTree
, conditionalElse = fromCondHasBuildInfo <$> elseTree
}
fromCondition :: Cabal.Condition Cabal.ConfVar -> String
fromCondition (Cabal.Var c) = case c of
Cabal.OS os -> "os(" ++ show (Cabal.disp os) ++ ")"
Cabal.Flag (Cabal.FlagName fl) -> "flag(" ++ fl ++ ")"
Cabal.Arch ar -> "arch(" ++ show (Cabal.disp ar) ++ ")"
Cabal.Impl cc vr -> "impl(" ++ show (Cabal.disp cc <+> Cabal.disp vr) ++ ")"
fromCondition (Cabal.CNot c) = "!(" ++ fromCondition c ++ ")"
fromCondition (Cabal.COr c1 c2) = "(" ++ fromCondition c1 ++ ") || (" ++ fromCondition c2 ++ ")"
fromCondition (Cabal.CAnd c1 c2) = "(" ++ fromCondition c1 ++ ") && (" ++ fromCondition c2 ++ ")"
fromCondition (Cabal.Lit b) = show b
sectionWithBuildInfo :: a -> Cabal.BuildInfo -> Section a
sectionWithBuildInfo d Cabal.BuildInfo{..} =
Section { sectionData = d
, sectionSourceDirs = hsSourceDirs
, sectionDependencies = map fromDependency targetBuildDepends
, sectionDefaultExtensions = map (show . Cabal.disp)
defaultExtensions
, sectionOtherExtensions = map (show . Cabal.disp) otherExtensions
, sectionGhcOptions = fromMaybe [] $
lookup Compiler.GHC options
, sectionGhcProfOptions = fromMaybe [] $
lookup Compiler.GHC profOptions
, sectionCppOptions = cppOptions
, sectionCCOptions = ccOptions
, sectionCSources = cSources
, sectionExtraLibDirs = extraLibDirs
, sectionExtraLibraries = extraLibs
, sectionIncludeDirs = includeDirs
, sectionInstallIncludes = installIncludes
, sectionLdOptions = ldOptions
, sectionBuildable = Just buildable
, sectionConditionals = []
, sectionBuildTools = map fromDependency buildTools
}
libFromCondLibrary :: Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Library -> Maybe Library
libFromCondLibrary (Cabal.CondNode (Cabal.Library{..}) _ _) = do
let Cabal.BuildInfo{..} = libBuildInfo
return Library { libraryExposed = Just libExposed
, libraryExposedModules = map (show . Cabal.disp)
exposedModules
, libraryOtherModules = map (show . Cabal.disp) otherModules
, libraryReexportedModules = map (show . Cabal.disp)
reexportedModules
}
exeFromCondExecutableTup :: (String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Executable) -> Executable
exeFromCondExecutableTup (name, Cabal.CondNode Cabal.Executable{..} _ _) =
Executable { executableName = name
, executableMain = modulePath
, executableOtherModules = map (show . Cabal.disp)
(Cabal.otherModules buildInfo)
}
testExeFromCondExecutableTup :: (String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.TestSuite) -> Maybe Executable
testExeFromCondExecutableTup (name, Cabal.CondNode Cabal.TestSuite{..} _ _) =
case testInterface of
Cabal.TestSuiteExeV10 _ mainIs -> Just
Executable { executableName = name
, executableMain = mainIs
, executableOtherModules = map (show . Cabal.disp)
(Cabal.otherModules testBuildInfo)
}
_ -> Nothing
benchExeFromCondExecutableTup :: (String, Cabal.CondTree Cabal.ConfVar [Cabal.Dependency] Cabal.Benchmark) -> Maybe Executable
benchExeFromCondExecutableTup (name, Cabal.CondNode Cabal.Benchmark{..} _ _) =
case benchmarkInterface of
Cabal.BenchmarkExeV10 _ mainIs -> Just
Executable { executableName = name
, executableMain = mainIs
, executableOtherModules = map (show . Cabal.disp)
(Cabal.otherModules benchmarkBuildInfo)
}
_ -> Nothing
nullNothing :: [a] -> Maybe [a]
nullNothing s = const s <$> listToMaybe s