Setup.hs 85.3 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
22
    , configureExCommand, ConfigExFlags(..), defaultConfigExFlags
                        , configureExOptions
23
    , buildCommand, BuildFlags(..), BuildExFlags(..), SkipAddSourceDepsCheck(..)
24
    , replCommand, testCommand, benchmarkCommand
25
    , installCommand, InstallFlags(..), installOptions, defaultInstallFlags
26
    , defaultSolver, defaultMaxBackjumps
27
    , listCommand, ListFlags(..)
Duncan Coutts's avatar
Duncan Coutts committed
28
    , updateCommand
ijones's avatar
ijones committed
29
    , upgradeCommand
30
    , uninstallCommand
31
    , infoCommand, InfoFlags(..)
32
    , fetchCommand, FetchFlags(..)
33
    , freezeCommand, FreezeFlags(..)
34
    , genBoundsCommand
35
    , getCommand, unpackCommand, GetFlags(..)
36
    , checkCommand
37
    , formatCommand
38
    , uploadCommand, UploadFlags(..)
39
    , reportCommand, ReportFlags(..)
refold's avatar
refold committed
40
    , runCommand
41
    , initCommand, IT.InitFlags(..)
42
    , sdistCommand, SDistFlags(..), SDistExFlags(..), ArchiveFormat(..)
43
    , win32SelfUpgradeCommand, Win32SelfUpgradeFlags(..)
44
    , actAsSetupCommand, ActAsSetupFlags(..)
refold's avatar
refold committed
45
    , sandboxCommand, defaultSandboxLocation, SandboxFlags(..)
46
    , execCommand, ExecFlags(..)
47
    , userConfigCommand, UserConfigFlags(..)
Maciek Makowski's avatar
Maciek Makowski committed
48
    , manpageCommand
Duncan Coutts's avatar
Duncan Coutts committed
49
50

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

57
import Distribution.Client.Types
Edsko de Vries's avatar
Edsko de Vries committed
58
         ( Username(..), Password(..), RemoteRepo(..) )
59
60
import Distribution.Client.BuildReports.Types
         ( ReportLevel(..) )
61
import Distribution.Client.Dependency.Types
62
63
64
         ( PreSolver(..), ConstraintSource(..), ReorderGoals(..)
         , IndependentGoals(..), AvoidReinstalls(..), ShadowPkgs(..)
         , StrongFlags(..) )
65
66
import qualified Distribution.Client.Init.Types as IT
         ( InitFlags(..), PackageType(..) )
67
68
import Distribution.Client.Targets
         ( UserConstraint, readUserConstraint )
69
70
import Distribution.Utils.NubList
         ( NubList, toNubList, fromNubList)
71

72

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

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

127
128
globalCommand :: [Command action] -> CommandUI GlobalFlags
globalCommand commands = CommandUI {
129
    commandName         = "",
130
131
    commandSynopsis     =
         "Command line interface to the Haskell Cabal infrastructure.",
132
133
134
135
    commandUsage        = \pname ->
         "See http://www.haskell.org/cabal/ for more information.\n"
      ++ "\n"
      ++ "Usage: " ++ pname ++ " [GLOBAL FLAGS] [COMMAND [FLAGS]]\n",
136
    commandDescription  = Just $ \pname ->
137
138
139
      let
        commands' = commands ++ [commandAddAction helpCommandUI undefined]
        cmdDescs = getNormalCommandDescriptions commands'
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
        -- 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"
168
          , "gen-bounds"
169
170
171
172
173
174
175
          , "haddock"
          , "hscolour"
          , "copy"
          , "register"
          , "sandbox"
          , "exec"
          ]
176
177
        maxlen    = maximum $ [length name | (name, _) <- cmdDescs]
        align str = str ++ replicate (maxlen - length str) ' '
178
179
180
181
182
183
184
185
186
        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
187
188
      in
         "Commands:\n"
189
190
191
192
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
      ++ 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"
219
        , addCmd "gen-bounds"
220
221
222
223
224
225
        , addCmd "haddock"
        , addCmd "hscolour"
        , addCmd "copy"
        , addCmd "register"
        , par
        , startGroup "sandbox"
226
        , addCmd "sandbox"
227
228
229
230
231
        , addCmd "exec"
        , addCmdCustom "repl" "Open interpreter with access to sandbox packages."
        ] ++ if null otherCmds then [] else par
                                           :startGroup "other"
                                           :[addCmd n | n <- otherCmds])
232
233
      ++ "\n"
      ++ "For more information about a command use:\n"
234
235
      ++ "   " ++ pname ++ " COMMAND --help\n"
      ++ "or " ++ pname ++ " help COMMAND\n"
236
      ++ "\n"
237
      ++ "To install Cabal packages from hackage use:\n"
238
239
      ++ "  " ++ pname ++ " install foo [--dry-run]\n"
      ++ "\n"
240
241
      ++ "Occasionally you need to update the list of available packages:\n"
      ++ "  " ++ pname ++ " update\n",
242
    commandNotes = Nothing,
243
    commandDefaultFlags = mempty,
244
245
246
247
248
249
250
251
252
253
254
    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"]
255
256
257
258
259
260
261
262
263
264
265
266
267
268
         "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")

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

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

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

284
285
286
287
288
      ,option [] ["ignore-sandbox"]
         "Ignore any existing sandbox"
         globalIgnoreSandbox (\v flags -> flags { globalIgnoreSandbox = v })
         trueArg

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

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

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

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

318
319
320
321
322
      ,option [] ["logs-dir"]
         "The location to put log files"
         globalLogsDir (\v flags -> flags { globalLogsDir = v })
         (reqArgFlag "DIR")

323
324
325
326
      ,option [] ["world-file"]
         "The location of the world file"
         globalWorldFile (\v flags -> flags { globalWorldFile = v })
         (reqArgFlag "FILE")
327
328
329
330
331
      ]

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

333
configureCommand :: CommandUI ConfigFlags
334
335
configureCommand = c
  { commandDefaultFlags = mempty
336
337
338
  , commandNotes = Just $ \pname -> (case commandNotes c of
         Nothing -> ""
         Just n  -> n pname ++ "\n")
339
340
341
342
343
344
       ++ "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
345
  }
346
347
 where
  c = Cabal.configureCommand defaultProgramConfiguration
Duncan Coutts's avatar
Duncan Coutts committed
348

349
350
351
configureOptions ::  ShowOrParseArgs -> [OptionField ConfigFlags]
configureOptions = commandOptions configureCommand

352
filterConfigureFlags :: ConfigFlags -> Version -> ConfigFlags
353
filterConfigureFlags flags cabalLibVersion
354
  | cabalLibVersion >= Version [1,23,0] [] = flags_latest
355
  -- ^ NB: we expect the latest version to be the most common case.
356
357
  | cabalLibVersion <  Version [1,3,10] [] = flags_1_3_10
  | cabalLibVersion <  Version [1,10,0] [] = flags_1_10_0
358
  | cabalLibVersion <  Version [1,12,0] [] = flags_1_12_0
359
  | cabalLibVersion <  Version [1,14,0] [] = flags_1_14_0
360
  | cabalLibVersion <  Version [1,18,0] [] = flags_1_18_0
361
  | cabalLibVersion <  Version [1,19,1] [] = flags_1_19_0
362
  | cabalLibVersion <  Version [1,19,2] [] = flags_1_19_1
363
  | cabalLibVersion <  Version [1,21,1] [] = flags_1_20_0
364
  | cabalLibVersion <  Version [1,22,0] [] = flags_1_21_0
365
  | cabalLibVersion <  Version [1,23,0] [] = flags_1_22_0
366
  | otherwise = flags_latest
367
  where
368
369
370
371
372
    flags_latest = flags        {
      -- Cabal >= 1.19.1 uses '--dependency' and does not need '--constraint'.
      configConstraints = [],
      -- Passing '--allow-newer' to Setup.hs is unnecessary, we use
      -- '--exact-configuration' instead.
373
      configAllowNewer  = Just Cabal.AllowNewerNone
374
      }
375

376
377
    -- Cabal < 1.23 doesn't know about '--profiling-detail'.
    flags_1_22_0 = flags_latest { configProfDetail    = NoFlag
378
379
                                , configProfLibDetail = NoFlag
                                , configIPID          = NoFlag }
380

381
    -- Cabal < 1.22 doesn't know about '--disable-debug-info'.
382
    flags_1_21_0 = flags_1_22_0 { configDebugInfo = NoFlag }
383

384
    -- Cabal < 1.21.1 doesn't know about 'disable-relocatable'
385
386
    -- Cabal < 1.21.1 doesn't know about 'enable-profiling'
    flags_1_20_0 =
387
      flags_1_21_0 { configRelocatable = NoFlag
388
389
390
391
                   , configProf = NoFlag
                   , configProfExe = configProf flags
                   , configProfLib =
                     mappend (configProf flags) (configProfLib flags)
392
393
                   , configCoverage = NoFlag
                   , configLibCoverage = configCoverage flags
394
                   }
395
396
397
398
    -- Cabal < 1.19.2 doesn't know about '--exact-configuration' and
    -- '--enable-library-stripping'.
    flags_1_19_1 = flags_1_20_0 { configExactConfiguration = NoFlag
                                , configStripLibs = NoFlag }
399
400
401
    -- Cabal < 1.19.1 uses '--constraint' instead of '--dependency'.
    flags_1_19_0 = flags_1_19_1 { configDependencies = []
                                , configConstraints  = configConstraints flags }
402
    -- Cabal < 1.18.0 doesn't know about --extra-prog-path and --sysconfdir.
403
    flags_1_18_0 = flags_1_19_0 { configProgramPathExtra = toNubList []
404
405
                                , configInstallDirs = configInstallDirs_1_18_0}
    configInstallDirs_1_18_0 = (configInstallDirs flags) { sysconfdir = NoFlag }
406
    -- Cabal < 1.14.0 doesn't know about '--disable-benchmarks'.
407
    flags_1_14_0 = flags_1_18_0 { configBenchmarks  = NoFlag }
408
409
410
411
    -- 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 }
412
    -- Cabal < 1.10.0 doesn't know about '--disable-tests'.
413
    flags_1_10_0 = flags_1_12_0 { configTests       = NoFlag }
414
    -- Cabal < 1.3.10 does not grok the '--constraints' flag.
415
    flags_1_3_10 = flags_1_10_0 { configConstraints = [] }
416

417
418
419
420
421
422
423
424
-- ------------------------------------------------------------
-- * Config extra flags
-- ------------------------------------------------------------

-- | cabal configure takes some extra flags beyond runghc Setup configure
--
data ConfigExFlags = ConfigExFlags {
    configCabalVersion :: Flag Version,
425
    configExConstraints:: [(UserConstraint, ConstraintSource)],
426
    configPreferences  :: [Dependency],
427
    configSolver       :: Flag PreSolver
428
  }
429
  deriving (Eq, Generic)
430
431

defaultConfigExFlags :: ConfigExFlags
432
defaultConfigExFlags = mempty { configSolver     = Flag defaultSolver }
433
434
435
436
437

configureExCommand :: CommandUI (ConfigFlags, ConfigExFlags)
configureExCommand = configureCommand {
    commandDefaultFlags = (mempty, defaultConfigExFlags),
    commandOptions      = \showOrParseArgs ->
438
         liftOptions fst setFst
439
         (filter ((`notElem` ["constraint", "dependency", "exact-configuration"])
440
                  . optionName) $ configureOptions  showOrParseArgs)
441
442
      ++ liftOptions snd setSnd
         (configureExOptions showOrParseArgs ConstraintSourceCommandlineFlag)
443
444
445
446
447
  }
  where
    setFst a (_,b) = (a,b)
    setSnd b (a,_) = (a,b)

448
449
450
451
configureExOptions :: ShowOrParseArgs
                   -> ConstraintSource
                   -> [OptionField ConfigExFlags]
configureExOptions _showOrParseArgs src =
452
453
454
455
456
457
458
  [ 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))
459
460
461
462
  , option [] ["constraint"]
      "Specify constraints on a package (version, installed/source, flags)"
      configExConstraints (\v flags -> flags { configExConstraints = v })
      (reqArg "CONSTRAINT"
463
464
              ((\x -> [(x, src)]) `fmap` ReadE readUserConstraint)
              (map $ display . fst))
465
466
467
468

  , option [] ["preference"]
      "Specify preferences (soft constraints) on the version of a package"
      configPreferences (\v flags -> flags { configPreferences = v })
469
470
471
472
      (reqArg "CONSTRAINT"
              (readP_to_E (const "dependency expected")
                          (fmap (\x -> [x]) parse))
              (map display))
473
474

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

476
477
478
  ]

instance Monoid ConfigExFlags where
479
  mempty = gmempty
480
481
482
  mappend = (<>)

instance Semigroup ConfigExFlags where
483
  (<>) = gmappend
484

ttuegel's avatar
ttuegel committed
485
486
487
488
-- ------------------------------------------------------------
-- * Build flags
-- ------------------------------------------------------------

489
490
491
492
493
494
data SkipAddSourceDepsCheck =
  SkipAddSourceDepsCheck | DontSkipAddSourceDepsCheck
  deriving Eq

data BuildExFlags = BuildExFlags {
  buildOnly     :: Flag SkipAddSourceDepsCheck
495
} deriving Generic
496
497
498

buildExOptions :: ShowOrParseArgs -> [OptionField BuildExFlags]
buildExOptions _showOrParseArgs =
499
  option [] ["only"]
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
  "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)

    parent = Cabal.buildCommand defaultProgramConfiguration

instance Monoid BuildExFlags where
522
  mempty = gmempty
523
524
525
  mappend = (<>)

instance Semigroup BuildExFlags where
526
  (<>) = gmappend
527
528

-- ------------------------------------------------------------
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
-- * 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)

    parent = Cabal.replCommand defaultProgramConfiguration

547
548
549
550
-- ------------------------------------------------------------
-- * Test command
-- ------------------------------------------------------------

551
testCommand :: CommandUI (TestFlags, BuildFlags, BuildExFlags)
552
testCommand = parent {
553
554
  commandDefaultFlags = (commandDefaultFlags parent,
                         Cabal.defaultBuildFlags, mempty),
555
  commandOptions      =
556
    \showOrParseArgs -> liftOptions get1 set1
557
558
                        (commandOptions parent showOrParseArgs)
                        ++
559
560
561
562
                        liftOptions get2 set2
                        (Cabal.buildOptions progConf showOrParseArgs)
                        ++
                        liftOptions get3 set3 (buildExOptions showOrParseArgs)
563
564
  }
  where
565
566
567
    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)
568

569
570
    parent   = Cabal.testCommand
    progConf = defaultProgramConfiguration
571
572
573
574
575

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

576
benchmarkCommand :: CommandUI (BenchmarkFlags, BuildFlags, BuildExFlags)
577
benchmarkCommand = parent {
578
579
  commandDefaultFlags = (commandDefaultFlags parent,
                         Cabal.defaultBuildFlags, mempty),
580
  commandOptions      =
581
    \showOrParseArgs -> liftOptions get1 set1
582
583
                        (commandOptions parent showOrParseArgs)
                        ++
584
585
586
587
                        liftOptions get2 set2
                        (Cabal.buildOptions progConf showOrParseArgs)
                        ++
                        liftOptions get3 set3 (buildExOptions showOrParseArgs)
ttuegel's avatar
ttuegel committed
588
  }
589
  where
590
591
592
    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)
593

594
595
    parent   = Cabal.benchmarkCommand
    progConf = defaultProgramConfiguration
ttuegel's avatar
ttuegel committed
596

597
-- ------------------------------------------------------------
598
-- * Fetch command
599
-- ------------------------------------------------------------
600

601
602
603
604
data FetchFlags = FetchFlags {
--    fetchOutput    :: Flag FilePath,
      fetchDeps      :: Flag Bool,
      fetchDryRun    :: Flag Bool,
605
      fetchSolver           :: Flag PreSolver,
606
      fetchMaxBackjumps     :: Flag Int,
607
608
609
610
      fetchReorderGoals     :: Flag ReorderGoals,
      fetchIndependentGoals :: Flag IndependentGoals,
      fetchShadowPkgs       :: Flag ShadowPkgs,
      fetchStrongFlags      :: Flag StrongFlags,
611
612
613
614
615
616
617
618
      fetchVerbosity :: Flag Verbosity
    }

defaultFetchFlags :: FetchFlags
defaultFetchFlags = FetchFlags {
--  fetchOutput    = mempty,
    fetchDeps      = toFlag True,
    fetchDryRun    = toFlag False,
619
620
    fetchSolver           = Flag defaultSolver,
    fetchMaxBackjumps     = Flag defaultMaxBackjumps,
621
622
623
624
    fetchReorderGoals     = Flag (ReorderGoals False),
    fetchIndependentGoals = Flag (IndependentGoals False),
    fetchShadowPkgs       = Flag (ShadowPkgs False),
    fetchStrongFlags      = Flag (StrongFlags False),
625
626
627
628
    fetchVerbosity = toFlag normal
   }

fetchCommand :: CommandUI FetchFlags
Duncan Coutts's avatar
Duncan Coutts committed
629
630
fetchCommand = CommandUI {
    commandName         = "fetch",
631
    commandSynopsis     = "Downloads packages for later installation.",
632
633
634
635
636
    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",
637
    commandNotes        = Nothing,
638
    commandDefaultFlags = defaultFetchFlags,
639
    commandOptions      = \ showOrParseArgs -> [
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
         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
661
662
663
664

       ] ++

       optionSolver      fetchSolver           (\v flags -> flags { fetchSolver           = v }) :
665
666
       optionSolverFlags showOrParseArgs
                         fetchMaxBackjumps     (\v flags -> flags { fetchMaxBackjumps     = v })
667
668
                         fetchReorderGoals     (\v flags -> flags { fetchReorderGoals     = v })
                         fetchIndependentGoals (\v flags -> flags { fetchIndependentGoals = v })
669
                         fetchShadowPkgs       (\v flags -> flags { fetchShadowPkgs       = v })
Andres Löh's avatar
Andres Löh committed
670
                         fetchStrongFlags      (\v flags -> flags { fetchStrongFlags      = v })
671

Duncan Coutts's avatar
Duncan Coutts committed
672
673
  }

674
675
676
677
678
679
-- ------------------------------------------------------------
-- * Freeze command
-- ------------------------------------------------------------

data FreezeFlags = FreezeFlags {
      freezeDryRun           :: Flag Bool,
680
681
      freezeTests            :: Flag Bool,
      freezeBenchmarks       :: Flag Bool,
682
683
      freezeSolver           :: Flag PreSolver,
      freezeMaxBackjumps     :: Flag Int,
684
685
686
687
      freezeReorderGoals     :: Flag ReorderGoals,
      freezeIndependentGoals :: Flag IndependentGoals,
      freezeShadowPkgs       :: Flag ShadowPkgs,
      freezeStrongFlags      :: Flag StrongFlags,
688
689
690
691
692
693
      freezeVerbosity        :: Flag Verbosity
    }

defaultFreezeFlags :: FreezeFlags
defaultFreezeFlags = FreezeFlags {
    freezeDryRun           = toFlag False,
694
695
    freezeTests            = toFlag False,
    freezeBenchmarks       = toFlag False,
696
697
    freezeSolver           = Flag defaultSolver,
    freezeMaxBackjumps     = Flag defaultMaxBackjumps,
698
699
700
701
    freezeReorderGoals     = Flag (ReorderGoals False),
    freezeIndependentGoals = Flag (IndependentGoals False),
    freezeShadowPkgs       = Flag (ShadowPkgs False),
    freezeStrongFlags      = Flag (StrongFlags False),
702
703
704
705
706
707
708
    freezeVerbosity        = toFlag normal
   }

freezeCommand :: CommandUI FreezeFlags
freezeCommand = CommandUI {
    commandName         = "freeze",
    commandSynopsis     = "Freeze dependencies.",
709
710
711
712
713
714
715
716
    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",
717
    commandNotes        = Nothing,
718
    commandUsage        = usageFlags "freeze",
719
720
721
722
723
724
725
726
727
    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

728
729
730
731
732
733
734
735
736
737
       , 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 [] [])

738
739
740
741
742
743
744
745
       ] ++

       optionSolver      freezeSolver           (\v flags -> flags { freezeSolver           = v }) :
       optionSolverFlags showOrParseArgs
                         freezeMaxBackjumps     (\v flags -> flags { freezeMaxBackjumps     = v })
                         freezeReorderGoals     (\v flags -> flags { freezeReorderGoals     = v })
                         freezeIndependentGoals (\v flags -> flags { freezeIndependentGoals = v })
                         freezeShadowPkgs       (\v flags -> flags { freezeShadowPkgs       = v })
Andres Löh's avatar
Andres Löh committed
746
                         freezeStrongFlags      (\v flags -> flags { freezeStrongFlags      = v })
747
748
749

  }

750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
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 })
     ]
  }

766
767
768
769
-- ------------------------------------------------------------
-- * Other commands
-- ------------------------------------------------------------

770
updateCommand  :: CommandUI (Flag Verbosity)
Duncan Coutts's avatar
Duncan Coutts committed
771
772
updateCommand = CommandUI {
    commandName         = "update",
773
    commandSynopsis     = "Updates list of known packages.",
774
775
776
    commandDescription  = Just $ \_ ->
      "For all known remote repositories, download the package list.\n",
    commandNotes        = Just $ \_ ->
777
778
779
      relevantConfigValuesText ["remote-repo"
                               ,"remote-repo-cache"
                               ,"local-repo"],
refold's avatar
refold committed
780
    commandUsage        = usageFlags "update",
781
    commandDefaultFlags = toFlag normal,
782
    commandOptions      = \_ -> [optionVerbosity id const]
Duncan Coutts's avatar
Duncan Coutts committed
783
784
  }

785
upgradeCommand  :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
786
upgradeCommand = configureCommand {
ijones's avatar
ijones committed
787
    commandName         = "upgrade",
788
    commandSynopsis     = "(command disabled, use install instead)",
ijones's avatar
ijones committed
789
    commandDescription  = Nothing,
refold's avatar
refold committed
790
    commandUsage        = usageFlagsOrPackages "upgrade",
791
    commandDefaultFlags = (mempty, mempty, mempty, mempty),
792
    commandOptions      = commandOptions installCommand
ijones's avatar
ijones committed
793
794
  }

Duncan Coutts's avatar
Duncan Coutts committed
795
796
797
798
799
800
801
802
803
804
805
{-
cleanCommand  :: CommandUI ()
cleanCommand = makeCommand name shortDesc longDesc emptyFlags options
  where
    name       = "clean"
    shortDesc  = "Removes downloaded files"
    longDesc   = Nothing
    emptyFlags = ()
    options _  = []
-}

806
807
808
checkCommand  :: CommandUI (Flag Verbosity)
checkCommand = CommandUI {
    commandName         = "check",
809
    commandSynopsis     = "Check the package for common mistakes.",
810
811
812
813
814
815
    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",
816
    commandNotes        = Nothing,
817
    commandUsage        = \pname -> "Usage: " ++ pname ++ " check\n",
818
    commandDefaultFlags = toFlag normal,
819
    commandOptions      = \_ -> []
820
821
  }

822
823
824
825
826
formatCommand  :: CommandUI (Flag Verbosity)
formatCommand = CommandUI {
    commandName         = "format",
    commandSynopsis     = "Reformat the .cabal file using the standard style.",
    commandDescription  = Nothing,
827
    commandNotes        = Nothing,
828
    commandUsage        = usageAlternatives "format" ["[FILE]"],
829
830
831
832
    commandDefaultFlags = toFlag normal,
    commandOptions      = \_ -> []
  }

833
834
835
836
837
838
839
840
841
842
843
uninstallCommand  :: CommandUI (Flag Verbosity)
uninstallCommand = CommandUI {
    commandName         = "uninstall",
    commandSynopsis     = "Warn about 'uninstall' not being implemented.",
    commandDescription  = Nothing,
    commandNotes        = Nothing,
    commandUsage        = usageAlternatives "uninstall" ["PACKAGES"],
    commandDefaultFlags = toFlag normal,
    commandOptions      = \_ -> []
  }

Maciek Makowski's avatar
Maciek Makowski committed
844
845
846
847
848
849
850
851
852
853
854
855
manpageCommand :: CommandUI (Flag Verbosity)
manpageCommand = CommandUI {
    commandName         = "manpage",
    commandSynopsis     = "Outputs manpage source.",
    commandDescription  = Just $ \_ ->
      "Output manpage source to STDOUT.\n",
    commandNotes        = Nothing,
    commandUsage        = usageFlags "manpage",
    commandDefaultFlags = toFlag normal,
    commandOptions      = \_ -> [optionVerbosity id const]
  }

856
runCommand :: CommandUI (BuildFlags, BuildExFlags)
refold's avatar
refold committed
857
858
runCommand = CommandUI {
    commandName         = "run",
859
    commandSynopsis     = "Builds and runs an executable.",
860
    commandDescription  = Just $ \pname -> wrapText $
861
862
         "Builds and then runs the specified executable. If no executable is "
      ++ "specified, but the package contains just one executable, that one "
863
864
865
866
      ++ "is built and executed.\n"
      ++ "\n"
      ++ "Use `" ++ pname ++ " test --show-details=streaming` to run a "
      ++ "test-suite and get its full output.\n",
867
868
869
870
    commandNotes        = Just $ \pname ->
          "Examples:\n"
       ++ "  " ++ pname ++ " run\n"
       ++ "    Run the only executable in the current package;\n"
871
872
       ++ "  " ++ pname ++ " run foo -- --fooflag\n"
       ++ "    Works similar to `./foo --fooflag`.\n",
873
874
    commandUsage        = usageAlternatives "run"
        ["[FLAGS] [EXECUTABLE] [-- EXECUTABLE_FLAGS]"],
refold's avatar
refold committed
875
    commandDefaultFlags = mempty,
876
877
    commandOptions      =
      \showOrParseArgs -> liftOptions fst setFst
878
                          (commandOptions parent showOrParseArgs)
879
880
881
                          ++
                          liftOptions snd setSnd
                          (buildExOptions showOrParseArgs)
refold's avatar
refold committed
882
883
  }
  where
884
885
886
    setFst a (_,b) = (a,b)
    setSnd b (a,_) = (a,b)

887
    parent = Cabal.buildCommand defaultProgramConfiguration
refold's avatar
refold committed
888

889
890
891
892
893
894
895
896
-- ------------------------------------------------------------
-- * Report flags
-- ------------------------------------------------------------

data ReportFlags = ReportFlags {
    reportUsername  :: Flag Username,
    reportPassword  :: Flag Password,
    reportVerbosity :: Flag Verbosity
897
  } deriving Generic
898
899
900
901
902
903
904
905
906

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

reportCommand :: CommandUI ReportFlags
907
908
909
reportCommand = CommandUI {
    commandName         = "report",
    commandSynopsis     = "Upload build reports to a remote server.",
910
911
    commandDescription  = Nothing,
    commandNotes        = Just $ \_ ->
912
         "You can store your Hackage login in the ~/.cabal/config file\n",
913
    commandUsage        = usageAlternatives "report" ["[FLAGS]"],
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
    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))
      ]
930
931
  }

932
instance Monoid ReportFlags where
933
  mempty = gmempty
934
935
936
  mappend = (<>)

instance Semigroup ReportFlags where
937
  (<>) = gmappend
938

939
-- ------------------------------------------------------------
940
-- * Get flags
941
942
-- ------------------------------------------------------------

943
944
945
946
947
data GetFlags = GetFlags {
    getDestDir          :: Flag FilePath,
    getPristine         :: Flag Bool,
    getSourceRepository :: Flag (Maybe RepoKind),
    getVerbosity        :: Flag Verbosity
948
  } deriving Generic
949

950
951
952
953
954
955
defaultGetFlags :: GetFlags
defaultGetFlags = GetFlags {
    getDestDir          = mempty,
    getPristine         = mempty,
    getSourceRepository = mempty,
    getVerbosity        = toFlag normal
956
957
   }

958
959
960
getCommand :: CommandUI GetFlags
getCommand = CommandUI {
    commandName         = "get",
961
962
    commandSynopsis     = "Download/Extract a package's source code (repository).",
    commandDescription  = Just $ \_ -> wrapText $
963
964
965
966
          "Creates a local copy of a package's source code. By default it gets "
       ++ "the source\ntarball and unpacks it in a local subdirectory. "
       ++ "Alternatively, with -s it will\nget the code from the source "
       ++ "repository specified by the package.\n",
967
968
969
970
    commandNotes        = Just $ \pname ->
          "Examples:\n"
       ++ "  " ++ pname ++ " get hlint\n"
       ++ "    Download the latest stable version of hlint;\n"
971
       ++ "  " ++ pname ++ " get lens --source-repository=head\n"
972
       ++ "    Download the source repository (i.e. git clone from github).\n",
973
    commandUsage        = usagePackages "get",
974
    commandDefaultFlags = defaultGetFlags,
975
    commandOptions      = \_ -> [
976
        optionVerbosity getVerbosity (\v flags -> flags { getVerbosity = v })
977
978

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

983
       ,option "s" ["source-repository"]
984
         "Copy the package's source repository (ie git clone, darcs get, etc as appropriate)."
985
986
987
988
989
990
         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))

991
992
993
       , option [] ["pristine"]
           ("Unpack the original pristine tarball, rather than updating the "
           ++ ".cabal file with the latest revision from the package archive.")
994
           getPristine (\v flags -> flags { getPristine = v })
995
           trueArg
996
997
998
       ]
  }

999
1000
1001
1002
1003
1004
1005
-- 'cabal unpack' is a deprecated alias for 'cabal get'.
unpackCommand :: CommandUI GetFlags
unpackCommand = getCommand {
  commandName  = "unpack",
  commandUsage = usagePackages "unpack"
  }

1006
instance Monoid GetFlags where
1007
  mempty = gmempty
1008
1009
1010
  mappend = (<>)

instance Semigroup GetFlags where
1011
  (<>) = gmappend
1012

1013
1014
1015
1016
1017
-- ------------------------------------------------------------
-- * List flags
-- ------------------------------------------------------------

data ListFlags = ListFlags {
1018
    listInstalled    :: Flag Bool,
1019
    listSimpleOutput :: Flag Bool,
1020
1021
    listVerbosity    :: Flag Verbosity,
    listPackageDBs   :: [Maybe PackageDB]
1022
  } deriving Generic
1023
1024
1025

defaultListFlags :: ListFlags
defaultListFlags = ListFlags {
1026
    listInstalled    = Flag False,
1027
    listSimpleOutput = Flag False,
1028
1029
    listVerbosity    = toFlag normal,
    listPackageDBs   = []
1030
1031
1032
1033
1034
  }

listCommand  :: CommandUI ListFlags
listCommand = CommandUI {
    commandName         = "list",
1035
    commandSynopsis     = "List packages matching a search string.",
1036
1037
1038
1039
1040
1041
1042
1043
    commandDescription  = Just $ \_ -> wrapText $
         "List all packages, or all packages matching one of the search"
      ++ " strings.\n"
      ++</