stackage2nix-0.5.0: src/Runner/Cli.hs
module Runner.Cli where
import Control.Lens
import Data.Monoid ( (<>) )
import Data.Text as T
import qualified Distribution.Compat.ReadP as P
import Distribution.Compiler as Compiler
import Distribution.System as System
import qualified Distribution.Text as Text
import Options.Applicative as Opts
import Paths_stackage2nix ( version )
import Stack.Config
import Stack.Types
import System.FilePath
data Tweaks = Tweaks
{ _tExtraDepsRevisionLatest :: Bool
} deriving (Show)
makeLenses ''Tweaks
-- | What will be generated
data Target
= TargetStackagePackages
| TargetStackageClosure
| TargetStackageOverride
deriving (Show)
makePrisms ''Target
-- | Source that would be used to produce target derivation
data ConfigOrigin
= OriginResolver StackResolver
-- ^ Resolver to generate Stackage LTS
| OriginStackYaml StackYaml Target
-- ^ Stack config to generate build derivation
deriving (Show)
makePrisms ''ConfigOrigin
data StackageOptions = StackageOptions
{ _soptAllCabalHashesRepo :: FilePath
, _soptLtsHaskellRepo :: FilePath
} deriving (Show)
makeLenses ''StackageOptions
data Options = Options
{ _optAllCabalHashesRepo :: Maybe FilePath
, _optLtsHaskellRepo :: Maybe FilePath
, _optOutStackagePackages :: FilePath
, _optOutStackageConfig :: FilePath
, _optOutDerivation :: FilePath
, _optDoCheckPackages :: Bool
, _optDoHaddockPackages :: Bool
, _optTweaks :: Tweaks
, _optHackageDb :: Maybe FilePath
, _optNixpkgsRepository :: FilePath
, _optCompilerId :: CompilerId
, _optPlatform :: Platform
, _optConfigOrigin :: ConfigOrigin
} deriving (Show)
makeLenses ''Options
mkStackYaml :: FilePath -> StackYaml
mkStackYaml p = case splitFileName p of
(dir, "") -> StackYaml dir "stack.yaml"
(dir, ".") -> StackYaml dir "stack.yaml"
(_ , "..") -> StackYaml p "stack.yaml"
(dir, file) -> case splitExtension file of
(_, "") -> StackYaml p "stack.yaml"
_ -> StackYaml dir file
options :: Parser Options
options = Options
<$> optional allCabalHashesRepo
<*> optional ltsHaskellRepo
<*> outStackagePackages
<*> outStackageConfig
<*> outDerivation
<*> doCheckPackages
<*> doHaddockPackages
<*> tweaks
<*> optional optionHackageDb
<*> nixpkgsRepository
<*> compilerId
<*> platform
<*> configOrigin
pinfo :: ParserInfo Options
pinfo = info
( helper
<*> infoOption ("stackage2nix " ++ Text.display version) (long "version" <> help "Show version")
<*> options )
( fullDesc
<> header "stackage2nix converts Stack files into build instructions for Nix." )
nixpkgsRepository :: Parser FilePath
nixpkgsRepository = option str
( long "nixpkgs"
<> metavar "NIXPKGS"
<> help "path to Nixpkgs repository"
<> value "<nixpkgs>"
<> showDefaultWith id )
allCabalHashesRepo :: Parser FilePath
allCabalHashesRepo = option str
( long "all-cabal-hashes"
<> metavar "REPO_DIR"
<> help "path to commercialhaskell/all-cabal-hashes repository" )
ltsHaskellRepo :: Parser FilePath
ltsHaskellRepo = option str
( long "lts-haskell"
<> metavar "REPO_DIR"
<> help "path to fpco/lts-haskell repository" )
outStackagePackages :: Parser FilePath
outStackagePackages = option str
( long "out-packages"
<> metavar "NIX_FILE"
<> help "output file of the stackage packages set"
<> value "packages.nix"
<> showDefaultWith id)
outStackageConfig :: Parser FilePath
outStackageConfig = option str
( long "out-config"
<> metavar "NIX_FILE"
<> help "output file of the stackage packages compiler config"
<> value "configuration-packages.nix"
<> showDefaultWith id)
outDerivation :: Parser FilePath
outDerivation = option str
( long "out-derivation"
<> metavar "NIX_FILE"
<> help "path to output derivation"
<> value "default.nix"
<> showDefaultWith id )
doCheckPackages :: Parser Bool
doCheckPackages = flag True False
( long "no-check"
<> help "disable tests for project packages")
doHaddockPackages :: Parser Bool
doHaddockPackages = flag True False
( long "no-haddock"
<> help "disable haddock for project packages")
withStackage :: Parser ()
withStackage = flag' ()
( long "with-stackage"
<> help "generate full Stackage" )
withStackageClosure :: Parser ()
withStackageClosure = flag' ()
( long "with-stackage-closure"
<> help "generate Stackage subset containing only build dependencies" )
extraDepsRevisionLatest :: Parser Bool
extraDepsRevisionLatest = switch
( long "extra-deps-revision-latest"
<> help "Changes algorithm for the dependencies generation of the stack.yaml extra-deps. Default one is to generate exact revision defined in the Stackage config. With this flag enabled, direct dependencies of the stack.yaml extra-deps will be generated with the latest revision available on Hackage. This may help when Cabal fails to resolve dependencies of extra-deps, and dependences are fixed in the latest revision" )
tweaks :: Parser Tweaks
tweaks = Tweaks <$> extraDepsRevisionLatest
resolver :: Parser StackResolver
resolver = StackResolver <$> option text
( long "resolver"
<> help "stackage LTS resolver" )
stackYamlArg :: Parser StackYaml
stackYamlArg = mkStackYaml <$> Opts.argument str
( metavar "STACK_YAML"
<> help "path to stack.yaml file or directory" )
target :: Parser Target
target =
withStackage *> pure TargetStackagePackages <|>
withStackageClosure *> pure TargetStackageClosure <|>
pure TargetStackageOverride
configOrigin :: Parser ConfigOrigin
configOrigin =
OriginStackYaml <$> stackYamlArg <*> target <|>
OriginResolver <$> resolver
-- required for cabal2nix
optionHackageDb :: Parser FilePath
optionHackageDb = option str
( long "hackage-db"
<> metavar "HACKAGE_DB"
<> help "path to the local hackage db in tar format" )
cabalFlag :: Parser CabalFlag
cabalFlag = CabalFlag <$>
option text
( short 'f'
<> long "flag"
<> help "Cabal flag (may be specified multiple times)" )
compilerId :: Parser CompilerId
compilerId = option (readP Text.parse)
( long "compiler"
<> help "compiler to use when evaluating the Cabal file"
<> value buildCompilerId
<> showDefaultWith Text.display )
platform :: Parser Platform
platform = option (readP Text.parse)
( long "system"
<> help "target system to use when evaluating the Cabal file"
<> value buildPlatform
<> showDefaultWith Text.display )
-- utils
text :: ReadM Text
text = T.pack <$> str
readP :: P.ReadP a a -> ReadM a
readP p = eitherReader $ \s ->
case [ r' | (r',"") <- P.readP_to_S p s ] of
(r:_) -> Right r
_ -> Left ("invalid value " ++ show s)