{-# LANGUAGE TupleSections #-} module Options where import Control.Applicative import Control.Monad.M import qualified Data.List as L import Data.Monoid import qualified Distribution.Package as C import qualified Distribution.Version as CV import Distribution.Text import Options.Applicative.Builder import Options.Applicative.Common import Options.Cabal import Options.CabalConstraints (toConstraints, none, CabalConstraints) import Options.DbProvider import PackageId import Pipes import qualified Data.Set as S data Options = Options { dbprovider :: DbProvider, outputDir :: FilePath, quiet :: Bool, cabal :: Maybe FilePath, cabalConstraints :: CabalConstraints, packages :: [C.PackageId] } deriving Show parser :: Parser Options parser = Options <$> option toProvider (long "dbprovider" <> short 'p' <> metavar "" <> value (CabalSandbox Nothing) <> help "a ghc package db provider: cabal|ghc|dir\n") <*> strOption ( long "output" <> short 'o' <> metavar "" <> value "./docsets" <> help "the directory to write created docsets to") <*> switch (long "quiet" <> short 'q' <> help "set to quiet output") <*> option (return . Just) (long "cabal" <> short 'c' <> metavar "" <> value Nothing <> help "the cabal file to retrieve package dependencies from") <*> option toConstraints (long "cabal-constraints" <> short 'r' <> value none <> metavar "executable=name, .." <> help "limit package results from a cabal file source, see documentation") <*> many ( argument simpleParse (metavar "packages" <> help "a list of packages to specifically build, e.g. either-1.0.1 text" )) -- | Given two lists of package satisfying strings, -- return a list that is non-duplicate, the most versioned of the two. -- e.g. if 'either-4.1.0' is in one, and 'either' is the other, -- the versioned is chosen. If both are versioned, both appear in -- the final result. reduce :: [C.PackageId] -> [C.PackageId] reduce = fromAsc . L.sort where -- Here we exploit the fact that you only need to examine the next member of -- an ascending list to determine a version fromAsc :: [C.PackageId] -> [C.PackageId] fromAsc [] = [] fromAsc (p:[]) = [p] fromAsc (p:nxt:rest) | p == nxt = -- duplicate fromAsc (nxt:rest) | unversioned p == unversioned nxt = if unversioned p == p then fromAsc $ nxt:rest else -- both are versioned by list ordering p : nxt : fromAsc rest | otherwise = -- they're different packages p : fromAsc ( nxt : rest ) versionless :: String -> C.PackageId versionless n = C.PackageIdentifier (C.PackageName n) $ CV.Version [] [] prod_Packages :: Options -> ProducerM (S.Set String) () prod_Packages options = do cabal_dependencies <- lift $ case cabal options of Nothing -> return [] Just fp -> (S.toList . S.map versionless) <$> readPackages fp (cabalConstraints options) yield . S.fromList . map (show . disp) $ reduce (packages options ++ cabal_dependencies)