Install.hs 6.29 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-----------------------------------------------------------------------------
-- |
-- Module      :  Network.Hackage.CabalInstall.Install
-- Copyright   :  (c) David Himmelstrup 2005
-- License     :  BSD-like
--
-- Maintainer  :  lemmih@gmail.com
-- Stability   :  provisional
-- Portability :  portable
--
-- High level interface to package installation.
-----------------------------------------------------------------------------
module Network.Hackage.CabalInstall.Install
    ( install    -- :: ConfigFlags -> [UnresolvedDependency] -> IO ()
15
    , installPackages
16
17
18
19
    , installPkg -- :: ConfigFlags -> (PackageIdentifier,[String],String) -> IO ()
    ) where

import Control.Exception (bracket_)
20
import Control.Monad (when)
bjorn@bringert.net's avatar
bjorn@bringert.net committed
21
import System.Directory (getTemporaryDirectory, createDirectoryIfMissing
22
23
                        ,removeDirectoryRecursive, doesFileExist)
import System.FilePath ((</>),(<.>))
bjorn@bringert.net's avatar
bjorn@bringert.net committed
24
25
26

import Text.Printf (printf)

27

bjorn@bringert.net's avatar
bjorn@bringert.net committed
28
import Network.Hackage.CabalInstall.Config (findCompiler, message)
29
import Network.Hackage.CabalInstall.Dependency (getPackages, resolveDependencies)
30
import Network.Hackage.CabalInstall.Fetch (isFetched, packageFile, fetchPackage)
31
import Network.Hackage.CabalInstall.Tar (extractTarGzFile)
32
import Network.Hackage.CabalInstall.Types (ConfigFlags(..), UnresolvedDependency(..)
bjorn@bringert.net's avatar
bjorn@bringert.net committed
33
                                      , Repo(..))
34

35
36
import Distribution.Simple.Compiler (Compiler(..))
import Distribution.Simple.InstallDirs (InstallDirs(..), absoluteInstallDirs)
37
import Distribution.Simple.SetupWrapper (setupWrapper)
38
import Distribution.Simple.Setup (CopyDest(..))
39
import Distribution.Package (showPackageId, PackageIdentifier)
mnislaih's avatar
mnislaih committed
40
import Distribution.Verbosity
41

42

bjorn@bringert.net's avatar
bjorn@bringert.net committed
43

44
45
46
47

-- |Installs the packages needed to satisfy a list of dependencies.
install :: ConfigFlags -> [String] -> [UnresolvedDependency] -> IO ()
install cfg globalArgs deps
48
    = do (comp,conf) <- findCompiler cfg
49
         resolvedDeps <- resolveDependencies cfg comp conf deps
50
51
52
         let apkgs = getPackages resolvedDeps
         if null apkgs
           then putStrLn "All requested packages already installed. Nothing to do."
53
           else installPackages cfg comp globalArgs apkgs
54
55

-- Fetch a package and output nice messages.
56
57
58
downloadPkg :: ConfigFlags -> PackageIdentifier -> Repo -> IO FilePath
downloadPkg cfg pkg repo
    = do fetched <- isFetched cfg pkg repo
59
         if fetched
bjorn@bringert.net's avatar
bjorn@bringert.net committed
60
            then do printf "'%s' is present.\n" (showPackageId pkg)
61
62
                    return (packageFile cfg pkg repo)
            else fetchPackage cfg pkg repo
63
64
65

-- Attach the correct prefix flag to configure commands,
-- correct --user flag to install commands and no options to other commands.
66
67
mkPkgOps :: ConfigFlags -> Compiler -> PackageIdentifier -> String -> [String] -> [String]
mkPkgOps cfg comp pkgId cmd ops = verbosity ++
68
  case cmd of
69
    "configure" -> user ++ installDirFlags installDirs ++ ops
70
71
    "install"   -> user
    _ -> []
mnislaih's avatar
mnislaih committed
72
 where verbosity = ["--verbose=" ++ showForCabal (configVerbose cfg)]
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
       user = if configUserInstall cfg then ["--user"] else []
       installDirs = absoluteInstallDirs pkgId (compilerId comp) NoCopyDest (configInstallDirs cfg)

installDirFlags :: InstallDirs FilePath -> [String]
installDirFlags dirs =
    [flag "prefix" prefix,
     flag "bindir" bindir,
     flag "libdir" libdir,
--     flag "dynlibdir" dynlibdir, -- not accepted as argument by cabal?
     flag "libexecdir" libexecdir,
--     flag "progdir" progdir, -- not accepted as argument by cabal?
--     flag "includedir" includedir, -- not accepted as argument by cabal?
     flag "datadir" datadir,
     flag "docdir" docdir,
     flag "htmldir" htmldir]
  where flag s f = "--" ++ s ++ "=" ++ f dirs

installPackages :: ConfigFlags
91
                -> Compiler
92
93
94
                -> [String] -- ^Options which will be parse to every package.
                -> [(PackageIdentifier,[String],Repo)] -- ^(Package, list of configure options, package location)
                -> IO ()
95
installPackages cfg comp globalArgs pkgs =
96
97
       mapM_ (installPkg cfg comp globalArgs) pkgs

98
99
100
101
102
103
104
105
106
107
108
{-|
  Download, build and install a given package with some given flags.

  The process is divided up in a few steps:

    * The package is downloaded to {config-dir}\/packages\/{pkg-id} (if not already there).

    * The fetched tarball is then moved to a temporary directory (\/tmp on linux) and unpacked.

    * setupWrapper (equivalent to cabal-setup) is called with the options
      \'configure\' and the user specified options, \'--user\'
109
      if the 'configUser' flag is @True@ and install directory flags depending on @configInstallDirs@.
110
111
112

    * setupWrapper \'build\' is called with no options.

113
    * setupWrapper \'install\' is called with the \'--user\' flag if 'configUserInstall' is @True@.
114
115
116
117

    * The installation finishes by deleting the unpacked tarball.
-} 
installPkg :: ConfigFlags
118
           -> Compiler
119
           -> [String] -- ^Options which will be parse to every package.
120
           -> (PackageIdentifier,[String],Repo) -- ^(Package, list of configure options, package location)
121
           -> IO ()
122
installPkg cfg comp globalArgs (pkg,ops,repo)
123
    = do pkgPath <- downloadPkg cfg pkg repo
124
         tmp <- getTemporaryDirectory
125
         let tmpDirPath = tmp </> printf "TMP%sTMP" (showPackageId pkg)
126
             setup cmd
127
128
                 = do let cmdOps = mkPkgOps cfg comp pkg cmd (globalArgs++ops)
                          path = tmpDirPath </> showPackageId pkg
bjorn@bringert.net's avatar
bjorn@bringert.net committed
129
                      message cfg deafening $ 
mnislaih's avatar
mnislaih committed
130
                                 unwords ["setupWrapper", show (cmd:cmdOps), show path]
131
                      setupWrapper (cmd:cmdOps) (Just path)
132
133
         bracket_ (createDirectoryIfMissing True tmpDirPath)
                  (removeDirectoryRecursive tmpDirPath)
bjorn@bringert.net's avatar
bjorn@bringert.net committed
134
                  (do message cfg deafening (printf "Extracting %s..." pkgPath)
135
136
                      extractTarGzFile (Just tmpDirPath) pkgPath
                      installUnpackedPkg cfg pkg setup
137
138
                      return ())

139
installUnpackedPkg :: ConfigFlags -> PackageIdentifier
140
                   -> (String -> IO ()) -> IO ()
141
installUnpackedPkg cfg pkgId setup
bjorn@bringert.net's avatar
bjorn@bringert.net committed
142
143
    = do printf "Building '%s'\n" (showPackageId pkgId)
         printf "  Configuring...\n"
144
         setup "configure"
bjorn@bringert.net's avatar
bjorn@bringert.net committed
145
         printf "  Building...\n"
146
         setup "build"
bjorn@bringert.net's avatar
bjorn@bringert.net committed
147
         printf "  Installing...\n"
148
         setup "install"
bjorn@bringert.net's avatar
bjorn@bringert.net committed
149
         printf "  Done.\n"
150
         return ()