Setup.hs 59.5 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(..)
33
    , indexCommand, IndexFlags(..)
refold's avatar
refold committed
34
    , dumpPkgEnvCommand
refold's avatar
refold committed
35
36
    , sandboxInitCommand, sandboxDeleteCommand, sandboxConfigureCommand
    , sandboxAddSourceCommand, sandboxBuildCommand, sandboxInstallCommand
refold's avatar
refold committed
37
    , SandboxFlags(..), defaultSandboxLocation
Duncan Coutts's avatar
Duncan Coutts committed
38
39

    , parsePackageArgs
40
41
42
    --TODO: stop exporting these:
    , showRepo
    , parseRepo
43
44
    ) where

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

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

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

98
99
100
101
102
103
104
105
106
-- ------------------------------------------------------------
-- * 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,
107
    globalRemoteRepos    :: [RemoteRepo],     -- ^ Available Hackage servers.
108
    globalCacheDir       :: Flag FilePath,
109
    globalLocalRepos     :: [FilePath],
110
    globalLogsDir        :: Flag FilePath,
111
    globalWorldFile      :: Flag FilePath
112
  }
Duncan Coutts's avatar
Duncan Coutts committed
113

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

globalCommand :: CommandUI GlobalFlags
globalCommand = CommandUI {
    commandName         = "",
    commandSynopsis     = "",
130
131
132
133
    commandUsage        = \_ ->
         "This program is the command line interface "
           ++ "to the Haskell Cabal infrastructure.\n"
      ++ "See http://www.haskell.org/cabal/ for more information.\n",
134
    commandDescription  = Just $ \pname ->
135
136
137
138
139
140
         "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",
141
142
    commandDefaultFlags = defaultGlobalFlags,
    commandOptions      = \showOrParseArgs ->
143
      (case showOrParseArgs of ShowArgs -> take 3; ParseArgs -> id)
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
172
      [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)
173

174
175
176
177
178
      ,option [] ["logs-dir"]
         "The location to put log files"
         globalLogsDir (\v flags -> flags { globalLogsDir = v })
         (reqArgFlag "DIR")

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

instance Monoid GlobalFlags where
  mempty = GlobalFlags {
    globalVersion        = mempty,
    globalNumericVersion = mempty,
    globalConfigFile     = mempty,
    globalRemoteRepos    = mempty,
    globalCacheDir       = mempty,
193
    globalLocalRepos     = mempty,
194
    globalLogsDir        = mempty,
195
    globalWorldFile      = mempty
196
197
198
199
200
201
202
  }
  mappend a b = GlobalFlags {
    globalVersion        = combine globalVersion,
    globalNumericVersion = combine globalNumericVersion,
    globalConfigFile     = combine globalConfigFile,
    globalRemoteRepos    = combine globalRemoteRepos,
    globalCacheDir       = combine globalCacheDir,
203
    globalLocalRepos     = combine globalLocalRepos,
204
    globalLogsDir        = combine globalLogsDir,
205
    globalWorldFile      = combine globalWorldFile
Duncan Coutts's avatar
Duncan Coutts committed
206
  }
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
    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
224

225
configureCommand :: CommandUI ConfigFlags
226
configureCommand = (Cabal.configureCommand defaultProgramConfiguration) {
227
    commandDefaultFlags = mempty
Duncan Coutts's avatar
Duncan Coutts committed
228
229
  }

230
231
232
configureOptions ::  ShowOrParseArgs -> [OptionField ConfigFlags]
configureOptions = commandOptions configureCommand

233
filterConfigureFlags :: ConfigFlags -> Version -> ConfigFlags
234
filterConfigureFlags flags cabalLibVersion
235
236
237
238
239
240
241
242
243
244
245
246
247
248
  | 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 = [] }
249

250
251
252
253
254
255
256
257
-- ------------------------------------------------------------
-- * Config extra flags
-- ------------------------------------------------------------

-- | cabal configure takes some extra flags beyond runghc Setup configure
--
data ConfigExFlags = ConfigExFlags {
    configCabalVersion :: Flag Version,
258
    configExConstraints:: [UserConstraint],
259
    configPreferences  :: [Dependency],
260
    configSolver       :: Flag PreSolver
261
262
263
  }

defaultConfigExFlags :: ConfigExFlags
264
defaultConfigExFlags = mempty { configSolver = Flag defaultSolver }
265
266
267
268
269

configureExCommand :: CommandUI (ConfigFlags, ConfigExFlags)
configureExCommand = configureCommand {
    commandDefaultFlags = (mempty, defaultConfigExFlags),
    commandOptions      = \showOrParseArgs ->
270
271
         liftOptions fst setFst (filter ((/="constraint") . optionName) $
                                 configureOptions   showOrParseArgs)
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
      ++ 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))
287
288
289
290
291
292
  , 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))
293
294
295
296

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

  , optionSolver configSolver (\v flags -> flags { configSolver = v })
303
304
305
306
307
  ]

instance Monoid ConfigExFlags where
  mempty = ConfigExFlags {
    configCabalVersion = mempty,
308
    configExConstraints= mempty,
309
310
    configPreferences  = mempty,
    configSolver       = mempty
311
312
313
  }
  mappend a b = ConfigExFlags {
    configCabalVersion = combine configCabalVersion,
314
    configExConstraints= combine configExConstraints,
315
316
    configPreferences  = combine configPreferences,
    configSolver       = combine configSolver
317
318
319
  }
    where combine field = field a `mappend` field b

ttuegel's avatar
ttuegel committed
320
321
322
323
324
325
326
327
328
-- ------------------------------------------------------------
-- * Build flags
-- ------------------------------------------------------------

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

329
-- ------------------------------------------------------------
330
-- * Fetch command
331
-- ------------------------------------------------------------
332

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

defaultFetchFlags :: FetchFlags
defaultFetchFlags = FetchFlags {
--  fetchOutput    = mempty,
    fetchDeps      = toFlag True,
    fetchDryRun    = toFlag False,
350
351
352
353
    fetchSolver           = Flag defaultSolver,
    fetchMaxBackjumps     = Flag defaultMaxBackjumps,
    fetchReorderGoals     = Flag False,
    fetchIndependentGoals = Flag False,
354
    fetchShadowPkgs       = Flag False,
355
356
357
358
    fetchVerbosity = toFlag normal
   }

fetchCommand :: CommandUI FetchFlags
Duncan Coutts's avatar
Duncan Coutts committed
359
360
fetchCommand = CommandUI {
    commandName         = "fetch",
361
    commandSynopsis     = "Downloads packages for later installation.",
Duncan Coutts's avatar
Duncan Coutts committed
362
    commandDescription  = Nothing,
refold's avatar
refold committed
363
    commandUsage        = usagePackages "fetch",
364
    commandDefaultFlags = defaultFetchFlags,
365
    commandOptions      = \ showOrParseArgs -> [
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
         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
387
388
389
390

       ] ++

       optionSolver      fetchSolver           (\v flags -> flags { fetchSolver           = v }) :
391
392
       optionSolverFlags showOrParseArgs
                         fetchMaxBackjumps     (\v flags -> flags { fetchMaxBackjumps     = v })
393
394
                         fetchReorderGoals     (\v flags -> flags { fetchReorderGoals     = v })
                         fetchIndependentGoals (\v flags -> flags { fetchIndependentGoals = v })
395
                         fetchShadowPkgs       (\v flags -> flags { fetchShadowPkgs       = v })
396

Duncan Coutts's avatar
Duncan Coutts committed
397
398
  }

399
400
401
402
-- ------------------------------------------------------------
-- * Other commands
-- ------------------------------------------------------------

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

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

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

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

refold's avatar
refold committed
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
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

459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
-- ------------------------------------------------------------
-- * 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
477
478
479
reportCommand = CommandUI {
    commandName         = "report",
    commandSynopsis     = "Upload build reports to a remote server.",
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
    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))
      ]
500
501
  }

502
503
504
505
506
507
508
509
510
511
512
513
514
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

515
-- ------------------------------------------------------------
516
-- * Get flags
517
518
-- ------------------------------------------------------------

519
520
521
522
523
524
data GetFlags = GetFlags {
    getDestDir          :: Flag FilePath,
    getPristine         :: Flag Bool,
    getSourceRepository :: Flag (Maybe RepoKind),
    getVerbosity        :: Flag Verbosity
  }
525

526
527
528
529
530
531
defaultGetFlags :: GetFlags
defaultGetFlags = GetFlags {
    getDestDir          = mempty,
    getPristine         = mempty,
    getSourceRepository = mempty,
    getVerbosity        = toFlag normal
532
533
   }

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

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

549
       ,option "s" ["source-repository"]
refold's avatar
refold committed
550
         "Fork the package's source repository."
551
552
553
554
555
556
         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))

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

565
566
567
568
569
570
571
-- 'cabal unpack' is a deprecated alias for 'cabal get'.
unpackCommand :: CommandUI GetFlags
unpackCommand = getCommand {
  commandName  = "unpack",
  commandUsage = usagePackages "unpack"
  }

572
573
574
575
576
577
578
instance Monoid GetFlags where
  mempty = defaultGetFlags
  mappend a b = GetFlags {
    getDestDir          = combine getDestDir,
    getPristine         = combine getPristine,
    getSourceRepository = combine getSourceRepository,
    getVerbosity        = combine getVerbosity
579
580
581
  }
    where combine field = field a `mappend` field b

582
583
584
585
586
587
-- ------------------------------------------------------------
-- * List flags
-- ------------------------------------------------------------

data ListFlags = ListFlags {
    listInstalled :: Flag Bool,
588
    listSimpleOutput :: Flag Bool,
589
590
591
592
593
594
    listVerbosity :: Flag Verbosity
  }

defaultListFlags :: ListFlags
defaultListFlags = ListFlags {
    listInstalled = Flag False,
595
    listSimpleOutput = Flag False,
596
597
598
599
600
601
    listVerbosity = toFlag normal
  }

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

609
        , option [] ["installed"]
610
611
612
613
            "Only print installed packages"
            listInstalled (\v flags -> flags { listInstalled = v })
            trueArg

614
615
616
617
618
        , option [] ["simple-output"]
            "Print in a easy-to-parse format"
            listSimpleOutput (\v flags -> flags { listSimpleOutput = v })
            trueArg

619
620
621
622
623
624
625
        ]
  }

instance Monoid ListFlags where
  mempty = defaultListFlags
  mappend a b = ListFlags {
    listInstalled = combine listInstalled,
626
    listSimpleOutput = combine listSimpleOutput,
627
628
629
630
    listVerbosity = combine listVerbosity
  }
    where combine field = field a `mappend` field b

631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
-- ------------------------------------------------------------
-- * 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
649
    commandUsage        = usagePackages "info",
650
651
652
653
654
655
656
657
658
659
660
661
662
    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

663
664
665
666
-- ------------------------------------------------------------
-- * Install flags
-- ------------------------------------------------------------

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

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

718
719
720
defaultMaxBackjumps :: Int
defaultMaxBackjumps = 200

721
722
defaultSolver :: PreSolver
defaultSolver = Choose
723
724

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

727
installCommand :: CommandUI (ConfigFlags, ConfigExFlags, InstallFlags, HaddockFlags)
728
installCommand = CommandUI {
729
730
  commandName         = "install",
  commandSynopsis     = "Installs a list of packages.",
refold's avatar
refold committed
731
  commandUsage        = usageFlagsOrPackages "install",
732
733
734
735
736
  commandDescription  = Just $ \pname ->
    let original = case commandDescription configureCommand of
          Just desc -> desc pname ++ "\n"
          Nothing   -> ""
     in original
737
     ++ "Examples:\n"
738
739
740
741
742
743
744
745
     ++ "  " ++ 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",
746
  commandDefaultFlags = (mempty, mempty, mempty, mempty),
747
  commandOptions      = \showOrParseArgs ->
748
749
       liftOptions get1 set1 (filter ((/="constraint") . optionName) $
                              configureOptions   showOrParseArgs)
750
751
    ++ liftOptions get2 set2 (configureExOptions showOrParseArgs)
    ++ liftOptions get3 set3 (installOptions     showOrParseArgs)
752
    ++ liftOptions get4 set4 (haddockOptions     showOrParseArgs)
753
  }
754
  where
755
756
757
758
759
    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)

760
761
762
763
764
765
766
767
768
769
770
771
772
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
773
774
775
776
777
    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
778
779
780
781

installOptions ::  ShowOrParseArgs -> [OptionField InstallFlags]
installOptions showOrParseArgs =
      [ option "" ["documentation"]
782
783
784
785
          "building of documentation"
          installDocumentation (\v flags -> flags { installDocumentation = v })
          (boolOpt [] [])

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

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

798
799
      optionSolverFlags showOrParseArgs
                        installMaxBackjumps     (\v flags -> flags { installMaxBackjumps     = v })
800
                        installReorderGoals     (\v flags -> flags { installReorderGoals     = v })
801
802
                        installIndependentGoals (\v flags -> flags { installIndependentGoals = v })
                        installShadowPkgs       (\v flags -> flags { installShadowPkgs       = v }) ++
803

804
      [ option [] ["reinstall"]
805
806
          "Install even if it means installing the same version again."
          installReinstall (\v flags -> flags { installReinstall = v })
807
          (yesNoOpt showOrParseArgs)
808

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

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

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

824
825
826
      , option [] ["only-dependencies"]
          "Install only the dependencies necessary to build the given packages"
          installOnlyDeps (\v flags -> flags { installOnlyDeps = v })
827
          (yesNoOpt showOrParseArgs)
828

829
830
831
832
833
      , option [] ["dependencies-only"]
          "A synonym for --only-dependencies"
          installOnlyDeps (\v flags -> flags { installOnlyDeps = v })
          (yesNoOpt showOrParseArgs)

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

839
840
841
842
843
      , option [] ["symlink-bindir"]
          "Add symlinks to installed executables into this directory."
           installSymlinkBinDir (\v flags -> flags { installSymlinkBinDir = v })
           (reqArgFlag "DIR")

844
845
846
847
848
849
      , 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
850
851
          "Log all builds to file (name template can use $pkgid, $compiler, $os, $arch)"
          installLogFile (\v flags -> flags { installLogFile = v })
852
853
          (reqArg' "TEMPLATE" (toFlag.toPathTemplate)
                              (flagToList . fmap fromPathTemplate))
Duncan Coutts's avatar
Duncan Coutts committed
854

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

863
864
865
      , option [] ["one-shot"]
          "Do not record the packages in the world file."
          installOneShot (\v flags -> flags { installOneShot = v })
866
          (yesNoOpt showOrParseArgs)
867
868

      , option "j" ["jobs"]
869
        "Run NUM jobs simultaneously (or '$ncpus' if no NUM is given)."
870
        installNumJobs (\v flags -> flags { installNumJobs = v })
871
        (optArg "NUM" (fmap Flag flagToJobs)
872
                      (Flag Nothing)
873
                      (map (Just . maybe "$ncpus" show) . flagToList))
874
875
      ] ++ case showOrParseArgs of      -- TODO: remove when "cabal install" avoids
          ParseArgs ->
EyalLotem's avatar
EyalLotem committed
876
            [ option [] ["only"]
877
878
              "Only installs the package in the current directory."
              installOnly (\v flags -> flags { installOnly = v })
EyalLotem's avatar
EyalLotem committed
879
              trueArg ]
880
          _ -> []
881
882
883
884
885
  where
    flagToJobs :: ReadE (Maybe Int)
    flagToJobs = ReadE $ \s ->
      case s of
        "$ncpus" -> Right Nothing
886
        _        -> case reads s of
887
888
889
890
891
892
          [(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'"

893
894

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

941
942
943
944
945
946
947
948
949
-- ------------------------------------------------------------
-- * Upload flags
-- ------------------------------------------------------------

data UploadFlags = UploadFlags {
    uploadCheck     :: Flag Bool,
    uploadUsername  :: Flag Username,
    uploadPassword  :: Flag Password,
    uploadVerbosity :: Flag Verbosity
950
  }
951
952
953
954
955
956
957
958
959
960
961
962
963
964

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 $ \_ ->
965
         "You can store your Hackage login in the ~/.cabal/config file\n",
966
967
968
969
970
    commandUsage        = \pname ->
         "Usage: " ++ pname ++ " upload [FLAGS] [TARFILES]\n\n"
      ++ "Flags for upload:",
    commandDefaultFlags = defaultUploadFlags,
    commandOptions      = \_ ->
971
      [optionVerbosity uploadVerbosity (\v flags -> flags { uploadVerbosity = v })
972
973
974
975

      ,option ['c'] ["check"]
         "Do not upload, just do QA checks."
        uploadCheck (\v flags -> flags { uploadCheck = v })
976
        trueArg
977
978
979
980

      ,option ['u'] ["username"]
        "Hackage username."
        uploadUsername (\v flags -> flags { uploadUsername = v })
981
982
        (reqArg' "USERNAME" (toFlag . Username)
                            (flagToList . fmap unUsername))
983
984
985
986

      ,option ['p'] ["password"]
        "Hackage password."
        uploadPassword (\v flags -> flags { uploadPassword = v })
987
988
        (reqArg' "PASSWORD" (toFlag . Password)
                            (flagToList . fmap unPassword))
989
990
991
992
993
994
995
996
997
998
999
1000
      ]
  }

instance Monoid UploadFlags where
  mempty = UploadFlags {
    uploadCheck     = mempty,
    uploadUsername  = mempty,
    uploadPassword  = mempty,
    uploadVerbosity = mempty
  }
  mappend a b = UploadFlags {
    uploadCheck     = combine uploadCheck,