module Debian.Debianize.Optparse (
CommandLineOptions(..),
BehaviorAdjustment,
Flags(..),
parseProgramArguments,
parseProgramArguments',
handleBehaviorAdjustment) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), (<*>), pure)
#endif
import Control.Applicative (many, (<|>))
import Control.Lens
import Control.Monad.State.Class (MonadState)
import Control.Monad.Trans
import "newtype-generics" Control.Newtype
import Data.Bifunctor (first)
import Data.Char(toUpper)
import Data.Foldable (forM_)
import Data.Maybe.Extended (fromMaybe)
import Data.Maybe.Extended (nothingIf)
import Data.Monoid ((<>))
import Debian.Debianize.BasicInfo (EnvSet(EnvSet), cleanOS, dependOS, buildOS, Flags(..))
import Debian.Debianize.DebInfo (TestsStatus(..))
import Debian.Debianize.Monad
import Debian.Debianize.Prelude (maybeRead)
import Debian.Debianize.VersionSplits
import Debian.GHC ()
import Debian.Policy
import Debian.Relation
import Debian.Version (DebianVersion, parseDebianVersion')
import Distribution.Compiler (CompilerFlavor(..))
#if MIN_VERSION_Cabal(2,0,0)
import Distribution.Package (PackageName, mkPackageName, unPackageName)
import Distribution.PackageDescription (FlagName, mkFlagName)
#else
import Distribution.Package (PackageName(..))
import Distribution.PackageDescription (FlagName(FlagName))
#endif
import GHC.Generics
import System.Environment (getArgs)
import System.FilePath(splitFileName, (</>))
import System.Process (showCommandForUser)
#if MIN_VERSION_hsemail(2,0,0)
import Text.Parsec.Rfc2822 (NameAddr(..))
#else
import Text.ParserCombinators.Parsec.Rfc2822 (NameAddr(..))
#endif
import Text.PrettyPrint.ANSI.Leijen (linebreak, (<+>), string, indent)
import qualified Debian.Debianize.DebInfo as D
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Debian.Debianize.BinaryDebDescription as B
import qualified Debian.Debianize.CabalInfo as A
import qualified Debian.Debianize.SourceDebDescription as S
import qualified Options.Applicative as O
data HaddockStatus = HaddockEnabled | HaddockDisabled deriving Eq
data ProfilingStatus = ProfilingEnabled | ProfilingDisabled deriving Eq
data OfficialStatus = Official| NonOfficial deriving Eq
newtype BuildDep = BuildDep Relations deriving Generic
instance Newtype BuildDep
newtype BuildDepIndep = BuildDepIndep Relations deriving Generic
instance Newtype BuildDepIndep
newtype DevDep = DevDep Relations deriving Generic
instance Newtype DevDep
newtype ExtraDepends = ExtraDepends (BinPkgName, Relations) deriving Generic
instance Newtype ExtraDepends
newtype ExtraConflicts = ExtraConflicts (BinPkgName, Relations) deriving Generic
instance Newtype ExtraConflicts
newtype ExtraProvides = ExtraProvides (BinPkgName, Relations) deriving Generic
instance Newtype ExtraProvides
newtype ExtraReplaces = ExtraReplaces (BinPkgName, Relations) deriving Generic
instance Newtype ExtraReplaces
newtype ExtraRecommends = ExtraRecommends (BinPkgName, Relations) deriving Generic
instance Newtype ExtraRecommends
newtype ExtraSuggests = ExtraSuggests (BinPkgName, Relations) deriving Generic
instance Newtype ExtraSuggests
newtype CabalDebMapping = CabalDebMapping (PackageName, Relations) deriving Generic
instance Newtype CabalDebMapping
newtype ExecDebMapping = ExecDebMapping (String, Relations) deriving Generic
instance Newtype ExecDebMapping
newtype Revision = Revision String deriving Generic
instance Newtype Revision
newtype CabalEpochMapping = CabalEpochMapping (PackageName, Int) deriving Generic
instance Newtype CabalEpochMapping
newtype CabalFlagMapping = CabalFlagMapping (FlagName, Bool) deriving Generic
instance Newtype CabalFlagMapping
data CommandLineOptions = CommandLineOptions {
_flags :: Flags,
_adjustment :: BehaviorAdjustment
}
data BehaviorAdjustment = BehaviorAdjustment {
_maintainer :: NameAddr,
_uploaders :: [NameAddr],
_executable :: [(BinPkgName, D.InstallFile)],
_defaultPackage :: Maybe String,
_missingDependency :: [BinPkgName],
_debianNameBase :: Maybe DebBase,
_debianVersion :: Maybe DebianVersion,
_revision :: Maybe Revision,
_sourcePackageName :: Maybe SrcPkgName,
_sourceSection :: Section,
_standardsVersion :: StandardsVersion,
_buildDep :: [BuildDep],
_buildDepIndep :: [BuildDepIndep],
_devDep :: [DevDep],
_extraDepends :: [ExtraDepends],
_extraConflicts :: [ExtraConflicts],
_extraProvides :: [ExtraProvides],
_extraReplaces :: [ExtraReplaces],
_extraRecommends :: [ExtraRecommends],
_extraSuggests :: [ExtraSuggests],
_cabalDebMapping :: [CabalDebMapping],
_cabalEpochMapping :: [CabalEpochMapping],
_execDebMapping :: [ExecDebMapping],
_profiling :: ProfilingStatus,
_haddock :: [HaddockStatus],
_official :: OfficialStatus,
_sourceFormat :: SourceFormat,
_tests :: TestsStatus
}
executableR :: O.ReadM (BinPkgName, D.InstallFile)
executableR = parsePair . span (/= ':') <$> O.str where
parsePair :: (String, String) -> (BinPkgName, D.InstallFile)
parsePair (sp, md) = let (sd, name) = splitFileName sp in
(BinPkgName name, D.InstallFile { D.execName = name,
D.destName = name,
D.sourceDir = nothingIf ( == "./") sd,
D.destDir = case md of
(':' : dd) -> Just dd
_ -> Nothing })
binPkgNameR :: O.ReadM BinPkgName
binPkgNameR = BinPkgName <$> O.str
nameAddrR :: O.ReadM NameAddr
nameAddrR = either fail return =<< parseMaintainer <$> O.str
relationsR :: O.ReadM Relations
relationsR = either (fail . show) return =<< parseRelations <$> (O.str :: O.ReadM String)
mappingR :: O.ReadM (String, Relations)
mappingR = span (/= ':') <$> O.str >>= \case
(str, "") -> fail $ "Does not contains colon: `" ++ str ++ "'"
(pkgstr, _ : relstr) -> do
rels <- either (fail . show) return $ parseRelations relstr
return (pkgstr, rels)
epochMappingR :: O.ReadM (String, Int)
epochMappingR = span (/= '=') <$> O.str >>= \case
(pkgstr, '=' : numstr) -> do
let epoch = fromMaybe (error ("Invalid epoch: " ++ numstr)) (maybeRead numstr :: Maybe Int)
return (pkgstr, epoch)
(str, _) -> fail $ "Does not contains equals: `" ++ str ++ "'"
extraRelationsR :: O.ReadM (BinPkgName, Relations)
extraRelationsR = first BinPkgName <$> mappingR
cabalDebMappingR :: O.ReadM CabalDebMapping
#if MIN_VERSION_Cabal(2,0,0)
cabalDebMappingR = CabalDebMapping . first mkPackageName <$> mappingR
#else
cabalDebMappingR = CabalDebMapping . first PackageName <$> mappingR
#endif
cabalEpochMappingR :: O.ReadM CabalEpochMapping
#if MIN_VERSION_Cabal(2,0,0)
cabalEpochMappingR = CabalEpochMapping . first mkPackageName <$> epochMappingR
#else
cabalEpochMappingR = CabalEpochMapping . first PackageName <$> epochMappingR
#endif
cabalFlagMappingR :: O.ReadM CabalFlagMapping
cabalFlagMappingR = O.str >>= \case
#if MIN_VERSION_Cabal(2,0,0)
('-' : str) -> return $ CabalFlagMapping (mkFlagName str, False)
str -> return $ CabalFlagMapping (mkFlagName str, True)
#else
('-' : str) -> return $ CabalFlagMapping (FlagName str, False)
str -> return $ CabalFlagMapping (FlagName str, True)
#endif
behaviorAdjustmentP :: O.Parser BehaviorAdjustment
behaviorAdjustmentP = BehaviorAdjustment <$> maintainerP
<*> uploadersP
<*> executableP
<*> defaultPackageP
<*> missingDependencyP
<*> debianNameBaseP
<*> debianVersionP
<*> debianRevisionP
<*> sourcePackageNameP
<*> sourceSectionP
<*> standardsVersionP
<*> buildDepP
<*> buildDepIndepP
<*> devDepP
<*> extraDependsP
<*> extraConflictsP
<*> extraProvidesP
<*> extraReplacesP
<*> extraRecommendsP
<*> extraSuggestsP
<*> cabalDebMappingP
<*> cabalEpochMappingP
<*> execDebMappingP
<*> profilingP
<*> haddockP
<*> officialP
<*> sourceFormatP
<*> testsP
maintainerP :: O.Parser NameAddr
maintainerP = O.option nameAddrR m where
m = O.help helpMsg
<> O.long "maintainer"
<> O.short 'm'
<> O.value (NameAddr (Just "Debian Haskell Group")
"pkg-haskell-maintainers@lists.alioth.debian.org")
<> O.metavar "'NAME <EMAIL>'"
helpMsg = "Set the `Maintainer' field in debian/control file."
uploadersP :: O.Parser [NameAddr]
uploadersP = many $ O.option nameAddrR m where
m = O.help helpMsg
<> O.long "uploader"
<> O.short 'u'
<> O.metavar "'NAME <EMAIL>'"
helpMsg = "Add entry to `Uploaders' field in debian/control file."
executableP :: O.Parser [(BinPkgName, D.InstallFile)]
executableP = many $ O.option executableR m where
m = O.help helpMsg
<> O.long "executable"
<> O.short 'e'
<> O.metavar "SOURCEPATH[:DESTDIR]"
helpMsg = unlines [
"Create an individual binary package to hold this executable.",
"Other executables and data files are gathered into a single package",
"named `haskell-PACKAGENAME-utils'"
]
defaultPackageP :: O.Parser (Maybe String)
defaultPackageP = O.option (Just <$> O.str) m where
m = O.help helpMsg
<> O.long "default-package"
<> O.short 'd'
<> O.value Nothing
<> O.metavar "PKGNAME"
helpMsg = unlines [
"Set the name of the catch-all package that receives",
"all the files not included in a library package or some",
"other executable package. By default this is `haskell-PACKAGENAME-utils'"
]
missingDependencyP :: O.Parser [BinPkgName]
missingDependencyP = many $ O.option binPkgNameR m where
m = O.help helpMsg
<> O.long "missing-dependency"
<> O.metavar "DEB"
helpMsg = unlines [
"This is the counterpart to --disable-haddock. It prevents a package",
"from being added to the build dependencies. This is necessary,",
"for example, when a dependency package was built with the",
"--disable-haddock option, because normally cabal-debian assumes",
"that the -doc package exists and adds it as a build dependency."
]
debianNameBaseP :: O.Parser (Maybe DebBase)
debianNameBaseP = O.option (Just . DebBase <$> O.str) m where
m = O.help helpMsg
<> O.long "debian-name-base"
<> O.short 'b'
<> O.value Nothing
<> O.metavar "NAME"
helpMsg = unlines [
"Use this name for the base of the debian binary packages - the string between",
"'libghc-' and '-dev'. Normally this is derived from the hackage package name."
]
debianVersionP :: O.Parser (Maybe DebianVersion)
debianVersionP = O.option (Just . parseDebianVersion' <$> (O.str :: O.ReadM String)) m where
m = O.help helpMsg
<> O.long "deb-version"
<> O.metavar "DEBIANVERSION"
<> O.value Nothing
helpMsg = unlines [
"Specify the version number for the debian package.",
"This will pin the version and should be considered dangerous."
]
debianRevisionP :: O.Parser (Maybe Revision)
debianRevisionP = O.option (Just . Revision <$> O.str) m where
m = O.help helpMsg
<> O.long "revision"
<> O.value Nothing
<> O.metavar "DEBIANREVISION"
helpMsg = unlines [
"Add this string to the cabal version to get the debian version number.",
"Debian policy says this must either be empty (--revision '')",
"or begin with a dash."
]
sourcePackageNameP :: O.Parser (Maybe SrcPkgName)
sourcePackageNameP = O.option (Just . SrcPkgName <$> O.str) m where
m = O.help helpMsg
<> O.long "source-package-name"
<> O.short 's'
<> O.value Nothing
<> O.metavar "DEBIANNAME"
helpMsg = unlines [
"Use this name for the debian source package, the name in the Source field",
"at the top of the debian/control file, and also at the very beginning",
"of the debian/changelog file. By default it is haskell-<cabalname>,",
"where the cabal package name is downcased."
]
sourceSectionP :: O.Parser Section
sourceSectionP = O.option (MainSection <$> O.str) m where
m = O.help helpMsg
<> O.long "source-section"
<> O.short 'S'
<> O.value (MainSection "haskell")
<> O.metavar "SECTION"
helpMsg = "Set the `Section' field in debian/control file."
standardsVersionP :: O.Parser StandardsVersion
standardsVersionP = O.option (parseStandardsVersion <$> O.str) m where
m = O.help helpMsg
<> O.long "standards-version"
<> O.value (parseStandardsVersion "3.9.6")
<> O.metavar "CABALVERSION"
helpMsg = unlines [
"Claim compatibility to this version of the Debian policy",
"(i.e. the value of the Standards-Version field)"
]
buildDepP :: O.Parser [BuildDep]
buildDepP = many $ O.option (BuildDep <$> relationsR) m where
m = O.help helpMsg
<> O.long "build-dep"
<> O.metavar "DEBIANRELATIONS"
helpMsg = unlines [
"Add a dependency relation to the `Build-Depends'",
"field for this source package."
]
buildDepIndepP :: O.Parser [BuildDepIndep]
buildDepIndepP = many $ O.option (BuildDepIndep <$> relationsR) m where
m = O.help helpMsg
<> O.long "build-dep-indep"
<> O.metavar "DEBIANRELATIONS"
helpMsg = unlines [
"Add a dependency relation to the `Build-Depends-Indep'",
"field for this source package."
]
devDepP :: O.Parser [DevDep]
devDepP = many $ O.option (DevDep <$> relationsR) m where
m = O.help helpMsg
<> O.long "dev-dep"
<> O.metavar "RELATION"
helpMsg = "Add an entry to the `Depends' field of the -dev package"
mkExtraP :: (Newtype n, O n ~ (BinPkgName, Relations))
=> String -> O.Parser [n]
mkExtraP long@(c:cr) = many $ O.option (pack <$> extraRelationsR) m where
fieldName = toUpper c : cr
m = O.help helpMsg
<> O.long long
<> O.metavar "DEB:RELATION"
helpMsg = "Add extry to '" ++ fieldName ++ " 'field of DEB binary package"
mkExtraP "" = error "mkExtraP: empty long option"
extraDependsP :: O.Parser [ExtraDepends]
extraDependsP = mkExtraP "depends"
extraConflictsP :: O.Parser [ExtraConflicts]
extraConflictsP = mkExtraP "conflicts"
extraProvidesP :: O.Parser [ExtraProvides]
extraProvidesP = mkExtraP "provides"
extraReplacesP :: O.Parser [ExtraReplaces]
extraReplacesP = mkExtraP "replaces"
extraRecommendsP :: O.Parser [ExtraRecommends]
extraRecommendsP = mkExtraP "recommends"
extraSuggestsP :: O.Parser [ExtraSuggests]
extraSuggestsP = mkExtraP "suggests"
cabalDebMappingP :: O.Parser [CabalDebMapping]
cabalDebMappingP = many $ O.option cabalDebMappingR m where
m = O.help helpMsg
<> O.long "dep-map"
<> O.metavar "CABAL:DEBIANBINARYPACKAGE"
helpMsg = unlines [
"Specify what debian package name corresponds with a name that appears",
"in the Extra-Library field of a cabal file,",
"e.g. --map-dep cryptopp:libcrypto-dev."
]
execDebMappingP :: O.Parser [ExecDebMapping]
execDebMappingP = many $ O.option (ExecDebMapping <$> mappingR) m where
m = O.help helpMsg
<> O.long "exec-map"
<> O.metavar "CABAL:DEBIANBINARYPACKAGE"
helpMsg = unlines [
"Specify a mapping from the name appearing in the Build-Tool",
"field of the cabal file to a debian binary package name,",
"e.g. --exec-map trhsx:haskell-hsx-utils"
]
cabalEpochMappingP :: O.Parser [CabalEpochMapping]
cabalEpochMappingP = many $ O.option (cabalEpochMappingR) m where
m = O.help helpMsg
<> O.long "epoch-map"
<> O.metavar "CABALPACKAGE=DIGIT"
helpMsg = unlines [
"Specify a mapping from the cabal package name to a digit to use",
"as the debian package epoch number, e.g. --epoch-map HTTP=1"
]
cabalFlagsP :: O.Parser [CabalFlagMapping]
cabalFlagsP = many $ O.option (cabalFlagMappingR) m where
m = O.help helpMsg
<> O.long "cabal-flags"
<> O.long "cabal-flag"
<> O.metavar "CABALFLAG or -CABALFLAG"
helpMsg = "Flags to pass to cabal configure with the --flags= option"
profilingP :: O.Parser ProfilingStatus
profilingP = O.flag ProfilingEnabled ProfilingDisabled m where
m = O.help helpMsg
<> O.long "disable-profiling"
helpMsg = "Do not generate profiling (-prof) library package."
haddockP :: O.Parser [HaddockStatus]
haddockP = (: []) <$> (O.flag HaddockEnabled HaddockDisabled m) where
m = O.help helpMsg
<> O.long "disable-haddock"
helpMsg = "Do not create a -doc package"
officialP :: O.Parser OfficialStatus
officialP = O.flag NonOfficial Official m where
m = O.help helpMsg
<> O.long "official"
helpMsg = "Follow guidelines of Debian Haskell Group"
sourceFormatP :: O.Parser SourceFormat
sourceFormatP = O.flag Quilt3 Native3 m where
m = O.help helpMsg
<> O.long "native"
helpMsg = unlines [
"Package has an no upstream tarball,",
"write '3.0 (native)' into source/format."
]
testsP :: O.Parser TestsStatus
testsP = buildOnlyTestsP <|> disableTestsP
disableTestsP :: O.Parser TestsStatus
disableTestsP = O.flag TestsRun TestsDisable m where
m = O.help "disable test suite"
<> O.long "disable-tests"
<> O.long "no-tests"
buildOnlyTestsP :: O.Parser TestsStatus
buildOnlyTestsP = O.flag TestsRun TestsBuild m where
m = O.help "build, but do not run test suite"
<> O.long "no-run-tests"
<> O.long "disable-running-tests"
flagsP :: O.Parser Flags
flagsP = Flags <$> verbosityP
<*> dryRunP
<*> upgradeP
<*> roundtripP
<*> pure False
<*> hcFlavorP
<*> (flagSet <$> cabalFlagsP)
<*> buildEnvDirP
where
flagSet cfms = Set.fromList (map (\ (CabalFlagMapping (name, bool)) -> (name, bool)) cfms)
verbosityP :: O.Parser Int
verbosityP = length <$> many (O.flag' () m) where
m = O.help helpMsg
<> O.short 'v'
<> O.long "verbose"
helpMsg = unlines [
"Every instance of this flag increases amount",
"of progress messages generated"
]
dryRunP :: O.Parser Bool
dryRunP = O.switch m where
m = O.help helpMsg
<> O.short 'n'
<> O.long "dry-run"
helpMsg = unlines [
"Just compare the existing debianization",
"to the one we would generate."
]
upgradeP :: O.Parser Bool
upgradeP = O.switch m where
m = O.help helpMsg
<> O.long "upgrade"
helpMsg = unlines [
"Upgrade an existing debianization carefully",
"preserving fields that are commonly hand-edited."
]
roundtripP :: O.Parser Bool
roundtripP = O.switch m where
m = O.help helpMsg
<> O.long "roundtrip"
helpMsg = unlines [
"Roundtrip a debianization to normalize it."
]
hcFlavorP :: O.Parser CompilerFlavor
hcFlavorP = O.flag GHC
#if MIN_VERSION_Cabal(1,22,0)
GHCJS
#else
GHC
#endif
m where
m = O.help helpMsg
<> O.long "ghcjs"
helpMsg = "Set compiler flavor to GHCJS."
buildEnvDirP :: O.Parser EnvSet
buildEnvDirP = O.option ((\s -> EnvSet {cleanOS = s </> "clean", dependOS = s </> "depend", buildOS = s </> "build"}) <$> O.str) m where
m = O.help "Directory containing the three build environments, clean, depend, and build."
<> O.long "buildenvdir"
<> O.value (EnvSet {cleanOS = "/", dependOS = "/", buildOS = "/"})
<> O.metavar "DIR"
commandLineOptionsP :: O.Parser CommandLineOptions
commandLineOptionsP = CommandLineOptions <$> flagsP <*> behaviorAdjustmentP
commandLineOptionsParserInfo :: [String] -> O.ParserInfo CommandLineOptions
commandLineOptionsParserInfo args = O.info (O.helper <*> commandLineOptionsP) im where
im = O.header "cabal-debian -- create debianization of cabal package"
<> O.fullDesc
<> O.progDescDoc (Just descDoc)
descDoc =
"Typical usage is run in unpacked source root directory"
<+> linebreak <+> linebreak
<+> indent 2 "% cabal-debian --maintainer 'Maintainer Name <maintainer@email>'"
<+> linebreak <+> linebreak
<+> (string . unlines $ [
"This will read the package's cabal file and any existing debian/changelog file and",
"deduce what it can about the debianization, then it will create or modify files in",
"the debian subdirectory. Note that it will not remove any files in debian, and",
"these could affect the operation of the debianization in unknown ways. For this",
"reason it is recommended either using a pristine unpacked directory each time, or else",
"using a revision control system to revert the package to a known state before running.",
"",
"Arguments: " ++ showCommandForUser "cabal-debian" args
])
handleBehaviorAdjustment :: (MonadIO m, Functor m) => BehaviorAdjustment -> CabalT m ()
handleBehaviorAdjustment (BehaviorAdjustment {..}) = do
forM_ _cabalEpochMapping $ \(CabalEpochMapping (pkg, num)) -> A.epochMap %= Map.insert pkg num
zoom A.debInfo $ do
forM_ _executable $ (D.executable %=) . uncurry Map.insert
forM_ _execDebMapping $ (D.execMap %=) . uncurry Map.insert . unpack
forM_ _missingDependency $ (D.missingDependencies %=) . Set.insert
D.utilsPackageNameBase .= _defaultPackage
D.noDocumentationLibrary .= (HaddockDisabled `elem` _haddock)
D.noProfilingLibrary .= (_profiling == ProfilingDisabled)
D.overrideDebianNameBase .= _debianNameBase
D.sourcePackageName .= _sourcePackageName
D.maintainerOption .= Just _maintainer
D.sourceFormat .= _sourceFormat
D.revision .= unpack `fmap` _revision
D.debVersion .= _debianVersion
D.uploadersOption %= (++ _uploaders)
D.extraDevDeps %= (++ concatMap unpack _devDep)
#if MIN_VERSION_Cabal(2,0,0)
forM_ _cabalDebMapping $ \(CabalDebMapping (pkg, rels)) -> do
D.extraLibMap %= Map.insert (unPackageName pkg) rels
#else
forM_ _cabalDebMapping $ \(CabalDebMapping (PackageName pkg, rels)) -> do
D.extraLibMap %= Map.insert pkg rels
#endif
addExtra _extraDepends B.depends
addExtra _extraConflicts B.conflicts
addExtra _extraProvides B.provides
addExtra _extraReplaces B.replaces
addExtra _extraRecommends B.recommends
addExtra _extraSuggests B.suggests
D.testsStatus .= _tests
D.official .= (_official == Official)
zoom D.control $ do
S.section .= Just _sourceSection
S.standardsVersion .= Just _standardsVersion
S.buildDepends %= (++ concatMap unpack _buildDep)
S.buildDepends %= (++ concatMap unpack _devDep)
S.buildDependsIndep %= (++ concatMap unpack _buildDepIndep)
addExtra :: (MonadState D.DebInfo m, Newtype n, O n ~ (BinPkgName, Relations)) =>
[n] -> Lens' B.PackageRelations Relations -> m ()
addExtra extra lens' = forM_ extra $ \arg -> do
let (pkg, rel) = unpack arg
D.binaryDebDescription pkg . B.relations . lens' %= (++ rel)
parseProgramArguments' :: [String] -> IO CommandLineOptions
parseProgramArguments' args = O.handleParseResult result where
prefs = O.prefs O.idm
result = O.execParserPure prefs (commandLineOptionsParserInfo args) args
parseProgramArguments :: IO CommandLineOptions
parseProgramArguments = getArgs >>= parseProgramArguments' . leaveOne "--disable-haddock"
where
leaveOne :: String -> [String] -> [String]
leaveOne s xs = go False xs
where
go _ [] = []
go False (x : xs') | x == s = x : go True xs'
go True (x : xs') | x == s = go True xs'
go flag (x : xs') = x : go flag xs'