Setup.hs 53.3 KB
Newer Older
1 2
-----------------------------------------------------------------------------
-- |
3
-- Module      :  Distribution.Client.Setup
4 5 6 7 8 9 10 11 12
-- Copyright   :  (c) David Himmelstrup 2005
-- License     :  BSD-like
--
-- Maintainer  :  lemmih@gmail.com
-- Stability   :  provisional
-- Portability :  portable
--
--
-----------------------------------------------------------------------------
13
module Distribution.Client.Setup
14
    ( globalCommand, GlobalFlags(..), globalRepos
15
    , configureCommand, ConfigFlags(..), filterConfigureFlags
16 17
    , configureExCommand, ConfigExFlags(..), defaultConfigExFlags
                        , configureExOptions
ttuegel's avatar
ttuegel committed
18
    , buildCommand, BuildFlags(..)
19
    , installCommand, InstallFlags(..), installOptions, defaultInstallFlags
20
    , listCommand, ListFlags(..)
Duncan Coutts's avatar
Duncan Coutts committed
21
    , updateCommand
ijones's avatar
ijones committed
22
    , upgradeCommand
23
    , infoCommand, InfoFlags(..)
24
    , fetchCommand, FetchFlags(..)
25
    , getCommand, unpackCommand, GetFlags(..)
26
    , checkCommand
27
    , uploadCommand, UploadFlags(..)
28
    , reportCommand, ReportFlags(..)
refold's avatar
refold committed
29
    , runCommand
30
    , initCommand, IT.InitFlags(..)
31
    , sdistCommand, SDistFlags(..), SDistExFlags(..), ArchiveFormat(..)
32
    , win32SelfUpgradeCommand, Win32SelfUpgradeFlags(..)
refold's avatar
refold committed
33
    , sandboxCommand, defaultSandboxLocation, SandboxFlags(..)
Duncan Coutts's avatar
Duncan Coutts committed
34 35

    , parsePackageArgs
36 37 38
    --TODO: stop exporting these:
    , showRepo
    , parseRepo
39 40
    ) where

41
import Distribution.Client.Types
42
         ( Username(..), Password(..), Repo(..), RemoteRepo(..), LocalRepo(..) )
43 44
import Distribution.Client.BuildReports.Types
         ( ReportLevel(..) )
45
import Distribution.Client.Dependency.Types
46
         ( PreSolver(..) )
47 48
import qualified Distribution.Client.Init.Types as IT
         ( InitFlags(..), PackageType(..) )
49 50
import Distribution.Client.Targets
         ( UserConstraint, readUserConstraint )
51 52 53

import Distribution.Simple.Program
         ( defaultProgramConfiguration )
54
import Distribution.Simple.Command hiding (boolOpt)
Duncan Coutts's avatar
Duncan Coutts committed
55
import qualified Distribution.Simple.Setup as Cabal
56
import Distribution.Simple.Setup
EyalLotem's avatar
EyalLotem committed
57 58
         ( ConfigFlags(..), BuildFlags(..), SDistFlags(..), HaddockFlags(..)
         , Flag(..), toFlag, fromFlag, flagToMaybe, flagToList
59
         , optionVerbosity, boolOpt, trueArg, falseArg )
60 61
import Distribution.Simple.InstallDirs
         ( PathTemplate, toPathTemplate, fromPathTemplate )
62
import Distribution.Version
Duncan Coutts's avatar
Duncan Coutts committed
63
         ( Version(Version), anyVersion, thisVersion )
64
import Distribution.Package
65
         ( PackageIdentifier, packageName, packageVersion, Dependency(..) )
66 67
import Distribution.PackageDescription
         ( RepoKind(..) )
68
import Distribution.Text
69
         ( Text(..), display )
70
import Distribution.ReadE
71
         ( ReadE(..), readP_to_E, succeedReadE )
72
import qualified Distribution.Compat.ReadP as Parse
Andres Löh's avatar
Andres Löh committed
73
         ( ReadP, readP_to_S, readS_to_P, char, munch1, pfail, (+++) )
74 75
import Distribution.Verbosity
         ( Verbosity, normal )
76 77
import Distribution.Simple.Utils
         ( wrapText )
78

79 80
import Data.Char
         ( isSpace, isAlphaNum )
81 82
import Data.List
         ( intercalate )
83
import Data.Maybe
84
         ( listToMaybe, maybeToList, fromMaybe )
85 86 87 88 89 90 91 92
import Data.Monoid
         ( Monoid(..) )
import Control.Monad
         ( liftM )
import System.FilePath
         ( (</>) )
import Network.URI
         ( parseAbsoluteURI, uriToString )
93

94 95 96 97 98 99 100 101 102
-- ------------------------------------------------------------
-- * Global flags
-- ------------------------------------------------------------

-- | Flags that apply at the top level, not to any sub-command.
data GlobalFlags = GlobalFlags {
    globalVersion        :: Flag Bool,
    globalNumericVersion :: Flag Bool,
    globalConfigFile     :: Flag FilePath,
103
    globalRemoteRepos    :: [RemoteRepo],     -- ^ Available Hackage servers.
104
    globalCacheDir       :: Flag FilePath,
105
    globalLocalRepos     :: [FilePath],
106
    globalLogsDir        :: Flag FilePath,
107
    globalWorldFile      :: Flag FilePath
108
  }
Duncan Coutts's avatar
Duncan Coutts committed
109

110 111 112 113 114 115 116
defaultGlobalFlags :: GlobalFlags
defaultGlobalFlags  = GlobalFlags {
    globalVersion        = Flag False,
    globalNumericVersion = Flag False,
    globalConfigFile     = mempty,
    globalRemoteRepos    = [],
    globalCacheDir       = mempty,
117
    globalLocalRepos     = mempty,
118
    globalLogsDir        = mempty,
119
    globalWorldFile      = mempty
120 121 122 123 124 125
  }

globalCommand :: CommandUI GlobalFlags
globalCommand = CommandUI {
    commandName         = "",
    commandSynopsis     = "",
126 127 128 129
    commandUsage        = \_ ->
         "This program is the command line interface "
           ++ "to the Haskell Cabal infrastructure.\n"
      ++ "See http://www.haskell.org/cabal/ for more information.\n",
130
    commandDescription  = Just $ \pname ->
131 132 133 134 135 136
         "For more information about a command use:\n"
      ++ "  " ++ pname ++ " COMMAND --help\n\n"
      ++ "To install Cabal packages from hackage use:\n"
      ++ "  " ++ pname ++ " install foo [--dry-run]\n\n"
      ++ "Occasionally you need to update the list of available packages:\n"
      ++ "  " ++ pname ++ " update\n",
137 138
    commandDefaultFlags = defaultGlobalFlags,
    commandOptions      = \showOrParseArgs ->
139
      (case showOrParseArgs of ShowArgs -> take 3; ParseArgs -> id)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
      [option ['V'] ["version"]
         "Print version information"
         globalVersion (\v flags -> flags { globalVersion = v })
         trueArg

      ,option [] ["numeric-version"]
         "Print just the version number"
         globalNumericVersion (\v flags -> flags { globalNumericVersion = v })
         trueArg

      ,option [] ["config-file"]
         "Set an alternate location for the config file"
         globalConfigFile (\v flags -> flags { globalConfigFile = v })
         (reqArgFlag "FILE")

      ,option [] ["remote-repo"]
         "The name and url for a remote repository"
         globalRemoteRepos (\v flags -> flags { globalRemoteRepos = v })
         (reqArg' "NAME:URL" (maybeToList . readRepo) (map showRepo))

      ,option [] ["remote-repo-cache"]
         "The location where downloads from all remote repos are cached"
         globalCacheDir (\v flags -> flags { globalCacheDir = v })
         (reqArgFlag "DIR")

      ,option [] ["local-repo"]
         "The location of a local repository"
         globalLocalRepos (\v flags -> flags { globalLocalRepos = v })
         (reqArg' "DIR" (\x -> [x]) id)
169

170 171 172 173 174
      ,option [] ["logs-dir"]
         "The location to put log files"
         globalLogsDir (\v flags -> flags { globalLogsDir = v })
         (reqArgFlag "DIR")

175 176 177 178
      ,option [] ["world-file"]
         "The location of the world file"
         globalWorldFile (\v flags -> flags { globalWorldFile = v })
         (reqArgFlag "FILE")
179 180 181 182 183 184 185 186 187 188
      ]
  }

instance Monoid GlobalFlags where
  mempty = GlobalFlags {
    globalVersion        = mempty,
    globalNumericVersion = mempty,
    globalConfigFile     = mempty,
    globalRemoteRepos    = mempty,
    globalCacheDir       = mempty,
189
    globalLocalRepos     = mempty,
190
    globalLogsDir        = mempty,
191
    globalWorldFile      = mempty
192 193 194 195 196 197 198
  }
  mappend a b = GlobalFlags {
    globalVersion        = combine globalVersion,
    globalNumericVersion = combine globalNumericVersion,
    globalConfigFile     = combine globalConfigFile,
    globalRemoteRepos    = combine globalRemoteRepos,
    globalCacheDir       = combine globalCacheDir,
199
    globalLocalRepos     = combine globalLocalRepos,
200
    globalLogsDir        = combine globalLogsDir,
201
    globalWorldFile      = combine globalWorldFile
Duncan Coutts's avatar
Duncan Coutts committed
202
  }
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
    where combine field = field a `mappend` field b

globalRepos :: GlobalFlags -> [Repo]
globalRepos globalFlags = remoteRepos ++ localRepos
  where
    remoteRepos =
      [ Repo (Left remote) cacheDir
      | remote <- globalRemoteRepos globalFlags
      , let cacheDir = fromFlag (globalCacheDir globalFlags)
                   </> remoteRepoName remote ]
    localRepos =
      [ Repo (Right LocalRepo) local
      | local <- globalLocalRepos globalFlags ]

-- ------------------------------------------------------------
-- * Config flags
-- ------------------------------------------------------------
Duncan Coutts's avatar
Duncan Coutts committed
220

221
configureCommand :: CommandUI ConfigFlags
222
configureCommand = (Cabal.configureCommand defaultProgramConfiguration) {
223
    commandDefaultFlags = mempty
Duncan Coutts's avatar
Duncan Coutts committed
224 225
  }

226 227 228
configureOptions ::  ShowOrParseArgs -> [OptionField ConfigFlags]
configureOptions = commandOptions configureCommand

229
filterConfigureFlags :: ConfigFlags -> Version -> ConfigFlags
230
filterConfigureFlags flags cabalLibVersion
231 232 233 234 235 236 237 238 239 240 241 242 243 244
  | cabalLibVersion >= Version [1,14,0] [] = flags
  | cabalLibVersion <  Version [1,3,10] [] = flags_1_3_10
  | cabalLibVersion <  Version [1,10,0] [] = flags_1_10_0
  | cabalLibVersion <  Version [1,14,0] [] = flags_1_14_0

  -- A no-op that silences the "pattern match is non-exhaustive" warning.
  | otherwise = flags
  where
    -- Cabal < 1.14.0 doesn't know about --disable-benchmarks.
    flags_1_14_0 = flags        { configBenchmarks  = NoFlag }
    -- Cabal < 1.10.0 doesn't know about --disable-tests.
    flags_1_10_0 = flags_1_14_0 { configTests       = NoFlag }
    -- Cabal < 1.3.10 does not grok the constraints flag.
    flags_1_3_10 = flags_1_10_0 { configConstraints = [] }
245

246 247 248 249 250 251 252 253
-- ------------------------------------------------------------
-- * Config extra flags
-- ------------------------------------------------------------

-- | cabal configure takes some extra flags beyond runghc Setup configure
--
data ConfigExFlags = ConfigExFlags {
    configCabalVersion :: Flag Version,
254
    configExConstraints:: [UserConstraint],
255
    configPreferences  :: [Dependency],
256
    configSolver       :: Flag PreSolver
257 258 259
  }

defaultConfigExFlags :: ConfigExFlags
260
defaultConfigExFlags = mempty { configSolver = Flag defaultSolver }
261 262 263 264 265

configureExCommand :: CommandUI (ConfigFlags, ConfigExFlags)
configureExCommand = configureCommand {
    commandDefaultFlags = (mempty, defaultConfigExFlags),
    commandOptions      = \showOrParseArgs ->
266 267
         liftOptions fst setFst (filter ((/="constraint") . optionName) $
                                 configureOptions   showOrParseArgs)
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
      ++ liftOptions snd setSnd (configureExOptions showOrParseArgs)
  }
  where
    setFst a (_,b) = (a,b)
    setSnd b (a,_) = (a,b)

configureExOptions ::  ShowOrParseArgs -> [OptionField ConfigExFlags]
configureExOptions _showOrParseArgs =
  [ option [] ["cabal-lib-version"]
      ("Select which version of the Cabal lib to use to build packages "
      ++ "(useful for testing).")
      configCabalVersion (\v flags -> flags { configCabalVersion = v })
      (reqArg "VERSION" (readP_to_E ("Cannot parse cabal lib version: "++)
                                    (fmap toFlag parse))
                        (map display . flagToList))
283 284 285 286 287 288
  , option [] ["constraint"]
      "Specify constraints on a package (version, installed/source, flags)"
      configExConstraints (\v flags -> flags { configExConstraints = v })
      (reqArg "CONSTRAINT"
              (fmap (\x -> [x]) (ReadE readUserConstraint))
              (map display))
289 290 291 292

  , option [] ["preference"]
      "Specify preferences (soft constraints) on the version of a package"
      configPreferences (\v flags -> flags { configPreferences = v })
293 294 295 296
      (reqArg "CONSTRAINT"
              (readP_to_E (const "dependency expected")
                          (fmap (\x -> [x]) parse))
              (map display))
297 298

  , optionSolver configSolver (\v flags -> flags { configSolver = v })
299 300 301 302 303
  ]

instance Monoid ConfigExFlags where
  mempty = ConfigExFlags {
    configCabalVersion = mempty,
304
    configExConstraints= mempty,
305 306
    configPreferences  = mempty,
    configSolver       = mempty
307 308 309
  }
  mappend a b = ConfigExFlags {
    configCabalVersion = combine configCabalVersion,
310
    configExConstraints= combine configExConstraints,
311 312
    configPreferences  = combine configPreferences,
    configSolver       = combine configSolver
313 314 315
  }
    where combine field = field a `mappend` field b

ttuegel's avatar
ttuegel committed
316 317 318 319 320 321 322 323 324
-- ------------------------------------------------------------
-- * Build flags
-- ------------------------------------------------------------

buildCommand :: CommandUI BuildFlags
buildCommand = (Cabal.buildCommand defaultProgramConfiguration) {
    commandDefaultFlags = mempty
  }

325
-- ------------------------------------------------------------
326
-- * Fetch command
327
-- ------------------------------------------------------------
328

329 330 331 332
data FetchFlags = FetchFlags {
--    fetchOutput    :: Flag FilePath,
      fetchDeps      :: Flag Bool,
      fetchDryRun    :: Flag Bool,
333
      fetchSolver           :: Flag PreSolver,
334 335 336
      fetchMaxBackjumps     :: Flag Int,
      fetchReorderGoals     :: Flag Bool,
      fetchIndependentGoals :: Flag Bool,
337
      fetchShadowPkgs       :: Flag Bool,
338 339 340 341 342 343 344 345
      fetchVerbosity :: Flag Verbosity
    }

defaultFetchFlags :: FetchFlags
defaultFetchFlags = FetchFlags {
--  fetchOutput    = mempty,
    fetchDeps      = toFlag True,
    fetchDryRun    = toFlag False,
346 347 348 349
    fetchSolver           = Flag defaultSolver,
    fetchMaxBackjumps     = Flag defaultMaxBackjumps,
    fetchReorderGoals     = Flag False,
    fetchIndependentGoals = Flag False,
350
    fetchShadowPkgs       = Flag False,
351 352 353 354
    fetchVerbosity = toFlag normal
   }

fetchCommand :: CommandUI FetchFlags
Duncan Coutts's avatar
Duncan Coutts committed
355 356
fetchCommand = CommandUI {
    commandName         = "fetch",
357
    commandSynopsis     = "Downloads packages for later installation.",
Duncan Coutts's avatar
Duncan Coutts committed
358
    commandDescription  = Nothing,
refold's avatar
refold committed
359
    commandUsage        = usagePackages "fetch",
360
    commandDefaultFlags = defaultFetchFlags,
361
    commandOptions      = \ showOrParseArgs -> [
362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
         optionVerbosity fetchVerbosity (\v flags -> flags { fetchVerbosity = v })

--     , option "o" ["output"]
--         "Put the package(s) somewhere specific rather than the usual cache."
--         fetchOutput (\v flags -> flags { fetchOutput = v })
--         (reqArgFlag "PATH")

       , option [] ["dependencies", "deps"]
           "Resolve and fetch dependencies (default)"
           fetchDeps (\v flags -> flags { fetchDeps = v })
           trueArg

       , option [] ["no-dependencies", "no-deps"]
           "Ignore dependencies"
           fetchDeps (\v flags -> flags { fetchDeps = v })
           falseArg

       , option [] ["dry-run"]
           "Do not install anything, only print what would be installed."
           fetchDryRun (\v flags -> flags { fetchDryRun = v })
           trueArg
383 384 385 386

       ] ++

       optionSolver      fetchSolver           (\v flags -> flags { fetchSolver           = v }) :
387 388
       optionSolverFlags showOrParseArgs
                         fetchMaxBackjumps     (\v flags -> flags { fetchMaxBackjumps     = v })
389 390
                         fetchReorderGoals     (\v flags -> flags { fetchReorderGoals     = v })
                         fetchIndependentGoals (\v flags -> flags { fetchIndependentGoals = v })
391
                         fetchShadowPkgs       (\v flags -> flags { fetchShadowPkgs       = v })
392

Duncan Coutts's avatar
Duncan Coutts committed
393 394
  }

395 396 397 398
-- ------------------------------------------------------------
-- * Other commands
-- ------------------------------------------------------------

399
updateCommand  :: CommandUI (Flag Verbosity)
Duncan Coutts's avatar
Duncan Coutts committed
400 401 402 403
updateCommand = CommandUI {
    commandName         = "update",
    commandSynopsis     = "Updates list of known packages",
    commandDescription  = Nothing,
refold's avatar
refold committed
404
    commandUsage        = usageFlags "update",
405
    commandDefaultFlags = toFlag normal,
406
    commandOptions      = \_ -> [optionVerbosity id const]
Duncan Coutts's avatar
Duncan Coutts committed
407 408
  }

409
upgradeCommand  :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
410
upgradeCommand = configureCommand {
ijones's avatar
ijones committed
411
    commandName         = "upgrade",
412
    commandSynopsis     = "(command disabled, use install instead)",
ijones's avatar
ijones committed
413
    commandDescription  = Nothing,
refold's avatar
refold committed
414
    commandUsage        = usageFlagsOrPackages "upgrade",
415
    commandDefaultFlags = (mempty, mempty, mempty, mempty),
416
    commandOptions      = commandOptions installCommand
ijones's avatar
ijones committed
417 418
  }

Duncan Coutts's avatar
Duncan Coutts committed
419 420 421 422 423 424 425 426 427 428 429
{-
cleanCommand  :: CommandUI ()
cleanCommand = makeCommand name shortDesc longDesc emptyFlags options
  where
    name       = "clean"
    shortDesc  = "Removes downloaded files"
    longDesc   = Nothing
    emptyFlags = ()
    options _  = []
-}

430 431 432 433 434 435
checkCommand  :: CommandUI (Flag Verbosity)
checkCommand = CommandUI {
    commandName         = "check",
    commandSynopsis     = "Check the package for common mistakes",
    commandDescription  = Nothing,
    commandUsage        = \pname -> "Usage: " ++ pname ++ " check\n",
436
    commandDefaultFlags = toFlag normal,
437
    commandOptions      = \_ -> []
438 439
  }

refold's avatar
refold committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
runCommand :: CommandUI BuildFlags
runCommand = CommandUI {
    commandName         = "run",
    commandSynopsis     = "Runs the compiled executable.",
    commandDescription  = Nothing,
    commandUsage        =
      (\pname -> "Usage: " ++ pname
                 ++ " run [FLAGS] [EXECUTABLE] [-- EXECUTABLE_FLAGS]\n\n"
                 ++ "Flags for run:"),
    commandDefaultFlags = mempty,
    commandOptions      = Cabal.buildOptions progConf
  }
  where
    progConf = defaultProgramConfiguration

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
-- ------------------------------------------------------------
-- * Report flags
-- ------------------------------------------------------------

data ReportFlags = ReportFlags {
    reportUsername  :: Flag Username,
    reportPassword  :: Flag Password,
    reportVerbosity :: Flag Verbosity
  }

defaultReportFlags :: ReportFlags
defaultReportFlags = ReportFlags {
    reportUsername  = mempty,
    reportPassword  = mempty,
    reportVerbosity = toFlag normal
  }

reportCommand :: CommandUI ReportFlags
473 474 475
reportCommand = CommandUI {
    commandName         = "report",
    commandSynopsis     = "Upload build reports to a remote server.",
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
    commandDescription  = Just $ \_ ->
         "You can store your Hackage login in the ~/.cabal/config file\n",
    commandUsage        = \pname -> "Usage: " ++ pname ++ " report [FLAGS]\n\n"
      ++ "Flags for upload:",
    commandDefaultFlags = defaultReportFlags,
    commandOptions      = \_ ->
      [optionVerbosity reportVerbosity (\v flags -> flags { reportVerbosity = v })

      ,option ['u'] ["username"]
        "Hackage username."
        reportUsername (\v flags -> flags { reportUsername = v })
        (reqArg' "USERNAME" (toFlag . Username)
                            (flagToList . fmap unUsername))

      ,option ['p'] ["password"]
        "Hackage password."
        reportPassword (\v flags -> flags { reportPassword = v })
        (reqArg' "PASSWORD" (toFlag . Password)
                            (flagToList . fmap unPassword))
      ]
496 497
  }

498 499 500 501 502 503 504 505 506 507 508 509 510
instance Monoid ReportFlags where
  mempty = ReportFlags {
    reportUsername  = mempty,
    reportPassword  = mempty,
    reportVerbosity = mempty
  }
  mappend a b = ReportFlags {
    reportUsername  = combine reportUsername,
    reportPassword  = combine reportPassword,
    reportVerbosity = combine reportVerbosity
  }
    where combine field = field a `mappend` field b

511
-- ------------------------------------------------------------
512
-- * Get flags
513 514
-- ------------------------------------------------------------

515 516 517 518 519 520
data GetFlags = GetFlags {
    getDestDir          :: Flag FilePath,
    getPristine         :: Flag Bool,
    getSourceRepository :: Flag (Maybe RepoKind),
    getVerbosity        :: Flag Verbosity
  }
521

522 523 524 525 526 527
defaultGetFlags :: GetFlags
defaultGetFlags = GetFlags {
    getDestDir          = mempty,
    getPristine         = mempty,
    getSourceRepository = mempty,
    getVerbosity        = toFlag normal
528 529
   }

530 531 532 533
getCommand :: CommandUI GetFlags
getCommand = CommandUI {
    commandName         = "get",
    commandSynopsis     = "Gets a package's source code.",
534
    commandDescription  = Nothing,
535
    commandUsage        = usagePackages "get",
536 537
    commandDefaultFlags = mempty,
    commandOptions      = \_ -> [
538
        optionVerbosity getVerbosity (\v flags -> flags { getVerbosity = v })
539 540

       ,option "d" ["destdir"]
refold's avatar
refold committed
541
         "Where to place the package source, defaults to the current directory."
542
         getDestDir (\v flags -> flags { getDestDir = v })
543
         (reqArgFlag "PATH")
544

545
       ,option "s" ["source-repository"]
refold's avatar
refold committed
546
         "Fork the package's source repository."
547 548 549 550 551 552
         getSourceRepository (\v flags -> flags { getSourceRepository = v })
        (optArg "[head|this|...]" (readP_to_E (const "invalid source-repository")
                                              (fmap (toFlag . Just) parse))
                                  (Flag Nothing)
                                  (map (fmap show) . flagToList))

553 554 555
       , option [] ["pristine"]
           ("Unpack the original pristine tarball, rather than updating the "
           ++ ".cabal file with the latest revision from the package archive.")
556
           getPristine (\v flags -> flags { getPristine = v })
557
           trueArg
558 559 560
       ]
  }

561 562 563 564 565 566 567
-- 'cabal unpack' is a deprecated alias for 'cabal get'.
unpackCommand :: CommandUI GetFlags
unpackCommand = getCommand {
  commandName  = "unpack",
  commandUsage = usagePackages "unpack"
  }

568 569 570 571 572 573 574
instance Monoid GetFlags where
  mempty = defaultGetFlags
  mappend a b = GetFlags {
    getDestDir          = combine getDestDir,
    getPristine         = combine getPristine,
    getSourceRepository = combine getSourceRepository,
    getVerbosity        = combine getVerbosity
575 576 577
  }
    where combine field = field a `mappend` field b

578 579 580 581 582 583
-- ------------------------------------------------------------
-- * List flags
-- ------------------------------------------------------------

data ListFlags = ListFlags {
    listInstalled :: Flag Bool,
584
    listSimpleOutput :: Flag Bool,
585 586 587 588 589 590
    listVerbosity :: Flag Verbosity
  }

defaultListFlags :: ListFlags
defaultListFlags = ListFlags {
    listInstalled = Flag False,
591
    listSimpleOutput = Flag False,
592 593 594 595 596 597
    listVerbosity = toFlag normal
  }

listCommand  :: CommandUI ListFlags
listCommand = CommandUI {
    commandName         = "list",
598
    commandSynopsis     = "List packages matching a search string.",
599
    commandDescription  = Nothing,
refold's avatar
refold committed
600
    commandUsage        = usageFlagsOrPackages "list",
601
    commandDefaultFlags = defaultListFlags,
602
    commandOptions      = \_ -> [
603
        optionVerbosity listVerbosity (\v flags -> flags { listVerbosity = v })
604

605
        , option [] ["installed"]
606 607 608 609
            "Only print installed packages"
            listInstalled (\v flags -> flags { listInstalled = v })
            trueArg

610 611 612 613 614
        , option [] ["simple-output"]
            "Print in a easy-to-parse format"
            listSimpleOutput (\v flags -> flags { listSimpleOutput = v })
            trueArg

615 616 617 618 619 620 621
        ]
  }

instance Monoid ListFlags where
  mempty = defaultListFlags
  mappend a b = ListFlags {
    listInstalled = combine listInstalled,
622
    listSimpleOutput = combine listSimpleOutput,
623 624 625 626
    listVerbosity = combine listVerbosity
  }
    where combine field = field a `mappend` field b

627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
-- ------------------------------------------------------------
-- * Info flags
-- ------------------------------------------------------------

data InfoFlags = InfoFlags {
    infoVerbosity :: Flag Verbosity
  }

defaultInfoFlags :: InfoFlags
defaultInfoFlags = InfoFlags {
    infoVerbosity = toFlag normal
  }

infoCommand  :: CommandUI InfoFlags
infoCommand = CommandUI {
    commandName         = "info",
    commandSynopsis     = "Display detailed information about a particular package.",
    commandDescription  = Nothing,
refold's avatar
refold committed
645
    commandUsage        = usagePackages "info",
646 647 648 649 650 651 652 653 654 655 656 657 658
    commandDefaultFlags = defaultInfoFlags,
    commandOptions      = \_ -> [
        optionVerbosity infoVerbosity (\v flags -> flags { infoVerbosity = v })
        ]
  }

instance Monoid InfoFlags where
  mempty = defaultInfoFlags
  mappend a b = InfoFlags {
    infoVerbosity = combine infoVerbosity
  }
    where combine field = field a `mappend` field b

659 660 661 662
-- ------------------------------------------------------------
-- * Install flags
-- ------------------------------------------------------------

663 664
-- | Install takes the same flags as configure along with a few extras.
--
665
data InstallFlags = InstallFlags {
666 667 668
    installDocumentation    :: Flag Bool,
    installHaddockIndex     :: Flag PathTemplate,
    installDryRun           :: Flag Bool,
669 670 671
    installMaxBackjumps     :: Flag Int,
    installReorderGoals     :: Flag Bool,
    installIndependentGoals :: Flag Bool,
672
    installShadowPkgs       :: Flag Bool,
673 674
    installReinstall        :: Flag Bool,
    installAvoidReinstalls  :: Flag Bool,
675
    installOverrideReinstall :: Flag Bool,
676 677 678 679 680 681 682 683
    installUpgradeDeps      :: Flag Bool,
    installOnly             :: Flag Bool,
    installOnlyDeps         :: Flag Bool,
    installRootCmd          :: Flag String,
    installSummaryFile      :: [PathTemplate],
    installLogFile          :: Flag PathTemplate,
    installBuildReports     :: Flag ReportLevel,
    installSymlinkBinDir    :: Flag FilePath,
684
    installOneShot          :: Flag Bool,
685
    installNumJobs          :: Flag (Maybe Int)
686 687 688 689
  }

defaultInstallFlags :: InstallFlags
defaultInstallFlags = InstallFlags {
690 691 692
    installDocumentation   = Flag False,
    installHaddockIndex    = Flag docIndexFile,
    installDryRun          = Flag False,
693 694 695
    installMaxBackjumps    = Flag defaultMaxBackjumps,
    installReorderGoals    = Flag False,
    installIndependentGoals= Flag False,
696
    installShadowPkgs      = Flag False,
697 698
    installReinstall       = Flag False,
    installAvoidReinstalls = Flag False,
699
    installOverrideReinstall = Flag False,
700 701 702 703 704 705 706 707
    installUpgradeDeps     = Flag False,
    installOnly            = Flag False,
    installOnlyDeps        = Flag False,
    installRootCmd         = mempty,
    installSummaryFile     = mempty,
    installLogFile         = mempty,
    installBuildReports    = Flag NoReports,
    installSymlinkBinDir   = mempty,
708
    installOneShot         = Flag False,
709
    installNumJobs         = mempty
710
  }
711 712
  where
    docIndexFile = toPathTemplate ("$datadir" </> "doc" </> "index.html")
713

714 715 716
defaultMaxBackjumps :: Int
defaultMaxBackjumps = 200

717 718
defaultSolver :: PreSolver
defaultSolver = Choose
719 720

allSolvers :: String
721
allSolvers = intercalate ", " (map display ([minBound .. maxBound] :: [PreSolver]))
722

723
installCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
724
installCommand = CommandUI {
725 726
  commandName         = "install",
  commandSynopsis     = "Installs a list of packages.",
refold's avatar
refold committed
727
  commandUsage        = usageFlagsOrPackages "install",
728 729 730 731 732
  commandDescription  = Just $ \pname ->
    let original = case commandDescription configureCommand of
          Just desc -> desc pname ++ "\n"
          Nothing   -> ""
     in original
733
     ++ "Examples:\n"
734 735 736 737 738 739 740 741
     ++ "  " ++ pname ++ " install                 "
     ++ "    Package in the current directory\n"
     ++ "  " ++ pname ++ " install foo             "
     ++ "    Package from the hackage server\n"
     ++ "  " ++ pname ++ " install foo-1.0         "
     ++ "    Specific version of a package\n"
     ++ "  " ++ pname ++ " install 'foo < 2'       "
     ++ "    Constrained package version\n",
742
  commandDefaultFlags = (mempty, mempty, mempty, mempty),
743
  commandOptions      = \showOrParseArgs ->
744 745
       liftOptions get1 set1 (filter ((/="constraint") . optionName) $
                              configureOptions   showOrParseArgs)
746 747
    ++ liftOptions get2 set2 (configureExOptions showOrParseArgs)
    ++ liftOptions get3 set3 (installOptions     showOrParseArgs)
748
    ++ liftOptions get4 set4 (haddockOptions     showOrParseArgs)
749
  }
750
  where
751 752 753 754 755
    get1 (a,_,_,_) = a; set1 a (_,b,c,d) = (a,b,c,d)
    get2 (_,b,_,_) = b; set2 b (a,_,c,d) = (a,b,c,d)
    get3 (_,_,c,_) = c; set3 c (a,b,_,d) = (a,b,c,d)
    get4 (_,_,_,d) = d; set4 d (a,b,c,_) = (a,b,c,d)

756 757 758 759 760 761 762 763 764 765 766 767 768
haddockOptions :: ShowOrParseArgs -> [OptionField HaddockFlags]
haddockOptions showOrParseArgs
  = [ opt { optionName = "haddock-" ++ name,
            optionDescr = [ fmapOptFlags (\(_, lflags) -> ([], map ("haddock-" ++) lflags)) descr
                          | descr <- optionDescr opt] }
    | opt <- commandOptions Cabal.haddockCommand showOrParseArgs
    , let name = optionName opt
    , name `elem` ["hoogle", "html", "html-location",
                   "executables", "internal", "css",
                   "hyperlink-source", "hscolour-css",
                   "contents-location"]
    ]
  where
769 770 771 772 773
    fmapOptFlags :: (OptFlags -> OptFlags) -> OptDescr a -> OptDescr a
    fmapOptFlags modify (ReqArg d f p r w)    = ReqArg d (modify f) p r w
    fmapOptFlags modify (OptArg d f p r i w)  = OptArg d (modify f) p r i w
    fmapOptFlags modify (ChoiceOpt xs)        = ChoiceOpt [(d, modify f, i, w) | (d, f, i, w) <- xs]
    fmapOptFlags modify (BoolOpt d f1 f2 r w) = BoolOpt d (modify f1) (modify f2) r w
774 775 776 777

installOptions ::  ShowOrParseArgs -> [OptionField InstallFlags]
installOptions showOrParseArgs =
      [ option "" ["documentation"]
778 779 780 781
          "building of documentation"
          installDocumentation (\v flags -> flags { installDocumentation = v })
          (boolOpt [] [])

782 783
      , option [] ["doc-index-file"]
          "A central index of haddock API documentation (template cannot use $pkgid)"
784 785 786
          installHaddockIndex (\v flags -> flags { installHaddockIndex = v })
          (reqArg' "TEMPLATE" (toFlag.toPathTemplate)
                              (flagToList . fmap fromPathTemplate))
787

788
      , option [] ["dry-run"]
789 790 791
          "Do not install anything, only print what would be installed."
          installDryRun (\v flags -> flags { installDryRun = v })
          trueArg
792
      ] ++
793

794 795
      optionSolverFlags showOrParseArgs
                        installMaxBackjumps     (\v flags -> flags { installMaxBackjumps     = v })
796
                        installReorderGoals     (\v flags -> flags { installReorderGoals     = v })
797 798
                        installIndependentGoals (\v flags -> flags { installIndependentGoals = v })
                        installShadowPkgs       (\v flags -> flags { installShadowPkgs       = v }) ++
799

800
      [ option [] ["reinstall"]
801 802
          "Install even if it means installing the same version again."
          installReinstall (\v flags -> flags { installReinstall = v })
803
          (yesNoOpt showOrParseArgs)
804

805 806 807
      , option [] ["avoid-reinstalls"]
          "Do not select versions that would destructively overwrite installed packages."
          installAvoidReinstalls (\v flags -> flags { installAvoidReinstalls = v })
808
          (yesNoOpt showOrParseArgs)
809

810
      , option [] ["force-reinstalls"]
811
          "Reinstall packages even if they will most likely break other installed packages."
812
          installOverrideReinstall (\v flags -> flags { installOverrideReinstall = v })
813
          (yesNoOpt showOrParseArgs)
814

815 816 817
      , option [] ["upgrade-dependencies"]
          "Pick the latest version for all dependencies, rather than trying to pick an installed version."
          installUpgradeDeps (\v flags -> flags { installUpgradeDeps = v })
818
          (yesNoOpt showOrParseArgs)
819

820 821 822
      , option [] ["only-dependencies"]
          "Install only the dependencies necessary to build the given packages"
          installOnlyDeps (\v flags -> flags { installOnlyDeps = v })
823
          (yesNoOpt showOrParseArgs)
824

825 826 827 828 829
      , option [] ["dependencies-only"]
          "A synonym for --only-dependencies"
          installOnlyDeps (\v flags -> flags { installOnlyDeps = v })
          (yesNoOpt showOrParseArgs)

830 831 832 833 834
      , option [] ["root-cmd"]
          "Command used to gain root privileges, when installing with --global."
          installRootCmd (\v flags -> flags { installRootCmd = v })
          (reqArg' "COMMAND" toFlag flagToList)

835 836 837 838 839
      , option [] ["symlink-bindir"]
          "Add symlinks to installed executables into this directory."
           installSymlinkBinDir (\v flags -> flags { installSymlinkBinDir = v })
           (reqArgFlag "DIR")

840 841 842 843 844 845
      , option [] ["build-summary"]
          "Save build summaries to file (name template can use $pkgid, $compiler, $os, $arch)"
          installSummaryFile (\v flags -> flags { installSummaryFile = v })
          (reqArg' "TEMPLATE" (\x -> [toPathTemplate x]) (map fromPathTemplate))

      , option [] ["build-log"]
Duncan Coutts's avatar
Duncan Coutts committed
846 847
          "Log all builds to file (name template can use $pkgid, $compiler, $os, $arch)"
          installLogFile (\v flags -> flags { installLogFile = v })
848 849
          (reqArg' "TEMPLATE" (toFlag.toPathTemplate)
                              (flagToList . fmap fromPathTemplate))
Duncan Coutts's avatar
Duncan Coutts committed
850

851 852
      , option [] ["remote-build-reporting"]
          "Generate build reports to send to a remote server (none, anonymous or detailed)."
853
          installBuildReports (\v flags -> flags { installBuildReports = v })
854 855 856 857
          (reqArg "LEVEL" (readP_to_E (const $ "report level must be 'none', "
                                            ++ "'anonymous' or 'detailed'")
                                      (toFlag `fmap` parse))
                          (flagToList . fmap display))
858

859 860 861
      , option [] ["one-shot"]
          "Do not record the packages in the world file."
          installOneShot (\v flags -> flags { installOneShot = v })
862
          (yesNoOpt showOrParseArgs)
863 864

      , option "j" ["jobs"]
865
        "Run NUM jobs simultaneously (or '$ncpus' if no NUM is given)."
866
        installNumJobs (\v flags -> flags { installNumJobs = v })
867
        (optArg "NUM" (fmap Flag flagToJobs)
868
                      (Flag Nothing)
869
                      (map (Just . maybe "$ncpus" show) . flagToList))
870 871
      ] ++ case showOrParseArgs of      -- TODO: remove when "cabal install" avoids
          ParseArgs ->
EyalLotem's avatar
EyalLotem committed
872
            [ option [] ["only"]
873 874
              "Only installs the package in the current directory."
              installOnly (\v flags -> flags { installOnly = v })
EyalLotem's avatar
EyalLotem committed
875
              trueArg ]
876
          _ -> []
877 878 879 880 881
  where
    flagToJobs :: ReadE (Maybe Int)
    flagToJobs = ReadE $ \s ->
      case s of
        "$ncpus" -> Right Nothing
882
        _        -> case reads s of
883 884 885 886 887 888
          [(n, "")]
            | n < 1     -> Left "The number of jobs should be 1 or more."
            | n > 64    -> Left "You probably don't want that many jobs."
            | otherwise -> Right (Just n)
          _             -> Left "The jobs value should be a number or '$ncpus'"

889 890

instance Monoid InstallFlags where
891
  mempty = InstallFlags {
892 893 894 895 896
    installDocumentation   = mempty,
    installHaddockIndex    = mempty,
    installDryRun          = mempty,
    installReinstall       = mempty,
    installAvoidReinstalls = mempty,
897
    installOverrideReinstall = mempty,
Andres Löh's avatar
Andres Löh committed
898
    installMaxBackjumps    = mempty,
899
    installUpgradeDeps     = mempty,
Andres Löh's avatar
Andres Löh committed
900
    installReorderGoals    = mempty,
901
    installIndependentGoals= mempty,
902
    installShadowPkgs      = mempty,
903 904 905 906 907 908 909
    installOnly            = mempty,
    installOnlyDeps        = mempty,
    installRootCmd         = mempty,
    installSummaryFile     = mempty,
    installLogFile         = mempty,
    installBuildReports    = mempty,
    installSymlinkBinDir   = mempty,
910 911
    installOneShot         = mempty,
    installNumJobs         = mempty
912
  }
913
  mappend a b = InstallFlags {
914 915 916 917 918
    installDocumentation   = combine installDocumentation,
    installHaddockIndex    = combine installHaddockIndex,
    installDryRun          = combine installDryRun,
    installReinstall       = combine installReinstall,
    installAvoidReinstalls = combine installAvoidReinstalls,
919
    installOverrideReinstall = combine installOverrideReinstall,
Andres Löh's avatar
Andres Löh committed
920
    installMaxBackjumps    = combine installMaxBackjumps,
921
    installUpgradeDeps     = combine installUpgradeDeps,
Andres Löh's avatar
Andres Löh committed
922
    installReorderGoals    = combine installReorderGoals,
923
    installIndependentGoals= combine installIndependentGoals,
924
    installShadowPkgs      = combine installShadowPkgs,
925 926 927 928 929 930 931
    installOnly            = combine installOnly,
    installOnlyDeps        = combine installOnlyDeps,
    installRootCmd         = combine installRootCmd,
    installSummaryFile     = combine installSummaryFile,
    installLogFile         = combine installLogFile,
    installBuildReports    = combine installBuildReports,
    installSymlinkBinDir   = combine installSymlinkBinDir,
932 933
    installOneShot         = combine installOneShot,
    installNumJobs         = combine installNumJobs
934 935 936
  }
    where combine field = field a `mappend` field b

937 938 939 940 941 942 943 944 945
-- ------------------------------------------------------------
-- * Upload flags
-- ------------------------------------------------------------

data UploadFlags = UploadFlags {
    uploadCheck     :: Flag Bool,
    uploadUsername  :: Flag Username,
    uploadPassword  :: Flag Password,
    uploadVerbosity :: Flag Verbosity
946
  }
947 948 949 950 951 952 953 954 955 956 957 958 959 960

defaultUploadFlags :: UploadFlags
defaultUploadFlags = UploadFlags {
    uploadCheck     = toFlag False,
    uploadUsername  = mempty,
    uploadPassword  = mempty,
    uploadVerbosity = toFlag normal
  }

uploadCommand :: CommandUI UploadFlags
uploadCommand = CommandUI {
    commandName         = "upload",
    commandSynopsis     = "Uploads source packages to Hackage",
    commandDescription  = Just $ \_ ->
961
         "You can store your Hackage login in the ~/.cabal/config file\n",
962 963 964 965 966
    commandUsage        = \pname ->
         "Usage: " ++ pname ++ " upload [FLAGS] [TARFILES]\n\n"
      ++ "Flags for upload:",
    commandDefaultFlags = defaultUploadFlags,
    commandOptions      = \_ ->
967
      [optionVerbosity uploadVerbosity (\v flags -> flags { uploadVerbosity = v })
968 969 970 971

      ,option ['c'] ["check"]
         "Do not upload, just do QA checks."
        uploadCheck (\v flags -> flags { uploadCheck = v })
972
        trueArg
973 974 975 976

      ,option ['u'] ["username"]
        "Hackage username."
        uploadUsername (\v flags -> flags { uploadUsername = v })
977 978
        (reqArg' "USERNAME" (toFlag . Username)
                            (flagToList . fmap unUsername))
979 980 981 982

      ,option ['p'] ["password"]
        "Hackage password."
        uploadPassword (\v flags -> flags { uploadPassword = v })
983 984
        (reqArg' "PASSWORD" (toFlag . Password)
                            (flagToList . fmap unPassword))