Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/cmd-help.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ on:
- doc/cmd-v2-hidden-help/**
- doc/setup-help/**
- cabal-install/src/Distribution/Client/Cmd*.hs
- cabal-install/src/Distribution/Client/NixStyleOptions.hs
- cabal-install/src/Distribution/Client/ProjectFlags.hs
- cabal-install/src/Distribution/Client/Main.hs
- cabal-install/src/Distribution/Client/Setup.hs
- Cabal/src/Distribution/Simple.hs
Expand Down
1 change: 1 addition & 0 deletions cabal-install/cabal-install.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ test-suite unit-tests
UnitTests.Distribution.Client.Init.FileCreators
UnitTests.Distribution.Client.InstallPlan
UnitTests.Distribution.Client.JobControl
UnitTests.Distribution.Client.NixStyleOptions
UnitTests.Distribution.Client.ProjectConfig
UnitTests.Distribution.Client.ProjectPlanning
UnitTests.Distribution.Client.Store
Expand Down
203 changes: 170 additions & 33 deletions cabal-install/src/Distribution/Client/NixStyleOptions.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@
module Distribution.Client.NixStyleOptions
( NixStyleFlags (..)
, nixStyleOptions
, configureOptionNames
, excludedConfigureOptionNames
, installOptionNames
, excludedInstallOptionNames
, isProgramOptionName
, defaultNixStyleFlags
, updNixStyleCommonSetupFlags
, cfgVerbosity
Expand All @@ -20,6 +25,7 @@ import Distribution.Simple.Setup
, HaddockFlags (..)
, TestFlags (testCommonFlags)
, fromFlagOrDefault
, installDirsOptions
)
import Distribution.Solver.Types.ConstraintSource (ConstraintSource (..))

Expand Down Expand Up @@ -62,20 +68,11 @@ nixStyleOptions commandOptions showOrParseArgs =
configFlags
set1
-- Note: [Hidden Flags]
-- We reuse the configure options from v1 commands which on their turn
-- reuse the ones from Cabal) but we hide some of them in v2 commands.
( filter
( ( `notElem`
[ "cabal-file"
, "constraint"
, "dependency"
, "promised-dependency"
, "exact-configuration"
]
)
. optionName
)
$ configureOptions showOrParseArgs
-- We reuse the configure options from v1 commands (which on their turn
-- reuse the ones from Cabal) but only take the ones named in
-- 'configureOptionNames'. See 'excludedConfigureOptionNames' for the rest.
( selectOptions configureOptionNames isProgramOptionName $
configureOptions showOrParseArgs
)
++ liftOptions
configExFlags
Expand All @@ -87,26 +84,10 @@ nixStyleOptions commandOptions showOrParseArgs =
++ liftOptions
installFlags
set3
-- hide "target-package-db" and "symlink-bindir" flags from the
-- install options.
-- "symlink-bindir" is obsoleted by "installdir" in ClientInstallFlags
( filter
( (`notElem` ["target-package-db", "symlink-bindir"])
. optionName
)
$ installOptions showOrParseArgs
)
++ liftOptions
haddockFlags
set4
-- hide "verbose" and "builddir" flags from the
-- haddock options.
( filter
( (`notElem` ["v", "verbose", "builddir"])
. optionName
)
$ haddockOptions showOrParseArgs
( selectOptions installOptionNames (const False) $
installOptions showOrParseArgs
)
++ liftOptions haddockFlags set4 (haddockOptions showOrParseArgs)
++ liftOptions testFlags set5 (testOptions showOrParseArgs)
++ liftOptions benchmarkFlags set6 (benchmarkOptions showOrParseArgs)
++ liftOptions projectFlags set7 (projectFlagsOptions showOrParseArgs)
Expand All @@ -121,6 +102,162 @@ nixStyleOptions commandOptions showOrParseArgs =
set7 x flags = flags{projectFlags = x}
set8 x flags = flags{extraFlags = x}

-- | Keep the options whose name is listed or satisfies the predicate.
selectOptions :: [String] -> (String -> Bool) -> [OptionField a] -> [OptionField a]
selectOptions names p = filter (\o -> optionName o `elem` names || p (optionName o))

-- | The program options of 'configureOptions' are generated for each known
-- program, @--with-PROG@, @--PROG-option@ and @--PROG-options@, so they are
-- matched by shape rather than listed by name. Only "configure-option",
-- "with-compiler" and "with-hc-pkg" share that shape, and those are wanted too.
isProgramOptionName :: String -> Bool
isProgramOptionName name =
"with-" `isPrefixOf` name
|| "-option" `isSuffixOf` name
|| "-options" `isSuffixOf` name

-- | The 'configureOptions' that nix-style commands take, grouped by what they
-- affect. Together with 'excludedConfigureOptionNames' and
-- 'isProgramOptionName' this covers every option in 'configureOptions', which
-- a unit test checks, so a new v1 option has to be placed in one list or the
-- other before v2 commands accept it.
configureOptionNames :: [String]
configureOptionNames =
[ -- plan and solver settings
"verbose"
, "builddir"
, "compiler"
, "with-compiler"
, "with-hc-pkg"
, "package-db"
, "extra-prog-path"
, "tests"
, -- benchmark settings
"benchmarks"
, -- build-phase settings
"keep-temp-files"
, -- per-package build settings
"program-prefix"
, "program-suffix"
, "library-vanilla"
, "library-profiling"
, "shared"
, "static"
, "library-bytecode"
, "executable-dynamic"
, "executable-static"
, "profiling"
, "profiling-shared"
, "executable-profiling"
, "profiling-detail"
, "library-profiling-detail"
, "optimization"
, "debug-info"
, "build-info"
, "library-for-ghci"
, "split-sections"
, "split-objs"
, "executable-stripping"
, "library-stripping"
, "configure-option"
, "flags"
, "extra-include-dirs"
, "extra-lib-dirs"
, "extra-lib-dirs-static"
, "extra-framework-dirs"
, "coverage"
, "library-coverage"
, "relocatable"
]
++ map optionName installDirsOptions

-- | The 'configureOptions' that nix-style commands do not take. The first
-- group is set by the planner itself from the install plan; the second is
-- handled by nix-style commands in another way; the third has no meaning for
-- a nix-style build. 'Distribution.Client.ProjectConfig.Legacy' never reads
-- these fields of 'ConfigFlags' into the project configuration. They remain
-- v1 command options and fields of the global config file.
excludedConfigureOptionNames :: [String]
excludedConfigureOptionNames =
[ -- computed per package by the planner, see elaborateInstallPlan
"ipid"
, "cid"
, "instantiate-with"
, "deterministic"
, "response-files"
, "allow-depending-on-private-libs"
, "coverage-for"
, "ignore-build-tools"
, -- the solver's business: --constraint is taken from 'configureExOptions'
-- instead, with a constraint source
"constraint"
, "dependency"
, "promised-dependency"
, "exact-configuration"
, -- per-package or per-user installs do not exist in nix-style builds
"user-install"
, "cabal-file"
]

-- | The 'installOptions' that nix-style commands take, grouped by what they
-- affect. See 'excludedInstallOptionNames' for the rest.
installOptionNames :: [String]
installOptionNames =
[ -- plan and solver settings
"documentation"
, "per-component"
, "max-backjumps"
, "reorder-goals"
, "count-conflicts"
, "fine-grained-conflicts"
, "minimize-conflict-set"
, "independent-goals"
, "prefer-oldest"
, "prefer-version"
, "strong-flags"
, "allow-boot-library-installs"
, "reject-unconstrained-dependencies"
, "index-state"
, -- haddock settings
"doc-index-file"
, -- per-package build settings
"run-tests"
, -- build-phase settings
"dry-run"
, "only-download"
, "only-dependencies"
, "dependencies-only"
, "build-summary"
, "build-log"
, "build-timings"
, "remote-build-reporting"
, "report-planning-failure"
, "semaphore"
, "jobs"
, "keep-going"
, "offline"
, -- read by @install --lib@ only, to overwrite packages already in the
-- environment file
"force-reinstalls"
]

-- | The 'installOptions' that nix-style commands do not take. They are knobs
-- of the v1 install plan that 'Distribution.Client.ProjectConfig.Legacy' never
-- reads into the project configuration. They remain v1 command options and
-- fields of the global config file.
excludedInstallOptionNames :: [String]
excludedInstallOptionNames =
[ "reinstall"
, "avoid-reinstalls"
, "upgrade-dependencies"
, "shadow-installed-packages"
, "root-cmd"
, "only"
, -- obsoleted by --installdir in 'ClientInstallFlags'
"symlink-bindir"
, "target-package-db"
]

defaultNixStyleFlags :: a -> NixStyleFlags a
defaultNixStyleFlags x =
NixStyleFlags
Expand Down
4 changes: 4 additions & 0 deletions cabal-install/tests/UnitTests.hs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import qualified UnitTests.Distribution.Client.IndexUtils.Timestamp
import qualified UnitTests.Distribution.Client.Init
import qualified UnitTests.Distribution.Client.InstallPlan
import qualified UnitTests.Distribution.Client.JobControl
import qualified UnitTests.Distribution.Client.NixStyleOptions
import qualified UnitTests.Distribution.Client.ProjectConfig
import qualified UnitTests.Distribution.Client.ProjectPlanning
import qualified UnitTests.Distribution.Client.Store
Expand Down Expand Up @@ -72,6 +73,9 @@ main = do
, testGroup
"UnitTests.Distribution.Client.JobControl"
UnitTests.Distribution.Client.JobControl.tests
, testGroup
"UnitTests.Distribution.Client.NixStyleOptions"
UnitTests.Distribution.Client.NixStyleOptions.tests
, testGroup
"UnitTests.Distribution.Client.ProjectConfig"
UnitTests.Distribution.Client.ProjectConfig.tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
-- | Check that the nix-style commands classify every option they could
-- inherit from the v1 option lists: each one is either taken or deliberately
-- left out, and the names in those lists are spelt as the options are.
module UnitTests.Distribution.Client.NixStyleOptions (tests) where

import Distribution.Client.Compat.Prelude
import Prelude ()

import Distribution.Client.NixStyleOptions
( configureOptionNames
, excludedConfigureOptionNames
, excludedInstallOptionNames
, installOptionNames
, isProgramOptionName
)
import Distribution.Client.Setup (configureOptions, installOptions)
import Distribution.Simple.Command (OptionField (optionName), ShowOrParseArgs (..))

import Test.Tasty
import Test.Tasty.HUnit

tests :: [TestTree]
tests =
[ testGroup "configureOptions" $
classified
(map optionName . configureOptions)
configureOptionNames
excludedConfigureOptionNames
isProgramOptionName
, testGroup "installOptions" $
classified
(map optionName . installOptions)
installOptionNames
excludedInstallOptionNames
(const False)
]

-- | Every name in the source list is taken or excluded, and never both;
-- every listed name exists in the source, so a renamed or removed v1 option
-- cannot leave a stale name behind.
--
-- The source differs between showing and parsing: shown, it has the
-- @--with-PROG@ placeholders; parsed, it has one option per known program
-- and some options that are accepted but not shown, such as @--only@.
classified :: (ShowOrParseArgs -> [String]) -> [String] -> [String] -> (String -> Bool) -> [TestTree]
classified source taken excluded byShape =
[ testCase "every option shown is classified" $ covered (source ShowArgs)
, testCase "every option parsed is classified" $ covered (source ParseArgs)
, testCase "no option is both taken and excluded" $
assertEqual "" [] [n | n <- taken, n `elem` excluded]
, testCase "no excluded option is matched by shape" $
assertEqual "" [] [n | n <- excluded, byShape n]
, testCase "every taken name is an option" $
assertEqual "" [] [n | n <- taken, n `notElem` known]
, testCase "every excluded name is an option" $
assertEqual "" [] [n | n <- excluded, n `notElem` known]
]
where
known = source ShowArgs ++ source ParseArgs
covered names =
assertEqual "" [] [n | n <- names, n `notElem` taken, n `notElem` excluded, not (byShape n)]
Loading
Loading