-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Simple.Register
-- Copyright   :  Isaac Jones 2003-2004
--
-- Maintainer  :  cabal-devel@haskell.org
-- Portability :  portable
--
-- This module deals with registering and unregistering packages. There are a
-- couple ways it can do this, one is to do it directly. Another is to generate
-- a script that can be run later to do it. The idea here being that the user
-- is shielded from the details of what command to use for package registration
-- for a particular compiler. In practice this aspect was not especially
-- popular so we also provide a way to simply generate the package registration
-- file which then must be manually passed to @ghc-pkg@. It is possible to
-- generate registration information for where the package is to be installed,
-- or alternatively to register the package inplace in the build tree. The
-- latter is occasionally handy, and will become more important when we try to
-- build multi-package systems.
--
-- This module does not delegate anything to the per-compiler modules but just
-- mixes it all in in this module, which is rather unsatisfactory. The script
-- generation and the unregister feature are not well used or tested.

{- Copyright (c) 2003-2004, Isaac Jones
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.

    * Redistributions in binary form must reproduce the above
      copyright notice, this list of conditions and the following
      disclaimer in the documentation and/or other materials provided
      with the distribution.

    * Neither the name of Isaac Jones nor the names of other
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -}

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 qualified Distribution.Simple.LHC  as LHC
import qualified Distribution.Simple.Hugs as Hugs
import qualified Distribution.Simple.UHC  as UHC
import Distribution.Simple.Compiler
         ( compilerVersion, CompilerFlavor(..), compilerFlavor
         , PackageDBStack, 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
         ( writeUTF8File, writeFileAtomic, setFileExecutable
         , 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.Exception
         ( tryIO )

import System.FilePath ((</>), (<.>), isAbsolute)
import System.Directory
         ( getCurrentDirectory, removeDirectoryRecursive )

import Data.Maybe
         ( isJust, fromMaybe, maybeToList )
import Data.List
         ( partition, nub )


-- -----------------------------------------------------------------------------
-- Registration

register :: PackageDescription -> LocalBuildInfo
         -> RegisterFlags -- ^Install in the user's database?; verbose
         -> IO ()
register pkg@PackageDescription { library       = Just lib  }
         lbi@LocalBuildInfo     { libraryConfig = Just clbi } regFlags
  = do

    installedPkgInfo <- generateRegistrationInfo ::
  Verbosity
  -> PackageDescription
  -> Library
  -> LocalBuildInfo
  -> ComponentLocalBuildInfo
  -> Bool
  -> FilePath
  -> IO InstalledPackageInfogenerateRegistrationInfo
                           verbosity :: Verbosityverbosity pkg :: PackageDescriptionpkg lib :: Librarylib lbi :: LocalBuildInfolbi clbi :: ComponentLocalBuildInfoclbi inplace :: Boolinplace distPref :: FilePathdistPref

     -- Three different modes:
    case () of
     _ | modeGenerateRegFile :: BoolmodeGenerateRegFile   -> writeRegistrationFile :: InstalledPackageInfo -> IO ()writeRegistrationFile installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo
       | modeGenerateRegScript :: BoolmodeGenerateRegScript -> writeRegisterScript :: InstalledPackageInfo -> IO ()writeRegisterScript   installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo
       | otherwise :: Boolotherwise             -> registerPackage ::
  Verbosity
  -> InstalledPackageInfo
  -> PackageDescription
  -> LocalBuildInfo
  -> Bool
  -> PackageDBStack
  -> IO ()registerPackage verbosity :: Verbosityverbosity
                                    installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi inplace :: Boolinplace packageDbs :: [PackageDB]packageDbs

  where
    modeGenerateRegFile = isJust :: Maybe a -> BoolisJust (flagToMaybe :: Flag a -> Maybe aflagToMaybe (regGenPkgConf :: RegisterFlags -> Flag (Maybe FilePath)regGenPkgConf regFlags :: RegisterFlagsregFlags))
    regFile             = fromMaybe :: a -> Maybe a -> afromMaybe (display :: Text a => a -> Stringdisplay (packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg) (<.>) :: FilePath -> String -> FilePath<.> "conf")
                                    (fromFlag :: Flag a -> afromFlag (regGenPkgConf :: RegisterFlags -> Flag (Maybe FilePath)regGenPkgConf regFlags :: RegisterFlagsregFlags))

    modeGenerateRegScript = fromFlag :: Flag a -> afromFlag (regGenScript :: RegisterFlags -> Flag BoolregGenScript regFlags :: RegisterFlagsregFlags)

    inplace   = fromFlag :: Flag a -> afromFlag (regInPlace :: RegisterFlags -> Flag BoolregInPlace regFlags :: RegisterFlagsregFlags)
    -- FIXME: there's really no guarantee this will work.
    -- registering into a totally different db stack can
    -- fail if dependencies cannot be satisfied.
    packageDbs = nub :: Eq a => [a] -> [a]nub ($) :: (a -> b) -> a -> b$ withPackageDB :: LocalBuildInfo -> PackageDBStackwithPackageDB lbi :: LocalBuildInfolbi
                    (++) :: [a] -> [a] -> [a]++ maybeToList :: Maybe a -> [a]maybeToList (flagToMaybe :: Flag a -> Maybe aflagToMaybe  (regPackageDB :: RegisterFlags -> Flag PackageDBregPackageDB regFlags :: RegisterFlagsregFlags))
    distPref  = fromFlag :: Flag a -> afromFlag (regDistPref :: RegisterFlags -> Flag FilePathregDistPref regFlags :: RegisterFlagsregFlags)
    verbosity = fromFlag :: Flag a -> afromFlag (regVerbosity :: RegisterFlags -> Flag VerbosityregVerbosity regFlags :: RegisterFlagsregFlags)

    writeRegistrationFile installedPkgInfo = do
      notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity ("Creating package registration file: " (++) :: [a] -> [a] -> [a]++ regFile :: FilePathregFile)
      writeUTF8File :: FilePath -> String -> IO ()writeUTF8File regFile :: FilePathregFile (showInstalledPackageInfo :: InstalledPackageInfo -> StringshowInstalledPackageInfo installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo)

    writeRegisterScript installedPkgInfo =
      case compilerFlavor :: Compiler -> CompilerFlavorcompilerFlavor (compiler :: LocalBuildInfo -> Compilercompiler lbi :: LocalBuildInfolbi) of
        GHC  -> do (ghcPkg, _) <- requireProgram ::
  Verbosity
  -> Program
  -> ProgramDb
  -> IO (ConfiguredProgram, ProgramDb)requireProgram verbosity :: Verbosityverbosity ghcPkgProgram :: ProgramghcPkgProgram (withPrograms :: LocalBuildInfo -> ProgramConfigurationwithPrograms lbi :: LocalBuildInfolbi)
                   writeHcPkgRegisterScript ::
  Verbosity
  -> InstalledPackageInfo
  -> ConfiguredProgram
  -> PackageDBStack
  -> IO ()writeHcPkgRegisterScript verbosity :: Verbosityverbosity installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo ghcPkg :: ConfiguredProgramghcPkg packageDbs :: [PackageDB]packageDbs
        LHC  -> do (lhcPkg, _) <- requireProgram ::
  Verbosity
  -> Program
  -> ProgramDb
  -> IO (ConfiguredProgram, ProgramDb)requireProgram verbosity :: Verbosityverbosity lhcPkgProgram :: ProgramlhcPkgProgram (withPrograms :: LocalBuildInfo -> ProgramConfigurationwithPrograms lbi :: LocalBuildInfolbi)
                   writeHcPkgRegisterScript ::
  Verbosity
  -> InstalledPackageInfo
  -> ConfiguredProgram
  -> PackageDBStack
  -> IO ()writeHcPkgRegisterScript verbosity :: Verbosityverbosity installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo lhcPkg :: ConfiguredProgramlhcPkg packageDbs :: [PackageDB]packageDbs
        Hugs -> notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "Registration scripts not needed for hugs"
        JHC  -> notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "Registration scripts not needed for jhc"
        NHC  -> notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "Registration scripts not needed for nhc98"
        UHC  -> notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "Registration scripts not needed for uhc"
        _    -> die :: String -> IO adie "Registration scripts are not implemented for this compiler"

register _ _ regFlags = notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "No package to register"
  where
    verbosity = fromFlag :: Flag a -> afromFlag (regVerbosity :: RegisterFlags -> Flag VerbosityregVerbosity regFlags :: RegisterFlagsregFlags)


generateRegistrationInfo :: Verbosity
                         -> PackageDescription
                         -> Library
                         -> LocalBuildInfo
                         -> ComponentLocalBuildInfo
                         -> Bool
                         -> FilePath
                         -> IO InstalledPackageInfo
generateRegistrationInfo verbosity pkg lib lbi clbi inplace distPref = do
  --TODO: eliminate pwd!
  pwd <- getCurrentDirectory :: IO FilePathgetCurrentDirectory

  --TODO: the method of setting the InstalledPackageId is compiler specific
  --      this aspect should be delegated to a per-compiler helper.
  let comp = compiler :: LocalBuildInfo -> Compilercompiler lbi :: LocalBuildInfolbi
  ipid <-
    case compilerFlavor :: Compiler -> CompilerFlavorcompilerFlavor comp :: Compilercomp of
     GHC | compilerVersion :: Compiler -> VersioncompilerVersion comp :: Compilercomp (>=) :: Ord a => a -> a -> Bool>= Version :: [Int] -> [String] -> VersionVersion [6,11] [] :: [a][] -> do
            s <- libAbiHash ::
  Verbosity
  -> PackageDescription
  -> LocalBuildInfo
  -> Library
  -> ComponentLocalBuildInfo
  -> IO StringGHC.libAbiHash verbosity :: Verbosityverbosity pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi lib :: Librarylib clbi :: ComponentLocalBuildInfoclbi
            return :: Monad m => forall a. a -> m areturn (InstalledPackageId :: String -> InstalledPackageIdInstalledPackageId (display :: Text a => a -> Stringdisplay (packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg) (++) :: [a] -> [a] -> [a]++ '-'(:) :: a -> [a] -> [a]:s :: Strings))
     _other -> do
            return :: Monad m => forall a. a -> m areturn (InstalledPackageId :: String -> InstalledPackageIdInstalledPackageId (display :: Text a => a -> Stringdisplay (packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg)))

  let installedPkgInfo
        | inplace :: Boolinplace   = inplaceInstalledPackageInfo ::
  FilePath
  -> FilePath
  -> PackageDescription
  -> Library
  -> LocalBuildInfo
  -> ComponentLocalBuildInfo
  -> InstalledPackageInfoinplaceInstalledPackageInfo pwd :: FilePathpwd distPref :: FilePathdistPref
                        pkg :: PackageDescriptionpkg lib :: Librarylib lbi :: LocalBuildInfolbi clbi :: ComponentLocalBuildInfoclbi
        | otherwise :: Boolotherwise = absoluteInstalledPackageInfo ::
  PackageDescription
  -> Library
  -> LocalBuildInfo
  -> ComponentLocalBuildInfo
  -> InstalledPackageInfoabsoluteInstalledPackageInfo
                        pkg :: PackageDescriptionpkg lib :: Librarylib lbi :: LocalBuildInfolbi clbi :: ComponentLocalBuildInfoclbi

  return :: Monad m => forall a. a -> m areturn installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo{ IPI.installedPackageId = ipid :: InstalledPackageIdipid }


registerPackage :: Verbosity
                -> InstalledPackageInfo
                -> PackageDescription
                -> LocalBuildInfo
                -> Bool
                -> PackageDBStack
                -> IO ()
registerPackage verbosity installedPkgInfo pkg lbi inplace packageDbs = do
  setupMessage :: Verbosity -> String -> PackageIdentifier -> IO ()setupMessage verbosity :: Verbosityverbosity "Registering" (packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg)
  case compilerFlavor :: Compiler -> CompilerFlavorcompilerFlavor (compiler :: LocalBuildInfo -> Compilercompiler lbi :: LocalBuildInfolbi) of
    GHC  -> registerPackage ::
  Verbosity
  -> InstalledPackageInfo
  -> PackageDescription
  -> LocalBuildInfo
  -> Bool
  -> PackageDBStack
  -> IO ()GHC.registerPackage  verbosity :: Verbosityverbosity installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi inplace :: Boolinplace packageDbs :: [PackageDB]packageDbs
    LHC  -> registerPackage ::
  Verbosity
  -> InstalledPackageInfo
  -> PackageDescription
  -> LocalBuildInfo
  -> Bool
  -> PackageDBStack
  -> IO ()LHC.registerPackage  verbosity :: Verbosityverbosity installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi inplace :: Boolinplace packageDbs :: [PackageDB]packageDbs
    Hugs -> registerPackage ::
  Verbosity
  -> InstalledPackageInfo
  -> PackageDescription
  -> LocalBuildInfo
  -> Bool
  -> PackageDBStack
  -> IO ()Hugs.registerPackage verbosity :: Verbosityverbosity installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi inplace :: Boolinplace packageDbs :: [PackageDB]packageDbs
    UHC  -> registerPackage ::
  Verbosity
  -> InstalledPackageInfo
  -> PackageDescription
  -> LocalBuildInfo
  -> Bool
  -> PackageDBStack
  -> IO ()UHC.registerPackage  verbosity :: Verbosityverbosity installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi inplace :: Boolinplace packageDbs :: [PackageDB]packageDbs
    JHC  -> notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "Registering for jhc (nothing to do)"
    NHC  -> notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity "Registering for nhc98 (nothing to do)"
    _    -> die :: String -> IO adie "Registering is not implemented for this compiler"


writeHcPkgRegisterScript :: Verbosity
                         -> InstalledPackageInfo
                         -> ConfiguredProgram
                         -> PackageDBStack
                         -> IO ()
writeHcPkgRegisterScript verbosity installedPkgInfo hcPkg packageDbs = do
  let invocation  = reregisterInvocation ::
  ConfiguredProgram
  -> Verbosity
  -> PackageDBStack
  -> Either FilePath InstalledPackageInfo
  -> ProgramInvocationHcPkg.reregisterInvocation hcPkg :: ConfiguredProgramhcPkg normal :: VerbosityVerbosity.normal
                      packageDbs :: [PackageDB]packageDbs (Right :: b -> Either a bRight installedPkgInfo :: InstalledPackageInfoinstalledPkgInfo)
      regScript   = invocationAsSystemScript :: OS -> ProgramInvocation -> StringinvocationAsSystemScript buildOS :: OSbuildOS   invocation :: ProgramInvocationinvocation

  notice :: Verbosity -> String -> IO ()notice verbosity :: Verbosityverbosity ("Creating package registration script: " (++) :: [a] -> [a] -> [a]++ regScriptFileName :: FilePathregScriptFileName)
  writeUTF8File :: FilePath -> String -> IO ()writeUTF8File regScriptFileName :: FilePathregScriptFileName regScript :: StringregScript
  setFileExecutable :: FilePath -> IO ()setFileExecutable regScriptFileName :: FilePathregScriptFileName

regScriptFileName :: FilePath
regScriptFileName = case buildOS :: OSbuildOS of
                        Windows -> "register.bat"
                        _       -> "register.sh"


-- -----------------------------------------------------------------------------
-- Making the InstalledPackageInfo

-- | Construct 'InstalledPackageInfo' for a library in a package, given a set
-- of installation directories.
--
generalInstalledPackageInfo
  :: ([FilePath] -> [FilePath]) -- ^ Translate relative include dir paths to
                                -- absolute paths.
  -> PackageDescription
  -> Library
  -> ComponentLocalBuildInfo
  -> InstallDirs FilePath
  -> InstalledPackageInfo
generalInstalledPackageInfo adjustRelIncDirs pkg lib clbi installDirs =
  InstalledPackageInfo {
    --TODO: do not open-code this conversion from PackageId to InstalledPackageId
    IPI.installedPackageId = InstalledPackageId :: String -> InstalledPackageIdInstalledPackageId (display :: Text a => a -> Stringdisplay (packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg)),
    IPI.sourcePackageId    = packageId :: Package pkg => pkg -> PackageIdentifierpackageId   pkg :: PackageDescriptionpkg,
    IPI.license            = license :: PackageDescription -> Licenselicense     pkg :: PackageDescriptionpkg,
    IPI.copyright          = copyright :: PackageDescription -> Stringcopyright   pkg :: PackageDescriptionpkg,
    IPI.maintainer         = maintainer :: PackageDescription -> Stringmaintainer  pkg :: PackageDescriptionpkg,
    IPI.author             = author :: PackageDescription -> Stringauthor      pkg :: PackageDescriptionpkg,
    IPI.stability          = stability :: PackageDescription -> Stringstability   pkg :: PackageDescriptionpkg,
    IPI.homepage           = homepage :: PackageDescription -> Stringhomepage    pkg :: PackageDescriptionpkg,
    IPI.pkgUrl             = pkgUrl :: PackageDescription -> StringpkgUrl      pkg :: PackageDescriptionpkg,
    IPI.synopsis           = synopsis :: PackageDescription -> Stringsynopsis    pkg :: PackageDescriptionpkg,
    IPI.description        = description :: PackageDescription -> Stringdescription pkg :: PackageDescriptionpkg,
    IPI.category           = category :: PackageDescription -> Stringcategory    pkg :: PackageDescriptionpkg,
    IPI.exposed            = libExposed :: Library -> BoollibExposed  lib :: Librarylib,
    IPI.exposedModules     = exposedModules :: Library -> [ModuleName]exposedModules lib :: Librarylib,
    IPI.hiddenModules      = otherModules :: BuildInfo -> [ModuleName]otherModules bi :: BuildInfobi,
    IPI.importDirs         = [ libdir :: InstallDirs dir -> dirlibdir installDirs :: InstallDirs FilePathinstallDirs | hasModules :: BoolhasModules ],
    IPI.libraryDirs        = if hasLibrary :: BoolhasLibrary
                               then libdir :: InstallDirs dir -> dirlibdir installDirs :: InstallDirs FilePathinstallDirs (:) :: a -> [a] -> [a]: extraLibDirs :: BuildInfo -> [String]extraLibDirs bi :: BuildInfobi
                               else                      extraLibDirs :: BuildInfo -> [String]extraLibDirs bi :: BuildInfobi,
    IPI.hsLibraries        = [ "HS" (++) :: [a] -> [a] -> [a]++ display :: Text a => a -> Stringdisplay (packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg) | hasLibrary :: BoolhasLibrary ],
    IPI.extraLibraries     = extraLibs :: BuildInfo -> [String]extraLibs bi :: BuildInfobi,
    IPI.extraGHCiLibraries = [] :: [a][],
    IPI.includeDirs        = absinc :: [FilePath]absinc (++) :: [a] -> [a] -> [a]++ adjustRelIncDirs :: [FilePath] -> [FilePath]adjustRelIncDirs relinc :: [FilePath]relinc,
    IPI.includes           = includes :: BuildInfo -> [FilePath]includes bi :: BuildInfobi,
    IPI.depends            = map :: (a -> b) -> [a] -> [b]map fst :: (a, b) -> afst (componentPackageDeps ::
  ComponentLocalBuildInfo -> [(InstalledPackageId, PackageId)]componentPackageDeps clbi :: ComponentLocalBuildInfoclbi),
    IPI.hugsOptions        = hcOptions :: CompilerFlavor -> BuildInfo -> [String]hcOptions Hugs :: CompilerFlavorHugs bi :: BuildInfobi,
    IPI.ccOptions          = [] :: [a][], -- Note. NOT ccOptions bi!
                                 -- We don't want cc-options to be propagated
                                 -- to C compilations in other packages.
    IPI.ldOptions          = ldOptions :: BuildInfo -> [String]ldOptions bi :: BuildInfobi,
    IPI.frameworkDirs      = [] :: [a][],
    IPI.frameworks         = frameworks :: BuildInfo -> [String]frameworks bi :: BuildInfobi,
    IPI.haddockInterfaces  = [haddockdir :: InstallDirs dir -> dirhaddockdir installDirs :: InstallDirs FilePathinstallDirs (</>) :: FilePath -> FilePath -> FilePath</> haddockName :: PackageDescription -> FilePathhaddockName pkg :: PackageDescriptionpkg],
    IPI.haddockHTMLs       = [htmldir :: InstallDirs dir -> dirhtmldir installDirs :: InstallDirs FilePathinstallDirs]
  }
  where
    bi = libBuildInfo :: Library -> BuildInfolibBuildInfo lib :: Librarylib
    (absinc, relinc) = partition :: (a -> Bool) -> [a] -> ([a], [a])partition isAbsolute :: FilePath -> BoolisAbsolute (includeDirs :: BuildInfo -> [FilePath]includeDirs bi :: BuildInfobi)
    hasModules = not :: Bool -> Boolnot ($) :: (a -> b) -> a -> b$ null :: [a] -> Boolnull (exposedModules :: Library -> [ModuleName]exposedModules lib :: Librarylib)
                    (&&) :: Bool -> Bool -> Bool&& null :: [a] -> Boolnull (otherModules :: BuildInfo -> [ModuleName]otherModules bi :: BuildInfobi)
    hasLibrary = hasModules :: BoolhasModules (||) :: Bool -> Bool -> Bool|| not :: Bool -> Boolnot (null :: [a] -> Boolnull (cSources :: BuildInfo -> [FilePath]cSources bi :: BuildInfobi))


-- | Construct 'InstalledPackageInfo' for a library that is inplace in the
-- build tree.
--
-- This function knows about the layout of inplace packages.
--
inplaceInstalledPackageInfo :: FilePath -- ^ top of the build tree
                            -> FilePath -- ^ location of the dist tree
                            -> PackageDescription
                            -> Library
                            -> LocalBuildInfo
                            -> ComponentLocalBuildInfo
                            -> InstalledPackageInfo
inplaceInstalledPackageInfo inplaceDir distPref pkg lib lbi clbi =
    generalInstalledPackageInfo ::
  ([FilePath] -> [FilePath])
  -> PackageDescription
  -> Library
  -> ComponentLocalBuildInfo
  -> InstallDirs FilePath
  -> InstalledPackageInfogeneralInstalledPackageInfo adjustReativeIncludeDirs :: t -> [FilePath]adjustReativeIncludeDirs pkg :: PackageDescriptionpkg lib :: Librarylib clbi :: ComponentLocalBuildInfoclbi installDirs :: InstallDirs FilePathinstallDirs
  where
    adjustReativeIncludeDirs = map :: (a -> b) -> [a] -> [b]map (inplaceDir :: FilePathinplaceDir (</>) :: FilePath -> FilePath -> FilePath</>)
    installDirs =
      (absoluteInstallDirs ::
  PackageDescription
  -> LocalBuildInfo
  -> CopyDest
  -> InstallDirs FilePathabsoluteInstallDirs pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi NoCopyDest :: CopyDestNoCopyDest) {
        libdir     = inplaceDir :: FilePathinplaceDir (</>) :: FilePath -> FilePath -> FilePath</> buildDir :: LocalBuildInfo -> FilePathbuildDir lbi :: LocalBuildInfolbi,
        datadir    = inplaceDir :: FilePathinplaceDir,
        datasubdir = distPref :: FilePathdistPref,
        docdir     = inplaceDocdir :: FilePathinplaceDocdir,
        htmldir    = inplaceHtmldir :: FilePathinplaceHtmldir,
        haddockdir = inplaceHtmldir :: FilePathinplaceHtmldir
      }
    inplaceDocdir  = inplaceDir :: FilePathinplaceDir (</>) :: FilePath -> FilePath -> FilePath</> distPref :: FilePathdistPref (</>) :: FilePath -> FilePath -> FilePath</> "doc"
    inplaceHtmldir = inplaceDocdir :: FilePathinplaceDocdir (</>) :: FilePath -> FilePath -> FilePath</> "html" (</>) :: FilePath -> FilePath -> FilePath</> display :: Text a => a -> Stringdisplay (packageName :: Package pkg => pkg -> PackageNamepackageName pkg :: PackageDescriptionpkg)


-- | Construct 'InstalledPackageInfo' for the final install location of a
-- library package.
--
-- This function knows about the layout of installed packages.
--
absoluteInstalledPackageInfo :: PackageDescription
                             -> Library
                             -> LocalBuildInfo
                             -> ComponentLocalBuildInfo
                             -> InstalledPackageInfo
absoluteInstalledPackageInfo pkg lib lbi clbi =
    generalInstalledPackageInfo ::
  ([FilePath] -> [FilePath])
  -> PackageDescription
  -> Library
  -> ComponentLocalBuildInfo
  -> InstallDirs FilePath
  -> InstalledPackageInfogeneralInstalledPackageInfo adjustReativeIncludeDirs :: t -> [FilePath]adjustReativeIncludeDirs pkg :: PackageDescriptionpkg lib :: Librarylib clbi :: ComponentLocalBuildInfoclbi installDirs :: InstallDirs FilePathinstallDirs
  where
    -- For installed packages we install all include files into one dir,
    -- whereas in the build tree they may live in multiple local dirs.
    adjustReativeIncludeDirs _
      | null :: [a] -> Boolnull (installIncludes :: BuildInfo -> [FilePath]installIncludes bi :: BuildInfobi) = [] :: [a][]
      | otherwise :: Boolotherwise                 = [includedir :: InstallDirs dir -> dirincludedir installDirs :: InstallDirs FilePathinstallDirs]
    bi = libBuildInfo :: Library -> BuildInfolibBuildInfo lib :: Librarylib
    installDirs = absoluteInstallDirs ::
  PackageDescription
  -> LocalBuildInfo
  -> CopyDest
  -> InstallDirs FilePathabsoluteInstallDirs pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi NoCopyDest :: CopyDestNoCopyDest

-- -----------------------------------------------------------------------------
-- Unregistration

unregister :: PackageDescription -> LocalBuildInfo -> RegisterFlags -> IO ()
unregister pkg lbi regFlags = do
  let pkgid     = packageId :: Package pkg => pkg -> PackageIdentifierpackageId pkg :: PackageDescriptionpkg
      genScript = fromFlag :: Flag a -> afromFlag (regGenScript :: RegisterFlags -> Flag BoolregGenScript regFlags :: RegisterFlagsregFlags)
      verbosity = fromFlag :: Flag a -> afromFlag (regVerbosity :: RegisterFlags -> Flag VerbosityregVerbosity regFlags :: RegisterFlagsregFlags)
      packageDb = fromFlagOrDefault :: a -> Flag a -> afromFlagOrDefault (registrationPackageDB :: PackageDBStack -> PackageDBregistrationPackageDB (withPackageDB :: LocalBuildInfo -> PackageDBStackwithPackageDB lbi :: LocalBuildInfolbi))
                                    (regPackageDB :: RegisterFlags -> Flag PackageDBregPackageDB regFlags :: RegisterFlagsregFlags)
      installDirs = absoluteInstallDirs ::
  PackageDescription
  -> LocalBuildInfo
  -> CopyDest
  -> InstallDirs FilePathabsoluteInstallDirs pkg :: PackageDescriptionpkg lbi :: LocalBuildInfolbi NoCopyDest :: CopyDestNoCopyDest
  setupMessage :: Verbosity -> String -> PackageIdentifier -> IO ()setupMessage verbosity :: Verbosityverbosity "Unregistering" pkgid :: PackageIdentifierpkgid
  case compilerFlavor :: Compiler -> CompilerFlavorcompilerFlavor (compiler :: LocalBuildInfo -> Compilercompiler lbi :: LocalBuildInfolbi) of
    GHC ->
      let Just ghcPkg = lookupProgram :: Program -> ProgramDb -> Maybe ConfiguredProgramlookupProgram ghcPkgProgram :: ProgramghcPkgProgram (withPrograms :: LocalBuildInfo -> ProgramConfigurationwithPrograms lbi :: LocalBuildInfolbi)
          invocation = unregisterInvocation ::
  ConfiguredProgram
  -> Verbosity
  -> PackageDB
  -> PackageId
  -> ProgramInvocationHcPkg.unregisterInvocation ghcPkg :: ConfiguredProgramghcPkg normal :: VerbosityVerbosity.normal
                         packageDb :: PackageDBpackageDb pkgid :: PackageIdentifierpkgid
      in if genScript :: BoolgenScript
           then writeFileAtomic :: FilePath -> String -> IO ()writeFileAtomic unregScriptFileName :: FilePathunregScriptFileName
                  (invocationAsSystemScript :: OS -> ProgramInvocation -> StringinvocationAsSystemScript buildOS :: OSbuildOS invocation :: ProgramInvocationinvocation)
            else runProgramInvocation :: Verbosity -> ProgramInvocation -> IO ()runProgramInvocation verbosity :: Verbosityverbosity invocation :: ProgramInvocationinvocation
    Hugs -> do
        _ <- tryIO :: IO a -> IO (Either IOException a)tryIO ($) :: (a -> b) -> a -> b$ removeDirectoryRecursive :: FilePath -> IO ()removeDirectoryRecursive (libdir :: InstallDirs dir -> dirlibdir installDirs :: InstallDirs FilePathinstallDirs)
        return :: Monad m => forall a. a -> m areturn ()
    NHC -> do
        _ <- tryIO :: IO a -> IO (Either IOException a)tryIO ($) :: (a -> b) -> a -> b$ removeDirectoryRecursive :: FilePath -> IO ()removeDirectoryRecursive (libdir :: InstallDirs dir -> dirlibdir installDirs :: InstallDirs FilePathinstallDirs)
        return :: Monad m => forall a. a -> m areturn ()
    _ ->
        die :: String -> IO adie ("only unregistering with GHC and Hugs is implemented")

unregScriptFileName :: FilePath
unregScriptFileName = case buildOS :: OSbuildOS of
                          Windows -> "unregister.bat"
                          _       -> "unregister.sh"