Setup.hs 89.6 KB
Newer Older
Edsko de Vries's avatar
Edsko de Vries committed
1 2 3
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE RankNTypes #-}
4
{-# LANGUAGE DeriveGeneric #-}
5 6
-----------------------------------------------------------------------------
-- |
7
-- Module      :  Distribution.Client.Setup
8 9 10 11 12 13 14 15 16
-- Copyright   :  (c) David Himmelstrup 2005
-- License     :  BSD-like
--
-- Maintainer  :  lemmih@gmail.com
-- Stability   :  provisional
-- Portability :  portable
--
--
-----------------------------------------------------------------------------
17
module Distribution.Client.Setup
Edsko de Vries's avatar
Edsko de Vries committed
18 19
    ( globalCommand, GlobalFlags(..), defaultGlobalFlags
    , RepoContext(..), withRepoContext
20
    , configureCommand, ConfigFlags(..), filterConfigureFlags
21
    , configPackageDB', configCompilerAux'
22
    , configureExCommand, ConfigExFlags(..), defaultConfigExFlags
23
    , buildCommand, BuildFlags(..), BuildExFlags(..), SkipAddSourceDepsCheck(..)
24
    , replCommand, testCommand, benchmarkCommand
ttuegel's avatar
ttuegel committed
25
                        , configureExOptions, reconfigureCommand
26
    , installCommand, InstallFlags(..), installOptions, defaultInstallFlags
27
    , defaultSolver, defaultMaxBackjumps
28
    , listCommand, ListFlags(..)
Duncan Coutts's avatar
Duncan Coutts committed
29
    , updateCommand
ijones's avatar
ijones committed
30
    , upgradeCommand
31
    , uninstallCommand
32
    , infoCommand, InfoFlags(..)
33
    , fetchCommand, FetchFlags(..)
34
    , freezeCommand, FreezeFlags(..)
35
    , genBoundsCommand
36
    , getCommand, unpackCommand, GetFlags(..)
37
    , checkCommand
38
    , formatCommand
39
    , uploadCommand, UploadFlags(..), IsCandidate(..)
40
    , reportCommand, ReportFlags(..)
refold's avatar
refold committed
41
    , runCommand
42
    , initCommand, IT.InitFlags(..)
43
    , sdistCommand, SDistFlags(..), SDistExFlags(..), ArchiveFormat(..)
44
    , win32SelfUpgradeCommand, Win32SelfUpgradeFlags(..)
45
    , actAsSetupCommand, ActAsSetupFlags(..)
refold's avatar
refold committed
46
    , sandboxCommand, defaultSandboxLocation, SandboxFlags(..)
47
    , execCommand, ExecFlags(..)
48
    , userConfigCommand, UserConfigFlags(..)
Maciek Makowski's avatar
Maciek Makowski committed
49
    , manpageCommand
Duncan Coutts's avatar
Duncan Coutts committed
50 51

    , parsePackageArgs
52 53 54
    --TODO: stop exporting these:
    , showRepo
    , parseRepo
55
    , readRepo
56 57
    ) where

58
import Distribution.Client.Types
59
         ( Username(..), Password(..), RemoteRepo(..) )
60 61
import Distribution.Client.BuildReports.Types
         ( ReportLevel(..) )
62
import Distribution.Client.Dependency.Types
63
         ( PreSolver(..) )
64 65
import qualified Distribution.Client.Init.Types as IT
         ( InitFlags(..), PackageType(..) )
66 67
import Distribution.Client.Targets
         ( UserConstraint, readUserConstraint )
68 69
import Distribution.Utils.NubList
         ( NubList, toNubList, fromNubList)
70

71
import Distribution.Solver.Types.ConstraintSource
72
import Distribution.Solver.Types.Settings
73

74 75
import Distribution.Simple.Compiler ( Compiler, PackageDB, PackageDBStack )
import Distribution.Simple.Program (ProgramDb, defaultProgramDb)
76 77
import Distribution.Simple.Command hiding (boolOpt, boolOpt')
import qualified Distribution.Simple.Command as Command
78
import Distribution.Simple.Configure
79
       ( configCompilerAuxEx, interpretPackageDbFlags, computeEffectiveProfiling )
Duncan Coutts's avatar
Duncan Coutts committed
80
import qualified Distribution.Simple.Setup as Cabal
81
import Distribution.Simple.Setup
82 83
         ( ConfigFlags(..), BuildFlags(..), ReplFlags
         , TestFlags(..), BenchmarkFlags(..)
84
         , SDistFlags(..), HaddockFlags(..)
85
         , readPackageDbList, showPackageDbList
Edsko de Vries's avatar
Edsko de Vries committed
86
         , Flag(..), toFlag, flagToMaybe, flagToList
87 88
         , BooleanFlag(..), optionVerbosity
         , boolOpt, boolOpt', trueArg, falseArg
89
         , readPToMaybe, optionNumJobs )
90
import Distribution.Simple.InstallDirs
91 92
         ( PathTemplate, InstallDirs(sysconfdir)
         , toPathTemplate, fromPathTemplate )
93
import Distribution.Version
Duncan Coutts's avatar
Duncan Coutts committed
94
         ( Version(Version), anyVersion, thisVersion )
95
import Distribution.Package
96
         ( PackageIdentifier, packageName, packageVersion, Dependency(..) )
97
import Distribution.PackageDescription
98
         ( BuildType(..), RepoKind(..) )
99
import Distribution.System ( Platform )
100
import Distribution.Text
101
         ( Text(..), display )
102
import Distribution.ReadE
103
         ( ReadE(..), readP_to_E, succeedReadE )
104
import qualified Distribution.Compat.ReadP as Parse
105
         ( ReadP, char, munch1, pfail,  (+++) )
106
import Distribution.Compat.Semigroup
107
import Distribution.Verbosity
108
         ( Verbosity, lessVerbose, normal )
109
import Distribution.Simple.Utils
110
         ( wrapText, wrapLine )
111
import Distribution.Client.GlobalFlags
Edsko de Vries's avatar
Edsko de Vries committed
112 113 114
         ( GlobalFlags(..), defaultGlobalFlags
         , RepoContext(..), withRepoContext
         )
115

116
import Data.Char
117
         ( isAlphaNum )
118
import Data.List
119
         ( intercalate, deleteFirstsBy )
120
import Data.Maybe
121
         ( maybeToList, fromMaybe )
122 123
import GHC.Generics (Generic)
import Distribution.Compat.Binary (Binary)
124 125 126 127 128 129
import Control.Monad
         ( liftM )
import System.FilePath
         ( (</>) )
import Network.URI
         ( parseAbsoluteURI, uriToString )
130

131 132
globalCommand :: [Command action] -> CommandUI GlobalFlags
globalCommand commands = CommandUI {
133
    commandName         = "",
134 135
    commandSynopsis     =
         "Command line interface to the Haskell Cabal infrastructure.",
136 137 138 139
    commandUsage        = \pname ->
         "See http://www.haskell.org/cabal/ for more information.\n"
      ++ "\n"
      ++ "Usage: " ++ pname ++ " [GLOBAL FLAGS] [COMMAND [FLAGS]]\n",
140
    commandDescription  = Just $ \pname ->
141 142 143
      let
        commands' = commands ++ [commandAddAction helpCommandUI undefined]
        cmdDescs = getNormalCommandDescriptions commands'
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 169 170 171
        -- if new commands are added, we want them to appear even if they
        -- are not included in the custom listing below. Thus, we calculate
        -- the `otherCmds` list and append it under the `other` category.
        -- Alternatively, a new testcase could be added that ensures that
        -- the set of commands listed here is equal to the set of commands
        -- that are actually available.
        otherCmds = deleteFirstsBy (==) (map fst cmdDescs)
          [ "help"
          , "update"
          , "install"
          , "fetch"
          , "list"
          , "info"
          , "user-config"
          , "get"
          , "init"
          , "configure"
          , "build"
          , "clean"
          , "run"
          , "repl"
          , "test"
          , "bench"
          , "check"
          , "sdist"
          , "upload"
          , "report"
          , "freeze"
172
          , "gen-bounds"
173 174 175 176 177 178 179
          , "haddock"
          , "hscolour"
          , "copy"
          , "register"
          , "sandbox"
          , "exec"
          ]
180 181
        maxlen    = maximum $ [length name | (name, _) <- cmdDescs]
        align str = str ++ replicate (maxlen - length str) ' '
182 183 184 185 186 187 188 189 190
        startGroup n = " ["++n++"]"
        par          = ""
        addCmd n     = case lookup n cmdDescs of
                         Nothing -> ""
                         Just d -> "  " ++ align n ++ "    " ++ d
        addCmdCustom n d = case lookup n cmdDescs of -- make sure that the
                                                  -- command still exists.
                         Nothing -> ""
                         Just _ -> "  " ++ align n ++ "    " ++ d
191 192
      in
         "Commands:\n"
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
      ++ unlines (
        [ startGroup "global"
        , addCmd "update"
        , addCmd "install"
        , par
        , addCmd "help"
        , addCmd "info"
        , addCmd "list"
        , addCmd "fetch"
        , addCmd "user-config"
        , par
        , startGroup "package"
        , addCmd "get"
        , addCmd "init"
        , par
        , addCmd "configure"
        , addCmd "build"
        , addCmd "clean"
        , par
        , addCmd "run"
        , addCmd "repl"
        , addCmd "test"
        , addCmd "bench"
        , par
        , addCmd "check"
        , addCmd "sdist"
        , addCmd "upload"
        , addCmd "report"
        , par
        , addCmd "freeze"
223
        , addCmd "gen-bounds"
224 225 226 227 228 229
        , addCmd "haddock"
        , addCmd "hscolour"
        , addCmd "copy"
        , addCmd "register"
        , par
        , startGroup "sandbox"
230
        , addCmd "sandbox"
231 232 233 234 235
        , addCmd "exec"
        , addCmdCustom "repl" "Open interpreter with access to sandbox packages."
        ] ++ if null otherCmds then [] else par
                                           :startGroup "other"
                                           :[addCmd n | n <- otherCmds])
236 237
      ++ "\n"
      ++ "For more information about a command use:\n"
238 239
      ++ "   " ++ pname ++ " COMMAND --help\n"
      ++ "or " ++ pname ++ " help COMMAND\n"
240
      ++ "\n"
241
      ++ "To install Cabal packages from hackage use:\n"
242 243
      ++ "  " ++ pname ++ " install foo [--dry-run]\n"
      ++ "\n"
244 245
      ++ "Occasionally you need to update the list of available packages:\n"
      ++ "  " ++ pname ++ " update\n",
246
    commandNotes = Nothing,
247
    commandDefaultFlags = mempty,
248 249 250 251 252 253 254 255 256 257 258
    commandOptions = args
  }
  where
    args :: ShowOrParseArgs -> [OptionField GlobalFlags]
    args ShowArgs  = argsShown
    args ParseArgs = argsShown ++ argsNotShown

    -- arguments we want to show in the help
    argsShown :: [OptionField GlobalFlags]
    argsShown = [
       option ['V'] ["version"]
259 260 261 262 263 264 265 266 267 268 269 270 271 272
         "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")

273
      ,option [] ["sandbox-config-file"]
274
         "Set an alternate location for the sandbox config file (default: './cabal.sandbox.config')"
275
         globalSandboxConfigFile (\v flags -> flags { globalSandboxConfigFile = v })
276 277
         (reqArgFlag "FILE")

U-CIQDEV\gbazerman's avatar
U-CIQDEV\gbazerman committed
278 279
      ,option [] ["default-user-config"]
         "Set a location for a cabal.config file for projects without their own cabal.config freeze file."
280
         globalConstraintsFile (\v flags -> flags {globalConstraintsFile = v})
U-CIQDEV\gbazerman's avatar
U-CIQDEV\gbazerman committed
281 282
         (reqArgFlag "FILE")

283
      ,option [] ["require-sandbox"]
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
284
         "requiring the presence of a sandbox for sandbox-aware commands"
285 286 287
         globalRequireSandbox (\v flags -> flags { globalRequireSandbox = v })
         (boolOpt' ([], ["require-sandbox"]) ([], ["no-require-sandbox"]))

288 289 290 291 292
      ,option [] ["ignore-sandbox"]
         "Ignore any existing sandbox"
         globalIgnoreSandbox (\v flags -> flags { globalIgnoreSandbox = v })
         trueArg

293
      ,option [] ["ignore-expiry"]
Edsko de Vries's avatar
Edsko de Vries committed
294
         "Ignore expiry dates on signed metadata (use only in exceptional circumstances)"
295 296 297
         globalIgnoreExpiry (\v flags -> flags { globalIgnoreExpiry = v })
         trueArg

298
      ,option [] ["http-transport"]
299
         "Set a transport for http(s) requests. Accepts 'curl', 'wget', 'powershell', and 'plain-http'. (default: 'curl')"
300
         globalHttpTransport (\v flags -> flags { globalHttpTransport = v })
301
         (reqArgFlag "HttpTransport")
302
      ]
303

304 305 306 307
    -- arguments we don't want shown in the help
    argsNotShown :: [OptionField GlobalFlags]
    argsNotShown = [
       option [] ["remote-repo"]
308 309
         "The name and url for a remote repository"
         globalRemoteRepos (\v flags -> flags { globalRemoteRepos = v })
310
         (reqArg' "NAME:URL" (toNubList . maybeToList . readRepo) (map showRepo . fromNubList))
311 312 313 314 315 316 317 318 319

      ,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 })
320
         (reqArg' "DIR" (\x -> toNubList [x]) fromNubList)
321

322 323 324 325 326
      ,option [] ["logs-dir"]
         "The location to put log files"
         globalLogsDir (\v flags -> flags { globalLogsDir = v })
         (reqArgFlag "DIR")

327 328 329 330
      ,option [] ["world-file"]
         "The location of the world file"
         globalWorldFile (\v flags -> flags { globalWorldFile = v })
         (reqArgFlag "FILE")
331 332 333 334 335
      ]

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

337
configureCommand :: CommandUI ConfigFlags
338 339
configureCommand = c
  { commandDefaultFlags = mempty
340 341 342
  , commandNotes = Just $ \pname -> (case commandNotes c of
         Nothing -> ""
         Just n  -> n pname ++ "\n")
343 344 345 346 347 348
       ++ "Examples:\n"
       ++ "  " ++ pname ++ " configure\n"
       ++ "    Configure with defaults;\n"
       ++ "  " ++ pname ++ " configure --enable-tests -fcustomflag\n"
       ++ "    Configure building package including tests,\n"
       ++ "    with some package-specific flag.\n"
Duncan Coutts's avatar
Duncan Coutts committed
349
  }
350
 where
351
  c = Cabal.configureCommand defaultProgramDb
Duncan Coutts's avatar
Duncan Coutts committed
352

353 354 355
configureOptions ::  ShowOrParseArgs -> [OptionField ConfigFlags]
configureOptions = commandOptions configureCommand

356 357 358 359 360 361 362 363
-- | Given some 'ConfigFlags' for the version of Cabal that
-- cabal-install was built with, and a target older 'Version' of
-- Cabal that we want to pass these flags to, convert the
-- flags into a form that will be accepted by the older
-- Setup script.  Generally speaking, this just means filtering
-- out flags that the old Cabal library doesn't understand, but
-- in some cases it may also mean "emulating" a feature using
-- some more legacy flags.
364
filterConfigureFlags :: ConfigFlags -> Version -> ConfigFlags
365
filterConfigureFlags flags cabalLibVersion
366 367
  -- NB: we expect the latest version to be the most common case,
  -- so test it first.
368
  | cabalLibVersion >= Version [1,23,0] [] = flags_latest
369 370 371 372 373
  -- The naming convention is that flags_version gives flags with
  -- all flags *introduced* in version eliminated.
  -- It is NOT the latest version of Cabal library that
  -- these flags work for; version of introduction is a more
  -- natural metric.
374 375
  | cabalLibVersion <  Version [1,3,10] [] = flags_1_3_10
  | cabalLibVersion <  Version [1,10,0] [] = flags_1_10_0
376
  | cabalLibVersion <  Version [1,12,0] [] = flags_1_12_0
377
  | cabalLibVersion <  Version [1,14,0] [] = flags_1_14_0
378
  | cabalLibVersion <  Version [1,18,0] [] = flags_1_18_0
379 380 381 382 383
  | cabalLibVersion <  Version [1,19,1] [] = flags_1_19_1
  | cabalLibVersion <  Version [1,19,2] [] = flags_1_19_2
  | cabalLibVersion <  Version [1,21,1] [] = flags_1_21_1
  | cabalLibVersion <  Version [1,22,0] [] = flags_1_22_0
  | cabalLibVersion <  Version [1,23,0] [] = flags_1_23_0
384
  | otherwise = flags_latest
385
  where
386 387 388
    flags_latest = flags        {
      -- Cabal >= 1.19.1 uses '--dependency' and does not need '--constraint'.
      configConstraints = [],
389
      -- Passing '--allow-{older,newer}' to Setup.hs is unnecessary, we use
390
      -- '--exact-configuration' instead.
391
      configAllowOlder  = Just (Cabal.AllowOlder Cabal.RelaxDepsNone),
392
      configAllowNewer  = Just (Cabal.AllowNewer Cabal.RelaxDepsNone)
393
      }
394

395
    -- Cabal < 1.23 doesn't know about '--profiling-detail'.
396 397 398
    -- Cabal < 1.23 has a hacked up version of 'enable-profiling'
    -- which we shouldn't use.
    (tryLibProfiling, tryExeProfiling) = computeEffectiveProfiling flags
399
    flags_1_23_0 = flags_latest { configProfDetail    = NoFlag
400
                                , configProfLibDetail = NoFlag
401 402 403 404 405
                                , configIPID          = NoFlag
                                , configProf = mempty
                                , configProfExe = Flag tryExeProfiling
                                , configProfLib = Flag tryLibProfiling
                                }
406

407
    -- Cabal < 1.22 doesn't know about '--disable-debug-info'.
408
    flags_1_22_0 = flags_1_23_0 { configDebugInfo = NoFlag }
409

410
    -- Cabal < 1.21.1 doesn't know about 'disable-relocatable'
411
    -- Cabal < 1.21.1 doesn't know about 'enable-profiling'
412
    -- (but we already dealt with it in flags_1_23_0)
413 414
    flags_1_21_1 =
      flags_1_22_0 { configRelocatable = NoFlag
415 416
                   , configCoverage = NoFlag
                   , configLibCoverage = configCoverage flags
417
                   }
418 419
    -- Cabal < 1.19.2 doesn't know about '--exact-configuration' and
    -- '--enable-library-stripping'.
420
    flags_1_19_2 = flags_1_21_1 { configExactConfiguration = NoFlag
421
                                , configStripLibs = NoFlag }
422
    -- Cabal < 1.19.1 uses '--constraint' instead of '--dependency'.
423
    flags_1_19_1 = flags_1_19_2 { configDependencies = []
424
                                , configConstraints  = configConstraints flags }
425
    -- Cabal < 1.18.0 doesn't know about --extra-prog-path and --sysconfdir.
426
    flags_1_18_0 = flags_1_19_1 { configProgramPathExtra = toNubList []
427 428
                                , configInstallDirs = configInstallDirs_1_18_0}
    configInstallDirs_1_18_0 = (configInstallDirs flags) { sysconfdir = NoFlag }
429
    -- Cabal < 1.14.0 doesn't know about '--disable-benchmarks'.
430
    flags_1_14_0 = flags_1_18_0 { configBenchmarks  = NoFlag }
431 432 433 434
    -- Cabal < 1.12.0 doesn't know about '--enable/disable-executable-dynamic'
    -- and '--enable/disable-library-coverage'.
    flags_1_12_0 = flags_1_14_0 { configLibCoverage = NoFlag
                                , configDynExe      = NoFlag }
435
    -- Cabal < 1.10.0 doesn't know about '--disable-tests'.
436
    flags_1_10_0 = flags_1_12_0 { configTests       = NoFlag }
437
    -- Cabal < 1.3.10 does not grok the '--constraints' flag.
438
    flags_1_3_10 = flags_1_10_0 { configConstraints = [] }
439

440 441
-- | Get the package database settings from 'ConfigFlags', accounting for
-- @--package-db@ and @--user@ flags.
442 443 444 445 446 447
configPackageDB' :: ConfigFlags -> PackageDBStack
configPackageDB' cfg =
    interpretPackageDbFlags userInstall (configPackageDBs cfg)
  where
    userInstall = Cabal.fromFlagOrDefault True (configUserInstall cfg)

448
-- | Configure the compiler, but reduce verbosity during this step.
449 450 451 452 453 454
configCompilerAux' :: ConfigFlags -> IO (Compiler, Platform, ProgramDb)
configCompilerAux' configFlags =
  configCompilerAuxEx configFlags
    --FIXME: make configCompilerAux use a sensible verbosity
    { configVerbosity = fmap lessVerbose (configVerbosity configFlags) }

455 456 457 458 459 460 461 462
-- ------------------------------------------------------------
-- * Config extra flags
-- ------------------------------------------------------------

-- | cabal configure takes some extra flags beyond runghc Setup configure
--
data ConfigExFlags = ConfigExFlags {
    configCabalVersion :: Flag Version,
463
    configExConstraints:: [(UserConstraint, ConstraintSource)],
464
    configPreferences  :: [Dependency],
465
    configSolver       :: Flag PreSolver
466
  }
467
  deriving (Eq, Generic)
468 469

defaultConfigExFlags :: ConfigExFlags
470
defaultConfigExFlags = mempty { configSolver     = Flag defaultSolver }
471 472 473 474 475

configureExCommand :: CommandUI (ConfigFlags, ConfigExFlags)
configureExCommand = configureCommand {
    commandDefaultFlags = (mempty, defaultConfigExFlags),
    commandOptions      = \showOrParseArgs ->
476
         liftOptions fst setFst
477
         (filter ((`notElem` ["constraint", "dependency", "exact-configuration"])
478
                  . optionName) $ configureOptions  showOrParseArgs)
479 480
      ++ liftOptions snd setSnd
         (configureExOptions showOrParseArgs ConstraintSourceCommandlineFlag)
481 482 483 484 485
  }
  where
    setFst a (_,b) = (a,b)
    setSnd b (a,_) = (a,b)

486 487 488 489
configureExOptions :: ShowOrParseArgs
                   -> ConstraintSource
                   -> [OptionField ConfigExFlags]
configureExOptions _showOrParseArgs src =
490 491 492 493 494 495 496
  [ 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))
497 498 499 500
  , option [] ["constraint"]
      "Specify constraints on a package (version, installed/source, flags)"
      configExConstraints (\v flags -> flags { configExConstraints = v })
      (reqArg "CONSTRAINT"
501 502
              ((\x -> [(x, src)]) `fmap` ReadE readUserConstraint)
              (map $ display . fst))
503 504 505 506

  , option [] ["preference"]
      "Specify preferences (soft constraints) on the version of a package"
      configPreferences (\v flags -> flags { configPreferences = v })
507 508 509 510
      (reqArg "CONSTRAINT"
              (readP_to_E (const "dependency expected")
                          (fmap (\x -> [x]) parse))
              (map display))
511 512

  , optionSolver configSolver (\v flags -> flags { configSolver = v })
513

514 515 516
  ]

instance Monoid ConfigExFlags where
517
  mempty = gmempty
518 519 520
  mappend = (<>)

instance Semigroup ConfigExFlags where
521
  (<>) = gmappend
522

ttuegel's avatar
ttuegel committed
523 524 525 526 527 528
reconfigureCommand :: CommandUI (ConfigFlags, ConfigExFlags)
reconfigureCommand
  = configureExCommand
    { commandName         = "reconfigure"
    , commandSynopsis     = "Reconfigure the package if necessary."
    , commandDescription  = Just $ \pname -> wrapText $
529 530
         "Run `configure` with the most recently used flags, or append FLAGS "
         ++ "to the most recently used configuration. "
ttuegel's avatar
ttuegel committed
531
         ++ "Accepts the same flags as `" ++ pname ++ " configure'. "
532 533 534 535 536 537 538 539 540
         ++ "If the package has never been configured, the default flags are "
         ++ "used."
    , commandNotes        = Just $ \pname ->
        "Examples:\n"
        ++ "  " ++ pname ++ " reconfigure\n"
        ++ "    Configure with the most recently used flags.\n"
        ++ "  " ++ pname ++ " reconfigure -w PATH\n"
        ++ "    Reconfigure with the most recently used flags,\n"
        ++ "    but use the compiler at PATH.\n\n"
ttuegel's avatar
ttuegel committed
541 542 543 544
    , commandUsage        = usageAlternatives "reconfigure" [ "[FLAGS]" ]
    , commandDefaultFlags = mempty
    }

ttuegel's avatar
ttuegel committed
545 546 547 548
-- ------------------------------------------------------------
-- * Build flags
-- ------------------------------------------------------------

549 550 551 552 553 554
data SkipAddSourceDepsCheck =
  SkipAddSourceDepsCheck | DontSkipAddSourceDepsCheck
  deriving Eq

data BuildExFlags = BuildExFlags {
  buildOnly     :: Flag SkipAddSourceDepsCheck
555
} deriving Generic
556 557 558

buildExOptions :: ShowOrParseArgs -> [OptionField BuildExFlags]
buildExOptions _showOrParseArgs =
559
  option [] ["only"]
560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578
  "Don't reinstall add-source dependencies (sandbox-only)"
  buildOnly (\v flags -> flags { buildOnly = v })
  (noArg (Flag SkipAddSourceDepsCheck))

  : []

buildCommand :: CommandUI (BuildFlags, BuildExFlags)
buildCommand = parent {
    commandDefaultFlags = (commandDefaultFlags parent, mempty),
    commandOptions      =
      \showOrParseArgs -> liftOptions fst setFst
                          (commandOptions parent showOrParseArgs)
                          ++
                          liftOptions snd setSnd (buildExOptions showOrParseArgs)
  }
  where
    setFst a (_,b) = (a,b)
    setSnd b (a,_) = (a,b)

579
    parent = Cabal.buildCommand defaultProgramDb
580 581

instance Monoid BuildExFlags where
582
  mempty = gmempty
583 584 585
  mappend = (<>)

instance Semigroup BuildExFlags where
586
  (<>) = gmappend
587 588

-- ------------------------------------------------------------
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604
-- * Repl command
-- ------------------------------------------------------------

replCommand :: CommandUI (ReplFlags, BuildExFlags)
replCommand = parent {
    commandDefaultFlags = (commandDefaultFlags parent, mempty),
    commandOptions      =
      \showOrParseArgs -> liftOptions fst setFst
                          (commandOptions parent showOrParseArgs)
                          ++
                          liftOptions snd setSnd (buildExOptions showOrParseArgs)
  }
  where
    setFst a (_,b) = (a,b)
    setSnd b (a,_) = (a,b)

605
    parent = Cabal.replCommand defaultProgramDb
606

607 608 609 610
-- ------------------------------------------------------------
-- * Test command
-- ------------------------------------------------------------

611
testCommand :: CommandUI (TestFlags, BuildFlags, BuildExFlags)
612
testCommand = parent {
613 614
  commandDefaultFlags = (commandDefaultFlags parent,
                         Cabal.defaultBuildFlags, mempty),
615
  commandOptions      =
616
    \showOrParseArgs -> liftOptions get1 set1
617 618
                        (commandOptions parent showOrParseArgs)
                        ++
619
                        liftOptions get2 set2
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
620
                        (Cabal.buildOptions progDb showOrParseArgs)
621 622
                        ++
                        liftOptions get3 set3 (buildExOptions showOrParseArgs)
623 624
  }
  where
625 626 627
    get1 (a,_,_) = a; set1 a (_,b,c) = (a,b,c)
    get2 (_,b,_) = b; set2 b (a,_,c) = (a,b,c)
    get3 (_,_,c) = c; set3 c (a,b,_) = (a,b,c)
628

Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
629 630
    parent = Cabal.testCommand
    progDb = defaultProgramDb
631 632 633 634 635

-- ------------------------------------------------------------
-- * Bench command
-- ------------------------------------------------------------

636
benchmarkCommand :: CommandUI (BenchmarkFlags, BuildFlags, BuildExFlags)
637
benchmarkCommand = parent {
638 639
  commandDefaultFlags = (commandDefaultFlags parent,
                         Cabal.defaultBuildFlags, mempty),
640
  commandOptions      =
641
    \showOrParseArgs -> liftOptions get1 set1
642 643
                        (commandOptions parent showOrParseArgs)
                        ++
644
                        liftOptions get2 set2
Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
645
                        (Cabal.buildOptions progDb showOrParseArgs)
646 647
                        ++
                        liftOptions get3 set3 (buildExOptions showOrParseArgs)
ttuegel's avatar
ttuegel committed
648
  }
649
  where
650 651 652
    get1 (a,_,_) = a; set1 a (_,b,c) = (a,b,c)
    get2 (_,b,_) = b; set2 b (a,_,c) = (a,b,c)
    get3 (_,_,c) = c; set3 c (a,b,_) = (a,b,c)
653

Mikhail Glushenkov's avatar
Mikhail Glushenkov committed
654 655
    parent = Cabal.benchmarkCommand
    progDb = defaultProgramDb
ttuegel's avatar
ttuegel committed
656

657
-- ------------------------------------------------------------
658
-- * Fetch command
659
-- ------------------------------------------------------------
660

661 662 663 664
data FetchFlags = FetchFlags {
--    fetchOutput    :: Flag FilePath,
      fetchDeps      :: Flag Bool,
      fetchDryRun    :: Flag Bool,
665
      fetchSolver           :: Flag PreSolver,
666
      fetchMaxBackjumps     :: Flag Int,
667
      fetchReorderGoals     :: Flag ReorderGoals,
668
      fetchCountConflicts   :: Flag CountConflicts,
669 670 671
      fetchIndependentGoals :: Flag IndependentGoals,
      fetchShadowPkgs       :: Flag ShadowPkgs,
      fetchStrongFlags      :: Flag StrongFlags,
672 673 674 675 676 677 678 679
      fetchVerbosity :: Flag Verbosity
    }

defaultFetchFlags :: FetchFlags
defaultFetchFlags = FetchFlags {
--  fetchOutput    = mempty,
    fetchDeps      = toFlag True,
    fetchDryRun    = toFlag False,
680 681
    fetchSolver           = Flag defaultSolver,
    fetchMaxBackjumps     = Flag defaultMaxBackjumps,
682
    fetchReorderGoals     = Flag (ReorderGoals False),
683
    fetchCountConflicts   = Flag (CountConflicts True),
684 685 686
    fetchIndependentGoals = Flag (IndependentGoals False),
    fetchShadowPkgs       = Flag (ShadowPkgs False),
    fetchStrongFlags      = Flag (StrongFlags False),
687 688 689 690
    fetchVerbosity = toFlag normal
   }

fetchCommand :: CommandUI FetchFlags
Duncan Coutts's avatar
Duncan Coutts committed
691 692
fetchCommand = CommandUI {
    commandName         = "fetch",
693
    commandSynopsis     = "Downloads packages for later installation.",
694 695 696 697 698
    commandUsage        = usageAlternatives "fetch" [ "[FLAGS] PACKAGES"
                                                    ],
    commandDescription  = Just $ \_ ->
          "Note that it currently is not possible to fetch the dependencies for a\n"
       ++ "package in the current directory.\n",
699
    commandNotes        = Nothing,
700
    commandDefaultFlags = defaultFetchFlags,
701
    commandOptions      = \ showOrParseArgs -> [
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
         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
723 724 725 726

       ] ++

       optionSolver      fetchSolver           (\v flags -> flags { fetchSolver           = v }) :
727 728
       optionSolverFlags showOrParseArgs
                         fetchMaxBackjumps     (\v flags -> flags { fetchMaxBackjumps     = v })
729
                         fetchReorderGoals     (\v flags -> flags { fetchReorderGoals     = v })
730
                         fetchCountConflicts   (\v flags -> flags { fetchCountConflicts   = v })
731
                         fetchIndependentGoals (\v flags -> flags { fetchIndependentGoals = v })
732
                         fetchShadowPkgs       (\v flags -> flags { fetchShadowPkgs       = v })
Andres Löh's avatar
Andres Löh committed
733
                         fetchStrongFlags      (\v flags -> flags { fetchStrongFlags      = v })
734

Duncan Coutts's avatar
Duncan Coutts committed
735 736
  }

737 738 739 740 741 742
-- ------------------------------------------------------------
-- * Freeze command
-- ------------------------------------------------------------

data FreezeFlags = FreezeFlags {
      freezeDryRun           :: Flag Bool,
743 744
      freezeTests            :: Flag Bool,
      freezeBenchmarks       :: Flag Bool,
745 746
      freezeSolver           :: Flag PreSolver,
      freezeMaxBackjumps     :: Flag Int,
747
      freezeReorderGoals     :: Flag ReorderGoals,
748
      freezeCountConflicts   :: Flag CountConflicts,
749 750 751
      freezeIndependentGoals :: Flag IndependentGoals,
      freezeShadowPkgs       :: Flag ShadowPkgs,
      freezeStrongFlags      :: Flag StrongFlags,
752 753 754 755 756 757
      freezeVerbosity        :: Flag Verbosity
    }

defaultFreezeFlags :: FreezeFlags
defaultFreezeFlags = FreezeFlags {
    freezeDryRun           = toFlag False,
758 759
    freezeTests            = toFlag False,
    freezeBenchmarks       = toFlag False,
760 761
    freezeSolver           = Flag defaultSolver,
    freezeMaxBackjumps     = Flag defaultMaxBackjumps,
762
    freezeReorderGoals     = Flag (ReorderGoals False),
763
    freezeCountConflicts   = Flag (CountConflicts True),
764 765 766
    freezeIndependentGoals = Flag (IndependentGoals False),
    freezeShadowPkgs       = Flag (ShadowPkgs False),
    freezeStrongFlags      = Flag (StrongFlags False),
767 768 769 770 771 772 773
    freezeVerbosity        = toFlag normal
   }

freezeCommand :: CommandUI FreezeFlags
freezeCommand = CommandUI {
    commandName         = "freeze",
    commandSynopsis     = "Freeze dependencies.",
774 775 776 777 778 779 780 781
    commandDescription  = Just $ \_ -> wrapText $
         "Calculates a valid set of dependencies and their exact versions. "
      ++ "If successful, saves the result to the file `cabal.config`.\n"
      ++ "\n"
      ++ "The package versions specified in `cabal.config` will be used for "
      ++ "any future installs.\n"
      ++ "\n"
      ++ "An existing `cabal.config` is ignored and overwritten.\n",
782
    commandNotes        = Nothing,
783
    commandUsage        = usageFlags "freeze",
784 785 786 787 788 789 790 791 792
    commandDefaultFlags = defaultFreezeFlags,
    commandOptions      = \ showOrParseArgs -> [
         optionVerbosity freezeVerbosity (\v flags -> flags { freezeVerbosity = v })

       , option [] ["dry-run"]
           "Do not freeze anything, only print what would be frozen"
           freezeDryRun (\v flags -> flags { freezeDryRun = v })
           trueArg

793 794 795 796 797 798 799 800 801 802
       , option [] ["tests"]
           "freezing of the dependencies of any tests suites in the package description file."
           freezeTests (\v flags -> flags { freezeTests = v })
           (boolOpt [] [])

       , option [] ["benchmarks"]
           "freezing of the dependencies of any benchmarks suites in the package description file."
           freezeBenchmarks (\v flags -> flags { freezeBenchmarks = v })
           (boolOpt [] [])

803 804 805 806 807 808
       ] ++

       optionSolver      freezeSolver           (\v flags -> flags { freezeSolver           = v }) :
       optionSolverFlags showOrParseArgs
                         freezeMaxBackjumps     (\v flags -> flags { freezeMaxBackjumps     = v })
                         freezeReorderGoals     (\v flags -> flags { freezeReorderGoals     = v })
809
                         freezeCountConflicts   (\v flags -> flags { freezeCountConflicts   = v })
810 811
                         freezeIndependentGoals (\v flags -> flags { freezeIndependentGoals = v })
                         freezeShadowPkgs       (\v flags -> flags { freezeShadowPkgs       = v })
Andres Löh's avatar
Andres Löh committed
812
                         freezeStrongFlags      (\v flags -> flags { freezeStrongFlags      = v })
813 814 815

  }

816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
genBoundsCommand :: CommandUI FreezeFlags
genBoundsCommand = CommandUI {
    commandName         = "gen-bounds",
    commandSynopsis     = "Generate dependency bounds.",
    commandDescription  = Just $ \_ -> wrapText $
         "Generates bounds for all dependencies that do not currently have them. "
      ++ "Generated bounds are printed to stdout.  You can then paste them into your .cabal file.\n"
      ++ "\n",
    commandNotes        = Nothing,
    commandUsage        = usageFlags "gen-bounds",
    commandDefaultFlags = defaultFreezeFlags,
    commandOptions      = \ _ -> [
     optionVerbosity freezeVerbosity (\v flags -> flags { freezeVerbosity = v })
     ]
  }

832 833 834 835
-- ------------------------------------------------------------
-- * Other commands
-- ------------------------------------------------------------

836
updateCommand  :: CommandUI (Flag Verbosity)
Duncan Coutts's avatar
Duncan Coutts committed
837 838
updateCommand = CommandUI {
    commandName         = "update",
839
    commandSynopsis     = "Updates list of known packages.",
840 841 842
    commandDescription  = Just $ \_ ->
      "For all known remote repositories, download the package list.\n",
    commandNotes        = Just $ \_ ->
843 844 845
      relevantConfigValuesText ["remote-repo"
                               ,"remote-repo-cache"
                               ,"local-repo"],
refold's avatar
refold committed
846
    commandUsage        = usageFlags "update",
847
    commandDefaultFlags = toFlag normal,
848
    commandOptions      = \_ -> [optionVerbosity id const]
Duncan Coutts's avatar
Duncan Coutts committed
849 850
  }

851
upgradeCommand  :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
852
upgradeCommand = configureCommand {
ijones's avatar
ijones committed
853
    commandName         = "upgrade",
854
    commandSynopsis     = "(command disabled, use install instead)",
ijones's avatar
ijones committed
855
    commandDescription  = Nothing,
refold's avatar
refold committed
856
    commandUsage        = usageFlagsOrPackages "upgrade",
857
    commandDefaultFlags = (mempty, mempty, mempty, mempty),
858
    commandOptions      = commandOptions installCommand
ijones's avatar
ijones committed
859 860
  }

Duncan Coutts's avatar
Duncan Coutts committed
861 862 863 864 865 866 867 868 869 870 871
{-
cleanCommand  :: CommandUI ()
cleanCommand = makeCommand name shortDesc longDesc emptyFlags options
  where
    name       = "clean"
    shortDesc  = "Removes downloaded files"
    longDesc   = Nothing
    emptyFlags = ()
    options _  = []
-}

872 873 874
checkCommand  :: CommandUI (Flag Verbosity)
checkCommand = CommandUI {
    commandName         = "check",
875
    commandSynopsis     = "Check the package for common mistakes.",
876 877 878 879 880 881
    commandDescription  = Just $ \_ -> wrapText $
         "Expects a .cabal package file in the current directory.\n"
      ++ "\n"
      ++ "The checks correspond to the requirements to packages on Hackage. "
      ++ "If no errors and warnings are reported, Hackage will accept this "
      ++ "package.\n",
882
    commandNotes        = Nothing,
883
    commandUsage        = \pname -> "Usage: " ++ pname ++ " check\n",
884
    commandDefaultFlags = toFlag normal,
885
    commandOptions      = \_ -> []
886 887
  }

888 889 890 891 892
formatCommand  :: CommandUI (Flag Verbosity)
formatCommand = CommandUI {
    commandName         = "format",
    commandSynopsis     = "Reformat the .cabal file using the standard style.",
    commandDescription  = Nothing,
893
    commandNotes        = Nothing,
894
    commandUsage        = usageAlternatives "format" ["[FILE]"],
895 896 <