module Distribution.Simple.Register (
register,
unregister,
registerPackage,
generateRegistrationInfo,
inplaceInstalledPackageInfo,
absoluteInstalledPackageInfo,
generalInstalledPackageInfo,
) where
import Distribution.Simple.LocalBuildInfo
( LocalBuildInfo(..), ComponentLocalBuildInfo(..)
, InstallDirs(..), absoluteInstallDirs )
import Distribution.Simple.BuildPaths (haddockName)
import qualified Distribution.Simple.GHC as GHC
import Distribution.Simple.Compiler
( compilerVersion, CompilerFlavor(..), compilerFlavor
, PackageDB(..), registrationPackageDB )
import Distribution.Simple.Program
( ConfiguredProgram, runProgramInvocation
, requireProgram, lookupProgram, ghcPkgProgram, lhcPkgProgram )
import Distribution.Simple.Program.Script
( invocationAsSystemScript )
import qualified Distribution.Simple.Program.HcPkg as HcPkg
import Distribution.Simple.Setup
( RegisterFlags(..), CopyDest(..)
, fromFlag, fromFlagOrDefault, flagToMaybe )
import Distribution.PackageDescription
( PackageDescription(..), Library(..), BuildInfo(..), hcOptions )
import Distribution.Package
( Package(..), packageName, InstalledPackageId(..) )
import Distribution.InstalledPackageInfo
( InstalledPackageInfo, InstalledPackageInfo_(InstalledPackageInfo)
, showInstalledPackageInfo )
import qualified Distribution.InstalledPackageInfo as IPI
import Distribution.Simple.Utils
( createDirectoryIfMissingVerbose, writeUTF8File, writeFileAtomic
, die, notice, setupMessage )
import Distribution.System
( OS(..), buildOS )
import Distribution.Text
( display )
import Distribution.Version ( Version(..) )
import Distribution.Verbosity as Verbosity
( Verbosity, normal )
import Distribution.Compat.CopyFile
( setFileExecutable )
import System.FilePath ((</>), (<.>), isAbsolute)
import System.Directory
( getCurrentDirectory, removeDirectoryRecursive )
import System.IO.Error (try)
import Control.Monad (when)
import Data.Maybe
( isJust, fromMaybe )
import Data.List (partition)
register :: PackageDescription -> LocalBuildInfo
-> RegisterFlags
-> IO ()
register pkg@PackageDescription { library = Just lib }
lbi@LocalBuildInfo { libraryConfig = Just clbi } regFlags
= do
installedPkgInfo <- generateRegistrationInfo
verbosity pkg lib lbi clbi inplace distPref
case () of
_ | modeGenerateRegFile -> writeRegistrationFile installedPkgInfo
| modeGenerateRegScript -> writeRegisterScript installedPkgInfo
| otherwise -> registerPackage verbosity
installedPkgInfo pkg lbi inplace packageDb
where
modeGenerateRegFile = isJust (flagToMaybe (regGenPkgConf regFlags))
regFile = fromMaybe (display (packageId pkg) <.> "conf")
(fromFlag (regGenPkgConf regFlags))
modeGenerateRegScript = fromFlag (regGenScript regFlags)
inplace = fromFlag (regInPlace regFlags)
packageDb = fromFlagOrDefault (registrationPackageDB (withPackageDB lbi))
(regPackageDB regFlags)
distPref = fromFlag (regDistPref regFlags)
verbosity = fromFlag (regVerbosity regFlags)
writeRegistrationFile installedPkgInfo = do
notice verbosity ("Creating package registration file: " ++ regFile)
writeUTF8File regFile (showInstalledPackageInfo installedPkgInfo)
writeRegisterScript installedPkgInfo =
case compilerFlavor (compiler lbi) of
GHC -> do (ghcPkg, _) <- requireProgram verbosity ghcPkgProgram (withPrograms lbi)
writeHcPkgRegisterScript verbosity installedPkgInfo ghcPkg packageDb
LHC -> do (lhcPkg, _) <- requireProgram verbosity lhcPkgProgram (withPrograms lbi)
writeHcPkgRegisterScript verbosity installedPkgInfo lhcPkg packageDb
Hugs -> notice verbosity "Registration scripts not needed for hugs"
JHC -> notice verbosity "Registration scripts not needed for jhc"
NHC -> notice verbosity "Registration scripts not needed for nhc98"
_ -> die "Registration scripts are not implemented for this compiler"
register _ _ regFlags = notice verbosity "No package to register"
where
verbosity = fromFlag (regVerbosity regFlags)
generateRegistrationInfo :: Verbosity
-> PackageDescription
-> Library
-> LocalBuildInfo
-> ComponentLocalBuildInfo
-> Bool
-> FilePath
-> IO InstalledPackageInfo
generateRegistrationInfo verbosity pkg lib lbi clbi inplace distPref = do
pwd <- getCurrentDirectory
let comp = compiler lbi
ipid <-
case compilerFlavor comp of
GHC | compilerVersion comp >= Version [6,11] [] -> do
s <- GHC.libAbiHash verbosity pkg lbi lib clbi
return (InstalledPackageId (display (packageId pkg) ++ '-':s))
_other -> do
return (InstalledPackageId (display (packageId pkg)))
let installedPkgInfo
| inplace = inplaceInstalledPackageInfo pwd distPref
pkg lib lbi clbi
| otherwise = absoluteInstalledPackageInfo
pkg lib lbi clbi
return installedPkgInfo{ IPI.installedPackageId = ipid }
registerPackage :: Verbosity
-> InstalledPackageInfo
-> PackageDescription
-> LocalBuildInfo
-> Bool
-> PackageDB
-> IO ()
registerPackage verbosity installedPkgInfo pkg lbi inplace packageDb = do
setupMessage verbosity "Registering" (packageId pkg)
case compilerFlavor (compiler lbi) of
GHC -> registerPackageGHC verbosity installedPkgInfo pkg lbi inplace packageDb
LHC -> registerPackageLHC verbosity installedPkgInfo pkg lbi inplace packageDb
Hugs -> registerPackageHugs verbosity installedPkgInfo pkg lbi inplace packageDb
JHC -> notice verbosity "Registering for jhc (nothing to do)"
NHC -> notice verbosity "Registering for nhc98 (nothing to do)"
_ -> die "Registering is not implemented for this compiler"
registerPackageGHC, registerPackageLHC, registerPackageHugs
:: Verbosity
-> InstalledPackageInfo
-> PackageDescription
-> LocalBuildInfo
-> Bool
-> PackageDB
-> IO ()
registerPackageGHC verbosity installedPkgInfo _pkg lbi _inplace packageDb = do
let Just ghcPkg = lookupProgram ghcPkgProgram (withPrograms lbi)
HcPkg.reregister verbosity ghcPkg packageDb (Right installedPkgInfo)
registerPackageLHC verbosity installedPkgInfo _pkg lbi _inplace packageDb = do
let Just lhcPkg = lookupProgram lhcPkgProgram (withPrograms lbi)
HcPkg.reregister verbosity lhcPkg packageDb (Right installedPkgInfo)
registerPackageHugs verbosity installedPkgInfo pkg lbi inplace _packageDb = do
when inplace $ die "--inplace is not supported with Hugs"
let installDirs = absoluteInstallDirs pkg lbi NoCopyDest
createDirectoryIfMissingVerbose verbosity True (libdir installDirs)
writeUTF8File (libdir installDirs </> "package.conf")
(showInstalledPackageInfo installedPkgInfo)
writeHcPkgRegisterScript :: Verbosity
-> InstalledPackageInfo
-> ConfiguredProgram
-> PackageDB
-> IO ()
writeHcPkgRegisterScript verbosity installedPkgInfo hcPkg packageDb = do
let invocation = HcPkg.reregisterInvocation hcPkg Verbosity.normal
packageDb (Right installedPkgInfo)
regScript = invocationAsSystemScript buildOS invocation
notice verbosity ("Creating package registration script: " ++ regScriptFileName)
writeUTF8File regScriptFileName regScript
setFileExecutable regScriptFileName
regScriptFileName :: FilePath
regScriptFileName = case buildOS of
Windows -> "register.bat"
_ -> "register.sh"
generalInstalledPackageInfo
:: ([FilePath] -> [FilePath])
-> PackageDescription
-> Library
-> ComponentLocalBuildInfo
-> InstallDirs FilePath
-> InstalledPackageInfo
generalInstalledPackageInfo adjustRelIncDirs pkg lib clbi installDirs =
InstalledPackageInfo {
IPI.installedPackageId = InstalledPackageId (display (packageId pkg)),
IPI.sourcePackageId = packageId pkg,
IPI.license = license pkg,
IPI.copyright = copyright pkg,
IPI.maintainer = maintainer pkg,
IPI.author = author pkg,
IPI.stability = stability pkg,
IPI.homepage = homepage pkg,
IPI.pkgUrl = pkgUrl pkg,
IPI.description = description pkg,
IPI.category = category pkg,
IPI.exposed = libExposed lib,
IPI.exposedModules = exposedModules lib,
IPI.hiddenModules = otherModules bi,
IPI.importDirs = [ libdir installDirs | hasModules ],
IPI.libraryDirs = if hasLibrary
then libdir installDirs : extraLibDirs bi
else extraLibDirs bi,
IPI.hsLibraries = [ "HS" ++ display (packageId pkg) | hasLibrary ],
IPI.extraLibraries = extraLibs bi,
IPI.extraGHCiLibraries = [],
IPI.includeDirs = absinc ++ adjustRelIncDirs relinc,
IPI.includes = includes bi,
IPI.depends = map fst (componentPackageDeps clbi),
IPI.hugsOptions = hcOptions Hugs bi,
IPI.ccOptions = [],
IPI.ldOptions = ldOptions bi,
IPI.frameworkDirs = [],
IPI.frameworks = frameworks bi,
IPI.haddockInterfaces = [haddockdir installDirs </> haddockName pkg],
IPI.haddockHTMLs = [htmldir installDirs]
}
where
bi = libBuildInfo lib
(absinc, relinc) = partition isAbsolute (includeDirs bi)
hasModules = not $ null (exposedModules lib)
&& null (otherModules bi)
hasLibrary = hasModules || not (null (cSources bi))
inplaceInstalledPackageInfo :: FilePath
-> FilePath
-> PackageDescription
-> Library
-> LocalBuildInfo
-> ComponentLocalBuildInfo
-> InstalledPackageInfo
inplaceInstalledPackageInfo inplaceDir distPref pkg lib lbi clbi =
generalInstalledPackageInfo adjustReativeIncludeDirs pkg lib clbi installDirs
where
adjustReativeIncludeDirs = map (inplaceDir </>)
installDirs =
(absoluteInstallDirs pkg lbi NoCopyDest) {
libdir = inplaceDir </> buildDir lbi,
datadir = inplaceDir,
datasubdir = distPref,
docdir = inplaceDocdir,
htmldir = inplaceHtmldir,
haddockdir = inplaceHtmldir
}
inplaceDocdir = inplaceDir </> distPref </> "doc"
inplaceHtmldir = inplaceDocdir </> "html" </> display (packageName pkg)
absoluteInstalledPackageInfo :: PackageDescription
-> Library
-> LocalBuildInfo
-> ComponentLocalBuildInfo
-> InstalledPackageInfo
absoluteInstalledPackageInfo pkg lib lbi clbi =
generalInstalledPackageInfo adjustReativeIncludeDirs pkg lib clbi installDirs
where
adjustReativeIncludeDirs _
| null (installIncludes bi) = []
| otherwise = [includedir installDirs]
bi = libBuildInfo lib
installDirs = absoluteInstallDirs pkg lbi NoCopyDest
unregister :: PackageDescription -> LocalBuildInfo -> RegisterFlags -> IO ()
unregister pkg lbi regFlags = do
let pkgid = packageId pkg
genScript = fromFlag (regGenScript regFlags)
verbosity = fromFlag (regVerbosity regFlags)
packageDb = fromFlagOrDefault (registrationPackageDB (withPackageDB lbi))
(regPackageDB regFlags)
installDirs = absoluteInstallDirs pkg lbi NoCopyDest
setupMessage verbosity "Unregistering" pkgid
case compilerFlavor (compiler lbi) of
GHC ->
let Just ghcPkg = lookupProgram ghcPkgProgram (withPrograms lbi)
invocation = HcPkg.unregisterInvocation ghcPkg Verbosity.normal
packageDb pkgid
in if genScript
then writeFileAtomic unregScriptFileName
(invocationAsSystemScript buildOS invocation)
else runProgramInvocation verbosity invocation
Hugs -> do
_ <- try $ removeDirectoryRecursive (libdir installDirs)
return ()
NHC -> do
_ <- try $ removeDirectoryRecursive (libdir installDirs)
return ()
_ ->
die ("only unregistering with GHC and Hugs is implemented")
unregScriptFileName :: FilePath
unregScriptFileName = case buildOS of
Windows -> "unregister.bat"
_ -> "unregister.sh"