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

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

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

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

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

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

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

globalCommand :: CommandUI GlobalFlags
globalCommand = CommandUI {
    commandName         = "",
    commandSynopsis     = "",
128
129
130
131
    commandUsage        = \_ ->
         "This program is the command line interface "
           ++ "to the Haskell Cabal infrastructure.\n"
      ++ "See http://www.haskell.org/cabal/ for more information.\n",
132
    commandDescription  = Just $ \pname ->
133
134
135
136
137
138
         "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",
139
140
    commandDefaultFlags = defaultGlobalFlags,
    commandOptions      = \showOrParseArgs ->
141
      (case showOrParseArgs of ShowArgs -> take 3; ParseArgs -> id)
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
      [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)
171

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

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

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

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

228
229
230
configureOptions ::  ShowOrParseArgs -> [OptionField ConfigFlags]
configureOptions = commandOptions configureCommand

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

248
249
250
251
252
253
254
255
-- ------------------------------------------------------------
-- * Config extra flags
-- ------------------------------------------------------------

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

defaultConfigExFlags :: ConfigExFlags
262
defaultConfigExFlags = mempty { configSolver = Flag defaultSolver }
263
264
265
266
267

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

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

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

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

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

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

327
-- ------------------------------------------------------------
328
-- * Fetch command
329
-- ------------------------------------------------------------
330

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

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

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

       ] ++

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

Duncan Coutts's avatar
Duncan Coutts committed
395
396
  }

397
398
399
400
-- ------------------------------------------------------------
-- * Other commands
-- ------------------------------------------------------------

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

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

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

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

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

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

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

513
-- ------------------------------------------------------------
514
-- * Get flags
515
516
-- ------------------------------------------------------------

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

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

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

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

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

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

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

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

580
581
582
583
584
585
-- ------------------------------------------------------------
-- * List flags
-- ------------------------------------------------------------

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

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

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

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

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

617
618
619
620
621
622
623
        ]
  }

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

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

661
662
663
664
-- ------------------------------------------------------------
-- * Install flags
-- ------------------------------------------------------------

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

defaultInstallFlags :: InstallFlags
defaultInstallFlags = InstallFlags {
693
694
695
    installDocumentation   = Flag False,
    installHaddockIndex    = Flag docIndexFile,
    installDryRun          = Flag False,
696
697
698
    installMaxBackjumps    = Flag defaultMaxBackjumps,
    installReorderGoals    = Flag False,
    installIndependentGoals= Flag False,
699
    installShadowPkgs      = Flag False,
700
701
    installReinstall       = Flag False,
    installAvoidReinstalls = Flag False,
702
    installOverrideReinstall = Flag False,
703
704
705
706
707
708
709
710
    installUpgradeDeps     = Flag False,
    installOnly            = Flag False,
    installOnlyDeps        = Flag False,
    installRootCmd         = mempty,
    installSummaryFile     = mempty,
    installLogFile         = mempty,
    installBuildReports    = Flag NoReports,
    installSymlinkBinDir   = mempty,
711
    installOneShot         = Flag False,
712
713
    installNumJobs         = mempty,
    installUseSandbox      = 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 numJobsParser)
872
                      (Flag Nothing)
873
                      (map (Just . maybe "$ncpus" show) . flagToList))
874
875
      ] ++ case showOrParseArgs of      -- TODO: remove when "cabal install"
                                        -- avoids
876
          ParseArgs ->
EyalLotem's avatar
EyalLotem committed
877
            [ option [] ["only"]
878
879
              "Only installs the package in the current directory."
              installOnly (\v flags -> flags { installOnly = v })
EyalLotem's avatar
EyalLotem committed
880
              trueArg ]
881
          _ -> []
882

883
884

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

933
934
935
936
937
938
939
940
941
-- ------------------------------------------------------------
-- * Upload flags
-- ------------------------------------------------------------

data UploadFlags = UploadFlags {
    uploadCheck     :: Flag Bool,
    uploadUsername  :: Flag Username,
    uploadPassword  :: Flag Password,
    uploadVerbosity :: Flag Verbosity
942
  }
943
944
945
946
947
948
949
950
951
952
953
954
955
956

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 $ \_ ->
957
         "You can store your Hackage login in the ~/.cabal/config file\n",
958
959
960
961
962
    commandUsage        = \pname ->
         "Usage: " ++ pname ++ " upload [FLAGS] [TARFILES]\n\n"
      ++ "Flags for upload:",
    commandDefaultFlags = defaultUploadFlags,
    commandOptions      = \_ ->
963
      [optionVerbosity uploadVerbosity (\v flags -> flags { uploadVerbosity = v })
964
965
966
967

      ,option ['c'] ["check"]
         "Do not upload, just do QA checks."
        uploadCheck (\v flags -> flags { uploadCheck = v })
968
        trueArg
969
970
971
972

      ,option ['u'] ["username"]
        "Hackage username."
        uploadUsername (\v flags -> flags { uploadUsername = v })
973
974
        (reqArg' "USERNAME" (toFlag . Username)
                            (flagToList . fmap unUsername))
975
976
977
978

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

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

999
1000
-- ------------------------------------------------------------
-- * Init flags