packages feed

hackport-0.2.10: cabal-install-0.9.5_rc20101226/Distribution/Client/Unpack.hs

-----------------------------------------------------------------------------
-- |
-- Module      :  Distribution.Client.Unpack
-- Copyright   :  (c) Andrea Vezzosi 2008
-- License     :  BSD-like
--
-- Maintainer  :  cabal-devel@haskell.org
-- Stability   :  provisional
-- Portability :  portable
--
--
-----------------------------------------------------------------------------
module Distribution.Client.Unpack (

    -- * Commands
    unpack,

  ) where

import Distribution.Package
         ( PackageId, Dependency(..) )
import Distribution.Simple.Setup(fromFlag, fromFlagOrDefault)
import Distribution.Simple.Utils
         ( notice, die )
import Distribution.Verbosity
         ( Verbosity )
import Distribution.Text(display)

import Distribution.Client.Setup(UnpackFlags(unpackVerbosity,
                                             unpackDestDir))
import Distribution.Client.Types(UnresolvedDependency(..),
                                 Repo, AvailablePackageSource(..),
                                 AvailablePackage(AvailablePackage),
                                 AvailablePackageDb(AvailablePackageDb))
import Distribution.Client.Dependency as Dependency
         ( resolveAvailablePackages
         , dependencyConstraints, dependencyTargets
         , PackagesPreference(..), PackagesPreferenceDefault(..)
         , PackagePreference(..) )
import Distribution.Client.Fetch
        ( fetchPackage )
import Distribution.Client.HttpUtils
        ( downloadURI )
import qualified Distribution.Client.Tar as Tar (extractTarGzFile)
import Distribution.Client.IndexUtils as IndexUtils
    (getAvailablePackages, disambiguateDependencies)

import System.Directory
         ( createDirectoryIfMissing, doesDirectoryExist, doesFileExist
         , getTemporaryDirectory )
import System.IO
         ( openTempFile, hClose )
import Control.Monad
         ( unless, when )
import Data.Monoid
         ( mempty )
import System.FilePath
         ( (</>), addTrailingPathSeparator )
import qualified Data.Map as Map

unpack :: UnpackFlags -> [Repo] -> [Dependency] -> IO ()
unpack flags _ [] =
    notice verbosity "No packages requested. Nothing to do."
  where
    verbosity = fromFlag (unpackVerbosity flags)

unpack flags repos deps = do
  db@(AvailablePackageDb available _)
            <- getAvailablePackages verbosity repos
  deps' <- IndexUtils.disambiguateDependencies available
         . map toUnresolved $ deps

  pkgs <- resolvePackages db deps'

  unless (null prefix) $
         createDirectoryIfMissing True prefix

  flip mapM_ pkgs $ \pkg -> case pkg of

    AvailablePackage pkgid _ (LocalTarballPackage tarballPath) ->
      unpackPackage verbosity prefix pkgid tarballPath

    AvailablePackage pkgid _ (RemoteTarballPackage tarballURL) -> do
      tmp <- getTemporaryDirectory
      (tarballPath, hnd) <- openTempFile tmp (display pkgid)
      hClose hnd
      --TODO: perhaps we've already had to download this to a local cache
      --      so we even know what package version it is. So might be able
      --      to get it from the local cache rather than from remote.
      downloadURI verbosity tarballURL tarballPath
      unpackPackage verbosity prefix pkgid tarballPath

    AvailablePackage pkgid _ (RepoTarballPackage repo) -> do
      tarballPath <- fetchPackage verbosity repo pkgid
      unpackPackage verbosity prefix pkgid tarballPath

    AvailablePackage _ _ (LocalUnpackedPackage _) ->
      error "Distribution.Client.Unpack.unpack: the impossible happened."

    where
      verbosity = fromFlag (unpackVerbosity flags)
      prefix = fromFlagOrDefault "" (unpackDestDir flags)
      toUnresolved d = UnresolvedDependency d []

unpackPackage :: Verbosity -> FilePath -> PackageId -> FilePath -> IO ()
unpackPackage verbosity prefix pkgid pkgPath = do
    let pkgdirname = display pkgid
        pkgdir     = prefix </> pkgdirname
        pkgdir'    = addTrailingPathSeparator pkgdir
    existsDir  <- doesDirectoryExist pkgdir
    when existsDir $ die $
     "The directory \"" ++ pkgdir' ++ "\" already exists, not unpacking."
    existsFile  <- doesFileExist pkgdir
    when existsFile $ die $
     "A file \"" ++ pkgdir ++ "\" is in the way, not unpacking."
    notice verbosity $ "Unpacking to " ++ pkgdir'
    Tar.extractTarGzFile prefix pkgdirname pkgPath

resolvePackages :: AvailablePackageDb
                -> [UnresolvedDependency]
                -> IO [AvailablePackage]
resolvePackages
  (AvailablePackageDb available availablePrefs) deps =

    either (die . unlines . map show) return $
      resolveAvailablePackages
        installed   available
        preferences constraints
        targets

  where
    installed   = mempty
    targets     = dependencyTargets     deps
    constraints = dependencyConstraints deps
    preferences = PackagesPreference
                    PreferLatestForSelected
                    [ PackageVersionPreference name ver
                    | (name, ver) <- Map.toList availablePrefs ]